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 }