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,34 +493,39 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
break; break;
case WM_KILLFOCUS: case WM_KILLFOCUS:
/* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
/* If this is a menu that lost focus, see if user either switched
application or FreeGLUT window (if one is running multiple
windows). If so, close menu that lost focus.
*/
if( window->IsMenu &&
window->ActiveMenu && window->ActiveMenu->IsActive )
{ {
SFG_Window* wnd = NULL; SFG_Menu* menu = NULL;
HWND hwnd = GetForegroundWindow(); /* Get window with current focus */ /* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
if (hwnd) lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
/* See if its one of our windows */ INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
wnd = fgWindowByHandle(hwnd);
if (!hwnd || !wnd) /* If we have an open menu, see if the open menu should be closed
/* User switched to another application*/ when focus was lost because user either switched
fgDeactivateMenu(window->ActiveMenu->ParentWindow); application or FreeGLUT window (if one is running multiple
else if ( windows). If so, close menu the active menu.
( 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!=window->ActiveMenu->ParentWindow) if ( fgStructure.CurrentMenu )
) menu = fgGetActiveMenu();
/* User switched to another FreeGLUT window */
fgDeactivateMenu(window->ActiveMenu->ParentWindow); if ( menu )
{
SFG_Window* wnd = NULL;
HWND hwnd = GetForegroundWindow(); /* Get window with current focus */
if (hwnd)
/* See if its one of our windows */
wnd = fgWindowByHandle(hwnd);
if (!hwnd || !wnd)
/* User switched to another application*/
fgDeactivateMenu(menu->ParentWindow);
else if (
( 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!=menu->ParentWindow)
)
/* User switched to another FreeGLUT window */
fgDeactivateMenu(menu->ParentWindow);
}
} }
break; break;
#if 0 #if 0