added note about maximizing behavior on Windows (when the maximize
[freeglut] / src / fg_menu.c
index 2460b1d..6a7d96d 100644 (file)
@@ -29,6 +29,7 @@
 #include <GL/freeglut.h>
 #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(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 )
 {
@@ -512,7 +514,7 @@ static void fghActivateMenu( SFG_Window* window, int button )
     SFG_Menu* menu = window->Menu[ button ];
     SFG_Window* current_window = fgStructure.CurrentWindow;
 
-    /* If the menu is already active in another window, deactivate it (and any submenu's) there */
+    /* If the menu is already active in another window, deactivate it (and any submenus) there */
     if ( menu->ParentWindow )
       fgDeactivateMenu(menu->ParentWindow);
 
@@ -543,6 +545,17 @@ static void fghActivateMenu( SFG_Window* window, int button )
     menu->Window->State.MouseY =
         window->State.MouseY + glutGet( GLUT_WINDOW_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)
+            fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY);
+    }
+
     fgSetWindow( menu->Window );
     glutPositionWindow( menu->X, menu->Y );
     glutReshapeWindow( menu->Width, menu->Height );
@@ -620,11 +633,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
@@ -659,12 +673,13 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed,
 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 );
 
     parent_window = menu->ParentWindow;
@@ -689,12 +704,32 @@ 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 );
     }
 
     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 on screen and convert to relative to parent_window's client area */
+            SFG_XYUse mouse_pos;
+            fghPlatformGetCursorPos(&mouse_pos);
+            
+            mouse_pos.X -= glutGet( GLUT_WINDOW_X );
+            mouse_pos.Y -= glutGet( GLUT_WINDOW_Y );
+
+            fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y);
+        }
+    }
 }
 
 /*
@@ -751,6 +786,9 @@ int FGAPIENTRY glutCreateMenu( void(* callback)( int ) )
 {
     /* 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 +803,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 +846,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 +873,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 +894,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 +924,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 +957,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 +983,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 +1002,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 );