can now also handle the case where menus is opened, client area of

window with menu is clicked and then user switches to another window.

Implemented menu enumerator and a function for getting currently active
menu, if any


git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@1354 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
dcnieho 2012-07-21 04:04:45 +00:00
parent e32b8f09fb
commit 233d93d550
4 changed files with 133 additions and 41 deletions

View File

@ -661,7 +661,8 @@ struct tagSFG_Enumerator
GLboolean found; /* Used to terminate search */ GLboolean found; /* Used to terminate search */
void* data; /* Custom data pointer */ void* data; /* Custom data pointer */
}; };
typedef void (* FGCBenumerator )( SFG_Window *, SFG_Enumerator * ); typedef void (* FGCBWindowEnumerator )( SFG_Window *, SFG_Enumerator * );
typedef void (* FGCBMenuEnumerator )( SFG_Menu *, SFG_Enumerator * );
/* The bitmap font structure */ /* The bitmap font structure */
typedef struct tagSFG_Font SFG_Font; typedef struct tagSFG_Font SFG_Font;
@ -915,8 +916,8 @@ void fgSetCursor ( SFG_Window *window, int cursorID );
* and userData is the a custom user-supplied pointer. Functions * and userData is the a custom user-supplied pointer. Functions
* are defined and exported from freeglut_structure.c file. * are defined and exported from freeglut_structure.c file.
*/ */
void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator );
void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
SFG_Enumerator* enumerator ); SFG_Enumerator* enumerator );
/* /*
@ -939,6 +940,12 @@ SFG_Window* fgWindowByID( int windowID );
*/ */
SFG_Menu* fgMenuByID( int menuID ); SFG_Menu* fgMenuByID( int menuID );
/*
* Returns active menu, if any. Assumption: only one menu active throughout application at any one time.
* This is easier than fgWindowByXXX as all menus are placed in one doubly linked list...
*/
SFG_Menu* fgGetActiveMenu( );
/* /*
* The menu activation and deactivation the code. This is the meat * The menu activation and deactivation the code. This is the meat
* of the menu user interface handling code... * of the menu user interface handling code...

View File

@ -512,7 +512,7 @@ static void fghActivateMenu( SFG_Window* window, int button )
SFG_Menu* menu = window->Menu[ button ]; SFG_Menu* menu = window->Menu[ button ];
SFG_Window* current_window = fgStructure.CurrentWindow; 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 ) if ( menu->ParentWindow )
fgDeactivateMenu(menu->ParentWindow); fgDeactivateMenu(menu->ParentWindow);

View File

@ -378,7 +378,7 @@ void fgDestroyStructure( void )
/* /*
* Helper function to enumerate through all registered top-level windows * Helper function to enumerate through all registered top-level windows
*/ */
void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ) void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator )
{ {
SFG_Window *window; SFG_Window *window;
@ -397,11 +397,33 @@ void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator )
} }
} }
/*
* Helper function to enumerate through all registered top-level windows
*/
void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator )
{
SFG_Menu *menu;
FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator,
"Enumerator or callback missing from window enumerator call",
"fgEnumWindows" );
/* It's enough to check all entries in fgStructure.Menus... */
for( menu = (SFG_Menu *)fgStructure.Menus.First;
menu;
menu = (SFG_Menu *)menu->Node.Next )
{
enumCallback( menu, enumerator );
if( enumerator->found )
return;
}
}
/* /*
* Helper function to enumerate through all a window's subwindows * Helper function to enumerate through all a window's subwindows
* (single level descent) * (single level descent)
*/ */
void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
SFG_Enumerator* enumerator ) SFG_Enumerator* enumerator )
{ {
SFG_Window *child; SFG_Window *child;
@ -485,7 +507,7 @@ static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator )
} }
/* /*
* This function is similiar to the previous one, except it is * This function is similar to the previous one, except it is
* looking for a specified (sub)window identifier. The function * looking for a specified (sub)window identifier. The function
* is defined in freeglut_structure.c file. * is defined in freeglut_structure.c file.
*/ */
@ -493,7 +515,7 @@ SFG_Window* fgWindowByID( int windowID )
{ {
SFG_Enumerator enumerator; SFG_Enumerator enumerator;
/* Uses a method very similiar for fgWindowByHandle... */ /* Uses a method very similar for fgWindowByHandle... */
enumerator.found = GL_FALSE; enumerator.found = GL_FALSE;
enumerator.data = ( void * )&windowID; enumerator.data = ( void * )&windowID;
fgEnumWindows( fghcbWindowByID, &enumerator ); fgEnumWindows( fghcbWindowByID, &enumerator );
@ -503,19 +525,77 @@ SFG_Window* fgWindowByID( int windowID )
} }
/* /*
* Looks up a menu given its ID. This is easier that fgWindowByXXX * A static helper function to look for a menu given its ID
*/
static void fghcbMenuByID( SFG_Menu *menu,
SFG_Enumerator *enumerator )
{
if ( enumerator->found )
return;
/* Check the menu's ID. */
if( menu->ID == (int)(enumerator->data) )
{
enumerator->found = GL_TRUE;
enumerator->data = menu;
return;
}
}
/*
* Looks up a menu given its ID. This is easier than fgWindowByXXX
* as all menus are placed in one doubly linked list... * as all menus are placed in one doubly linked list...
*/ */
SFG_Menu* fgMenuByID( int menuID ) SFG_Menu* fgMenuByID( int menuID )
{ {
SFG_Menu *menu = NULL; SFG_Enumerator enumerator;
/* This is easy and makes use of the menus enumeration defined above */
enumerator.found = GL_FALSE;
enumerator.data = (void *)menuID;
fgEnumMenus( fghcbMenuByID, &enumerator );
if( enumerator.found )
return( SFG_Menu *) enumerator.data;
return NULL;
}
/*
* A static helper function to look for an active menu
*/
static void fghcbGetActiveMenu( SFG_Menu *menu,
SFG_Enumerator *enumerator )
{
if ( enumerator->found )
return;
/* Check the menu's ID. */
if( menu->IsActive )
{
enumerator->found = GL_TRUE;
enumerator->data = menu;
return;
}
}
/*
* Returns active menu, if any. Assumption: only one menu active throughout application at any one time.
* This is easier than fgWindowByXXX as all menus are placed in one doubly linked list...
*/
SFG_Menu* fgGetActiveMenu( )
{
SFG_Enumerator enumerator;
/* This is easy and makes use of the menus enumeration defined above */
enumerator.found = GL_FALSE;
fgEnumMenus( fghcbGetActiveMenu, &enumerator );
if( enumerator.found )
return( SFG_Menu *) enumerator.data;
/* It's enough to check all entries in fgStructure.Menus... */
for( menu = (SFG_Menu *)fgStructure.Menus.First;
menu;
menu = (SFG_Menu *)menu->Node.Next )
if( menu->ID == menuID )
return menu;
return NULL; return NULL;
} }

