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 =
353 // FIXME: perhaps add another function or do this in some other way
354 if( substring( pName, 0, 2 ) == "::" )
355 lItem = findstring( null_entity, name, substring( pName, 2, 100000 ) );
356 // support for direction tokens, init token ##
357 else if( substring( pName, 0, 2 ) == "##" ) {
359 local float lCount, lCounter;
361 lCount = tokenize( substring( pName, 2, 100000 ) );
362 // we have the following tokens atfer the ##: up down next prev
363 for( lCounter = 0 ; lCounter < lCount && lItem ; ++lCounter ) {
364 lToken = argv( lCounter );
366 lItem = lItem._parent;
367 else if( lToken == "down" )
368 lItem = lItem._child;
369 else if( lToken == "next" )
371 else if( lToken == "prev" )
374 error( "Bad direction link(bad token): '", pName, "'!" );
377 // we start from the current namespace and try to find the object
378 // by checking for it in all parent namespaces
380 while( !lItem && (pOrigin = pOrigin._parent) != null_entity )
381 lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
384 lItem = findstring( null_entity, name, pName );
387 if( lItem == null_entity && pThrow )
388 error( "Couldn't find item '", pName, "'!" );
393 entity( entity pOrigin, string pName, bool pThrow ) Menu_GetChildEx =
398 lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
400 lItem = findstring( null_entity, name, pName );
402 if( lItem == null_entity && pThrow )
403 error( "Couldn't find item '", pName, "'!" );
408 entity( string pName ) Menu_GetItem =
410 return Menu_GetItemEx( self, pName, true );
413 entity( string pName ) Menu_GetChild =
415 return Menu_GetChildEx( self, pName, true );
418 void( entity pWindow ) Menu_EmptyWindow =
422 for( lChild = pWindow._child ; lChild ; lChild = lChild._next ) {
423 Menu_EmptyWindow( lChild );
424 Raise_Destroy( lChild );
428 pWindow._child = null_entity;
431 void( entity pEntity ) Menu_RemoveItem =
433 local entity lParent;
434 // raise the destroy event
435 lParent = pEntity._parent;
436 Menu_EmptyWindow( pEntity );
437 Raise_Destroy( pEntity );
440 Menu_LinkChildren( lParent );
443 void( entity pItem ) _Menu_PrintRunFlag =
445 if( sys_debug_runflag ) {
446 print( " ", pItem.name, " Runflags: " );
447 if( pItem._runFlag & RUNFLAG_TEMPLATE )
448 print( "TEMPLATE " );
449 if( pItem._runFlag & RUNFLAG_MOUSEINAREA )
450 print( "MOUSEINAREA " );
451 if( pItem._runFlag & RUNFLAG_HADMOUSE )
452 print( "HADMOUSE " );
453 if( pItem._runFlag & RUNFLAG_CHILDDRAWONLY )
454 print( "CHILDDRAWONLY " );
455 if( pItem._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY )
456 print( "CHILDDRAWUPDATEONLY " );
457 if( pItem._runFlag & RUNFLAG_HIDDEN )
459 if( pItem._runFlag & RUNFLAG_CLIPPED )
461 if( pItem._runFlag & RUNFLAG_NOSELECT )
462 print( "NOSELECT " );
467 void( entity pItem ) Menu_SetRunFlag =
470 if( pItem.flag & FLAG_TEMPLATE )
471 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
473 if( pItem._runFlag & RUNFLAG_MOUSEINAREA )
474 pItem._runFlag = (pItem._runFlag - RUNFLAG_MOUSEINAREA) | RUNFLAG_HADMOUSE;
475 // RUNFLAG_MOUSEINAREA,
476 // these will be handled in MENU_PROCESS_MOUSE
477 // RUNFLAG_CHILDDRAWONLY,
478 // RUNFLAG_CHILDDRAWONLY,
479 // these two are handled in InheritRunFlag
481 // check if it is within the clipping area (ie. really visible)
482 // trick: since the position and size are clipped against the previous clipping area
483 // Menu_Clip_Size will be '0 0 0', if the areas dont overlap
484 if( Menu_Clip_Size == '0 0 0' && Menu_Clip_Position != '0 0 0' )
485 pItem._runFlag = pItem._runFlag | RUNFLAG_CLIPPED;
487 if( ( pItem.flag & FLAG_HIDDEN ) ||
488 ( pItem._runFlag & RUNFLAG_TEMPLATE ) ||
489 ( ( pItem.flag & FLAG_SERVERONLY ) && !( gamestatus & GAME_ISSERVER ) ) ||
490 ( ( pItem.flag & FLAG_CONNECTEDONLY ) && !( gamestatus & GAME_CONNECTED ) ) ||
491 ( ( pItem.flag & FLAG_DEVELOPERONLY ) && !( gamestatus & GAME_DEVELOPER ) ) )
492 pItem._runFlag = pItem._runFlag | RUNFLAG_HIDDEN;
494 if( ( pItem.flag & FLAG_NOSELECT ) ||
495 ( pItem.flag & FLAG_DRAWONLY ) ||
496 ( pItem.flag & FLAG_DRAWUPDATEONLY ) ||
497 ( pItem.flag & FLAG_EMBEDDED ) ||
498 ( pItem._runFlag & RUNFLAG_TEMPLATE ) ||
499 ( pItem._runFlag & RUNFLAG_HIDDEN ) ||
500 ( pItem._runFlag & RUNFLAG_CHILDDRAWONLY ) ||
501 ( pItem._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) )
502 pItem._runFlag = pItem._runFlag | RUNFLAG_NOSELECT;
504 _Menu_PrintRunFlag( pItem );
507 void( entity pParent, entity pItem ) Menu_InheritRunFlag =
510 pItem._runFlag = pItem._runFlag & (RUNFLAG_MOUSEINAREA | RUNFLAG_DELETEFRAME | RUNFLAG_DELETETOGGLE | RUNFLAG_SPAWNED);
512 if( pParent._runFlag & RUNFLAG_TEMPLATE )
513 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
515 if( ( pParent._runFlag & RUNFLAG_CHILDDRAWONLY ) ||
516 ( pParent.flag & FLAG_CHILDDRAWONLY ) )
517 pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWONLY;
518 // inherit drawupdateonly
519 if( ( pParent._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) ||
520 ( pParent.flag & FLAG_CHILDDRAWUPDATEONLY ) )
521 pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWUPDATEONLY;
522 if( pParent._runFlag & RUNFLAG_HIDDEN )
523 pItem._runFlag = pItem._runFlag | RUNFLAG_HIDDEN;
526 void() Menu_UpdateRunFlags =
528 local vector lPos, lSize, lOrg;
530 lPos = Menu_Clip_Position;
531 lSize = Menu_Clip_Size;
534 Menu_Process_Setup();
536 // set the runflag of the active window
537 Menu_ActiveWindow._runFlag = Menu_ActiveWindow._runFlag & RUNFLAG_MOUSEINAREA;
539 // update runflag by using the view tree
540 Menu_ProcessRunFlag( Menu_ActiveWindow );
542 Menu_Clip_Size = lSize;
543 Menu_Clip_Position = lPos;
545 Menu_Cursor_Position = Cursor_Position - Menu_Origin;
548 bool( entity pEntity ) Menu_HasEvents =
550 if( pEntity._runFlag & RUNFLAG_CHILDDRAWONLY )
552 if( pEntity._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY )
554 if( pEntity.flag & FLAG_DRAWONLY )
556 if( pEntity.flag & FLAG_DRAWUPDATEONLY )
558 //if( pEntity._runflag & RUNFLAG_HIDDEN )
564 bool( entity pEntity ) Menu_IsVisible =
566 return !(pEntity._runFlag & (RUNFLAG_HIDDEN | RUNFLAG_CLIPPED));
569 bool( entity pEntity ) Menu_IsSelectable =
571 return !(pEntity._runFlag & RUNFLAG_NOSELECT); // && !(pEntity._runFlag & RUNFLAG_TEMPLATE);
574 bool( entity pEntity ) Menu_IsTemplate =
576 return pEntity._runFlag & RUNFLAG_TEMPLATE;
579 bool( entity pEntity ) Menu_IsEmbedded =
581 return pEntity.flag & FLAG_EMBEDDED;
584 string( entity pItem ) Menu_GetName =
586 return substring( pItem.name, strlen( pItem.parent ) + 2, 100000 );