Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/freeglut/src/fg_structure.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * fg_structure.c | |
| 3 * | |
| 4 * Windows and menus need tree structure | |
| 5 * | |
| 6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. | |
| 7 * Written by Pawel W. Olszta, <olszta@sourceforge.net> | |
| 8 * Creation date: Sat Dec 18 1999 | |
| 9 * | |
| 10 * Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 * copy of this software and associated documentation files (the "Software"), | |
| 12 * to deal in the Software without restriction, including without limitation | |
| 13 * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 * and/or sell copies of the Software, and to permit persons to whom the | |
| 15 * Software is furnished to do so, subject to the following conditions: | |
| 16 * | |
| 17 * The above copyright notice and this permission notice shall be included | |
| 18 * in all copies or substantial portions of the Software. | |
| 19 * | |
| 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
| 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| 24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 26 */ | |
| 27 | |
| 28 #include <GL/freeglut.h> | |
| 29 #include "fg_internal.h" | |
| 30 | |
| 31 /* -- GLOBAL EXPORTS ------------------------------------------------------- */ | |
| 32 | |
| 33 /* | |
| 34 * The SFG_Structure container holds information about windows and menus | |
| 35 * created between glutInit() and glutMainLoop() return. | |
| 36 */ | |
| 37 | |
| 38 SFG_Structure fgStructure = { { NULL, NULL }, /* The list of windows */ | |
| 39 { NULL, NULL }, /* The list of menus */ | |
| 40 { NULL, NULL }, /* Windows to Destroy list */ | |
| 41 NULL, /* The current window */ | |
| 42 NULL, /* The current menu */ | |
| 43 NULL, /* The menu OpenGL context */ | |
| 44 NULL, /* The game mode window */ | |
| 45 0, /* The current new window ID */ | |
| 46 0 }; /* The current new menu ID */ | |
| 47 | |
| 48 | |
| 49 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ | |
| 50 | |
| 51 extern void fgPlatformCreateWindow ( SFG_Window *window ); | |
| 52 extern void fghDefaultReshape(int width, int height); | |
| 53 | |
| 54 static void fghClearCallBacks( SFG_Window *window ) | |
| 55 { | |
| 56 if( window ) | |
| 57 { | |
| 58 int i; | |
| 59 for( i = 0; i < TOTAL_CALLBACKS; ++i ) | |
| 60 window->CallBacks[ i ] = NULL; | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 /* | |
| 65 * This private function creates, opens and adds to the hierarchy | |
| 66 * a freeglut window complete with OpenGL context and stuff... | |
| 67 * | |
| 68 * If parent is set to NULL, the window created will be a topmost one. | |
| 69 */ | |
| 70 SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, | |
| 71 GLboolean positionUse, int x, int y, | |
| 72 GLboolean sizeUse, int w, int h, | |
| 73 GLboolean gameMode, GLboolean isMenu ) | |
| 74 { | |
| 75 /* Have the window object created */ | |
| 76 SFG_Window *window = (SFG_Window *)calloc( 1, sizeof(SFG_Window) ); | |
| 77 | |
| 78 fgPlatformCreateWindow ( window ); | |
| 79 | |
| 80 fghClearCallBacks( window ); | |
| 81 SET_WCB( *window, Reshape, fghDefaultReshape); | |
| 82 | |
| 83 /* Initialize the object properties */ | |
| 84 window->ID = ++fgStructure.WindowID; | |
| 85 | |
| 86 fgListInit( &window->Children ); | |
| 87 if( parent ) | |
| 88 { | |
| 89 fgListAppend( &parent->Children, &window->Node ); | |
| 90 window->Parent = parent; | |
| 91 } | |
| 92 else | |
| 93 fgListAppend( &fgStructure.Windows, &window->Node ); | |
| 94 | |
| 95 /* Set the default mouse cursor */ | |
| 96 window->State.Cursor = GLUT_CURSOR_INHERIT; | |
| 97 | |
| 98 /* Mark window as menu if a menu is to be created */ | |
| 99 window->IsMenu = isMenu; | |
| 100 | |
| 101 /* | |
| 102 * Open the window now. The fgOpenWindow() function is system | |
| 103 * dependent, and resides in fg_window.c. Uses fgState. | |
| 104 */ | |
| 105 fgOpenWindow( window, title, positionUse, x, y, sizeUse, w, h, gameMode, | |
| 106 (GLboolean)(parent ? GL_TRUE : GL_FALSE) ); | |
| 107 | |
| 108 return window; | |
| 109 } | |
| 110 | |
| 111 /* | |
| 112 * This private function creates a menu and adds it to the menus list | |
| 113 */ | |
| 114 SFG_Menu* fgCreateMenu( FGCBMenu menuCallback ) | |
| 115 { | |
| 116 SFG_Window *current_window = fgStructure.CurrentWindow; | |
| 117 | |
| 118 /* Have the menu object created */ | |
| 119 SFG_Menu* menu = (SFG_Menu *)calloc( sizeof(SFG_Menu), 1 ); | |
| 120 | |
| 121 menu->ParentWindow = NULL; | |
| 122 | |
| 123 /* Create a window for the menu to reside in. */ | |
| 124 fgCreateWindow( NULL, "freeglut menu", GL_FALSE, 0, 0, GL_FALSE, 0, 0, | |
| 125 GL_FALSE, GL_TRUE ); | |
| 126 menu->Window = fgStructure.CurrentWindow; | |
| 127 glutDisplayFunc( fgDisplayMenu ); | |
| 128 | |
| 129 fgSetWindow( current_window ); | |
| 130 | |
| 131 /* Initialize the object properties: */ | |
| 132 menu->ID = ++fgStructure.MenuID; | |
| 133 menu->Callback = menuCallback; | |
| 134 menu->ActiveEntry = NULL; | |
| 135 menu->Font = fgState.MenuFont; | |
| 136 | |
| 137 fgListInit( &menu->Entries ); | |
| 138 fgListAppend( &fgStructure.Menus, &menu->Node ); | |
| 139 | |
| 140 /* Newly created menus implicitly become current ones */ | |
| 141 fgStructure.CurrentMenu = menu; | |
| 142 | |
| 143 return menu; | |
| 144 } | |
| 145 | |
| 146 /* | |
| 147 * Function to add a window to the linked list of windows to destroy. | |
| 148 * Subwindows are automatically added because they hang from the window | |
| 149 * structure. | |
| 150 */ | |
| 151 void fgAddToWindowDestroyList( SFG_Window* window ) | |
| 152 { | |
| 153 SFG_WindowList *new_list_entry = | |
| 154 ( SFG_WindowList* )malloc( sizeof(SFG_WindowList ) ); | |
| 155 new_list_entry->window = window; | |
| 156 fgListAppend( &fgStructure.WindowsToDestroy, &new_list_entry->node ); | |
| 157 | |
| 158 /* Check if the window is the current one... */ | |
| 159 if( fgStructure.CurrentWindow == window ) | |
| 160 fgStructure.CurrentWindow = NULL; | |
| 161 | |
| 162 /* | |
| 163 * Clear all window callbacks except Destroy, which will | |
| 164 * be invoked later. Right now, we are potentially carrying | |
| 165 * out a freeglut operation at the behest of a client callback, | |
| 166 * so we are reluctant to re-enter the client with the Destroy | |
| 167 * callback, right now. The others are all wiped out, however, | |
| 168 * to ensure that they are no longer called after this point. | |
| 169 */ | |
| 170 { | |
| 171 FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy ); | |
| 172 fghClearCallBacks( window ); | |
| 173 SET_WCB( *window, Destroy, destroy ); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 /* | |
| 178 * Function to close down all the windows in the "WindowsToDestroy" list | |
| 179 */ | |
| 180 void fgCloseWindows( ) | |
| 181 { | |
| 182 while( fgStructure.WindowsToDestroy.First ) | |
| 183 { | |
| 184 SFG_WindowList *window_ptr = fgStructure.WindowsToDestroy.First; | |
| 185 fgDestroyWindow( window_ptr->window ); | |
| 186 fgListRemove( &fgStructure.WindowsToDestroy, &window_ptr->node ); | |
| 187 free( window_ptr ); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 /* | |
| 192 * This function destroys a window and all of its subwindows. Actually, | |
| 193 * another function, defined in fg_window.c is called, but this is | |
| 194 * a whole different story... | |
| 195 */ | |
| 196 void fgDestroyWindow( SFG_Window* window ) | |
| 197 { | |
| 198 FREEGLUT_INTERNAL_ERROR_EXIT ( window, "Window destroy function called with null window", | |
| 199 "fgDestroyWindow" ); | |
| 200 | |
| 201 while( window->Children.First ) | |
| 202 fgDestroyWindow( ( SFG_Window * )window->Children.First ); | |
| 203 | |
| 204 { | |
| 205 SFG_Window *activeWindow = fgStructure.CurrentWindow; | |
| 206 INVOKE_WCB( *window, Destroy, ( ) ); | |
| 207 fgSetWindow( activeWindow ); | |
| 208 } | |
| 209 | |
| 210 if( window->Parent ) | |
| 211 fgListRemove( &window->Parent->Children, &window->Node ); | |
| 212 else | |
| 213 fgListRemove( &fgStructure.Windows, &window->Node ); | |
| 214 | |
| 215 if( window->ActiveMenu ) | |
| 216 fgDeactivateMenu( window ); | |
| 217 | |
| 218 fghClearCallBacks( window ); | |
| 219 fgCloseWindow( window ); | |
| 220 free( window ); | |
| 221 if( fgStructure.CurrentWindow == window ) | |
| 222 fgStructure.CurrentWindow = NULL; | |
| 223 } | |
| 224 | |
| 225 /* | |
| 226 * This is a helper static function that removes a menu (given its pointer) | |
| 227 * from any windows that can be accessed from a given parent... | |
| 228 */ | |
| 229 static void fghRemoveMenuFromWindow( SFG_Window* window, SFG_Menu* menu ) | |
| 230 { | |
| 231 SFG_Window *subWindow; | |
| 232 int i; | |
| 233 | |
| 234 /* Check whether this is the active menu in the window */ | |
| 235 if ( menu == window->ActiveMenu ) | |
| 236 window->ActiveMenu = NULL ; | |
| 237 | |
| 238 /* | |
| 239 * Check if the menu is attached to the current window, | |
| 240 * if so, have it detached (by overwriting with a NULL): | |
| 241 */ | |
| 242 for( i = 0; i < FREEGLUT_MAX_MENUS; i++ ) | |
| 243 if( window->Menu[ i ] == menu ) | |
| 244 window->Menu[ i ] = NULL; | |
| 245 | |
| 246 /* Call this function for all of the window's children recursively: */ | |
| 247 for( subWindow = (SFG_Window *)window->Children.First; | |
| 248 subWindow; | |
| 249 subWindow = (SFG_Window *)subWindow->Node.Next) | |
| 250 fghRemoveMenuFromWindow( subWindow, menu ); | |
| 251 } | |
| 252 | |
| 253 /* | |
| 254 * This is a static helper function that removes menu references | |
| 255 * from another menu, given two pointers to them... | |
| 256 */ | |
| 257 static void fghRemoveMenuFromMenu( SFG_Menu* from, SFG_Menu* menu ) | |
| 258 { | |
| 259 SFG_MenuEntry *entry; | |
| 260 | |
| 261 for( entry = (SFG_MenuEntry *)from->Entries.First; | |
| 262 entry; | |
| 263 entry = ( SFG_MenuEntry * )entry->Node.Next ) | |
| 264 if( entry->SubMenu == menu ) | |
| 265 entry->SubMenu = NULL; | |
| 266 } | |
| 267 | |
| 268 /* | |
| 269 * This function destroys a menu specified by the parameter. All menus | |
| 270 * and windows are updated to make sure no ill pointers hang around. | |
| 271 */ | |
| 272 void fgDestroyMenu( SFG_Menu* menu ) | |
| 273 { | |
| 274 SFG_Window *window; | |
| 275 SFG_Menu *from; | |
| 276 | |
| 277 FREEGLUT_INTERNAL_ERROR_EXIT ( menu, "Menu destroy function called with null menu", | |
| 278 "fgDestroyMenu" ); | |
| 279 | |
| 280 /* First of all, have all references to this menu removed from all windows: */ | |
| 281 for( window = (SFG_Window *)fgStructure.Windows.First; | |
| 282 window; | |
| 283 window = (SFG_Window *)window->Node.Next ) | |
| 284 fghRemoveMenuFromWindow( window, menu ); | |
| 285 | |
| 286 /* Now proceed with removing menu entries that lead to this menu */ | |
| 287 for( from = ( SFG_Menu * )fgStructure.Menus.First; | |
| 288 from; | |
| 289 from = ( SFG_Menu * )from->Node.Next ) | |
| 290 fghRemoveMenuFromMenu( from, menu ); | |
| 291 | |
| 292 /* | |
| 293 * If the programmer defined a destroy callback, call it | |
| 294 * A. Donev: But first make this the active menu | |
| 295 */ | |
| 296 if( menu->Destroy ) | |
| 297 { | |
| 298 SFG_Menu *activeMenu=fgStructure.CurrentMenu; | |
| 299 fgStructure.CurrentMenu = menu; | |
| 300 menu->Destroy( ); | |
| 301 fgStructure.CurrentMenu = activeMenu; | |
| 302 } | |
| 303 | |
| 304 /* | |
| 305 * Now we are pretty sure the menu is not used anywhere | |
| 306 * and that we can remove all of its entries | |
| 307 */ | |
| 308 while( menu->Entries.First ) | |
| 309 { | |
| 310 SFG_MenuEntry *entry = ( SFG_MenuEntry * ) menu->Entries.First; | |
| 311 | |
| 312 fgListRemove( &menu->Entries, &entry->Node ); | |
| 313 | |
| 314 if( entry->Text ) | |
| 315 free( entry->Text ); | |
| 316 entry->Text = NULL; | |
| 317 | |
| 318 free( entry ); | |
| 319 } | |
| 320 | |
| 321 if( fgStructure.CurrentWindow == menu->Window ) | |
| 322 fgSetWindow( NULL ); | |
| 323 fgDestroyWindow( menu->Window ); | |
| 324 fgListRemove( &fgStructure.Menus, &menu->Node ); | |
| 325 if( fgStructure.CurrentMenu == menu ) | |
| 326 fgStructure.CurrentMenu = NULL; | |
| 327 | |
| 328 free( menu ); | |
| 329 } | |
| 330 | |
| 331 /* | |
| 332 * This function should be called on glutInit(). It will prepare the internal | |
| 333 * structure of freeglut to be used in the application. The structure will be | |
| 334 * destroyed using fgDestroyStructure() on glutMainLoop() return. In that | |
| 335 * case further use of freeglut should be preceded with a glutInit() call. | |
| 336 */ | |
| 337 void fgCreateStructure( void ) | |
| 338 { | |
| 339 /* | |
| 340 * We will be needing two lists: the first containing windows, | |
| 341 * and the second containing the user-defined menus. | |
| 342 * Also, no current window/menu is set, as none has been created yet. | |
| 343 */ | |
| 344 | |
| 345 fgListInit(&fgStructure.Windows); | |
| 346 fgListInit(&fgStructure.Menus); | |
| 347 fgListInit(&fgStructure.WindowsToDestroy); | |
| 348 | |
| 349 fgStructure.CurrentWindow = NULL; | |
| 350 fgStructure.CurrentMenu = NULL; | |
| 351 fgStructure.MenuContext = NULL; | |
| 352 fgStructure.GameModeWindow = NULL; | |
| 353 fgStructure.WindowID = 0; | |
| 354 fgStructure.MenuID = 0; | |
| 355 } | |
| 356 | |
| 357 /* | |
| 358 * This function is automatically called on glutMainLoop() return. | |
| 359 * It should deallocate and destroy all remnants of previous | |
| 360 * glutInit()-enforced structure initialization... | |
| 361 */ | |
| 362 void fgDestroyStructure( void ) | |
| 363 { | |
| 364 /* Clean up the WindowsToDestroy list. */ | |
| 365 fgCloseWindows( ); | |
| 366 | |
| 367 /* Make sure all windows and menus have been deallocated */ | |
| 368 while( fgStructure.Menus.First ) | |
| 369 fgDestroyMenu( ( SFG_Menu * )fgStructure.Menus.First ); | |
| 370 | |
| 371 while( fgStructure.Windows.First ) | |
| 372 fgDestroyWindow( ( SFG_Window * )fgStructure.Windows.First ); | |
| 373 } | |
| 374 | |
| 375 /* | |
| 376 * Helper function to enumerate through all registered top-level windows | |
| 377 */ | |
| 378 void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator ) | |
| 379 { | |
| 380 SFG_Window *window; | |
| 381 | |
| 382 FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, | |
| 383 "Enumerator or callback missing from window enumerator call", | |
| 384 "fgEnumWindows" ); | |
| 385 | |
| 386 /* Check every of the top-level windows */ | |
| 387 for( window = ( SFG_Window * )fgStructure.Windows.First; | |
| 388 window; | |
| 389 window = ( SFG_Window * )window->Node.Next ) | |
| 390 { | |
| 391 enumCallback( window, enumerator ); | |
| 392 if( enumerator->found ) | |
| 393 return; | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 /* | |
| 398 * Helper function to enumerate through all registered top-level windows | |
| 399 */ | |
| 400 void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator ) | |
| 401 { | |
| 402 SFG_Menu *menu; | |
| 403 | |
| 404 FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, | |
| 405 "Enumerator or callback missing from window enumerator call", | |
| 406 "fgEnumWindows" ); | |
| 407 | |
| 408 /* It's enough to check all entries in fgStructure.Menus... */ | |
| 409 for( menu = (SFG_Menu *)fgStructure.Menus.First; | |
| 410 menu; | |
| 411 menu = (SFG_Menu *)menu->Node.Next ) | |
| 412 { | |
| 413 enumCallback( menu, enumerator ); | |
| 414 if( enumerator->found ) | |
| 415 return; | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 /* | |
| 420 * Helper function to enumerate through all a window's subwindows | |
| 421 * (single level descent) | |
| 422 */ | |
| 423 void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback, | |
| 424 SFG_Enumerator* enumerator ) | |
| 425 { | |
| 426 SFG_Window *child; | |
| 427 | |
| 428 FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, | |
| 429 "Enumerator or callback missing from subwindow enumerator call", | |
| 430 "fgEnumSubWindows" ); | |
| 431 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Window Enumeration" ); | |
| 432 | |
| 433 for( child = ( SFG_Window * )window->Children.First; | |
| 434 child; | |
| 435 child = ( SFG_Window * )child->Node.Next ) | |
| 436 { | |
| 437 enumCallback( child, enumerator ); | |
| 438 if( enumerator->found ) | |
| 439 return; | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 /* | |
| 444 * A static helper function to look for a window given its handle | |
| 445 */ | |
| 446 static void fghcbWindowByHandle( SFG_Window *window, | |
| 447 SFG_Enumerator *enumerator ) | |
| 448 { | |
| 449 if ( enumerator->found ) | |
| 450 return; | |
| 451 | |
| 452 /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ | |
| 453 if( window->Window.Handle == (SFG_WindowHandleType) (enumerator->data) ) | |
| 454 { | |
| 455 enumerator->found = GL_TRUE; | |
| 456 enumerator->data = window; | |
| 457 | |
| 458 return; | |
| 459 } | |
| 460 | |
| 461 /* Otherwise, check this window's children */ | |
| 462 fgEnumSubWindows( window, fghcbWindowByHandle, enumerator ); | |
| 463 } | |
| 464 | |
| 465 /* | |
| 466 * fgWindowByHandle returns a (SFG_Window *) value pointing to the | |
| 467 * first window in the queue matching the specified window handle. | |
| 468 * The function is defined in fg_structure.c file. | |
| 469 */ | |
| 470 SFG_Window* fgWindowByHandle ( SFG_WindowHandleType hWindow ) | |
| 471 { | |
| 472 SFG_Enumerator enumerator; | |
| 473 | |
| 474 /* This is easy and makes use of the windows enumeration defined above */ | |
| 475 enumerator.found = GL_FALSE; | |
| 476 enumerator.data = (void *)hWindow; | |
| 477 fgEnumWindows( fghcbWindowByHandle, &enumerator ); | |
| 478 | |
| 479 if( enumerator.found ) | |
| 480 return( SFG_Window *) enumerator.data; | |
| 481 return NULL; | |
| 482 } | |
| 483 | |
| 484 /* | |
| 485 * A static helper function to look for a window given its ID | |
| 486 */ | |
| 487 static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator ) | |
| 488 { | |
| 489 /* Make sure we do not overwrite our precious results... */ | |
| 490 if( enumerator->found ) | |
| 491 return; | |
| 492 | |
| 493 /* Check the window's handle. Hope this works. Looks ugly. That's for sure. */ | |
| 494 if( window->ID == *( int *)(enumerator->data) ) | |
| 495 { | |
| 496 enumerator->found = GL_TRUE; | |
| 497 enumerator->data = window; | |
| 498 | |
| 499 return; | |
| 500 } | |
| 501 | |
| 502 /* Otherwise, check this window's children */ | |
| 503 fgEnumSubWindows( window, fghcbWindowByID, enumerator ); | |
| 504 } | |
| 505 | |
| 506 /* | |
| 507 * This function is similar to the previous one, except it is | |
| 508 * looking for a specified (sub)window identifier. The function | |
| 509 * is defined in fg_structure.c file. | |
| 510 */ | |
| 511 SFG_Window* fgWindowByID( int windowID ) | |
| 512 { | |
| 513 SFG_Enumerator enumerator; | |
| 514 | |
| 515 /* Uses a method very similar for fgWindowByHandle... */ | |
| 516 enumerator.found = GL_FALSE; | |
| 517 enumerator.data = ( void * )&windowID; | |
| 518 fgEnumWindows( fghcbWindowByID, &enumerator ); | |
| 519 if( enumerator.found ) | |
| 520 return ( SFG_Window * )enumerator.data; | |
| 521 return NULL; | |
| 522 } | |
| 523 | |
| 524 /* | |
| 525 * A static helper function to look for a menu given its ID | |
| 526 */ | |
| 527 static void fghcbMenuByID( SFG_Menu *menu, | |
| 528 SFG_Enumerator *enumerator ) | |
| 529 { | |
| 530 if ( enumerator->found ) | |
| 531 return; | |
| 532 | |
| 533 /* Check the menu's ID. */ | |
| 534 if( menu->ID == *( int *)(enumerator->data) ) | |
| 535 { | |
| 536 enumerator->found = GL_TRUE; | |
| 537 enumerator->data = menu; | |
| 538 | |
| 539 return; | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 /* | |
| 544 * Looks up a menu given its ID. This is easier than fgWindowByXXX | |
| 545 * as all menus are placed in one doubly linked list... | |
| 546 */ | |
| 547 SFG_Menu* fgMenuByID( int menuID ) | |
| 548 { | |
| 549 SFG_Enumerator enumerator; | |
| 550 | |
| 551 /* This is easy and makes use of the menus enumeration defined above */ | |
| 552 enumerator.found = GL_FALSE; | |
| 553 enumerator.data = (void *)&menuID; | |
| 554 fgEnumMenus( fghcbMenuByID, &enumerator ); | |
| 555 | |
| 556 if( enumerator.found ) | |
| 557 return( SFG_Menu *) enumerator.data; | |
| 558 | |
| 559 return NULL; | |
| 560 } | |
| 561 | |
| 562 /* | |
| 563 * A static helper function to look for an active menu | |
| 564 */ | |
| 565 static void fghcbGetActiveMenu( SFG_Menu *menu, | |
| 566 SFG_Enumerator *enumerator ) | |
| 567 { | |
| 568 if ( enumerator->found ) | |
| 569 return; | |
| 570 | |
| 571 /* Check the menu's is active */ | |
| 572 if( menu->IsActive ) | |
| 573 { | |
| 574 enumerator->found = GL_TRUE; | |
| 575 enumerator->data = menu; | |
| 576 | |
| 577 return; | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 /* | |
| 582 * Returns active menu, if any. Assumption: only one menu active throughout application at any one time. | |
| 583 * This is false when a submenu is also open. | |
| 584 * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list... | |
| 585 */ | |
| 586 SFG_Menu* fgGetActiveMenu( ) | |
| 587 { | |
| 588 SFG_Enumerator enumerator; | |
| 589 | |
| 590 /* This is easy and makes use of the menus enumeration defined above */ | |
| 591 enumerator.found = GL_FALSE; | |
| 592 fgEnumMenus( fghcbGetActiveMenu, &enumerator ); | |
| 593 | |
| 594 if( enumerator.found ) | |
| 595 return( SFG_Menu *) enumerator.data; | |
| 596 | |
| 597 return NULL; | |
| 598 } | |
| 599 | |
| 600 /* | |
| 601 * List functions... | |
| 602 */ | |
| 603 void fgListInit(SFG_List *list) | |
| 604 { | |
| 605 list->First = NULL; | |
| 606 list->Last = NULL; | |
| 607 } | |
| 608 | |
| 609 void fgListAppend(SFG_List *list, SFG_Node *node) | |
| 610 { | |
| 611 if ( list->Last ) | |
| 612 { | |
| 613 SFG_Node *ln = (SFG_Node *) list->Last; | |
| 614 ln->Next = node; | |
| 615 node->Prev = ln; | |
| 616 } | |
| 617 else | |
| 618 { | |
| 619 node->Prev = NULL; | |
| 620 list->First = node; | |
| 621 } | |
| 622 | |
| 623 node->Next = NULL; | |
| 624 list->Last = node; | |
| 625 } | |
| 626 | |
| 627 void fgListRemove(SFG_List *list, SFG_Node *node) | |
| 628 { | |
| 629 if( node->Next ) | |
| 630 ( ( SFG_Node * )node->Next )->Prev = node->Prev; | |
| 631 if( node->Prev ) | |
| 632 ( ( SFG_Node * )node->Prev )->Next = node->Next; | |
| 633 if( ( ( SFG_Node * )list->First ) == node ) | |
| 634 list->First = node->Next; | |
| 635 if( ( ( SFG_Node * )list->Last ) == node ) | |
| 636 list->Last = node->Prev; | |
| 637 } | |
| 638 | |
| 639 int fgListLength(SFG_List *list) | |
| 640 { | |
| 641 SFG_Node *node; | |
| 642 int length = 0; | |
| 643 | |
| 644 for( node =( SFG_Node * )list->First; | |
| 645 node; | |
| 646 node = ( SFG_Node * )node->Next ) | |
| 647 ++length; | |
| 648 | |
| 649 return length; | |
| 650 } | |
| 651 | |
| 652 | |
| 653 void fgListInsert(SFG_List *list, SFG_Node *next, SFG_Node *node) | |
| 654 { | |
| 655 SFG_Node *prev; | |
| 656 | |
| 657 if( (node->Next = next) ) | |
| 658 { | |
| 659 prev = next->Prev; | |
| 660 next->Prev = node; | |
| 661 } | |
| 662 else | |
| 663 { | |
| 664 prev = list->Last; | |
| 665 list->Last = node; | |
| 666 } | |
| 667 | |
| 668 if( (node->Prev = prev) ) | |
| 669 prev->Next = node; | |
| 670 else | |
| 671 list->First = node; | |
| 672 } | |
| 673 | |
| 674 /*** END OF FILE ***/ |
