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:
parent
e32b8f09fb
commit
233d93d550
@ -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...
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user