1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // gui_events.c
22 //
23
24 #include "gui_local.h"
25
26 /*
27 =============================================================================
28
29 NAMED EVENTS
30
31 =============================================================================
32 */
33
34 /*
35 ==================
36 GUI_QueueWindowNamedEvent
37
38 Queues a named event to trigger on a specified window.
39 ==================
40 */
GUI_QueueWindowNamedEvent(gui_t * gui,char * name,qBool warn)41 static void GUI_QueueWindowNamedEvent (gui_t *gui, char *name, qBool warn)
42 {
43 event_t *event;
44 int i;
45
46 assert (name && name[0]);
47 if (!name || !name[0])
48 return;
49
50 // Only send if the window is visible
51 if (!FRVALUE (gui, FR_VISIBLE)
52 || FRVALUE (gui, FR_NO_EVENTS))
53 return;
54
55 // Find it in the event list
56 for (i=0, event=&gui->eventList[0] ; i<gui->numEvents ; event++, i++) {
57 if (event->type != WEV_NAMED)
58 continue;
59 if (Q_stricmp (name, event->named))
60 continue;
61 break;
62 }
63
64 // Not found
65 if (i == gui->numEvents) {
66 if (warn)
67 Com_Printf (PRNT_WARNING, "WARNING: Named event '%s' not found in '%s'\n", name, gui->name);
68 return;
69 }
70
71 // No room!
72 if (gui->numQueued+1 >= MAX_GUI_EVENTS)
73 return;
74
75 // Make sure it's not already queued
76 for (i=0 ; i<gui->numQueued ; i++) {
77 if (gui->queueList[i] == event)
78 return;
79 }
80
81 // Append
82 gui->queueList[gui->numQueued++] = event;
83 }
84
85
86 /*
87 ==================
88 GUI_NamedGlobalEvent
89
90 Affects all opened GUIs.
91 ==================
92 */
GUI_NamedGlobalEvent(char * name)93 void GUI_NamedGlobalEvent (char *name)
94 {
95 gui_t *gui;
96 int i;
97
98 // Recurse through each open GUI and apply
99 for (i=0, gui=cl_guiState.openLayers[0] ; i<cl_guiState.numLayers ; gui++, i++)
100 GUI_NamedGUIEvent (gui, name);
101 }
102
103
104 /*
105 ==================
106 GUI_NamedGUIEvent
107
108 Affects only the specified GUI.
109 ==================
110 */
GUI_NamedGUIEvent(gui_t * gui,char * name)111 void GUI_NamedGUIEvent (gui_t *gui, char *name)
112 {
113 gui_t *child;
114 int i;
115
116 // Queue any matching events
117 GUI_QueueWindowNamedEvent (gui, name, qFalse);
118
119 // Recurse down the children
120 for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++)
121 GUI_NamedGUIEvent (child, name);
122 }
123
124 /*
125 =============================================================================
126
127 ACTION PROCESSING
128
129 =============================================================================
130 */
131
132 /*
133 ==================
134 GUI_SetAction
135 ==================
136 */
GUI_SetAction(gui_t * gui,eva_set_t * setAction)137 static void GUI_SetAction (gui_t *gui, eva_set_t *setAction)
138 {
139 gui_t *queueWindow;
140 int queueEvent;
141 int i;
142
143 if (!setAction->destWindowPtr)
144 return;
145
146 queueEvent = WEV_NONE;
147
148 switch (setAction->destType) {
149 case EVA_SETDEST_FLOAT|EVA_SETDEST_STORAGE:
150 switch (setAction->destRegister) {
151 case FR_VISIBLE:
152 if (FRVALUE (setAction->destWindowPtr, setAction->destRegister) != setAction->srcStorage[0]) {
153 gui->shared->cursor.mouseMoved = qTrue;
154 queueWindow = setAction->destWindowPtr;
155 if (FRVALUE (setAction->destWindowPtr, setAction->destRegister))
156 queueEvent = WEV_INIT;
157 else
158 queueEvent = WEV_SHUTDOWN;
159 }
160 break;
161 }
162
163 switch (setAction->srcType) {
164 case EVA_SETSRC_STORAGE:
165 setAction->destWindowPtr->d.floatRegisters[setAction->destRegister].storage = setAction->srcStorage[0];
166 setAction->destWindowPtr->d.floatRegisters[setAction->destRegister].var = &setAction->destWindowPtr->d.floatRegisters[setAction->destRegister].storage;
167 break;
168 case EVA_SETSRC_DEF:
169 break;
170 case EVA_SETSRC_GUIVAR:
171 break;
172 }
173 break;
174
175 case EVA_SETDEST_VEC|EVA_SETDEST_STORAGE:
176 for (i=0 ; i<setAction->destNumVecs ; i++)
177 setAction->destWindowPtr->d.vecRegisters[setAction->destRegister].storage[i] = setAction->srcStorage[i];
178
179 setAction->destWindowPtr->d.vecRegisters[setAction->destRegister].var = setAction->destWindowPtr->d.vecRegisters[setAction->destRegister].storage;
180 break;
181
182 case EVA_SETDEST_FLOAT|EVA_SETDEST_DEF:
183 break;
184
185 case EVA_SETDEST_VEC|EVA_SETDEST_DEF:
186 break;
187
188 default:
189 assert (0);
190 break;
191 }
192
193 // Trigger events
194 if (queueEvent != WEV_NONE)
195 GUI_QueueTrigger (queueWindow, queueEvent);
196 }
197
198
199 /*
200 ==================
201 GUI_RunEvent
202
203 Processes event actions.
204 ==================
205 */
GUI_RunEvent(gui_t * gui,event_t * event)206 static void GUI_RunEvent (gui_t *gui, event_t *event)
207 {
208 evAction_t *action;
209 int i;
210
211 for (i=0, action=event->actionList ; i<event->numActions ; action++, i++) {
212 switch (action->type) {
213 case EVA_CLOSE:
214 gui->shared->queueClose = qTrue;
215 break;
216
217 case EVA_COMMAND:
218 assert (action->command && action->command[0]);
219 Cbuf_AddText (action->command);
220 break;
221
222 case EVA_IF:
223 break;
224
225 case EVA_LOCAL_SOUND:
226 Snd_StartLocalSound (action->localSound->sound, action->localSound->volume);
227 break;
228
229 case EVA_NAMED_EVENT:
230 GUI_QueueWindowNamedEvent (action->named->destWindowPtr, action->named->eventName, qTrue);
231 break;
232
233 case EVA_RESET_TIME:
234 gui->openTime = Sys_UMilliseconds () - action->resetTime;
235 gui->time = gui->lastTime = action->resetTime;
236 break;
237
238 case EVA_SET:
239 GUI_SetAction (gui, action->set);
240 break;
241
242 case EVA_STOP_TRANSITIONS:
243 break;
244 case EVA_TRANSITION:
245 break;
246 }
247 }
248 }
249
250 /*
251 =============================================================================
252
253 DEFAULT EVENTS
254
255 =============================================================================
256 */
257
258 /*
259 ==================
260 GUI_CheckDefDefault
261 ==================
262 */
GUI_CheckDefDefault(gui_t * gui,evType_t type)263 static void GUI_CheckDefDefault (gui_t *gui, evType_t type)
264 {
265 switch (type) {
266 case WEV_ACTION:
267 if (gui->d.checkDef->liveUpdate) {
268 if (!Q_stricmp (gui->d.checkDef->cvar->string, gui->d.checkDef->values[0]))
269 Cvar_VariableSet (gui->d.checkDef->cvar, gui->d.checkDef->values[1], qFalse);
270 else
271 Cvar_VariableSet (gui->d.checkDef->cvar, gui->d.checkDef->values[0], qFalse);
272 }
273 else {
274 assert (0);
275 }
276 break;
277 }
278 }
279
280 /*
281 =============================================================================
282
283 EVENT QUEUE
284
285 Events can be saved here as "triggers", so that on the next render call
286 they will trigger the appropriate event.
287 =============================================================================
288 */
289
290 /*
291 ==================
292 GUI_TriggerEvents
293
294 Triggers any queued events, along with the per-frame and time-based events.
295 ==================
296 */
GUI_TriggerEvents(gui_t * gui)297 void GUI_TriggerEvents (gui_t *gui)
298 {
299 gui_t *child;
300 event_t *event;
301 int i;
302
303 if (!FRVALUE (gui, FR_VISIBLE)
304 || FRVALUE (gui, FR_NO_EVENTS)) {
305 // Clear default events
306 gui->numDefaultQueued = 0;
307
308 // Clear queued triggers
309 gui->numQueued = 0;
310 return;
311 }
312
313 // Update time
314 gui->time = Sys_UMilliseconds () - gui->openTime;
315
316 // FIXME: something needs to be done about uint32 wrapping!!
317 /*if (gui->lastTime > gui->time) {
318 gui->lastTime = gui->time;
319 }*/
320
321 // Process events
322 for (i=0, event=gui->eventList ; i<gui->numEvents ; event++, i++) {
323 // This is triggered every frame
324 if (event->type == WEV_FRAME) {
325 GUI_RunEvent (gui, event);
326 continue;
327 }
328
329 // Time-based triggers
330 if (event->type == WEV_TIME) {
331 if (event->onTime >= gui->lastTime && event->onTime < gui->time)
332 GUI_RunEvent (gui, event);
333 continue;
334 }
335 break;
336 }
337
338 // Fire queued triggers
339 for (i=0 ; i<gui->numQueued ; i++)
340 GUI_RunEvent (gui, gui->queueList[i]);
341 gui->numQueued = 0;
342
343 // Fire default events
344 for (i=0 ; i<gui->numDefaultQueued ; i++) {
345 switch (gui->type) {
346 case WTP_CHECKBOX:
347 GUI_CheckDefDefault (gui, gui->defaultQueueList[i]);
348 break;
349 }
350 }
351 gui->numDefaultQueued = 0;
352
353 // Store the current time for the next trip
354 gui->lastTime = gui->time;
355
356 // Recurse down the children
357 for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++)
358 GUI_TriggerEvents (child);
359 }
360
361
362 /*
363 ==================
364 GUI_QueueTrigger
365 ==================
366 */
GUI_QueueTrigger(gui_t * gui,evType_t type)367 void GUI_QueueTrigger (gui_t *gui, evType_t type)
368 {
369 gui_t *child;
370 event_t *event;
371 int i;
372
373 if (!gui)
374 return;
375
376 // Mouse enter/exit is sent every frame, regardless of the state actually changing
377 // or not. This is purely to make the exit event as reliable as possible.
378 switch (type) {
379 case WEV_ACTION:
380 break;
381
382 case WEV_ESCAPE:
383 break;
384
385 case WEV_INIT:
386 if (gui->inited)
387 return;
388 gui->inited = qTrue;
389 break;
390
391 case WEV_SHUTDOWN:
392 if (!gui->inited)
393 return;
394 gui->inited = qFalse;
395
396 GUI_QueueTrigger (gui, WEV_MOUSE_EXIT);
397 for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++)
398 GUI_QueueTrigger (child, WEV_SHUTDOWN);
399 break;
400
401 case WEV_MOUSE_ENTER:
402 if (gui->mouseEntered && !gui->mouseExited)
403 return;
404 gui->mouseEntered = qTrue;
405 gui->mouseExited = qFalse;
406 break;
407
408 case WEV_MOUSE_EXIT:
409 if (!gui->mouseEntered && gui->mouseExited)
410 return;
411 gui->mouseEntered = qFalse;
412 gui->mouseExited = qTrue;
413 break;
414
415 case WEV_NAMED:
416 // These are queued up elsewhere!
417 assert (0);
418 return;
419
420 case WEV_FRAME:
421 case WEV_TIME:
422 // These should *NEVER* be queued!!
423 // They're forcibly ran in GUI_TriggerEvents at the beginning of every frame anyways!
424 assert (0);
425 return;
426
427 default:
428 // Should never happen!
429 assert (0);
430 return;
431 }
432
433 // Add to default action list (if not found already)
434 for (i=0 ; i<gui->numDefaultQueued ; i++) {
435 if (gui->defaultQueueList[i] == type)
436 break;
437 }
438 if (i == gui->numDefaultQueued) {
439 if (gui->numDefaultQueued < MAX_GUI_EVENTS)
440 gui->defaultQueueList[gui->numDefaultQueued++] = type;
441 }
442
443 // Find it in the event list
444 for (i=0, event=&gui->eventList[0] ; i<gui->numEvents ; event++, i++) {
445 if (event->type == type)
446 break;
447 }
448 if (i == gui->numEvents)
449 return; // Not found
450
451 // If already in the list, ignore
452 for (i=0 ; i<gui->numQueued ; i++) {
453 if (gui->queueList[i] == event)
454 return;
455 }
456
457 // Append
458 if (gui->numQueued < MAX_GUI_EVENTS)
459 gui->queueList[gui->numQueued++] = event;
460
461 // Update
462 gui->shared->cursor.mouseMoved = qTrue;
463
464 // Post-process sub-triggers
465 switch (type) {
466 case WEV_INIT:
467 for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++)
468 GUI_QueueTrigger (child, WEV_INIT);
469 GUI_QueueTrigger (gui, WEV_MOUSE_ENTER);
470 break;
471 }
472 }
473