X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=freeglut-1.3%2Ffreeglut_menu.c;fp=freeglut-1.3%2Ffreeglut_menu.c;h=c50cea5e14c05d1ab3312ab73237b43bda7e31ab;hb=a82e219413778d1fd55d270af98e9ad6a97e25a0;hp=e90b0acaa8c80fac0956dbfd428d81d1cdaee8f8;hpb=c41ee8f7e365eabcc5391cb953c9c81af34c6bb6;p=freeglut diff --git a/freeglut-1.3/freeglut_menu.c b/freeglut-1.3/freeglut_menu.c index e90b0ac..c50cea5 100644 --- a/freeglut-1.3/freeglut_menu.c +++ b/freeglut-1.3/freeglut_menu.c @@ -49,6 +49,7 @@ */ #define FREEGLUT_MENU_FONT GLUT_BITMAP_8_BY_13 #define FREEGLUT_MENU_HEIGHT 15 +#define FREEGLUT_MENU_BORDER 8 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ @@ -74,215 +75,247 @@ static SFG_MenuEntry *fghFindMenuEntry( SFG_Menu* menu, int index ) /* * Private static function to check for the current menu/sub menu activity state */ -static GLboolean fghCheckMenuStatus( SFG_Menu* menu ) +static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) { - SFG_Window* window = fgStructure.Window; - SFG_MenuEntry* menuEntry; - int x, y; + SFG_MenuEntry* menuEntry; + int x, y; + /* + * First of all check any of the active sub menus... + */ + for( menuEntry = menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next ) + { /* - * First of all check any of the active sub menus... + * Is that an active sub menu by any case? */ - for( menuEntry = menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next ) + if( menuEntry->SubMenu != NULL && menuEntry->IsActive == TRUE ) { - /* - * Is that an active sub menu by any case? - */ - if( menuEntry->SubMenu != NULL && menuEntry->IsActive == TRUE ) - { - /* - * OKi, have the sub-menu checked, too. If it returns TRUE, it will mean - * that it caught the mouse cursor and we do not need to regenerate - * the activity list, and so our parents do... - */ - if( fghCheckMenuStatus( menuEntry->SubMenu ) == TRUE ) - return( TRUE ); - } + /* + * OK, have the sub-menu checked, too. If it returns TRUE, it will mean + * that it caught the mouse cursor and we do not need to regenerate + * the activity list, and so our parents do... + */ + if( fghCheckMenuStatus( window, menuEntry->SubMenu ) == TRUE ) + return( TRUE ); } + } + /* + * That much about our sub menus, let's get to checking the current menu: + */ + x = window->State.MouseX - menu->X; + y = window->State.MouseY - menu->Y; + + /* + * Mark all menu entries inactive... + */ + for( menuEntry = menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next ) + { + menuEntry->IsActive = FALSE; + } + + menu->IsActive = FALSE; + + /* + * Check if the mouse cursor is contained within the current menu box + */ + if( x >= 0 && x < menu->Width && y >= 0 && y < menu->Height ) + { /* - * That much about our sub menus, let's get to checking the current menu: + * Calculation of the highlighted menu item is easy enough now: */ - x = window->State.MouseX - menu->X; - y = window->State.MouseY - menu->Y; + int menuID = y / FREEGLUT_MENU_HEIGHT; /* - * Mark all menu entries inactive... + * The mouse cursor is somewhere over our box, check it out. */ - for( menuEntry = menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next ) - { - menuEntry->IsActive = FALSE; - } - - menu->IsActive = FALSE; + menuEntry = fghFindMenuEntry( menu, menuID + 1 ); + assert( menuEntry != NULL ); /* - * Check if the mouse cursor is contained within the current menu box + * Mark the menu as active... */ - if( x >= 0 && x < menu->Width && y >= 0 && y < menu->Height ) - { - /* - * Calculation of the highlighted menu item is easy enough now: - */ - int menuID = y / FREEGLUT_MENU_HEIGHT; - - /* - * The mouse cursor is somewhere over our box, check it out. - */ - menuEntry = fghFindMenuEntry( menu, menuID + 1 ); - assert( menuEntry != NULL ); + menuEntry->IsActive = TRUE; + menuEntry->Ordinal = menuID; - /* - * Mark the menu as active... - */ - menuEntry->IsActive = TRUE; - menuEntry->Ordinal = menuID; - - /* - * Don't forget about marking the current menu as active, too: - */ - menu->IsActive = TRUE; - - /* - * OKi, we have marked that entry as active, but it would be also - * nice to have it's contents updated, in case it's a sub menu. - * Also, ignore the return value of the check function: - */ - if( menuEntry->SubMenu != NULL ) - { - int x = window->State.MouseX; - int y = window->State.MouseY; - - /* - * Set up the initial menu position now... - */ - - if( x > 15 ) menuEntry->SubMenu->X = x - 15; else menuEntry->SubMenu->X = 15; - if( y > 15 ) menuEntry->SubMenu->Y = y - 15; else menuEntry->SubMenu->Y = 15; - - if( x > (glutGet( GLUT_WINDOW_WIDTH ) - menuEntry->SubMenu->Width - 15) ) - menuEntry->SubMenu->X = glutGet( GLUT_WINDOW_WIDTH ) - menuEntry->SubMenu->Width - 15; - if( y > (glutGet( GLUT_WINDOW_HEIGHT ) - menuEntry->SubMenu->Height - 15) ) - menuEntry->SubMenu->Y = glutGet( GLUT_WINDOW_HEIGHT ) - menuEntry->SubMenu->Height - 15; - - /* - * ...then check the submenu's state: - */ - fghCheckMenuStatus( menuEntry->SubMenu ); - } + /* + * Don't forget about marking the current menu as active, too: + */ + menu->IsActive = TRUE; - /* - * Report back that we have caught the menu cursor - */ - return( TRUE ); + /* + * OKi, we have marked that entry as active, but it would be also + * nice to have its contents updated, in case it's a sub menu. + * Also, ignore the return value of the check function: + */ + if( menuEntry->SubMenu != NULL ) + { + /* + * Set up the initial menu position now... + */ + + menuEntry->SubMenu->X = menu->X + menu->Width ; + menuEntry->SubMenu->Y = menu->Y + menuEntry->Ordinal * FREEGLUT_MENU_HEIGHT ; + + /* + * Make sure the submenu stays within the window + */ + if ( menuEntry->SubMenu->X + menuEntry->SubMenu->Width > glutGet ( GLUT_WINDOW_WIDTH ) ) + { + menuEntry->SubMenu->X = menu->X - menuEntry->SubMenu->Width ; + if ( menuEntry->SubMenu->X < 0 ) + menuEntry->SubMenu->X = glutGet ( GLUT_WINDOW_WIDTH ) - menuEntry->SubMenu->Width ; + } + + /* + * ...then check the submenu's state: + */ + fghCheckMenuStatus( window, menuEntry->SubMenu ); + + /* + * Even if the submenu turned up inactive, activate it because its parent entry is active + */ + menuEntry->SubMenu->IsActive = TRUE ; } /* - * Looks like the menu cursor is somewhere else... + * Report back that we have caught the menu cursor */ - return( FALSE ); + return( TRUE ); + } + + /* + * Looks like the menu cursor is somewhere else... + */ + return( FALSE ); } /* - * Displays a menu box and all of it's submenus (if they are active) + * Displays a menu box and all of its submenus (if they are active) */ static void fghDisplayMenuBox( SFG_Menu* menu ) { - SFG_MenuEntry *menuEntry; - int i; + SFG_MenuEntry *menuEntry; + int i; + + /* + * Have the menu box drawn first. The +- values are + * here just to make it more nice-looking... + */ + glColor4f( 0.0, 0.0, 0.0, 1.0 ); + glBegin( GL_QUADS ); + glVertex2f( menu->X , menu->Y - 1 ); + glVertex2f( menu->X + menu->Width, menu->Y - 1 ); + glVertex2f( menu->X + menu->Width, menu->Y + 4 + menu->Height ); + glVertex2f( menu->X , menu->Y + 4 + menu->Height ); + glEnd(); + + glColor4f( 0.3, 0.4, 0.5, 1.0 ); + glBegin( GL_QUADS ); + glVertex2f( menu->X - 2 , menu->Y + 1 ); + glVertex2f( menu->X - 2 + menu->Width, menu->Y + 1 ); + glVertex2f( menu->X - 2 + menu->Width, menu->Y + 2 + menu->Height ); + glVertex2f( menu->X - 2 , menu->Y + 2 + menu->Height ); + glEnd(); + + /* + * Check if any of the submenus is currently active... + */ + for( menuEntry = menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next ) + { + /* + * Has the menu been marked as active, maybe? + */ + if( menuEntry->IsActive == TRUE ) + { + /* + * That's truly right, and we need to have it highlighted. + * There is an assumption that mouse cursor didn't move + * since the last check of menu activity state: + */ + int menuID = menuEntry->Ordinal; + + /* + * So have the highlight drawn... + */ + glColor4f( 0.2, 0.3, 0.4, 1.0 ); + glBegin( GL_QUADS ); + glVertex2f( menu->X - 2 , menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); + glVertex2f( menu->X - 2 + menu->Width, menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); + glVertex2f( menu->X - 2 + menu->Width, menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); + glVertex2f( menu->X - 2 , menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); + glEnd(); + } + } + /* + * Print the menu entries now... + */ + glColor4f( 1, 1, 1, 1 ); + + for( menuEntry = menu->Entries.First, i=0; menuEntry; + menuEntry = menuEntry->Node.Next, ++i ) + { /* - * Have the menu box drawn first. The +- values are - * here just to make it more nice-looking... + * Move the raster into position... */ - glColor4f( 0.0, 0.0, 0.0, 1.0 ); - glBegin( GL_QUADS ); - glVertex2f( menu->X - 8 , menu->Y - 1 ); - glVertex2f( menu->X + 8 + menu->Width, menu->Y - 1 ); - glVertex2f( menu->X + 8 + menu->Width, menu->Y + 4 + menu->Height ); - glVertex2f( menu->X - 8 , menu->Y + 4 + menu->Height ); - glEnd(); - - glColor4f( 0.3, 0.4, 0.5, 1.0 ); - glBegin( GL_QUADS ); - glVertex2f( menu->X - 6 , menu->Y + 1 ); - glVertex2f( menu->X + 6 + menu->Width, menu->Y + 1 ); - glVertex2f( menu->X + 6 + menu->Width, menu->Y + 2 + menu->Height ); - glVertex2f( menu->X - 6 , menu->Y + 2 + menu->Height ); - glEnd(); + glRasterPos2i( + menu->X + FREEGLUT_MENU_BORDER, + menu->Y + (i + 1)*FREEGLUT_MENU_HEIGHT + ); /* - * Check if any of the submenus is currently active... + * Have the label drawn, character after character: */ - for( menuEntry = menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next ) - { - /* - * Has the menu been marked as active, maybe? - */ - if( menuEntry->IsActive == TRUE ) - { - /* - * That's truly right, and we need to have it highlighted. - * There is an assumption that mouse cursor didn't move - * since the last check of menu activity state: - */ - int menuID = menuEntry->Ordinal; - - /* - * So have the highlight drawn... - */ - glColor4f( 0.2, 0.3, 0.4, 1.0 ); - glBegin( GL_QUADS ); - glVertex2f( menu->X - 6 , menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); - glVertex2f( menu->X + 6 + menu->Width, menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); - glVertex2f( menu->X + 6 + menu->Width, menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); - glVertex2f( menu->X - 6 , menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); - glEnd(); - } - } + glutBitmapString( FREEGLUT_MENU_FONT, menuEntry->Text); /* - * Print the menu entries now... + * If it's a submenu, draw a right arrow */ - glColor4f( 1, 1, 1, 1 ); - - for( menuEntry = menu->Entries.First, i=0; menuEntry; - menuEntry = menuEntry->Node.Next, ++i ) + if ( menuEntry->SubMenu != NULL ) { - /* - * Move the raster into position... - */ - glRasterPos2i( - menu->X, - menu->Y + (i + 1)*FREEGLUT_MENU_HEIGHT - ); - - /* - * Have the label drawn, character after character: - */ - glutBitmapString( FREEGLUT_MENU_FONT, menuEntry->Text); + GLubyte arrow_char [] = { 0, 0, 32, 48, 56, 60, 62, 63, 62, 60, 56, 48, 32, 0, 0 } ; + int width = glutBitmapWidth ( FREEGLUT_MENU_FONT, ' ' ) ; + + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); + + /* + * Set up the pixel unpacking ways + */ + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glRasterPos2i ( menu->X + menu->Width - 2 - width, + menu->Y + (i + 1)*FREEGLUT_MENU_HEIGHT ) ; + glBitmap ( width, FREEGLUT_MENU_HEIGHT, 0, 0, 0.0, 0.0, arrow_char ) ; + glPopClientAttrib(); } + } + /* + * Now we are ready to check if any of our children needs to be redrawn: + */ + for( menuEntry = menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next ) + { /* - * Now we are ready to check if any of our children needs to be redrawn: + * Is that an active sub menu by any case? */ - for( menuEntry = menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next ) + if( menuEntry->SubMenu != NULL && menuEntry->IsActive == TRUE ) { - /* - * Is that an active sub menu by any case? - */ - if( menuEntry->SubMenu != NULL && menuEntry->IsActive == TRUE ) - { - /* - * Yeah, indeed. Have it redrawn now: - */ - fghDisplayMenuBox( menuEntry->SubMenu ); - } + /* + * Yeah, indeed. Have it redrawn now: + */ + fghDisplayMenuBox( menuEntry->SubMenu ); } + } } /* @@ -292,7 +325,6 @@ void fgDisplayMenu( void ) { SFG_Window* window = fgStructure.Window; SFG_Menu* menu = NULL; - int i; /* * Make sure there is a current window available @@ -302,17 +334,12 @@ void fgDisplayMenu( void ) /* * Check if there is an active menu attached to this window... */ - for( i=0; iMenu[ i ] != NULL && window->MenuActive[ i ] == TRUE ) - menu = window->Menu[ i ]; - }; + menu = window->ActiveMenu; /* * Did we find an active window? */ freeglut_return_if_fail( menu != NULL ); - /* * Prepare the OpenGL state to do the rendering first: */ @@ -345,7 +372,7 @@ void fgDisplayMenu( void ) /* * First of all, have the exact menu status check: */ - fghCheckMenuStatus( menu ); + fghCheckMenuStatus( window, menu ); /* * The status has been updated and we're ready to have the menu drawn now: @@ -357,118 +384,119 @@ void fgDisplayMenu( void ) */ glPopAttrib(); - glMatrixMode( GL_MODELVIEW ); - glPopMatrix(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); } /* * Activates a menu pointed by the function argument */ -void fgActivateMenu( int button ) +void fgActivateMenu( SFG_Window* window, int button ) { - SFG_Window* window = fgStructure.Window; - SFG_Menu* menu = NULL; - int x, y; - - freeglut_assert_window; - - /* - * Mark the menu as active, so that it gets displayed: - */ - window->MenuActive[ button ] = TRUE; - - /* - * We'll be referencing this menu a lot, so remember it's address: - */ - menu = window->Menu[ button ]; - - /* - * Grab the mouse cursor position respective to the current window - */ - x = window->State.MouseX; - y = window->State.MouseY; - - /* - * Set up the initial menu position now: - */ - if( x > 10 ) menu->X = x - 10; else menu->X = 5; - if( y > 10 ) menu->Y = y - 10; else menu->Y = 5; + int x, y; + + /* + * We'll be referencing this menu a lot, so remember its address: + */ + SFG_Menu* menu = window->Menu[ button ]; + + /* + * Mark the menu as active, so that it gets displayed: + */ + window->ActiveMenu = menu; + menu->IsActive = TRUE ; + + /* + * Grab the mouse cursor position respective to the current window + */ + x = window->State.MouseX; + y = window->State.MouseY; + + /* + * Set up the initial menu position now: + */ + menu->X = x ; + menu->Y = y ; + + glutSetWindow ( window->ID ) ; + + if( x > ( glutGet( GLUT_WINDOW_WIDTH ) - menu->Width ) ) + menu->X = glutGet( GLUT_WINDOW_WIDTH ) - menu->Width; + if( y > ( glutGet( GLUT_WINDOW_HEIGHT ) - menu->Height) ) + menu->Y = glutGet( GLUT_WINDOW_HEIGHT ) - menu->Height; +} - if( x > (glutGet( GLUT_WINDOW_WIDTH ) - menu->Width ) ) - menu->X = glutGet( GLUT_WINDOW_WIDTH ) - menu->Width; - if( y > (glutGet( GLUT_WINDOW_HEIGHT ) - menu->Height) ) - menu->Y = glutGet( GLUT_WINDOW_HEIGHT ) - menu->Height; +/* + * Check whether an active menu absorbs a mouse click + */ +GLboolean fgCheckActiveMenu ( SFG_Window *window, SFG_Menu *menu ) +{ + /* + * Near as I can tell, this is the active menu behaviour: + * - Down-click any button outside the menu, menu active: deactivate the menu + * - Down-click any button inside the menu, menu active: select the menu entry and deactivate the menu + * - Up-click the menu button outside the menu, menu active: nothing happens + * - Up-click the menu button inside the menu, menu active: select the menu entry and deactivate the menu + * Since menus can have submenus, we need to check this recursively. + */ + return fghCheckMenuStatus ( window, menu ) ; } /* - * Private static function to check for menu entry selection on menu deactivation + * Function to check for menu entry selection on menu deactivation */ -static void fghCheckMenuSelect( SFG_Menu* menu ) +void fgExecuteMenuCallback( SFG_Menu* menu ) { - SFG_MenuEntry *menuEntry; + SFG_MenuEntry *menuEntry; + /* + * First of all check any of the active sub menus... + */ + for( menuEntry = menu->Entries.First; menuEntry; menuEntry = menuEntry->Node.Next) + { /* - * First of all check any of the active sub menus... + * Is this menu entry active? */ - for( menuEntry = menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next) + if( menuEntry->IsActive == TRUE ) { + /* + * If there is not a sub menu, execute the menu callback and return... + */ + if( menuEntry->SubMenu == NULL ) + { /* - * Is this menu entry active? + * ...certainly given that there is one... */ - if( menuEntry->IsActive == TRUE ) - { - /* - * If this is not a sub menu, execute the menu callback and return... - */ - if( menuEntry->SubMenu == NULL ) - { - /* - * ...certainly given that there is one... - */ - if( menu->Callback != NULL ) - menu->Callback( menuEntry->ID ); - - return; - } - - /* - * Otherwise recurse into the submenu. - */ - fghCheckMenuSelect( menuEntry->SubMenu ); - - /* - * There is little sense in dwelling the search on - */ - return; - } + if( menu->Callback != NULL ) + menu->Callback( menuEntry->ID ); + + return; + } + + /* + * Otherwise recurse into the submenu. + */ + fgExecuteMenuCallback( menuEntry->SubMenu ); + + /* + * There is little sense in dwelling the search on + */ + return; } + } } /* * Deactivates a menu pointed by the function argument. */ -void fgDeactivateMenu( int button ) +void fgDeactivateMenu( SFG_Window *window ) { - SFG_Window* window = fgStructure.Window; - SFG_Menu* menu = NULL; - int i; - - /* - * Make sure there is a current window available... - */ - freeglut_assert_window; - /* * Check if there is an active menu attached to this window... */ - for( i=0; iMenu[ i ] != NULL && window->MenuActive[ i ] == TRUE ) - menu = window->Menu[ i ]; - }; + SFG_Menu* menu = window->ActiveMenu; /* * Did we find an active window? @@ -476,15 +504,10 @@ void fgDeactivateMenu( int button ) freeglut_return_if_fail( menu != NULL ); /* - * Check if there was any menu entry active. This would - * mean the user has selected a menu entry... - */ - fghCheckMenuSelect( menu ); - - /* * Forget about having that menu active anymore, now: */ - fgStructure.Window->MenuActive[ button ] = FALSE; + window->ActiveMenu = NULL; + menu->IsActive = FALSE ; } /* @@ -492,39 +515,39 @@ void fgDeactivateMenu( int button ) */ void fghCalculateMenuBoxSize( void ) { - SFG_MenuEntry* menuEntry; - int width = 0, height = 0; + SFG_MenuEntry* menuEntry; + int width = 0, height = 0; + + /* + * Make sure there is a current menu set + */ + freeglut_assert_ready; freeglut_return_if_fail( fgStructure.Menu != NULL ); + /* + * The menu's box size depends on the menu entries: + */ + for( menuEntry = fgStructure.Menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next) + { /* - * Make sure there is a current menu set + * Update the menu entry's width value */ - freeglut_assert_ready; freeglut_return_if_fail( fgStructure.Menu != NULL ); + menuEntry->Width = glutBitmapLength( FREEGLUT_MENU_FONT, menuEntry->Text ); /* - * The menu's box size depends on the menu entries: + * Check if it's the biggest we've found */ - for( menuEntry = fgStructure.Menu->Entries.First; menuEntry; - menuEntry = menuEntry->Node.Next) - { - /* - * Update the menu entry's width value - */ - menuEntry->Width = glutBitmapLength( FREEGLUT_MENU_FONT, menuEntry->Text ); - - /* - * Check if it's the biggest we've found - */ - if( menuEntry->Width > width ) - width = menuEntry->Width; + if( menuEntry->Width > width ) + width = menuEntry->Width; - height += FREEGLUT_MENU_HEIGHT; - } + height += FREEGLUT_MENU_HEIGHT; + } - /* - * Store the menu's box size now: - */ - fgStructure.Menu->Height = height; - fgStructure.Menu->Width = width; + /* + * Store the menu's box size now: + */ + fgStructure.Menu->Height = height; + fgStructure.Menu->Width = width + 2 * FREEGLUT_MENU_BORDER ; } @@ -581,7 +604,7 @@ int FGAPIENTRY glutGetMenu( void ) } /* - * Sets the current menu given it's menu ID + * Sets the current menu given its menu ID */ void FGAPIENTRY glutSetMenu( int menuID ) { @@ -629,32 +652,32 @@ void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) */ void FGAPIENTRY glutAddSubMenu( const char* label, int subMenuID ) { - SFG_MenuEntry* menuEntry = calloc( sizeof(SFG_MenuEntry), 1 ); - SFG_Menu* subMenu = fgMenuByID( subMenuID ); - - /* - * Make sure there is a current menu and the sub menu - * we want to attach actually exists... - */ - freeglut_assert_ready; freeglut_return_if_fail( fgStructure.Menu != NULL ); - freeglut_return_if_fail( subMenu != NULL ); - - /* - * Fill in the appropriate values - */ - menuEntry->Text = strdup( label ); - menuEntry->SubMenu = subMenu; - menuEntry->ID = -1; - - /* - * Have the new menu entry attached to the current menu - */ - fgListAppend( &fgStructure.Menu->Entries, &menuEntry->Node ); - - /* - * Update the menu's dimensions now - */ - fghCalculateMenuBoxSize(); + SFG_MenuEntry* menuEntry = calloc( sizeof(SFG_MenuEntry), 1 ); + SFG_Menu* subMenu = fgMenuByID( subMenuID ); + + /* + * Make sure there is a current menu and the sub menu + * we want to attach actually exists... + */ + freeglut_assert_ready; freeglut_return_if_fail( fgStructure.Menu != NULL ); + freeglut_return_if_fail( subMenu != NULL ); + + /* + * Fill in the appropriate values + */ + menuEntry->Text = strdup( label ); + menuEntry->SubMenu = subMenu; + menuEntry->ID = -1; + + /* + * Have the new menu entry attached to the current menu + */ + fgListAppend( &fgStructure.Menu->Entries, &menuEntry->Node ); + + /* + * Update the menu's dimensions now + */ + fghCalculateMenuBoxSize(); } /*