4 // TODO: finish the debug output
5 void( float pLevel, string pText ) _Menu_Structure_Debug =
7 if( pLevel <= sys_debug_structure )
11 void( bool pUser ) _Menu_Select =
13 Raise_Select( Menu_ActiveItem, true, pUser );
16 entity( entity pItem ) _Menu_GetParent =
20 if( Menu_IsEmbedded( pItem._parent ) )
21 return _Menu_GetParent( pItem._parent );
25 bool( entity pItem, entity pParent ) _Menu_IsEmbeddedParentOf =
27 if( pItem._parent == pParent )
29 if( Menu_IsEmbedded( pItem._parent ) )
30 return _Menu_IsEmbeddedParentOf( pItem._parent, pParent );
34 entity( entity pItem ) _Menu_GetFirst =
36 if( Menu_IsEmbedded( pItem ) && pItem._child )
37 return _Menu_GetFirst( pItem._child );
41 entity( entity pItem ) _Menu_GetLast =
43 if( Menu_IsEmbedded( pItem ) && pItem._child ) {
46 for( lNode = pItem._child ; lNode._next ; lNode = lNode._next );
47 return _Menu_GetLast( lNode );
52 entity( entity pItem ) _Menu_GetNext =
58 return _Menu_GetFirst( lNext );
59 if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow )
60 return _Menu_GetNext( pItem._parent );
65 entity( entity pItem ) _Menu_GetPrev =
71 return _Menu_GetLast( lPrev );
72 if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow )
73 return _Menu_GetPrev( pItem._parent );
78 void() _Menu_SelectNext =
82 if( !Menu_ActiveItem ) {
83 _Menu_Structure_Debug( 1, "_SelectNext: Bad Menu_ActiveItem!\n" );
87 // try to select the next item
88 lTemp = Menu_ActiveItem;
89 while( (lTemp = _Menu_GetNext( lTemp )) != null_entity )
90 if( Menu_IsSelectable( lTemp ) ) {
91 Menu_ActiveItem = lTemp;
92 _Menu_Structure_Debug( 1, strcat( "_SelectNext: ", lTemp.name, "\n" ) );
96 // only because of embedded:
97 for( lTemp = Menu_ActiveItem ; _Menu_GetPrev( lTemp ) ; lTemp = _Menu_GetPrev( lTemp ) );
98 // TODO: rewrite _Menu_Select* to use an additional temp variable for storing the result of the functionc all
99 for( ; lTemp != Menu_ActiveItem ; lTemp = _Menu_GetNext( lTemp ) )
100 if( Menu_IsSelectable( lTemp ) ) {
101 Menu_ActiveItem = lTemp;
102 _Menu_Structure_Debug( 1, strcat( "_SelectNext after loop: ", lTemp.name, "\n" ) );
107 void() _Menu_SelectPrev =
111 if( !Menu_ActiveItem ) {
112 _Menu_Structure_Debug( 1, "_SelectPrev: Bad Menu_ActiveItem!\n" );
116 // try to select the previous item
117 lTemp = Menu_ActiveItem;
118 while( (lTemp = _Menu_GetPrev( lTemp )) != null_entity )
119 if( Menu_IsSelectable( lTemp ) ) {
120 Menu_ActiveItem = lTemp;
121 _Menu_Structure_Debug( 1, strcat( "_SelectPrev: ", lTemp.name, "\n" ) );
125 for( lTemp = Menu_ActiveItem ; _Menu_GetNext( lTemp ) ; lTemp = _Menu_GetNext( lTemp ) );
126 for( ; lTemp != Menu_ActiveItem ; lTemp = _Menu_GetPrev( lTemp ) ) {
127 if( Menu_IsSelectable( lTemp ) ) {
128 Menu_ActiveItem = lTemp;
129 _Menu_Structure_Debug( 1, strcat( "_SelectPrev after loop: ", lTemp.name, "\n" ) );
135 bool() _Menu_SelectUp =
137 // Menu_ActiveItem is the child
138 local entity lSelected, lParent, lNode;
140 lSelected = Menu_ActiveItem;
142 _Menu_Structure_Debug( 1, "_SelectUp: Bad Menu_ActiveItem!\n" );
146 // If we try to select up the active window, we'll pop the menu history
147 if( lSelected == Menu_ActiveWindow ) {
148 // If there is no history, we quit the menu
149 _Menu_Structure_Debug( 2, "_SelectUp: Selecting up current active window..\n" );
150 if( Menu_History == null_entity ) {
151 _Menu_Structure_Debug( 2, "_SelectUp: Empty history -> toggling menu..\n" );
153 Menu_Reselect( false );
157 _Menu_Structure_Debug( 2, "_SelectUp: Popping history..\n" );
161 lParent = _Menu_GetParent( lSelected );
163 _Menu_Structure_Debug( 2, "_SelectUp: No parent and not active window!\n" );
167 // If this window is selectable, we know that there is at least one selectable item in the parent,
168 // thus we will select the parent
169 if( Menu_IsSelectable( lParent ) ) {
170 Menu_ActiveItem = lParent;
171 _Menu_Structure_Debug( 1, strcat( "_SelectUp: first parent: ", lParent.name, "\n" ) );
175 // if there is no parent window of this window (lParent), it's the active window
176 // else we have failed
177 if( lParent == Menu_ActiveWindow ) {
178 Menu_ActiveItem = Menu_ActiveWindow;
179 _Menu_Structure_Debug( 2, strcat( "_SelectUp: select up parent: ", Menu_ActiveItem.name, "\n" ) );
180 if( _Menu_SelectUp() )
182 Menu_ActiveItem = lSelected;
184 } else if( !lParent._parent ) {
185 _Menu_Structure_Debug( 1, "_SelectUp: No parent of parent and not active window!\n" );
189 // If not, we try to determine whether the window is the first window with a selectable children in
190 // the parent window. If lParent is the selected by selectdown, we move up, if not we have found it.
192 Menu_ActiveItem = _Menu_GetParent( lParent );
193 _Menu_Structure_Debug( 2, strcat( "_SelectUp: SelectDown on parent of parent '", Menu_ActiveItem.name, "' \n" ) );
195 // thanks to embedded windows (and not only them) - added later on - perhaps doesnt really
196 // fit into the old logic behind it - take this with caution
197 for( lNode = Menu_ActiveItem ; lNode ; lNode = lNode._parent )
198 if( lNode._parent == lParent ) {
199 Menu_ActiveItem = _Menu_GetParent( lSelected ); //lParent._parent;
200 if( _Menu_SelectUp() )
202 Menu_ActiveItem = lSelected;
206 // else we have already found the window we have searched!
210 void( entity pItem ) _Menu_PrintRunFlag;
211 bool() _Menu_SelectDown =
213 // Menu_ActiveItem is the window
214 local entity lParent, lChild;
216 lParent = Menu_ActiveItem;
218 _Menu_Structure_Debug( 1, "_SelectDown: Bad Menu_ActiveItem!\n" );
222 // lets find the first selectable item
223 for( lChild = _Menu_GetFirst( lParent._child ) ; lChild ; lChild = _Menu_GetNext( lChild ) )
224 if( Menu_IsSelectable( lChild ) ) {
225 Menu_ActiveItem = lChild;
226 _Menu_PrintRunFlag( lChild );
227 _Menu_Structure_Debug( 1, strcat( "_SelectDown: ", lChild.name, "\n" ) );
231 // lets find the first window that has a selectable item
232 for( lChild = _Menu_GetFirst( lParent._child ) ; lChild ; lChild = _Menu_GetNext( lChild ) )
233 if( !Menu_IsEmbedded( lChild ) ) {
234 Menu_ActiveItem = lChild;
235 _Menu_Structure_Debug( 2, strcat( "_SelectDown: Try child: ", Menu_ActiveItem.name, "\n" ) );
236 if( _Menu_SelectDown() )
240 Menu_ActiveItem = lParent;
244 void() _Menu_Reselect =
246 Menu_ActiveItem = Menu_ActiveWindow;
250 void( bool pUser ) Menu_SelectNext =
252 Raise_Select( Menu_ActiveItem, false, pUser );
254 Raise_Select( Menu_ActiveItem, true, pUser );
257 void( bool pUser ) Menu_SelectPrev =
259 Raise_Select( Menu_ActiveItem, false, pUser );
261 Raise_Select( Menu_ActiveItem, true, pUser );
264 bool( bool pUser ) Menu_SelectUp =
268 lOld = Menu_ActiveItem;
269 if( _Menu_SelectUp() ) {
270 Raise_Select( lOld, false, pUser );
271 Raise_Select( Menu_ActiveItem, true, pUser );
277 bool( bool pUser ) Menu_SelectDown =
281 lOld = Menu_ActiveItem;
282 if( _Menu_SelectDown() ) {
283 Raise_Select( lOld, false, pUser );
284 Raise_Select( Menu_ActiveItem, true, pUser );
290 void( entity pItem, bool pUser ) Menu_Select =
292 Raise_Select( Menu_ActiveItem, false, pUser );
293 _Menu_Structure_Debug( 1, strcat( "Menu_Select: ", pItem.name, "\n" ) );
294 Menu_ActiveItem = pItem;
295 Raise_Select( Menu_ActiveItem, true, pUser );
298 void( entity pItem, bool pUser ) Menu_CorrectSelection =
300 if( Menu_ActiveItem != pItem )
301 Menu_Select( pItem, pUser );
304 void( bool pUser ) Menu_Reselect =
306 Raise_Select( Menu_ActiveItem, false, pUser );
308 Raise_Select( Menu_ActiveItem, true, pUser );
311 void( entity pMenu, bool pMakeActive, bool pUser ) Menu_JumpToWindow =
313 Raise_Select( Menu_ActiveItem, false, pUser );
315 // only jump to windows
317 error("Cant jump to ", pMenu.name, " !\n");
319 // add a history point
321 Menu_History_Push( pMenu, Util_NullFunction );
322 Menu_ActiveWindow = pMenu;
325 // now set the selected to the first selectable child
326 Menu_ActiveItem = pMenu;
327 if( !_Menu_SelectDown() )
328 error( "Couldn't jump to ", pMenu.name, " !\n" );
330 Raise_Select( Menu_ActiveItem, true, pUser );
334 bool( entity pEntity, float pFlag ) Menu_HasFlag =
336 if( pEntity.flag & pFlag )
341 bool( entity pEntity, float pRunFlag ) Menu_HasRunFlag =
343 if( pEntity._runFlag & pRunFlag )
349 entity( entity pOrigin, string pName, bool pThrow ) Menu_GetItemEx =
352 local string lFirstTwo;
354 lFirstTwo = substring( pName, 0, 2 );
356 // FIXME: perhaps add another function or do this in some other way
357 if( lFirstTwo == "::" )
358 lItem = findstring( null_entity, name, substring( pName, 2, 100000 ) );
359 // support for direction tokens, init token ##
360 else if( lFirstTwo == "##" ) {
362 local float lCount, lCounter;
364 lCount = tokenize( substring( pName, 2, 100000 ) );
365 // we have the following tokens atfer the ##: up down next prev
366 for( lCounter = 0 ; lCounter < lCount && lItem ; ++lCounter ) {
367 lToken = argv( lCounter );
369 lItem = lItem._parent;
370 else if( lToken == "down" )
371 lItem = lItem._child;
372 else if( lToken == "next" )
374 else if( lToken == "prev" )
377 error( "Bad direction link(bad token): '", pName, "'!" );
380 // we start from the current namespace and try to find the object
381 // by checking for it in all parent namespaces
383 while( !lItem && (pOrigin = pOrigin._parent) != null_entity )
384 lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
387 lItem = findstring( null_entity, name, pName );
390 if( lItem == null_entity && pThrow )
391 error( "Couldn't find item '", pName, "'!" );
396 entity( entity pOrigin, string pName, bool pThrow ) Menu_GetChildEx =
401 lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
403 lItem = findstring( null_entity, name, pName );
405 if( lItem == null_entity && pThrow )
406 error( "Couldn't find item '", pName, "'!" );
411 entity( string pName ) Menu_GetItem =
413 return Menu_GetItemEx( self, pName, true );
416 entity( string pName ) Menu_GetChild =
418 return Menu_GetChildEx( self, pName, true );
421 void( entity pWindow ) Menu_EmptyWindow =
425 for( lChild = pWindow._child ; lChild ; lChild = lChild._next ) {
426 Menu_EmptyWindow( lChild );
427 Raise_Destroy( lChild );
431 pWindow._child = null_entity;
434 void( entity pEntity ) Menu_RemoveItem =
436 local entity lParent;
437 // raise the destroy event
438 lParent = pEntity._parent;
439 Menu_EmptyWindow( pEntity );
440 Raise_Destroy( pEntity );
443 Menu_LinkChildren( lParent );
446 void( entity pItem ) _Menu_PrintRunFlag =
448 if( sys_debug_runflag ) {
449 print( " ", pItem.name, " Runflags: " );
450 if( pItem._runFlag & RUNFLAG_TEMPLATE )
451 print( "TEMPLATE " );
452 if( pItem._runFlag & RUNFLAG_MOUSEINAREA )
453 print( "MOUSEINAREA " );
454 if( pItem._runFlag & RUNFLAG_HADMOUSE )
455 print( "HADMOUSE " );
456 if( pItem._runFlag & RUNFLAG_CHILDDRAWONLY )
457 print( "CHILDDRAWONLY " );
458 if( pItem._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY )
459 print( "CHILDDRAWUPDATEONLY " );
460 if( pItem._runFlag & RUNFLAG_HIDDEN )
462 if( pItem._runFlag & RUNFLAG_CLIPPED )
464 if( pItem._runFlag & RUNFLAG_NOSELECT )
465 print( "NOSELECT " );
470 void( entity pItem ) Menu_SetRunFlag =
473 local float lRunFlag;
478 if( lFlag & FLAG_TEMPLATE )
479 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
481 lRunFlag = pItem._runFlag;
482 if(lRunFlag & RUNFLAG_MOUSEINAREA )
483 pItem._runFlag = (lRunFlag - RUNFLAG_MOUSEINAREA) | RUNFLAG_HADMOUSE;
484 // RUNFLAG_MOUSEINAREA,
485 // these will be handled in MENU_PROCESS_MOUSE
486 // RUNFLAG_CHILDDRAWONLY,
487 // RUNFLAG_CHILDDRAWONLY,
488 // these two are handled in InheritRunFlag
490 // check if it is within the clipping area (ie. really visible)
491 // trick: since the position and size are clipped against the previous clipping area
492 // Menu_Clip_Size will be '0 0 0', if the areas dont overlap
493 if( Menu_Clip_Size == '0 0 0' && Menu_Clip_Position != '0 0 0' )
494 pItem._runFlag = pItem._runFlag | RUNFLAG_CLIPPED;
496 lRunFlag = pItem._runFlag;
497 if( ( lFlag & FLAG_HIDDEN ) ||
498 ( lRunFlag & RUNFLAG_TEMPLATE ) ||
499 ( ( lFlag & FLAG_SERVERONLY ) && !( gamestatus & GAME_ISSERVER ) ) ||
500 ( ( lFlag & FLAG_CONNECTEDONLY ) && !( gamestatus & GAME_CONNECTED ) ) ||
501 ( ( lFlag & FLAG_DEVELOPERONLY ) && !( gamestatus & GAME_DEVELOPER ) ) )
502 pItem._runFlag = lRunFlag | RUNFLAG_HIDDEN;
504 lRunFlag = pItem._runFlag;
505 if( ( lFlag & FLAG_NOSELECT ) ||
506 ( lFlag & FLAG_DRAWONLY ) ||
507 ( lFlag & FLAG_DRAWUPDATEONLY ) ||
508 ( lFlag & FLAG_EMBEDDED ) ||
509 ( lRunFlag & RUNFLAG_TEMPLATE ) ||
510 ( lRunFlag & RUNFLAG_HIDDEN ) ||
511 ( lRunFlag & RUNFLAG_CHILDDRAWONLY ) ||
512 ( lRunFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) )
513 pItem._runFlag = lRunFlag | RUNFLAG_NOSELECT;
515 _Menu_PrintRunFlag( pItem );
518 void( entity pParent, entity pItem ) Menu_InheritRunFlag =
521 pItem._runFlag = pItem._runFlag & (RUNFLAG_MOUSEINAREA | RUNFLAG_DELETEFRAME | RUNFLAG_DELETETOGGLE | RUNFLAG_SPAWNED);
523 if( pParent._runFlag & RUNFLAG_TEMPLATE )
524 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
526 if( ( pParent._runFlag & RUNFLAG_CHILDDRAWONLY ) ||
527 ( pParent.flag & FLAG_CHILDDRAWONLY ) )
528 pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWONLY;
529 // inherit drawupdateonly
530 if( ( pParent._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) ||
531 ( pParent.flag & FLAG_CHILDDRAWUPDATEONLY ) )
532 pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWUPDATEONLY;
533 if( pParent._runFlag & RUNFLAG_HIDDEN )
534 pItem._runFlag = pItem._runFlag | RUNFLAG_HIDDEN;
537 void() Menu_UpdateRunFlags =
539 local vector lPos, lSize, lOrg;
541 lPos = Menu_Clip_Position;
542 lSize = Menu_Clip_Size;
545 Menu_Process_Setup();
547 // set the runflag of the active window
548 Menu_ActiveWindow._runFlag = Menu_ActiveWindow._runFlag & RUNFLAG_MOUSEINAREA;
550 // update runflag by using the view tree
551 Menu_ProcessRunFlag( Menu_ActiveWindow );
553 Menu_Clip_Size = lSize;
554 Menu_Clip_Position = lPos;
556 Menu_Cursor_Position = Cursor_Position - Menu_Origin;
559 bool( entity pEntity ) Menu_HasEvents =
561 if( pEntity._runFlag & RUNFLAG_CHILDDRAWONLY )
563 if( pEntity._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY )
565 if( pEntity.flag & FLAG_DRAWONLY )
567 if( pEntity.flag & FLAG_DRAWUPDATEONLY )
569 //if( pEntity._runflag & RUNFLAG_HIDDEN )
575 bool( entity pEntity ) Menu_IsVisible =
577 return !(pEntity._runFlag & (RUNFLAG_HIDDEN | RUNFLAG_CLIPPED));
580 bool( entity pEntity ) Menu_IsSelectable =
582 return !(pEntity._runFlag & RUNFLAG_NOSELECT); // && !(pEntity._runFlag & RUNFLAG_TEMPLATE);
585 bool( entity pEntity ) Menu_IsTemplate =
587 return pEntity._runFlag & RUNFLAG_TEMPLATE;
590 bool( entity pEntity ) Menu_IsEmbedded =
592 return pEntity.flag & FLAG_EMBEDDED;
595 string( entity pItem ) Menu_GetName =
597 return substring( pItem.name, strlen( pItem.parent ) + 2, 100000 );