//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include #include #include #include #include // isdigit() #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vgui_controls/Menu.h" #include "vgui_controls/MenuItem.h" #include "UtlSortVector.h" #include "tier1/utldict.h" #include "tier1/utlbuffer.h" #include "mempool.h" #include "filesystem.h" #include "tier0/icommandline.h" #include "tier0/minidump.h" #include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include using namespace vgui; #define TRIPLE_PRESS_MSEC 300 const char *g_PinCornerStrings [] = { "PIN_TOPLEFT", "PIN_TOPRIGHT", "PIN_BOTTOMLEFT", "PIN_BOTTOMRIGHT", "PIN_CENTER_TOP", "PIN_CENTER_RIGHT", "PIN_CENTER_BOTTOM", "PIN_CENTER_LEFT", }; COMPILE_TIME_ASSERT( Panel::PIN_LAST == ARRAYSIZE( g_PinCornerStrings ) ); extern int GetBuildModeDialogCount(); static char *CopyString( const char *in ) { if ( !in ) return NULL; int len = strlen( in ); char *n = new char[ len + 1 ]; Q_strncpy( n, in, len + 1 ); return n; } #ifdef STAGING_ONLY ConVar tf_strict_mouse_up_events( "tf_strict_mouse_up_events", "0", FCVAR_ARCHIVE, "Only allow Mouse-Release events to happens on panels we also Mouse-Downed in" ); #endif // Temporary convar to help debug why the MvMVictoryMannUpPanel TabContainer is sometimes way off to the left. ConVar tf_debug_tabcontainer( "tf_debug_tabcontainer", "0", FCVAR_HIDDEN, "Spew TabContainer dimensions." ); #if defined( VGUI_USEDRAGDROP ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- struct vgui::DragDrop_t { DragDrop_t() : m_bDragEnabled( false ), m_bShowDragHelper( true ), m_bDropEnabled( false ), m_bDragStarted( false ), m_nDragStartTolerance( 8 ), m_bDragging( false ), m_lDropHoverTime( 0 ), m_bDropMenuShown( false ), m_bPreventChaining( false ) { m_nStartPos[ 0 ] = m_nStartPos[ 1 ] = 0; m_nLastPos[ 0 ] = m_nLastPos[ 1 ] = 0; } // Drag related data bool m_bDragEnabled; bool m_bShowDragHelper; bool m_bDragging; bool m_bDragStarted; // How many pixels the dragged box must move before showing the outline rect... int m_nDragStartTolerance; int m_nStartPos[ 2 ]; int m_nLastPos[ 2 ]; CUtlVector< KeyValues * > m_DragData; CUtlVector< PHandle > m_DragPanels; // Drop related data bool m_bDropEnabled; // A droppable panel can have a hover context menu, which will show up after m_flHoverContextTime of hovering float m_flHoverContextTime; PHandle m_hCurrentDrop; // Amount of time hovering over current drop target long m_lDropHoverTime; bool m_bDropMenuShown; DHANDLE< Menu > m_hDropContextMenu; // Misc data bool m_bPreventChaining; }; //----------------------------------------------------------------------------- // Purpose: Helper for painting to the full screen... //----------------------------------------------------------------------------- class CDragDropHelperPanel : public Panel { DECLARE_CLASS_SIMPLE( CDragDropHelperPanel, Panel ); public: CDragDropHelperPanel(); virtual VPANEL IsWithinTraverse(int x, int y, bool traversePopups); virtual void PostChildPaint(); void AddPanel( Panel *current ); void RemovePanel( Panel *search ); private: struct DragHelperPanel_t { PHandle m_hPanel; }; CUtlVector< DragHelperPanel_t > m_PaintList; }; vgui::DHANDLE< CDragDropHelperPanel > s_DragDropHelper; #endif #if defined( VGUI_USEKEYBINDINGMAPS ) BoundKey_t::BoundKey_t(): isbuiltin( true ), bindingname( 0 ), keycode( KEY_NONE ), modifiers( 0 ) { } BoundKey_t::BoundKey_t( const BoundKey_t& src ) { isbuiltin = src.isbuiltin; bindingname = isbuiltin ? src.bindingname : CopyString( src.bindingname ); keycode = src.keycode; modifiers = src.modifiers; } BoundKey_t& BoundKey_t::operator =( const BoundKey_t& src ) { if ( this == &src ) return *this; isbuiltin = src.isbuiltin; bindingname = isbuiltin ? src.bindingname : CopyString( src.bindingname ); keycode = src.keycode; modifiers = src.modifiers; return *this; } BoundKey_t::~BoundKey_t() { if ( !isbuiltin ) { delete[] bindingname; } } KeyBindingMap_t::KeyBindingMap_t() : bindingname( 0 ), func( 0 ), helpstring( 0 ), docstring( 0 ), passive( false ) { } KeyBindingMap_t::KeyBindingMap_t( const KeyBindingMap_t& src ) { bindingname = src.bindingname; helpstring = src.helpstring; docstring = src.docstring; func = src.func; passive = src.passive; } KeyBindingMap_t::~KeyBindingMap_t() { } class CKeyBindingsMgr { public: CKeyBindingsMgr() : m_Bindings( 0, 0, KeyBindingContextHandleLessFunc ), m_nKeyBindingContexts( 0 ) { } struct KBContext_t { KBContext_t() : m_KeyBindingsFile( UTL_INVAL_SYMBOL ), m_KeyBindingsPathID( UTL_INVAL_SYMBOL ) { m_Handle = INVALID_KEYBINDINGCONTEXT_HANDLE; } KBContext_t( const KBContext_t& src ) { m_Handle = src.m_Handle; m_KeyBindingsFile = src.m_KeyBindingsFile; m_KeyBindingsPathID = src.m_KeyBindingsPathID; int c = src.m_Panels.Count(); for ( int i = 0; i < c; ++i ) { m_Panels.AddToTail( src.m_Panels[ i ] ); } } KeyBindingContextHandle_t m_Handle; CUtlSymbol m_KeyBindingsFile; CUtlSymbol m_KeyBindingsPathID; CUtlVector< Panel * > m_Panels; }; static bool KeyBindingContextHandleLessFunc( const KBContext_t& lhs, const KBContext_t& rhs ) { return lhs.m_Handle < rhs.m_Handle; } KeyBindingContextHandle_t CreateContext( char const *filename, char const *pathID ) { KBContext_t entry; entry.m_Handle = (KeyBindingContextHandle_t)++m_nKeyBindingContexts; entry.m_KeyBindingsFile = filename; if ( pathID ) { entry.m_KeyBindingsPathID = pathID; } else { entry.m_KeyBindingsPathID = UTL_INVAL_SYMBOL; } m_Bindings.Insert( entry ); return entry.m_Handle; } void AddPanelToContext( KeyBindingContextHandle_t handle, Panel *panel ) { if ( !panel->GetName() || !panel->GetName()[ 0 ] ) { Warning( "Can't add Keybindings Context for unnamed panels\n" ); return; } KBContext_t *entry = Find( handle ); Assert( entry ); if ( entry ) { int idx = entry->m_Panels.Find( panel ); if ( idx == entry->m_Panels.InvalidIndex() ) { entry->m_Panels.AddToTail( panel ); } } } void OnPanelDeleted( KeyBindingContextHandle_t handle, Panel *panel ) { KBContext_t *kb = Find( handle ); if ( kb ) { kb->m_Panels.FindAndRemove( panel ); } } KBContext_t *Find( KeyBindingContextHandle_t handle ) { KBContext_t search; search.m_Handle = handle; int idx = m_Bindings.Find( search ); if ( idx == m_Bindings.InvalidIndex() ) { return NULL; } return &m_Bindings[ idx ]; } char const *GetKeyBindingsFile( KeyBindingContextHandle_t handle ) { KBContext_t *kb = Find( handle ); if ( kb ) { return kb->m_KeyBindingsFile.String(); } Assert( 0 ); return ""; } char const *GetKeyBindingsFilePathID( KeyBindingContextHandle_t handle ) { KBContext_t *kb = Find( handle ); if ( kb ) { return kb->m_KeyBindingsPathID.String(); } Assert( 0 ); return NULL; } int GetPanelsWithKeyBindingsCount( KeyBindingContextHandle_t handle ) { KBContext_t *kb = Find( handle ); if ( kb ) { return kb->m_Panels.Count(); } Assert( 0 ); return 0; } //----------------------------------------------------------------------------- // Purpose: static method // Input : index - // Output : Panel //----------------------------------------------------------------------------- Panel *GetPanelWithKeyBindings( KeyBindingContextHandle_t handle, int index ) { KBContext_t *kb = Find( handle ); if ( kb ) { Assert( index >= 0 && index < kb->m_Panels.Count() ); return kb->m_Panels[ index ]; } Assert( 0 ); return 0; } CUtlRBTree< KBContext_t, int > m_Bindings; int m_nKeyBindingContexts; }; static CKeyBindingsMgr g_KBMgr; //----------------------------------------------------------------------------- // Purpose: Static method to allocate a context // Input : - // Output : KeyBindingContextHandle_t //----------------------------------------------------------------------------- KeyBindingContextHandle_t Panel::CreateKeyBindingsContext( char const *filename, char const *pathID /*=0*/ ) { return g_KBMgr.CreateContext( filename, pathID ); } COMPILE_TIME_ASSERT( ( MOUSE_MIDDLE - MOUSE_LEFT ) == 2 ); Panel* Panel::m_sMousePressedPanels[] = { NULL, NULL, NULL }; //----------------------------------------------------------------------------- // Purpose: static method // Input : - // Output : int //----------------------------------------------------------------------------- int Panel::GetPanelsWithKeyBindingsCount( KeyBindingContextHandle_t handle ) { return g_KBMgr.GetPanelsWithKeyBindingsCount( handle ); } //----------------------------------------------------------------------------- // Purpose: static method // Input : index - // Output : Panel //----------------------------------------------------------------------------- Panel *Panel::GetPanelWithKeyBindings( KeyBindingContextHandle_t handle, int index ) { return g_KBMgr.GetPanelWithKeyBindings( handle, index ); } //----------------------------------------------------------------------------- // Returns the number of keybindings //----------------------------------------------------------------------------- int Panel::GetKeyMappingCount( ) { int nCount = 0; PanelKeyBindingMap *map = GetKBMap(); while ( map ) { nCount += map->entries.Count(); map = map->baseMap; } return nCount; } //----------------------------------------------------------------------------- // Purpose: static method. Reverts key bindings for all registered panels (panels with keybindings actually // loaded from file // Input : - //----------------------------------------------------------------------------- void Panel::RevertKeyBindings( KeyBindingContextHandle_t handle ) { int c = GetPanelsWithKeyBindingsCount( handle ); for ( int i = 0; i < c; ++i ) { Panel *kbPanel = GetPanelWithKeyBindings( handle, i ); Assert( kbPanel ); kbPanel->RevertKeyBindingsToDefault(); } } static void BufPrint( CUtlBuffer& buf, int level, char const *fmt, ... ) { char string[ 2048 ]; va_list argptr; va_start( argptr, fmt ); _vsnprintf( string, sizeof( string ) - 1, fmt, argptr ); va_end( argptr ); string[ sizeof( string ) - 1 ] = 0; while ( --level >= 0 ) { buf.Printf( " " ); } buf.Printf( "%s", string ); } //----------------------------------------------------------------------------- // Purpose: // Input : handle - //----------------------------------------------------------------------------- void Panel::SaveKeyBindings( KeyBindingContextHandle_t handle ) { char const *filename = g_KBMgr.GetKeyBindingsFile( handle ); char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle ); SaveKeyBindingsToFile( handle, filename, pathID ); } //----------------------------------------------------------------------------- // Purpose: static method. Saves key binding files out for all keybindings // Input : - //----------------------------------------------------------------------------- void Panel::SaveKeyBindingsToFile( KeyBindingContextHandle_t handle, char const *filename, char const *pathID /*= 0*/ ) { CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); BufPrint( buf, 0, "keybindings\n" ); BufPrint( buf, 0, "{\n" ); int c = GetPanelsWithKeyBindingsCount( handle ); for ( int i = 0; i < c; ++i ) { Panel *kbPanel = GetPanelWithKeyBindings( handle, i ); Assert( kbPanel ); if ( !kbPanel ) continue; Assert( kbPanel->GetName() ); Assert( kbPanel->GetName()[ 0 ] ); if ( !kbPanel->GetName() || !kbPanel->GetName()[ 0 ] ) continue; BufPrint( buf, 1, "\"%s\"\n", kbPanel->GetName() ); BufPrint( buf, 1, "{\n" ); kbPanel->SaveKeyBindingsToBuffer( 2, buf ); BufPrint( buf, 1, "}\n" ); } BufPrint( buf, 0, "}\n" ); if ( g_pFullFileSystem->FileExists( filename, pathID ) && !g_pFullFileSystem->IsFileWritable( filename, pathID ) ) { Warning( "Panel::SaveKeyBindings '%s' is read-only!!!\n", filename ); } FileHandle_t h = g_pFullFileSystem->Open( filename, "wb", pathID ); if ( FILESYSTEM_INVALID_HANDLE != h ) { g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), h ); g_pFullFileSystem->Close( h ); } } //----------------------------------------------------------------------------- // Purpose: // Input : handle - // *panelOfInterest - //----------------------------------------------------------------------------- void Panel::LoadKeyBindingsForOnePanel( KeyBindingContextHandle_t handle, Panel *panelOfInterest ) { if ( !panelOfInterest ) return; if ( !panelOfInterest->GetName() ) return; if ( !panelOfInterest->GetName()[ 0 ] ) return; char const *filename = g_KBMgr.GetKeyBindingsFile( handle ); char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle ); KeyValues *kv = new KeyValues( "keybindings" ); if ( kv->LoadFromFile( g_pFullFileSystem, filename, pathID ) ) { int c = GetPanelsWithKeyBindingsCount( handle ); for ( int i = 0; i < c; ++i ) { Panel *kbPanel = GetPanelWithKeyBindings( handle, i ); Assert( kbPanel ); char const *panelName = kbPanel->GetName(); if ( !panelName ) { continue; } if ( Q_stricmp( panelOfInterest->GetName(), panelName ) ) continue; KeyValues *subKey = kv->FindKey( panelName, false ); if ( !subKey ) { Warning( "Panel::ReloadKeyBindings: Can't find entry for panel '%s'\n", panelName ); continue; } kbPanel->ParseKeyBindings( subKey ); } } kv->deleteThis(); } //----------------------------------------------------------------------------- // Purpose: static method. Loads all key bindings again // Input : - //----------------------------------------------------------------------------- void Panel::ReloadKeyBindings( KeyBindingContextHandle_t handle ) { char const *filename = g_KBMgr.GetKeyBindingsFile( handle ); char const *pathID = g_KBMgr.GetKeyBindingsFilePathID( handle ); KeyValues *kv = new KeyValues( "keybindings" ); if ( kv->LoadFromFile( g_pFullFileSystem, filename, pathID ) ) { int c = GetPanelsWithKeyBindingsCount( handle ); for ( int i = 0; i < c; ++i ) { Panel *kbPanel = GetPanelWithKeyBindings( handle, i ); Assert( kbPanel ); char const *panelName = kbPanel->GetName(); if ( !panelName ) { continue; } KeyValues *subKey = kv->FindKey( panelName, false ); if ( !subKey ) { Warning( "Panel::ReloadKeyBindings: Can't find entry for panel '%s'\n", panelName ); continue; } kbPanel->ParseKeyBindings( subKey ); } } kv->deleteThis(); } #endif // VGUI_USEKEYBINDINGMAPS DECLARE_BUILD_FACTORY( Panel ); //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- Panel::Panel() { Init(0, 0, 64, 24); } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- Panel::Panel(Panel *parent) { Init(0, 0, 64, 24); SetParent(parent); } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- Panel::Panel(Panel *parent, const char *panelName) { Init(0, 0, 64, 24); SetName(panelName); SetParent(parent); SetBuildModeEditable(true); } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- Panel::Panel( Panel *parent, const char *panelName, HScheme scheme ) { Init(0, 0, 64, 24); SetName(panelName); SetParent(parent); SetBuildModeEditable(true); SetScheme( scheme ); } //----------------------------------------------------------------------------- // Purpose: Setup //----------------------------------------------------------------------------- void Panel::Init( int x, int y, int wide, int tall ) { _panelName = NULL; _tooltipText = NULL; _pinToSibling = NULL; m_hMouseEventHandler = NULL; _pinCornerToSibling = PIN_TOPLEFT; _pinToSiblingCorner = PIN_TOPLEFT; // get ourselves an internal panel _vpanel = ivgui()->AllocPanel(); ipanel()->Init(_vpanel, this); SetPos(x, y); SetSize(wide, tall); _flags.SetFlag( NEEDS_LAYOUT | NEEDS_SCHEME_UPDATE | NEEDS_DEFAULT_SETTINGS_APPLIED ); _flags.SetFlag( AUTODELETE_ENABLED | PAINT_BORDER_ENABLED | PAINT_BACKGROUND_ENABLED | PAINT_ENABLED ); #if defined( VGUI_USEKEYBINDINGMAPS ) _flags.SetFlag( ALLOW_CHAIN_KEYBINDING_TO_PARENT ); #endif m_nPinDeltaX = m_nPinDeltaY = 0; m_nResizeDeltaX = m_nResizeDeltaY = 0; _autoResizeDirection = AUTORESIZE_NO; _pinCorner = PIN_TOPLEFT; _cursor = dc_arrow; _border = NULL; _buildGroup = UTLHANDLE_INVALID; _tabPosition = 0; m_iScheme = 0; m_bIsSilent = false; m_bParentNeedsCursorMoveEvents = false; _buildModeFlags = 0; // not editable or deletable in buildmode dialog by default m_pTooltips = NULL; m_bToolTipOverridden = false; m_flAlpha = 255.0f; m_nPaintBackgroundType = 0; //============================================================================= // HPE_BEGIN: // [tj] Default to rounding all corners (for draw style 2) //============================================================================= m_roundedCorners = PANEL_ROUND_CORNER_ALL; //============================================================================= // HPE_END //============================================================================= m_nBgTextureId1 = -1; m_nBgTextureId2 = -1; m_nBgTextureId3 = -1; m_nBgTextureId4 = -1; #if defined( VGUI_USEDRAGDROP ) m_pDragDrop = new DragDrop_t; #endif m_lLastDoublePressTime = 0L; #if defined( VGUI_USEKEYBINDINGMAPS ) m_hKeyBindingsContext = INVALID_KEYBINDINGCONTEXT_HANDLE; #endif REGISTER_COLOR_AS_OVERRIDABLE( _fgColor, "fgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( _bgColor, "bgcolor_override" ); m_bIsConsoleStylePanel = false; m_NavUp = NULL; m_NavDown = NULL; m_NavLeft = NULL; m_NavRight = NULL; m_NavToRelay = NULL; m_NavActivate = NULL; m_NavBack = NULL; m_sNavUpName = NULL; m_sNavDownName = NULL; m_sNavLeftName = NULL; m_sNavRightName = NULL; m_sNavToRelayName = NULL; m_sNavActivateName = NULL; m_sNavBackName = NULL; m_PassUnhandledInput = true; m_LastNavDirection = ND_NONE; m_bWorldPositionCurrentFrame = false; m_bForceStereoRenderToFrameBuffer = false; } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- Panel::~Panel() { // @note Tom Bui: only cleanup if we've created it if ( !m_bToolTipOverridden ) { if ( m_pTooltips ) { delete m_pTooltips; } } #if defined( VGUI_USEKEYBINDINGMAPS ) if ( IsValidKeyBindingsContext() ) { g_KBMgr.OnPanelDeleted( m_hKeyBindingsContext, this ); } #endif // VGUI_USEKEYBINDINGMAPS #if defined( VGUI_USEDRAGDROP ) if ( m_pDragDrop->m_bDragging ) { OnFinishDragging( false, (MouseCode)-1 ); } #endif // VGUI_USEDRAGDROP _flags.ClearFlag( AUTODELETE_ENABLED ); _flags.SetFlag( MARKED_FOR_DELETION ); // remove panel from any list SetParent((VPANEL)NULL); // Stop our children from pointing at us, and delete them if possible while (ipanel()->GetChildCount(GetVPanel())) { VPANEL child = ipanel()->GetChild(GetVPanel(), 0); if (ipanel()->IsAutoDeleteSet(child)) { ipanel()->DeletePanel(child); } else { ipanel()->SetParent(child, NULL); } } // delete VPanel ivgui()->FreePanel(_vpanel); // free our name delete [] _panelName; if ( _tooltipText && _tooltipText[0] ) { delete [] _tooltipText; } delete [] _pinToSibling; _vpanel = NULL; #if defined( VGUI_USEDRAGDROP ) delete m_pDragDrop; #endif // VGUI_USEDRAGDROP #if defined( VGUI_PANEL_VERIFY_DELETES ) // Zero out our vtbl pointer. This should hopefully help us catch bad guys using // this panel after it has been deleted. uintp *panel_vtbl = (uintp *)this; *panel_vtbl = NULL; #endif } //----------------------------------------------------------------------------- // Purpose: fully construct this panel so its ready for use right now (i.e fonts loaded, colors set, default label text set, ...) //----------------------------------------------------------------------------- void Panel::MakeReadyForUse() { // PerformApplySchemeSettings(); UpdateSiblingPin(); surface()->SolveTraverse( GetVPanel(), true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetName( const char *panelName ) { // No change? if ( _panelName && panelName && !Q_strcmp( _panelName, panelName ) ) { return; } if (_panelName) { delete [] _panelName; _panelName = NULL; } if (panelName) { int len = Q_strlen(panelName) + 1; _panelName = new char[ len ]; Q_strncpy( _panelName, panelName, len ); } } //----------------------------------------------------------------------------- // Purpose: returns the given name of the panel //----------------------------------------------------------------------------- const char *Panel::GetName() { if (_panelName) return _panelName; return ""; } //----------------------------------------------------------------------------- // Purpose: returns the name of the module that this instance of panel was compiled into //----------------------------------------------------------------------------- const char *Panel::GetModuleName() { return vgui::GetControlsModuleName(); } //----------------------------------------------------------------------------- // Purpose: returns the classname of the panel (as specified in the panelmaps) //----------------------------------------------------------------------------- const char *Panel::GetClassName() { // loop up the panel map name PanelMessageMap *panelMap = GetMessageMap(); if ( panelMap ) { return panelMap->pfnClassName(); } return "Panel"; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetPos(int x, int y) { if ( !HushAsserts() ) { Assert( abs(x) < 32768 && abs(y) < 32768 ); } ipanel()->SetPos(GetVPanel(), x, y); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::GetPos(int &x, int &y) { ipanel()->GetPos(GetVPanel(), x, y); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int Panel::GetXPos() { int x,y; GetPos( x, y ); return x; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int Panel::GetYPos() { int x,y; GetPos( x, y ); return y; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetSize(int wide, int tall) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() ); Assert( abs(wide) < 32768 && abs(tall) < 32768 ); ipanel()->SetSize(GetVPanel(), wide, tall); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::GetSize(int &wide, int &tall) { ipanel()->GetSize(GetVPanel(), wide, tall); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetBounds(int x, int y, int wide, int tall) { SetPos(x,y); SetSize(wide,tall); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::GetBounds(int &x, int &y, int &wide, int &tall) { GetPos(x, y); GetSize(wide, tall); } //----------------------------------------------------------------------------- // Purpose: returns safe handle to parent //----------------------------------------------------------------------------- VPANEL Panel::GetVParent() { if ( ipanel() ) { return ipanel()->GetParent(GetVPanel()); } return 0; } //----------------------------------------------------------------------------- // Purpose: returns a pointer to a controls version of a Panel pointer //----------------------------------------------------------------------------- Panel *Panel::GetParent() { // get the parent and convert it to a Panel * // this is OK, the hierarchy is guaranteed to be all from the same module, except for the root node // the root node always returns NULL when a GetParent() is done so everything is OK if ( ipanel() ) { VPANEL parent = ipanel()->GetParent(GetVPanel()); if (parent) { Panel *pParent = ipanel()->GetPanel(parent, GetControlsModuleName()); Assert(!pParent || !strcmp(pParent->GetModuleName(), GetControlsModuleName())); return pParent; } } return NULL; } //----------------------------------------------------------------------------- // Purpose: Screen size change notification handler //----------------------------------------------------------------------------- void Panel::OnScreenSizeChanged(int nOldWide, int nOldTall) { // post to all children for (int i = 0; i < ipanel()->GetChildCount(GetVPanel()); i++) { VPANEL child = ipanel()->GetChild(GetVPanel(), i); PostMessage(child, new KeyValues("OnScreenSizeChanged", "oldwide", nOldWide, "oldtall", nOldTall), NULL); } // make any currently fullsize window stay fullsize int x, y, wide, tall; GetBounds(x, y, wide, tall); int screenWide, screenTall; surface()->GetScreenSize(screenWide, screenTall); if (x == 0 && y == 0 && nOldWide == wide && tall == nOldTall) { // fullsize surface()->GetScreenSize(wide, tall); SetBounds(0, 0, wide, tall); } // panel needs to re-get it's scheme settings _flags.SetFlag( NEEDS_SCHEME_UPDATE ); // invalidate our settings InvalidateLayout(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetVisible(bool state) { ipanel()->SetVisible(GetVPanel(), state); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::IsVisible() { if (ipanel()) { return ipanel()->IsVisible(GetVPanel()); } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetEnabled(bool state) { if (state != ipanel()->IsEnabled( GetVPanel())) { ipanel()->SetEnabled(GetVPanel(), state); InvalidateLayout(false); Repaint(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::IsEnabled() { return ipanel()->IsEnabled(GetVPanel()); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::IsPopup() { return ipanel()->IsPopup(GetVPanel()); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::Repaint() { _flags.SetFlag( NEEDS_REPAINT ); if (surface()) { surface()->Invalidate(GetVPanel()); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::Think() { if (IsVisible()) { // update any tooltips if (m_pTooltips) { m_pTooltips->PerformLayout(); } if ( _flags.IsFlagSet( NEEDS_LAYOUT ) ) { InternalPerformLayout(); } } OnThink(); } void Panel::OnChildSettingsApplied( KeyValues *pInResourceData, Panel *pChild ) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() ); Panel* pParent = GetParent(); if( pParent ) { pParent->OnChildSettingsApplied( pInResourceData, pChild ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::PaintTraverse( bool repaint, bool allowForce ) { if ( m_bWorldPositionCurrentFrame ) { surface()->SolveTraverse( GetVPanel() ); } if ( !IsVisible() ) { return; } float oldAlphaMultiplier = surface()->DrawGetAlphaMultiplier(); float newAlphaMultiplier = oldAlphaMultiplier * m_flAlpha * 1.0f/255.0f; if ( IsXbox() && !newAlphaMultiplier ) { // xbox optimization not suitable for pc // xbox panels are compliant and can early out and not traverse their children // when they have no opacity return; } if ( !repaint && allowForce && _flags.IsFlagSet( NEEDS_REPAINT ) ) { repaint = true; _flags.ClearFlag( NEEDS_REPAINT ); } VPANEL vpanel = GetVPanel(); bool bPushedViewport = false; if( GetForceStereoRenderToFrameBuffer() ) { CMatRenderContextPtr pRenderContext( materials ); if( pRenderContext->GetRenderTarget() ) { surface()->PushFullscreenViewport(); bPushedViewport = true; } } int clipRect[4]; ipanel()->GetClipRect( vpanel, clipRect[0], clipRect[1], clipRect[2], clipRect[3] ); if ( ( clipRect[2] <= clipRect[0] ) || ( clipRect[3] <= clipRect[1] ) ) { repaint = false; } // set global alpha surface()->DrawSetAlphaMultiplier( newAlphaMultiplier ); bool bBorderPaintFirst = _border ? _border->PaintFirst() : false; // draw the border first if requested to if ( bBorderPaintFirst && repaint && _flags.IsFlagSet( PAINT_BORDER_ENABLED ) && ( _border != null ) ) { // Paint the border over the background with no inset surface()->PushMakeCurrent( vpanel, false ); PaintBorder(); surface()->PopMakeCurrent( vpanel ); } if ( repaint ) { // draw the background with no inset if ( _flags.IsFlagSet( PAINT_BACKGROUND_ENABLED ) ) { surface()->PushMakeCurrent( vpanel, false ); PaintBackground(); surface()->PopMakeCurrent( vpanel ); } // draw the front of the panel with the inset if ( _flags.IsFlagSet( PAINT_ENABLED ) ) { surface()->PushMakeCurrent( vpanel, true ); Paint(); surface()->PopMakeCurrent( vpanel ); } } // traverse and paint all our children CUtlVector< VPANEL > &children = ipanel()->GetChildren( vpanel ); int childCount = children.Count(); for (int i = 0; i < childCount; i++) { VPANEL child = children[ i ]; bool bVisible = ipanel()->IsVisible( child ); if ( surface()->ShouldPaintChildPanel( child ) ) { if ( bVisible ) { ipanel()->PaintTraverse( child, repaint, allowForce ); } } else { // Invalidate the child panel so that it gets redrawn surface()->Invalidate( child ); // keep traversing the tree, just don't allow anyone to paint after here if ( bVisible ) { ipanel()->PaintTraverse( child, false, false ); } } } // draw the border last if ( repaint ) { if ( !bBorderPaintFirst && _flags.IsFlagSet( PAINT_BORDER_ENABLED ) && ( _border != null ) ) { // Paint the border over the background with no inset surface()->PushMakeCurrent( vpanel, false ); PaintBorder(); surface()->PopMakeCurrent( vpanel ); } #ifdef _DEBUG // IsBuildGroupEnabled recurses up all the parents and ends up being very expensive as it wanders all over memory if ( GetBuildModeDialogCount() && IsBuildGroupEnabled() ) //&& HasFocus() ) { // outline all selected panels // outline all selected panels CUtlVector *controlGroup = _buildGroup->GetControlGroup(); for (int i=0; i < controlGroup->Size(); ++i) { surface()->PushMakeCurrent( ((*controlGroup)[i].Get())->GetVPanel(), false ); ((*controlGroup)[i].Get())->PaintBuildOverlay(); surface()->PopMakeCurrent( ((*controlGroup)[i].Get())->GetVPanel() ); } _buildGroup->DrawRulers(); } #endif // All of our children have painted, etc, now allow painting in top of them if ( _flags.IsFlagSet( POST_CHILD_PAINT_ENABLED ) ) { surface()->PushMakeCurrent( vpanel, false ); PostChildPaint(); surface()->PopMakeCurrent( vpanel ); } } surface()->DrawSetAlphaMultiplier( oldAlphaMultiplier ); surface()->SwapBuffers( vpanel ); if( bPushedViewport ) { surface()->PopFullscreenViewport(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::PaintBorder() { _border->Paint(GetVPanel()); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::PaintBackground() { int wide, tall; GetSize( wide, tall ); if ( m_SkipChild.Get() && m_SkipChild->IsVisible() ) { if ( GetPaintBackgroundType() == 2 ) { int cornerWide, cornerTall; GetCornerTextureSize( cornerWide, cornerTall ); Color col = GetBgColor(); DrawHollowBox( 0, 0, wide, tall, col, 1.0f ); wide -= 2 * cornerWide; tall -= 2 * cornerTall; FillRectSkippingPanel( GetBgColor(), cornerWide, cornerTall, wide, tall, m_SkipChild.Get() ); } else { FillRectSkippingPanel( GetBgColor(), 0, 0, wide, tall, m_SkipChild.Get() ); } } else { Color col = GetBgColor(); switch ( m_nPaintBackgroundType ) { default: case 0: { surface()->DrawSetColor(col); surface()->DrawFilledRect(0, 0, wide, tall); } break; case 1: { DrawTexturedBox( 0, 0, wide, tall, col, 1.0f ); } break; case 2: { DrawBox( 0, 0, wide, tall, col, 1.0f ); } break; case 3: { DrawBoxFade( 0, 0, wide, tall, col, 1.0f, 255, 0, true ); } break; } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::Paint() { // empty on purpose // PaintBackground is painted and default behavior is for Paint to do nothing } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::PostChildPaint() { // Empty on purpose // This is called if _postChildPaintEnabled is true and allows painting to // continue on the surface after all of the panel's children have painted // themselves. Allows drawing an overlay on top of the children, etc. } //----------------------------------------------------------------------------- // Purpose: Draws a black rectangle around the panel. //----------------------------------------------------------------------------- void Panel::PaintBuildOverlay() { int wide,tall; GetSize(wide,tall); surface()->DrawSetColor(0, 0, 0, 255); surface()->DrawFilledRect(0,0,wide,2); //top surface()->DrawFilledRect(0,tall-2,wide,tall); //bottom surface()->DrawFilledRect(0,2,2,tall-2); //left surface()->DrawFilledRect(wide-2,2,wide,tall-2); //right } //----------------------------------------------------------------------------- // Purpose: Returns true if the panel's draw code will fully cover it's area //----------------------------------------------------------------------------- bool Panel::IsOpaque() { // FIXME: Add code to account for the 'SkipChild' functionality in Frame if ( IsVisible() && _flags.IsFlagSet( PAINT_BACKGROUND_ENABLED ) && ( _bgColor[3] == 255 ) ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: returns true if the settings are aligned to the right of the screen //----------------------------------------------------------------------------- bool Panel::IsRightAligned() { return (_buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED); } //----------------------------------------------------------------------------- // Purpose: returns true if the settings are aligned to the bottom of the screen //----------------------------------------------------------------------------- bool Panel::IsBottomAligned() { return (_buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED); } //----------------------------------------------------------------------------- // Purpose: sets the parent //----------------------------------------------------------------------------- void Panel::SetParent(Panel *newParent) { // Assert that the parent is from the same module as the child // FIXME: !!! work out how to handle this properly! // Assert(!newParent || !strcmp(newParent->GetModuleName(), GetControlsModuleName())); Panel* pCurrentParent = GetParent(); if ( pCurrentParent ) { pCurrentParent->m_dictChidlren.Remove( GetName() ); } if (newParent) { SetParent(newParent->GetVPanel()); } else { SetParent((VPANEL)NULL); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetParent(VPANEL newParent) { if (newParent) { ipanel()->SetParent(GetVPanel(), newParent); } else { ipanel()->SetParent(GetVPanel(), NULL); } if (GetVParent() && !IsPopup()) { SetProportional(ipanel()->IsProportional(GetVParent())); // most of the time KBInput == parents kbinput if (ipanel()->IsKeyBoardInputEnabled(GetVParent()) != IsKeyBoardInputEnabled()) { SetKeyBoardInputEnabled(ipanel()->IsKeyBoardInputEnabled(GetVParent())); } if (ipanel()->IsMouseInputEnabled(GetVParent()) != IsMouseInputEnabled()) { SetMouseInputEnabled(ipanel()->IsMouseInputEnabled(GetVParent())); } } UpdateSiblingPin(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::OnChildAdded(VPANEL child) { Assert( !_flags.IsFlagSet( IN_PERFORM_LAYOUT ) ); Panel *pChild = ipanel()->GetPanel(child, GetControlsModuleName()); if ( pChild ) { auto idx = m_dictChidlren.Insert( pChild->GetName() ); m_dictChidlren[ idx ].Set( child ); } } //----------------------------------------------------------------------------- // Purpose: default message handler //----------------------------------------------------------------------------- void Panel::OnSizeChanged(int newWide, int newTall) { InvalidateLayout(); // our size changed so force us to layout again } //----------------------------------------------------------------------------- // Purpose: sets Z ordering - lower numbers are always behind higher z's //----------------------------------------------------------------------------- void Panel::SetZPos(int z) { ipanel()->SetZPos(GetVPanel(), z); } //----------------------------------------------------------------------------- // Purpose: sets Z ordering - lower numbers are always behind higher z's //----------------------------------------------------------------------------- int Panel::GetZPos() const { return ( ipanel()->GetZPos( GetVPanel() ) ); } //----------------------------------------------------------------------------- // Purpose: sets alpha modifier for panel and all child panels [0..255] //----------------------------------------------------------------------------- void Panel::SetAlpha(int alpha) { m_flAlpha = alpha; } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- int Panel::GetAlpha() { return (int)m_flAlpha; } //----------------------------------------------------------------------------- // Purpose: Moves the panel to the front of the z-order //----------------------------------------------------------------------------- void Panel::MoveToFront(void) { // FIXME: only use ipanel() as per src branch? if (IsPopup()) { surface()->BringToFront(GetVPanel()); } else { ipanel()->MoveToFront(GetVPanel()); } } //----------------------------------------------------------------------------- // Purpose: Iterates up the hierarchy looking for a particular parent //----------------------------------------------------------------------------- bool Panel::HasParent(VPANEL potentialParent) { if (!potentialParent) return false; return ipanel()->HasParent(GetVPanel(), potentialParent); } //----------------------------------------------------------------------------- // Purpose: Finds the index of a child panel by string name // Output : int - -1 if no panel of that name is found //----------------------------------------------------------------------------- int Panel::FindChildIndexByName(const char *childName) { for (int i = 0; i < GetChildCount(); i++) { Panel *pChild = GetChild(i); if (!pChild) continue; if (!stricmp(pChild->GetName(), childName)) { return i; } } return -1; } //----------------------------------------------------------------------------- // Purpose: Finds a child panel by string name // Output : Panel * - NULL if no panel of that name is found //----------------------------------------------------------------------------- Panel *Panel::FindChildByName(const char *childName, bool recurseDown) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s finding %s", __FUNCTION__, GetName(), childName ); auto idx = m_dictChidlren.Find( childName ); if ( idx != m_dictChidlren.InvalidIndex() ) { Panel *pCachedChild = ipanel()->GetPanel( m_dictChidlren[ idx ], GetControlsModuleName() ); if ( !pCachedChild ) { m_dictChidlren.Remove( childName ); } else { return pCachedChild; } } for (int i = 0; i < GetChildCount(); i++) { Panel *pChild = GetChild(i); if (!pChild) continue; if (!V_stricmp(pChild->GetName(), childName)) { idx = m_dictChidlren.Insert( childName ); m_dictChidlren[ idx ].Set( pChild->GetVPanel() ); return pChild; } if (recurseDown) { Panel *panel = pChild->FindChildByName(childName, recurseDown); if ( panel ) { return panel; } } } m_dictChidlren.Insert( childName ); // Defaults the handle to INVALID_PANEL return NULL; } //----------------------------------------------------------------------------- // Purpose: Finds a sibling panel by name //----------------------------------------------------------------------------- Panel *Panel::FindSiblingByName(const char *siblingName) { if ( !GetVParent() ) return NULL; int siblingCount = ipanel()->GetChildCount(GetVParent()); for (int i = 0; i < siblingCount; i++) { VPANEL sibling = ipanel()->GetChild(GetVParent(), i); Panel *panel = ipanel()->GetPanel(sibling, GetControlsModuleName()); if (!stricmp(panel->GetName(), siblingName)) { return panel; } } return NULL; } //----------------------------------------------------------------------------- // Purpose: Dispatches immediately a message to the parent //----------------------------------------------------------------------------- void Panel::CallParentFunction(KeyValues *message) { if (GetVParent()) { ipanel()->SendMessage(GetVParent(), message, GetVPanel()); } if (message) { message->deleteThis(); } } //----------------------------------------------------------------------------- // Purpose: if set to true, panel automatically frees itself when parent is deleted //----------------------------------------------------------------------------- void Panel::SetAutoDelete( bool state ) { _flags.SetFlag( AUTODELETE_ENABLED, state ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::IsAutoDeleteSet() { return _flags.IsFlagSet( AUTODELETE_ENABLED ); } //----------------------------------------------------------------------------- // Purpose: Just calls 'delete this' //----------------------------------------------------------------------------- void Panel::DeletePanel() { // Avoid re-entrancy _flags.SetFlag( MARKED_FOR_DELETION ); _flags.ClearFlag( AUTODELETE_ENABLED ); delete this; } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- HScheme Panel::GetScheme() { if (m_iScheme) { return m_iScheme; // return our internal scheme } if (GetVParent()) // recurse down the heirarchy { return ipanel()->GetScheme(GetVParent()); } return scheme()->GetDefaultScheme(); } //----------------------------------------------------------------------------- // Purpose: set the scheme to render this panel with by name //----------------------------------------------------------------------------- void Panel::SetScheme(const char *tag) { if (strlen(tag) > 0 && scheme()->GetScheme(tag)) // check the scheme exists { SetScheme(scheme()->GetScheme(tag)); } } //----------------------------------------------------------------------------- // Purpose: set the scheme to render this panel with //----------------------------------------------------------------------------- void Panel::SetScheme(HScheme scheme) { if (scheme != m_iScheme) { m_iScheme = scheme; // This will cause the new scheme to be applied at a later point // InvalidateLayout( false, true ); } } //----------------------------------------------------------------------------- // Purpose: returns the char of this panels hotkey //----------------------------------------------------------------------------- Panel *Panel::HasHotkey(wchar_t key) { return NULL; } #if defined( VGUI_USEDRAGDROP ) static vgui::PHandle g_DragDropCapture; #endif // VGUI_USEDRAGDROP void Panel::InternalCursorMoved(int x, int y) { #if defined( VGUI_USEDRAGDROP ) if ( g_DragDropCapture.Get() ) { bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted; g_DragDropCapture->OnContinueDragging(); if ( started ) { bool isEscapeKeyDown = input()->IsKeyDown( KEY_ESCAPE ); if ( isEscapeKeyDown ) { g_DragDropCapture->OnFinishDragging( true, (MouseCode)-1, true ); } return; } } #endif // VGUI_USEDRAGDROP if ( !ShouldHandleInputMessage() ) return; if ( IsCursorNone() ) return; if ( !IsMouseInputEnabled() ) { return; } if (IsBuildGroupEnabled()) { if ( _buildGroup->CursorMoved(x, y, this) ) { return; } } if (m_pTooltips) { if ( _tooltipText ) { m_pTooltips->SetText( _tooltipText ); } m_pTooltips->ShowTooltip(this); } ScreenToLocal(x, y); OnCursorMoved(x, y); } void Panel::InternalCursorEntered() { if (IsCursorNone() || !IsMouseInputEnabled()) return; if (IsBuildGroupEnabled()) return; if (m_pTooltips) { m_pTooltips->ResetDelay(); if ( _tooltipText ) { m_pTooltips->SetText( _tooltipText ); } m_pTooltips->ShowTooltip(this); } OnCursorEntered(); } void Panel::InternalCursorExited() { if (IsCursorNone() || !IsMouseInputEnabled()) return; if (IsBuildGroupEnabled()) return; if (m_pTooltips) { m_pTooltips->HideTooltip(); } OnCursorExited(); } bool Panel::IsChildOfSurfaceModalPanel() { VPANEL appModalPanel = input()->GetAppModalSurface(); if ( !appModalPanel ) return true; if ( ipanel()->HasParent( GetVPanel(), appModalPanel ) ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsChildOfModalSubTree() { VPANEL subTree = input()->GetModalSubTree(); if ( !subTree ) return true; if ( HasParent( subTree ) ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: Checks to see if message is being subverted due to modal subtree logic // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- static bool ShouldHandleInputMessage( VPANEL p ) { // If there is not modal subtree, then always handle the msg if ( !input()->GetModalSubTree() ) return true; // What state are we in? bool bChildOfModal = false; VPANEL subTree = input()->GetModalSubTree(); if ( !subTree ) { bChildOfModal = true; } else if ( ipanel()->HasParent( p, subTree ) ) { bChildOfModal = true; } if ( input()->ShouldModalSubTreeReceiveMessages() ) return bChildOfModal; return !bChildOfModal; } bool Panel::ShouldHandleInputMessage() { return ::ShouldHandleInputMessage( GetVPanel() ); } void Panel::InternalMousePressed(int code) { long curtime = system()->GetTimeMillis(); if ( IsTriplePressAllowed() ) { long elapsed = curtime - m_lLastDoublePressTime; if ( elapsed < TRIPLE_PRESS_MSEC ) { InternalMouseTriplePressed( code ); return; } } // The menu system passively watches for mouse released messages so it // can clear any open menus if the release is somewhere other than on a menu Menu::OnInternalMousePressed( this, (MouseCode)code ); if ( !ShouldHandleInputMessage() ) return; if ( IsCursorNone() ) return; if ( !IsMouseInputEnabled()) { #if defined( VGUI_USEDRAGDROP ) DragDropStartDragging(); #endif return; } if (IsBuildGroupEnabled()) { if ( _buildGroup->MousePressed((MouseCode)code, this) ) { return; } } #ifdef STAGING_ONLY // If holding CTRL + ALT, invalidate layout. For debugging purposes if ( ( vgui::input()->IsKeyDown(KEY_LCONTROL) || vgui::input()->IsKeyDown(KEY_RCONTROL) ) && ( vgui::input()->IsKeyDown(KEY_LALT) || vgui::input()->IsKeyDown(KEY_RALT) ) ) { InvalidateLayout( true, true ); } #endif #ifdef STAGING_ONLY const char *pGameDir = CommandLine()->ParmValue( "-game", "hl2" ); if ( !V_stricmp( pGameDir, "tf" ) ) { if ( code >= MOUSE_LEFT && code <= MOUSE_MIDDLE ) { m_sMousePressedPanels[ code - MOUSE_LEFT ] = this; } } #endif Panel *pMouseHandler = m_hMouseEventHandler.Get(); if ( pMouseHandler ) { pMouseHandler->OnMousePressed( (MouseCode)code ); } else { OnMousePressed( (MouseCode)code ); } #if defined( VGUI_USEDRAGDROP ) DragDropStartDragging(); #endif } void Panel::InternalMouseDoublePressed(int code) { m_lLastDoublePressTime = system()->GetTimeMillis(); if ( !ShouldHandleInputMessage() ) return; if ( IsCursorNone() ) return; if ( !IsMouseInputEnabled()) { return; } if (IsBuildGroupEnabled()) { if ( _buildGroup->MouseDoublePressed((MouseCode)code, this) ) { return; } } Panel *pMouseHandler = m_hMouseEventHandler.Get(); if ( pMouseHandler ) { pMouseHandler->OnMouseDoublePressed( (MouseCode)code ); } else { OnMouseDoublePressed( (MouseCode)code ); } } #if defined( VGUI_USEDRAGDROP ) void Panel::SetStartDragWhenMouseExitsPanel( bool state ) { _flags.SetFlag( DRAG_REQUIRES_PANEL_EXIT, state ); } bool Panel::IsStartDragWhenMouseExitsPanel() const { return _flags.IsFlagSet( DRAG_REQUIRES_PANEL_EXIT ); } #endif // VGUI_USEDRAGDROP void Panel::SetTriplePressAllowed( bool state ) { _flags.SetFlag( TRIPLE_PRESS_ALLOWED, state ); } bool Panel::IsTriplePressAllowed() const { return _flags.IsFlagSet( TRIPLE_PRESS_ALLOWED ); } void Panel::InternalMouseTriplePressed( int code ) { Assert( IsTriplePressAllowed() ); m_lLastDoublePressTime = 0L; if ( !ShouldHandleInputMessage() ) return; if ( IsCursorNone() ) return; if ( !IsMouseInputEnabled()) { #if defined( VGUI_USEDRAGDROP ) DragDropStartDragging(); #endif return; } if (IsBuildGroupEnabled()) { return; } OnMouseTriplePressed((MouseCode)code); #if defined( VGUI_USEDRAGDROP ) DragDropStartDragging(); #endif } void Panel::InternalMouseReleased(int code) { #if defined( VGUI_USEDRAGDROP ) if ( g_DragDropCapture.Get() ) { bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted; g_DragDropCapture->OnFinishDragging( true, (MouseCode)code ); if ( started ) { return; } } #endif if ( !ShouldHandleInputMessage() ) return; if ( IsCursorNone() ) return; if ( !IsMouseInputEnabled()) { return; } if (IsBuildGroupEnabled()) { if ( _buildGroup->MouseReleased((MouseCode)code, this) ) { return; } } #ifdef STAGING_ONLY const char *pGameDir = CommandLine()->ParmValue( "-game", "hl2" ); if ( tf_strict_mouse_up_events.GetBool() && !V_stricmp( pGameDir, "tf" ) ) { // Only allow mouse release events to go to panels that we also // first clicked into if ( code >= MOUSE_LEFT && code <= MOUSE_MIDDLE ) { const int nIndex = code - MOUSE_LEFT; Panel* pPressedPanel = m_sMousePressedPanels[ nIndex ]; m_sMousePressedPanels[ nIndex ] = NULL; // Clear out pressed panel if ( pPressedPanel != this ) { OnMouseMismatchedRelease( (MouseCode)code, pPressedPanel ); return; } } } #endif OnMouseReleased((MouseCode)code); } void Panel::InternalMouseWheeled(int delta) { if (IsBuildGroupEnabled() || !IsMouseInputEnabled()) { return; } if ( !ShouldHandleInputMessage() ) return; OnMouseWheeled(delta); } void Panel::InternalKeyCodePressed(int code) { if ( !ShouldHandleInputMessage() ) return; if (IsKeyBoardInputEnabled()) { OnKeyCodePressed((KeyCode)code); } else { CallParentFunction(new KeyValues("KeyCodePressed", "code", code)); } } #if defined( VGUI_USEKEYBINDINGMAPS ) //----------------------------------------------------------------------------- // Purpose: // Input : *bindingName - // keycode - // modifiers - //----------------------------------------------------------------------------- void Panel::AddKeyBinding( char const *bindingName, int keycode, int modifiers ) { PanelKeyBindingMap *map = LookupMapForBinding( bindingName ); if ( !map ) { Assert( 0 ); return; } BoundKey_t kb; kb.isbuiltin = false; kb.bindingname = CopyString( bindingName ); kb.keycode = keycode; kb.modifiers = modifiers; map->boundkeys.AddToTail( kb ); } KeyBindingMap_t *Panel::LookupBinding( char const *bindingName ) { PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->entries.Count(); for( int i = 0; i < c ; ++i ) { KeyBindingMap_t *binding = &map->entries[ i ]; if ( !Q_stricmp( binding->bindingname, bindingName ) ) return binding; } map = map->baseMap; } return NULL; } PanelKeyBindingMap *Panel::LookupMapForBinding( char const *bindingName ) { PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->entries.Count(); for( int i = 0; i < c ; ++i ) { KeyBindingMap_t *binding = &map->entries[ i ]; if ( !Q_stricmp( binding->bindingname, bindingName ) ) return map; } map = map->baseMap; } return NULL; } KeyBindingMap_t *Panel::LookupBindingByKeyCode( KeyCode code, int modifiers ) { PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->boundkeys.Count(); for( int i = 0; i < c ; ++i ) { BoundKey_t *kb = &map->boundkeys[ i ]; if ( kb->keycode == code && kb->modifiers == modifiers ) { KeyBindingMap_t *binding = LookupBinding( kb->bindingname ); Assert( binding ); if ( binding ) { return binding; } } } map = map->baseMap; } return NULL; } BoundKey_t *Panel::LookupDefaultKey( char const *bindingName ) { PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->defaultkeys.Count(); for( int i = 0; i < c ; ++i ) { BoundKey_t *kb = &map->defaultkeys[ i ]; if ( !Q_stricmp( kb->bindingname, bindingName ) ) { return kb; } } map = map->baseMap; } return NULL; } void Panel::LookupBoundKeys( char const *bindingName, CUtlVector< BoundKey_t * >& list ) { PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->boundkeys.Count(); for( int i = 0; i < c ; ++i ) { BoundKey_t *kb = &map->boundkeys[ i ]; if ( !Q_stricmp( kb->bindingname, bindingName ) ) { list.AddToTail( kb ); } } map = map->baseMap; } } void Panel::RevertKeyBindingsToDefault() { PanelKeyBindingMap *map = GetKBMap(); while( map ) { map->boundkeys.RemoveAll(); map->boundkeys = map->defaultkeys; map = map->baseMap; } } void Panel::RemoveAllKeyBindings() { PanelKeyBindingMap *map = GetKBMap(); while( map ) { map->boundkeys.RemoveAll(); map = map->baseMap; } } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- void Panel::ReloadKeyBindings() { RevertKeyBindingsToDefault(); LoadKeyBindingsForOnePanel( GetKeyBindingsContext(), this ); } #define MAKE_STRING( x ) #x #define KEY_NAME( str, disp ) { KEY_##str, MAKE_STRING( KEY_##str ), disp } struct KeyNames_t { KeyCode code; char const *string; char const *displaystring; }; static KeyNames_t g_KeyNames[] = { KEY_NAME( NONE, "None" ), KEY_NAME( 0, "0" ), KEY_NAME( 1, "1" ), KEY_NAME( 2, "2" ), KEY_NAME( 3, "3" ), KEY_NAME( 4, "4" ), KEY_NAME( 5, "5" ), KEY_NAME( 6, "6" ), KEY_NAME( 7, "7" ), KEY_NAME( 8, "8" ), KEY_NAME( 9, "9" ), KEY_NAME( A, "A" ), KEY_NAME( B, "B" ), KEY_NAME( C, "C" ), KEY_NAME( D, "D" ), KEY_NAME( E, "E" ), KEY_NAME( F, "F" ), KEY_NAME( G, "G" ), KEY_NAME( H, "H" ), KEY_NAME( I, "I" ), KEY_NAME( J, "J" ), KEY_NAME( K, "K" ), KEY_NAME( L, "L" ), KEY_NAME( M, "M" ), KEY_NAME( N, "N" ), KEY_NAME( O, "O" ), KEY_NAME( P, "P" ), KEY_NAME( Q, "Q" ), KEY_NAME( R, "R" ), KEY_NAME( S, "S" ), KEY_NAME( T, "T" ), KEY_NAME( U, "U" ), KEY_NAME( V, "V" ), KEY_NAME( W, "W" ), KEY_NAME( X, "X" ), KEY_NAME( Y, "Y" ), KEY_NAME( Z, "Z" ), KEY_NAME( PAD_0, "Key Pad 0" ), KEY_NAME( PAD_1, "Key Pad 1" ), KEY_NAME( PAD_2, "Key Pad 2" ), KEY_NAME( PAD_3, "Key Pad 3" ), KEY_NAME( PAD_4, "Key Pad 4" ), KEY_NAME( PAD_5, "Key Pad 5" ), KEY_NAME( PAD_6, "Key Pad 6" ), KEY_NAME( PAD_7, "Key Pad 7" ), KEY_NAME( PAD_8, "Key Pad 8" ), KEY_NAME( PAD_9, "Key Pad 9" ), KEY_NAME( PAD_DIVIDE, "Key Pad /" ), KEY_NAME( PAD_MULTIPLY, "Key Pad *" ), KEY_NAME( PAD_MINUS, "Key Pad -" ), KEY_NAME( PAD_PLUS, "Key Pad +" ), KEY_NAME( PAD_ENTER, "Key Pad Enter" ), KEY_NAME( PAD_DECIMAL, "Key Pad ." ), KEY_NAME( LBRACKET, "[" ), KEY_NAME( RBRACKET, "]" ), KEY_NAME( SEMICOLON, "," ), KEY_NAME( APOSTROPHE, "'" ), KEY_NAME( BACKQUOTE, "`" ), KEY_NAME( COMMA, "," ), KEY_NAME( PERIOD, "." ), KEY_NAME( SLASH, "/" ), KEY_NAME( BACKSLASH, "\\" ), KEY_NAME( MINUS, "-" ), KEY_NAME( EQUAL, "=" ), KEY_NAME( ENTER, "Enter" ), KEY_NAME( SPACE, "Space" ), KEY_NAME( BACKSPACE, "Backspace" ), KEY_NAME( TAB, "Tab" ), KEY_NAME( CAPSLOCK, "Caps Lock" ), KEY_NAME( NUMLOCK, "Num Lock" ), KEY_NAME( ESCAPE, "Escape" ), KEY_NAME( SCROLLLOCK, "Scroll Lock" ), KEY_NAME( INSERT, "Ins" ), KEY_NAME( DELETE, "Del" ), KEY_NAME( HOME, "Home" ), KEY_NAME( END, "End" ), KEY_NAME( PAGEUP, "PgUp" ), KEY_NAME( PAGEDOWN, "PgDn" ), KEY_NAME( BREAK, "Break" ), KEY_NAME( LSHIFT, "Shift" ), KEY_NAME( RSHIFT, "Shift" ), KEY_NAME( LALT, "Alt" ), KEY_NAME( RALT, "Alt" ), KEY_NAME( LCONTROL, "Ctrl" ), KEY_NAME( RCONTROL, "Ctrl" ), KEY_NAME( LWIN, "Windows" ), KEY_NAME( RWIN, "Windows" ), KEY_NAME( APP, "App" ), KEY_NAME( UP, "Up" ), KEY_NAME( LEFT, "Left" ), KEY_NAME( DOWN, "Down" ), KEY_NAME( RIGHT, "Right" ), KEY_NAME( F1, "F1" ), KEY_NAME( F2, "F2" ), KEY_NAME( F3, "F3" ), KEY_NAME( F4, "F4" ), KEY_NAME( F5, "F5" ), KEY_NAME( F6, "F6" ), KEY_NAME( F7, "F7" ), KEY_NAME( F8, "F8" ), KEY_NAME( F9, "F9" ), KEY_NAME( F10, "F10" ), KEY_NAME( F11, "F11" ), KEY_NAME( F12, "F12" ), KEY_NAME( CAPSLOCKTOGGLE, "Caps Lock Toggle" ), KEY_NAME( NUMLOCKTOGGLE, "Num Lock Toggle" ), KEY_NAME( SCROLLLOCKTOGGLE, "Scroll Lock Toggle" ), }; char const *Panel::KeyCodeToString( KeyCode code ) { int c = ARRAYSIZE( g_KeyNames ); for ( int i = 0; i < c ; ++i ) { if ( g_KeyNames[ i ].code == code ) return g_KeyNames[ i ].string; } return ""; } wchar_t const *Panel::KeyCodeToDisplayString( KeyCode code ) { int c = ARRAYSIZE( g_KeyNames ); for ( int i = 0; i < c ; ++i ) { if ( g_KeyNames[ i ].code == code ) { char const *str = g_KeyNames[ i ].displaystring; wchar_t *wstr = g_pVGuiLocalize->Find( str ); if ( wstr ) { return wstr; } static wchar_t buf[ 64 ]; g_pVGuiLocalize->ConvertANSIToUnicode( str, buf, sizeof( buf ) ); return buf; } } return L""; } static void AddModifierToString( char const *modifiername, char *buf, size_t bufsize ) { char add[ 32 ]; if ( Q_strlen( buf ) > 0 ) { Q_snprintf( add, sizeof( add ), "+%s", modifiername ); } else { Q_strncpy( add, modifiername, sizeof( add ) ); } Q_strncat( buf, add, bufsize, COPY_ALL_CHARACTERS ); } wchar_t const *Panel::KeyCodeModifiersToDisplayString( KeyCode code, int modifiers ) { char sz[ 256 ]; sz[ 0 ] = 0; if ( modifiers & MODIFIER_SHIFT ) { AddModifierToString( "Shift", sz, sizeof( sz ) ); } if ( modifiers & MODIFIER_CONTROL ) { AddModifierToString( "Ctrl", sz, sizeof( sz ) ); } if ( modifiers & MODIFIER_ALT ) { AddModifierToString( "Alt", sz, sizeof( sz ) ); } if ( Q_strlen( sz ) > 0 ) { Q_strncat( sz, "+", sizeof( sz ), COPY_ALL_CHARACTERS ); } static wchar_t unicode[ 256 ]; V_swprintf_safe( unicode, L"%S%s", sz, Panel::KeyCodeToDisplayString( (KeyCode)code ) ); return unicode; } KeyCode Panel::StringToKeyCode( char const *str ) { int c = ARRAYSIZE( g_KeyNames ); for ( int i = 0; i < c ; ++i ) { if ( !Q_stricmp( str, g_KeyNames[ i ].string ) ) return g_KeyNames[ i ].code; } return KEY_NONE; } static void WriteKeyBindingToBuffer( CUtlBuffer& buf, int level, const BoundKey_t& binding ) { BufPrint( buf, level, "\"keycode\"\t\"%s\"\n", Panel::KeyCodeToString( (KeyCode)binding.keycode ) ); if ( binding.modifiers & MODIFIER_SHIFT ) { BufPrint( buf, level, "\"shift\"\t\"1\"\n" ); } if ( binding.modifiers & MODIFIER_CONTROL ) { BufPrint( buf, level, "\"ctrl\"\t\"1\"\n" ); } if ( binding.modifiers & MODIFIER_ALT ) { BufPrint( buf, level, "\"alt\"\t\"1\"\n" ); } } //----------------------------------------------------------------------------- // Purpose: // Input : *filename - // *pathID - //----------------------------------------------------------------------------- void Panel::SaveKeyBindingsToBuffer( int level, CUtlBuffer& buf ) { Assert( IsValidKeyBindingsContext() ); Assert( buf.IsText() ); PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->boundkeys.Count(); for( int i = 0; i < c ; ++i ) { const BoundKey_t& binding = map->boundkeys[ i ]; // Spew to file BufPrint( buf, level, "\"%s\"\n", binding.bindingname ); BufPrint( buf, level, "{\n" ); WriteKeyBindingToBuffer( buf, level + 1, binding ); BufPrint( buf, level, "}\n" ); } map = map->baseMap; } } bool Panel::ParseKeyBindings( KeyValues *kv ) { Assert( IsValidKeyBindingsContext() ); if ( !IsValidKeyBindingsContext() ) return false; // To have KB the panel must have a name Assert( GetName() && GetName()[ 0 ] ); if ( !GetName() || !GetName()[ 0 ] ) return false; bool success = false; g_KBMgr.AddPanelToContext( GetKeyBindingsContext(), this ); RemoveAllKeyBindings(); // Walk through bindings for ( KeyValues *binding = kv->GetFirstSubKey(); binding != NULL; binding = binding->GetNextKey() ) { char const *bindingName = binding->GetName(); if ( !bindingName || !bindingName[ 0 ] ) continue; KeyBindingMap_t *b = LookupBinding( bindingName ); if ( b ) { success = true; const char *keycode = binding->GetString( "keycode", "" ); int modifiers = 0; if ( binding->GetInt( "shift", 0 ) != 0 ) { modifiers |= MODIFIER_SHIFT; } if ( binding->GetInt( "ctrl", 0 ) != 0 ) { modifiers |= MODIFIER_CONTROL; } if ( binding->GetInt( "alt", 0 ) != 0 ) { modifiers |= MODIFIER_ALT; } KeyBindingMap_t *bound = LookupBindingByKeyCode( StringToKeyCode( keycode ), modifiers ); if ( !bound ) { AddKeyBinding( bindingName, StringToKeyCode( keycode ), modifiers ); } } else { Warning( "KeyBinding for panel '%s' contained unknown binding '%s'\n", GetName() ? GetName() : "???", bindingName ); } } // Now for each binding which is currently "unbound" to any key, use the default binding PanelKeyBindingMap *map = GetKBMap(); while( map ) { int c = map->entries.Count(); for( int i = 0; i < c ; ++i ) { KeyBindingMap_t *binding = &map->entries[ i ]; // See if there is a bound key CUtlVector< BoundKey_t * > list; LookupBoundKeys( binding->bindingname, list ); if ( list.Count() == 0 ) { // Assign the default binding to this key BoundKey_t *defaultKey = LookupDefaultKey( binding->bindingname ); if ( defaultKey ) { KeyBindingMap_t *alreadyBound = LookupBindingByKeyCode( (KeyCode)defaultKey->keycode, defaultKey->modifiers ); if ( alreadyBound ) { Warning( "No binding for '%s', defautl key already bound to '%s'\n", binding->bindingname, alreadyBound->bindingname ); } else { AddKeyBinding( defaultKey->bindingname, defaultKey->keycode, defaultKey->modifiers ); } } } } map = map->baseMap; } return success; } //----------------------------------------------------------------------------- // Purpose: // Input : handle - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- void Panel::SetKeyBindingsContext( KeyBindingContextHandle_t handle ) { Assert( !IsValidKeyBindingsContext() || handle == GetKeyBindingsContext() ); g_KBMgr.AddPanelToContext( handle, this ); m_hKeyBindingsContext = handle; } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : KeyBindingContextHandle_t //----------------------------------------------------------------------------- KeyBindingContextHandle_t Panel::GetKeyBindingsContext() const { return m_hKeyBindingsContext; } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsValidKeyBindingsContext() const { return GetKeyBindingsContext() != INVALID_KEYBINDINGCONTEXT_HANDLE; } char const *Panel::GetKeyBindingsFile() const { Assert( IsValidKeyBindingsContext() ); return g_KBMgr.GetKeyBindingsFile( GetKeyBindingsContext() ); } char const *Panel::GetKeyBindingsFilePathID() const { Assert( IsValidKeyBindingsContext() ); return g_KBMgr.GetKeyBindingsFilePathID( GetKeyBindingsContext() ); } void Panel::EditKeyBindings() { Assert( 0 ); } //----------------------------------------------------------------------------- // Purpose: Set this to false to disallow IsKeyRebound chaining to GetParent() Panels... // Input : state - //----------------------------------------------------------------------------- void Panel::SetAllowKeyBindingChainToParent( bool state ) { _flags.SetFlag( ALLOW_CHAIN_KEYBINDING_TO_PARENT, state ); } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsKeyBindingChainToParentAllowed() const { return _flags.IsFlagSet( ALLOW_CHAIN_KEYBINDING_TO_PARENT ); } bool Panel::IsKeyOverridden( KeyCode code, int modifiers ) { // By default assume all keys should pass through binding system return false; } bool Panel::IsKeyRebound( KeyCode code, int modifiers ) { if ( IsKeyBoardInputEnabled() ) { KeyBindingMap_t* binding = LookupBindingByKeyCode( code, modifiers ); // Only dispatch if we're part of the current modal subtree if ( binding && IsChildOfSurfaceModalPanel() ) { // Found match, post message to panel if ( binding->func ) { // dispatch the func (this->*binding->func)(); } else { Assert( 0 ); } if ( !binding->passive ) { // Exit this function... return true; } } } // Chain to parent Panel* pParent = GetParent(); if ( IsKeyBindingChainToParentAllowed() && pParent && !IsKeyOverridden( code, modifiers ) ) return pParent->IsKeyRebound( code, modifiers ); // No suitable binding found return false; } static bool s_bSuppressRebindChecks = false; #endif // VGUI_USEKEYBINDINGMAPS void Panel::InternalKeyCodeTyped( int code ) { if ( !ShouldHandleInputMessage() ) { input()->OnKeyCodeUnhandled( code ); return; } if (IsKeyBoardInputEnabled()) { bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT)); bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL)); bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT)); int modifiers = 0; if ( shift ) { modifiers |= MODIFIER_SHIFT; } if ( ctrl ) { modifiers |= MODIFIER_CONTROL; } if ( alt ) { modifiers |= MODIFIER_ALT; } // Things in build mode don't have accelerators if (IsBuildGroupEnabled()) { _buildGroup->KeyCodeTyped((KeyCode)code, this); return; } if ( !s_bSuppressRebindChecks && IsKeyRebound( (KeyCode)code, modifiers ) ) { return; } bool oldVal = s_bSuppressRebindChecks; s_bSuppressRebindChecks = true; OnKeyCodeTyped((KeyCode)code); s_bSuppressRebindChecks = oldVal; } else { if ( GetVPanel() == surface()->GetEmbeddedPanel() ) { input()->OnKeyCodeUnhandled( code ); } CallParentFunction(new KeyValues("KeyCodeTyped", "code", code)); } } void Panel::InternalKeyTyped(int unichar) { if ( !ShouldHandleInputMessage() ) return; if (IsKeyBoardInputEnabled()) { if ( IsBuildGroupEnabled() ) { if ( _buildGroup->KeyTyped( (wchar_t)unichar, this ) ) { return; } } OnKeyTyped((wchar_t)unichar); } else { CallParentFunction(new KeyValues("KeyTyped", "unichar", unichar)); } } void Panel::InternalKeyCodeReleased(int code) { if ( !ShouldHandleInputMessage() ) return; if (IsKeyBoardInputEnabled()) { if (IsBuildGroupEnabled()) { if ( _buildGroup->KeyCodeReleased((KeyCode)code, this) ) { return; } } OnKeyCodeReleased((KeyCode)code); } else { CallParentFunction(new KeyValues("KeyCodeReleased", "code", code)); } } void Panel::InternalKeyFocusTicked() { if (IsBuildGroupEnabled()) return; OnKeyFocusTicked(); } void Panel::InternalMouseFocusTicked() { if (IsBuildGroupEnabled()) { // must repaint so the numbers will be accurate if (_buildGroup->HasRulersOn()) { PaintTraverse(true); } return; } // update cursor InternalSetCursor(); OnMouseFocusTicked(); } void Panel::InternalSetCursor() { bool visible = IsVisible(); if (visible) { #if defined( VGUI_USEDRAGDROP ) // Drag drop is overriding cursor? if ( m_pDragDrop->m_bDragging || g_DragDropCapture.Get() != NULL ) return; #endif // chain up and make sure all our parents are also visible VPANEL p = GetVParent(); while (p) { visible &= ipanel()->IsVisible(p); p = ipanel()->GetParent(p); } // only change the cursor if this panel is visible, and if its part of the main VGUI tree if (visible && HasParent(surface()->GetEmbeddedPanel())) { HCursor cursor = GetCursor(); if (IsBuildGroupEnabled()) { cursor = _buildGroup->GetCursor(this); } if (input()->GetCursorOveride()) { cursor = input()->GetCursorOveride(); } surface()->SetCursor(cursor); } } } //----------------------------------------------------------------------------- // Purpose: Called every frame the panel is visible, designed to be overridden //----------------------------------------------------------------------------- void Panel::OnThink() { #if defined( VGUI_USEDRAGDROP ) if ( IsPC() && m_pDragDrop->m_bDragEnabled && m_pDragDrop->m_bDragging && m_pDragDrop->m_bDragStarted ) { bool isEscapeKeyDown = input()->IsKeyDown( KEY_ESCAPE ); if ( isEscapeKeyDown ) { OnContinueDragging(); OnFinishDragging( true, (MouseCode)-1, true ); return; } if ( m_pDragDrop->m_hCurrentDrop != 0 ) { if ( !input()->IsMouseDown( MOUSE_LEFT ) ) { OnContinueDragging(); OnFinishDragging( true, (MouseCode)-1 ); return; } // allow the cursor to change based upon things like changing keystate, etc. surface()->SetCursor( m_pDragDrop->m_hCurrentDrop->GetDropCursor( m_pDragDrop->m_DragData ) ); if ( !m_pDragDrop->m_bDropMenuShown ) { // See if the hover time has gotten larger float hoverSeconds = ( system()->GetTimeMillis() - m_pDragDrop->m_lDropHoverTime ) * 0.001f; DragDrop_t *dropInfo = m_pDragDrop->m_hCurrentDrop->GetDragDropInfo(); if ( dropInfo->m_flHoverContextTime != 0.0f ) { if ( hoverSeconds >= dropInfo->m_flHoverContextTime ) { m_pDragDrop->m_bDropMenuShown = true; CUtlVector< KeyValues * > data; GetDragData( data ); int x, y; input()->GetCursorPos( x, y ); if ( m_pDragDrop->m_hDropContextMenu.Get() ) { delete m_pDragDrop->m_hDropContextMenu.Get(); } Menu *menu = new Menu( m_pDragDrop->m_hCurrentDrop.Get(), "DropContext" ); bool useMenu = m_pDragDrop->m_hCurrentDrop->GetDropContextMenu( menu, data ); if ( useMenu ) { m_pDragDrop->m_hDropContextMenu = menu; menu->SetPos( x, y ); menu->SetVisible( true ); menu->MakePopup(); surface()->MovePopupToFront( menu->GetVPanel() ); if ( menu->GetItemCount() > 0 ) { int id = menu->GetMenuID( 0 ); menu->SetCurrentlyHighlightedItem( id ); MenuItem *item = menu->GetMenuItem( id ); item->SetArmed( true ); } } else { delete menu; } m_pDragDrop->m_hCurrentDrop->OnDropContextHoverShow( data ); } } } } } #endif } // input messages handlers (designed for override) void Panel::OnCursorMoved(int x, int y) { if( ParentNeedsCursorMoveEvents() ) { // figure out x and y in parent space int thisX, thisY; ipanel()->GetPos( GetVPanel(), thisX, thisY ); CallParentFunction( new KeyValues( "OnCursorMoved", "x", x + thisX, "y", y + thisY ) ); } } void Panel::OnCursorEntered() { } void Panel::OnCursorExited() { } void Panel::OnMousePressed(MouseCode code) { } void Panel::OnMouseDoublePressed(MouseCode code) { } void Panel::OnMouseTriplePressed(MouseCode code) { } void Panel::OnMouseReleased(MouseCode code) { } void Panel::OnMouseMismatchedRelease( MouseCode code, Panel* pPressedPanel ) { } void Panel::OnMouseWheeled(int delta) { CallParentFunction(new KeyValues("MouseWheeled", "delta", delta)); } // base implementation forwards Key messages to the Panel's parent - override to 'swallow' the input void Panel::OnKeyCodePressed(KeyCode code) { static ConVarRef vgui_nav_lock( "vgui_nav_lock" ); bool handled = false; switch( GetBaseButtonCode( code ) ) { case KEY_XBUTTON_UP: case KEY_XSTICK1_UP: case KEY_XSTICK2_UP: case KEY_UP: case STEAMCONTROLLER_DPAD_UP: if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateUp() ) { vgui_nav_lock.SetValue( 1 ); vgui::surface()->PlaySound( "UI/menu_focus.wav" ); handled = true; } break; case KEY_XBUTTON_DOWN: case KEY_XSTICK1_DOWN: case KEY_XSTICK2_DOWN: case KEY_DOWN: case STEAMCONTROLLER_DPAD_DOWN: if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateDown() ) { vgui_nav_lock.SetValue( 1 ); vgui::surface()->PlaySound( "UI/menu_focus.wav" ); handled = true; } break; case KEY_XBUTTON_LEFT: case KEY_XSTICK1_LEFT: case KEY_XSTICK2_LEFT: case KEY_LEFT: case STEAMCONTROLLER_DPAD_LEFT: if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateLeft() ) { vgui_nav_lock.SetValue( 1 ); vgui::surface()->PlaySound( "UI/menu_focus.wav" ); handled = true; } break; case KEY_XBUTTON_RIGHT: case KEY_XSTICK1_RIGHT: case KEY_XSTICK2_RIGHT: case KEY_RIGHT: case STEAMCONTROLLER_DPAD_RIGHT: if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateRight() ) { vgui_nav_lock.SetValue( 1 ); vgui::surface()->PlaySound( "UI/menu_focus.wav" ); handled = true; } break; case KEY_XBUTTON_B: case STEAMCONTROLLER_B: if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateBack() ) { vgui_nav_lock.SetValue( 1 ); vgui::surface()->PlaySound( "UI/menu_focus.wav" ); handled = true; } break; } if( !handled && !m_PassUnhandledInput ) return; CallParentFunction(new KeyValues("KeyCodePressed", "code", code)); } void Panel::OnKeyCodeTyped(KeyCode keycode) { vgui::KeyCode code = GetBaseButtonCode( keycode ); // handle focus change if ( IsX360() || IsConsoleStylePanel() ) { // eat these typed codes, will get handled in OnKeyCodePressed switch ( code ) { case KEY_XBUTTON_UP: case KEY_XSTICK1_UP: case KEY_XSTICK2_UP: case KEY_XBUTTON_DOWN: case KEY_XSTICK1_DOWN: case KEY_XSTICK2_DOWN: case KEY_XBUTTON_LEFT: case KEY_XSTICK1_LEFT: case KEY_XSTICK2_LEFT: case KEY_XBUTTON_RIGHT: case KEY_XSTICK1_RIGHT: case KEY_XSTICK2_RIGHT: case KEY_XBUTTON_A: case KEY_XBUTTON_B: case KEY_XBUTTON_X: case KEY_XBUTTON_Y: case KEY_XBUTTON_LEFT_SHOULDER: case KEY_XBUTTON_RIGHT_SHOULDER: case KEY_XBUTTON_BACK: case KEY_XBUTTON_START: case KEY_XBUTTON_STICK1: case KEY_XBUTTON_STICK2: case KEY_XBUTTON_LTRIGGER: case KEY_XBUTTON_RTRIGGER: case STEAMCONTROLLER_A: case STEAMCONTROLLER_B: case KEY_UP: case KEY_DOWN: case KEY_LEFT: case KEY_RIGHT: case STEAMCONTROLLER_DPAD_UP: case STEAMCONTROLLER_DPAD_DOWN: case STEAMCONTROLLER_DPAD_LEFT: case STEAMCONTROLLER_DPAD_RIGHT: return; } // legacy handling - need to re-enable for older apps? /* if ( code == KEY_XSTICK1_RIGHT || code == KEY_XBUTTON_RIGHT ) { RequestFocusNext(); return; } else if ( code == KEY_XSTICK1_LEFT || code == KEY_XBUTTON_LEFT ) { RequestFocusPrev(); return; } */ } if (code == KEY_TAB) { bool bShiftDown = input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT); if ( IsConsoleStylePanel() ) { if ( bShiftDown ) { NavigateUp(); } else { NavigateDown(); } } else { // if shift is down goto previous tab position, otherwise goto next if ( bShiftDown ) { RequestFocusPrev(); } else { RequestFocusNext(); } } } else { // forward up if ( GetVPanel() == surface()->GetEmbeddedPanel() ) { input()->OnKeyCodeUnhandled( keycode ); } CallParentFunction(new KeyValues("KeyCodeTyped", "code", keycode)); } } void Panel::OnKeyTyped(wchar_t unichar) { CallParentFunction(new KeyValues("KeyTyped", "unichar", unichar)); } void Panel::OnKeyCodeReleased(KeyCode code) { CallParentFunction(new KeyValues("KeyCodeReleased", "code", code)); } void Panel::OnKeyFocusTicked() { CallParentFunction(new KeyValues("KeyFocusTicked")); } void Panel::OnMouseFocusTicked() { CallParentFunction(new KeyValues("OnMouseFocusTicked")); } bool Panel::IsWithin(int x,int y) { // check against our clip rect int clipRect[4]; ipanel()->GetClipRect(GetVPanel(), clipRect[0], clipRect[1], clipRect[2], clipRect[3]); if (x < clipRect[0]) { return false; } if (y < clipRect[1]) { return false; } if (x >= clipRect[2]) { return false; } if (y >= clipRect[3]) { return false; } return true; } //----------------------------------------------------------------------------- // Purpose: determines which is the topmost panel under the coordinates (x, y) //----------------------------------------------------------------------------- VPANEL Panel::IsWithinTraverse(int x, int y, bool traversePopups) { // if this one is not visible, its children won't be either // also if it doesn't want mouse input its children can't get it either if (!IsVisible() || !IsMouseInputEnabled()) return NULL; if (traversePopups) { // check popups first int i; CUtlVector< VPANEL > &children = ipanel()->GetChildren( GetVPanel() ); int childCount = children.Count(); for (i = childCount - 1; i >= 0; i--) { VPANEL panel = children[ i ]; if (ipanel()->IsPopup(panel)) { panel = ipanel()->IsWithinTraverse(panel, x, y, true); if (panel != null) { return panel; } } } // check children recursive, if you find one, just return first one // this checks in backwards order so the last child drawn for this panel is chosen which // coincides to how it would be visibly displayed for (i = childCount - 1; i >= 0; i--) { VPANEL panel = children[ i ]; // we've already checked popups so ignore if (!ipanel()->IsPopup(panel)) { panel = ipanel()->IsWithinTraverse(panel, x, y, true); if (panel != 0) { return panel; } } } // check ourself if ( !IsMouseInputDisabledForThisPanel() && IsWithin(x, y) ) { return GetVPanel(); } } else { // since we're not checking popups, it must be within us, so we can check ourself first if (IsWithin(x, y)) { // check children recursive, if you find one, just return first one // this checks in backwards order so the last child drawn for this panel is chosen which // coincides to how it would be visibly displayed CUtlVector< VPANEL > &children = ipanel()->GetChildren( GetVPanel() ); int childCount = children.Count(); for (int i = childCount - 1; i >= 0; i--) { VPANEL panel = children[ i ]; // ignore popups if (!ipanel()->IsPopup(panel)) { panel = ipanel()->IsWithinTraverse(panel, x, y, false); if (panel != 0) { return panel; } } } // not a child, must be us if ( !IsMouseInputDisabledForThisPanel() ) return GetVPanel(); } } return NULL; } void Panel::LocalToScreen(int& x,int& y) { int px, py; ipanel()->GetAbsPos(GetVPanel(), px, py); x = x + px; y = y + py; } void Panel::ScreenToLocal(int& x,int& y) { int px, py; ipanel()->GetAbsPos(GetVPanel(), px, py); x = x - px; y = y - py; } void Panel::ParentLocalToScreen(int &x, int &y) { int px, py; ipanel()->GetAbsPos(GetVParent(), px, py); x = x + px; y = y + py; } void Panel::MakePopup(bool showTaskbarIcon,bool disabled) { surface()->CreatePopup(GetVPanel(), false, showTaskbarIcon,disabled); } void Panel::SetCursor(HCursor cursor) { _cursor = cursor; } HCursor Panel::GetCursor() { return _cursor; } void Panel::SetCursorAlwaysVisible( bool visible ) { surface()->SetCursorAlwaysVisible( visible ); } void Panel::SetMinimumSize(int wide,int tall) { ipanel()->SetMinimumSize(GetVPanel(), wide, tall); } void Panel::GetMinimumSize(int& wide,int &tall) { ipanel()->GetMinimumSize(GetVPanel(), wide, tall); } bool Panel::IsBuildModeEditable() { return true; } void Panel::SetBuildModeEditable(bool state) { if (state) { _buildModeFlags |= BUILDMODE_EDITABLE; } else { _buildModeFlags &= ~BUILDMODE_EDITABLE; } } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- bool Panel::IsBuildModeDeletable() { return (_buildModeFlags & BUILDMODE_DELETABLE); } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- void Panel::SetBuildModeDeletable(bool state) { if (state) { _buildModeFlags |= BUILDMODE_DELETABLE; } else { _buildModeFlags &= ~BUILDMODE_DELETABLE; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::IsBuildModeActive() { return _buildGroup ? _buildGroup->IsEnabled() : false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::GetClipRect(int& x0,int& y0,int& x1,int& y1) { ipanel()->GetClipRect(GetVPanel(), x0, y0, x1, y1); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int Panel::GetChildCount() { if (ipanel()) { return ipanel()->GetChildCount(GetVPanel()); } return 0; } //----------------------------------------------------------------------------- // Purpose: returns a child by the specified index //----------------------------------------------------------------------------- Panel *Panel::GetChild(int index) { // get the child and cast it to a panel // this assumes that the child is from the same module as the this (precondition) return ipanel()->GetPanel(ipanel()->GetChild(GetVPanel(), index), GetControlsModuleName()); } CUtlVector< VPANEL > &Panel::GetChildren() { return ipanel()->GetChildren(GetVPanel()); } //----------------------------------------------------------------------------- // Purpose: moves the key focus back //----------------------------------------------------------------------------- bool Panel::RequestFocusPrev(VPANEL panel) { // chain to parent if (GetVParent()) { return ipanel()->RequestFocusPrev(GetVParent(), GetVPanel()); } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool Panel::RequestFocusNext(VPANEL panel) { // chain to parent if (GetVParent()) { return ipanel()->RequestFocusNext(GetVParent(), GetVPanel()); } return false; } //----------------------------------------------------------------------------- // Purpose: Sets the panel to have the current sub focus // Input : direction - the direction in which focus travelled to arrive at this panel; forward = 1, back = -1 //----------------------------------------------------------------------------- void Panel::RequestFocus(int direction) { // NOTE: This doesn't make any sense if we don't have keyboard input enabled // NOTE: Well, maybe it does if you have a steam controller... // Assert( ( IsX360() || IsConsoleStylePanel() ) || IsKeyBoardInputEnabled() ); // ivgui()->DPrintf2("RequestFocus(%s, %s)\n", GetName(), GetClassName()); OnRequestFocus(GetVPanel(), NULL); } //----------------------------------------------------------------------------- // Purpose: Called after a panel requests focus to fix up the whole chain //----------------------------------------------------------------------------- void Panel::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel) { CallParentFunction(new KeyValues("OnRequestFocus", "subFocus", subFocus, "defaultPanel", defaultPanel)); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- VPANEL Panel::GetCurrentKeyFocus() { return NULL; } //----------------------------------------------------------------------------- // Purpose: returns true if the panel has focus //----------------------------------------------------------------------------- bool Panel::HasFocus() { if (input()->GetFocus() == GetVPanel()) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetTabPosition(int position) { _tabPosition = position; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int Panel::GetTabPosition() { return _tabPosition; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::InternalFocusChanged(bool lost) { /* //if focus is gained tell the focusNavGroup about it so its current can be correct if( (!lost) && (_focusNavGroup!=null) ) { _focusNavGroup->setCurrentPanel(this); } */ } //----------------------------------------------------------------------------- // Purpose: Called when a panel loses it's mouse capture //----------------------------------------------------------------------------- void Panel::OnMouseCaptureLost() { if (m_pTooltips) { m_pTooltips->ResetDelay(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::AddActionSignalTarget(Panel *messageTarget) { HPanel target = ivgui()->PanelToHandle(messageTarget->GetVPanel()); if (!_actionSignalTargetDar.HasElement(target)) { _actionSignalTargetDar.AddElement(target); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::AddActionSignalTarget(VPANEL messageTarget) { HPanel target = ivgui()->PanelToHandle(messageTarget); if (!_actionSignalTargetDar.HasElement(target)) { _actionSignalTargetDar.AddElement(target); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::RemoveActionSignalTarget(Panel *oldTarget) { _actionSignalTargetDar.RemoveElement(ivgui()->PanelToHandle(oldTarget->GetVPanel())); } //----------------------------------------------------------------------------- // Purpose: Sends a message to all the panels that have requested action signals //----------------------------------------------------------------------------- void Panel::PostActionSignal( KeyValues *message ) { if ( m_bIsSilent != true ) { // add who it was from the message message->SetPtr("panel", this); int i; for (i = _actionSignalTargetDar.GetCount() - 1; i > 0; i--) { VPANEL panel = ivgui()->HandleToPanel(_actionSignalTargetDar[i]); if (panel) { ivgui()->PostMessage(panel, message->MakeCopy(), GetVPanel()); } } // do this so we can save on one MakeCopy() call if (i == 0) { VPANEL panel = ivgui()->HandleToPanel(_actionSignalTargetDar[i]); if (panel) { ivgui()->PostMessage(panel, message, GetVPanel()); return; } } } message->deleteThis(); } void Panel::SetBorder(IBorder *border) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() ); _border = border; if (border) { int x, y, x2, y2; border->GetInset(x, y, x2, y2); ipanel()->SetInset(GetVPanel(), x, y, x2, y2); // update our background type based on the bord SetPaintBackgroundType(border->GetBackgroundType()); } else { ipanel()->SetInset(GetVPanel(), 0, 0, 0, 0); } } IBorder *Panel::GetBorder() { return _border; } void Panel::SetPaintBorderEnabled(bool state) { _flags.SetFlag( PAINT_BORDER_ENABLED, state ); } void Panel::SetPaintBackgroundEnabled(bool state) { _flags.SetFlag( PAINT_BACKGROUND_ENABLED, state ); } void Panel::SetPaintBackgroundType( int type ) { // HACK only 0 through 2 supported for now m_nPaintBackgroundType = clamp( type, 0, 2 ); } void Panel::SetPaintEnabled(bool state) { _flags.SetFlag( PAINT_ENABLED, state ); } void Panel::SetPostChildPaintEnabled(bool state) { _flags.SetFlag( POST_CHILD_PAINT_ENABLED, state ); } void Panel::GetInset(int& left,int& top,int& right,int& bottom) { ipanel()->GetInset(GetVPanel(), left, top, right, bottom); } void Panel::GetPaintSize(int& wide,int& tall) { GetSize(wide, tall); if (_border != null) { int left,top,right,bottom; _border->GetInset(left,top,right,bottom); wide -= (left+right); tall -= (top+bottom); } } int Panel::GetWide() { int wide, tall; ipanel()->GetSize(GetVPanel(), wide, tall); return wide; } void Panel::SetWide(int wide) { ipanel()->SetSize(GetVPanel(), wide, GetTall()); } int Panel::GetTall() { int wide, tall; ipanel()->GetSize(GetVPanel(), wide, tall); return tall; } void Panel::SetTall(int tall) { ipanel()->SetSize(GetVPanel(), GetWide(), tall); } void Panel::SetBuildGroup(BuildGroup* buildGroup) { //TODO: remove from old group Assert(buildGroup != NULL); _buildGroup = buildGroup; _buildGroup->PanelAdded(this); } bool Panel::IsBuildGroupEnabled() { if ( !_buildGroup.IsValid() ) return false; bool enabled = _buildGroup->IsEnabled(); if ( enabled ) return enabled; if ( GetParent() && GetParent()->IsBuildGroupEnabled() ) return true; return false; } void Panel::SetBgColor(Color color) { _bgColor = color; } void Panel::SetFgColor(Color color) { _fgColor = color; } Color Panel::GetBgColor() { return _bgColor; } Color Panel::GetFgColor() { return _fgColor; } void Panel::InternalPerformLayout() { // Don't layout if we're still waiting for our scheme to be applied. // At worst, it leads to crashes, at best it does work that we'll redo as soon as the scheme has been applied. if ( _flags.IsFlagSet( NEEDS_SCHEME_UPDATE ) ) return; _flags.SetFlag( IN_PERFORM_LAYOUT ); // make sure the scheme has been applied _flags.ClearFlag( NEEDS_LAYOUT ); PerformLayout(); _flags.ClearFlag( IN_PERFORM_LAYOUT ); } void Panel::PerformLayout() { // this should be overridden to relayout controls } void Panel::InvalidateLayout( bool layoutNow, bool reloadScheme ) { _flags.SetFlag( NEEDS_LAYOUT ); if (reloadScheme) { // make all our children reload the scheme _flags.SetFlag( NEEDS_SCHEME_UPDATE ); for (int i = 0; i < GetChildCount(); i++) { vgui::Panel* panel = GetChild(i); if( panel ) { panel->InvalidateLayout(layoutNow, true); } } PerformApplySchemeSettings(); } if (layoutNow) { InternalPerformLayout(); Repaint(); } } bool Panel::IsCursorNone() { HCursor cursor = GetCursor(); if (!cursor) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: returns true if the cursor is currently over the panel // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsCursorOver(void) { int x, y; input()->GetCursorPos(x, y); return IsWithin(x, y); } //----------------------------------------------------------------------------- // Purpose: Called when a panel receives a command message from another panel //----------------------------------------------------------------------------- void Panel::OnCommand(const char *command) { if ( !Q_stricmp( "performlayout", command ) ) { InvalidateLayout(); } else if ( !Q_stricmp( "reloadscheme", command ) ) { InvalidateLayout( false, true ); } else { // if noone else caught this, pass along to the listeners // (this is useful for generic dialogs - otherwise, commands just get ignored) KeyValues *msg = new KeyValues( command ); PostActionSignal( msg ); } } //----------------------------------------------------------------------------- // Purpose: panel gained focus message //----------------------------------------------------------------------------- void Panel::OnSetFocus() { Repaint(); } //----------------------------------------------------------------------------- // Purpose: panel lost focus message //----------------------------------------------------------------------------- void Panel::OnKillFocus() { Repaint(); } //----------------------------------------------------------------------------- // Purpose: Sets the object up to be deleted next frame //----------------------------------------------------------------------------- void Panel::MarkForDeletion() { if ( _flags.IsFlagSet( MARKED_FOR_DELETION ) ) return; _flags.SetFlag( MARKED_FOR_DELETION ); _flags.ClearFlag( AUTODELETE_ENABLED ); if (ivgui()->IsRunning()) { ivgui()->MarkPanelForDeletion(GetVPanel()); } // direct delete is never safe because even if ivgui is shutdown we manually do RunFrame() // and we can enter here in a think traverse and then delete from underneath ourselves /*else { delete this; }*/ } //----------------------------------------------------------------------------- // Purpose: return true if this object require a perform layout //----------------------------------------------------------------------------- bool Panel::IsLayoutInvalid() { return _flags.IsFlagSet( NEEDS_LAYOUT ); } //----------------------------------------------------------------------------- // Sets the pin corner + resize mode for resizing panels //----------------------------------------------------------------------------- void Panel::SetAutoResize( PinCorner_e pinCorner, AutoResize_e resizeDir, int nPinOffsetX, int nPinOffsetY, int nUnpinnedCornerOffsetX, int nUnpinnedCornerOffsetY ) { _pinCorner = pinCorner; _autoResizeDirection = resizeDir; m_nPinDeltaX = nPinOffsetX; m_nPinDeltaY = nPinOffsetY; m_nResizeDeltaX = nUnpinnedCornerOffsetX; m_nResizeDeltaY = nUnpinnedCornerOffsetY; } //----------------------------------------------------------------------------- // Sets the pin corner for non-resizing panels //----------------------------------------------------------------------------- void Panel::SetPinCorner( PinCorner_e pinCorner, int nOffsetX, int nOffsetY ) { _pinCorner = pinCorner; _autoResizeDirection = AUTORESIZE_NO; m_nPinDeltaX = nOffsetX; m_nPinDeltaY = nOffsetY; m_nResizeDeltaX = 0; m_nResizeDeltaY = 0; } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- Panel::PinCorner_e Panel::GetPinCorner() { return (PinCorner_e)_pinCorner; } //----------------------------------------------------------------------------- // Gets the relative offset of the control from the pin corner //----------------------------------------------------------------------------- void Panel::GetPinOffset( int &dx, int &dy ) { dx = m_nPinDeltaX; dy = m_nPinDeltaY; } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- Panel::AutoResize_e Panel::GetAutoResize() { return (AutoResize_e)_autoResizeDirection; } //----------------------------------------------------------------------------- // Gets the relative offset of the control from the pin corner //----------------------------------------------------------------------------- void Panel::GetResizeOffset( int &dx, int &dy ) { dx = m_nResizeDeltaX; dy = m_nResizeDeltaY; } //----------------------------------------------------------------------------- // Tells this panel that it should pin itself to the corner of a specified sibling panel //----------------------------------------------------------------------------- void Panel::PinToSibling( const char *pszSibling, PinCorner_e pinOurCorner, PinCorner_e pinSibling ) { _pinCornerToSibling = pinOurCorner; _pinToSiblingCorner = pinSibling; if ( m_pinSibling.Get() && _pinToSibling && pszSibling && !Q_strcmp( _pinToSibling, pszSibling ) ) return; if (_pinToSibling) { delete [] _pinToSibling; _pinToSibling = NULL; } if (pszSibling) { int len = Q_strlen(pszSibling) + 1; _pinToSibling = new char[ len ]; Q_strncpy( _pinToSibling, pszSibling, len ); } m_pinSibling = NULL; UpdateSiblingPin(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::UpdateSiblingPin( void ) { if ( !_pinToSibling ) { ipanel()->SetSiblingPin(GetVPanel(), NULL); return; } if ( !m_pinSibling.Get() ) { // Resolve our sibling now m_pinSibling = FindSiblingByName( _pinToSibling ); } if ( m_pinSibling.Get() ) { ipanel()->SetSiblingPin( GetVPanel(), m_pinSibling->GetVPanel(), _pinCornerToSibling, _pinToSiblingCorner ); } else { ipanel()->SetSiblingPin(GetVPanel(), NULL); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::ApplySchemeSettings(IScheme *pScheme) { // get colors SetFgColor(GetSchemeColor("Panel.FgColor", pScheme)); SetBgColor(GetSchemeColor("Panel.BgColor", pScheme)); #if defined( VGUI_USEDRAGDROP ) m_clrDragFrame = pScheme->GetColor("DragDrop.DragFrame", Color(255, 255, 255, 192)); m_clrDropFrame = pScheme->GetColor("DragDrop.DropFrame", Color(150, 255, 150, 255)); m_infoFont = pScheme->GetFont( "DefaultVerySmall" ); #endif // mark us as no longer needing scheme settings applied _flags.ClearFlag( NEEDS_SCHEME_UPDATE ); if ( IsBuildGroupEnabled() ) { _buildGroup->ApplySchemeSettings(pScheme); return; } } //----------------------------------------------------------------------------- // Purpose: Checks to see if the panel needs it's scheme info setup //----------------------------------------------------------------------------- void Panel::PerformApplySchemeSettings() { if ( _flags.IsFlagSet( NEEDS_DEFAULT_SETTINGS_APPLIED ) ) { InternalInitDefaultValues( GetAnimMap() ); } if ( _flags.IsFlagSet( NEEDS_SCHEME_UPDATE ) ) { VPROF( "ApplySchemeSettings" ); IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); AssertOnce( pScheme ); if ( pScheme ) // this should NEVER be null, but if it is bad things would happen in ApplySchemeSettings... { ApplySchemeSettings( pScheme ); //_needsSchemeUpdate = false; ApplyOverridableColors(); UpdateSiblingPin(); } } } //----------------------------------------------------------------------------- // Purpose: Loads panel details related to autoresize from the resource info //----------------------------------------------------------------------------- #if defined( _DEBUG ) static Panel *lastWarningParent = 0; #endif void Panel::ApplyAutoResizeSettings(KeyValues *inResourceData) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() ); int x, y; GetPos(x, y); int wide, tall; GetSize( wide, tall ); AutoResize_e autoResize = (AutoResize_e)inResourceData->GetInt( "AutoResize", AUTORESIZE_NO ); PinCorner_e pinCorner = (PinCorner_e)inResourceData->GetInt( "PinCorner", PIN_TOPLEFT ); // By default, measure unpinned corner for the offset int pw = wide, pt = tall; if ( GetParent() ) { GetParent()->GetSize( pw, pt ); #if defined( _DEBUG ) if ( pw == 64 && pt == 24 ) { if ( GetParent() != lastWarningParent ) { lastWarningParent = GetParent(); Warning( "Resize parent (panel(%s) -> parent(%s)) not sized yet!!!\n", GetName(), GetParent()->GetName() ); } } #endif } int nPinnedCornerOffsetX = 0, nPinnedCornerOffsetY = 0; int nUnpinnedCornerOffsetX = 0, nUnpinnedCornerOffsetY = 0; switch( pinCorner ) { case PIN_TOPLEFT: nPinnedCornerOffsetX = x; nPinnedCornerOffsetY = y; nUnpinnedCornerOffsetX = (x + wide) - pw; nUnpinnedCornerOffsetY = (y + tall) - pt; break; case PIN_TOPRIGHT: nPinnedCornerOffsetX = (x + wide) - pw; nPinnedCornerOffsetY = y; nUnpinnedCornerOffsetX = x; nUnpinnedCornerOffsetY = (y + tall) - pt; break; case PIN_BOTTOMLEFT: nPinnedCornerOffsetX = x; nPinnedCornerOffsetY = (y + tall) - pt; nUnpinnedCornerOffsetX = (x + wide) - pw; nUnpinnedCornerOffsetY = y; break; case PIN_BOTTOMRIGHT: nPinnedCornerOffsetX = (x + wide) - pw; nPinnedCornerOffsetY = (y + tall) - pt; nUnpinnedCornerOffsetX = x; nUnpinnedCornerOffsetY = y; break; } // Allow specific overrides in the resource file if ( IsProportional() ) { if ( inResourceData->FindKey( "PinnedCornerOffsetX" ) ) { nPinnedCornerOffsetX = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "PinnedCornerOffsetX" ) ); } if ( inResourceData->FindKey( "PinnedCornerOffsetY" ) ) { nPinnedCornerOffsetY = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "PinnedCornerOffsetY" ) ); } if ( inResourceData->FindKey( "UnpinnedCornerOffsetX" ) ) { nUnpinnedCornerOffsetX = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "UnpinnedCornerOffsetX" ) ); } if ( inResourceData->FindKey( "UnpinnedCornerOffsetY" ) ) { nUnpinnedCornerOffsetY = scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "UnpinnedCornerOffsetY" ) ); } } else { nPinnedCornerOffsetX = inResourceData->GetInt( "PinnedCornerOffsetX", nPinnedCornerOffsetX ); nPinnedCornerOffsetY = inResourceData->GetInt( "PinnedCornerOffsetY", nPinnedCornerOffsetY ); nUnpinnedCornerOffsetX = inResourceData->GetInt( "UnpinnedCornerOffsetX", nUnpinnedCornerOffsetX ); nUnpinnedCornerOffsetY = inResourceData->GetInt( "UnpinnedCornerOffsetY", nUnpinnedCornerOffsetY ); } if ( autoResize == AUTORESIZE_NO ) { nUnpinnedCornerOffsetX = nUnpinnedCornerOffsetY = 0; } SetAutoResize( pinCorner, autoResize, nPinnedCornerOffsetX, nPinnedCornerOffsetY, nUnpinnedCornerOffsetX, nUnpinnedCornerOffsetY ); } ConVar panel_test_title_safe( "panel_test_title_safe", "0", FCVAR_CHEAT, "Test vgui panel positioning with title safe indentation" ); Panel::PinCorner_e GetPinCornerFromString( const char* pszCornerName ) { if ( pszCornerName == NULL ) { return Panel::PIN_TOPLEFT; } // Optimize for all the old entries of a single digit if ( strlen( pszCornerName ) == 1 ) { return (Panel::PinCorner_e)atoi( pszCornerName ); } for( int i=0; iGetScreenSize( alignScreenWide, alignScreenTall ); int screenWide = alignScreenWide; int screenTall = alignScreenTall; // temporarily remove the override to get the fullscreen dimensions if ( surface()->IsScreenSizeOverrideActive() ) { surface()->ForceScreenSizeOverride( false, 0, 0 ); surface()->GetScreenSize( screenWide, screenTall ); // restore the override surface()->ForceScreenSizeOverride( true, alignScreenWide, alignScreenTall ); } int parentX = 0; int parentY = 0; // flag to cause windows to get screenWide and screenTall from their parents, // this allows children windows to use fill and right/bottom alignment even // if their parent does not use the full screen. if ( inResourceData->GetInt( "proportionalToParent", 0 ) == 1 ) { _buildModeFlags |= BUILDMODE_SAVE_PROPORTIONAL_TO_PARENT; if ( GetParent() != NULL ) { GetParent()->GetBounds( parentX, parentY, alignScreenWide, alignScreenTall ); } } // size int wide = ComputeWide( this, _buildModeFlags, inResourceData, alignScreenWide, alignScreenTall, false ); int tall = ComputeTall( this, _buildModeFlags, inResourceData, alignScreenWide, alignScreenTall, false ); int x, y; GetPos(x, y); const char *xstr = inResourceData->GetString( "xpos", NULL ); const char *ystr = inResourceData->GetString( "ypos", NULL ); _buildModeFlags |= ComputePos( this, xstr, x, wide, alignScreenWide, true, OP_SET ); _buildModeFlags |= ComputePos( this, ystr, y, tall, alignScreenTall, false, OP_SET ); bool bUsesTitleSafeArea = false; int titleSafeWide = 0; int titleSafeTall = 0; Rect_t excludeEdgeFromTitleSafe; // if a side is set to != 0, don't title safe relative to that edge excludeEdgeFromTitleSafe.x = 0; excludeEdgeFromTitleSafe.y = 0; excludeEdgeFromTitleSafe.width = 0; excludeEdgeFromTitleSafe.height = 0; if ( IsX360() || panel_test_title_safe.GetBool() ) { // "usetitlesafe" "1" - required inner 90% // "usetitlesafe" "2" - suggested inner 85% int iUseTitleSafeValue = 0; if ( inResourceData->FindKey( "usetitlesafe" ) ) { iUseTitleSafeValue = inResourceData->GetInt( "usetitlesafe" ); bUsesTitleSafeArea = ( iUseTitleSafeValue > 0 ); } if( bUsesTitleSafeArea ) { titleSafeWide = screenWide * ( iUseTitleSafeValue == 1 ? 0.05f : 0.075f ); titleSafeTall = screenTall * ( iUseTitleSafeValue == 1 ? 0.05f : 0.075f ); // Don't title safe internal boundaries for split screen viewports int splitX = 0; int splitY = 0; vgui::surface()->OffsetAbsPos( splitX, splitY ); bool bHorizontalSplit = ( alignScreenTall != screenTall ); bool bVerticalSplit = ( alignScreenWide != screenWide ); if ( bHorizontalSplit ) { // top or bottom? if ( splitY != parentY ) { excludeEdgeFromTitleSafe.y = 1; } else { excludeEdgeFromTitleSafe.height = 1; } } if ( bVerticalSplit ) { // left or right if ( splitX != parentX ) { excludeEdgeFromTitleSafe.x = 1; } else { excludeEdgeFromTitleSafe.width = 1; } } if ( _buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED ) { if ( !excludeEdgeFromTitleSafe.width ) { x -= titleSafeWide; // right edge } } else if (_buildModeFlags & BUILDMODE_SAVE_XPOS_CENTERALIGNED) { } else if ( !excludeEdgeFromTitleSafe.x ) { x += titleSafeWide; // left edge } if ( _buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED ) { if ( !excludeEdgeFromTitleSafe.height ) { y -= titleSafeTall; // bottom edge } } else if (_buildModeFlags & BUILDMODE_SAVE_YPOS_CENTERALIGNED) { } else if ( !excludeEdgeFromTitleSafe.y ) { y += titleSafeTall; // top edge } } } SetNavUp( inResourceData->GetString("navUp") ); SetNavDown( inResourceData->GetString("navDown") ); SetNavLeft( inResourceData->GetString("navLeft") ); SetNavRight( inResourceData->GetString("navRight") ); SetNavToRelay( inResourceData->GetString("navToRelay") ); SetNavActivate( inResourceData->GetString("navActivate") ); SetNavBack( inResourceData->GetString("navBack") ); SetPos(x, y); if (inResourceData->FindKey( "zpos" )) { SetZPos( inResourceData->GetInt( "zpos" ) ); } if( bUsesTitleSafeArea ) { if ( _buildModeFlags & BUILDMODE_SAVE_WIDE_FULL ) { if ( !excludeEdgeFromTitleSafe.x ) wide -= titleSafeWide; if ( !excludeEdgeFromTitleSafe.width ) wide -= titleSafeWide; } if ( _buildModeFlags & BUILDMODE_SAVE_TALL_FULL ) { if ( !excludeEdgeFromTitleSafe.y ) tall -= titleSafeTall; if ( !excludeEdgeFromTitleSafe.height ) tall -= titleSafeTall; } } SetSize( wide, tall ); // NOTE: This has to happen after pos + size is set ApplyAutoResizeSettings( inResourceData ); // only get colors if we're ignoring the scheme if (inResourceData->GetInt("IgnoreScheme", 0)) { PerformApplySchemeSettings(); } // state int state = inResourceData->GetInt("visible", 1); if (state == 0) { SetVisible(false); } else if (state == 1) { SetVisible(true); } SetEnabled( inResourceData->GetInt("enabled", true) ); bool bMouseEnabled = inResourceData->GetInt( "mouseinputenabled", true ); if ( !bMouseEnabled ) { SetMouseInputEnabled( false ); } // tab order SetTabPosition(inResourceData->GetInt("tabPosition", 0)); const char *tooltip = inResourceData->GetString("tooltiptext", NULL); if (tooltip && *tooltip) { GetTooltip()->SetText(tooltip); } // paint background? int nPaintBackground = inResourceData->GetInt("paintbackground", -1); if (nPaintBackground >= 0) { SetPaintBackgroundEnabled( nPaintBackground != 0 ); } // paint border? int nPaintBorder = inResourceData->GetInt("paintborder", -1); if (nPaintBorder >= 0) { SetPaintBorderEnabled( nPaintBorder != 0 ); } // border? const char *pBorder = inResourceData->GetString( "border", "" ); if ( *pBorder ) { IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); SetBorder( pScheme->GetBorder( pBorder ) ); } // check to see if we have a new name assigned const char *newName = inResourceData->GetString("fieldName", NULL); if ( newName ) { // Only slam the name if the new one differs... SetName(newName); } tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Action signal", __FUNCTION__, GetName() ); // Automatically add an action signal target if one is specified. This allows for // nested child buttons to add their distant parents as action signal targets. int nActionSignalLevel = inResourceData->GetInt( "actionsignallevel", -1 ); if ( nActionSignalLevel != -1 ) { Panel *pActionSignalTarget = this; while( nActionSignalLevel-- ) { pActionSignalTarget = pActionSignalTarget->GetParent(); } AddActionSignalTarget( pActionSignalTarget ); } // check to see if we need to render to the frame buffer even if // stereo mode is trying to render all of the ui to a render target m_bForceStereoRenderToFrameBuffer = inResourceData->GetBool( "ForceStereoRenderToFrameBuffer", false ); //============================================================================= // HPE_BEGIN: // [pfreese] Support for reading rounded corner flags //============================================================================= int roundedCorners = inResourceData->GetInt( "RoundedCorners", -1 ); if ( roundedCorners >= 0 ) { m_roundedCorners = roundedCorners; } //============================================================================= // HPE_END //============================================================================= tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Pin Sibling", __FUNCTION__, GetName() ); const char *pszSiblingName = inResourceData->GetString("pin_to_sibling", NULL); PinCorner_e pinOurCornerToSibling = GetPinCornerFromString( inResourceData->GetString( "pin_corner_to_sibling", NULL ) ); PinCorner_e pinSiblingCorner = GetPinCornerFromString( inResourceData->GetString( "pin_to_sibling_corner", NULL ) ); PinToSibling( pszSiblingName, pinOurCornerToSibling, pinSiblingCorner ); tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Color overrides", __FUNCTION__, GetName() ); // Allow overriding of colors. Used mostly by HUD elements, where scheme color usage is often undesired. IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() ); for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ ) { // Need to ensure the key exists, so we don't overwrite existing colors when it's not set. if ( inResourceData->FindKey( m_OverridableColorEntries[i].m_pszScriptName, false ) ) { // Get the color as a string - test whether it is an actual color or a reference to a scheme color const char *pColorStr = inResourceData->GetString( m_OverridableColorEntries[i].m_pszScriptName ); Color &clrDest = m_OverridableColorEntries[i].m_colFromScript; if ( pColorStr[0] == '.' || isdigit( pColorStr[0] ) ) { float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f; sscanf( pColorStr, "%f %f %f %f", &r, &g, &b, &a ); clrDest[0] = (unsigned char)r; clrDest[1] = (unsigned char)g; clrDest[2] = (unsigned char)b; clrDest[3] = (unsigned char)a; } else { // First character wasn't a digit or a decimal - do a scheme color lookup clrDest = pScheme->GetColor( pColorStr, Color( 255, 255, 255, 255 ) ); } (*m_OverridableColorEntries[i].m_pColor) = m_OverridableColorEntries[i].m_colFromScript; m_OverridableColorEntries[i].m_bOverridden = true; } } tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s: Keyboard enabled", __FUNCTION__, GetName() ); const char *pKeyboardInputEnabled = inResourceData->GetString( "keyboardinputenabled", NULL ); if ( pKeyboardInputEnabled && pKeyboardInputEnabled[0] ) { SetKeyBoardInputEnabled( atoi( pKeyboardInputEnabled ) ); } OnChildSettingsApplied( inResourceData, this ); } //----------------------------------------------------------------------------- // Purpose: Saves out a resource description of this panel //----------------------------------------------------------------------------- void Panel::GetSettings( KeyValues *outResourceData ) { // control class name (so it can be recreated later if needed) outResourceData->SetString( "ControlName", GetClassName() ); // name outResourceData->SetString( "fieldName", _panelName ); // positioning int screenWide, screenTall; surface()->GetScreenSize(screenWide, screenTall); int x, y; GetPos( x, y ); if ( IsProportional() ) { x = scheme()->GetProportionalNormalizedValueEx( GetScheme(), x ); y = scheme()->GetProportionalNormalizedValueEx( GetScheme(), y ); } // correct for alignment if (_buildModeFlags & BUILDMODE_SAVE_XPOS_RIGHTALIGNED) { x = screenWide - x; char xstr[32]; Q_snprintf(xstr, sizeof( xstr ), "r%d", x); outResourceData->SetString( "xpos", xstr ); } else if (_buildModeFlags & BUILDMODE_SAVE_XPOS_CENTERALIGNED) { x = (screenWide / 2) + x; char xstr[32]; Q_snprintf(xstr, sizeof( xstr ), "c%d", x); outResourceData->SetString( "xpos", xstr ); } else { outResourceData->SetInt( "xpos", x ); } if (_buildModeFlags & BUILDMODE_SAVE_YPOS_BOTTOMALIGNED) { y = screenTall - y; char ystr[32]; Q_snprintf(ystr, sizeof( ystr ), "r%d", y); outResourceData->SetString( "ypos", ystr ); } else if (_buildModeFlags & BUILDMODE_SAVE_YPOS_CENTERALIGNED) { y = (screenTall / 2) + y; char ystr[32]; Q_snprintf(ystr, sizeof( ystr ), "c%d", y); outResourceData->SetString( "ypos", ystr ); } else { outResourceData->SetInt( "ypos", y ); } if (m_pTooltips) { if (strlen(m_pTooltips->GetText()) > 0) { outResourceData->SetString("tooltiptext", m_pTooltips->GetText()); } } int wide, tall; GetSize( wide, tall ); if ( IsProportional() ) { wide = scheme()->GetProportionalNormalizedValueEx( GetScheme(), wide ); tall = scheme()->GetProportionalNormalizedValueEx( GetScheme(), tall ); } int z = ipanel()->GetZPos(GetVPanel()); if (z) { outResourceData->SetInt("zpos", z); } // Correct for alignment if (_buildModeFlags & BUILDMODE_SAVE_WIDE_FULL ) { wide = screenWide - wide; char wstr[32]; Q_snprintf(wstr, sizeof( wstr ), "f%d", wide); outResourceData->SetString( "wide", wstr ); } else { outResourceData->SetInt( "wide", wide ); } outResourceData->SetInt( "tall", tall ); outResourceData->SetInt("AutoResize", GetAutoResize()); outResourceData->SetInt("PinCorner", GetPinCorner()); //============================================================================= // HPE_BEGIN: // [pfreese] Support for writing out rounded corner flags //============================================================================= outResourceData->SetInt("RoundedCorners", m_roundedCorners); //============================================================================= // HPE_END //============================================================================= outResourceData->SetString( "pin_to_sibling", _pinToSibling ); outResourceData->SetInt("pin_corner_to_sibling", _pinCornerToSibling ); outResourceData->SetInt("pin_to_sibling_corner", _pinToSiblingCorner ); // state outResourceData->SetInt( "visible", IsVisible() ); outResourceData->SetInt( "enabled", IsEnabled() ); outResourceData->SetInt( "tabPosition", GetTabPosition() ); for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ ) { if ( m_OverridableColorEntries[i].m_bOverridden ) { outResourceData->SetColor( m_OverridableColorEntries[i].m_pszScriptName, m_OverridableColorEntries[i].m_colFromScript ); } } } //----------------------------------------------------------------------------- // Purpose: After applying settings, apply overridable colors. // Done post apply settings, so that baseclass settings don't stomp // the script specified override colors. //----------------------------------------------------------------------------- void Panel::ApplyOverridableColors( void ) { for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ ) { if ( m_OverridableColorEntries[i].m_bOverridden ) { (*m_OverridableColorEntries[i].m_pColor) = m_OverridableColorEntries[i].m_colFromScript; } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetOverridableColor( Color *pColor, const Color &newColor ) { for ( int i = 0; i < m_OverridableColorEntries.Count(); i++ ) { if ( m_OverridableColorEntries[i].m_bOverridden ) { if ( m_OverridableColorEntries[i].m_pColor == pColor ) return; } } // Didn't find it, or it's not been overridden. *pColor = newColor; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Color Panel::GetSchemeColor(const char *keyName, IScheme *pScheme) { return pScheme->GetColor(keyName, Color(255, 255, 255, 255)); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Color Panel::GetSchemeColor(const char *keyName, Color defaultColor, IScheme *pScheme) { return pScheme->GetColor(keyName, defaultColor); } //----------------------------------------------------------------------------- // Purpose: Returns a string description of the panel fields for use in the UI //----------------------------------------------------------------------------- const char *Panel::GetDescription( void ) { static const char *panelDescription = "string fieldName, int xpos, int ypos, int wide, int tall, bool visible, bool enabled, int tabPosition, corner pinCorner, autoresize autoResize, string tooltiptext"; return panelDescription; } //----------------------------------------------------------------------------- // Purpose: user configuration settings // this is used for any control details the user wants saved between sessions // eg. dialog positions, last directory opened, list column width //----------------------------------------------------------------------------- void Panel::ApplyUserConfigSettings(KeyValues *userConfig) { } //----------------------------------------------------------------------------- // Purpose: returns user config settings for this control //----------------------------------------------------------------------------- void Panel::GetUserConfigSettings(KeyValues *userConfig) { } //----------------------------------------------------------------------------- // Purpose: optimization, return true if this control has any user config settings //----------------------------------------------------------------------------- bool Panel::HasUserConfigSettings() { return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::InternalInvalidateLayout() { InvalidateLayout(false, false); } //----------------------------------------------------------------------------- // Purpose: called whenever the panel moves //----------------------------------------------------------------------------- void Panel::OnMove() { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::InternalMove() { OnMove(); for(int i=0;iOnMove(); } } //----------------------------------------------------------------------------- // Purpose: empty function //----------------------------------------------------------------------------- void Panel::OnTick() { } //----------------------------------------------------------------------------- // Purpose: versioning //----------------------------------------------------------------------------- void *Panel::QueryInterface(EInterfaceID id) { if (id == ICLIENTPANEL_STANDARD_INTERFACE) { return this; } return NULL; } //----------------------------------------------------------------------------- // Purpose: Map all the base messages to functions // ordering from most -> least used improves speed //----------------------------------------------------------------------------- MessageMapItem_t Panel::m_MessageMap[] = { MAP_MESSAGE_INT( Panel, "RequestFocus", RequestFocus, "direction" ) }; // IMPLEMENT_PANELMAP( Panel, NULL ) PanelMap_t Panel::m_PanelMap = { Panel::m_MessageMap, ARRAYSIZE(Panel::m_MessageMap), "Panel", NULL }; PanelMap_t *Panel::GetPanelMap( void ) { return &m_PanelMap; } //----------------------------------------------------------------------------- // Purpose: !! Soon to replace existing prepare panel map //----------------------------------------------------------------------------- void PreparePanelMessageMap(PanelMessageMap *panelMap) { // iterate through the class hierarchy message maps while ( panelMap != NULL && !panelMap->processed ) { // hash message map strings into symbols for (int i = 0; i < panelMap->entries.Count(); i++) { MessageMapItem_t *item = &panelMap->entries[i]; if (item->name) { item->nameSymbol = KeyValuesSystem()->GetSymbolForString(item->name); } else { item->nameSymbol = INVALID_KEY_SYMBOL; } if (item->firstParamName) { item->firstParamSymbol = KeyValuesSystem()->GetSymbolForString(item->firstParamName); } else { item->firstParamSymbol = INVALID_KEY_SYMBOL; } if (item->secondParamName) { item->secondParamSymbol = KeyValuesSystem()->GetSymbolForString(item->secondParamName); } else { item->secondParamSymbol = INVALID_KEY_SYMBOL; } } panelMap->processed = true; panelMap = panelMap->baseMap; } } //----------------------------------------------------------------------------- // Purpose: Handles a message // Dispatches the message to a set of message maps //----------------------------------------------------------------------------- void Panel::OnMessage(const KeyValues *params, VPANEL ifromPanel) { PanelMessageMap *panelMap = GetMessageMap(); bool bFound = false; int iMessageName = params->GetNameSymbol(); if ( !panelMap->processed ) { PreparePanelMessageMap( panelMap ); } // iterate through the class hierarchy message maps for ( ; panelMap != NULL && !bFound; panelMap = panelMap->baseMap ) { #if defined( _DEBUG ) // char const *className = panelMap->pfnClassName(); // NOTE_UNUSED( className ); #endif // iterate all the entries in the panel map for ( int i = 0; i < panelMap->entries.Count(); i++ ) { MessageMapItem_t *pMap = &panelMap->entries[i]; if (iMessageName == pMap->nameSymbol) { bFound = true; switch (pMap->numParams) { case 0: { (this->*(pMap->func))(); break; } case 1: { KeyValues *param1 = params->FindKey(pMap->firstParamSymbol); if (!param1) { param1 = const_cast(params); } switch ( pMap->firstParamType ) { case DATATYPE_INT: typedef void (Panel::*MessageFunc_Int_t)(int); (this->*((MessageFunc_Int_t)pMap->func))( param1->GetInt() ); break; case DATATYPE_UINT64: typedef void (Panel::*MessageFunc_Uin64_t)(uint64); (this->*((MessageFunc_Uin64_t)pMap->func))( param1->GetUint64() ); break; case DATATYPE_PTR: typedef void (Panel::*MessageFunc_Ptr_t)( void * ); (this->*((MessageFunc_Ptr_t)pMap->func))( param1->GetPtr() ); break; case DATATYPE_HANDLE: { typedef void (Panel::*MessageFunc_VPANEL_t)( VPANEL ); VPANEL vpanel = ivgui()->HandleToPanel( param1->GetInt() ); (this->*((MessageFunc_VPANEL_t)pMap->func))( vpanel ); } break; case DATATYPE_FLOAT: typedef void (Panel::*MessageFunc_Float_t)( float ); (this->*((MessageFunc_Float_t)pMap->func))( param1->GetFloat() ); break; case DATATYPE_CONSTCHARPTR: typedef void (Panel::*MessageFunc_CharPtr_t)( const char * ); (this->*((MessageFunc_CharPtr_t)pMap->func))( param1->GetString() ); break; case DATATYPE_CONSTWCHARPTR: typedef void (Panel::*MessageFunc_WCharPtr_t)( const wchar_t * ); (this->*((MessageFunc_WCharPtr_t)pMap->func))( param1->GetWString() ); break; case DATATYPE_KEYVALUES: typedef void (Panel::*MessageFunc_KeyValues_t)(KeyValues *); if ( pMap->firstParamName ) { (this->*((MessageFunc_KeyValues_t)pMap->func))( (KeyValues *)param1->GetPtr() ); } else { // no param set, so pass in the whole thing (this->*((MessageFunc_KeyValues_t)pMap->func))( const_cast(params) ); } break; default: Assert(!("No handler for vgui message function")); break; } break; } case 2: { KeyValues *param1 = params->FindKey(pMap->firstParamSymbol); if (!param1) { param1 = const_cast(params); } KeyValues *param2 = params->FindKey(pMap->secondParamSymbol); if (!param2) { param2 = const_cast(params); } if ( (DATATYPE_INT == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_IntInt_t)(int, int); (this->*((MessageFunc_IntInt_t)pMap->func))( param1->GetInt(), param2->GetInt() ); } else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_PtrInt_t)(void *, int); (this->*((MessageFunc_PtrInt_t)pMap->func))( param1->GetPtr(), param2->GetInt() ); } else if ( (DATATYPE_CONSTCHARPTR == pMap->firstParamType) && (DATATYPE_INT == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_ConstCharPtrInt_t)(const char *, int); (this->*((MessageFunc_ConstCharPtrInt_t)pMap->func))( param1->GetString(), param2->GetInt() ); } else if ( (DATATYPE_CONSTCHARPTR == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_ConstCharPtrConstCharPtr_t)(const char *, const char *); (this->*((MessageFunc_ConstCharPtrConstCharPtr_t)pMap->func))( param1->GetString(), param2->GetString() ); } else if ( (DATATYPE_INT == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_IntConstCharPtr_t)(int, const char *); (this->*((MessageFunc_IntConstCharPtr_t)pMap->func))( param1->GetInt(), param2->GetString() ); } else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const char *); (this->*((MessageFunc_PtrConstCharPtr_t)pMap->func))( param1->GetPtr(), param2->GetString() ); } else if ( (DATATYPE_PTR == pMap->firstParamType) && (DATATYPE_CONSTWCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const wchar_t *); (this->*((MessageFunc_PtrConstCharPtr_t)pMap->func))( param1->GetPtr(), param2->GetWString() ); } else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_CONSTCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const char *); VPANEL vp = ivgui()->HandleToPanel( param1->GetInt() ); (this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp, param2->GetString() ); } else if ( (DATATYPE_HANDLE == pMap->firstParamType) && (DATATYPE_CONSTWCHARPTR == pMap->secondParamType) ) { typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const wchar_t *); VPANEL vp = ivgui()->HandleToPanel( param1->GetInt() ); (this->*((MessageFunc_HandleConstCharPtr_t)pMap->func))( vp, param2->GetWString() ); } else { // the message isn't handled ivgui()->DPrintf( "Message '%s', sent to '%s', has invalid parameter types\n", params->GetName(), GetName() ); } break; } default: Assert(!("Invalid number of parameters")); break; } // break the loop bFound = true; break; } } } if (!bFound) { OnOldMessage(const_cast(params), ifromPanel); } } void Panel::OnOldMessage(KeyValues *params, VPANEL ifromPanel) { bool bFound = false; // message map dispatch int iMessageName = params->GetNameSymbol(); PanelMap_t *panelMap = GetPanelMap(); if ( !panelMap->processed ) { PreparePanelMap( panelMap ); } // iterate through the class hierarchy message maps for ( ; panelMap != NULL && !bFound; panelMap = panelMap->baseMap ) { MessageMapItem_t *pMessageMap = panelMap->dataDesc; for ( int i = 0; i < panelMap->dataNumFields; i++ ) { if (iMessageName == pMessageMap[i].nameSymbol) { // call the mapped function switch ( pMessageMap[i].numParams ) { case 2: if ( (DATATYPE_INT == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_IntInt_t)(int, int); (this->*((MessageFunc_IntInt_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_PtrInt_t)(void *, int); (this->*((MessageFunc_PtrInt_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_CONSTCHARPTR == pMessageMap[i].firstParamType) && (DATATYPE_INT == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_ConstCharPtrInt_t)(const char *, int); (this->*((MessageFunc_ConstCharPtrInt_t)pMessageMap[i].func))( params->GetString(pMessageMap[i].firstParamName), params->GetInt(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_CONSTCHARPTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_ConstCharPtrConstCharPtr_t)(const char *, const char *); (this->*((MessageFunc_ConstCharPtrConstCharPtr_t)pMessageMap[i].func))( params->GetString(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_INT == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_IntConstCharPtr_t)(int, const char *); (this->*((MessageFunc_IntConstCharPtr_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const char *); (this->*((MessageFunc_PtrConstCharPtr_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetString(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_PTR == pMessageMap[i].firstParamType) && (DATATYPE_CONSTWCHARPTR == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_PtrConstCharPtr_t)(void *, const wchar_t *); (this->*((MessageFunc_PtrConstCharPtr_t)pMessageMap[i].func))( params->GetPtr(pMessageMap[i].firstParamName), params->GetWString(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_HANDLE == pMessageMap[i].firstParamType) && (DATATYPE_CONSTCHARPTR ==pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const char *); VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) ); (this->*((MessageFunc_HandleConstCharPtr_t)pMessageMap[i].func))( vp, params->GetString(pMessageMap[i].secondParamName) ); } else if ( (DATATYPE_HANDLE == pMessageMap[i].firstParamType) && (DATATYPE_CONSTWCHARPTR == pMessageMap[i].secondParamType) ) { typedef void (Panel::*MessageFunc_HandleConstCharPtr_t)(VPANEL, const wchar_t *); VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) ); (this->*((MessageFunc_HandleConstCharPtr_t)pMessageMap[i].func))( vp, params->GetWString(pMessageMap[i].secondParamName) ); } else { // the message isn't handled ivgui()->DPrintf( "Message '%s', sent to '%s', has invalid parameter types\n", params->GetName(), GetName() ); } break; case 1: switch ( pMessageMap[i].firstParamType ) { case DATATYPE_BOOL: typedef void (Panel::*MessageFunc_Bool_t)(bool); (this->*((MessageFunc_Bool_t)pMessageMap[i].func))( (bool)params->GetInt(pMessageMap[i].firstParamName) ); break; case DATATYPE_CONSTCHARPTR: typedef void (Panel::*MessageFunc_ConstCharPtr_t)(const char *); (this->*((MessageFunc_ConstCharPtr_t)pMessageMap[i].func))( (const char *)params->GetString(pMessageMap[i].firstParamName) ); break; case DATATYPE_CONSTWCHARPTR: typedef void (Panel::*MessageFunc_ConstCharPtr_t)(const char *); (this->*((MessageFunc_ConstCharPtr_t)pMessageMap[i].func))( (const char *)params->GetWString(pMessageMap[i].firstParamName) ); break; case DATATYPE_INT: typedef void (Panel::*MessageFunc_Int_t)(int); (this->*((MessageFunc_Int_t)pMessageMap[i].func))( params->GetInt(pMessageMap[i].firstParamName) ); break; case DATATYPE_FLOAT: typedef void (Panel::*MessageFunc_Float_t)(float); (this->*((MessageFunc_Float_t)pMessageMap[i].func))( params->GetFloat(pMessageMap[i].firstParamName) ); break; case DATATYPE_PTR: typedef void (Panel::*MessageFunc_Ptr_t)(void *); (this->*((MessageFunc_Ptr_t)pMessageMap[i].func))( (void *)params->GetPtr(pMessageMap[i].firstParamName) ); break; case DATATYPE_HANDLE: { typedef void (Panel::*MessageFunc_Ptr_t)(void *); VPANEL vp = ivgui()->HandleToPanel( params->GetInt( pMessageMap[i].firstParamName ) ); Panel *panel = ipanel()->GetPanel( vp, GetModuleName() ); (this->*((MessageFunc_Ptr_t)pMessageMap[i].func))( (void *)panel ); } break; case DATATYPE_KEYVALUES: typedef void (Panel::*MessageFunc_KeyValues_t)(KeyValues *); if ( pMessageMap[i].firstParamName ) { (this->*((MessageFunc_KeyValues_t)pMessageMap[i].func))( (KeyValues *)params->GetPtr(pMessageMap[i].firstParamName) ); } else { (this->*((MessageFunc_KeyValues_t)pMessageMap[i].func))( params ); } break; default: // the message isn't handled ivgui()->DPrintf( "Message '%s', sent to '%s', has an invalid parameter type\n", params->GetName(), GetName() ); break; } break; default: (this->*(pMessageMap[i].func))(); break; }; // break the loop bFound = true; break; } } } // message not handled // debug code if ( !bFound ) { static int s_bDebugMessages = -1; if ( s_bDebugMessages == -1 ) { s_bDebugMessages = CommandLine()->FindParm( "-vguimessages" ) ? 1 : 0; } if ( s_bDebugMessages == 1 ) { ivgui()->DPrintf( "Message '%s' not handled by panel '%s'\n", params->GetName(), GetName() ); } } } //----------------------------------------------------------------------------- // Purpose: Safe call to get info from child panel by name //----------------------------------------------------------------------------- bool Panel::RequestInfoFromChild(const char *childName, KeyValues *outputData) { Panel *panel = FindChildByName(childName); if (panel) { return panel->RequestInfo(outputData); } return false; } //----------------------------------------------------------------------------- // Purpose: Posts a message //----------------------------------------------------------------------------- void Panel::PostMessage(Panel *target, KeyValues *message, float delay) { ivgui()->PostMessage(target->GetVPanel(), message, GetVPanel(), delay); } void Panel::PostMessage(VPANEL target, KeyValues *message, float delaySeconds) { ivgui()->PostMessage(target, message, GetVPanel(), delaySeconds); } void Panel::PostMessageToAllSiblings( KeyValues *msg, float delaySeconds /*= 0.0f*/ ) { VPANEL parent = GetVParent(); if ( parent ) { VPANEL vpanel = GetVPanel(); CUtlVector< VPANEL > &children = ipanel()->GetChildren( parent ); int nChildCount = children.Count(); for ( int i = 0; i < nChildCount; ++i ) { VPANEL sibling = children[ i ]; if ( sibling == vpanel ) continue; if ( sibling ) { PostMessage( sibling, msg->MakeCopy(), delaySeconds ); } } } msg->deleteThis(); } //----------------------------------------------------------------------------- // Purpose: Safe call to post a message to a child by name //----------------------------------------------------------------------------- void Panel::PostMessageToChild(const char *childName, KeyValues *message) { Panel *panel = FindChildByName(childName); if (panel) { ivgui()->PostMessage(panel->GetVPanel(), message, GetVPanel()); } else { message->deleteThis(); } } //----------------------------------------------------------------------------- // Purpose: Requests some information from the panel // Look through the message map for the handler //----------------------------------------------------------------------------- bool Panel::RequestInfo( KeyValues *outputData ) { if ( InternalRequestInfo( GetAnimMap(), outputData ) ) { return true; } if (GetVParent()) { return ipanel()->RequestInfo(GetVParent(), outputData); } return false; } //----------------------------------------------------------------------------- // Purpose: sets a specified value in the control - inverse of RequestInfo //----------------------------------------------------------------------------- bool Panel::SetInfo(KeyValues *inputData) { if ( InternalSetInfo( GetAnimMap(), inputData ) ) { return true; } // doesn't chain to parent return false; } //----------------------------------------------------------------------------- // Purpose: change the panel's silent mode; if silent, the panel will not post // any action signals //----------------------------------------------------------------------------- void Panel::SetSilentMode( bool bSilent ) { m_bIsSilent = bSilent; } //----------------------------------------------------------------------------- // Purpose: mouse events will be send to handler panel instead of this panel //----------------------------------------------------------------------------- void Panel::InstallMouseHandler( Panel *pHandler ) { m_hMouseEventHandler = pHandler; } //----------------------------------------------------------------------------- // Purpose: Prepares the hierarchy panel maps for use (with message maps etc) //----------------------------------------------------------------------------- void Panel::PreparePanelMap( PanelMap_t *panelMap ) { // iterate through the class hierarchy message maps while ( panelMap != NULL && !panelMap->processed ) { // fixup cross-dll boundary panel maps if ( panelMap->baseMap == (PanelMap_t*)0x00000001 ) { panelMap->baseMap = &Panel::m_PanelMap; } // hash message map strings into symbols for (int i = 0; i < panelMap->dataNumFields; i++) { MessageMapItem_t *item = &panelMap->dataDesc[i]; if (item->name) { item->nameSymbol = KeyValuesSystem()->GetSymbolForString(item->name); } else { item->nameSymbol = INVALID_KEY_SYMBOL; } if (item->firstParamName) { item->firstParamSymbol = KeyValuesSystem()->GetSymbolForString(item->firstParamName); } else { item->firstParamSymbol = INVALID_KEY_SYMBOL; } if (item->secondParamName) { item->secondParamSymbol = KeyValuesSystem()->GetSymbolForString(item->secondParamName); } else { item->secondParamSymbol = INVALID_KEY_SYMBOL; } } panelMap->processed = true; panelMap = panelMap->baseMap; } } //----------------------------------------------------------------------------- // Purpose: Called to delete the panel //----------------------------------------------------------------------------- void Panel::OnDelete() { #ifdef WIN32 Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) ); #endif delete this; #ifdef WIN32 Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) ); #endif } //----------------------------------------------------------------------------- // Purpose: Panel handle implementation // Returns a pointer to a valid panel, NULL if the panel has been deleted //----------------------------------------------------------------------------- Panel *PHandle::Get() { if (m_iPanelID != INVALID_PANEL) { VPANEL panel = ivgui()->HandleToPanel(m_iPanelID); if (panel) { Panel *vguiPanel = ipanel()->GetPanel(panel, GetControlsModuleName()); return vguiPanel; } } return NULL; } //----------------------------------------------------------------------------- // Purpose: sets the smart pointer //----------------------------------------------------------------------------- Panel *PHandle::Set(Panel *pent) { if (pent) { m_iPanelID = ivgui()->PanelToHandle(pent->GetVPanel()); } else { m_iPanelID = INVALID_PANEL; } return pent; } Panel *PHandle::Set( HPanel hPanel ) { m_iPanelID = hPanel; return Get(); } //----------------------------------------------------------------------------- // Purpose: Returns a handle to a valid panel, NULL if the panel has been deleted //----------------------------------------------------------------------------- VPANEL VPanelHandle::Get() { if (m_iPanelID != INVALID_PANEL) { if (ivgui()) { return ivgui()->HandleToPanel(m_iPanelID); } } return NULL; } //----------------------------------------------------------------------------- // Purpose: sets the smart pointer //----------------------------------------------------------------------------- VPANEL VPanelHandle::Set(VPANEL pent) { if (pent) { m_iPanelID = ivgui()->PanelToHandle(pent); } else { m_iPanelID = INVALID_PANEL; } return pent; } //----------------------------------------------------------------------------- // Purpose: returns a pointer to the tooltip object associated with the panel //----------------------------------------------------------------------------- BaseTooltip *Panel::GetTooltip() { if (!m_pTooltips) { m_pTooltips = new TextTooltip(this, NULL); m_bToolTipOverridden = false; if ( IsConsoleStylePanel() ) { m_pTooltips->SetEnabled( false ); } } return m_pTooltips; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetTooltip( BaseTooltip *pToolTip, const char *pszText ) { if ( !m_bToolTipOverridden ) { // Remove the one we made, we're being overridden. delete m_pTooltips; } m_pTooltips = pToolTip; m_bToolTipOverridden = true; if ( _tooltipText ) { delete [] _tooltipText; _tooltipText = NULL; } if ( pszText ) { int len = Q_strlen(pszText) + 1; _tooltipText = new char[ len ]; Q_strncpy( _tooltipText, pszText, len ); } } //----------------------------------------------------------------------------- const char *Panel::GetEffectiveTooltipText() const { if ( _tooltipText ) { return _tooltipText; } if ( m_pTooltips ) { const char *result = m_pTooltips->GetText(); if ( result ) { return result; } } return ""; } //----------------------------------------------------------------------------- // Purpose: sets the proportional flag on this panel and all it's children //----------------------------------------------------------------------------- void Panel::SetProportional(bool state) { // only do something if the state changes if( state != _flags.IsFlagSet( IS_PROPORTIONAL ) ) { _flags.SetFlag( IS_PROPORTIONAL, state ); for(int i=0;iSetProportional( IsProportional() ); } } InvalidateLayout(); } void Panel::SetKeyBoardInputEnabled( bool state ) { ipanel()->SetKeyBoardInputEnabled( GetVPanel(), state ); for ( int i = 0; i < GetChildCount(); i++ ) { Panel *child = GetChild( i ); if ( !child ) { continue; } child->SetKeyBoardInputEnabled( state ); } // If turning off keyboard input enable, then make sure // this panel is not the current key focus of a parent panel if ( !state ) { Panel *pParent = GetParent(); if ( pParent ) { if ( pParent->GetCurrentKeyFocus() == GetVPanel() ) { pParent->RequestFocusNext(); } } } } void Panel::SetMouseInputEnabled( bool state ) { ipanel()->SetMouseInputEnabled( GetVPanel(), state ); /* for(int i=0;iSetMouseInput(state); }*/ vgui::surface()->CalculateMouseVisible(); } bool Panel::IsKeyBoardInputEnabled() { return ipanel()->IsKeyBoardInputEnabled( GetVPanel() ); } bool Panel::IsMouseInputEnabled() { return ipanel()->IsMouseInputEnabled( GetVPanel() ); } class CFloatProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); kv->SetFloat( entry->name(), *(float *)data ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(float *)data = kv->GetFloat( entry->name() ); } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(float *)data = atof( entry->defaultvalue() ); } }; class CProportionalFloatProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); float f = *(float *)data; f = scheme()->GetProportionalNormalizedValueEx( panel->GetScheme(), f ); kv->SetFloat( entry->name(), f ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); float f = kv->GetFloat( entry->name() ); f = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), f ); *(float *)data = f; } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); float f = atof( entry->defaultvalue() ); f = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), f ); *(float *)data = f; } }; class CIntProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); kv->SetInt( entry->name(), *(int *)data ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(int *)data = kv->GetInt( entry->name() ); } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(int *)data = atoi( entry->defaultvalue() ); } }; class CProportionalIntProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int i = *(int *)data; i = scheme()->GetProportionalNormalizedValueEx( panel->GetScheme(), i ); kv->SetInt( entry->name(), i ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int i = kv->GetInt( entry->name() ); i = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), i ); *(int *)data = i; } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int i = atoi( entry->defaultvalue() ); i = scheme()->GetProportionalScaledValueEx( panel->GetScheme(), i ); *(int *)data = i; } }; class CProportionalIntWithScreenspacePropertyX : public vgui::IPanelAnimationPropertyConverter { public: int ExtractValue( Panel *pPanel, const char *pszKey ) { int nPos = 0; ComputePos( pPanel, pszKey, nPos, GetPanelDimension( pPanel ), GetScreenSize( pPanel ), true, OP_ADD ); return nPos; } virtual int GetScreenSize( Panel *pPanel ) const { int nParentWide, nParentTall; if (pPanel->IsProportional() && pPanel->GetParent()) { nParentWide = pPanel->GetParent()->GetWide(); nParentTall = pPanel->GetParent()->GetTall(); } else { surface()->GetScreenSize(nParentWide, nParentTall); } return nParentWide; } virtual int GetPanelDimension( Panel *pPanel ) const { return pPanel->GetWide(); } virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { // Won't work with this, don't use it. Assert(0); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(int *)data = ExtractValue( panel, kv->GetString( entry->name() ) ); } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(int *)data = ExtractValue( panel, entry->defaultvalue() ); } }; class CProportionalIntWithScreenspacePropertyY : public CProportionalIntWithScreenspacePropertyX { public: virtual int GetScreenSize( Panel *pPanel ) const OVERRIDE { int nParentWide, nParentTall; if (pPanel->IsProportional() && pPanel->GetParent()) { nParentWide = pPanel->GetParent()->GetWide(); nParentTall = pPanel->GetParent()->GetTall(); } else { surface()->GetScreenSize(nParentWide, nParentTall); } return nParentTall; } virtual int GetPanelDimension(Panel *pPanel) const OVERRIDE { return pPanel->GetTall(); } }; class CProportionalWidthProperty : public vgui::IPanelAnimationPropertyConverter { public: int ExtractValue(Panel *pPanel, const char *pszKey) { if ( pszKey && ( pszKey[0] == 'o' || pszKey[0] == 'O' ) ) { // We don't handle sizes based on the other dimension in this case Assert( 0 ); return 0; } int nParentWide, nParentTall; if ( pPanel->IsProportional() && pPanel->GetParent() ) { nParentWide = pPanel->GetParent()->GetWide(); nParentTall = pPanel->GetParent()->GetTall(); } else { surface()->GetScreenSize( nParentWide, nParentTall ); } unsigned int nBuildFlags = 0; return Compute( pPanel, nBuildFlags, pszKey, nParentWide, nParentTall, false ); } virtual void GetData(Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry) { // Won't work with this, don't use it. Assert(0); } virtual void SetData(Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry) { void *data = (void *)((*entry->m_pfnLookup)(panel)); *(int *)data = ExtractValue(panel, kv->GetString(entry->name())); } virtual void InitFromDefault(Panel *panel, PanelAnimationMapEntry *entry) { void *data = (void *)((*entry->m_pfnLookup)(panel)); *(int *)data = ExtractValue(panel, entry->defaultvalue()); } private: virtual int Compute( Panel* pPanel, unsigned int& nBuildFlags, const char *pszKey, int nParentWide, int nParentTall, bool bComputingOther ) { KeyValuesAD kv( "temp" ); kv->SetString( "wide", pszKey ); return ComputeWide( pPanel, nBuildFlags, kv, nParentWide, nParentTall, false ); } }; class CProportionalHeightProperty : public CProportionalWidthProperty { private: virtual int Compute(Panel* pPanel, unsigned int& nBuildFlags, const char *pszKey, int nParentWide, int nParentTall, bool bComputingOther) OVERRIDE { KeyValuesAD kv( "temp" ); kv->SetString( "tall", pszKey ); return ComputeTall(pPanel, nBuildFlags, kv, nParentWide, nParentTall, false); } }; class CColorProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); kv->SetColor( entry->name(), *(Color *)data ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() ); Assert( scheme ); if ( scheme ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); char const *colorName = kv->GetString( entry->name() ); if ( !colorName || !colorName[0] ) { *(Color *)data = kv->GetColor( entry->name() ); } else { *(Color *)data = scheme->GetColor( colorName, Color( 0, 0, 0, 0 ) ); } } } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() ); Assert( scheme ); if ( scheme ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(Color *)data = scheme->GetColor( entry->defaultvalue(), Color( 0, 0, 0, 0 ) ); } } }; class CBoolProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); kv->SetInt( entry->name(), *(bool *)data ? 1 : 0 ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(bool *)data = kv->GetInt( entry->name() ) ? true : false; } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); bool b = false; if ( !stricmp( entry->defaultvalue(), "true" )|| atoi( entry->defaultvalue() )!= 0 ) { b = true; } *(bool *)data = b; } }; class CStringProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); kv->SetString( entry->name(), (char *)data ); } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); strcpy( (char *)data, kv->GetString( entry->name() ) ); } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); strcpy( ( char * )data, entry->defaultvalue() ); } }; class CHFontProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() ); Assert( scheme ); if ( scheme ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); char const *fontName = scheme->GetFontName( *(HFont *)data ); kv->SetString( entry->name(), fontName ); } } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() ); Assert( scheme ); if ( scheme ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); char const *fontName = kv->GetString( entry->name() ); *(HFont *)data = scheme->GetFont( fontName, panel->IsProportional() ); } } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { vgui::IScheme *scheme = vgui::scheme()->GetIScheme( panel->GetScheme() ); Assert( scheme ); if ( scheme ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); *(HFont *)data = scheme->GetFont( entry->defaultvalue(), panel->IsProportional() ); } } }; class CTextureIdProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int currentId = *(int *)data; // lookup texture name for id char texturename[ 512 ]; if ( currentId != -1 && surface()->DrawGetTextureFile( currentId, texturename, sizeof( texturename ) ) ) { kv->SetString( entry->name(), texturename ); } else { kv->SetString( entry->name(), "" ); } } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int currentId = -1; char const *texturename = kv->GetString( entry->name() ); if ( texturename && texturename[ 0 ] ) { currentId = surface()->DrawGetTextureId( texturename ); if ( currentId == -1 ) { currentId = surface()->CreateNewTextureID(); } surface()->DrawSetTextureFile( currentId, texturename, false, true ); } *(int *)data = currentId; } virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); int currentId = -1; char const *texturename = entry->defaultvalue(); if ( texturename && texturename[ 0 ] ) { currentId = surface()->DrawGetTextureId( texturename ); if ( currentId == -1 ) { currentId = surface()->CreateNewTextureID(); } surface()->DrawSetTextureFile( currentId, texturename, false, true ); } *(int *)data = currentId; } }; static CFloatProperty floatconverter; static CProportionalFloatProperty p_floatconverter; static CIntProperty intconverter; static CProportionalIntProperty p_intconverter; static CProportionalIntWithScreenspacePropertyX p_screenspace_intconverter_X; static CProportionalIntWithScreenspacePropertyY p_screenspace_intconverter_Y; static CColorProperty colorconverter; static CBoolProperty boolconverter; static CStringProperty stringconverter; static CHFontProperty fontconverter; static CTextureIdProperty textureidconverter; static CProportionalWidthProperty proportional_width_converter; static CProportionalHeightProperty proportional_height_converter; //static CProportionalXPosProperty xposconverter; //static CProportionalYPosProperty yposconverter; static CUtlDict< IPanelAnimationPropertyConverter *, int > g_AnimationPropertyConverters; static IPanelAnimationPropertyConverter *FindConverter( char const *typeName ) { int lookup = g_AnimationPropertyConverters.Find( typeName ); if ( lookup == g_AnimationPropertyConverters.InvalidIndex() ) return NULL; IPanelAnimationPropertyConverter *converter = g_AnimationPropertyConverters[ lookup ]; return converter; } void Panel::AddPropertyConverter( char const *typeName, IPanelAnimationPropertyConverter *converter ) { int lookup = g_AnimationPropertyConverters.Find( typeName ); if ( lookup != g_AnimationPropertyConverters.InvalidIndex() ) { Msg( "Already have converter for type %s, ignoring...\n", typeName ); return; } g_AnimationPropertyConverters.Insert( typeName, converter ); } //----------------------------------------------------------------------------- // Purpose: Static method to initialize all needed converters //----------------------------------------------------------------------------- void Panel::InitPropertyConverters( void ) { static bool initialized = false; if ( initialized ) return; initialized = true; AddPropertyConverter( "float", &floatconverter ); AddPropertyConverter( "int", &intconverter ); AddPropertyConverter( "Color", &colorconverter ); //AddPropertyConverter( "vgui::Color", &colorconverter ); AddPropertyConverter( "bool", &boolconverter ); AddPropertyConverter( "char", &stringconverter ); AddPropertyConverter( "string", &stringconverter ); AddPropertyConverter( "HFont", &fontconverter ); AddPropertyConverter( "vgui::HFont", &fontconverter ); // This is an aliased type for proportional float AddPropertyConverter( "proportional_float", &p_floatconverter ); AddPropertyConverter( "proportional_int", &p_intconverter ); AddPropertyConverter( "proportional_xpos", &p_screenspace_intconverter_X ); AddPropertyConverter( "proportional_ypos", &p_screenspace_intconverter_Y ); AddPropertyConverter( "proportional_width", &proportional_width_converter ); AddPropertyConverter( "proportional_height", &proportional_height_converter ); AddPropertyConverter( "textureid", &textureidconverter ); } bool Panel::InternalRequestInfo( PanelAnimationMap *map, KeyValues *outputData ) { if ( !map ) return false; Assert( outputData ); char const *name = outputData->GetName(); PanelAnimationMapEntry *e = FindPanelAnimationEntry( name, map ); if ( e ) { IPanelAnimationPropertyConverter *converter = FindConverter( e->type() ); if ( converter ) { converter->GetData( this, outputData, e ); return true; } } return false; } bool Panel::InternalSetInfo( PanelAnimationMap *map, KeyValues *inputData ) { if ( !map ) return false; Assert( inputData ); char const *name = inputData->GetName(); PanelAnimationMapEntry *e = FindPanelAnimationEntry( name, map ); if ( e ) { IPanelAnimationPropertyConverter *converter = FindConverter( e->type() ); if ( converter ) { converter->SetData( this, inputData, e ); return true; } } return false; } PanelAnimationMapEntry *Panel::FindPanelAnimationEntry( char const *scriptname, PanelAnimationMap *map ) { if ( !map ) return NULL; Assert( scriptname ); // Look through mapping for entry int c = map->entries.Count(); for ( int i = 0; i < c; i++ ) { PanelAnimationMapEntry *e = &map->entries[ i ]; if ( !stricmp( e->name(), scriptname ) ) { return e; } } // Recurse if ( map->baseMap ) { return FindPanelAnimationEntry( scriptname, map->baseMap ); } return NULL; } // Recursively invoke settings for PanelAnimationVars void Panel::InternalApplySettings( PanelAnimationMap *map, KeyValues *inResourceData) { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - %s", __FUNCTION__, GetName() ); // Loop through keys KeyValues *kv; for ( kv = inResourceData->GetFirstSubKey(); kv; kv = kv->GetNextKey() ) { char const *varname = kv->GetName(); PanelAnimationMapEntry *entry = FindPanelAnimationEntry( varname, GetAnimMap() ); if ( entry ) { // Set value to value from script IPanelAnimationPropertyConverter *converter = FindConverter( entry->type() ); if ( converter ) { converter->SetData( this, inResourceData, entry ); } } } } //----------------------------------------------------------------------------- // Purpose: sets the default values of all CPanelAnimationVars //----------------------------------------------------------------------------- void Panel::InternalInitDefaultValues( PanelAnimationMap *map ) { _flags.ClearFlag( NEEDS_DEFAULT_SETTINGS_APPLIED ); // Look through mapping for entry int c = map->entries.Count(); for ( int i = 0; i < c; i++ ) { PanelAnimationMapEntry *e = &map->entries[ i ]; Assert( e ); IPanelAnimationPropertyConverter *converter = FindConverter( e->type() ); if ( !converter ) continue; converter->InitFromDefault( this, e ); } if ( map->baseMap ) { InternalInitDefaultValues( map->baseMap ); } } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- int Panel::GetPaintBackgroundType() { return m_nPaintBackgroundType; } //----------------------------------------------------------------------------- // Purpose: // Input : w - // h - //----------------------------------------------------------------------------- void Panel::GetCornerTextureSize( int& w, int& h ) { if ( m_nBgTextureId1 == -1 ) { w = h = 0; return; } surface()->DrawGetTextureSize(m_nBgTextureId1, w, h); } //----------------------------------------------------------------------------- // Purpose: draws a selection box //----------------------------------------------------------------------------- void Panel::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, bool hollow /*=false*/ ) { if ( m_nBgTextureId1 == -1 || m_nBgTextureId2 == -1 || m_nBgTextureId3 == -1 || m_nBgTextureId4 == -1 ) { return; } color[3] *= normalizedAlpha; // work out our bounds int cornerWide, cornerTall; GetCornerTextureSize( cornerWide, cornerTall ); // draw the background in the areas not occupied by the corners // draw it in three horizontal strips surface()->DrawSetColor(color); surface()->DrawFilledRect(x + cornerWide, y, x + wide - cornerWide, y + cornerTall); if ( !hollow ) { surface()->DrawFilledRect(x, y + cornerTall, x + wide, y + tall - cornerTall); } else { surface()->DrawFilledRect(x, y + cornerTall, x + cornerWide, y + tall - cornerTall); surface()->DrawFilledRect(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall); } surface()->DrawFilledRect(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall); // draw the corners //============================================================================= // HPE_BEGIN: // [tj] We now check each individual corner and decide whether to draw it straight or rounded //============================================================================= //TOP-LEFT if (ShouldDrawTopLeftCornerRounded()) { surface()->DrawSetTexture(m_nBgTextureId1); surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall); } else { surface()->DrawFilledRect(x, y, x + cornerWide, y + cornerTall); } //TOP-RIGHT if (ShouldDrawTopRightCornerRounded()) { surface()->DrawSetTexture(m_nBgTextureId2); surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall); } else { surface()->DrawFilledRect(x + wide - cornerWide, y, x + wide, y + cornerTall); } //BOTTOM-LEFT if (ShouldDrawBottomLeftCornerRounded()) { surface()->DrawSetTexture(m_nBgTextureId4); surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall); } else { surface()->DrawFilledRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall); } //BOTTOM-RIGHT if (ShouldDrawBottomRightCornerRounded()) { surface()->DrawSetTexture(m_nBgTextureId3); surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall); } else { surface()->DrawFilledRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall); } //============================================================================= // HPE_END //============================================================================= } void Panel::DrawBoxFade(int x, int y, int wide, int tall, Color color, float normalizedAlpha, unsigned int alpha0, unsigned int alpha1, bool bHorizontal, bool hollow /*=false*/ ) { if ( m_nBgTextureId1 == -1 || m_nBgTextureId2 == -1 || m_nBgTextureId3 == -1 || m_nBgTextureId4 == -1 || surface()->DrawGetAlphaMultiplier() == 0 ) { return; } color[3] *= normalizedAlpha; // work out our bounds int cornerWide, cornerTall; GetCornerTextureSize( cornerWide, cornerTall ); if ( !bHorizontal ) { // draw the background in the areas not occupied by the corners // draw it in three horizontal strips surface()->DrawSetColor(color); surface()->DrawFilledRectFade(x + cornerWide, y, x + wide - cornerWide, y + cornerTall, alpha0, alpha0, bHorizontal ); if ( !hollow ) { surface()->DrawFilledRectFade(x, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal); } else { surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha1, bHorizontal); surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal); } surface()->DrawFilledRectFade(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall, alpha1, alpha1, bHorizontal); } else { // draw the background in the areas not occupied by the corners // draw it in three horizontal strips surface()->DrawSetColor(color); surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha0, bHorizontal ); if ( !hollow ) { surface()->DrawFilledRectFade(x + cornerWide, y, x + wide - cornerWide, y + tall, alpha0, alpha1, bHorizontal); } else { // FIXME: Hollow horz version not implemented //surface()->DrawFilledRectFade(x, y + cornerTall, x + cornerWide, y + tall - cornerTall, alpha0, alpha1, bHorizontal); //surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha0, alpha1, bHorizontal); } surface()->DrawFilledRectFade(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall, alpha1, alpha1, bHorizontal); } float fOldAlpha = color[ 3 ]; int iAlpha0 = fOldAlpha * ( static_cast( alpha0 ) / 255.0f ); int iAlpha1 = fOldAlpha * ( static_cast( alpha1 ) / 255.0f ); // draw the corners if ( !bHorizontal ) { color[ 3 ] = iAlpha0; surface()->DrawSetColor( color ); surface()->DrawSetTexture(m_nBgTextureId1); surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall); surface()->DrawSetTexture(m_nBgTextureId2); surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall); color[ 3 ] = iAlpha1; surface()->DrawSetColor( color ); surface()->DrawSetTexture(m_nBgTextureId3); surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall); surface()->DrawSetTexture(m_nBgTextureId4); surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall); } else { color[ 3 ] = iAlpha0; surface()->DrawSetColor( color ); surface()->DrawSetTexture(m_nBgTextureId1); surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall); surface()->DrawSetTexture(m_nBgTextureId4); surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall); color[ 3 ] = iAlpha1; surface()->DrawSetColor( color ); surface()->DrawSetTexture(m_nBgTextureId2); surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall); surface()->DrawSetTexture(m_nBgTextureId3); surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall); } } //----------------------------------------------------------------------------- // Purpose: // Input : x - // y - // wide - // tall - // color - // normalizedAlpha - //----------------------------------------------------------------------------- void Panel::DrawHollowBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha ) { DrawBox( x, y, wide, tall, color, normalizedAlpha, true ); } //============================================================================= // HPE_BEGIN: // [menglish] Draws a hollow box similar to the already existing draw hollow box function, but takes the indents as params //============================================================================= void Panel::DrawHollowBox( int x, int y, int wide, int tall, Color color, float normalizedAlpha, int cornerWide, int cornerTall ) { if ( m_nBgTextureId1 == -1 || m_nBgTextureId2 == -1 || m_nBgTextureId3 == -1 || m_nBgTextureId4 == -1 ) { return; } color[3] *= normalizedAlpha; // draw the background in the areas not occupied by the corners // draw it in three horizontal strips surface()->DrawSetColor(color); surface()->DrawFilledRect(x + cornerWide, y, x + wide - cornerWide, y + cornerTall); surface()->DrawFilledRect(x, y + cornerTall, x + cornerWide, y + tall - cornerTall); surface()->DrawFilledRect(x + wide - cornerWide, y + cornerTall, x + wide, y + tall - cornerTall); surface()->DrawFilledRect(x + cornerWide, y + tall - cornerTall, x + wide - cornerWide, y + tall); // draw the corners surface()->DrawSetTexture(m_nBgTextureId1); surface()->DrawTexturedRect(x, y, x + cornerWide, y + cornerTall); surface()->DrawSetTexture(m_nBgTextureId2); surface()->DrawTexturedRect(x + wide - cornerWide, y, x + wide, y + cornerTall); surface()->DrawSetTexture(m_nBgTextureId3); surface()->DrawTexturedRect(x + wide - cornerWide, y + tall - cornerTall, x + wide, y + tall); surface()->DrawSetTexture(m_nBgTextureId4); surface()->DrawTexturedRect(x + 0, y + tall - cornerTall, x + cornerWide, y + tall); } //============================================================================= // HPE_END //============================================================================= //----------------------------------------------------------------------------- // Purpose: draws a selection box //----------------------------------------------------------------------------- void Panel::DrawTexturedBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha ) { if ( m_nBgTextureId1 == -1 ) return; color[3] *= normalizedAlpha; surface()->DrawSetColor( color ); surface()->DrawSetTexture(m_nBgTextureId1); surface()->DrawTexturedRect(x, y, x + wide, y + tall); } //----------------------------------------------------------------------------- // Purpose: Marks this panel as draggable (note that children will chain to their parents to see if any parent is draggable) // Input : enabled - //----------------------------------------------------------------------------- void Panel::SetDragEnabled( bool enabled ) { #if defined( VGUI_USEDRAGDROP ) // If turning it off, quit dragging if mid-drag if ( !enabled && m_pDragDrop->m_bDragging ) { OnFinishDragging( false, (MouseCode)-1 ); } m_pDragDrop->m_bDragEnabled = enabled; #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsDragEnabled() const { #if defined( VGUI_USEDRAGDROP ) return m_pDragDrop->m_bDragEnabled; #endif return false; } void Panel::SetShowDragHelper( bool enabled ) { #if defined( VGUI_USEDRAGDROP ) m_pDragDrop->m_bShowDragHelper = enabled; #endif } // Use this to prevent chaining up from a parent which can mess with mouse functionality if you don't want to chain up from a child panel to the best // draggable parent. void Panel::SetBlockDragChaining( bool block ) { #if defined( VGUI_USEDRAGDROP ) m_pDragDrop->m_bPreventChaining = block; #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsBlockingDragChaining() const { #if defined( VGUI_USEDRAGDROP ) return m_pDragDrop->m_bPreventChaining; #endif return true; } //----------------------------------------------------------------------------- // accessors for m_nDragStartTolerance //----------------------------------------------------------------------------- int Panel::GetDragStartTolerance() const { #if defined( VGUI_USEDRAGDROP ) return m_pDragDrop->m_nDragStartTolerance; #endif return 0; } void Panel::SetDragSTartTolerance( int nTolerance ) { #if defined( VGUI_USEDRAGDROP ) m_pDragDrop->m_nDragStartTolerance = nTolerance; #endif } //----------------------------------------------------------------------------- // Purpose: Marks this panel as droppable ( note that children will chain to their parents to see if any parent is droppable) // Input : enabled - //----------------------------------------------------------------------------- void Panel::SetDropEnabled( bool enabled, float flHoverContextTime /* = 0.0f */ ) { #if defined( VGUI_USEDRAGDROP ) m_pDragDrop->m_bDropEnabled = enabled; m_pDragDrop->m_flHoverContextTime = flHoverContextTime; #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsDropEnabled() const { #if defined( VGUI_USEDRAGDROP ) return m_pDragDrop->m_bDropEnabled; #endif return false; } //----------------------------------------------------------------------------- // Purpose: Chains up to any parent // 1) marked DropEnabled; and // 2) willing to accept the drop payload // Input : - // Output : Panel //----------------------------------------------------------------------------- Panel *Panel::GetDropTarget( CUtlVector< KeyValues * >& msglist ) { #if defined( VGUI_USEDRAGDROP ) // Found one if ( m_pDragDrop->m_bDropEnabled && IsDroppable( msglist ) ) { return this; } // Chain up if ( GetParent() ) { return GetParent()->GetDropTarget( msglist ); } #endif // No luck return NULL; } //----------------------------------------------------------------------------- // Purpose: Chains up to first parent marked DragEnabled // Input : - // Output : Panel //----------------------------------------------------------------------------- Panel *Panel::GetDragPanel() { #if defined( VGUI_USEDRAGDROP ) // If we encounter a blocker, stop chaining if ( m_pDragDrop->m_bPreventChaining ) return NULL; if ( m_pDragDrop->m_bDragEnabled ) return this; // Chain up if ( GetParent() ) { return GetParent()->GetDragPanel(); } #endif // No luck return NULL; } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- void Panel::OnStartDragging() { #if defined( VGUI_USEDRAGDROP ) // Only left mouse initiates drag/drop. // FIXME: Revisit? if ( !input()->IsMouseDown( MOUSE_LEFT ) ) return; if ( !m_pDragDrop->m_bDragEnabled ) return; if ( m_pDragDrop->m_bDragging ) return; g_DragDropCapture = this; m_pDragDrop->m_bDragStarted = false; m_pDragDrop->m_bDragging = true; input()->GetCursorPos( m_pDragDrop->m_nStartPos[ 0 ], m_pDragDrop->m_nStartPos[ 1 ] ); m_pDragDrop->m_nLastPos[ 0 ] = m_pDragDrop->m_nStartPos[ 0 ]; m_pDragDrop->m_nLastPos[ 1 ] = m_pDragDrop->m_nStartPos[ 1 ]; OnContinueDragging(); #endif } //----------------------------------------------------------------------------- // Purpose: Called if drag drop is started but not dropped on top of droppable panel... // Input : - //----------------------------------------------------------------------------- void Panel::OnDragFailed( CUtlVector< KeyValues * >& msglist ) { } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- void Panel::OnFinishDragging( bool mousereleased, MouseCode code, bool abort /*= false*/ ) { #if defined( VGUI_USEDRAGDROP ) g_DragDropCapture = NULL; if ( !m_pDragDrop->m_bDragEnabled ) return; Assert( m_pDragDrop->m_bDragging ); if ( !m_pDragDrop->m_bDragging ) return; int x, y; input()->GetCursorPos( x, y ); m_pDragDrop->m_nLastPos[ 0 ] = x; m_pDragDrop->m_nLastPos[ 1 ] = y; if ( s_DragDropHelper.Get() ) { s_DragDropHelper->RemovePanel( this ); } m_pDragDrop->m_bDragging = false; CUtlVector< KeyValues * >& data = m_pDragDrop->m_DragData; int nData = data.Count(); Panel *target = NULL; bool shouldDrop = false; if ( m_pDragDrop->m_bDragStarted ) { char cmd[ 256 ]; Q_strncpy( cmd, "default", sizeof( cmd ) ); if ( mousereleased && m_pDragDrop->m_hCurrentDrop != 0 && m_pDragDrop->m_hDropContextMenu.Get() ) { Menu *menu = m_pDragDrop->m_hDropContextMenu; VPANEL hover = menu->IsWithinTraverse( x, y, false ); if ( hover ) { Panel *pHover = ipanel()->GetPanel( hover, GetModuleName() ); if ( pHover ) { // Figure out if it's a menu item... int c = menu->GetItemCount(); for ( int i = 0; i < c; ++i ) { int id = menu->GetMenuID( i ); MenuItem *item = menu->GetMenuItem( id ); if ( item == pHover ) { KeyValues *command = item->GetCommand(); if ( command ) { char const *p = command->GetString( "command", "" ); if ( p && p[ 0 ] ) { Q_strncpy( cmd, p, sizeof( cmd ) ); } } } } } } delete menu; m_pDragDrop->m_hDropContextMenu = NULL; } for ( int i = 0 ; i < nData; ++i ) { KeyValues *msg = data[ i ]; msg->SetString( "command", cmd ); msg->SetInt( "screenx", x ); msg->SetInt( "screeny", y ); } target = m_pDragDrop->m_hCurrentDrop.Get(); if ( target && !abort ) { int localmousex = x, localmousey = y; // Convert screen space coordintes to coordinates relative to drop window target->ScreenToLocal( localmousex, localmousey ); for ( int i = 0 ; i < nData; ++i ) { KeyValues *msg = data[ i ]; msg->SetInt( "x", localmousex ); msg->SetInt( "y", localmousey ); } shouldDrop = true; } if ( !shouldDrop ) { OnDragFailed( data ); } } m_pDragDrop->m_bDragStarted = false; m_pDragDrop->m_DragPanels.RemoveAll(); m_pDragDrop->m_hCurrentDrop = NULL; // Copy data ptrs out of data because OnPanelDropped might cause this panel to be deleted // and our this ptr will be hosed... CUtlVector< KeyValues * > temp; for ( int i = 0 ; i < nData; ++i ) { temp.AddToTail( data[ i ] ); } data.RemoveAll(); if ( shouldDrop && target ) { target->OnPanelDropped( temp ); } for ( int i = 0 ; i < nData; ++i ) { temp[ i ]->deleteThis(); } #endif } void Panel::OnDropContextHoverShow( CUtlVector< KeyValues * >& msglist ) { } void Panel::OnDropContextHoverHide( CUtlVector< KeyValues * >& msglist ) { } //----------------------------------------------------------------------------- // Purpose: // Input : *msg - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsDroppable( CUtlVector< KeyValues * >& msglist ) { return false; } //----------------------------------------------------------------------------- // Purpose: // Input : startx - // starty - // mx - // my - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::CanStartDragging( int startx, int starty, int mx, int my ) { #if defined( VGUI_USEDRAGDROP ) if ( IsStartDragWhenMouseExitsPanel() ) { ScreenToLocal( mx, my ); if ( mx < 0 || my < 0 ) return true; if ( mx > GetWide() || my > GetTall() ) return true; return false; } int deltax = abs( mx - startx ); int deltay = abs( my - starty ); if ( deltax > m_pDragDrop->m_nDragStartTolerance || deltay > m_pDragDrop->m_nDragStartTolerance ) { return true; } #endif return false; } HCursor Panel::GetDropCursor( CUtlVector< KeyValues * >& msglist ) { return dc_arrow; } bool IsSelfDroppable( CUtlVector< KeyValues * > &dragData ) { if ( dragData.Count() == 0 ) return false; KeyValues *pKeyValues( dragData[ 0 ] ); if ( !pKeyValues ) return false; return pKeyValues->GetInt( "selfDroppable" ) != 0; } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- void Panel::OnContinueDragging() { #if defined( VGUI_USEDRAGDROP ) if ( !m_pDragDrop->m_bDragEnabled ) return; if ( !m_pDragDrop->m_bDragging ) return; int x, y; input()->GetCursorPos( x, y ); // Update last position m_pDragDrop->m_nLastPos[ 0 ] = x; m_pDragDrop->m_nLastPos[ 1 ] = y; if ( !m_pDragDrop->m_bDragStarted ) { if ( CanStartDragging( m_pDragDrop->m_nStartPos[ 0 ], m_pDragDrop->m_nStartPos[ 1 ], x, y ) ) { m_pDragDrop->m_bDragStarted = true; CreateDragData(); } else { return; } } if ( !s_DragDropHelper.Get() && m_pDragDrop->m_bShowDragHelper ) { s_DragDropHelper = new CDragDropHelperPanel(); s_DragDropHelper->SetKeyBoardInputEnabled( false ); s_DragDropHelper->SetMouseInputEnabled( false ); Assert( s_DragDropHelper.Get() ); } if ( !s_DragDropHelper.Get() ) return; s_DragDropHelper->AddPanel( this ); Assert( m_pDragDrop->m_DragData.Count() ); vgui::PHandle oldDrop = m_pDragDrop->m_hCurrentDrop; // See what's under that m_pDragDrop->m_hCurrentDrop = NULL; // Search under mouse pos... Panel *dropTarget = FindDropTargetPanel(); if ( dropTarget ) { dropTarget = dropTarget->GetDropTarget( m_pDragDrop->m_DragData ); } // it's not okay until we find a droppable panel surface()->SetCursor( dc_no ); if ( dropTarget ) { if ( dropTarget != this || IsSelfDroppable( m_pDragDrop->m_DragData ) ) { m_pDragDrop->m_hCurrentDrop = dropTarget; surface()->SetCursor( dropTarget->GetDropCursor( m_pDragDrop->m_DragData ) ); } } if ( m_pDragDrop->m_hCurrentDrop.Get() != oldDrop.Get() ) { if ( oldDrop.Get() ) { oldDrop->OnPanelExitedDroppablePanel( m_pDragDrop->m_DragData ); } if ( m_pDragDrop->m_hCurrentDrop.Get() ) { m_pDragDrop->m_hCurrentDrop->OnPanelEnteredDroppablePanel( m_pDragDrop->m_DragData ); m_pDragDrop->m_hCurrentDrop->OnDropContextHoverHide( m_pDragDrop->m_DragData ); // Reset hover time m_pDragDrop->m_lDropHoverTime = system()->GetTimeMillis(); m_pDragDrop->m_bDropMenuShown = false; } // Discard any stale context menu... if ( m_pDragDrop->m_hDropContextMenu.Get() ) { delete m_pDragDrop->m_hDropContextMenu.Get(); } } if ( m_pDragDrop->m_hCurrentDrop != 0 && m_pDragDrop->m_hDropContextMenu.Get() ) { Menu *menu = m_pDragDrop->m_hDropContextMenu; VPANEL hover = menu->IsWithinTraverse( x, y, false ); if ( hover ) { Panel *pHover = ipanel()->GetPanel( hover, GetModuleName() ); if ( pHover ) { // Figure out if it's a menu item... int c = menu->GetItemCount(); for ( int i = 0; i < c; ++i ) { int id = menu->GetMenuID( i ); MenuItem *item = menu->GetMenuItem( id ); if ( item == pHover ) { menu->SetCurrentlyHighlightedItem( id ); } } } } else { menu->ClearCurrentlyHighlightedItem(); } } #endif } #if defined( VGUI_USEDRAGDROP ) //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : DragDrop_t //----------------------------------------------------------------------------- DragDrop_t *Panel::GetDragDropInfo() { Assert( m_pDragDrop ); return m_pDragDrop; } #endif void Panel::OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles ) { // Nothing here } //----------------------------------------------------------------------------- // Purpose: Virtual method to allow panels to add to the default values // Input : *msg - //----------------------------------------------------------------------------- void Panel::OnCreateDragData( KeyValues *msg ) { // These values are filled in for you: // "panel" ptr to panel being dropped // "screenx", "screeny" - drop cursor pos in screen space // "x", "y" - drop coordinates relative to this window (the window being dropped upon) } // Called if m_flHoverContextTime was non-zero, allows droppee to preview the drop data and show an appropriate menu bool Panel::GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist ) { return false; } void Panel::CreateDragData() { #if defined( VGUI_USEDRAGDROP ) int i, c; if ( m_pDragDrop->m_DragData.Count() ) { return; } PHandle h; h = this; m_pDragDrop->m_DragPanels.AddToTail( h ); CUtlVector< Panel * > temp; OnGetAdditionalDragPanels( temp ); c = temp.Count(); for ( i = 0; i < c; ++i ) { h = temp[ i ]; m_pDragDrop->m_DragPanels.AddToTail( h ); } c = m_pDragDrop->m_DragPanels.Count(); for ( i = 0 ; i < c; ++i ) { Panel *sibling = m_pDragDrop->m_DragPanels[ i ].Get(); if ( !sibling ) { continue; } KeyValues *msg = new KeyValues( "DragDrop" ); msg->SetPtr( "panel", sibling ); sibling->OnCreateDragData( msg ); m_pDragDrop->m_DragData.AddToTail( msg ); } #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : KeyValues //----------------------------------------------------------------------------- void Panel::GetDragData( CUtlVector< KeyValues * >& list ) { #if defined( VGUI_USEDRAGDROP ) int i, c; list.RemoveAll(); c = m_pDragDrop->m_DragData.Count(); for ( i = 0 ; i < c; ++i ) { list.AddToTail( m_pDragDrop->m_DragData[ i ] ); } #endif } #if defined( VGUI_USEDRAGDROP ) CDragDropHelperPanel::CDragDropHelperPanel() : BaseClass( NULL, "DragDropHelper" ) { SetVisible( true ); SetPaintEnabled( false ); SetPaintBackgroundEnabled( false ); SetMouseInputEnabled( false ); SetKeyBoardInputEnabled( false ); // SetCursor( dc_none ); ipanel()->SetTopmostPopup( GetVPanel(), true ); int w, h; surface()->GetScreenSize( w, h ); SetBounds( 0, 0, w, h ); SetPostChildPaintEnabled( true ); MakePopup( false ); } VPANEL CDragDropHelperPanel::IsWithinTraverse(int x, int y, bool traversePopups) { return (VPANEL)0; } void CDragDropHelperPanel::PostChildPaint() { int c = m_PaintList.Count(); for ( int i = c - 1; i >= 0 ; --i ) { DragHelperPanel_t& data = m_PaintList[ i ]; Panel *panel = data.m_hPanel.Get(); if ( !panel ) { m_PaintList.Remove( i ); continue; } Panel *dropPanel = panel->GetDragDropInfo()->m_hCurrentDrop.Get(); if ( panel ) { if ( !dropPanel ) { panel->OnDraggablePanelPaint(); } else { CUtlVector< Panel * > temp; CUtlVector< PHandle >& dragData = panel->GetDragDropInfo()->m_DragPanels; CUtlVector< KeyValues * >& msglist = panel->GetDragDropInfo()->m_DragData; int j, nDragData; nDragData = dragData.Count(); for ( j = 0; j < nDragData; ++j ) { Panel *pPanel = dragData[ j ].Get(); if ( pPanel ) { temp.AddToTail( pPanel ); } } dropPanel->OnDroppablePanelPaint( msglist, temp ); } } } if ( c == 0 ) { MarkForDeletion(); } } void CDragDropHelperPanel::AddPanel( Panel *current ) { if ( !current ) return; Menu *hover = current->GetDragDropInfo()->m_hDropContextMenu.Get(); surface()->MovePopupToFront( GetVPanel() ); if ( hover && hover->IsPopup() ) { surface()->MovePopupToFront( hover->GetVPanel() ); } int c = m_PaintList.Count(); for ( int i = 0; i < c; ++i ) { if ( m_PaintList[ i ].m_hPanel.Get() == current ) return; } DragHelperPanel_t data; data.m_hPanel = current; m_PaintList.AddToTail( data ); } //----------------------------------------------------------------------------- // Purpose: // Input : *search - //----------------------------------------------------------------------------- void CDragDropHelperPanel::RemovePanel( Panel *search ) { int c = m_PaintList.Count(); for ( int i = c - 1 ; i >= 0; --i ) { if ( m_PaintList[ i ].m_hPanel.Get() == search ) { m_PaintList.Remove( i ); return; } } } #endif //----------------------------------------------------------------------------- // Purpose: Enumerates panels under mouse x,y // Input : panelList - // x - // y - // check - //----------------------------------------------------------------------------- void Panel::FindDropTargetPanel_R( CUtlVector< VPANEL >& panelList, int x, int y, VPANEL check ) { #if defined( VGUI_USEDRAGDROP ) if ( !ipanel()->IsFullyVisible( check ) ) return; if ( ::ShouldHandleInputMessage( check ) && ipanel()->IsWithinTraverse( check, x, y, false ) ) { panelList.AddToTail( check ); } CUtlVector< VPANEL > &children = ipanel()->GetChildren( check ); int childCount = children.Count(); for ( int i = 0; i < childCount; i++ ) { VPANEL child = children[ i ]; FindDropTargetPanel_R( panelList, x, y, child ); } #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Panel //----------------------------------------------------------------------------- Panel *Panel::FindDropTargetPanel() { #if defined( VGUI_USEDRAGDROP ) if ( !s_DragDropHelper.Get() ) return NULL; CUtlVector< VPANEL > hits; int x, y; input()->GetCursorPos( x, y ); VPANEL embedded = surface()->GetEmbeddedPanel(); VPANEL helper = s_DragDropHelper.Get()->GetVPanel(); if ( surface()->IsCursorVisible() && surface()->IsWithin(x, y) ) { // faster version of code below // checks through each popup in order, top to bottom windows int c = surface()->GetPopupCount(); for (int i = c - 1; i >= 0 && hits.Count() == 0; i--) { VPANEL popup = surface()->GetPopup(i); if ( popup == embedded ) continue; // Don't return helper panel!!! if ( popup == helper ) continue; if ( !ipanel()->IsFullyVisible( popup ) ) continue; FindDropTargetPanel_R( hits, x, y, popup ); } // Check embedded if ( !hits.Count() ) { FindDropTargetPanel_R( hits, x, y, embedded ); } } // Nothing under mouse... if ( !hits.Count() ) return NULL; // Return topmost panel under mouse, if it's visible to this .dll Panel *panel = NULL; int nCount = hits.Count(); while ( --nCount >= 0 ) { panel = ipanel()->GetPanel( hits[ nCount ], GetModuleName() ); if ( panel ) return panel; } #endif return NULL; } //----------------------------------------------------------------------------- // Purpose: Mouse is on draggable panel and has started moving, but is not over a droppable panel yet // Input : - //----------------------------------------------------------------------------- void Panel::OnDraggablePanelPaint() { #if defined( VGUI_USEDRAGDROP ) int sw, sh; GetSize( sw, sh ); int x, y; input()->GetCursorPos( x, y ); int w, h; w = min( sw, 80 ); h = min( sh, 80 ); x -= ( w >> 1 ); y -= ( h >> 1 ); surface()->DrawSetColor( m_clrDragFrame ); surface()->DrawOutlinedRect( x, y, x + w, y + h ); if ( m_pDragDrop->m_DragPanels.Count() > 1 ) { surface()->DrawSetTextColor( m_clrDragFrame ); surface()->DrawSetTextFont( m_infoFont ); surface()->DrawSetTextPos( x + 5, y + 2 ); wchar_t sz[ 64 ]; V_swprintf_safe( sz, L"[ %i ]", m_pDragDrop->m_DragPanels.Count() ); surface()->DrawPrintText( sz, wcslen( sz ) ); } #endif } //----------------------------------------------------------------------------- // Purpose: Mouse is now over a droppable panel // Input : *dragPanel - //----------------------------------------------------------------------------- void Panel::OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels ) { #if defined( VGUI_USEDRAGDROP ) if ( !dragPanels.Count() ) return; // Convert this panel's bounds to screen space int w, h; GetSize( w, h ); int x, y; x = y = 0; LocalToScreen( x, y ); surface()->DrawSetColor( m_clrDropFrame ); // Draw 2 pixel frame surface()->DrawOutlinedRect( x, y, x + w, y + h ); surface()->DrawOutlinedRect( x+1, y+1, x + w-1, y + h-1 ); #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Color //----------------------------------------------------------------------------- Color Panel::GetDropFrameColor() { #if defined( VGUI_USEDRAGDROP ) return m_clrDropFrame; #endif return Color(0, 0, 0, 0); } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Color //----------------------------------------------------------------------------- Color Panel::GetDragFrameColor() { #if defined( VGUI_USEDRAGDROP ) return m_clrDragFrame; #endif return Color(0, 0, 0, 0); } //----------------------------------------------------------------------------- // Purpose: // Input : *data - //----------------------------------------------------------------------------- void Panel::OnPanelDropped( CUtlVector< KeyValues * >& data ) { // Empty. Derived classes would implement handlers here } //----------------------------------------------------------------------------- // called on droptarget when draggable panel enters droptarget //----------------------------------------------------------------------------- void Panel::OnPanelEnteredDroppablePanel( CUtlVector< KeyValues * >& msglist ) { // Empty. Derived classes would implement handlers here } //----------------------------------------------------------------------------- // called on droptarget when draggable panel exits droptarget //----------------------------------------------------------------------------- void Panel::OnPanelExitedDroppablePanel ( CUtlVector< KeyValues * >& msglist ) { // Empty. Derived classes would implement handlers here } //----------------------------------------------------------------------------- // Purpose: // Input : - //----------------------------------------------------------------------------- void Panel::DragDropStartDragging() { #if defined( VGUI_USEDRAGDROP ) // We somehow missed a mouse release, cancel the previous drag if ( g_DragDropCapture.Get() ) { if ( HasParent( g_DragDropCapture.Get()->GetVPanel() ) ) return; bool started = g_DragDropCapture->GetDragDropInfo()->m_bDragStarted; g_DragDropCapture->OnFinishDragging( true, (MouseCode)-1 ); if ( started ) { return; } } // Find actual target panel Panel *panel = GetDragPanel(); if ( !panel ) return; DragDrop_t *data = panel->GetDragDropInfo(); if ( !data ) return; if ( !panel->IsDragEnabled() ) return; if ( data->m_bDragging ) return; panel->OnStartDragging(); #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Panel::IsBeingDragged() { #if defined( VGUI_USEDRAGDROP ) if ( !g_DragDropCapture.Get() ) return false; if ( g_DragDropCapture.Get() == this ) return true; // If we encounter a blocker, stop chaining if ( m_pDragDrop->m_bPreventChaining ) return false; // Chain up if ( GetParent() ) { return GetParent()->IsBeingDragged(); } #endif // No luck return false; } struct srect_t { int x0, y0; int x1, y1; bool IsDegenerate() { if ( x1 - x0 <= 0 ) return true; if ( y1 - y0 <= 0 ) return true; return false; } }; // Draws a filled rect of specified bounds, but omits the bounds of the skip panel from those bounds void Panel::FillRectSkippingPanel( const Color &clr, int x, int y, int w, int h, Panel *skipPanel ) { int sx = 0, sy = 0, sw, sh; skipPanel->GetSize( sw, sh ); skipPanel->LocalToScreen( sx, sy ); ScreenToLocal( sx, sy ); surface()->DrawSetColor( clr ); srect_t r1; r1.x0 = x; r1.y0 = y; r1.x1 = x + w; r1.y1 = y + h; srect_t r2; r2.x0 = sx; r2.y0 = sy; r2.x1 = sx + sw; r2.y1 = sy + sh; int topy = r1.y0; int bottomy = r1.y1; // We'll descend vertically and draw: // 1 a possible bar across the top // 2 a possible bar across the bottom // 3 possible left bar // 4 possible right bar // Room at top? if ( r2.y0 > r1.y0 ) { topy = r2.y0; surface()->DrawFilledRect( r1.x0, r1.y0, r1.x1, topy ); } // Room at bottom? if ( r2.y1 < r1.y1 ) { bottomy = r2.y1; surface()->DrawFilledRect( r1.x0, bottomy, r1.x1, r1.y1 ); } // Room on left side? if ( r2.x0 > r1.x0 ) { int left = r2.x0; surface()->DrawFilledRect( r1.x0, topy, left, bottomy ); } // Room on right side if ( r2.x1 < r1.x1 ) { int right = r2.x1; surface()->DrawFilledRect( right, topy, r1.x1, bottomy ); } } //----------------------------------------------------------------------------- // Purpose: // Input : *child - //----------------------------------------------------------------------------- void Panel::SetSkipChildDuringPainting( Panel *child ) { m_SkipChild = child; } HPanel Panel::ToHandle() const { return ivgui()->PanelToHandle( _vpanel ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::NavigateUp() { Panel *target = GetNavUp(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_UP; target->NavigateTo(); } return target; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::NavigateDown() { Panel *target = GetNavDown(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_DOWN; target->NavigateTo(); } return target; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::NavigateLeft() { Panel *target = GetNavLeft(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_LEFT; target->NavigateTo(); } return target; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::NavigateRight() { Panel *target = GetNavRight(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_RIGHT; target->NavigateTo(); } return target; } Panel* Panel::NavigateActivate() { Panel *target = GetNavActivate(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_NONE; target->NavigateTo(); } return target; } Panel* Panel::NavigateBack() { Panel *target = GetNavBack(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_NONE; target->NavigateTo(); } return target; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::NavigateTo() { if ( IsX360() ) { RequestFocus( 0 ); } CallParentFunction( new KeyValues( "OnNavigateTo", "panelName", GetName() ) ); Panel *target = GetNavToRelay(); if ( target ) { NavigateFrom(); target->m_LastNavDirection = ND_NONE; NavigateToChild( target ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::NavigateFrom() { for ( int i = 0; i < GetChildCount(); ++i ) { Panel* currentNav = GetChild(i); if ( currentNav != 0 ) { currentNav->NavigateFrom(); } } CallParentFunction( new KeyValues( "OnNavigateFrom", "panelName", GetName() ) ); if ( m_pTooltips ) { m_pTooltips->HideTooltip(); } m_LastNavDirection = ND_NONE; } void Panel::NavigateToChild( Panel *pNavigateTo ) { for( int i = 0; i != GetChildCount(); ++i ) { vgui::Panel *pChild = GetChild(i); if( pChild ) pChild->NavigateFrom(); } pNavigateTo->NavigateTo(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::SetNavUp( Panel* navUp ) { Panel* lastNav = m_NavUp; m_NavUp = navUp; if( navUp ) m_sNavUpName = navUp->GetName(); else m_sNavUpName.Clear(); return lastNav; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::SetNavDown( Panel* navDown ) { Panel* lastNav = m_NavDown; m_NavDown = navDown; if( navDown ) m_sNavDownName = navDown->GetName(); else m_sNavDownName.Clear(); return lastNav; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::SetNavLeft( Panel* navLeft ) { Panel* lastNav = m_NavLeft; m_NavLeft = navLeft; if( navLeft ) m_sNavLeftName = navLeft->GetName(); else m_sNavLeftName.Clear(); return lastNav; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel* Panel::SetNavRight( Panel* navRight ) { Panel* lastNav = m_NavRight; m_NavRight = navRight; if( navRight ) m_sNavRightName = navRight->GetName(); else m_sNavRightName.Clear(); return lastNav; } Panel* Panel::SetNavToRelay( Panel* navToRelay ) { Panel* lastNav = m_NavToRelay; m_NavToRelay = navToRelay; return lastNav; } Panel* Panel::SetNavActivate( Panel* navActivate ) { Panel* lastNav = m_NavActivate; m_NavActivate = navActivate; return lastNav; } Panel* Panel::SetNavBack( Panel* navBack ) { Panel* lastNav = m_NavBack; m_NavBack = navBack; return lastNav; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Panel::NAV_DIRECTION Panel::GetLastNavDirection() { return m_LastNavDirection; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::OnNavigateTo( const char* panelName ) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::OnNavigateFrom( const char* panelName ) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetNavUp( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavUp = NULL; m_sNavUpName = controlName; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetNavDown( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavDown = NULL; m_sNavDownName = controlName; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetNavLeft( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavLeft = NULL; m_sNavLeftName = controlName; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Panel::SetNavRight( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavRight = NULL; m_sNavRightName = controlName; } } void Panel::SetNavToRelay( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavToRelay = NULL; m_sNavToRelayName = controlName; } } void Panel::SetNavActivate( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavActivate = NULL; m_sNavActivateName = controlName; } } void Panel::SetNavBack( const char* controlName ) { if ( controlName && 0 < Q_strlen( controlName ) && GetParent() != 0 ) { m_NavBack = NULL; m_sNavBackName = controlName; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- vgui::Panel* Panel::GetNavUp( Panel *first ) { if ( !m_NavUp && m_sNavUpName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavUpName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel *foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavUp = foundPanel; } } vgui::Panel* nextPanel = m_NavUp; if( m_NavUp && m_NavUp != first && !m_NavUp->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavUp( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavDown( Panel *first ) { if ( !m_NavDown && m_sNavDownName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavDownName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel* foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavDown = foundPanel->GetPanel(); } } vgui::Panel* nextPanel = m_NavDown; if( m_NavDown && m_NavDown != first && !m_NavDown->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavDown( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavLeft( Panel *first ) { if ( !m_NavLeft && m_sNavLeftName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavLeftName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel* foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavLeft = foundPanel->GetPanel(); } } vgui::Panel* nextPanel = m_NavLeft; if( m_NavLeft && m_NavLeft != first && !m_NavLeft->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavLeft( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavRight( Panel *first ) { if ( !m_NavRight && m_sNavRightName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavRightName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel* foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavRight = foundPanel->GetPanel(); } } vgui::Panel* nextPanel = m_NavRight; if( m_NavRight && m_NavRight != first && !m_NavRight->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavRight( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavToRelay( Panel *first ) { if ( !m_NavToRelay && m_sNavToRelayName.Length() > 0 ) { Panel *pParent = this; const char *pName = m_sNavToRelayName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel* foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavToRelay = foundPanel->GetPanel(); } } vgui::Panel* nextPanel = m_NavToRelay; if ( m_NavToRelay && m_NavToRelay != first && !m_NavToRelay->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavToRelay( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavActivate( Panel *first ) { if ( !m_NavActivate && m_sNavActivateName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavActivateName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel* foundPanel = pParent->FindChildByName( pName, true ); if ( foundPanel != 0 ) { m_NavActivate = foundPanel->GetPanel(); } } vgui::Panel* nextPanel = m_NavActivate; if ( m_NavActivate && m_NavActivate != first && !m_NavActivate->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavActivate( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavBack( Panel *first ) { if ( !m_NavBack && m_sNavBackName.Length() > 0 ) { Panel *pParent = GetParent(); const char *pName = m_sNavBackName.String(); while ( pParent && pName[ 0 ] == '<' ) { pParent = pParent->GetParent(); pName++; } if ( !pParent ) { return NULL; } Panel *foundPanel = pParent->FindChildByName( pName ); if ( foundPanel ) { m_NavBack = foundPanel; } } vgui::Panel* nextPanel = m_NavBack; if ( m_NavBack && m_NavBack != first && !m_NavBack->IsVisible() ) { Panel *firstPanel = first == NULL ? this : first; nextPanel = nextPanel->GetNavBack( firstPanel ); } return nextPanel; } vgui::Panel* Panel::GetNavUpPanel() { return m_NavUp; } vgui::Panel* Panel::GetNavDownPanel() { return m_NavDown; } vgui::Panel* Panel::GetNavLeftPanel() { return m_NavLeft; } vgui::Panel* Panel::GetNavRightPanel() { return m_NavRight; } vgui::Panel* Panel::GetNavToRelayPanel() { return m_NavToRelay; } vgui::Panel* Panel::GetNavActivatePanel() { return m_NavActivate; } vgui::Panel* Panel::GetNavBackPanel() { return m_NavBack; } void Panel::SetConsoleStylePanel( bool bConsoleStyle ) { m_bIsConsoleStylePanel = bConsoleStyle; } bool Panel::IsConsoleStylePanel() const { return m_bIsConsoleStylePanel; } //----------------------------------------------------------------------------- // Purpose: Utility class for handling message map allocation //----------------------------------------------------------------------------- class CPanelMessageMapDictionary { public: CPanelMessageMapDictionary() : m_PanelMessageMapPool( sizeof(PanelMessageMap), 32, CUtlMemoryPool::GROW_FAST, "CPanelMessageMapDictionary::m_PanelMessageMapPool" ) { m_MessageMaps.RemoveAll(); } PanelMessageMap *FindOrAddPanelMessageMap( char const *className ); PanelMessageMap *FindPanelMessageMap( char const *className ); private: struct PanelMessageMapDictionaryEntry { PanelMessageMap *map; }; char const *StripNamespace( char const *className ); CUtlDict< PanelMessageMapDictionaryEntry, int > m_MessageMaps; CUtlMemoryPool m_PanelMessageMapPool; }; char const *CPanelMessageMapDictionary::StripNamespace( char const *className ) { if ( !strnicmp( className, "vgui::", 6 ) ) { return className + 6; } return className; } //----------------------------------------------------------------------------- // Purpose: Find but don't add mapping //----------------------------------------------------------------------------- PanelMessageMap *CPanelMessageMapDictionary::FindPanelMessageMap( char const *className ) { int lookup = m_MessageMaps.Find( StripNamespace( className ) ); if ( lookup != m_MessageMaps.InvalidIndex() ) { return m_MessageMaps[ lookup ].map; } return NULL; } #include //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- PanelMessageMap *CPanelMessageMapDictionary::FindOrAddPanelMessageMap( char const *className ) { PanelMessageMap *map = FindPanelMessageMap( className ); if ( map ) return map; PanelMessageMapDictionaryEntry entry; // use the alloc in place method of new entry.map = new (m_PanelMessageMapPool.Alloc(sizeof(PanelMessageMap))) PanelMessageMap; Construct(entry.map); m_MessageMaps.Insert( StripNamespace( className ), entry ); return entry.map; } #include #if defined( VGUI_USEKEYBINDINGMAPS ) //----------------------------------------------------------------------------- // Purpose: Utility class for handling keybinding map allocation //----------------------------------------------------------------------------- class CPanelKeyBindingMapDictionary { public: CPanelKeyBindingMapDictionary() : m_PanelKeyBindingMapPool( sizeof(PanelKeyBindingMap), 32, CUtlMemoryPool::GROW_FAST, "CPanelKeyBindingMapDictionary::m_PanelKeyBindingMapPool" ) { m_MessageMaps.RemoveAll(); } PanelKeyBindingMap *FindOrAddPanelKeyBindingMap( char const *className ); PanelKeyBindingMap *FindPanelKeyBindingMap( char const *className ); private: struct PanelKeyBindingMapDictionaryEntry { PanelKeyBindingMap *map; }; char const *StripNamespace( char const *className ); CUtlDict< PanelKeyBindingMapDictionaryEntry, int > m_MessageMaps; CUtlMemoryPool m_PanelKeyBindingMapPool; }; char const *CPanelKeyBindingMapDictionary::StripNamespace( char const *className ) { if ( !strnicmp( className, "vgui::", 6 ) ) { return className + 6; } return className; } //----------------------------------------------------------------------------- // Purpose: Find but don't add mapping //----------------------------------------------------------------------------- PanelKeyBindingMap *CPanelKeyBindingMapDictionary::FindPanelKeyBindingMap( char const *className ) { int lookup = m_MessageMaps.Find( StripNamespace( className ) ); if ( lookup != m_MessageMaps.InvalidIndex() ) { return m_MessageMaps[ lookup ].map; } return NULL; } #include //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- PanelKeyBindingMap *CPanelKeyBindingMapDictionary::FindOrAddPanelKeyBindingMap( char const *className ) { PanelKeyBindingMap *map = FindPanelKeyBindingMap( className ); if ( map ) return map; PanelKeyBindingMapDictionaryEntry entry; // use the alloc in place method of new entry.map = new (m_PanelKeyBindingMapPool.Alloc(sizeof(PanelKeyBindingMap))) PanelKeyBindingMap; Construct(entry.map); m_MessageMaps.Insert( StripNamespace( className ), entry ); return entry.map; } #include CPanelKeyBindingMapDictionary& GetPanelKeyBindingMapDictionary() { static CPanelKeyBindingMapDictionary dictionary; return dictionary; } #endif // VGUI_USEKEYBINDINGMAPS CPanelMessageMapDictionary& GetPanelMessageMapDictionary() { static CPanelMessageMapDictionary dictionary; return dictionary; } namespace vgui { //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- PanelMessageMap *FindOrAddPanelMessageMap( char const *className ) { return GetPanelMessageMapDictionary().FindOrAddPanelMessageMap( className ); } //----------------------------------------------------------------------------- // Purpose: Find but don't add mapping //----------------------------------------------------------------------------- PanelMessageMap *FindPanelMessageMap( char const *className ) { return GetPanelMessageMapDictionary().FindPanelMessageMap( className ); } #if defined( VGUI_USEKEYBINDINGMAPS ) CPanelKeyBindingMapDictionary& GetPanelKeyBindingMapDictionary() { static CPanelKeyBindingMapDictionary dictionary; return dictionary; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- PanelKeyBindingMap *FindOrAddPanelKeyBindingMap( char const *className ) { return GetPanelKeyBindingMapDictionary().FindOrAddPanelKeyBindingMap( className ); } //----------------------------------------------------------------------------- // Purpose: Find but don't add mapping //----------------------------------------------------------------------------- PanelKeyBindingMap *FindPanelKeyBindingMap( char const *className ) { return GetPanelKeyBindingMapDictionary().FindPanelKeyBindingMap( className ); } #endif // VGUI_USEKEYBINDINGMAPS SortedPanel_t::SortedPanel_t( Panel *panel ) { pPanel = panel; pButton = dynamic_cast< Button* >( panel ); } void VguiPanelGetSortedChildPanelList( Panel *pParentPanel, void *pSortedPanels ) { CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels ); for ( int i = 0; i < pParentPanel->GetChildCount(); i++ ) { // perform auto-layout on the child panel Panel *pPanel = pParentPanel->GetChild( i ); if ( !pPanel || !pPanel->IsVisible() ) continue; pList->Insert( SortedPanel_t( static_cast< Panel* >( pPanel ) ) ); } } void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, char *pchFilter /*= NULL*/, int nFilterType /*= 0*/ ) { CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels ); for ( int i = 0; i < pParentPanel->GetChildCount(); i++ ) { // perform auto-layout on the child panel Button *pPanel = dynamic_cast< Button* >( pParentPanel->GetChild( i ) ); if ( !pPanel || !pPanel->IsVisible() ) continue; if ( pchFilter && pchFilter[ 0 ] != '\0' ) { char szBuff[ 128 ]; pPanel->GetText( szBuff, sizeof( szBuff ) ); // Prefix if ( nFilterType == 0 ) { if ( !StringHasPrefix( szBuff, pchFilter ) ) { continue; } } // Substring else if ( nFilterType == 1 ) { if ( V_strstr( szBuff, pchFilter ) == NULL ) { continue; } } } pList->Insert( SortedPanel_t( pPanel ) ); } } int VguiPanelNavigateSortedChildButtonList( void *pSortedPanels, int nDir ) { CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels ); if ( pList->Count() <= 0 ) return -1; if ( nDir != 0 ) { int nArmed = -1; for ( int i = 0; i < pList->Count(); i++ ) { if ( (*pList)[ i ].pButton->IsArmed() ) { nArmed = i; break; } } if ( nArmed == -1 ) { (*pList)[ 0 ].pButton->SetArmed( true ); return 0; } else { int nNewArmed = clamp( nArmed + nDir, 0, pList->Count() - 1 ); if ( nNewArmed != nArmed ) { (*pList)[ nArmed ].pButton->SetArmed( false ); } (*pList)[ nNewArmed ].pButton->RequestFocus(); (*pList)[ nNewArmed ].pButton->SetArmed( true ); return nNewArmed; } } return -1; } int ComputeWide(Panel* pPanel, unsigned int& nBuildFlags, KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingOther) { int wide = pPanel->GetWide(); const char *wstr = inResourceData->GetString("wide", NULL); if (wstr) { if (wstr[0] == 'f' || wstr[0] == 'F') { nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_FULL; wstr++; } else { if (wstr[0] == 'o' || wstr[0] == 'O') { wstr++; if (bComputingOther) { Warning("Wide and Tall of panel %s are set to be each other!\n", pPanel->GetName()); return 0; } nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL; wide = ComputeTall(pPanel, nBuildFlags, inResourceData, nParentWide, nParentTall, true); if (pPanel->IsProportional()) { wide = scheme()->GetProportionalNormalizedValue(wide); } } else if (wstr[0] == 'p' || wstr[0] == 'P') { nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL; wstr++; } else if (wstr[0] == 's' || wstr[0] == 'S') { nBuildFlags |= Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_SELF; wstr++; } } float flWide = atof(wstr); if (!(nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL)) { wide = atoi(wstr); } if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_TALL) { wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide); wide *= flWide; } else if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL) { wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide); wide = nParentWide - wide; wide *= flWide; } else if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_PROPORTIONAL_SELF) { wide = pPanel->GetWide() * flWide; } else { if (pPanel->IsProportional()) { // scale the width up to our screen co-ords wide = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), wide); } // now correct the alignment if (nBuildFlags & Panel::BUILDMODE_SAVE_WIDE_FULL) { wide = nParentWide - wide; } } } return wide; } int ComputeTall(Panel* pPanel, unsigned int& nBuildFlags, KeyValues *inResourceData, int nParentWide, int nParentTall, bool bComputingOther) { int tall = pPanel->GetTall(); // allow tall to be use the "fill" option, set to the height of the parent/screen const char *tstr = inResourceData->GetString("tall", NULL); if (tstr) { if (tstr[0] == 'f' || tstr[0] == 'F') { nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_FULL; tstr++; } else { if (tstr[0] == 'o' || tstr[0] == 'O') { tstr++; if (bComputingOther) { Warning("Wide and Tall of panel %s are set to be each other!\n", pPanel->GetName()); return 0; } nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE; tall = ComputeWide(pPanel, nBuildFlags, inResourceData, nParentWide, nParentTall, true); if (pPanel->IsProportional()) { tall = scheme()->GetProportionalNormalizedValue(tall); } } else if (tstr[0] == 'p' || tstr[0] == 'P') { nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL; tstr++; } else if (tstr[0] == 's' || tstr[0] == 'S') { nBuildFlags |= Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_SELF; tstr++; } } float flTall = atof(tstr); if (!(nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE)) { tall = atoi(tstr); } if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_WIDE) { tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall); tall *= flTall; } else if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL) { // scale the height up to our screen co-ords tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall); tall = nParentTall - tall; tall *= flTall; } else if(nBuildFlags & Panel::BUILDMODE_SAVE_TALL_PROPORTIONAL_SELF) { tall = pPanel->GetTall() * flTall; } else { if (pPanel->IsProportional()) { // scale the height up to our screen co-ords tall = scheme()->GetProportionalScaledValueEx(pPanel->GetScheme(), tall); } // now correct the alignment if (nBuildFlags & Panel::BUILDMODE_SAVE_TALL_FULL) { tall = nParentTall - tall; } } } return tall; } int ComputePos( Panel* pPanel, const char *pszInput, int &nPos, const int& nSize, const int& nParentSize, const bool& bX, EOperator eOp) { const int nFlagRightAlign = bX ? Panel::BUILDMODE_SAVE_XPOS_RIGHTALIGNED : Panel::BUILDMODE_SAVE_YPOS_BOTTOMALIGNED; const int nFlagCenterAlign = bX ? Panel::BUILDMODE_SAVE_XPOS_CENTERALIGNED : Panel::BUILDMODE_SAVE_YPOS_CENTERALIGNED; const int nFlagProportionalSelf = bX ? Panel::BUILDMODE_SAVE_XPOS_PROPORTIONAL_SELF : Panel::BUILDMODE_SAVE_YPOS_PROPORTIONAL_SELF; const int nFlagProportionalParent = bX ? Panel::BUILDMODE_SAVE_XPOS_PROPORTIONAL_PARENT : Panel::BUILDMODE_SAVE_YPOS_PROPORTIONAL_PARENT; int nFlags = 0; int nPosDelta = 0; if (pszInput) { // look for alignment flags if (pszInput[0] == 'r' || pszInput[0] == 'R') { nFlags |= nFlagRightAlign; pszInput++; } else if (pszInput[0] == 'c' || pszInput[0] == 'C') { nFlags |= nFlagCenterAlign; pszInput++; } if (pszInput[0] == 's' || pszInput[0] == 'S') { nFlags |= nFlagProportionalSelf; pszInput++; } else if (pszInput[0] == 'p' || pszInput[0] == 'P') { nFlags |= nFlagProportionalParent; pszInput++; } // get the value int nNewPos = atoi(pszInput); float flPos = atof(pszInput); float flProportion = 1.f; // scale the x up to our screen co-ords if ( pPanel->IsProportional() ) { int nOldPos = nNewPos; nNewPos = scheme()->GetProportionalScaledValueEx( pPanel->GetScheme(), nNewPos ); flProportion = (float)nNewPos / (float)nOldPos; } if (nFlags & nFlagProportionalSelf) { nPosDelta = nSize * flPos; } else if (nFlags & nFlagProportionalParent) { nPosDelta = nParentSize * flPos; } else { nPosDelta = nNewPos; } // now correct the alignment if (nFlags & nFlagRightAlign) { nNewPos = nParentSize - nPosDelta; } else if (nFlags & nFlagCenterAlign) { nNewPos = (nParentSize / 2) + nPosDelta; } else { nNewPos = nPosDelta; } switch (eOp) { case OP_ADD: nPos += nNewPos; break; case OP_SUB: nPos -= nNewPos; break; case OP_SET: nPos = nNewPos; break; } // Jump the sign if it's there if (pszInput[0] == '-' || pszInput[0] == '+') pszInput++; // Go past the number while (V_isdigit(pszInput[0]) || pszInput[0] == '.') pszInput++; // Peep if there's an operator if (pszInput && pszInput[0]) { // Recurse! switch (pszInput[0]) { case '+': ComputePos( pPanel, ++pszInput, nPos, nSize, nParentSize, bX, OP_ADD); break; case '-': ComputePos( pPanel, ++pszInput, nPos, nSize, nParentSize, bX, OP_SUB); break; } } } if (tf_debug_tabcontainer.GetBool() && !Q_stricmp("TabContainer", pPanel->GetName())) { Msg("TabContainer nFlags:%x nPos:%d nParentSize:%d nPosDelta:%d nSize:%d GetParent:%p (%s) pszInput:'%s'\n", nFlags, nPos, nParentSize, nPosDelta, nSize, pPanel->GetParent(), pPanel->GetParent() ? pPanel->GetParent()->GetName() : "??", pszInput ? pszInput : "??"); } return nFlags; } }