]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu/item/container.c
yet another fteqcc bug workaround
[divverent/nexuiz.git] / data / qcsrc / menu / item / container.c
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))
13         METHOD(Container, addItem, void(entity, entity, vector, vector, float))
14         METHOD(Container, addItemCentered, void(entity, entity, vector, float))
15         METHOD(Container, moveItemAfter, void(entity, entity, entity))
16         METHOD(Container, removeItem, void(entity, entity))
17         METHOD(Container, setFocus, void(entity, entity))
18         METHOD(Container, setAlphaOf, void(entity, entity, float))
19         METHOD(Container, itemFromPoint, entity(entity, vector))
20         METHOD(Container, showNotify, void(entity))
21         METHOD(Container, hideNotify, void(entity))
22         METHOD(Container, preferredFocusedGrandChild, entity(entity))
23         ATTRIB(Container, focusable, float, 0)
24         ATTRIB(Container, firstChild, entity, NULL)
25         ATTRIB(Container, lastChild, entity, NULL)
26         ATTRIB(Container, focusedChild, entity, NULL)
27         ATTRIB(Container, shown, float, 0)
28 ENDCLASS(Container)
29 .entity nextSibling;
30 .entity prevSibling;
31 .float resized;
32 .vector Container_origin;
33 .vector Container_size;
34 .float Container_alpha;
35 #endif
36
37 #ifdef IMPLEMENTATION
38 void showNotifyContainer(entity me)
39 {
40         entity e;
41         if(me.shown)
42                 return;
43         me.shown = 1;
44         for(e = me.firstChild; e; e = e.nextSibling)
45                 if(e.Container_alpha > 0)
46                         e.showNotify(e);
47 }
48
49 void hideNotifyContainer(entity me)
50 {
51         entity e;
52         if not(me.shown)
53                 return;
54         me.shown = 0;
55         for(e = me.firstChild; e; e = e.nextSibling)
56                 if(e.Container_alpha > 0)
57                         e.hideNotify(e);
58 }
59
60 void setAlphaOfContainer(entity me, entity other, float theAlpha)
61 {
62         if(theAlpha <= 0)
63         {
64                 if(other.Container_alpha > 0)
65                         other.hideNotify(other);
66         }
67         else // value > 0
68         {
69                 if(other.Container_alpha <= 0)
70                         other.showNotify(other);
71         }
72         other.Container_alpha = theAlpha;
73 }
74
75 void resizeNotifyLieContainer(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField)
76 {
77         entity e;
78         vector o, s;
79         float d;
80         for(e = me.firstChild; e; e = e.nextSibling)
81         {
82                 o = e.originField;
83                 s = e.sizeField;
84                 e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
85         }
86         do
87         {
88                 d = 0;
89                 for(e = me.firstChild; e; e = e.nextSibling)
90                         if(e.resized)
91                         {
92                                 e.resized = 0;
93                                 d = 1;
94                                 o = e.originField;
95                                 s = e.sizeField;
96                                 e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
97                         }
98         }
99         while(d);
100         resizeNotifyItem(me, relOrigin, relSize, absOrigin, absSize);
101 }
102
103 void resizeNotifyContainer(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
104 {
105         me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size);
106 }
107
108 entity itemFromPointContainer(entity me, vector pos)
109 {
110         entity e;
111         vector o, s;
112         for(e = me.lastChild; e; e = e.prevSibling)
113         {
114                 o = e.Container_origin;
115                 s = e.Container_size;
116                 if(pos_x < o_x) continue;
117                 if(pos_y < o_y) continue;
118                 if(pos_x >= o_x + s_x) continue;
119                 if(pos_y >= o_y + s_y) continue;
120                 return e;
121         }
122         return NULL;
123 }
124
125 void drawContainer(entity me)
126 {
127         vector oldshift;
128         vector oldscale;
129         float oldalpha;
130         entity e;
131
132         oldshift = draw_shift;
133         oldscale = draw_scale;
134         oldalpha = draw_alpha;
135         me.focusable = 0;
136         for(e = me.firstChild; e; e = e.nextSibling)
137         {
138                 if(e.focusable)
139                         me.focusable += 1;
140                 if(e.Container_alpha < 0.003) // can't change color values anyway
141                         continue;
142                 draw_shift = boxToGlobal(e.Container_origin, oldshift, oldscale);
143                 draw_scale = boxToGlobalSize(e.Container_size, oldscale);
144                 draw_alpha *= e.Container_alpha;
145                 e.draw(e);
146                 draw_shift = oldshift;
147                 draw_scale = oldscale;
148                 draw_alpha = oldalpha;
149         }
150 };
151
152 void focusLeaveContainer(entity me)
153 {
154         me.setFocus(me, NULL);
155 }
156
157 float keyUpContainer(entity me, float scan, float ascii, float shift)
158 {
159         entity f;
160         f = me.focusedChild;
161         if(f)
162                 return f.keyUp(f, scan, ascii, shift);
163         return 0;
164 }
165
166 float keyDownContainer(entity me, float scan, float ascii, float shift)
167 {
168         entity f;
169         f = me.focusedChild;
170         if(f)
171                 return f.keyDown(f, scan, ascii, shift);
172         return 0;
173 }
174
175 float mouseMoveContainer(entity me, vector pos)
176 {
177         entity f;
178         f = me.focusedChild;
179         if(f)
180                 return f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
181         return 0;
182 }
183 float mousePressContainer(entity me, vector pos)
184 {
185         entity f;
186         f = me.focusedChild;
187         if(f)
188                 return f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
189         return 0;
190 }
191 float mouseDragContainer(entity me, vector pos)
192 {
193         entity f;
194         f = me.focusedChild;
195         if(f)
196                 return f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
197         return 0;
198 }
199 float mouseReleaseContainer(entity me, vector pos)
200 {
201         entity f;
202         f = me.focusedChild;
203         if(f)
204                 return f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
205         return 0;
206 }
207
208 void addItemCenteredContainer(entity me, entity other, vector theSize, float theAlpha)
209 {
210         me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
211 }
212
213 void addItemContainer(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
214 {
215         if(other.parent)
216                 error("Can't add already added item!");
217
218         if(other.focusable)
219                 me.focusable += 1;
220
221         if(theSize_x > 1)
222         {
223                 theOrigin_x -= 0.5 * (theSize_x - 1);
224                 theSize_x = 1;
225         }
226         if(theSize_y > 1)
227         {
228                 theOrigin_y -= 0.5 * (theSize_y - 1);
229                 theSize_y = 1;
230         }
231         theOrigin_x = bound(0, theOrigin_x, 1 - theSize_x);
232         theOrigin_y = bound(0, theOrigin_y, 1 - theSize_y);
233
234         other.parent = me;
235         other.Container_origin = theOrigin;
236         other.Container_size = theSize;
237         me.setAlphaOf(me, other, theAlpha);
238
239         entity f, l;
240         f = me.firstChild;
241         l = me.lastChild;
242
243         if(l)
244                 l.nextSibling = other;
245         else
246                 me.firstChild = other;
247
248         other.prevSibling = l;
249         other.nextSibling = NULL;
250         me.lastChild = other;
251
252         draw_NeedResizeNotify = 1;
253 }
254
255 void removeItemContainer(entity me, entity other)
256 {
257         if(other.parent != me)
258                 error("Can't remove from wrong container!");
259
260         if(other.focusable)
261                 me.focusable -= 1;
262
263         other.parent = NULL;
264
265         entity n, p, f, l;
266         f = me.firstChild;
267         l = me.lastChild;
268         n = other.nextSibling;
269         p = other.prevSibling;
270
271         if(p)
272                 p.nextSibling = n;
273         else
274                 me.firstChild = n;
275
276         if(n)
277                 n.prevSibling = p;
278         else
279                 me.lastChild = p;
280 }
281
282 void setFocusContainer(entity me, entity other)
283 {
284         if(other)
285                 if not(me.focused)
286                         error("Trying to set focus in a non-focused control!");
287         if(me.focusedChild == other)
288                 return;
289         //print(etos(me), ": focus changes from ", etos(me.focusedChild), " to ", etos(other), "\n");
290         if(me.focusedChild)
291         {
292                 me.focusedChild.focused = 0;
293                 me.focusedChild.focusLeave(me.focusedChild);
294         }
295         if(other)
296         {
297                 other.focused = 1;
298                 other.focusEnter(other);
299         }
300         me.focusedChild = other;
301 }
302
303 void moveItemAfterContainer(entity me, entity other, entity dest)
304 {
305         // first: remove other from the chain
306         entity n, p, f, l;
307
308         if(other.parent != me)
309                 error("Can't move in wrong container!");
310
311         f = me.firstChild;
312         l = me.lastChild;
313         n = other.nextSibling;
314         p = other.prevSibling;
315
316         if(p)
317                 p.nextSibling = n;
318         else
319                 me.firstChild = n;
320
321         if(n)
322                 n.prevSibling = p;
323         else
324                 me.lastChild = p;
325         
326         // now other got removed. Insert it behind dest now.
327         other.prevSibling = dest;
328         if(dest)
329                 other.nextSibling = dest.nextSibling;
330         else
331                 other.nextSibling = me.firstChild;
332
333         if(dest)
334                 dest.nextSibling = other;
335         else
336                 me.firstChild = other;
337
338         if(other.nextSibling)
339                 other.nextSibling.prevSibling = other;
340         else
341                 me.lastChild = other;
342 }
343
344 entity preferredFocusedGrandChildContainer(entity me)
345 {
346         entity e, e2;
347         entity best;
348
349         best = NULL;
350
351         for(e = me.firstChild; e; e = e.nextSibling)
352         {
353                 if(e.instanceOfContainer)
354                 {
355                         e2 = e.preferredFocusedGrandChild(e);
356                         if(e2)
357                                 if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
358                                         best = e2;
359                 }
360                 if(e)
361                         if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
362                                 best = e;
363         }
364
365         return best;
366 }
367 #endif