]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu/menu.qc
demo browser
[divverent/nexuiz.git] / data / qcsrc / menu / menu.qc
1 ///////////////////////////////////////////////
2 // Menu Source File
3 ///////////////////////
4 // This file belongs to dpmod/darkplaces
5 // AK contains all menu functions (especially the required ones)
6 ///////////////////////////////////////////////
7
8 float mouseButtonsPressed;
9 vector menuMousePos;
10 float menuShiftState;
11 float menuPrevTime;
12 float menuAlpha;
13 float menuLogoAlpha;
14 float prevMenuAlpha;
15 float menuInitialized;
16 float menuNotTheFirstFrame;
17 float menuMouseMode;
18
19 void SUB_Null() { };
20
21 void() m_init =
22 {
23         dprint_load();
24 }
25
26 void UpdateConWidthHeight()
27 {
28         float conwidth_s, conheight_s;
29         conwidth_s = conwidth;
30         conheight_s = conheight;
31         conwidth = cvar("vid_conwidth");
32         conheight = cvar("vid_conheight");
33         if(conwidth < 800)
34         {
35                 conheight *= 800 / conwidth;
36                 conwidth = 800;
37         }
38         if(conheight < 600)
39         {
40                 conwidth *= 600 / conheight;
41                 conheight = 600;
42         }
43         if(main)
44         {
45                 if(conwidth_s != conwidth || conheight_s != conheight)
46                 {
47                         draw_reset();
48                         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
49                 }
50         }
51 }
52
53 void() m_init_delayed =
54 {
55         float fh, glob, n, i;
56         string s;
57
58         dprint_load();
59
60         menuInitialized = 0;
61         if(!preMenuInit())
62                 return;
63         menuInitialized = 1;
64         GameCommand_Init();
65
66         fh = -1;
67         if(cvar_string("menu_skin") != "")
68         {
69                 draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
70                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
71         }
72         if(fh < 0)
73         if(cvar_defstring("menu_skin") != "")
74         {
75                 draw_currentSkin = strcat("gfx/menu/", cvar_defstring("menu_skin"));
76                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
77         }
78         if(fh < 0)
79         {
80                 draw_currentSkin = "gfx/menu/default";
81                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
82         }
83         draw_currentSkin = strzone(draw_currentSkin);
84         while((s = fgets(fh)))
85         {
86                 // these two are handled by skinlist.qc
87                 if(substring(s, 0, 6) == "title ")
88                         continue;
89                 if(substring(s, 0, 7) == "author ")
90                         continue;
91                 n = tokenize_sane(s);
92                 if(n >= 2)
93                         Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
94         }
95         fclose(fh);
96
97         glob = search_begin(strcat(draw_currentSkin, "/*.tga"), TRUE, TRUE);
98         if(glob >= 0)
99         {
100                 n = search_getsize(glob);
101                 for(i = 0; i < n; ++i)
102                         precache_pic(search_getfilename(glob, i));
103                 search_end(glob);
104         }
105
106         draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
107
108         conwidth = conheight = -1;
109         draw_reset();
110         UpdateConWidthHeight();
111         main = spawnMainWindow(); main.configureMainWindow(main);
112         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
113         main.focused = 1;
114         menuShiftState = 0;
115         menuMousePos = '0.5 0.5 0';
116
117         if(Menu_Active)
118                 m_display(); // delayed menu display
119 };
120
121 void(float key, float ascii) m_keyup =
122 {
123         if(!menuInitialized)
124                 return;
125         if(!Menu_Active)
126                 return;
127         draw_reset();
128         main.keyUp(main, key, ascii, menuShiftState);
129         if(key >= K_MOUSE1 && key <= K_MOUSE3)
130         {
131                 --mouseButtonsPressed;
132                 if(!mouseButtonsPressed)
133                         main.mouseRelease(main, menuMousePos);
134                 if(mouseButtonsPressed < 0)
135                 {
136                         mouseButtonsPressed = 0;
137                         print("Warning: released an already released button\n");
138                 }
139         }
140         if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);
141         if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);
142         if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);
143 };
144
145 void(float key, float ascii) m_keydown =
146 {
147         if(!menuInitialized)
148                 return;
149         if(!Menu_Active)
150                 return;
151         if(keyGrabber)
152         {
153                 entity e;
154                 e = keyGrabber;
155                 keyGrabber = NULL;
156                 e.keyGrabbed(e, key, ascii);
157         }
158         else
159         {
160                 draw_reset();
161                 if(key >= K_MOUSE1 && key <= K_MOUSE3)
162                         if(!mouseButtonsPressed)
163                                 main.mousePress(main, menuMousePos);
164                 if(!main.keyDown(main, key, ascii, menuShiftState))
165                         if(key == K_ESCAPE)
166                                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
167                                         m_hide(); // disable menu on unhandled ESC
168         }
169         if(key >= K_MOUSE1 && key <= K_MOUSE3)
170         {
171                 ++mouseButtonsPressed;
172                 if(mouseButtonsPressed > 10)
173                 {
174                         mouseButtonsPressed = 10;
175                         print("Warning: pressed an already pressed button\n");
176                 }
177         }
178         if(key == K_ALT) menuShiftState |= S_ALT;
179         if(key == K_CTRL) menuShiftState |= S_CTRL;
180         if(key == K_SHIFT) menuShiftState |= S_SHIFT;
181 };
182
183 void(string img, float a) drawBackground =
184 {
185         vector sz;
186         vector isz;
187         sz = draw_PictureSize(img);
188         // keep aspect of image
189         if(sz_x * draw_scale_y >= sz_y * draw_scale_x)
190         {
191                 // that is, sz_x/sz_y >= draw_scale_x/draw_scale_y
192                 // match up the height
193                 isz_y = 1;
194                 isz_x = isz_y * (sz_x / sz_y) * (draw_scale_y / draw_scale_x);
195         }
196         else
197         {
198                 // that is, sz_x/sz_y <= draw_scale_x/draw_scale_y
199                 // match up the width
200                 isz_x = 1;
201                 isz_y = isz_x * (sz_y / sz_x) * (draw_scale_x / draw_scale_y);
202         }
203         draw_Picture('0.5 0.5 0' - 0.5 * isz, img, isz, '1 1 1', a);
204 }
205
206 void() m_draw =
207 {
208         float t;
209         float realFrametime;
210
211         menuMouseMode = cvar("menu_mouse_absolute");
212
213         if(main)
214                 UpdateConWidthHeight();
215
216         if(!menuInitialized)
217         {
218                 // TODO draw an info image about this situation
219                 m_init_delayed();
220                 return;
221         }
222         if(!menuNotTheFirstFrame)
223         {
224                 menuNotTheFirstFrame = 1;
225                 if(Menu_Active)
226                 if(!cvar("menu_video_played"))
227                 {
228                         localcmd("set menu_video_played 1; cd loop $menu_cdtrack; play sound/announcer/male/welcome.ogg\n");
229                         menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading
230                 }
231         }
232
233         t = gettime();
234         realFrametime = frametime = min(0.2, t - menuPrevTime);
235         menuPrevTime = t;
236         time += frametime;
237
238         t = cvar("menu_slowmo");
239         if(t)
240         {
241                 frametime *= t;
242                 realFrametime *= t;
243         }
244         else
245                 t = 1;
246
247         if(Menu_Active)
248         {
249                 if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
250                         setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
251                 else
252                         m_hide();
253         }
254
255         if(cvar("cl_capturevideo"))
256                 frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
257
258         dprint_load();
259         gamestatus = 0;
260         if(isserver())
261                 gamestatus = gamestatus | GAME_ISSERVER;
262         if(clientstate() == CS_CONNECTED)
263                 gamestatus = gamestatus | GAME_CONNECTED;
264         if(cvar("developer"))
265                 gamestatus = gamestatus | GAME_DEVELOPER;
266
267         prevMenuAlpha = menuAlpha;
268         if(Menu_Active)
269         {
270                 if(menuAlpha == 0 && menuLogoAlpha < 2)
271                 {
272                         menuLogoAlpha = menuLogoAlpha + frametime * 2;
273                 }
274                 else
275                 {
276                         menuAlpha = min(1, menuAlpha + frametime * 5);
277                         menuLogoAlpha = 2;
278                 }
279         }
280         else
281         {
282                 menuAlpha = max(0, menuAlpha - frametime * 5);
283                 menuLogoAlpha = 2;
284         }
285
286         draw_reset();
287
288         if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
289         {
290                 if(menuLogoAlpha > 0)
291                 {
292                         drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1));
293                         if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
294                         {
295                                 draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);
296                                 draw_drawMousePointer(menuMousePos);
297                                 draw_alpha = 1;
298                         }
299                 }
300         }
301         else if(SKINALPHA_BACKGROUND_INGAME)
302         {
303                 if(menuAlpha > 0)
304                         drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME);
305         }
306
307         draw_reset();
308         preMenuDraw();
309         draw_reset();
310
311         if(menuAlpha <= 0)
312         {
313                 if(prevMenuAlpha > 0)
314                         main.initializeDialog(main, main.firstChild);
315                 draw_reset();
316                 postMenuDraw();
317                 return;
318         }
319
320         draw_alpha *= menuAlpha;
321
322         if(menuMouseMode)
323         {
324                 vector newMouse;
325                 newMouse = globalToBoxSize(getmousepos(), draw_scale);
326                 if(newMouse != '0 0 0')
327                         if(newMouse != menuMousePos)
328                         {
329                                 menuMousePos = newMouse;
330                                 if(mouseButtonsPressed)
331                                         main.mouseDrag(main, menuMousePos);
332                                 else
333                                         main.mouseMove(main, menuMousePos);
334                         }
335         }
336         else
337         {
338                 if(frametime > 0)
339                 {
340                         vector dMouse;
341                         dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
342                         if(dMouse != '0 0 0')
343                         {
344                                 dMouse = globalToBoxSize(dMouse, draw_scale);
345                                 menuMousePos += dMouse * cvar("menu_mouse_speed");
346                                 menuMousePos_x = bound(0, menuMousePos_x, 1);
347                                 menuMousePos_y = bound(0, menuMousePos_y, 1);
348                                 if(mouseButtonsPressed)
349                                         main.mouseDrag(main, menuMousePos);
350                                 else
351                                         main.mouseMove(main, menuMousePos);
352                         }
353                 }
354         }
355         main.draw(main);
356         draw_alpha = max(draw_alpha, SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1));
357
358         draw_drawMousePointer(menuMousePos);
359
360         draw_reset();
361         postMenuDraw();
362
363         frametime = 0;
364 };
365
366 void() m_display =
367 {
368         Menu_Active = true;
369         setkeydest(KEY_MENU);
370         setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));
371
372         if(!menuInitialized)
373                 return;
374
375         if(mouseButtonsPressed)
376                 main.mouseRelease(main, menuMousePos);
377         mouseButtonsPressed = 0;
378
379         main.focusEnter(main);
380         main.showNotify(main);
381 };
382
383 void() m_hide =
384 {
385         Menu_Active = false;
386         setkeydest(KEY_GAME);
387         setmousetarget(MT_CLIENT);
388
389         if(!menuInitialized)
390                 return;
391
392         main.focusLeave(main);
393         main.hideNotify(main);
394 };
395
396 void() m_toggle =
397 {
398         if(Menu_Active)
399                 m_hide();
400         else
401                 m_display();
402 };
403
404 void() m_shutdown =
405 {
406         entity e;
407
408         m_hide();
409         for(e = NULL; (e = nextent(e)) != NULL; )
410         {
411                 if(e.destroy)
412                         e.destroy(e);
413         }
414 };
415
416 void m_activate_window(entity wnd)
417 {
418         entity par;
419         par = wnd.parent;
420         if(par)
421                 m_activate_window(par);
422
423         if(par.instanceOfModalController)
424         {
425                 if(wnd.tabSelectingButton)
426                         // tabs
427                         TabButton_Click(wnd.tabSelectingButton, wnd);
428                 else
429                         // root
430                         par.initializeDialog(par, wnd);
431         }
432         else if(par.instanceOfNexposee)
433         {
434                 // nexposee (sorry for violating abstraction here)
435                 par.selectedChild = wnd;
436                 par.animationState = 1;
437                 setFocusContainer(par, NULL);
438         }
439         else if(par.instanceOfContainer)
440         {
441                 // other containers
442                 if(par.focused)
443                         par.setFocus(par, wnd);
444         }
445 }
446
447 void(string itemname) m_goto =
448 {
449         entity e;
450         if(!menuInitialized)
451                 return;
452         if(itemname == "") // this can be called by GameCommand
453         {
454                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
455                         m_hide();
456                 else
457                 {
458                         m_activate_window(main.mainNexposee);
459                         m_display();
460                 }
461         }
462         else
463         {
464                 e = findstring(NULL, name, itemname);
465                 if(e)
466                 {
467                         m_hide();
468                         m_activate_window(e);
469                         m_display();
470                 }
471         }
472 }
473
474 void() m_goto_skin_selector =
475 {
476         if(!menuInitialized)
477                 return;
478         // TODO add code to switch back to the skin selector (no idea how to do it now)
479         m_goto("skinselector");
480 }