1 /* 2 * DQt - D bindings for the Qt Toolkit 3 * 4 * GNU Lesser General Public License Usage 5 * This file may be used under the terms of the GNU Lesser 6 * General Public License version 3 as published by the Free Software 7 * Foundation and appearing in the file LICENSE.LGPL3 included in the 8 * packaging of this file. Please review the following information to 9 * ensure the GNU Lesser General Public License version 3 requirements 10 * will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 11 */ 12 module qt.core.flags; 13 extern(C++): 14 15 import qt.config; 16 import qt.core.typeinfo; 17 import qt.helpers; 18 version(D_LP64){}else 19 import core.stdc.config; 20 21 /+ #ifndef QFLAGS_H +/ 22 /+ #define QFLAGS_H +/ 23 24 25 /// Binding for C++ class [QFlag](https://doc.qt.io/qt-6/qflag.html). 26 @Q_PRIMITIVE_TYPE extern(C++, class) struct QFlag 27 { 28 private: 29 int i; 30 public: 31 pragma(inline, true) this(int value)/+ noexcept+/ 32 { 33 this.i = value; 34 } 35 pragma(inline, true) /+ Q_IMPLICIT +/ auto opCast(T : int)() const/+ noexcept+/ { return i; } 36 pragma(inline, true) int toInt() const/+ noexcept+/ { return i; } 37 alias toInt this; 38 39 /+ #if !defined(Q_CC_MSVC) 40 // Microsoft Visual Studio has buggy behavior when it comes to 41 // unsigned enums: even if the enum is unsigned, the enum tags are 42 // always signed 43 # if !defined(__LP64__) && !defined(Q_CLANG_QDOC) +/ 44 version(D_LP64){}else 45 { 46 pragma(inline, true) this(cpp_long value)/+ noexcept+/ 47 { 48 this.i = cast(int)(value); 49 } 50 pragma(inline, true) this(cpp_ulong value)/+ noexcept+/ 51 { 52 this.i = cast(int)(long(value)); 53 } 54 } 55 /+ # endif +/ 56 pragma(inline, true) this(uint value)/+ noexcept+/ 57 { 58 this.i = int(value); 59 } 60 pragma(inline, true) this(short value)/+ noexcept+/ 61 { 62 this.i = int(value); 63 } 64 pragma(inline, true) this(ushort value)/+ noexcept+/ 65 { 66 this.i = int(uint(value)); 67 } 68 /+pragma(inline, true) /+ Q_IMPLICIT +/ auto opCast(T : uint)() const/+ noexcept+/ { return uint(i); }+/ 69 /+ #endif +/ 70 mixin(CREATE_CONVENIENCE_WRAPPERS); 71 } 72 /+ Q_DECLARE_TYPEINFO(QFlag, Q_PRIMITIVE_TYPE); +/ 73 74 @Q_PRIMITIVE_TYPE extern(C++, class) struct QIncompatibleFlag 75 { 76 private: 77 int i; 78 public: 79 /+ explicit +/pragma(inline, true) this(int value)/+ noexcept+/ 80 { 81 this.i = value; 82 } 83 /+pragma(inline, true) /+ Q_IMPLICIT +/ auto opCast(T : int)() const/+ noexcept+/ { return i; }+/ 84 mixin(CREATE_CONVENIENCE_WRAPPERS); 85 } 86 /+ Q_DECLARE_TYPEINFO(QIncompatibleFlag, Q_PRIMITIVE_TYPE); +/ 87 88 89 /// Binding for C++ class [QFlags](https://doc.qt.io/qt-6/qflags.html). 90 extern(C++, class) struct QFlags(Enum) 91 { 92 private: 93 static assert((Enum.sizeof <= int.sizeof), 94 "QFlags uses an int as storage, so an enum with underlying " ~ 95 "long long will overflow."); 96 static assert(is(Enum == enum), "QFlags is only usable on enumeration types."); 97 98 public: 99 /+ #if defined(Q_CC_MSVC) || defined(Q_CLANG_QDOC) 100 // see above for MSVC 101 // the definition below is too complex for qdoc 102 typedef int Int; 103 #else +/ 104 /+ typename std::conditional< 105 std::is_unsigned<typename std::underlying_type<Enum>::type>::value, 106 unsigned int, 107 signed int 108 >::type +/alias Int = int; 109 /+ #endif +/ 110 alias enum_type = Enum; 111 // compiler-generated copy/move ctor/assignment operators are fine! 112 /+pragma(inline, true) this()/+ noexcept+/ 113 { 114 this.i = 0; 115 }+/ 116 pragma(inline, true) this(Enum flags)/+ noexcept+/ 117 { 118 this.i = Int(flags); 119 } 120 pragma(inline, true) this(QFlag flag)/+ noexcept+/ 121 { 122 this.i = flag; 123 } 124 125 /+ constexpr inline QFlags(std::initializer_list<Enum> flags) noexcept 126 : i(initializer_list_helper(flags.begin(), flags.end())) {} +/ 127 128 pragma(inline, true) static QFlags fromInt(Int i)/+ noexcept+/ { return QFlags(QFlag(i)); } 129 pragma(inline, true) Int toInt() const/+ noexcept+/ { return i; } 130 131 pragma(inline, true) ref QFlags opOpAssign(string op)(int mask)/+ noexcept+/ if(op == "&") { i &= mask; return this; } 132 pragma(inline, true) ref QFlags opOpAssign(string op)(uint mask)/+ noexcept+/ if(op == "&") { i &= mask; return this; } 133 pragma(inline, true) ref QFlags opOpAssign(string op)(QFlags mask)/+ noexcept+/ if(op == "&") { i &= mask.i; return this; } 134 pragma(inline, true) ref QFlags opOpAssign(string op)(Enum mask)/+ noexcept+/ if(op == "&") { i &= Int(mask); return this; } 135 pragma(inline, true) ref QFlags opOpAssign(string op)(QFlags other)/+ noexcept+/ if(op == "|") { i |= other.i; return this; } 136 pragma(inline, true) ref QFlags opOpAssign(string op)(Enum other)/+ noexcept+/ if(op == "|") { i |= Int(other); return this; } 137 /+pragma(inline, true) ref QFlags operator ^=(QFlags other)/+ noexcept+/ { i ^= other.i; return this; }+/ 138 /+pragma(inline, true) ref QFlags operator ^=(Enum other)/+ noexcept+/ { i ^= Int(other); return this; }+/ 139 140 pragma(inline, true) auto opCast(T : Int)() const/+ noexcept+/ { return i; } 141 alias toInt this; 142 143 pragma(inline, true) QFlags opBinary(string op)(QFlags other) const/+ noexcept+/ if(op == "|") { return QFlags(QFlag(i | other.i)); } 144 pragma(inline, true) QFlags opBinary(string op)(Enum other) const/+ noexcept+/ if(op == "|") { return QFlags(QFlag(i | Int(other))); } 145 /+pragma(inline, true) QFlags operator ^(QFlags other) const/+ noexcept+/ { return QFlags(QFlag(i ^ other.i)); }+/ 146 /+pragma(inline, true) QFlags operator ^(Enum other) const/+ noexcept+/ { return QFlags(QFlag(i ^ Int(other))); }+/ 147 pragma(inline, true) QFlags opBinary(string op)(int mask) const/+ noexcept+/ if(op == "&") { return QFlags(QFlag(i & mask)); } 148 pragma(inline, true) QFlags opBinary(string op)(uint mask) const/+ noexcept+/ if(op == "&") { return QFlags(QFlag(i & mask)); } 149 pragma(inline, true) QFlags opBinary(string op)(QFlags other) const/+ noexcept+/ if(op == "&") { return QFlags(QFlag(i & other.i)); } 150 pragma(inline, true) QFlags opBinary(string op)(Enum other) const/+ noexcept+/ if(op == "&") { return QFlags(QFlag(i & Int(other))); } 151 /+pragma(inline, true) QFlags operator ~() const/+ noexcept+/ { return QFlags(QFlag(~i)); }+/ 152 153 pragma(inline, true) void opBinary(string op)(QFlags other) const/+ noexcept+/ if(op == "+") /+ = delete +/; 154 pragma(inline, true) void opBinary(string op)(Enum other) const/+ noexcept+/ if(op == "+") /+ = delete +/; 155 pragma(inline, true) void opBinary(string op)(int other) const/+ noexcept+/ if(op == "+") /+ = delete +/; 156 pragma(inline, true) void opBinary(string op)(QFlags other) const/+ noexcept+/ if(op == "-") /+ = delete +/; 157 pragma(inline, true) void opBinary(string op)(Enum other) const/+ noexcept+/ if(op == "-") /+ = delete +/; 158 pragma(inline, true) void opBinary(string op)(int other) const/+ noexcept+/ if(op == "-") /+ = delete +/; 159 160 /+pragma(inline, true) bool operator !() const/+ noexcept+/ { return !i; }+/ 161 162 pragma(inline, true) bool testFlag(Enum flag) const/+ noexcept+/ { return testFlags(QFlags(flag)); } 163 pragma(inline, true) bool testFlags(QFlags flags) const/+ noexcept+/ { return flags.i ? ((i & flags.i) == flags.i) : i == Int(0); } 164 pragma(inline, true) bool testAnyFlag(Enum flag) const/+ noexcept+/ { return testAnyFlags(QFlags(flag)); } 165 pragma(inline, true) bool testAnyFlags(QFlags flags) const/+ noexcept+/ { return (i & flags.i) != Int(0); } 166 /+ constexpr inline QFlags &setFlag(Enum flag, bool on = true) noexcept 167 { 168 return on ? (*this |= flag) : (*this &= ~QFlags(flag)); 169 } +/ 170 171 /+ friend constexpr inline bool operator==(QFlags lhs, QFlags rhs) noexcept 172 { return lhs.i == rhs.i; } +/ 173 /+ friend constexpr inline bool operator!=(QFlags lhs, QFlags rhs) noexcept 174 { return lhs.i != rhs.i; } +/ 175 /+ friend constexpr inline bool operator==(QFlags lhs, Enum rhs) noexcept 176 { return lhs == QFlags(rhs); } +/ 177 /+ friend constexpr inline bool operator!=(QFlags lhs, Enum rhs) noexcept 178 { return lhs != QFlags(rhs); } +/ 179 /+ friend constexpr inline bool operator==(Enum lhs, QFlags rhs) noexcept 180 { return QFlags(lhs) == rhs; } +/ 181 /+ friend constexpr inline bool operator!=(Enum lhs, QFlags rhs) noexcept 182 { return QFlags(lhs) != rhs; } +/ 183 184 template opDispatch(string name) if(__traits(hasMember, Enum, name)) 185 { 186 enum opDispatch = QFlags(__traits(getMember, Enum, name)); 187 } 188 189 bool opCast(T)() if(is(T == bool)) 190 { 191 return i != 0; 192 } 193 194 private: 195 /+pragma(inline, true) static Int initializer_list_helper(/+ std:: +/initializer_list!(Enum).const_iterator it, 196 /+ std:: +/initializer_list!(Enum).const_iterator end)/+ 197 noexcept+/ 198 { 199 return (it == end ? Int(0) : (Int(*it) | initializer_list_helper(it + 1, end))); 200 }+/ 201 202 Int i = 0; 203 } 204 205 /+ #ifndef Q_MOC_RUN 206 #define Q_DECLARE_FLAGS(Flags, Enum)\ 207 typedef QFlags<Enum> Flags; 208 #endif 209 210 #define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) \ 211 constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept \ 212 { return QFlags<Flags::enum_type>(f1) | f2; } \ 213 constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \ 214 { return f2 | f1; } \ 215 constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, Flags::enum_type f2) noexcept \ 216 { return QFlags<Flags::enum_type>(f1) & f2; } \ 217 constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \ 218 { return f2 & f1; } \ 219 constexpr inline void operator+(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \ 220 constexpr inline void operator+(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept = delete; \ 221 constexpr inline void operator+(int f1, QFlags<Flags::enum_type> f2) noexcept = delete; \ 222 constexpr inline void operator-(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \ 223 constexpr inline void operator-(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept = delete; \ 224 constexpr inline void operator-(int f1, QFlags<Flags::enum_type> f2) noexcept = delete; \ 225 constexpr inline QIncompatibleFlag operator|(Flags::enum_type f1, int f2) noexcept \ 226 { return QIncompatibleFlag(int(f1) | f2); } \ 227 constexpr inline void operator+(int f1, Flags::enum_type f2) noexcept = delete; \ 228 constexpr inline void operator+(Flags::enum_type f1, int f2) noexcept = delete; \ 229 constexpr inline void operator-(int f1, Flags::enum_type f2) noexcept = delete; \ 230 constexpr inline void operator-(Flags::enum_type f1, int f2) noexcept = delete; +/ 231 232 233 /+ #endif +/ // QFLAGS_H 234 235 template flagsFromStaticString(T, string str) 236 { 237 enum flagsFromStaticString = (){ 238 T r; 239 static foreach(element; dqtimported!q{std.array}.split(str, "|")) 240 { 241 r |= __traits(getMember, T.enum_type, dqtimported!q{std.array}.split(element, "::")[$-1]); 242 } 243 return r; 244 }(); 245 } 246 template enumFromStaticString(T, string str) 247 { 248 enum enumFromStaticString = __traits(getMember, T, dqtimported!q{std.array}.split(str, "::")[$-1]); 249 }