]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/container.qc
63366c0eed3ea6e2c0b14405fd8a99eab96c505b
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / container.qc
1 #include "container.qh"
2 #ifndef ITEM_CONTAINER_H
3         #define ITEM_CONTAINER_H
4         #include "../item.qc"
5         CLASS(Container, Item)
6                 METHOD(Container, draw, void(entity));
7                 METHOD(Container, keyUp, float(entity, float, float, float));
8                 METHOD(Container, keyDown, float(entity, float, float, float));
9                 METHOD(Container, mouseMove, float(entity, vector));
10                 METHOD(Container, mousePress, float(entity, vector));
11                 METHOD(Container, mouseDrag, float(entity, vector));
12                 METHOD(Container, mouseRelease, float(entity, vector));
13                 METHOD(Container, focusLeave, void(entity));
14                 METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector));
15                 METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector));
16                 METHOD(Container, addItem, void(entity, entity, vector, vector, float));
17                 METHOD(Container, addItemCentered, void(entity, entity, vector, float));
18                 METHOD(Container, addItemRightCentered, void(entity, entity, vector, float));
19                 METHOD(Container, moveItemAfter, void(entity, entity, entity));
20                 METHOD(Container, removeItem, void(entity, entity));
21                 METHOD(Container, setFocus, void(entity, entity));
22                 METHOD(Container, saveFocus, void(entity));
23                 METHOD(Container, setAlphaOf, void(entity, entity, float));
24                 METHOD(Container, itemFromPoint, entity(entity, vector));
25                 METHOD(Container, showNotify, void(entity));
26                 METHOD(Container, hideNotify, void(entity));
27                 METHOD(Container, preferredFocusedGrandChild, entity(entity));
28                 ATTRIB(Container, focusable, float, 0)
29                 ATTRIB(Container, firstChild, entity, NULL)
30                 ATTRIB(Container, lastChild, entity, NULL)
31                 ATTRIB(Container, focusedChild, entity, NULL)
32                 ATTRIB(Container, savedFocus, entity, NULL)
33                 ATTRIB(Container, shown, float, 0)
34
35                 METHOD(Container, enterSubitem, void(entity, entity));
36                 METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
37                 METHOD(Container, leaveSubitem, void(entity));
38         ENDCLASS(Container)
39         .entity nextSibling;
40         .entity prevSibling;
41         .float resized;
42         .vector Container_origin;
43         .vector Container_size;
44         .vector Container_fontscale;
45         .float Container_alpha;
46         .vector Container_save_shift;
47         .vector Container_save_scale;
48         .vector Container_save_fontscale;
49         .float Container_save_alpha;
50 #endif
51
52 #ifdef IMPLEMENTATION
53         void Container_enterSubitem(entity me, entity sub)
54         {
55                 me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
56         }
57
58         void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
59         {
60                 me.Container_save_shift = draw_shift;
61                 me.Container_save_scale = draw_scale;
62                 me.Container_save_alpha = draw_alpha;
63                 me.Container_save_fontscale = draw_fontscale;
64
65                 draw_shift = boxToGlobal(o, draw_shift, draw_scale);
66                 draw_scale = boxToGlobalSize(s, draw_scale);
67                 if (f != '0 0 0') draw_fontscale = boxToGlobalSize(f, draw_fontscale);
68                 draw_alpha *= a;
69         }
70
71         void Container_leaveSubitem(entity me)
72         {
73                 draw_shift = me.Container_save_shift;
74                 draw_scale = me.Container_save_scale;
75                 draw_alpha = me.Container_save_alpha;
76                 draw_fontscale = me.Container_save_fontscale;
77         }
78
79         void Container_showNotify(entity me)
80         {
81                 entity e;
82                 if (me.shown) return;
83                 me.shown = 1;
84                 for (e = me.firstChild; e; e = e.nextSibling)
85                         if (e.Container_alpha > 0) e.showNotify(e);
86         }
87
88         void Container_hideNotify(entity me)
89         {
90                 entity e;
91                 if (!me.shown) return;
92                 me.shown = 0;
93                 for (e = me.firstChild; e; e = e.nextSibling)
94                         if (e.Container_alpha > 0) e.hideNotify(e);
95         }
96
97         void Container_setAlphaOf(entity me, entity other, float theAlpha)
98         {
99                 if (theAlpha <= 0)
100                 {
101                         if (other.Container_alpha > 0) other.hideNotify(other);
102                 }
103                 else  // value > 0
104                 {
105                         if (other.Container_alpha <= 0) other.showNotify(other);
106                 }
107                 other.Container_alpha = theAlpha;
108         }
109
110         void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
111         {
112                 entity e;
113                 vector o, s;
114                 float d;
115                 for (e = me.firstChild; e; e = e.nextSibling)
116                 {
117                         o = e.(originField);
118                         s = e.(sizeField);
119                         me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
120                         e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
121                         me.leaveSubitem(me);
122                 }
123                 do
124                 {
125                         d = 0;
126                         for (e = me.firstChild; e; e = e.nextSibling)
127                                 if (e.resized)
128                                 {
129                                         e.resized = 0;
130                                         d = 1;
131                                         o = e.(originField);
132                                         s = e.(sizeField);
133                                         me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
134                                         e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
135                                         me.leaveSubitem(me);
136                                 }
137                 }
138                 while (d);
139                 SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
140         }
141
142         void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
143         {
144                 me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
145         }
146
147         entity Container_itemFromPoint(entity me, vector pos)
148         {
149                 entity e;
150                 vector o, s;
151                 for (e = me.lastChild; e; e = e.prevSibling)
152                 {
153                         o = e.Container_origin;
154                         s = e.Container_size;
155                         if (pos.x < o.x) continue;
156                         if (pos.y < o.y) continue;
157                         if (pos.x >= o.x + s.x) continue;
158                         if (pos.y >= o.y + s.y) continue;
159                         return e;
160                 }
161                 return NULL;
162         }
163
164         void Container_draw(entity me)
165         {
166                 entity e;
167
168                 me.focusable = 0;
169                 for (e = me.firstChild; e; e = e.nextSibling)
170                 {
171                         if (e.focusable) me.focusable += 1;
172                         if (e.Container_alpha < 0.003)  // can't change color values anyway
173                                 continue;
174                         me.enterSubitem(me, e);
175                         e.draw(e);
176                         me.leaveSubitem(me);
177                 }
178
179                 SUPER(Container).draw(me);
180         }
181
182         void Container_focusLeave(entity me)
183         {
184                 me.setFocus(me, NULL);
185         }
186
187         float Container_keyUp(entity me, float scan, float ascii, float shift)
188         {
189                 entity f;
190                 float r;
191                 f = me.focusedChild;
192                 if (f)
193                 {
194                         me.enterSubitem(me, f);
195                         r = f.keyUp(f, scan, ascii, shift);
196                         me.leaveSubitem(me);
197                         return r;
198                 }
199                 return 0;
200         }
201
202         float Container_keyDown(entity me, float scan, float ascii, float shift)
203         {
204                 entity f;
205                 float r;
206                 f = me.focusedChild;
207                 if (f)
208                 {
209                         me.enterSubitem(me, f);
210                         r = f.keyDown(f, scan, ascii, shift);
211                         me.leaveSubitem(me);
212                         return r;
213                 }
214                 return 0;
215         }
216
217         float Container_mouseMove(entity me, vector pos)
218         {
219                 entity f;
220                 float r;
221                 f = me.focusedChild;
222                 if (f)
223                 {
224                         me.enterSubitem(me, f);
225                         r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
226                         me.leaveSubitem(me);
227                         return r;
228                 }
229                 return 0;
230         }
231         float Container_mousePress(entity me, vector pos)
232         {
233                 entity f;
234                 float r;
235                 f = me.focusedChild;
236                 if (f)
237                 {
238                         me.enterSubitem(me, f);
239                         r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
240                         me.leaveSubitem(me);
241                         return r;
242                 }
243                 return 0;
244         }
245         float Container_mouseDrag(entity me, vector pos)
246         {
247                 entity f;
248                 float r;
249                 f = me.focusedChild;
250                 if (f)
251                 {
252                         me.enterSubitem(me, f);
253                         r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
254                         me.leaveSubitem(me);
255                         return r;
256                 }
257                 return 0;
258         }
259         float Container_mouseRelease(entity me, vector pos)
260         {
261                 entity f;
262                 float r;
263                 f = me.focusedChild;
264                 if (f)
265                 {
266                         me.enterSubitem(me, f);
267                         r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
268                         me.leaveSubitem(me);
269                         return r;
270                 }
271                 return 0;
272         }
273
274         void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
275         {
276                 me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
277         }
278
279         void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
280         {
281                 me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
282         }
283
284         void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
285         {
286                 if (other.parent) error("Can't add already added item!");
287
288                 if (other.focusable) me.focusable += 1;
289
290                 if (theSize.x > 1)
291                 {
292                         theOrigin.x -= 0.5 * (theSize.x - 1);
293                         theSize.x = 1;
294                 }
295                 if (theSize.y > 1)
296                 {
297                         theOrigin.y -= 0.5 * (theSize.y - 1);
298                         theSize.y = 1;
299                 }
300                 theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
301                 theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
302
303                 other.parent = me;
304                 other.Container_origin = theOrigin;
305                 other.Container_size = theSize;
306
307                 // don't call setAlphaOf, it would uneccessarily trigger showNotify
308                 //me.setAlphaOf(me, other, theAlpha);
309                 other.Container_alpha = theAlpha;
310
311                 entity l;
312                 l = me.lastChild;
313
314                 if (l) l.nextSibling = other;
315                 else me.firstChild = other;
316
317                 other.prevSibling = l;
318                 other.nextSibling = NULL;
319                 me.lastChild = other;
320         }
321
322         void Container_removeItem(entity me, entity other)
323         {
324                 if (other.parent != me) error("Can't remove from wrong container!");
325
326                 if (other.focusable) me.focusable -= 1;
327
328                 other.parent = NULL;
329
330                 entity n, p;
331                 n = other.nextSibling;
332                 p = other.prevSibling;
333
334                 if (p) p.nextSibling = n;
335                 else me.firstChild = n;
336
337                 if (n) n.prevSibling = p;
338                 else me.lastChild = p;
339         }
340
341         void Container_setFocus(entity me, entity other)
342         {
343                 if (me.focusedChild == other) return;
344
345                 if (me.focusedChild)
346                 {
347                         me.focusedChild.focused = 0;
348                         me.focusedChild.focusLeave(me.focusedChild);
349                         me.focusedChild = NULL;
350                 }
351
352                 if (other)
353                 {
354                         if (!me.focused) error("Trying to set focus in a non-focused control!");
355
356                         if (me.savedFocus)
357                         {
358                                 me.focusedChild = me.savedFocus;
359                                 me.savedFocus = NULL;
360                                 me.focusedChild.focused = 1;
361                                 me.focusedChild.focusEnter(me.focusedChild);
362
363                                 if (me.focusedChild.instanceOfContainer) me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
364                         }
365                         else
366                         {
367                                 me.focusedChild = other;
368                                 me.focusedChild.focused = 1;
369                                 me.focusedChild.focusEnter(me.focusedChild);
370                         }
371                 }
372         }
373
374         void Container_saveFocus(entity me)
375         {
376                 me.savedFocus = me.focusedChild;
377
378                 if (me.focusedChild.instanceOfContainer) me.focusedChild.saveFocus(me.focusedChild);
379         }
380
381         void Container_moveItemAfter(entity me, entity other, entity dest)
382         {
383                 // first: remove other from the chain
384                 entity n, p;
385
386                 if (other.parent != me) error("Can't move in wrong container!");
387
388                 n = other.nextSibling;
389                 p = other.prevSibling;
390
391                 if (p) p.nextSibling = n;
392                 else me.firstChild = n;
393
394                 if (n) n.prevSibling = p;
395                 else me.lastChild = p;
396
397                 // now other got removed. Insert it behind dest now.
398                 other.prevSibling = dest;
399                 if (dest) other.nextSibling = dest.nextSibling;
400                 else other.nextSibling = me.firstChild;
401
402                 if (dest) dest.nextSibling = other;
403                 else me.firstChild = other;
404
405                 if (other.nextSibling) other.nextSibling.prevSibling = other;
406                 else me.lastChild = other;
407         }
408
409         entity Container_preferredFocusedGrandChild(entity me)
410         {
411                 entity e, e2;
412                 entity best;
413
414                 best = NULL;
415
416                 for (e = me.firstChild; e; e = e.nextSibling)
417                 {
418                         if (e.instanceOfContainer)
419                         {
420                                 e2 = e.preferredFocusedGrandChild(e);
421                                 if (e2)
422                                         if (!best || best.preferredFocusPriority < e2.preferredFocusPriority) best = e2;
423                         }
424                         if (e)
425                                 if (!best || best.preferredFocusPriority < e.preferredFocusPriority) best = e;
426                 }
427
428                 return best;
429         }
430 #endif