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