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 */
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 */
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
* are defined and exported from freeglut_structure.c file.
*/
void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator );
void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator );
void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
SFG_Enumerator* enumerator );
/*
@ -939,6 +940,12 @@ SFG_Window* fgWindowByID( int windowID );
*/
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
* 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_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);

View File

@ -378,7 +378,7 @@ void fgDestroyStructure( void )
/*
* 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;
@ -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
* (single level descent)
*/
void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback,
void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback,
SFG_Enumerator* enumerator )
{
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
* is defined in freeglut_structure.c file.
*/
@ -493,7 +515,7 @@ SFG_Window* fgWindowByID( int windowID )
{
SFG_Enumerator enumerator;
/* Uses a method very similiar for fgWindowByHandle... */
/* Uses a method very similar for fgWindowByHandle... */
enumerator.found = GL_FALSE;
enumerator.data = ( void * )&windowID;
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...
*/
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;
}

View File

@ -493,34 +493,39 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
break;
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;
HWND hwnd = GetForegroundWindow(); /* Get window with current focus */
if (hwnd)
/* See if its one of our windows */
wnd = fgWindowByHandle(hwnd);
SFG_Menu* menu = NULL;
/* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
if (!hwnd || !wnd)
/* User switched to another application*/
fgDeactivateMenu(window->ActiveMenu->ParentWindow);
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!=window->ActiveMenu->ParentWindow)
)
/* User switched to another FreeGLUT window */
fgDeactivateMenu(window->ActiveMenu->ParentWindow);
/* 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
windows). If so, close menu the active menu.
*/
if ( fgStructure.CurrentMenu )
menu = fgGetActiveMenu();
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;
#if 0