]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/item/modalcontroller.c
added checkbox, radio button; removed unnecessary setFocus override in Nexposee and...
[divverent/nexuiz.git] / data / qcsrc / menu-div0test / item / modalcontroller.c
1 #ifdef INTERFACE
2 CLASS(ModalController) EXTENDS(Container)
3         METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector))
4         METHOD(ModalController, draw, void(entity))
5         METHOD(ModalController, addItem, void(entity, entity, vector, vector, float))
6         METHOD(ModalController, showChild, void(entity, entity, vector, vector, float))
7         METHOD(ModalController, hideChild, void(entity, entity, float))
8         METHOD(ModalController, hideAll, void(entity, float))
9         METHOD(ModalController, addItem, void(entity, entity, vector, vector, float))
10         METHOD(ModalController, addTab, void(entity, entity, entity))
11
12         METHOD(ModalController, initializeDialog, void(entity, entity))
13
14         METHOD(ModalController, switchState, void(entity, entity, float, float))
15         ATTRIB(ModalController, origin, vector, '0 0 0')
16         ATTRIB(ModalController, size, vector, '0 0 0')
17         ATTRIB(ModalController, previousButton, entity, NULL)
18         ATTRIB(ModalController, fadedAlpha, float, 0.3)
19 ENDCLASS(ModalController)
20
21 .vector origin;
22 .vector size;
23 void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
24 void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
25 void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
26 #endif
27
28 #ifdef IMPLEMENTATION
29
30 // modal dialog controller
31 // handles a stack of dialog elements
32 // each element can have one of the following states:
33 //   0: hidden (fading out)
34 //   1: visible (zooming in)
35 //   2: greyed out (inactive)
36 // While an animation is running, no item has focus. When an animation is done,
37 // the topmost item gets focus.
38 // The items are assumed to be added in overlapping order, that is, the lowest
39 // window must get added first.
40 //
41 // Possible uses:
42 // - to control a modal dialog:
43 //   - show modal dialog: me.showChild(me, childItem, buttonAbsOrigin, buttonAbsSize, 0) // childItem also gets focus
44 //   - dismiss modal dialog: me.hideChild(me, childItem, 0) // childItem fades out and relinquishes focus
45 //   - show first screen in m_show: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
46 // - to show a temporary dialog instead of the menu (teamselect): me.hideAll(me, 1); me.showChild(me, teamSelectDialog, '0 0 0', '0 0 0', 1);
47 // - as a tabbed dialog control:
48 //   - to initialize: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
49 //   - to show a tab: me.hideChild(me, currentTab, 0); me.showChild(me, newTab, buttonAbsOrigin, buttonAbsSize, 0);
50
51 .vector ModalController_initialSize;
52 .vector ModalController_initialOrigin;
53 .float ModalController_initialAlpha;
54 .vector ModalController_buttonSize;
55 .vector ModalController_buttonOrigin;
56 .float ModalController_state;
57 .float ModalController_factor;
58 .entity ModalController_controllingButton;
59
60 void initializeDialogModalController(entity me, entity root)
61 {
62         me.hideAll(me, 1);
63         me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
64 }
65
66 void TabButton_Click(entity button, entity tab)
67 {
68         if(tab.ModalController_state == 1)
69                 return;
70         tab.parent.hideAll(tab.parent, 0);
71         button.forcePressed = 1;
72         tab.ModalController_controllingButton = button;
73         tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
74 }
75
76 void DialogOpenButton_Click(entity button, entity tab)
77 {
78         if(tab.ModalController_state)
79                 return;
80         button.forcePressed = 1;
81         tab.ModalController_controllingButton = button;
82         tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
83 }
84
85 void DialogCloseButton_Click(entity button, entity tab)
86 {
87         tab.parent.hideChild(tab.parent, tab, 0);
88 }
89
90 void resizeNotifyModalController(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
91 {
92         me.origin = absOrigin;
93         me.size = absSize;
94         me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize);
95 }
96
97 void switchStateModalController(entity me, entity other, float state, float skipAnimation)
98 {
99         float previousState;
100         previousState = other.ModalController_state;
101         if(state == previousState)
102                 return;
103         other.ModalController_state = state;
104         switch(state)
105         {
106                 case 0:
107                         other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
108                         // fading out
109                         break;
110                 case 1:
111                         other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
112                         if(previousState == 0 && !skipAnimation)
113                         {
114                                 other.Container_origin = other.ModalController_buttonOrigin;
115                                 other.Container_size = other.ModalController_buttonSize;
116                         }
117                         // zooming in
118                         break;
119                 case 2:
120                         other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
121                         // fading out halfway
122                         break;
123         }
124         if(skipAnimation)
125                 other.ModalController_factor = 1;
126 }
127
128 void drawModalController(entity me)
129 {
130         // TODO set up alpha, sizes and focus
131         entity e;
132         entity front;
133         float animating;
134         float f; // animation factor
135         float df; // animation step size
136         float prevFactor, targetFactor;
137         vector targetOrigin, targetSize; float targetAlpha;
138         animating = 0;
139
140         for(e = me.firstChild; e; e = e.Container_nextSibling)
141                 if(e.ModalController_state)
142                 {
143                         if(front)
144                                 me.switchState(me, front, 2, 0);
145                         front = e;
146                 }
147         if(front)
148                 me.switchState(me, front, 1, 0);
149
150         df = frametime * 3; // animation speed
151
152         for(e = me.firstChild; e; e = e.Container_nextSibling)
153         {
154                 f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
155                 if(e.ModalController_state)
156                         if(f < 1)
157                                 animating = 1;
158
159                 if(f < 1)
160                 {
161                         prevFactor   = (1 - f) / (1 - f + df);
162                         targetFactor =     df  / (1 - f + df);
163                 }
164                 else
165                 {
166                         prevFactor = 0;
167                         targetFactor = 1;
168                 }
169
170                 if(e.ModalController_state == 2)
171                 {
172                         // fading out partially
173                         targetOrigin = e.Container_origin; // stay as is
174                         targetSize = e.Container_size; // stay as is
175                         targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
176                 }
177                 else if(e.ModalController_state == 1)
178                 {
179                         // zooming in
180                         targetOrigin = e.ModalController_initialOrigin;
181                         targetSize = e.ModalController_initialSize;
182                         targetAlpha = e.ModalController_initialAlpha;
183                 }
184                 else
185                 {
186                         // fading out
187                         if(f < 1)
188                                 animating = 1;
189                         targetOrigin = e.Container_origin; // stay as is
190                         targetSize = e.Container_size; // stay as is
191                         targetAlpha = 0;
192                 }
193
194                 if(f == 1)
195                 {
196                         e.Container_origin = targetOrigin;
197                         e.Container_size = targetSize;
198                         e.Container_alpha = targetAlpha;
199                 }
200                 else
201                 {
202                         e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
203                         e.Container_size   = e.Container_size   * prevFactor + targetSize   * targetFactor;
204                         e.Container_alpha  = e.Container_alpha  * prevFactor + targetAlpha  * targetFactor;
205                 }
206                 // assume: o == to * f_prev + X * (1 - f_prev)
207                 // make:   o' = to * f  + X * (1 - f)
208                 // -->
209                 // X == (o - to * f_prev) / (1 - f_prev)
210                 // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
211                 // --> (maxima)
212                 // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
213         }
214         if(animating || !me.focused)
215                 me.setFocus(me, NULL);
216         else
217                 me.setFocus(me, front);
218         drawContainer(me);
219 };
220
221 void addTabModalController(entity me, entity other, entity tabButton)
222 {
223         me.addItem(me, other, '0 0 0', '1 1 1', 1);
224         tabButton.onClick = TabButton_Click;
225         tabButton.onClickEntity = other;
226         if(other == me.firstChild)
227         {
228                 tabButton.forcePressed = 1;
229                 other.ModalController_controllingButton = tabButton;
230                 me.showChild(me, other, '0 0 0', '0 0 0', 1);
231         }
232 }
233
234 void addItemModalController(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
235 {
236         other.ModalController_initialSize = theSize;
237         other.ModalController_initialOrigin = theOrigin;
238         other.ModalController_initialAlpha = theAlpha;
239         addItemContainer(me, other, theOrigin, theSize, theAlpha);
240         if(other != me.firstChild)
241                 other.Container_alpha = 0;
242 }
243
244 void showChildModalController(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
245 {
246         if(other.ModalController_state == 0)
247         {
248                 me.setFocus(me, NULL);
249                 other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
250                 other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
251                 me.switchState(me, other, 1, skipAnimation);
252         } // zoom in from button (factor increases)
253 }
254
255 void hideAllModalController(entity me, float skipAnimation)
256 {
257         entity e;
258         for(e = me.firstChild; e; e = e.Container_nextSibling)
259                 me.hideChild(me, e, skipAnimation);
260 }
261
262 void hideChildModalController(entity me, entity other, float skipAnimation)
263 {
264         if(other.ModalController_state)
265         {
266                 me.setFocus(me, NULL);
267                 me.switchState(me, other, 0, skipAnimation);
268                 if(other.ModalController_controllingButton)
269                 {
270                         other.ModalController_controllingButton.forcePressed = 0;
271                         other.ModalController_controllingButton = NULL;
272                 }
273         } // just alpha fade out (factor increases and decreases alpha)
274 }
275 #endif