View File

@ -493,16 +493,21 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
break; break;
case WM_KILLFOCUS: case WM_KILLFOCUS:
{
SFG_Menu* menu = NULL;
/* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */ /* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
/* If this is a menu that lost focus, see if user either switched /* If we have an open menu, see if the open menu should be closed
when focus was lost because user either switched
application or FreeGLUT window (if one is running multiple application or FreeGLUT window (if one is running multiple
windows). If so, close menu that lost focus. windows). If so, close menu the active menu.
*/ */
if( window->IsMenu && if ( fgStructure.CurrentMenu )
window->ActiveMenu && window->ActiveMenu->IsActive ) menu = fgGetActiveMenu();
if ( menu )
{ {
SFG_Window* wnd = NULL; SFG_Window* wnd = NULL;
HWND hwnd = GetForegroundWindow(); /* Get window with current focus */ HWND hwnd = GetForegroundWindow(); /* Get window with current focus */
@ -512,15 +517,15 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
if (!hwnd || !wnd) if (!hwnd || !wnd)
/* User switched to another application*/ /* User switched to another application*/
fgDeactivateMenu(window->ActiveMenu->ParentWindow); fgDeactivateMenu(menu->ParentWindow);
else if ( else if (
( wnd->IsMenu && wnd->ActiveMenu->ParentWindow!=window->ActiveMenu->ParentWindow) || /* Make sure we don't kill the menu when trying to enter a submenu */ ( wnd->IsMenu && wnd->ActiveMenu && wnd->ActiveMenu->ParentWindow!=menu->ParentWindow) || /* Make sure we don't kill the menu when trying to enter a submenu */
(!wnd->IsMenu && wnd!=window->ActiveMenu->ParentWindow) (!wnd->IsMenu && wnd!=menu->ParentWindow)
) )
/* User switched to another FreeGLUT window */ /* User switched to another FreeGLUT window */
fgDeactivateMenu(window->ActiveMenu->ParentWindow); fgDeactivateMenu(menu->ParentWindow);
}
} }
break; break;
#if 0 #if 0