X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffg_menu.c;h=0247a88f27b0acf4866af6124dd64307415d742a;hb=8255a4e895c56fa302e3f4beb045e4ff2bf2bb3c;hp=0c6c64e5842f3709f5574b96d03d9e20d7df6ae7;hpb=49e61d9b74ae8520b5b7fddbcfc727081ac54391;p=freeglut diff --git a/src/fg_menu.c b/src/fg_menu.c index 0c6c64e..0247a88 100644 --- a/src/fg_menu.c +++ b/src/fg_menu.c @@ -29,6 +29,7 @@ #include #include "fg_internal.h" + /* -- DEFINITIONS ---------------------------------------------------------- */ /* @@ -75,6 +76,7 @@ static float menu_pen_hback [4] = FREEGLUT_MENU_PEN_HBACK_COLORS; extern GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y ); +extern void fghPlatformGetCursorPos(const SFG_Window *window, GLboolean client, SFG_XYUse *mouse_pos); /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ @@ -403,7 +405,7 @@ static void fghDisplayMenuBox( SFG_Menu* menu ) /* * Private static function to set the parent window of a submenu and all - * of its submenus + * of its submenus. */ static void fghSetMenuParentWindow( SFG_Window *window, SFG_Menu *menu ) { @@ -507,6 +509,7 @@ void fgDisplayMenu( void ) static void fghActivateMenu( SFG_Window* window, int button ) { int max_x, max_y; + SFG_XYUse mouse_pos; /* We'll be referencing this menu a lot, so remember its address: */ SFG_Menu* menu = window->Menu[ button ]; @@ -525,9 +528,17 @@ static void fghActivateMenu( SFG_Window* window, int button ) /* Set up the initial menu position now: */ fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); fgSetWindow( window ); - menu->X = window->State.MouseX + glutGet( GLUT_WINDOW_X ); - menu->Y = window->State.MouseY + glutGet( GLUT_WINDOW_Y ); + /* get mouse position on screen (window->State.MouseX and window->State.MouseY + * are relative to client area origin), and not easy to correct given that + * glutGet( GLUT_WINDOW_X ) and glutGet( GLUT_WINDOW_Y ) return relative to parent + * origin when looking at a child window + * for parent windows: window->State.MouseX + glutGet( GLUT_WINDOW_X ) == mouse_pos.X + */ + fghPlatformGetCursorPos(NULL, GL_FALSE, &mouse_pos); + menu->X = mouse_pos.X; + menu->Y = mouse_pos.Y; + /* Make sure the whole menu is on the screen */ if( menu->X + menu->Width > max_x ) menu->X -=menu->Width; @@ -538,10 +549,21 @@ static void fghActivateMenu( SFG_Window* window, int button ) menu->Y = 0; } - menu->Window->State.MouseX = - window->State.MouseX + glutGet( GLUT_WINDOW_X ) - menu->X; - menu->Window->State.MouseY = - window->State.MouseY + glutGet( GLUT_WINDOW_Y ) - menu->Y; + /* Set position of mouse relative to top-left menu in menu's window state (could as well set 0 at creation time...) */ + menu->Window->State.MouseX = mouse_pos.X - menu->X; + menu->Window->State.MouseY = mouse_pos.Y - menu->Y; + + /* Menu status callback */ + if (fgState.MenuStateCallback || fgState.MenuStatusCallback) + { + fgStructure.CurrentMenu = menu; + fgStructure.CurrentWindow = window; + if (fgState.MenuStateCallback) + fgState.MenuStateCallback(GLUT_MENU_IN_USE); + if (fgState.MenuStatusCallback) + /* window->State.MouseX and window->State.MouseY are relative to client area origin, as needed */ + fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY); + } fgSetWindow( menu->Window ); glutPositionWindow( menu->X, menu->Y ); @@ -620,11 +642,12 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, /* * Outside the menu, deactivate if it's a downclick * - * XXX This isn't enough. A downclick outside of - * XXX the interior of our freeglut windows should also - * XXX deactivate the menu. This is more complicated. + * A downclick outside of the interior of our freeglut windows + * is dealt with in the WM_KILLFOCUS handler of fgPlatformWindowProc */ + { fgDeactivateMenu( window->ActiveMenu->ParentWindow ); + } /* * XXX Why does an active menu require a redisplay at @@ -644,10 +667,18 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, ( window->Menu[ button ] ) && pressed ) { - /* XXX Posting a requisite Redisplay seems bogus. */ - window->State.Redisplay = GL_TRUE; - fghActivateMenu( window, button ); - return GL_TRUE; + /* If mouseclick was outside the parent window, ignore. This can + * happen when another mouse button is already depressed and the + * window thus has mouse capture + */ + if (window->State.MouseX>0 && window->State.MouseY>0 && + window->State.MouseXState.Width && window->State.MouseYState.Height) + { + /* XXX Posting a requisite Redisplay seems bogus. */ + window->State.Redisplay = GL_TRUE; + fghActivateMenu( window, button ); + return GL_TRUE; + } } return GL_FALSE; @@ -656,16 +687,22 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, /* * Deactivates a menu pointed by the function argument. */ +static SFG_Menu* menuDeactivating = NULL; void fgDeactivateMenu( SFG_Window *window ) { SFG_Window *parent_window = NULL; - - /* Check if there is an active menu attached to this window... */ - SFG_Menu* menu = window->ActiveMenu; + SFG_Menu* menu; SFG_MenuEntry *menuEntry; /* Did we find an active window? */ + freeglut_return_if_fail( window ); + /* Check if there is an active menu attached to this window... */ + menu = window->ActiveMenu; freeglut_return_if_fail( menu ); + /* Check if we are already deactivating this menu, abort in that case (glutHideWindow below can cause this function to be called again on the same menu..) */ + if (menu==menuDeactivating) + return; + menuDeactivating = menu; parent_window = menu->ParentWindow; @@ -689,12 +726,31 @@ void fgDeactivateMenu( SFG_Window *window ) { menuEntry->IsActive = GL_FALSE; - /* Is that an active submenu by any case? */ + /* Is that an active submenu by any chance? */ if( menuEntry->SubMenu ) fghDeactivateSubMenu( menuEntry ); } + /* Done deactivating menu */ + menuDeactivating = NULL; fgSetWindow ( parent_window ) ; + + /* Menu status callback */ + if (fgState.MenuStateCallback || fgState.MenuStatusCallback) + { + fgStructure.CurrentMenu = menu; + fgStructure.CurrentWindow = parent_window; + if (fgState.MenuStateCallback) + fgState.MenuStateCallback(GLUT_MENU_NOT_IN_USE); + if (fgState.MenuStatusCallback) + { + /* Get cursor position relative to parent_window's client area */ + SFG_XYUse mouse_pos; + fghPlatformGetCursorPos(parent_window, GL_TRUE, &mouse_pos); + + fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y); + } + } } /* @@ -747,10 +803,13 @@ void fghCalculateMenuBoxSize( void ) /* * Creates a new menu object, adding it to the freeglut structure */ -int FGAPIENTRY glutCreateMenu( void(* callback)( int ) ) +int FGAPIENTRY glutCreateMenu( FGCBMenu callback ) { /* The menu object creation code resides in freeglut_structure.c */ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + return fgCreateMenu( callback )->ID; } @@ -765,6 +824,8 @@ void FGAPIENTRY glutDestroyMenu( int menuID ) menu = fgMenuByID( menuID ); freeglut_return_if_fail( menu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); /* The menu object destruction code resides in freeglut_structure.c */ fgDestroyMenu( menu ); @@ -806,7 +867,10 @@ void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddMenuEntry" ); menuEntry = (SFG_MenuEntry *)calloc( sizeof(SFG_MenuEntry), 1 ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); menuEntry->Text = strdup( label ); menuEntry->ID = value; @@ -830,6 +894,9 @@ void FGAPIENTRY glutAddSubMenu( const char *label, int subMenuID ) subMenu = fgMenuByID( subMenuID ); freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + freeglut_return_if_fail( subMenu ); menuEntry->Text = strdup( label ); @@ -848,7 +915,10 @@ void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ) SFG_MenuEntry* menuEntry = NULL; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToMenuEntry" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); /* Get n-th menu entry in the current menu, starting from one: */ menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); @@ -875,10 +945,14 @@ void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToSubMenu" ); - subMenu = fgMenuByID( subMenuID ); - menuEntry = NULL; freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + + /* Get handle to sub menu */ + subMenu = fgMenuByID( subMenuID ); + menuEntry = NULL; freeglut_return_if_fail( subMenu ); /* Get n-th menu entry in the current menu, starting from one: */ @@ -904,7 +978,10 @@ void FGAPIENTRY glutRemoveMenuItem( int item ) SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutRemoveMenuItem" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); /* Get n-th menu entry in the current menu, starting from one: */ menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); @@ -927,7 +1004,10 @@ void FGAPIENTRY glutAttachMenu( int button ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAttachMenu" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); freeglut_return_if_fail( button >= 0 ); freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); @@ -943,7 +1023,10 @@ void FGAPIENTRY glutDetachMenu( int button ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDetachMenu" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); freeglut_return_if_fail( button >= 0 ); freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS );