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