From fc93453910bb997257758e92e18f17fe7db4d0da Mon Sep 17 00:00:00 2001 From: puggles Date: Sat, 2 Aug 2003 13:31:19 +0000 Subject: [PATCH] Major menu changes (they appear in their own window, have own rendering context) by John Fay and a little by James C. Jones. They work perfectly on Win32, and work... on Linux. git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@152 7f0cb862-5218-0410-a997-914c9d46530a --- freeglut/freeglut/src/freeglut_callbacks.c | 6 + freeglut/freeglut/src/freeglut_display.c | 3 +- .../src/freeglut_glutfont_definitions.c | 18 +- freeglut/freeglut/src/freeglut_init.c | 10 + freeglut/freeglut/src/freeglut_internal.h | 35 ++- freeglut/freeglut/src/freeglut_main.c | 115 ++++++--- freeglut/freeglut/src/freeglut_menu.c | 234 ++++++++++++++---- freeglut/freeglut/src/freeglut_state.c | 6 +- freeglut/freeglut/src/freeglut_structure.c | 46 +++- freeglut/freeglut/src/freeglut_window.c | 127 ++++++---- 10 files changed, 454 insertions(+), 146 deletions(-) diff --git a/freeglut/freeglut/src/freeglut_callbacks.c b/freeglut/freeglut/src/freeglut_callbacks.c index b741a0c..ef404f7 100644 --- a/freeglut/freeglut/src/freeglut_callbacks.c +++ b/freeglut/freeglut/src/freeglut_callbacks.c @@ -49,6 +49,12 @@ void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ) { SET_CALLBACK( Display ); + + /* + * Force a redisplay with the new callback + */ + fgStructure.Window->State.Redisplay = TRUE; + } /* diff --git a/freeglut/freeglut/src/freeglut_display.c b/freeglut/freeglut/src/freeglut_display.c index de19841..ca3b151 100644 --- a/freeglut/freeglut/src/freeglut_display.c +++ b/freeglut/freeglut/src/freeglut_display.c @@ -64,9 +64,8 @@ void FGAPIENTRY glutSwapBuffers( void ) freeglut_assert_ready; freeglut_assert_window; /* - * Have the mouse cursor and/or the menus drawn for the current window + * Have the mouse cursor drawn for the current window */ - fgDisplayMenu(); fgDisplayCursor(); /* diff --git a/freeglut/freeglut/src/freeglut_glutfont_definitions.c b/freeglut/freeglut/src/freeglut_glutfont_definitions.c index 8154774..7cb34f8 100644 --- a/freeglut/freeglut/src/freeglut_glutfont_definitions.c +++ b/freeglut/freeglut/src/freeglut_glutfont_definitions.c @@ -61,16 +61,16 @@ struct freeglutBitmapFont } ; -struct freeglutStrokeFont glutStrokeRoman ; -struct freeglutStrokeFont glutStrokeMonoRoman ; +struct freeglutStrokeFont *glutStrokeRoman ; +struct freeglutStrokeFont *glutStrokeMonoRoman ; -struct freeglutBitmapFont glutBitmap9By15 ; -struct freeglutBitmapFont glutBitmap8By13 ; -struct freeglutBitmapFont glutBitmapTimesRoman10 ; -struct freeglutBitmapFont glutBitmapTimesRoman24 ; -struct freeglutBitmapFont glutBitmapHelvetica10 ; -struct freeglutBitmapFont glutBitmapHelvetica12 ; -struct freeglutBitmapFont glutBitmapHelvetica18 ; +struct freeglutBitmapFont *glutBitmap9By15 ; +struct freeglutBitmapFont *glutBitmap8By13 ; +struct freeglutBitmapFont *glutBitmapTimesRoman10 ; +struct freeglutBitmapFont *glutBitmapTimesRoman24 ; +struct freeglutBitmapFont *glutBitmapHelvetica10 ; +struct freeglutBitmapFont *glutBitmapHelvetica12 ; +struct freeglutBitmapFont *glutBitmapHelvetica18 ; #endif diff --git a/freeglut/freeglut/src/freeglut_init.c b/freeglut/freeglut/src/freeglut_init.c index eb0935b..3399289 100644 --- a/freeglut/freeglut/src/freeglut_init.c +++ b/freeglut/freeglut/src/freeglut_init.c @@ -75,6 +75,7 @@ SFG_State fgState = { { -1, -1, FALSE }, /* Position */ #endif { NULL, NULL }, /* Timers */ NULL, /* IdleCallback */ + FALSE, /* BuildingAMenu */ NULL, /* MenuStateCallback */ NULL, /* MenuStatusCallback */ { 640, 480, TRUE }, /* GameModeSize */ @@ -268,6 +269,15 @@ void fgDeinitialize( void ) return; } + /* + * If there was a menu created, destroy the rendering context + */ + if ( fgStructure.MenuContext ) + { + free ( fgStructure.MenuContext ) ; + fgStructure.MenuContext = NULL ; + } + /* * Perform the freeglut structure deinitialization */ diff --git a/freeglut/freeglut/src/freeglut_internal.h b/freeglut/freeglut/src/freeglut_internal.h index 70c845f..26ee0c2 100644 --- a/freeglut/freeglut/src/freeglut_internal.h +++ b/freeglut/freeglut/src/freeglut_internal.h @@ -89,8 +89,10 @@ #include #include - #if HAVE_X11_EXTENSIONS_XF86VMODE_H - #include + #ifndef __sgi + #ifndef SOLARIS + #include + #endif #endif #endif @@ -235,6 +237,7 @@ struct tagSFG_State FGCBidle IdleCallback; /* The global idle callback */ + GLboolean BuildingAMenu; /* True if we are presently making a menu */ FGCBmenuState MenuStateCallback; /* Menu callbacks are global */ FGCBmenuStatus MenuStatusCallback; @@ -383,9 +386,26 @@ struct tagSFG_WindowCallbacks FGCBtabletButton TabletButton; }; +/* + * This structure holds the OpenGL rendering context for all the menu windows + */ +typedef struct tagSFG_MenuContext SFG_MenuContext; +struct tagSFG_MenuContext +{ +#if TARGET_HOST_UNIX_X11 + GLXContext Context; /* The menu OpenGL context */ + XVisualInfo* VisualInfo; /* The window's visual information */ +#elif TARGET_HOST_WIN32 + HGLRC Context; /* The menu window's WGL context */ +#endif + +}; + /* * This structure describes a menu */ +typedef struct tagSFG_Window SFG_Window; +typedef struct tagSFG_MenuEntry SFG_MenuEntry; typedef struct tagSFG_Menu SFG_Menu; struct tagSFG_Menu { @@ -399,12 +419,15 @@ struct tagSFG_Menu int Width; /* Menu box width in pixels */ int Height; /* Menu box height in pixels */ int X, Y; /* Menu box raster position */ + + SFG_MenuEntry *ActiveEntry ; /* Currently active entry in the menu */ + SFG_Window *Window ; /* OpenGL window for menu */ + SFG_Window *ParentWindow ; /* OpenGL window in which the menu is defined */ }; /* * This is a menu entry */ -typedef struct tagSFG_MenuEntry SFG_MenuEntry; struct tagSFG_MenuEntry { SFG_Node Node; @@ -419,7 +442,6 @@ struct tagSFG_MenuEntry /* * A window, making part of freeglut windows hierarchy. Should be kept portable. */ -typedef struct tagSFG_Window SFG_Window; struct tagSFG_Window { SFG_Node Node; @@ -435,6 +457,8 @@ struct tagSFG_Window SFG_Window* Parent; /* The parent to this window */ SFG_List Children; /* The subwindows d.l. list */ + + GLboolean IsMenu; /* Set to 1 if we are a menu */ }; /* @@ -460,6 +484,8 @@ struct tagSFG_Structure SFG_Window* Window; /* The currently active win. */ SFG_Menu* Menu; /* Same, but menu... */ + SFG_MenuContext* MenuContext; /* OpenGL rendering context for menus */ + SFG_Window* GameMode; /* The game mode window */ int WindowID; /* The new current window ID */ @@ -673,6 +699,7 @@ void fgActivateMenu( SFG_Window* window, int button ); void fgExecuteMenuCallback( SFG_Menu* menu ) ; GLboolean fgCheckActiveMenu ( SFG_Window *window, SFG_Menu *menu ) ; void fgDeactivateMenu( SFG_Window *window ); +void fgDeactivateSubMenu( SFG_MenuEntry *menuEntry ); /* * This function gets called just before the buffers swap, so that diff --git a/freeglut/freeglut/src/freeglut_main.c b/freeglut/freeglut/src/freeglut_main.c index f9c78ef..858116a 100644 --- a/freeglut/freeglut/src/freeglut_main.c +++ b/freeglut/freeglut/src/freeglut_main.c @@ -652,9 +652,17 @@ void FGAPIENTRY glutMainLoopEvent( void ) GETWINDOW( xmotion ); GETMOUSE( xmotion ); /* - * Set the current window + * Fallback if there's an active menu hooked to this window */ - fgStructure.Window = window ; + if( window->ActiveMenu != NULL ) + { + /* + * Let's make the window redraw as a result of the mouse motion. + */ + window->State.Redisplay = TRUE ; + + break; + } /* * What kind of a movement was it? @@ -669,6 +677,11 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ if( window->Callbacks.Motion != NULL ) { + /* + * Set the current window + */ + fgStructure.Window = window ; + /* * Yup. Have it executed immediately */ @@ -682,6 +695,11 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ if( window->Callbacks.Passive != NULL ) { + /* + * Set the current window + */ + fgStructure.Window = window ; + /* * That's right, and there is a passive callback, too. */ @@ -749,7 +767,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* Execute the menu callback */ fgExecuteMenuCallback ( window->ActiveMenu ) ; - fgDeactivateMenu ( window ) ; + fgDeactivateMenu ( window->ActiveMenu->ParentWindow ) ; /* Restore the current window and menu */ fgSetWindow ( save_window ) ; @@ -757,7 +775,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) } else /* Outside the menu, deactivate the menu if it's a downclick */ { - if ( pressed == TRUE ) fgDeactivateMenu ( window ) ; + if ( pressed == TRUE ) fgDeactivateMenu ( window->ActiveMenu->ParentWindow ) ; } /* @@ -778,6 +796,11 @@ void FGAPIENTRY glutMainLoopEvent( void ) */ window->State.Redisplay = TRUE ; + /* + * Set the current window + */ + fgSetWindow( window ); + /* * Activate the appropriate menu structure... */ @@ -789,14 +812,9 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* * Check if there is a mouse callback hooked to the window */ - if( window->Callbacks.Mouse == NULL ) + if( fgStructure.Window->Callbacks.Mouse == NULL ) break; - /* - * Set the current window - */ - fgSetWindow( window ); - /* * Remember the current modifiers state */ @@ -807,12 +825,12 @@ void FGAPIENTRY glutMainLoopEvent( void ) modifiers |= GLUT_ACTIVE_CTRL; if (event.xbutton.state & Mod1Mask) modifiers |= GLUT_ACTIVE_ALT; - window->State.Modifiers = modifiers; + fgStructure.Window->State.Modifiers = modifiers; /* * Finally execute the mouse callback */ - window->Callbacks.Mouse( + fgStructure.Window->Callbacks.Mouse( button, event.type == ButtonPress ? GLUT_DOWN : GLUT_UP, event.xbutton.x, @@ -822,7 +840,7 @@ void FGAPIENTRY glutMainLoopEvent( void ) /* * Trash the modifiers state */ - window->State.Modifiers = 0xffffffff; + fgStructure.Window->State.Modifiers = 0xffffffff; } break; @@ -1169,18 +1187,49 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara */ window->Window.Device = GetDC( hWnd ); - /* - * Setup the pixel format of our window - */ - fgSetupPixelFormat( window, FALSE, PFD_MAIN_PLANE ); - /* * Create or get the OpenGL rendering context now */ - if ( fgState.UseCurrentContext == TRUE ) - window->Window.Context = wglGetCurrentContext(); - else + if ( fgState.BuildingAMenu ) + { + /* + * Setup the pixel format of our window + */ + unsigned int current_DisplayMode = fgState.DisplayMode ; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ; + fgSetupPixelFormat( window, FALSE, PFD_MAIN_PLANE ); + fgState.DisplayMode = current_DisplayMode ; + + /* + * If there isn't already an OpenGL rendering context for menu windows, make one + */ + if ( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) ) ; + fgStructure.MenuContext->Context = wglCreateContext( window->Window.Device ); + } + else + wglMakeCurrent ( window->Window.Device, fgStructure.MenuContext->Context ) ; + +/* window->Window.Context = wglGetCurrentContext () ; */ window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + { + /* + * Setup the pixel format of our window + */ + fgSetupPixelFormat( window, FALSE, PFD_MAIN_PLANE ); + + if ( fgState.UseCurrentContext == TRUE ) + { + window->Window.Context = wglGetCurrentContext(); + if ( ! window->Window.Context ) + window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + window->Window.Context = wglCreateContext( window->Window.Device ); + } /* * Still, we'll be needing to explicitly resize the window @@ -1465,7 +1514,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara /* Execute the menu callback */ fgExecuteMenuCallback ( window->ActiveMenu ) ; - fgDeactivateMenu ( window ) ; + fgDeactivateMenu ( window->ActiveMenu->ParentWindow ) ; /* Restore the current window and menu */ fgSetWindow ( save_window ) ; @@ -1473,13 +1522,13 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } else /* Outside the menu, deactivate the menu if it's a downclick */ { - if ( pressed == TRUE ) fgDeactivateMenu ( window ) ; + if ( pressed == TRUE ) fgDeactivateMenu ( window->ActiveMenu->ParentWindow ) ; } /* * Let's make the window redraw as a result of the mouse click and menu activity. */ - window->State.Redisplay = TRUE ; + if ( ! window->IsMenu ) window->State.Redisplay = TRUE ; break ; } @@ -1494,6 +1543,11 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara */ window->State.Redisplay = TRUE ; + /* + * Set the current window + */ + fgSetWindow( window ); + /* * Activate the appropriate menu structure... */ @@ -1505,18 +1559,13 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara /* * Check if there is a mouse callback hooked to the window */ - if( window->Callbacks.Mouse == NULL ) + if( fgStructure.Window->Callbacks.Mouse == NULL ) break; - /* - * Set the current window - */ - fgSetWindow( window ); - /* * Remember the current modifiers state. */ - window->State.Modifiers = + fgStructure.Window->State.Modifiers = ( ( (GetKeyState( VK_LSHIFT ) < 0 ) || ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | ( ( (GetKeyState( VK_LCONTROL ) < 0 ) || ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | ( ( (GetKeyState( VK_LMENU ) < 0 ) || ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); @@ -1524,7 +1573,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara /* * Finally execute the mouse callback */ - window->Callbacks.Mouse( + fgStructure.Window->Callbacks.Mouse( button, pressed == TRUE ? GLUT_DOWN : GLUT_UP, window->State.MouseX, @@ -1534,7 +1583,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara /* * Trash the modifiers state */ - window->State.Modifiers = 0xffffffff; + fgStructure.Window->State.Modifiers = 0xffffffff; } break; diff --git a/freeglut/freeglut/src/freeglut_menu.c b/freeglut/freeglut/src/freeglut_menu.c index 921deec..00e415d 100644 --- a/freeglut/freeglut/src/freeglut_menu.c +++ b/freeglut/freeglut/src/freeglut_menu.c @@ -96,7 +96,14 @@ static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) * 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 ) + GLboolean return_status = fghCheckMenuStatus( window, menuEntry->SubMenu ) ; + + /* + * Reactivate the submenu as the checkMenuStatus may have turned it off if the mouse + * is in its parent menu entry. + */ + menuEntry->SubMenu->IsActive = TRUE ; + if ( return_status == TRUE ) return( TRUE ); } } @@ -104,8 +111,8 @@ static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) /* * 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; + x = window->State.MouseX; + y = window->State.MouseY; /* * Mark all menu entries inactive... @@ -116,12 +123,13 @@ static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) 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 ) + if ( ( x >= 0 ) && ( x < menu->Width ) && ( y >= 0 ) && ( y < menu->Height ) && ( window == menu->Window ) ) { /* * Calculation of the highlighted menu item is easy enough now: @@ -140,9 +148,22 @@ static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) menuEntry->IsActive = TRUE; menuEntry->Ordinal = menuID; + /* + * If this is not the same as the last active menu entry, deactivate the previous entry. + * Specifically, if the previous active entry was a submenu then deactivate it. + */ + if ( menu->ActiveEntry && ( menuEntry != menu->ActiveEntry ) ) + { + if ( menu->ActiveEntry->SubMenu != NULL ) + fgDeactivateSubMenu ( menu->ActiveEntry ) ; + } + + menu->ActiveEntry = menuEntry ; + /* * Don't forget about marking the current menu as active, too: */ + menu->IsActive = TRUE; /* @@ -152,21 +173,31 @@ static GLboolean fghCheckMenuStatus( SFG_Window* window, SFG_Menu* menu ) */ 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 ) ) + if ( ! menuEntry->SubMenu->IsActive ) { - menuEntry->SubMenu->X = menu->X - menuEntry->SubMenu->Width ; - if ( menuEntry->SubMenu->X < 0 ) - menuEntry->SubMenu->X = glutGet ( GLUT_WINDOW_WIDTH ) - menuEntry->SubMenu->Width ; + SFG_Window *current_window = fgStructure.Window ; + + /* + * Set up the initial menu position now... + */ + + /* + * Mark the menu as active, so that it gets displayed: + */ + menuEntry->SubMenu->IsActive = TRUE ; + + /* + * Set up the initial submenu position now: + */ + menuEntry->SubMenu->X = menu->X + menu->Width ; + menuEntry->SubMenu->Y = menu->Y + menuEntry->Ordinal * FREEGLUT_MENU_HEIGHT ; + + fgSetWindow ( menuEntry->SubMenu->Window ) ; + glutShowWindow () ; + glutPositionWindow ( menuEntry->SubMenu->X, menuEntry->SubMenu->Y ) ; + glutReshapeWindow ( menuEntry->SubMenu->Width, menuEntry->SubMenu->Height ) ; + menuEntry->SubMenu->Window->ActiveMenu = menuEntry->SubMenu ; + fgSetWindow ( current_window ) ; } /* @@ -204,20 +235,20 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) * Have the menu box drawn first. The +- values are * here just to make it more nice-looking... */ - glColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); + glColor4f( 0.1289f, 0.2257f, 0.28516f, 1.0f ); /* a non-black dark version of the below. */ glBegin( GL_QUADS ); - glVertex2i( menu->X , menu->Y - 1 ); - glVertex2i( menu->X + menu->Width, menu->Y - 1 ); - glVertex2i( menu->X + menu->Width, menu->Y + 4 + menu->Height ); - glVertex2i( menu->X , menu->Y + 4 + menu->Height ); + glVertex2i( 0 , 0 ); + glVertex2i( menu->Width, 0 ); + glVertex2i( menu->Width, menu->Height ); + glVertex2i( 0 , menu->Height ); glEnd(); glColor4f( 0.3f, 0.4f, 0.5f, 1.0f ); glBegin( GL_QUADS ); - glVertex2i( menu->X - 2 , menu->Y + 1 ); - glVertex2i( menu->X - 2 + menu->Width, menu->Y + 1 ); - glVertex2i( menu->X - 2 + menu->Width, menu->Y + 2 + menu->Height ); - glVertex2i( menu->X - 2 , menu->Y + 2 + menu->Height ); + glVertex2i( 1, 1 ); + glVertex2i( menu->Width-1, 1 ); + glVertex2i( menu->Width-1, menu->Height-1); + glVertex2i( 1, menu->Height-1); glEnd(); /* @@ -243,10 +274,10 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) */ glColor4f( 0.2f, 0.3f, 0.4f, 1.0f ); glBegin( GL_QUADS ); - glVertex2i( menu->X - 2 , menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); - glVertex2i( menu->X - 2 + menu->Width, menu->Y + (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); - glVertex2i( menu->X - 2 + menu->Width, menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); - glVertex2i( menu->X - 2 , menu->Y + (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); + glVertex2i( 2 , (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); + glVertex2i( menu->Width-2, (menuID + 0)*FREEGLUT_MENU_HEIGHT + 1 ); + glVertex2i( menu->Width-2, (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); + glVertex2i( 2 , (menuID + 1)*FREEGLUT_MENU_HEIGHT + 2 ); glEnd(); } } @@ -263,8 +294,8 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) * Move the raster into position... */ glRasterPos2i( - menu->X + FREEGLUT_MENU_BORDER, - menu->Y + (i + 1)*FREEGLUT_MENU_HEIGHT + FREEGLUT_MENU_BORDER, + (i + 1)*FREEGLUT_MENU_HEIGHT-(int)(FREEGLUT_MENU_HEIGHT*0.3) /* Try to center the text - JCJ 31 July 2003*/ ); /* @@ -292,8 +323,8 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) 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 ) ; + glRasterPos2i ( menu->Width - 2 - width, + (i + 1)*FREEGLUT_MENU_HEIGHT ) ; glBitmap ( width, FREEGLUT_MENU_HEIGHT, 0, 0, 0.0, 0.0, arrow_char ) ; glPopClientAttrib(); } @@ -313,11 +344,30 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) /* * Yeah, indeed. Have it redrawn now: */ + fgSetWindow ( menuEntry->SubMenu->Window ) ; fghDisplayMenuBox( menuEntry->SubMenu ); + fgSetWindow ( menu->Window ) ; } } } +/* + * Private static function to set the parent window of a submenu and all of its submenus + */ +static void fghSetSubmenuParentWindow ( SFG_Window *window, SFG_Menu *menu ) +{ + SFG_MenuEntry *menuEntry ; + + menu->ParentWindow = window ; + + for ( menuEntry = menu->Entries.First; menuEntry; menuEntry = menuEntry->Node.Next ) + { + if ( menuEntry->SubMenu != NULL ) + fghSetSubmenuParentWindow ( window, menuEntry->SubMenu ) ; + } +} + + /* * Displays the currently active menu for the current window */ @@ -337,9 +387,12 @@ void fgDisplayMenu( void ) menu = window->ActiveMenu; /* - * Did we find an active window? + * Did we find an active menu? */ freeglut_return_if_fail( menu != NULL ); + + fgSetWindow ( menu->Window ) ; + /* * Prepare the OpenGL state to do the rendering first: */ @@ -388,6 +441,13 @@ void fgDisplayMenu( void ) glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); + + glutSwapBuffers () ; + + /* + * Restore the current window + */ + fgSetWindow ( window ) ; } /* @@ -395,8 +455,6 @@ void fgDisplayMenu( void ) */ void fgActivateMenu( SFG_Window* window, int button ) { - int x, y; - /* * We'll be referencing this menu a lot, so remember its address: */ @@ -408,24 +466,23 @@ void fgActivateMenu( SFG_Window* window, int button ) 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 ; - fgSetWindow ( window ) ; + menu->X = window->State.MouseX + glutGet ( GLUT_WINDOW_X ) ; + menu->Y = window->State.MouseY + glutGet ( GLUT_WINDOW_Y ) ; - if( x > ( glutGet( GLUT_WINDOW_WIDTH ) - menu->Width ) ) + fgSetWindow ( menu->Window ) ; + glutShowWindow () ; + glutPositionWindow ( menu->X, menu->Y ) ; + glutReshapeWindow ( menu->Width, menu->Height ) ; + menu->Window->ActiveMenu = menu ; + +/* 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; + menu->Y = glutGet( GLUT_WINDOW_HEIGHT ) - menu->Height; */ } /* @@ -493,21 +550,81 @@ void fgExecuteMenuCallback( SFG_Menu* menu ) */ void fgDeactivateMenu( SFG_Window *window ) { + SFG_Window *current_window = fgStructure.Window ; + /* * Check if there is an active menu attached to this window... */ SFG_Menu* menu = window->ActiveMenu; + SFG_MenuEntry *menuEntry ; /* * Did we find an active window? */ freeglut_return_if_fail( menu != NULL ); + /* + * Hide the present menu's window + */ + fgSetWindow ( menu->Window ) ; + glutHideWindow () ; + /* * Forget about having that menu active anymore, now: */ - window->ActiveMenu = NULL; + menu->Window->ActiveMenu = NULL ; + menu->ParentWindow->ActiveMenu = NULL ; menu->IsActive = FALSE ; + + /* + * Hide all submenu windows, and the root menu's window. + */ + for ( menuEntry = menu->Entries.First; menuEntry; + menuEntry = menuEntry->Node.Next ) + { + /* + * Is that an active submenu by any case? + */ + if ( ( menuEntry->SubMenu != NULL ) && menuEntry->SubMenu->IsActive ) + fgDeactivateSubMenu ( menuEntry ) ; + } + + fgStructure.Window = current_window ; +} + +/* + * Deactivates a menu pointed by the function argument. + */ +void fgDeactivateSubMenu( SFG_MenuEntry *menuEntry ) +{ + SFG_Window *current_window = fgStructure.Window ; + SFG_MenuEntry *subMenuIter ; + /* + * Hide the present menu's window + */ + fgSetWindow ( menuEntry->SubMenu->Window ) ; + glutHideWindow () ; + + /* + * Forget about having that menu active anymore, now: + */ + menuEntry->SubMenu->Window->ActiveMenu = NULL ; + menuEntry->SubMenu->IsActive = FALSE ; + + /* + * Hide all submenu windows, and the root menu's window. + */ + for ( subMenuIter = menuEntry->SubMenu->Entries.First; subMenuIter; + subMenuIter = subMenuIter->Node.Next ) + { + /* + * Is that an active submenu by any case? + */ + if ( ( subMenuIter->SubMenu != NULL ) && subMenuIter->SubMenu->IsActive ) + fgDeactivateSubMenu ( subMenuIter ) ; + } + + fgStructure.Window = current_window ; } /* @@ -534,6 +651,13 @@ void fghCalculateMenuBoxSize( void ) */ menuEntry->Width = glutBitmapLength( FREEGLUT_MENU_FONT, menuEntry->Text ); + /* + * If the entry is a submenu, then it needs to be wider to accomodate the arrow. JCJ 31 July 2003 + */ + + if (menuEntry->SubMenu != NULL) + menuEntry->Width += glutBitmapLength( FREEGLUT_MENU_FONT, " " ); + /* * Check if it's the biggest we've found */ @@ -669,6 +793,11 @@ void FGAPIENTRY glutAddSubMenu( const char* label, int subMenuID ) menuEntry->SubMenu = subMenu; menuEntry->ID = -1; + /* + * Make the submenu's parent window be the menu's parent window + */ + fghSetSubmenuParentWindow ( fgStructure.Menu->ParentWindow, subMenu ) ; + /* * Have the new menu entry attached to the current menu */ @@ -819,6 +948,11 @@ void FGAPIENTRY glutAttachMenu( int button ) * It is safe now to attach the menu */ fgStructure.Window->Menu[ button ] = fgStructure.Menu; + + /* + * Make the parent window of the menu (and all submenus) the current window + */ + fghSetSubmenuParentWindow ( fgStructure.Window, fgStructure.Menu ) ; } /* diff --git a/freeglut/freeglut/src/freeglut_state.c b/freeglut/freeglut/src/freeglut_state.c index c225cae..3dbc4bb 100644 --- a/freeglut/freeglut/src/freeglut_state.c +++ b/freeglut/freeglut/src/freeglut_state.c @@ -367,7 +367,8 @@ int FGAPIENTRY glutGet( GLenum eWhat ) /* * ...then we've got to correct the results we've just received... */ - if ( ( fgStructure.GameMode != fgStructure.Window ) && ( fgStructure.Window->Parent == NULL ) ) + if ( ( fgStructure.GameMode != fgStructure.Window ) && ( fgStructure.Window->Parent == NULL ) && + ( ! fgStructure.Window->IsMenu ) ) { winRect.left += GetSystemMetrics( SM_CXSIZEFRAME ); winRect.right -= GetSystemMetrics( SM_CXSIZEFRAME ); @@ -659,7 +660,8 @@ int FGAPIENTRY glutLayerGet( GLenum eWhat ) /* * Check if an overlay display mode is possible */ - return FALSE; +/* return( fgSetupPixelFormat( fgStructure.Window, TRUE, PFD_OVERLAY_PLANE ) ); */ + return FALSE ; case GLUT_LAYER_IN_USE: /* diff --git a/freeglut/freeglut/src/freeglut_structure.c b/freeglut/freeglut/src/freeglut_structure.c index 6b54d50..9945e99 100644 --- a/freeglut/freeglut/src/freeglut_structure.c +++ b/freeglut/freeglut/src/freeglut_structure.c @@ -41,7 +41,15 @@ * The SFG_Structure container holds information about windows and menus * created between glutInit() and glutMainLoop() return. */ -SFG_Structure fgStructure; + +SFG_Structure fgStructure = { { NULL, NULL }, /* The list of windows */ + { NULL, NULL }, /* The list of menus */ + NULL, /* The current window */ + NULL, /* The current menu */ + NULL, /* The menu OpenGL context */ + NULL, /* The game mode window */ + 0, /* The current new window ID */ + 0 }; /* The current new menu ID */ /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ @@ -102,6 +110,11 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, int x, int y, window->State.Cursor = GLUT_CURSOR_INHERIT; window->State.Modifiers = 0xffffffff; + /* + * If this window is a menu, set IsMenu in the structure + */ + window->IsMenu = fgState.BuildingAMenu ; + /* * Open the window now. The fgOpenWindow() function is system * dependant, and resides in freeglut_window.c. Uses fgState. @@ -119,6 +132,9 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title, int x, int y, */ SFG_Menu* fgCreateMenu( FGCBmenu menuCallback ) { + int x = 100, y = 100, w = 100, h = 100 ; + SFG_Window *current_window = fgStructure.Window ; + /* * Have the menu object created */ @@ -132,11 +148,34 @@ SFG_Menu* fgCreateMenu( FGCBmenu menuCallback ) if( !fgState.Time.Set ) glutInit( &fakeArgc, NULL ); + menu->ParentWindow = fgStructure.Window ; + + /* + * Create a window for the menu to reside in. Set the + * global variable BuildingAMenu to true so we can ensure + * it is created without decorations. + */ + fgState.BuildingAMenu = TRUE ; + + fgCreateWindow ( NULL, NULL, x, y, w, h, FALSE ) ; + menu->Window = fgStructure.Window ; + glutDisplayFunc ( fgDisplayMenu ) ; + + /* + * While BuildingAMenu is true, all windows built have no decorations. That's + * not a good default behavior, so let's set it false again. + */ + fgState.BuildingAMenu = FALSE ; + + glutHideWindow () ; /* Hide the window for now */ + fgStructure.Window = current_window ; + /* * Initialize the object properties: */ menu->ID = ++fgStructure.MenuID; menu->Callback = menuCallback; + menu->ActiveEntry = NULL ; /* * Initialize the entries list @@ -390,6 +429,11 @@ void fgDestroyMenu( SFG_Menu* menu ) free( entry ); } + /* + * Destroy the window associated with the menu + */ + fgDestroyWindow ( menu->Window, TRUE ) ; + /* * Remove the menu from the menus list */ diff --git a/freeglut/freeglut/src/freeglut_window.c b/freeglut/freeglut/src/freeglut_window.c index 48ab127..08cb8d9 100644 --- a/freeglut/freeglut/src/freeglut_window.c +++ b/freeglut/freeglut/src/freeglut_window.c @@ -233,7 +233,7 @@ GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, unsigned * It might be the case for us to use double buffering */ if( fgState.DisplayMode & GLUT_DOUBLE ) - flags |= PFD_DOUBLEBUFFER; + flags |= PFD_DOUBLEBUFFER; /* * Specify which pixel format do we opt for... @@ -363,7 +363,24 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i /* * Here we are upon the stage. Have the visual selected. */ - window->Window.VisualInfo = fgChooseVisual(); + if ( fgState.BuildingAMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu windows, make one + */ + if ( !fgStructure.MenuContext ) + { + unsigned int current_DisplayMode = fgState.DisplayMode ; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ; + window->Window.VisualInfo = fgChooseVisual(); + fgState.DisplayMode = current_DisplayMode ; + } + else + window->Window.VisualInfo = fgChooseVisual(); + } + else + window->Window.VisualInfo = fgChooseVisual(); + if ( ! window->Window.VisualInfo ) { /* @@ -430,7 +447,28 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i * The GLX context creation, possibly trying the direct context rendering * or else use the current context if the user has so specified */ - if ( fgState.UseCurrentContext == TRUE ) + if ( fgState.BuildingAMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu windows, make one + */ + if ( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) ) ; + fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo ; + fgStructure.MenuContext->Context = glXCreateContext( + fgDisplay.Display, fgStructure.MenuContext->VisualInfo, + NULL, fgState.ForceDirectContext | fgState.TryDirectContext + ); + } + +/* window->Window.Context = fgStructure.MenuContext->Context ; */ + window->Window.Context = glXCreateContext( + fgDisplay.Display, window->Window.VisualInfo, + NULL, fgState.ForceDirectContext | fgState.TryDirectContext + ); + } + else if ( fgState.UseCurrentContext == TRUE ) { window->Window.Context = glXGetCurrentContext(); @@ -564,7 +602,7 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i if( gameMode == FALSE ) { - if ( !isSubWindow ) + if ( ( !isSubWindow ) && ( ! window->IsMenu ) ) { /* * Update the window dimensions, taking account of window decorations. @@ -575,26 +613,27 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + GetSystemMetrics( SM_CYCAPTION ); } - /* * Check if the user wants us to use the default position/size */ if( fgState.Position.Use == FALSE ) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; } - - if( fgState.Size .Use == FALSE ) { w = CW_USEDEFAULT; h = CW_USEDEFAULT; } + if( fgState.Size .Use == FALSE ) { w = CW_USEDEFAULT; h = CW_USEDEFAULT; } - - /* + /* * There's a small difference between creating the top, child and game mode windows */ flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; - if( window->Parent == NULL ) + /* + * If we're a menu, set our flags to include WS_POPUP to remove decorations + */ + if ( window->IsMenu ) + flags |= WS_POPUP ; + else if( window->Parent == NULL ) flags |= WS_OVERLAPPEDWINDOW; else flags |= WS_CHILD; } - else { /* @@ -608,7 +647,6 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; } - /* * Create the window now, passing the freeglut window structure as the parameter */ @@ -651,14 +689,12 @@ void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, i glReadBuffer ( GL_FRONT ) ; } - /* * Set the newly created window as the current one */ fgSetWindow( window ); } - /* * Closes a window, destroying the frame and OpenGL context */ @@ -697,7 +733,6 @@ void fgCloseWindow( SFG_Window* window ) } - /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ /* @@ -712,7 +747,6 @@ int FGAPIENTRY glutCreateWindow( const char* title ) fgState.Size.X, fgState.Size.Y, FALSE )->ID ); } - /* * This function creates a sub window. */ @@ -744,7 +778,6 @@ int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) return( window->ID ); } - /* * Destroys a window and all of its subwindows */ @@ -771,7 +804,6 @@ void FGAPIENTRY glutDestroyWindow( int windowID ) fgState.ExecState = ExecState ; } - /* * This function selects the current window */ @@ -808,11 +840,9 @@ void FGAPIENTRY glutSetWindow( int ID ) return; } - fgSetWindow ( window ) ; } - /* * This function returns the ID number of the current window, 0 if none exists */ @@ -831,14 +861,12 @@ int FGAPIENTRY glutGetWindow( void ) return( 0 ); } - /* * Otherwise, return the ID of the current window */ return( fgStructure.Window->ID ); } - /* * This function makes the current window visible */ @@ -860,8 +888,13 @@ void FGAPIENTRY glutShowWindow( void ) ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW ); #endif -} + /* + * Since the window is visible, we need to redisplay it ... + */ + fgStructure.Window->State.Redisplay = TRUE; + +} /* * This function hides the current window @@ -882,7 +915,6 @@ void FGAPIENTRY glutHideWindow( void ) */ XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen ); } - else { /* @@ -891,7 +923,6 @@ void FGAPIENTRY glutHideWindow( void ) XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); } - /* * Flush the X state now */ @@ -904,8 +935,12 @@ void FGAPIENTRY glutHideWindow( void ) ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE ); #endif -} + /* + * Since the window is hidden, we don't need to redisplay it ... + */ + fgStructure.Window->State.Redisplay = FALSE; +} /* * Iconify the current window (top-level windows only) @@ -928,8 +963,13 @@ void FGAPIENTRY glutIconifyWindow( void ) ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE ); #endif -} + /* + * Since the window is just an icon, we don't need to redisplay it ... + */ + fgStructure.Window->State.Redisplay = FALSE; + +} /* * Set the current window's title @@ -971,7 +1011,6 @@ void FGAPIENTRY glutSetWindowTitle( const char* title ) XFlush( fgDisplay.Display ); } - #elif TARGET_HOST_WIN32 /* * This seems to be a bit easier under Win32 @@ -981,7 +1020,6 @@ void FGAPIENTRY glutSetWindowTitle( const char* title ) #endif } - /* * Set the current window's iconified title */ @@ -1022,7 +1060,6 @@ void FGAPIENTRY glutSetIconTitle( const char* title ) XFlush( fgDisplay.Display ); } - #elif TARGET_HOST_WIN32 /* * This seems to be a bit easier under Win32 @@ -1032,7 +1069,6 @@ void FGAPIENTRY glutSetIconTitle( const char* title ) #endif } - /* * Change the current window's size */ @@ -1062,12 +1098,14 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) if ( fgStructure.Window->Parent == NULL ) /* If this is not a subwindow ... */ { /* - * Adjust the size of the window to allow for the size of the frame + * Adjust the size of the window to allow for the size of the frame, if we are not a menu */ - width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; - height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION ); + if ( ! fgStructure.Window->IsMenu ) + { + width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2; + height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION ); + } } - else /* This is a subwindow, get the parent window's position and subtract it off */ { GetWindowRect ( fgStructure.Window->Parent->Window.Handle, &winRect ) ; @@ -1075,7 +1113,6 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ) ; } - /* * Resize the window, forcing a redraw to happen */ @@ -1088,11 +1125,9 @@ void FGAPIENTRY glutReshapeWindow( int width, int height ) TRUE ); } - #endif } - /* * Change the current window's position */ @@ -1129,11 +1164,9 @@ void FGAPIENTRY glutPositionWindow( int x, int y ) ); } - #endif } - /* * Lowers the current window (by Z order change) */ @@ -1161,7 +1194,6 @@ void FGAPIENTRY glutPushWindow( void ) #endif } - /* * Raises the current window (by Z order change) */ @@ -1189,7 +1221,6 @@ void FGAPIENTRY glutPopWindow( void ) #endif } - /* * Resize the current window so that it fits the whole screen */ @@ -1208,7 +1239,6 @@ void FGAPIENTRY glutFullScreen( void ) ); } - /* * A.Donev: Set and retrieve the window's user data */ @@ -1217,11 +1247,18 @@ void* FGAPIENTRY glutGetWindowData( void ) return(fgStructure.Window->UserData); } - void FGAPIENTRY glutSetWindowData(void* data) { fgStructure.Window->UserData=data; } - /*** END OF FILE ***/ + + + + + + + + +