small updates to one demo, so windowed windows display after the
[freeglut] / src / fg_menu.c
index 65ec674..9b40bfe 100644 (file)
@@ -76,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 ---------------------------------------------------- */
 
@@ -508,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 ];
@@ -526,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(&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;
 
@@ -539,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 );
@@ -698,6 +719,26 @@ void fgDeactivateMenu( SFG_Window *window )
     }
 
     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);
+        }
+    }
 }
 
 /*
@@ -754,6 +795,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;
 }
 
@@ -768,6 +812,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 );
@@ -809,7 +855,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;
@@ -833,6 +882,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 );
@@ -851,7 +903,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 );
@@ -878,10 +933,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: */
@@ -907,7 +966,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 );
@@ -930,7 +992,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 );
@@ -946,7 +1011,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 );