Include gmqcc binaries for Windows and Linux
[voretournament/voretournament.git] / data / qcsrc / menu / menu.qc
1 ///////////////////////////////////////////////\r
2 // Menu Source File\r
3 ///////////////////////\r
4 // This file belongs to dpmod/darkplaces\r
5 // AK contains all menu functions (especially the required ones)\r
6 ///////////////////////////////////////////////\r
7 \r
8 float mouseButtonsPressed;\r
9 vector menuMousePos;\r
10 float menuShiftState;\r
11 float menuPrevTime;\r
12 float menuAlpha;\r
13 float menuLogoAlpha;\r
14 float prevMenuAlpha;\r
15 float menuInitialized;\r
16 float menuNotTheFirstFrame;\r
17 float menuMouseMode;\r
18 \r
19 void SUB_Null() { };\r
20 \r
21 void m_init()\r
22 {\r
23         localcmd("maxplayers $menu_maxplayers\n"); // make sure maxplayers is set if we start a game with the map command\r
24         cvar_set("_menu_alpha", "0");\r
25 \r
26         check_unacceptable_compiler_bugs();\r
27 \r
28         // list all game dirs (TEST)\r
29         if(cvar("developer"))\r
30         {\r
31                 float i;\r
32                 string s;\r
33                 for(i = 0; ; ++i)\r
34                 {\r
35                         s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);\r
36                         if not(s)\r
37                                 break;\r
38                         print(s, ": ", getgamedirinfo(i, GETGAMEDIRINFO_DESCRIPTION));\r
39                 }\r
40         }\r
41 }\r
42 \r
43 float MENU_ASPECT = 1.25; // 1280x1024\r
44 float MENU_MINHEIGHT = 600;\r
45 float conwidth_s, conheight_s, realconwidth, realconheight, screenconwidth, screenconheight;\r
46 void draw_reset_cropped()\r
47 {\r
48         draw_reset(screenconwidth, screenconheight, 0.5 * (realconwidth - screenconwidth), 0.5 * (realconheight - screenconheight));\r
49 }\r
50 void draw_reset_full()\r
51 {\r
52         draw_reset(realconwidth, realconheight, 0, 0);\r
53 }\r
54 void UpdateConWidthHeight()\r
55 {\r
56         conwidth_s = conwidth;\r
57         conheight_s = conheight;\r
58         realconwidth = cvar("vid_conwidth");\r
59         realconheight = cvar("vid_conheight");\r
60         if(realconwidth / realconheight > MENU_ASPECT)\r
61         {\r
62                 // widescreen\r
63                 conwidth = realconheight * MENU_ASPECT;\r
64                 conheight = realconheight;\r
65         }\r
66         else\r
67         {\r
68                 // squarescreen\r
69                 conwidth = realconwidth;\r
70                 conheight = realconwidth / MENU_ASPECT;\r
71         }\r
72         screenconwidth = conwidth;\r
73         screenconheight = conheight;\r
74         if(conwidth < MENU_MINHEIGHT * MENU_ASPECT)\r
75         {\r
76                 conheight *= MENU_MINHEIGHT * MENU_ASPECT / conwidth;\r
77                 conwidth = MENU_MINHEIGHT * MENU_ASPECT;\r
78         }\r
79         if(conheight < MENU_MINHEIGHT)\r
80         {\r
81                 conwidth *= MENU_MINHEIGHT / conheight;\r
82                 conheight = MENU_MINHEIGHT;\r
83         }\r
84         if(main)\r
85         {\r
86                 if(conwidth_s != conwidth || conheight_s != conheight)\r
87                 {\r
88                         draw_reset_cropped();\r
89                         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);\r
90                 }\r
91         }\r
92 }\r
93 \r
94 void m_init_delayed()\r
95 {\r
96         float fh, glob, n, i;\r
97         string s;\r
98 \r
99         conwidth = conheight = -1;\r
100         UpdateConWidthHeight();\r
101         draw_reset_cropped();\r
102 \r
103         menuInitialized = 0;\r
104         if(!preMenuInit())\r
105                 return;\r
106         menuInitialized = 1;\r
107         GameCommand_Init();\r
108 \r
109         RegisterWeapons();\r
110 \r
111         fh = -1;\r
112         if(cvar_string("menu_skin") != "")\r
113         {\r
114                 draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));\r
115                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
116         }\r
117         if(fh < 0)\r
118         if(cvar_defstring("menu_skin") != "")\r
119         {\r
120                 draw_currentSkin = strcat("gfx/menu/", cvar_defstring("menu_skin"));\r
121                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
122         }\r
123         if(fh < 0)\r
124         {\r
125                 draw_currentSkin = "gfx/menu/default";\r
126                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
127         }\r
128         draw_currentSkin = strzone(draw_currentSkin);\r
129         while((s = fgets(fh)))\r
130         {\r
131                 // these two are handled by skinlist.qc\r
132                 if(substring(s, 0, 6) == "title ")\r
133                         continue;\r
134                 if(substring(s, 0, 7) == "author ")\r
135                         continue;\r
136                 n = tokenize_console(s);\r
137                 if(n >= 2)\r
138                         Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));\r
139         }\r
140         fclose(fh);\r
141 \r
142         glob = search_begin(strcat(draw_currentSkin, "/*.tga"), TRUE, TRUE);\r
143         if(glob >= 0)\r
144         {\r
145                 n = search_getsize(glob);\r
146                 for(i = 0; i < n; ++i)\r
147                         precache_pic(search_getfilename(glob, i));\r
148                 search_end(glob);\r
149         }\r
150 \r
151         draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);\r
152 \r
153         loadTooltips();\r
154         main = spawnMainWindow(); main.configureMainWindow(main);\r
155         unloadTooltips();\r
156 \r
157         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);\r
158         main.focused = 1;\r
159         menuShiftState = 0;\r
160         menuMousePos = '0.5 0.5 0';\r
161 \r
162         if(Menu_Active)\r
163                 m_display(); // delayed menu display\r
164 };\r
165 \r
166 void m_keyup (float key, float ascii)\r
167 {\r
168         if(!menuInitialized)\r
169                 return;\r
170         if(!Menu_Active)\r
171                 return;\r
172         draw_reset_cropped();\r
173         main.keyUp(main, key, ascii, menuShiftState);\r
174         if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
175         {\r
176                 --mouseButtonsPressed;\r
177                 if(!mouseButtonsPressed)\r
178                         main.mouseRelease(main, menuMousePos);\r
179                 if(mouseButtonsPressed < 0)\r
180                 {\r
181                         mouseButtonsPressed = 0;\r
182                         print("Warning: released an already released button\n");\r
183                 }\r
184         }\r
185         if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);\r
186         if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);\r
187         if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);\r
188 };\r
189 \r
190 void m_keydown (float key, float ascii)\r
191 {\r
192         if(!menuInitialized)\r
193                 return;\r
194         if(!Menu_Active)\r
195                 return;\r
196         if(keyGrabber)\r
197         {\r
198                 entity e;\r
199                 e = keyGrabber;\r
200                 keyGrabber = NULL;\r
201                 e.keyGrabbed(e, key, ascii);\r
202         }\r
203         else\r
204         {\r
205                 draw_reset_cropped();\r
206                 if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
207                         if(!mouseButtonsPressed)\r
208                                 main.mousePress(main, menuMousePos);\r
209                 if(!main.keyDown(main, key, ascii, menuShiftState))\r
210                         if(key == K_ESCAPE)\r
211                                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only\r
212                                         m_hide(); // disable menu on unhandled ESC\r
213         }\r
214         if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
215         {\r
216                 ++mouseButtonsPressed;\r
217                 if(mouseButtonsPressed > 10)\r
218                 {\r
219                         mouseButtonsPressed = 10;\r
220                         print("Warning: pressed an already pressed button\n");\r
221                 }\r
222         }\r
223         if(key == K_ALT) menuShiftState |= S_ALT;\r
224         if(key == K_CTRL) menuShiftState |= S_CTRL;\r
225         if(key == K_SHIFT) menuShiftState |= S_SHIFT;\r
226 };\r
227 \r
228 float SCALEMODE_CROP = 0;\r
229 float SCALEMODE_LETTERBOX = 1;\r
230 float SCALEMODE_WIDTH = 2;\r
231 float SCALEMODE_HEIGHT = 3;\r
232 float SCALEMODE_STRETCH = 4;\r
233 void draw_Picture_Aligned(vector algn, float scalemode, string img, float a)\r
234 {\r
235         vector sz, org, isz, isz_w, isz_h;\r
236         float width_is_larger;\r
237 \r
238         sz = draw_PictureSize(img);\r
239         width_is_larger = (sz_x * draw_scale_y >= sz_y * draw_scale_x);\r
240         isz_w = '1 0 0' + '0 1 0' * ((sz_y / sz_x) * (draw_scale_x / draw_scale_y)); \r
241         isz_h = '0 1 0' + '1 0 0' * ((sz_x / sz_y) * (draw_scale_y / draw_scale_x)); \r
242 \r
243         switch(scalemode)\r
244         {\r
245                 default:\r
246                 case SCALEMODE_CROP:\r
247                         isz = (width_is_larger ? isz_h : isz_w);\r
248                         break;\r
249                 case SCALEMODE_LETTERBOX:\r
250                         isz = (width_is_larger ? isz_w : isz_h);\r
251                         break;\r
252                 case SCALEMODE_WIDTH:\r
253                         isz = isz_w;\r
254                         break;\r
255                 case SCALEMODE_HEIGHT:\r
256                         isz = isz_h;\r
257                         break;\r
258                 case SCALEMODE_STRETCH:\r
259                         isz = '1 1 0';\r
260                         break;\r
261         }\r
262 \r
263         org = eX * (algn_x * (1 - isz_x)) + eY * (algn_y * (1 - isz_y));\r
264         draw_Picture(org, img, isz, '1 1 1', a);\r
265 }\r
266 \r
267 void drawBackground (string img, float a, string algn, float force1)\r
268 {\r
269         vector v;\r
270         float i, l;\r
271         string c;\r
272         float scalemode;\r
273 \r
274         v_z = 0;\r
275 \r
276         scalemode = SCALEMODE_CROP;\r
277 \r
278         for(i = 0; i < strlen(algn); ++i)\r
279         {\r
280                 c = substring(algn, i, 1);\r
281                 switch(c)\r
282                 {\r
283                         case "c": scalemode = SCALEMODE_CROP; goto nopic;\r
284                         case "l": scalemode = SCALEMODE_LETTERBOX; goto nopic;\r
285                         case "h": scalemode = SCALEMODE_HEIGHT; goto nopic;\r
286                         case "w": scalemode = SCALEMODE_WIDTH; goto nopic;\r
287                         case "s": scalemode = SCALEMODE_STRETCH; goto nopic;\r
288                         case "1": case "4": case "7": v_x = 0.0; break;\r
289                         case "2": case "5": case "8": v_x = 0.5; break;\r
290                         case "3": case "6": case "9": v_x = 1.0; break;\r
291                         default: v_x = random(); break;\r
292                 }\r
293                 switch(c)\r
294                 {\r
295                         case "7": case "8": case "9": v_y = 0.0; break;\r
296                         case "4": case "5": case "6": v_y = 0.5; break;\r
297                         case "1": case "2": case "3": v_y = 1.0; break;\r
298                         default: v_y = random(); break;\r
299                 }\r
300                 if(l == 0)\r
301                         draw_Picture_Aligned(v, scalemode, img, a);\r
302                 else if(force1)\r
303                         // force all secondary layers to use alpha 1. Prevents ugly issues\r
304                         // with overlap. It's a flag because it cannot be used for the\r
305                         // ingame background\r
306                         draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), 1);\r
307                 else\r
308                         draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), a);\r
309                 ++l;\r
310 :nopic\r
311         }\r
312 }\r
313 \r
314 vector menuTooltipAveragedMousePos;\r
315 entity menuTooltipItem;\r
316 vector menuTooltipOrigin;\r
317 vector menuTooltipSize;\r
318 float menuTooltipAlpha;\r
319 float menuTooltipState; // 0: no tooltip, 1: fading in, 2: displaying, 3: fading out\r
320 float m_testmousetooltipbox(vector pos)\r
321 {\r
322         if(pos_x >= menuTooltipOrigin_x && pos_x < menuTooltipOrigin_x + menuTooltipSize_x)\r
323         if(pos_y >= menuTooltipOrigin_y && pos_y < menuTooltipOrigin_y + menuTooltipSize_y)\r
324                 return FALSE;\r
325         return TRUE;\r
326 }\r
327 float m_testtooltipbox(vector tooltippos)\r
328 {\r
329         if(tooltippos_x < 0)\r
330                 return FALSE;\r
331         if(tooltippos_y < 0)\r
332                 return FALSE;\r
333         if(tooltippos_x + menuTooltipSize_x > 1)\r
334                 return FALSE;\r
335         if(tooltippos_y + menuTooltipSize_y > 1)\r
336                 return FALSE;\r
337         /*\r
338         menuTooltipOrigin_x = rint(tooltippos_x * cvar("vid_width")) / cvar("vid_width");\r
339         menuTooltipOrigin_y = rint(tooltippos_y * cvar("vid_height")) / cvar("vid_height");\r
340         menuTooltipOrigin_z = 0;\r
341         */\r
342         menuTooltipOrigin = tooltippos;\r
343         return TRUE;\r
344 }\r
345 float m_allocatetooltipbox(vector pos)\r
346 {\r
347         vector avoidplus, avoidminus;\r
348         vector v;\r
349 \r
350         avoidplus_x = (SKINAVOID_TOOLTIP_x + SKINSIZE_CURSOR_x - SKINOFFSET_CURSOR_x) / conwidth;\r
351         avoidplus_y = (SKINAVOID_TOOLTIP_y + SKINSIZE_CURSOR_y - SKINOFFSET_CURSOR_y) / conheight;\r
352         avoidplus_z = 0;\r
353 \r
354         avoidminus_x = (SKINAVOID_TOOLTIP_x + SKINOFFSET_CURSOR_x) / conwidth + menuTooltipSize_x;\r
355         avoidminus_y = (SKINAVOID_TOOLTIP_y + SKINOFFSET_CURSOR_y) / conheight + menuTooltipSize_y;\r
356         avoidminus_z = 0;\r
357 \r
358         // bottom right\r
359         v = pos + avoidplus;\r
360         if(m_testtooltipbox(v))\r
361                 return TRUE;\r
362         \r
363         // bottom center\r
364         v_x = pos_x - menuTooltipSize_x * 0.5;\r
365         if(m_testtooltipbox(v))\r
366                 return TRUE;\r
367 \r
368         // bottom left\r
369         v_x = pos_x - avoidminus_x;\r
370         if(m_testtooltipbox(v))\r
371                 return TRUE;\r
372 \r
373         // top left\r
374         v_y = pos_y - avoidminus_y;\r
375         if(m_testtooltipbox(v))\r
376                 return TRUE;\r
377 \r
378         // top center\r
379         v_x = pos_x - menuTooltipSize_x * 0.5;\r
380         if(m_testtooltipbox(v))\r
381                 return TRUE;\r
382         \r
383         // top right\r
384         v_x = pos_x + avoidplus_x;\r
385         if(m_testtooltipbox(v))\r
386                 return TRUE;\r
387         \r
388         return FALSE;\r
389 }\r
390 entity m_findtooltipitem(entity root, vector pos)\r
391 {\r
392         entity it;\r
393         entity best;\r
394 \r
395         best = world;\r
396         it = root;\r
397 \r
398         while(it.instanceOfContainer)\r
399         {\r
400                 while(it.instanceOfNexposee && it.focusedChild)\r
401                 {\r
402                         it = it.focusedChild;\r
403                         pos = globalToBox(pos, it.Container_origin, it.Container_size);\r
404                 }\r
405                 if(it.instanceOfNexposee)\r
406                 {\r
407                         it = it.itemFromPoint(it, pos);\r
408                         if(it.tooltip)\r
409                                 best = it;\r
410                         it = world;\r
411                 }\r
412                 else if(it.instanceOfModalController)\r
413                         it = it.focusedChild;\r
414                 else\r
415                         it = it.itemFromPoint(it, pos);\r
416                 if(!it)\r
417                         break;\r
418                 if(it.tooltip)\r
419                         best = it;\r
420                 pos = globalToBox(pos, it.Container_origin, it.Container_size);\r
421         }\r
422 \r
423         return best;\r
424 }\r
425 void m_tooltip(vector pos)\r
426 {\r
427         float f, i, w;\r
428         entity it;\r
429         vector fontsize, p;\r
430         string s;\r
431 \r
432         fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);\r
433 \r
434         f = bound(0, frametime * 2, 1);\r
435         menuTooltipAveragedMousePos = menuTooltipAveragedMousePos * (1 - f) + pos * f;\r
436         f = vlen(pos - menuTooltipAveragedMousePos);\r
437 \r
438         if(f < 0.01)\r
439                 it = m_findtooltipitem(main, pos);\r
440         else    \r
441                 it = world;\r
442 \r
443         // float menuTooltipState; // 0: static, 1: fading in, 2: fading out\r
444         if(it != menuTooltipItem)\r
445         {\r
446                 switch(menuTooltipState)\r
447                 {\r
448                         case 0:\r
449                                 if(menuTooltipItem)\r
450                                 {\r
451                                         // another item: fade out first\r
452                                         menuTooltipState = 2;\r
453                                 }\r
454                                 else\r
455                                 {\r
456                                         // new item: fade in\r
457                                         menuTooltipState = 1;\r
458                                         menuTooltipItem = it;\r
459 \r
460                                         menuTooltipOrigin_x = -1; // unallocated\r
461                                         i = 0;\r
462                                         w =  0;\r
463                                         getWrappedLine_remaining = it.tooltip;\r
464                                         while(getWrappedLine_remaining)\r
465                                         {\r
466                                                 s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);\r
467                                                 ++i;\r
468                                                 f = draw_TextWidth(s, FALSE, fontsize);\r
469                                                 if(f > w)\r
470                                                         w = f;\r
471                                         }\r
472                                         menuTooltipSize_x = w + 2 * (SKINMARGIN_TOOLTIP_x / conwidth);\r
473                                         menuTooltipSize_y = i * fontsize_y + 2 * (SKINMARGIN_TOOLTIP_y / conheight);\r
474                                         menuTooltipSize_z = 0;\r
475                                 }\r
476                                 break;\r
477                         case 1:\r
478                                 // changing item while fading in: fade out first\r
479                                 menuTooltipState = 2;\r
480                                 break;\r
481                         case 2:\r
482                                 // changing item while fading out: can't\r
483                                 break;\r
484                 }\r
485         }\r
486         else if(menuTooltipState == 2) // re-fade in?\r
487                 menuTooltipState = 1;\r
488 \r
489         if(menuTooltipItem)\r
490                 if(!m_testmousetooltipbox(pos))\r
491                         menuTooltipState = 2; // fade out if mouse touches it\r
492 \r
493         switch(menuTooltipState)\r
494         {\r
495                 case 1:\r
496                         menuTooltipAlpha = bound(0, menuTooltipAlpha + 5 * frametime, 1);\r
497                         if(menuTooltipAlpha == 1)\r
498                                 menuTooltipState = 0;\r
499                         break;\r
500                 case 2:\r
501                         menuTooltipAlpha = bound(0, menuTooltipAlpha - 2 * frametime, 1);\r
502                         if(menuTooltipAlpha == 0)\r
503                         {\r
504                                 menuTooltipState = 0;\r
505                                 menuTooltipItem = world;\r
506                         }\r
507                         break;\r
508         }\r
509 \r
510         if(menuTooltipItem)\r
511         {\r
512                 if(menuTooltipOrigin_x < 0) // unallocated?\r
513                         m_allocatetooltipbox(pos);\r
514 \r
515                 if(menuTooltipOrigin_x >= 0)\r
516                 {\r
517                         // draw the tooltip!\r
518                         p = SKINBORDER_TOOLTIP;\r
519                         p_x *= 1 / conwidth;\r
520                         p_y *= 1 / conheight;\r
521                         draw_BorderPicture(menuTooltipOrigin, SKINGFX_TOOLTIP, menuTooltipSize, '1 1 1', menuTooltipAlpha, p);\r
522                         p = menuTooltipOrigin;\r
523                         p_x += SKINMARGIN_TOOLTIP_x / conwidth;\r
524                         p_y += SKINMARGIN_TOOLTIP_y / conheight;\r
525                         getWrappedLine_remaining = menuTooltipItem.tooltip;\r
526                         while(getWrappedLine_remaining)\r
527                         {\r
528                                 s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);\r
529                                 draw_Text(p, s, fontsize, '1 1 1', SKINALPHA_TOOLTIP * menuTooltipAlpha, FALSE);\r
530                                 p_y += fontsize_y;\r
531                         }\r
532                 }\r
533         }\r
534 }\r
535 \r
536 void m_draw()\r
537 {\r
538         float t;\r
539         float realFrametime;\r
540 \r
541         menuMouseMode = cvar("menu_mouse_absolute");\r
542 \r
543         if(main)\r
544                 UpdateConWidthHeight();\r
545 \r
546         if(!menuInitialized)\r
547         {\r
548                 // TODO draw an info image about this situation\r
549                 m_init_delayed();\r
550                 return;\r
551         }\r
552         if(!menuNotTheFirstFrame)\r
553         {\r
554                 menuNotTheFirstFrame = 1;\r
555                 if(Menu_Active)\r
556                 if(!cvar("menu_video_played"))\r
557                 {\r
558                         localcmd("set menu_video_played 1; cd loop $menu_cdtrack; play sound/announcer/default/welcome.ogg\n");\r
559                         menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading\r
560                 }\r
561         }\r
562 \r
563         t = gettime();\r
564         realFrametime = frametime = min(0.2, t - menuPrevTime);\r
565         menuPrevTime = t;\r
566         time += frametime;\r
567 \r
568         t = cvar("menu_slowmo");\r
569         if(t)\r
570         {\r
571                 frametime *= t;\r
572                 realFrametime *= t;\r
573         }\r
574         else\r
575                 t = 1;\r
576 \r
577         if(Menu_Active)\r
578         {\r
579                 if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))\r
580                         setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);\r
581                 else\r
582                         m_hide();\r
583         }\r
584 \r
585         if(cvar("cl_capturevideo"))\r
586                 frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly\r
587 \r
588         gamestatus = 0;\r
589         if(isserver())\r
590                 gamestatus = gamestatus | GAME_ISSERVER;\r
591         if(clientstate() == CS_CONNECTED)\r
592                 gamestatus = gamestatus | GAME_CONNECTED;\r
593         if(cvar("developer"))\r
594                 gamestatus = gamestatus | GAME_DEVELOPER;\r
595 \r
596         prevMenuAlpha = menuAlpha;\r
597         if(Menu_Active)\r
598         {\r
599                 if(menuAlpha == 0 && menuLogoAlpha < 2)\r
600                 {\r
601                         menuLogoAlpha = menuLogoAlpha + frametime * 2;\r
602                 }\r
603                 else\r
604                 {\r
605                         menuAlpha = min(1, menuAlpha + frametime * 5);\r
606                         menuLogoAlpha = 2;\r
607                 }\r
608         }\r
609         else\r
610         {\r
611                 menuAlpha = max(0, menuAlpha - frametime * 5);\r
612                 menuLogoAlpha = 2;\r
613         }\r
614 \r
615         draw_reset_cropped();\r
616 \r
617         if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))\r
618         {\r
619                 if(menuLogoAlpha > 0)\r
620                 {\r
621                         draw_reset_full();\r
622                         draw_Fill('0 0 0', '1 1 0', SKINCOLOR_BACKGROUND, 1);\r
623                         drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1), SKINALIGN_BACKGROUND, TRUE);\r
624                         draw_reset_cropped();\r
625                         if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)\r
626                         {\r
627                                 draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);\r
628                                 draw_drawMousePointer(menuMousePos);\r
629                                 draw_alpha = 1;\r
630                         }\r
631                 }\r
632         }\r
633         else if(SKINALPHA_BACKGROUND_INGAME)\r
634         {\r
635                 if(menuAlpha > 0)\r
636                 {\r
637                         draw_reset_full();\r
638                         drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME, SKINALIGN_BACKGROUND_INGAME, FALSE);\r
639                         draw_reset_cropped();\r
640                 }\r
641         }\r
642 \r
643         if(menuAlpha != prevMenuAlpha)\r
644                 cvar_set("_menu_alpha", ftos(menuAlpha));\r
645 \r
646         draw_reset_cropped();\r
647         preMenuDraw();\r
648         draw_reset_cropped();\r
649 \r
650         if(menuAlpha <= 0)\r
651         {\r
652                 if(prevMenuAlpha > 0)\r
653                         main.initializeDialog(main, main.firstChild);\r
654                 draw_reset_cropped();\r
655                 postMenuDraw();\r
656                 return;\r
657         }\r
658 \r
659         draw_alpha *= menuAlpha;\r
660 \r
661         if(menuMouseMode)\r
662         {\r
663                 vector newMouse;\r
664                 newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);\r
665                 if(newMouse != '0 0 0')\r
666                         if(newMouse != menuMousePos)\r
667                         {\r
668                                 menuMousePos = newMouse;\r
669                                 if(mouseButtonsPressed)\r
670                                         main.mouseDrag(main, menuMousePos);\r
671                                 else\r
672                                         main.mouseMove(main, menuMousePos);\r
673                         }\r
674         }\r
675         else\r
676         {\r
677                 if(frametime > 0)\r
678                 {\r
679                         vector dMouse, minpos, maxpos;\r
680                         dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo\r
681                         if(dMouse != '0 0 0')\r
682                         {\r
683                                 minpos = globalToBox('0 0 0', draw_shift, draw_scale);\r
684                                 maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);\r
685                                 dMouse = globalToBoxSize(dMouse, draw_scale);\r
686                                 menuMousePos += dMouse * cvar("menu_mouse_speed");\r
687                                 menuMousePos_x = bound(minpos_x, menuMousePos_x, maxpos_x);\r
688                                 menuMousePos_y = bound(minpos_y, menuMousePos_y, maxpos_y);\r
689                                 if(mouseButtonsPressed)\r
690                                         main.mouseDrag(main, menuMousePos);\r
691                                 else\r
692                                         main.mouseMove(main, menuMousePos);\r
693                         }\r
694                 }\r
695         }\r
696         main.draw(main);\r
697 \r
698         m_tooltip(menuMousePos);\r
699 \r
700         draw_alpha = max(draw_alpha, SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1));\r
701 \r
702         draw_drawMousePointer(menuMousePos);\r
703 \r
704         draw_reset_cropped();\r
705         postMenuDraw();\r
706 \r
707         frametime = 0;\r
708 };\r
709 \r
710 void m_display()\r
711 {\r
712         Menu_Active = true;\r
713         setkeydest(KEY_MENU);\r
714         setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));\r
715 \r
716         if(!menuInitialized)\r
717                 return;\r
718 \r
719         if(mouseButtonsPressed)\r
720                 main.mouseRelease(main, menuMousePos);\r
721         mouseButtonsPressed = 0;\r
722 \r
723         main.focusEnter(main);\r
724         main.showNotify(main);\r
725 };\r
726 \r
727 void m_hide()\r
728 {\r
729         Menu_Active = false;\r
730         setkeydest(KEY_GAME);\r
731         setmousetarget(MT_CLIENT);\r
732 \r
733         if(!menuInitialized)\r
734                 return;\r
735 \r
736         main.focusLeave(main);\r
737         main.hideNotify(main);\r
738 };\r
739 \r
740 void m_toggle()\r
741 {\r
742         if(Menu_Active)\r
743                 m_hide();\r
744         else\r
745                 m_display();\r
746 };\r
747 \r
748 void m_shutdown()\r
749 {\r
750         entity e;\r
751 \r
752         m_hide();\r
753         for(e = NULL; (e = nextent(e)) != NULL; )\r
754         {\r
755                 if(e.destroy)\r
756                         e.destroy(e);\r
757         }\r
758 };\r
759 \r
760 void m_focus_item_chain(entity outermost, entity innermost)\r
761 {\r
762         if(innermost.parent != outermost)\r
763                 m_focus_item_chain(outermost, innermost.parent);\r
764         innermost.parent.setFocus(innermost.parent, innermost);\r
765 }\r
766 \r
767 void m_activate_window(entity wnd)\r
768 {\r
769         entity par;\r
770         par = wnd.parent;\r
771         if(par)\r
772                 m_activate_window(par);\r
773 \r
774         if(par.instanceOfModalController)\r
775         {\r
776                 if(wnd.tabSelectingButton)\r
777                         // tabs\r
778                         TabButton_Click(wnd.tabSelectingButton, wnd);\r
779                 else\r
780                         // root\r
781                         par.initializeDialog(par, wnd);\r
782         }\r
783         else if(par.instanceOfNexposee)\r
784         {\r
785                 // nexposee (sorry for violating abstraction here)\r
786                 par.selectedChild = wnd;\r
787                 par.animationState = 1;\r
788                 setFocusContainer(par, NULL);\r
789         }\r
790         else if(par.instanceOfContainer)\r
791         {\r
792                 // other containers\r
793                 if(par.focused)\r
794                         par.setFocus(par, wnd);\r
795         }\r
796 }\r
797 \r
798 void m_setpointerfocus(entity wnd)\r
799 {\r
800         if(wnd.instanceOfContainer)\r
801         {\r
802                 entity focus = wnd.preferredFocusedGrandChild(wnd);\r
803                 if(focus)\r
804                 {\r
805                         menuMousePos = focus.origin + 0.5 * focus.size;\r
806                         menuMousePos_x *= 1 / conwidth;\r
807                         menuMousePos_y *= 1 / conheight;\r
808                         if(wnd.focused) // why does this never happen?\r
809                                 m_focus_item_chain(wnd, focus);\r
810                 }\r
811         }\r
812 }\r
813 \r
814 void m_goto(string itemname)\r
815 {\r
816         entity e;\r
817         if(!menuInitialized)\r
818                 return;\r
819         if(itemname == "") // this can be called by GameCommand\r
820         {\r
821                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))\r
822                         m_hide();\r
823                 else\r
824                 {\r
825                         m_activate_window(main.mainNexposee);\r
826                         m_display();\r
827                 }\r
828         }\r
829         else\r
830         {\r
831                 e = findstring(NULL, name, itemname);\r
832                 if(e)\r
833                 {\r
834                         m_hide();\r
835                         m_activate_window(e);\r
836                         m_setpointerfocus(e);\r
837                         m_display();\r
838                 }\r
839         }\r
840 }\r
841 \r
842 void m_goto_skin_selector()\r
843 {\r
844         if(!menuInitialized)\r
845                 return;\r
846         // TODO add code to switch back to the skin selector (no idea how to do it now)\r
847         m_goto("skinselector");\r
848 }\r
849 \r
850 void m_goto_video_settings()\r
851 {\r
852         if(!menuInitialized)\r
853                 return;\r
854         // TODO add code to switch back to the skin selector (no idea how to do it now)\r
855         m_goto("videosettings");\r
856 }\r