1 ///
2 module glui.utils;
3 
4 import raylib;
5 
6 import std.meta;
7 import std.functional;
8 
9 import glui.style;
10 import glui.structs;
11 
12 @safe:
13 
14 /// Create a simple node constructor for declarative usage.
15 ///
16 /// Initial properties can be provided in the function provided in the second argument.
17 enum simpleConstructor(T, alias fun = "a") = SimpleConstructor!(T, fun).init;
18 
19 /// Create a simple template node constructor for declarative usage.
20 ///
21 /// If the parent is a simple constructor, its initializer will be ran *after* this one. This is because the user
22 /// usually specifies the parent in templates, so it has more importance.
23 ///
24 /// T must be a template accepting a single parameter — Parent type will be passed to it.
25 template simpleConstructor(alias T, alias Parent, alias fun = "a") {
26 
27     alias simpleConstructor = simpleConstructor!(T!(Parent.Type), (a) {
28 
29         alias initializer = unaryFun!fun;
30 
31         initializer(a);
32         Parent.initializer(a);
33 
34     });
35 
36 }
37 
38 /// ditto
39 alias simpleConstructor(alias T, Parent, alias fun = "a") = simpleConstructor!(T!Parent, fun);
40 
41 enum isSimpleConstructor(T) = is(T : SimpleConstructor!(A, a), A, alias a);
42 
43 struct SimpleConstructor(T, alias fun = "a") {
44 
45     alias Type = T;
46     alias initializer = unaryFun!fun;
47 
48     Type opCall(Args...)(Args args) {
49 
50         auto result = new Type(args);
51         initializer(result);
52         return result;
53 
54     }
55 
56 }
57 
58 unittest {
59 
60     static class Foo {
61 
62         string value;
63 
64         this() { }
65 
66     }
67 
68     alias xfoo = simpleConstructor!Foo;
69     assert(xfoo().value == "");
70 
71     alias yfoo = simpleConstructor!(Foo, (a) {
72         a.value = "foo";
73     });
74     assert(yfoo().value == "foo");
75 
76     auto myFoo = new Foo;
77     yfoo.initializer(myFoo);
78     assert(myFoo.value == "foo");
79 
80     static class Bar(T) : T {
81 
82         int foo;
83 
84         this(int foo) {
85 
86             this.foo = foo;
87 
88         }
89 
90     }
91 
92     alias xbar(alias T) = simpleConstructor!(Bar, T);
93 
94     const barA = xbar!Foo(1);
95     assert(barA.value == "");
96     assert(barA.foo == 1);
97 
98     const barB = xbar!xfoo(2);
99     assert(barB.value == "");
100     assert(barB.foo == 2);
101 
102     const barC = xbar!yfoo(3);
103     assert(barC.value == "foo");
104     assert(barC.foo == 3);
105 
106 }
107 
108 // lmao
109 // AliasSeq!(AliasSeq!(T...)) won't work, this is a workaround
110 // too lazy to document, used to generate node constructors with variadic or optional arguments.
111 alias BasicNodeParamLength = Alias!5;
112 template BasicNodeParam(int index) {
113 
114     static if (index == 0) alias BasicNodeParam = AliasSeq!(Layout, const Theme);
115     static if (index == 1) alias BasicNodeParam = AliasSeq!(const Theme, Layout);
116     static if (index == 2) alias BasicNodeParam = AliasSeq!(Layout);
117     static if (index == 3) alias BasicNodeParam = AliasSeq!(const Theme);
118     static if (index == 4) alias BasicNodeParam = AliasSeq!();
119 
120 }
121 
122 /// Check if the rectangle contains a point.
123 bool contains(Rectangle rectangle, Vector2 point) {
124 
125     return rectangle.x <= point.x
126         && point.x < rectangle.x + rectangle.width
127         && rectangle.y <= point.y
128         && point.y < rectangle.y + rectangle.height;
129 
130 }
131 
132 /// Get names of static fields in the given object.
133 ///
134 /// Ignores deprecated fields.
135 template StaticFieldNames(T) {
136 
137     import std.traits : hasStaticMember;
138     import std.meta : Alias, Filter;
139 
140     // Prepare data
141     alias Members = __traits(allMembers, T);
142 
143     template isStaticMember(string member) {
144 
145         enum isStaticMember =
146 
147             // Make sure this isn't an alias
148             __traits(compiles,
149                 Alias!(__traits(getMember, T, member))
150             )
151 
152             && !__traits(isDeprecated, __traits(getMember, T, member))
153 
154             // Find the member
155             && hasStaticMember!(T, member);
156 
157     }
158 
159     // Result
160     alias StaticFieldNames = Filter!(isStaticMember, Members);
161 
162 }
163 
164 /// Get the current HiDPI scale. Returns Vector2(1, 1) if HiDPI is off.
165 Vector2 hidpiScale() @trusted {
166 
167     // HiDPI is on
168     return IsWindowState(ConfigFlags.FLAG_WINDOW_HIGHDPI)
169         ? GetWindowScaleDPI
170         : Vector2.one;
171 
172 }