]> icculus.org git repositories - divverent/nexuiz.git/blob - data/menuqc/system/structure.qc
Revert first change in the trunk.
[divverent/nexuiz.git] / data / menuqc / system / structure.qc
1 // DP/Nex Menu
2 // system/structure.qc
3
4 // TODO: finish the debug output
5 void( float pLevel, string pText ) _Menu_Structure_Debug =
6 {
7         if( pLevel <= sys_debug_structure )
8                 print( pText );
9 };
10
11 void( bool pUser ) _Menu_Select =
12 {
13         Raise_Select( Menu_ActiveItem, true, pUser );
14 };
15
16 entity( entity pItem ) _Menu_GetParent =
17 {
18         if( !pItem._parent )
19                 return null_entity;
20         if( Menu_IsEmbedded( pItem._parent ) )
21                 return _Menu_GetParent( pItem._parent );
22         return pItem._parent;
23 };
24
25 bool( entity pItem, entity pParent ) _Menu_IsEmbeddedParentOf =
26 {
27         if( pItem._parent == pParent )
28                 return true;
29         if( Menu_IsEmbedded( pItem._parent ) )
30                 return _Menu_IsEmbeddedParentOf( pItem._parent, pParent );
31         return false;
32 };
33
34 entity( entity pItem ) _Menu_GetFirst =
35 {
36         if( Menu_IsEmbedded( pItem ) && pItem._child )
37                 return _Menu_GetFirst( pItem._child );
38         return pItem;
39 };
40
41 entity( entity pItem ) _Menu_GetLast =
42 {
43         if( Menu_IsEmbedded( pItem ) && pItem._child ) {
44                 local entity lNode;
45
46                 for( lNode = pItem._child ; lNode._next ; lNode = lNode._next );
47                 return _Menu_GetLast( lNode );
48         }
49         return pItem;
50 };
51
52 entity( entity pItem ) _Menu_GetNext =
53 {
54         local entity lNext;
55
56         lNext = pItem._next;
57         if( lNext )
58                 return _Menu_GetFirst( lNext );
59         if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow )
60                 return _Menu_GetNext( pItem._parent );
61         else
62                 return null_entity;
63 };
64
65 entity( entity pItem ) _Menu_GetPrev =
66 {
67         local entity lPrev;
68
69         lPrev = pItem._prev;
70         if( lPrev )
71                 return _Menu_GetLast( lPrev );
72         if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow )
73                 return _Menu_GetPrev( pItem._parent );
74         else
75                 return null_entity;
76 };
77
78 void() _Menu_SelectNext =
79 {
80         local entity lTemp;
81
82         if( !Menu_ActiveItem ) {
83                 _Menu_Structure_Debug( 1, "_SelectNext: Bad Menu_ActiveItem!\n" );
84                 return;
85         }
86
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" ) );
93                         return;
94                 }
95         // loop
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" ) );
103                         return;
104                 }
105 };
106
107 void() _Menu_SelectPrev =
108 {
109         local entity lTemp;
110
111         if( !Menu_ActiveItem ) {
112                 _Menu_Structure_Debug( 1, "_SelectPrev: Bad Menu_ActiveItem!\n" );
113                 return;
114         }
115
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" ) );
122                         return;
123                 }
124         // loop
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" ) );
130                         return;
131                 }
132         }
133 };
134
135 bool() _Menu_SelectUp =
136 {
137         // Menu_ActiveItem is the child
138         local entity lSelected, lParent, lNode;
139
140         lSelected = Menu_ActiveItem;
141         if( !lSelected ) {
142                 _Menu_Structure_Debug( 1, "_SelectUp: Bad Menu_ActiveItem!\n" );
143                 return false;
144         }
145
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" );
152                         if( !Menu_Toggle() )
153                                 Menu_Reselect( false );
154                         return true;
155                 }
156
157                 _Menu_Structure_Debug( 2, "_SelectUp: Popping history..\n" );
158                 Menu_History_Pop();
159         }
160
161         lParent = _Menu_GetParent( lSelected );
162         if( !lParent ) {
163                 _Menu_Structure_Debug( 2, "_SelectUp: No parent and not active window!\n" );
164                 return false;
165         }
166
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" ) );
172                 return true;
173         }
174
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() )
181                         return true;
182                 Menu_ActiveItem = lSelected;
183                 return false;
184         } else if( !lParent._parent ) {
185                 _Menu_Structure_Debug( 1, "_SelectUp: No parent of parent and not active window!\n" );
186                 return false;
187         }
188
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.
191         // IDEA: inline this
192         Menu_ActiveItem = _Menu_GetParent( lParent );
193         _Menu_Structure_Debug( 2, strcat( "_SelectUp: SelectDown on parent of parent '", Menu_ActiveItem.name, "' \n" ) );
194         _Menu_SelectDown();
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() )
201                                 return true;
202                         Menu_ActiveItem = lSelected;
203                         return false;
204                 }
205
206         // else we have already found the window we have searched!
207         return true;
208 };
209
210 void( entity pItem ) _Menu_PrintRunFlag;
211 bool() _Menu_SelectDown =
212 {
213         // Menu_ActiveItem is the window
214         local entity lParent, lChild;
215
216         lParent = Menu_ActiveItem;
217         if( !lParent ) {
218                 _Menu_Structure_Debug( 1, "_SelectDown: Bad Menu_ActiveItem!\n" );
219                 return false;
220         }
221
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" ) );
228                         return true;
229                 }
230
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() )
237                                 return true;
238                 }
239
240         Menu_ActiveItem = lParent;
241         return false;
242 };
243
244 void() _Menu_Reselect =
245 {
246         Menu_ActiveItem = Menu_ActiveWindow;
247         _Menu_SelectDown();
248 };
249
250 void( bool pUser ) Menu_SelectNext =
251 {
252         Raise_Select( Menu_ActiveItem, false, pUser );
253         _Menu_SelectNext();
254         Raise_Select( Menu_ActiveItem, true, pUser );
255 };
256
257 void( bool pUser ) Menu_SelectPrev =
258 {
259         Raise_Select( Menu_ActiveItem, false, pUser );
260         _Menu_SelectPrev();
261         Raise_Select( Menu_ActiveItem, true, pUser );
262 };
263
264 bool( bool pUser ) Menu_SelectUp =
265 {
266         local entity lOld;
267
268         lOld = Menu_ActiveItem;
269         if( _Menu_SelectUp() ) {
270                 Raise_Select( lOld, false, pUser );
271                 Raise_Select( Menu_ActiveItem, true, pUser );
272                 return true;
273         }
274         return false;
275 };
276
277 bool( bool pUser ) Menu_SelectDown =
278 {
279         local entity lOld;
280
281         lOld = Menu_ActiveItem;
282         if( _Menu_SelectDown() ) {
283                 Raise_Select( lOld, false, pUser );
284                 Raise_Select( Menu_ActiveItem, true, pUser );
285                 return true;
286         }
287         return false;
288 };
289
290 void( entity pItem, bool pUser ) Menu_Select =
291 {
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 );
296 };
297
298 void( entity pItem, bool pUser ) Menu_CorrectSelection =
299 {
300         if( Menu_ActiveItem != pItem )
301                 Menu_Select( pItem, pUser );
302 };
303
304 void( bool pUser ) Menu_Reselect =
305 {
306         Raise_Select( Menu_ActiveItem, false, pUser );
307         _Menu_Reselect();
308         Raise_Select( Menu_ActiveItem, true, pUser );
309 };
310
311 void( entity pMenu, bool pMakeActive, bool pUser ) Menu_JumpToWindow =
312 {
313         Raise_Select( Menu_ActiveItem, false, pUser );
314
315         // only jump to windows
316         if( !pMenu._child )
317                 error("Cant jump to ", pMenu.name, " !\n");
318
319         // add a history point
320         if( pMakeActive ) {
321                 Menu_History_Push( pMenu, Util_NullFunction );
322                 Menu_ActiveWindow = pMenu;
323         }
324
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" );
329
330         Raise_Select( Menu_ActiveItem, true, pUser );
331 };
332
333 #ifdef USEFUNCTIONS
334 bool( entity pEntity, float pFlag ) Menu_HasFlag =
335 {
336         if( pEntity.flag & pFlag )
337                 return true;
338         return false;
339 };
340
341 bool( entity pEntity, float pRunFlag ) Menu_HasRunFlag =
342 {
343         if( pEntity._runFlag & pRunFlag )
344                 return true;
345         return false;
346 };
347 #endif
348
349 entity( entity pOrigin, string pName, bool pThrow ) Menu_GetItemEx =
350 {
351         local entity lItem;
352         local string lFirstTwo;
353
354         lFirstTwo = substring( pName, 0, 2 );
355
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 == "##" ) {
361                 local string lToken;
362                 local float lCount, lCounter;
363                 lItem = pOrigin;
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 );
368                         if( lToken == "up" )
369                                 lItem = lItem._parent;
370                         else if( lToken == "down" )
371                                 lItem = lItem._child;
372                         else if( lToken == "next" )
373                                 lItem = lItem._next;
374                         else if( lToken == "prev" )
375                                 lItem = lItem._prev;
376                         else
377                                 error( "Bad direction link(bad token): '", pName, "'!" );
378                 }
379         } else  {
380                 // we start from the current namespace and try to find the object
381                 // by checking for it in all parent namespaces
382                 lItem = null_entity;
383                 while( !lItem && (pOrigin = pOrigin._parent) != null_entity )
384                         lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
385
386                 if( !lItem )
387                         lItem = findstring( null_entity, name, pName );
388         }
389
390         if( lItem == null_entity && pThrow )
391                 error( "Couldn't find item '", pName, "'!" );
392
393         return lItem;
394 };
395
396 entity( entity pOrigin, string pName, bool pThrow ) Menu_GetChildEx =
397 {
398         local entity lItem;
399
400         if( pOrigin )
401                 lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) );
402         else
403                 lItem = findstring( null_entity, name, pName );
404
405         if( lItem == null_entity && pThrow )
406                 error( "Couldn't find item '", pName, "'!" );
407
408         return lItem;
409 };
410
411 entity( string pName ) Menu_GetItem =
412 {
413         return Menu_GetItemEx( self, pName, true );
414 };
415
416 entity( string pName ) Menu_GetChild =
417 {
418         return Menu_GetChildEx( self, pName, true );
419 };
420
421 void( entity pWindow ) Menu_EmptyWindow =
422 {
423         local entity lChild;
424
425         for( lChild = pWindow._child ; lChild ; lChild = lChild._next ) {
426                 Menu_EmptyWindow( lChild );
427                 Raise_Destroy( lChild );
428                 remove( lChild );
429         }
430
431         pWindow._child = null_entity;
432 };
433
434 void( entity pEntity ) Menu_RemoveItem =
435 {
436         local entity lParent;
437         // raise the destroy event
438         lParent = pEntity._parent;
439         Menu_EmptyWindow( pEntity );
440         Raise_Destroy( pEntity );
441         remove( pEntity );
442         if( lParent )
443                 Menu_LinkChildren( lParent );
444 };
445
446 void( entity pItem ) _Menu_PrintRunFlag =
447 {
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 )
461                         print( "HIDDEN " );
462                 if( pItem._runFlag & RUNFLAG_CLIPPED )
463                         print( "CLIPPED " );
464                 if( pItem._runFlag & RUNFLAG_NOSELECT )
465                         print( "NOSELECT " );
466                 print( "\n" );
467         }
468 };
469
470 void( entity pItem ) Menu_SetRunFlag =
471 {
472         local float lFlag;
473         local float lRunFlag;
474
475         lFlag = pItem.flag;
476
477         // RUNFLAG_TEMPLATE
478         if( lFlag & FLAG_TEMPLATE )
479                 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
480         // RUNFLAG_HADMOUSE,
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
489         // RUNFLAG_CLIPPED,
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;
495         // RUNFLAG_HIDDEN
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;
503         // RUNFLAG_NOSELECT
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;
514
515         _Menu_PrintRunFlag( pItem );
516 };
517
518 void( entity pParent, entity pItem ) Menu_InheritRunFlag =
519 {
520         // reset the runflag
521         pItem._runFlag = pItem._runFlag & (RUNFLAG_MOUSEINAREA | RUNFLAG_DELETEFRAME | RUNFLAG_DELETETOGGLE | RUNFLAG_SPAWNED);
522         // inherit template
523         if( pParent._runFlag & RUNFLAG_TEMPLATE )
524                 pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE;
525         // inherit drawonly
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;
535 };
536
537 void() Menu_UpdateRunFlags =
538 {
539         local vector lPos, lSize, lOrg;
540
541         lPos = Menu_Clip_Position;
542         lSize = Menu_Clip_Size;
543         lOrg = Menu_Origin;
544
545         Menu_Process_Setup();
546
547         // set the runflag of the active window
548         Menu_ActiveWindow._runFlag = Menu_ActiveWindow._runFlag & RUNFLAG_MOUSEINAREA;
549
550         // update runflag by using the view tree
551         Menu_ProcessRunFlag( Menu_ActiveWindow );
552
553         Menu_Clip_Size = lSize;
554         Menu_Clip_Position = lPos;
555         Menu_Origin = lOrg;
556         Menu_Cursor_Position = Cursor_Position - Menu_Origin;
557 };
558
559 bool( entity pEntity ) Menu_HasEvents =
560 {
561         if( pEntity._runFlag & RUNFLAG_CHILDDRAWONLY )
562                 return false;
563         if( pEntity._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY )
564                 return false;
565         if( pEntity.flag & FLAG_DRAWONLY )
566                 return false;
567         if( pEntity.flag & FLAG_DRAWUPDATEONLY )
568                 return false;
569         //if( pEntity._runflag & RUNFLAG_HIDDEN )
570         //      return false;
571         return true;
572 };
573
574 #ifdef USEFUNCTIONS
575 bool( entity pEntity ) Menu_IsVisible =
576 {
577         return !(pEntity._runFlag & (RUNFLAG_HIDDEN | RUNFLAG_CLIPPED));
578 };
579
580 bool( entity pEntity ) Menu_IsSelectable =
581 {
582         return !(pEntity._runFlag & RUNFLAG_NOSELECT); // && !(pEntity._runFlag & RUNFLAG_TEMPLATE);
583 };
584
585 bool( entity pEntity ) Menu_IsTemplate =
586 {
587         return pEntity._runFlag & RUNFLAG_TEMPLATE;
588 };
589
590 bool( entity pEntity ) Menu_IsEmbedded =
591 {
592         return pEntity.flag & FLAG_EMBEDDED;
593 };
594
595 string( entity pItem ) Menu_GetName =
596 {
597         return substring( pItem.name, strlen( pItem.parent ) + 2, 100000 );
598 };
599 #endif