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