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