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