1 ///////////////////////////////////////////////
2 // Menu Manager Source File
3 ///////////////////////
4 // This file belongs to dpmod/darkplaces
5 // AK contains the manager code
6 ///////////////////////////////////////////////
10 //registercvar("menu_reloadlist","0");
15 void(void) menu_load =
17 // load the menu files
20 count = tokenize(MENU_FILENAME_LIST);
22 for(i = 0; i < count; i = i + 1)
24 menu_loadmenu(argv(i));
25 dprint(argv(i), " loaded !\n");
31 void(string file) menu_addfiletolist =
35 count = tokenize(MENU_FILENAME_LIST);
37 for(i = 0; i < count; i = i + 1)
45 MENU_FILENAME_LIST = strcat(MENU_FILENAME_LIST," ",file);
48 void(void) menu_restart =
50 // actually we empty the ent list and load everything one more time, thats it
57 // we backup the active window name and the name of the selected item
58 oldactive = menu_activewindow.name;
59 oldselected = menu_selected.name;
61 if(self != null_entity)
71 // first clear the history
74 // we remove all items
76 while((ent = nextent(ent)) != null_entity)
81 // FIXME: here's a "little" hack (so PRVM_ED_Alloc replaces the items instead of creating new ones)
87 time = time - 1.0; // we cant use gettime cause that always returns time :-/
92 ent = menu_getitem(oldactive);
95 menu_activewindow = ent;
96 ent = menu_getitem(oldselected);
105 ent = menu_getitem(oldself);
109 } else // we have no current self...
111 error("Reloaded menu files, but the former self (", oldself ,") item is missing !\n");
115 void(string file) menu_loadmenu =
120 entity(entity start, .entity find1, entity match, .float find2, float match2) findef =
124 start = findentity(start, find1, match);
125 if(start == null_entity)
127 if(start.find2 == match2)
132 /*while((start = findentity(start,find1,match))!=null_entity)
133 if(start.find2 == match2)
138 void(void) menu_linkwindows =
140 // first verify that MENU_NORMAL_NAME and MENU_INGAME_NAME exist
141 // if not add the default strings
145 dprint("Loading defaults if necessary\n");
147 ent = findstring(null_entity,name, MENU_NORMAL_NAME);
148 if(ent == null_entity)
149 loadfromdata(MENU_NORMAL_DEFAULT);
151 // verify again if MENI_INGAME_NAME is there now
152 ent = findstring(null_entity,name, MENU_NORMAL_NAME);
153 if(ent == null_entity)
154 error("Bad MENU_NORMAL_DEFAULT !\n");
156 ent = findstring(null_entity,name, MENU_INGAME_NAME);
157 if(ent == null_entity)
158 loadfromdata(MENU_INGAME_DEFAULT);
160 // verify again if MENI_INGAME_NAME is there now
161 ent = findstring(null_entity,name, MENU_INGAME_NAME);
162 if(ent == null_entity)
163 error("Bad MENU_INGAME_DEFAULT !\n");
165 dprint("Verifying that each name is used only once\n");
167 // verify that every name is only used *once*
169 while((ent = nextent(ent)) != null_entity)
172 while((self = findstring(self, name, ent.name)) != null_entity)
174 if(self != null_entity)
176 objerror("Name ", ent.name, " already used !\n");
181 dprint("Verification/Setting of: type, parent, next, prev and child fields\n");
184 // set the parent field with parent_name
185 // set the next and prev fields
186 // set the child field
187 // check the type field
189 while((self = nextent(self)) != null_entity)
193 objerror("Name is missing !\n");
199 objerror("Type is missing !\n");
203 if(!isfunction(self.type))
205 objerror("Control ", self.type, " not found !\n");
210 // if parent_name is "" do nothing else set parent
211 if(self.parent != "")
213 ent = findstring(null_entity, name, self.parent);
215 if(ent == null_entity)
217 objerror("Item ", self.parent, " not found !\n");
225 self._parent = null_entity;
229 dprint("Calling the type functions\n");
231 // call the type functions (former classname functions)
233 while((ent = nextent(ent)) != null_entity)
236 //dprint("Calling ",self.type," (", etos(self),")\n");
237 callfunction(self.type);
240 dprint("Orderpos is verified or set\n");
242 // now auto-set all ents with orderpos 0
244 while((self = findfloat(self,orderpos, 0)) != null_entity)
246 if(self.parent == "")
249 // now go through all orderpos' beginning from 1
251 while((ent = findef(null_entity, _parent, self._parent, orderpos, opos)) != null_entity)
256 self.orderpos = opos;
259 dprint("Set the _child, _prev and _next fields\n");
262 while((self = nextent(self)) != null_entity)
265 // orderpos starts with 1
266 ent = findef(null_entity, _parent, self, orderpos, 1);
268 if(ent == null_entity)
270 if(findentity(ent, _parent, self) != null_entity)
272 objerror("Order pos 1 is missing in the child list of ", self.name, " !\n");
275 //else doesnt have any chilren
280 // add to next, previous list
281 // find orderpos - x (starting with x = 1)
288 ent = findef(null_entity, _parent, self._parent, orderpos, x);
289 if(ent != null_entity)
297 // find orderpos + x (starting with x = 1 until x == self.oderpos + 100)
300 while(x < self.orderpos + 100)
304 ent = findef(null_entity, _parent, self._parent, orderpos, x);
305 if(ent != null_entity)
314 dprint("Linking windows finished.\n");
317 void(void) menu_toggle =
319 // only let the qc toggle the menu if we are ingame or a developer
320 if(gamestatus & GAME_CONNECTED || cvar("developer"))
322 // then allow toggling
327 void(void) menu_performreinit =
332 // reset the key hook (if necessary at all)
333 menu_keyhook = null_function;
335 // and reinit all menu items
337 while((self = nextent(self)) != null_entity)
339 if(self.parent == "")
340 self._parent = null_entity;
341 //else actually this shouldnt happen
342 else if(self._parent.name != self.parent)
343 objerror("Parent (should be ", self.parent, ") of non-menu item ", self.name, " changed to ", self._parent.name, " !\n");
345 raise_reinit(self); // always call reinit
348 // choose which menu to display
349 if(MENU_ALLOWINGAME && (gamestatus & GAME_CONNECTED))
350 menu_activewindow = findstring(null_entity, name, MENU_INGAME_NAME);
352 menu_activewindow = findstring(null_entity, name, MENU_NORMAL_NAME);
354 // set the selected item
355 menu_selected = menu_activewindow;
357 // find first child that can be selected
361 void(entity par, float selectstate) menu_processmouse =
364 // loop through all childs
365 // and try to find an object whose click rect fits to the mouse coords
367 vector old_cursor, local_cursor;
368 vector old_c_size, old_c_pos, clipped_size;
371 if(ent == null_entity)
374 if(menu_clip_size != '0 0 0')
376 clipped_size = cliprectsize(gfx_conmentogfx(par.clip_pos),par.clip_size, menu_clip_pos, menu_clip_size);
380 clipped_size = par.clip_size;
383 if(clipped_size != '0 0 0')
385 // do clip the clip area
387 old_c_pos = menu_clip_pos;
388 old_c_size = menu_clip_size;
391 menu_clip_pos = cliprectpos(gfx_conmentogfx(par.clip_pos), par.clip_size, menu_clip_pos, menu_clip_size);
392 menu_clip_size = clipped_size;
395 menu_localorigin = menu_localorigin + par.origin;
397 old_cursor = menu_cursor;
398 local_cursor = gfx_congfxtomen(cursor);
400 //print(vtos(cursor)," ");print(vtos(menu_clip_pos)," ");print(vtos(menu_clip_size),"\n");
402 if(inrect(cursor, menu_clip_pos, menu_clip_size) || menu_clip_size == '0 0 0')
406 // if not visible, continue to the next item
407 if(menu_isvisible(ent))
409 old_cursor = menu_cursor;
410 menu_cursor = local_cursor;
411 if(inrect(local_cursor, ent.click_pos, ent.click_size))
413 // call mouse_enter event ?
414 if(!(ent.flag & _FLAG_MOUSEINAREA) && menu_hasevents(ent))
416 raise_mouse_enter(ent);
418 ent.flag = ent.flag | _FLAG_MOUSEINAREA;
422 if(menu_selectable(ent) && selectstate != MENU_SELECT_NEVER)
426 else if(selectstate == MENU_SELECT_ALWAYS)
428 if(menu_hasevents(ent))
436 // call mouse_leave event ?
437 if((ent.flag & _FLAG_MOUSEINAREA) && menu_hasevents(ent))
439 raise_mouse_leave(ent);
441 // this only works if _FLAG_MOUSEINAREA is set
442 ent.flag = ent.flag - _FLAG_MOUSEINAREA;
446 if(menu_selected != ent)
447 menu_cursor = old_cursor;
450 // if ent has children recurse through them
451 if(ent._child != null_entity)
453 if((ent.flag & FLAG_CHILDDRAWONLY) || (ent.flag & FLAG_CHILDDRAWREFRESHONLY))
455 menu_processmouse(ent, MENU_SELECT_NEVER);
459 menu_processmouse(ent, selectstate);
463 } while((ent = ent._next) != null_entity);
466 menu_localorigin = menu_localorigin - par.origin;
468 // restore the old menu_clip vars if necessary
469 if(clipped_size != '0 0 0')
471 menu_clip_size = old_c_size;
472 menu_clip_pos = old_c_pos;
476 void(void) menu_frame =
479 // this is only for debugging purposes
480 // thus its unstable and *won't* work any more when Ive changed dp's behavior with
481 // the builtin list (the precache functions will only work for menu_init)
482 if(cvar("menu_reloadlist"))
484 cvar_set("menu_reloadlist","0");
487 menu_automatedselection = false;
488 // if mouse moved, process it
489 if(cursor_rel != '0 0 0')
491 menu_processmouse(menu_activewindow, MENU_SELECT_SELECTABLE);
496 void(entity menu) menu_drawwindow =
498 // loop through all children and draw them
500 vector old_c_pos, old_c_size, clipped_size, clipped_pos;
502 // set the clipping area
503 // is this necessary at all ?
504 if(menu_clip_size != '0 0 0')
506 clipped_size = cliprectsize(gfx_conmentogfx(menu.clip_pos),menu.clip_size, menu_clip_pos, menu_clip_size);
510 clipped_size = menu.clip_size;
513 if(clipped_size != '0 0 0')
515 // do clip the clip area
517 old_c_pos = menu_clip_pos;
518 old_c_size = menu_clip_size;
521 menu_clip_pos = cliprectpos( gfx_conmentogfx(menu.clip_pos) , menu.clip_size, menu_clip_pos, menu_clip_size);
522 menu_clip_size = clipped_size;
523 gfx_setcliparea(menu_clip_pos, menu_clip_size);
526 // set the localorigin (the clipping position wont be affected)
527 menu_localorigin = menu_localorigin + menu.origin;
532 // if it's not visible continue
533 if(menu_isvisible(ent))
536 if(menu_hasevents(ent))
539 } else if(ent.flag & FLAG_DRAWREFRESHONLY)
542 } else if(ent.flag & FLAG_DRAWONLY)
544 // TODO: find a better solution for this hack
545 } else if(ent._parent)
547 if(ent._parent.flag & FLAG_CHILDDRAWREFRESHONLY)
553 if(ent._child != null_entity)
555 menu_drawwindow(ent);
559 } while((ent = ent._next) != null_entity);
561 menu_localorigin = menu_localorigin - menu.origin;
563 // restore the old menu_clip vars if necessary
564 if(clipped_size != '0 0 0')
566 menu_clip_size = old_c_size;
567 menu_clip_pos = old_c_pos;
570 // reset the clip area of the old menu
571 if(menu_clip_size != '0 0 0')
572 gfx_setcliparea(menu_clip_pos, menu_clip_size);
577 void(void) menu_draw =
579 // if menu_activewindow is visible loop though it
580 if(menu_isvisible(menu_activewindow))
582 //menu_setcliparea('100 100 0', '400 400 0');
583 menu_drawwindow(menu_activewindow);
584 menu_localorigin = '0 0 0';
585 menu_clip_pos = '0 0 0';
586 menu_clip_size = '0 0 0';
587 menu_resetcliparea();
591 float(entity e) menu_hasevents =
593 if(e.flag & FLAG_DRAWONLY)
595 if(e.flag & FLAG_DRAWREFRESHONLY)
599 if(e._parent.flag & FLAG_CHILDDRAWONLY)
601 if(e._parent.flag & FLAG_CHILDDRAWREFRESHONLY)
604 if(menu_isvisible(e))
609 float(entity e) menu_isvisible =
611 if(e.flag & FLAG_HIDDEN)
614 if((e.flag & FLAG_SERVERONLY) && !(gamestatus & GAME_ISSERVER))
617 if((e.flag & FLAG_DEVELOPERONLY) && !(gamestatus & GAME_DEVELOPER))
623 float(entity e) menu_selectable =
625 if(!menu_hasevents(e))
627 if(e.flag & FLAG_NOSELECT)
630 //if(e == menu_getitem("quit"))
636 void(void) menu_shutdown =
638 // call the terminate event for each object
640 while((self = nextent(self)) != null_entity)
646 void(float keynr, float ascii) menu_keydown =
648 // is a keyhook set ?
649 if(menu_keyhook != null_function)
652 menu_keyhook(keynr, ascii);
655 // before calling the current keydown functions, process the mouse again
656 // so only the correct item is called
657 // (except mouse wheel up and down)
658 // if the mouse doesnt point to an item, there wont be a reaction on the clicking
659 if(K_MOUSE1 <= keynr && keynr <= K_MOUSE10)
662 key_selected = menu_selected;
663 menu_selected = null_entity;
664 menu_processmouse(menu_activewindow, MENU_SELECT_ALWAYS);
666 // if we find anything, we give it the key event, perhaps it can use it
667 if(menu_selected != key_selected)
670 if(menu_selected != null_entity)
672 raise_key(menu_selected, keynr, ascii);
675 // if it is selectable the user perhaps wanted to reselect it
676 if(menu_selectable(menu_selected) == false || menu_selected == null_entity)
678 menu_selected = key_selected;
686 // call current selected keydown function
687 // if nothing is selected -> window has no items -> call window key
688 if(menu_selected == null_entity)
690 // call window keydown
691 raise_key(menu_activewindow, keynr, ascii);
693 else if(menu_hasevents(menu_selected))
695 raise_key(menu_selected, keynr, ascii);
699 void(void) menu_selectprev =
703 temp = menu_selected;
704 // loop backward through the list until one item is selectable
705 while((temp = temp._prev) != null_entity)
706 if(menu_selectable(temp))
709 if(temp != null_entity)
710 menu_selected = temp;
713 void(void) menu_selectnext =
717 temp = menu_selected;
718 // loop forward through the list until one item is selectable
719 while((temp = temp._next) != null_entity)
720 if(menu_selectable(temp))
723 if(temp != null_entity)
724 menu_selected = temp;
727 void(void) menu_loopnext =
733 if(menu_selected == old)
735 menu_selected = old._parent._child;
736 if(!menu_selectable(menu_selected))
741 void(void) menu_loopprev =
746 if(menu_selected == old)
748 while(old._next != null_entity)
754 if(!menu_selectable(old))
761 void(void) menu_selectdown =
763 // move down a level, then search for a selectable child
764 // if none is found, then search for a sub-menu
765 // if one is found, recurse through it, else keep the old menu_selected
766 // (while recursing set the history)
768 entity ent, old_selected;
770 // if there is no child, return
771 if(menu_selected._child == null_entity)
776 // loop through the children till a selectable is found
777 ent = menu_selected._child;
780 if(menu_selectable(ent))
782 // found one -> break
786 } while((ent = ent._next) != null_entity);
788 // we found no selectable child, thus we loop through the children once again
790 ent = menu_selected._child;
791 old_selected = menu_selected;
794 if(ent._child != null_entity)
796 if(!(ent.flag & FLAG_CHILDDRAWONLY) && !(ent.flag & FLAG_CHILDDRAWREFRESHONLY))
803 if(menu_selected != ent)
811 } while((ent = ent._next) != null_entity);
813 // we didnt find anything
814 menu_selected = old_selected;
818 void(void) menu_selectup =
820 // if we try to up from the current activewindow pop the history.
821 // else move up in the hierarchy and try to select and item.
823 //print( "Check whether menu_selected == menu_activewindow\n" );
824 if( menu_selected == menu_activewindow ) {
825 //print( "Pop history\n" );
826 if( menu_history == null_entity ) {
827 //print( "History empty!\n" );
835 //print( "Check whether parent exists\n" );
836 if( menu_selected._parent == null_entity )
839 //print( "Try to select the parent\n" );
840 menu_selected = menu_selected._parent;
841 if( menu_selectable( menu_selected ) )
844 //print( "Try to select an item after the parent\n" );
846 if( menu_selectable( menu_selected ) )
849 //print( "Try to select an item before the parent\n" );
851 if( menu_selectable( menu_selected ) )
854 //print( "Try to select the parent of the parent\n" );
857 //print( "Selected:\n" );
858 //eprint( menu_selected );
861 void(void) menu_reselect =
863 menu_selected = menu_activewindow;
867 void(entity menu, float setactive) menu_jumptowindow =
869 // only jump to windows
870 if(menu.type != "ITEM_WINDOW" && menu.type != "ITEM_REFERENCE")
871 error("Cant jump to ", menu.name, " !\n");
873 // add a history point
875 menu_pushhistory(menu);
876 menu_activewindow = menu;
879 // now set the selected to the first selectable child
880 menu_selected = menu;
881 menu_automatedselection = true;
885 entity(string item_name) menu_getitem =
889 item = findstring(null_entity, name, item_name);
890 if( item == null_entity )
891 error( "Couldn't find item '", item_name, "'!" );
896 void(entity ent) menu_removeitem =
898 // raise the destroy event
906 void(entity ent) menu_pushhistory =
911 // dont create multiple histories for the same 'trigger'
914 if(menu_history._next == ent)
918 menu_keyhook = null_function;
922 his.type = "MMANAGER_HISTORY";
923 his._prev = menu_history;
924 his._child = menu_selected;
925 his._parent = menu_activewindow;
926 his._next = ent; // "used for"
931 void(void) menu_pophistory =
935 if(menu_history == null_entity)
940 menu_keyhook = null_function;
942 menu_selected = menu_history._child;
943 menu_activewindow = menu_history._parent;
946 menu_history = menu_history._prev;
951 float(entity ent) menu_verifyhistory =
953 if(menu_history == null_entity)
956 if(menu_history._next == ent)
961 void(void) menu_clearhistory =
966 while((ent = findstring(ent, type, "MMANAGER_HISTORY")) != null_entity)
971 menu_history = null_entity;