]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/container.qc
Merge branch 'master' into terencehill/hud_configure
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / container.qc
1 #ifdef INTERFACE
2 CLASS(Container) EXTENDS(Item)
3         METHOD(Container, draw, void(entity))
4         METHOD(Container, keyUp, float(entity, float, float, float))
5         METHOD(Container, keyDown, float(entity, float, float, float))
6         METHOD(Container, mouseMove, float(entity, vector))
7         METHOD(Container, mousePress, float(entity, vector))
8         METHOD(Container, mouseDrag, float(entity, vector))
9         METHOD(Container, mouseRelease, float(entity, vector))
10         METHOD(Container, focusLeave, void(entity))
11         METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector))
12         METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector))
13         METHOD(Container, addItem, void(entity, entity, vector, vector, float))
14         METHOD(Container, addItemCentered, void(entity, entity, vector, float))
15         METHOD(Container, addItemRightCentered, 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_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
285 {
286         me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
287 }
288
289 void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
290 {
291         if(other.parent)
292                 error("Can't add already added item!");
293
294         if(other.focusable)
295                 me.focusable += 1;
296
297         if(theSize.x > 1)
298         {
299                 theOrigin.x -= 0.5 * (theSize.x - 1);
300                 theSize.x = 1;
301         }
302         if(theSize.y > 1)
303         {
304                 theOrigin.y -= 0.5 * (theSize.y - 1);
305                 theSize.y = 1;
306         }
307         theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
308         theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
309
310         other.parent = me;
311         other.Container_origin = theOrigin;
312         other.Container_size = theSize;
313         me.setAlphaOf(me, other, theAlpha);
314
315         entity l;
316         l = me.lastChild;
317
318         if(l)
319                 l.nextSibling = other;
320         else
321                 me.firstChild = other;
322
323         other.prevSibling = l;
324         other.nextSibling = NULL;
325         me.lastChild = other;
326 }
327
328 void Container_removeItem(entity me, entity other)
329 {
330         if(other.parent != me)
331                 error("Can't remove from wrong container!");
332
333         if(other.focusable)
334                 me.focusable -= 1;
335
336         other.parent = NULL;
337
338         entity n, p;
339         n = other.nextSibling;
340         p = other.prevSibling;
341
342         if(p)
343                 p.nextSibling = n;
344         else
345                 me.firstChild = n;
346
347         if(n)
348                 n.prevSibling = p;
349         else
350                 me.lastChild = p;
351 }
352
353 void Container_setFocus(entity me, entity other)
354 {
355         if(me.focusedChild == other)
356                 return;
357
358         if(me.focusedChild)
359         {
360                 me.focusedChild.focused = 0;
361                 me.focusedChild.focusLeave(me.focusedChild);
362                 me.focusedChild = NULL;
363         }
364
365         if(other)
366         {
367                 if(!me.focused)
368                         error("Trying to set focus in a non-focused control!");
369
370                 if(me.savedFocus)
371                 {
372                         me.focusedChild = me.savedFocus;
373                         me.savedFocus = NULL;
374                         me.focusedChild.focused = 1;
375                         me.focusedChild.focusEnter(me.focusedChild);
376
377                         if(me.focusedChild.instanceOfContainer)
378                                 me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
379                 }
380                 else
381                 {
382                         me.focusedChild = other;
383                         me.focusedChild.focused = 1;
384                         me.focusedChild.focusEnter(me.focusedChild);
385                 }
386         }
387 }
388
389 void Container_saveFocus(entity me)
390 {
391         me.savedFocus = me.focusedChild;
392
393         if(me.focusedChild.instanceOfContainer)
394                 me.focusedChild.saveFocus(me.focusedChild);
395 }
396
397 void Container_moveItemAfter(entity me, entity other, entity dest)
398 {
399         // first: remove other from the chain
400         entity n, p;
401
402         if(other.parent != me)
403                 error("Can't move in wrong container!");
404
405         n = other.nextSibling;
406         p = other.prevSibling;
407
408         if(p)
409                 p.nextSibling = n;
410         else
411                 me.firstChild = n;
412
413         if(n)
414                 n.prevSibling = p;
415         else
416                 me.lastChild = p;
417
418         // now other got removed. Insert it behind dest now.
419         other.prevSibling = dest;
420         if(dest)
421                 other.nextSibling = dest.nextSibling;
422         else
423                 other.nextSibling = me.firstChild;
424
425         if(dest)
426                 dest.nextSibling = other;
427         else
428                 me.firstChild = other;
429
430         if(other.nextSibling)
431                 other.nextSibling.prevSibling = other;
432         else
433                 me.lastChild = other;
434 }
435
436 entity Container_preferredFocusedGrandChild(entity me)
437 {
438         entity e, e2;
439         entity best;
440
441         best = NULL;
442
443         for(e = me.firstChild; e; e = e.nextSibling)
444         {
445                 if(e.instanceOfContainer)
446                 {
447                         e2 = e.preferredFocusedGrandChild(e);
448                         if(e2)
449                                 if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
450                                         best = e2;
451                 }
452                 if(e)
453                         if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
454                                 best = e;
455         }
456
457         return best;
458 }
459 #endif