//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: The menu manager // // $Revision: $ // $NoKeywords: $ //===========================================================================// #include "menumanager.h" #include "vgui_controls/panel.h" #include "vgui_controls/frame.h" #include "uimanager.h" //----------------------------------------------------------------------------- // Singleton //----------------------------------------------------------------------------- static CMenuManager s_MenuManager; extern CMenuManager *g_pMenuManager = &s_MenuManager; //----------------------------------------------------------------------------- // Static members. // NOTE: Do *not* set this to 0; it could cause us to lose some registered // menus since that list is set up during construction //----------------------------------------------------------------------------- IMenuFactory *CMenuManager::m_pFirstFactory; //----------------------------------------------------------------------------- // Call to register methods which can construct menus w/ particular names //----------------------------------------------------------------------------- IMenuFactory *CMenuManager::RegisterMenu( IMenuFactory *pMenuFactory ) { // NOTE: This method is expected to be called during global constructor // time, so it must not require any global constructors to be called to work IMenuFactory *pPrevFactory = m_pFirstFactory; m_pFirstFactory = pMenuFactory; return pPrevFactory; } //----------------------------------------------------------------------------- // Init, shutdown //----------------------------------------------------------------------------- bool CMenuManager::Init() { // Build a dictionary of all registered menus IMenuFactory *pFactory; for ( pFactory = m_pFirstFactory; pFactory; pFactory = pFactory->GetNextFactory() ) { m_MenuFactories.Insert( pFactory->GetMenuName(), pFactory ); } m_bPopRequested = false; m_bPopAllRequested = false; m_pPushRequested = NULL; return true; } void CMenuManager::Shutdown() { CleanUpAllMenus(); } //----------------------------------------------------------------------------- // Push, pop menus //----------------------------------------------------------------------------- void CMenuManager::PushMenu( const char *pMenuName ) { AssertMsg( !m_pPushRequested, "Can't request to push two menus in a single frame!" ); MenuFactoryIndex_t i = m_MenuFactories.Find( pMenuName ); if ( i == m_MenuFactories.InvalidIndex() ) { Warning( "Tried to push unknown menu %s\n", pMenuName ); return; } m_pPushRequested = m_MenuFactories[i]; } void CMenuManager::PopMenu( ) { AssertMsg( !m_bPopRequested, "Can't request to pop two menus in a single frame!" ); AssertMsg( !m_pPushRequested, "Can't request to pop after requesting to push a menu in a single frame!" ); m_bPopRequested = true; } void CMenuManager::PopAllMenus( ) { AssertMsg( !m_pPushRequested, "Can't request to pop after requesting to push a menu in a single frame!" ); m_bPopAllRequested = true; } //----------------------------------------------------------------------------- // Request a menu to switch to //----------------------------------------------------------------------------- void CMenuManager::SwitchToMenu( const char *pMenuName ) { AssertMsg( !m_bPopRequested, "Can't request to pop two menus in a single frame!" ); AssertMsg( !m_pPushRequested, "Can't request to push two menus in a single frame!" ); MenuFactoryIndex_t i = m_MenuFactories.Find( pMenuName ); if ( i == m_MenuFactories.InvalidIndex() ) { Warning( "Tried to switch to unknown menu %s\n", pMenuName ); return; } m_bPopRequested = true; m_pPushRequested = m_MenuFactories[i]; } //----------------------------------------------------------------------------- // Returns the name of the topmost panel //----------------------------------------------------------------------------- const char *CMenuManager::GetTopmostPanelName() { if ( !m_nActiveMenu.Count() ) return NULL; return m_nActiveMenu.Top()->GetName(); } //----------------------------------------------------------------------------- // Request a menu to switch to //----------------------------------------------------------------------------- void CMenuManager::Update( ) { if ( m_bPopAllRequested ) { CleanUpAllMenus(); m_bPopAllRequested = false; return; } if ( m_bPopRequested ) { AssertMsg( m_nActiveMenu.Count(), "Tried to pop a menu when no menus are active" ); vgui::Panel *pTop = m_nActiveMenu.Top(); pTop->MarkForDeletion(); m_nActiveMenu.Pop(); // Mark the new active menu as visible, attach it to hierarchy. if ( m_nActiveMenu.Count() > 0 ) { vgui::Panel *pTop = m_nActiveMenu.Top(); pTop->SetVisible( true ); pTop->SetParent( g_pUIManager->GetRootPanel( UI_ROOT_MENU ) ); } else { g_pUIManager->EnablePanel( UI_ROOT_MENU, false ); } m_bPopRequested = false; } if ( m_pPushRequested ) { // Mark the previous menu as not visible, detach it from hierarchy. if ( m_nActiveMenu.Count() > 0 ) { vgui::Panel *pTop = m_nActiveMenu.Top(); pTop->SetVisible( false ); pTop->SetParent( (vgui::Panel*)NULL ); } else { g_pUIManager->EnablePanel( UI_ROOT_MENU, true ); } vgui::Panel *pMenu = m_pPushRequested->CreateMenu( g_pUIManager->GetRootPanel( UI_ROOT_MENU ) ); m_nActiveMenu.Push( pMenu ); static_cast( pMenu )->Activate(); m_pPushRequested = NULL; } } //----------------------------------------------------------------------------- // Cleans up all menus //----------------------------------------------------------------------------- void CMenuManager::CleanUpAllMenus() { while ( m_nActiveMenu.Count() ) { vgui::Panel *pTop = m_nActiveMenu.Top(); pTop->MarkForDeletion(); m_nActiveMenu.Pop(); } g_pUIManager->EnablePanel( UI_ROOT_MENU, false ); }