1 /// This module defines the `Children` struct which will catch mutations to it made while drawing, and defines utils
2 /// for operating on children.
3 module glui.children;
4
5 import std.range;
6
7 import glui.node;
8
9 @safe pure:
10
11 debug struct Children {
12
13 private enum mutateError = "Cannot mutate children list while its being rendered. This should be done in an event "
14 ~ "handler, such as the mouseImpl/keyboardImpl methods.";
15
16 private {
17
18 GluiNode[] _children;
19 bool _locked;
20
21 }
22
23 @safe:
24
25 this(inout(Children) old) inout {
26
27 this._children = old._children;
28 this._locked = false;
29
30 }
31
32 @property {
33
34 size_t length() const {
35
36 return _children.length;
37
38 }
39
40 size_t length(size_t value) {
41
42 debug assert(!_locked, mutateError);
43
44 return _children.length = value;
45
46 }
47
48 }
49
50 @property
51 bool empty() const {
52
53 return _children.length == 0;
54
55 }
56
57 /// Remove the first item.
58 void popFront() {
59
60 debug assert(!_locked, mutateError);
61 assert(!empty, "Can't pop an empty children list");
62
63 _children.popFront();
64
65 }
66
67 /// Get the first child.
68 ref inout(GluiNode) front() inout {
69
70 assert(!empty, "Can't get the first item of an empty children list");
71
72 return _children[0];
73
74 }
75
76 void opAssign(GluiNode[] newList) {
77
78 debug assert(!_locked, mutateError);
79 _children = newList;
80
81 }
82
83 // Indexing and slicing is allowed
84 GluiNode[] opIndex() {
85
86 return _children[];
87
88 }
89 auto opIndex(Args...)(Args args) {
90
91 return _children[args];
92
93 }
94
95 @property
96 size_t opDollar() const {
97
98 return _children.length;
99
100 }
101
102 ref GluiNode[] getChildren() return {
103
104 debug assert(!_locked, "Can't get a mutable reference to children while rendering. Consider doing this in "
105 ~ "input handling methods like mouseImpl/keyboardImpl which happen after rendering is complete. But if "
106 ~ "this is necessary, you may use `glui.children.asConst` instead. Note, iterating over the (mutable) "
107 ~ "children is still legal. You can also use `node.remove` if you want to simply remove a node.");
108 return _children;
109
110 }
111
112 int opApply(int delegate(GluiNode node) @trusted dg) {
113
114 foreach (child; _children) {
115
116 if (auto result = dg(child)) return result;
117
118 }
119
120 return 0;
121
122 }
123
124 int opApply(int delegate(size_t index, GluiNode node) @trusted dg) {
125
126 foreach (i, child; _children) {
127
128 if (auto result = dg(i, child)) return result;
129
130 }
131
132 return 0;
133
134 }
135
136 alias getChildren this;
137
138 }
139
140 else alias Children = GluiNode[];
141
142 static assert(isInputRange!Children);
143
144
145 pragma(inline)
146 void lock(ref Children children) {
147
148 debug children._locked = true;
149
150 assertLocked(children);
151
152 }
153
154 pragma(inline)
155 void unlock(ref Children children) {
156
157 debug {
158
159 assert(children._locked, "Already unlocked.");
160
161 children._locked = false;
162
163 }
164
165 }
166
167 pragma(inline)
168 void assertLocked(ref Children children) {
169
170 // debug just to de sure lol
171 // pretty sure you can fiddle with the compiler flags enough to make this not compile
172 debug assert(children._locked);
173
174 }
175
176 /// Get the children list as const.
177 pragma(inline)
178 const(GluiNode[]) asConst(Children children) {
179
180 debug return children._children;
181 else return children;
182
183 }
184
185 /// Get a reference to the children list forcefully, ignoring the lock.
186 pragma(inline)
187 ref GluiNode[] forceMutable(return ref Children children) @system {
188
189 debug return children._children;
190 else return children;
191
192 }
193
194 /// Get a reference to child within the parent.
195 ///
196 /// This will probably be soon deprecated in favor of a "placeholder" node to fulfill this purpose.
197 ref GluiNode childRef(ref Children children, size_t index) @system {
198
199 debug assert(!children._locked, "Can't get reference to a locked child.");
200
201 debug return children._children[index];
202 else return children[index];
203
204 }