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