summaryrefslogtreecommitdiff
path: root/game/client/tf/vgui/tf_item_card_panel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/vgui/tf_item_card_panel.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf/vgui/tf_item_card_panel.cpp')
-rw-r--r--game/client/tf/vgui/tf_item_card_panel.cpp767
1 files changed, 767 insertions, 0 deletions
diff --git a/game/client/tf/vgui/tf_item_card_panel.cpp b/game/client/tf/vgui/tf_item_card_panel.cpp
new file mode 100644
index 0000000..0852db4
--- /dev/null
+++ b/game/client/tf/vgui/tf_item_card_panel.cpp
@@ -0,0 +1,767 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "tf_item_card_panel.h"
+#include "econ_item_description.h"
+#include "vgui_controls/TextImage.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "navigationpanel.h"
+#include "IconPanel.h"
+#include "vgui_controls/ScrollBar.h"
+#include "vgui_controls/ScrollBarSlider.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui_controls/Tooltip.h>
+#include <vgui_controls/AnimationController.h>
+#include "clientmode_tf.h"
+
+using namespace vgui;
+
+#ifdef STAGING_ONLY
+extern ConVar tf_use_card_tooltips;
+#endif // STAGING_ONLY
+
+//-----------------------------------------------------------------------------
+// Purpose: A label that can have multiple fonts specified and will try to use
+// them in order specified, using the first one that fits.
+//-----------------------------------------------------------------------------
+class CAutoFittingLabel : public Label
+{
+ DECLARE_CLASS_SIMPLE( CAutoFittingLabel, Label );
+public:
+
+ CAutoFittingLabel( Panel *parent, const char *name )
+ : Label( parent, name, (const char*)NULL )
+ {}
+
+ virtual void ApplySettings( KeyValues *inResourceData )
+ {
+ BaseClass::ApplySettings( inResourceData );
+
+ KeyValues *pFonts = inResourceData->FindKey( "fonts" );
+ if ( pFonts )
+ {
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ // Get all the fonts
+ FOR_EACH_SUBKEY( pFonts, pFont )
+ {
+ const HFont& font = pScheme->GetFont( pFont->GetString( "font" ), true );
+ m_vecFonts.AddToTail( font );
+ }
+ }
+ }
+
+ virtual void PerformLayout()
+ {
+ BaseClass::PerformLayout();
+
+ SetFont( m_vecFonts.Head() );
+
+ // Go through all the fonts and try to find one that fits
+ int nIndex = 0;
+ GetTextImage()->ResizeImageToContentMaxWidth( GetWide() );
+ while ( ( GetTextImage()->IsWrapping() || GetTextImage()->GetEllipsesPosition() ) && nIndex < m_vecFonts.Count() )
+ {
+ SetFont( m_vecFonts[ nIndex ] );
+ GetTextImage()->ResizeImageToContentMaxWidth( GetWide() );
+
+ ++nIndex;
+ }
+ }
+
+private:
+
+ CUtlVector< HFont > m_vecFonts;
+};
+
+DECLARE_BUILD_FACTORY( CAutoFittingLabel );
+
+
+DECLARE_BUILD_FACTORY( CRepeatingContainer );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CRepeatingContainer::CRepeatingContainer( Panel *pParent, const char *pszName )
+ : EditablePanel( pParent, pszName )
+ , m_eLayoutMethod( METHOD_EVEN )
+{}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CRepeatingContainer::~CRepeatingContainer()
+{}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRepeatingContainer::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ KeyValues* pCommonSettings = inResourceData->FindKey( "CommonSettings" );
+ KeyValues* pIndividualSettings = inResourceData->FindKey( "IndividualSettings" );
+
+ // Delete old panels
+ m_vecChildren.PurgeAndDeleteElements();
+
+ if ( pIndividualSettings && pCommonSettings )
+ {
+ // Go through every individual panel
+ FOR_EACH_SUBKEY( pIndividualSettings, pSubKey )
+ {
+ // Merge the individual keys onto the common keys, keeping "individual" values if there's a conflict
+ pSubKey->RecursiveMergeKeyValues( pCommonSettings );
+
+ // Create each panel
+ Panel *pNewPanel = CreateControlByName( pSubKey->GetString( "ControlName" ) );
+ if ( pNewPanel )
+ {
+ pNewPanel->SetParent( this );
+ pNewPanel->SetBuildGroup( GetBuildGroup() );
+ pNewPanel->ApplySettings( pSubKey );
+ m_vecChildren.AddToTail( pNewPanel );
+ }
+ }
+ }
+
+ const char *pszSpacingMethod = inResourceData->GetString( "spacing_method", NULL );
+ if ( pszSpacingMethod )
+ {
+ // Figure out how we're going to layout all these panels
+ if ( FStrEq( pszSpacingMethod, "METHOD_STEP" ) )
+ {
+ m_eLayoutMethod = METHOD_STEP;
+ }
+ else // Default to event
+ {
+ m_eLayoutMethod = METHOD_EVEN;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRepeatingContainer::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // No children? We're done.
+ if ( m_vecChildren.IsEmpty() )
+ return;
+
+ // Fixed step gaps
+ if ( m_eLayoutMethod == METHOD_STEP )
+ {
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ m_vecChildren[i]->SetPos( m_iXStep * i , 0 );
+ }
+ }
+ else // default METHOD_EVEN
+ {
+ // Evently spaced
+ int nParentWide = GetWide();
+ int nTotalChildWide = 0;
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ nTotalChildWide += m_vecChildren[i]->GetWide();
+ }
+
+ int nXStep = 0;
+ if ( nTotalChildWide < nParentWide )
+ {
+ nXStep = ( nParentWide - nTotalChildWide ) / ( m_vecChildren.Count() - 1 );
+ }
+
+ int nXPos = 0;
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ m_vecChildren[i]->SetPos( nXPos, 0 );
+ nXPos += m_vecChildren[i]->GetWide() + nXStep;
+ }
+ }
+}
+
+
+DECLARE_BUILD_FACTORY( CTFItemCardPanel );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFItemCardPanel::CTFItemCardPanel( Panel *pParent, const char *pszName )
+ : BaseClass( pParent, pszName )
+ , m_pItem( NULL )
+ , m_bAllControlsValid( false )
+ , m_bPinned( false )
+ , m_pDropShadow( NULL )
+ , m_pRarityBackgroundOverlay( NULL )
+ , m_pCardTop( NULL )
+ , m_pItemModel( NULL )
+ , m_pRarityContainer( NULL )
+ , m_pItemName( NULL )
+ , m_pRarityName( NULL )
+ , m_pInfoContainer( NULL )
+ , m_pClassLabel( NULL )
+ , m_pClassIconContainer( NULL )
+ , m_pTypeLabel( NULL )
+ , m_pTypeLabelValue( NULL )
+ , m_pExteriorLabel( NULL )
+ , m_pExteriorLabelValue( NULL )
+ , m_pBottomContainer( NULL )
+ , m_pBottomScrollingContainer( NULL )
+ , m_pAttribsLabel( NULL )
+ , m_pEquipSlotLabel( NULL )
+{
+ m_pDropShadow = new ImagePanel( pParent, "ItemCardShadow" );
+ m_pDropShadow->SetVisible( false );
+ m_pDropShadow->SetAutoDelete( false ); // We'll delete this panel
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFItemCardPanel::~CTFItemCardPanel()
+{
+ m_pDropShadow->MarkForDeletion();
+ m_pDropShadow = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Do FindControl() but also verify that we got what we were looking for
+//-----------------------------------------------------------------------------
+template < class T >
+T* CTFItemCardPanel::FindAndVerifyControl( Panel* pParent, const char* pszPanelName )
+{
+ if ( !m_bAllControlsValid )
+ return NULL;
+
+ // Find the panel
+ T* pChild = pParent->FindControl< T >( pszPanelName, true );
+ // Make sure it's still there
+ m_bAllControlsValid &= pChild != NULL;
+
+ return pChild;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadResFileForCurrentItem();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( !m_pItem )
+ {
+ return;
+ }
+
+ if ( !m_bAllControlsValid )
+ {
+ return;
+ }
+
+ m_pBottomScrollingContainer->InvalidateLayout();
+
+ UpdateDescription();
+ UpdateModelOrIcon();
+
+ // Position grime
+ {
+ // Randomize based on our original item ID, if we have one. If not, just use defindex
+ RandomSeed( m_pItem->GetSOCData() ? m_pItem->GetSOCData()->GetOriginalID() : m_pItem->GetItemDefIndex() );
+
+ // Randomize X/Y
+ int nGrimeX = RandomInt( -abs( m_pGrime->GetWide() - GetWide() ), 0 );
+ int nGrimeY = RandomInt( -abs( m_pGrime->GetTall() - GetTall() ), 0 );
+ m_pGrime->SetPos( nGrimeX, nGrimeY );
+ // Randomize 0,90,180,270 rotation
+ m_pGrime->GetImage()->SetRotation( RandomInt( 0, 3 ) ); // Have to GetImage()->SetRotation because ImagePanel::SetRotation does nothing!
+ }
+
+ // Update our shadow's settings
+ {
+ m_pDropShadow->SetZPos( GetZPos() - 1 );
+ m_pDropShadow->SetShouldScaleImage( true );
+ m_pDropShadow->SetMouseInputEnabled( false );
+ m_pDropShadow->SetImage( "item_card/standard_background_dropshadow" );
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::SetVisible( bool bVisible )
+{
+ // Update the position of our external shadow panel
+ if ( m_bAllControlsValid )
+ {
+ int x=0,y=0,wide,tall,xTemp,yTemp;
+ m_pBackground->GetBounds( xTemp, yTemp, wide, tall );
+ x += xTemp; y += yTemp;
+ m_pMainContainer->GetPos( xTemp, yTemp );
+ x += xTemp; y += yTemp;
+ GetPos( xTemp, yTemp );
+ x += xTemp; y += yTemp;
+
+ m_pDropShadow->SetBounds( x + m_iShadowOffset, y + m_iShadowOffset, wide * 1.15f, tall * 1.15f );
+ }
+
+ BaseClass::SetVisible( bVisible );
+
+ m_pDropShadow->SetVisible( bVisible );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Force the scrolling container to have mouse input matching the panel's
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::SetMouseInputEnabled( bool state )
+{
+ BaseClass::SetVisible( state );
+
+ if ( m_bAllControlsValid )
+ {
+ m_pBottomScrollingContainer->SetMouseInputEnabled( state );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::SetItem( CEconItemView* pItem )
+{
+ m_pItem = pItem;
+
+ // Update the panels
+ LoadResFileForCurrentItem();
+ MakeReadyForUse();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::PinCard( bool bPin )
+{
+#ifdef STAGING_ONLY
+ if ( !tf_use_card_tooltips.GetBool() )
+ {
+ return;
+ }
+#endif // STAGING_ONLY
+
+ bool bDiff = bPin != m_bPinned;
+ m_bPinned = bPin;
+
+ if ( bDiff && bPin )
+ {
+ g_pClientMode->GetViewportAnimationController()->CancelAnimationsForPanel( this );
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "ItemCard_HidePinHint" );
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "ItemCard_ShowCloseButton" );
+ SetVisible( true );
+ }
+ else if ( bDiff && !bPin )
+ {
+ g_pClientMode->GetViewportAnimationController()->CancelAnimationsForPanel( this );
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "ItemCard_ShowPinHint" );
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "ItemCard_HideCloseButton" );
+ SetVisible( false );
+ }
+
+ // Force mouse input
+ SetMouseInputEnabled( bPin );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::UpdateDescription()
+{
+ const GameItemDefinition_t *pItemDef = m_pItem->GetItemDefinition();
+ if ( !pItemDef )
+ return;
+
+ // Itm name
+ m_pItemName->SetText( m_pItem->GetItemName() );
+
+ // If we dont have a rarity, then we assume we're an "old" item.
+ if ( !GetItemSchema()->GetRarityColor(pItemDef->GetRarity() ) )
+ {
+ // Grab the item quality (ie. strange, unusual)
+ const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)m_pItem->GetItemQuality() );
+ if ( m_pItem->IsValid() && pszQualityColorString )
+ {
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ Color colorName = pScheme->GetColor( pszQualityColorString, Color( 0, 255, 0, 255 ) );
+ m_pItemName->SetFgColor( colorName );
+ }
+ }
+
+
+ // Set highlighting on the class icons
+ {
+ for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
+ {
+ CExImageButton *pExImage = dynamic_cast< CExImageButton* >( m_pClassIconContainer->GetRepeatingChild( GetRemappedMenuIndexForClass(i) - 1 ) );
+ if ( pExImage )
+ {
+ pExImage->SetSelected( pItemDef->CanBeUsedByClass( i ) );
+ }
+ }
+ }
+
+ // Set type name into the label
+ {
+ const locchar_t *locTypename = g_pVGuiLocalize->Find( pItemDef->GetItemTypeName() );
+ m_pTypeLabelValue->SetText( locTypename );
+ }
+
+ const CEconItemRarityDefinition* pItemRarity = GetItemSchema()->GetRarityDefinition( pItemDef->GetRarity() );
+
+ // Setup the rarity color overlay
+ {
+ attrib_colors_t attribColor = ATTRIB_COL_RARITY_DEFAULT;
+
+ if ( pItemRarity )
+ {
+ attribColor = pItemRarity->GetAttribColor();
+ }
+
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ Color color = pScheme->GetColor( GetColorNameForAttribColor( attribColor ), Color( 255, 255, 255, 255 ) );
+ m_pRarityBackgroundOverlay->SetDrawColor( color );
+ m_pRarityName->SetFgColor( color );
+ }
+
+ // Rarity name into the label
+ {
+ const char *pszRarityName = "#Rarity_Default";
+ if ( pItemRarity )
+ {
+ pszRarityName = pItemRarity->GetLocKey();
+ }
+
+ m_pRarityName->SetText( g_pVGuiLocalize->Find( pszRarityName ) );
+ }
+
+ enum { kAttribBufferSize = 4 * 1024 };
+ wchar_t wszAttribBuffer[ kAttribBufferSize ] = L"";
+
+ // Space out the attributes
+ const CEconItemDescription *pDescription = m_pItem->GetDescription();
+ if ( pDescription )
+ {
+ unsigned int unWrittenLines = 0;
+ for ( unsigned int i = 0; i < pDescription->GetLineCount(); i++ )
+ {
+ const econ_item_description_line_t& line = pDescription->GetLine(i);
+ if ( (line.unMetaType & ( kDescLineFlag_Name ) ) == 0 )
+ {
+ V_wcscat_safe( wszAttribBuffer, L"\n" ); // add empty lines everywhere
+ V_wcscat_safe( wszAttribBuffer, line.sText.Get() );
+ ++unWrittenLines;
+ }
+ }
+
+ // Get all the attributes
+ Assert( m_pItem->GetDescription() );
+ if ( m_pAttribsLabel->GetTextImage() && m_pItem->GetDescription() )
+ {
+ m_pAttribsLabel->SetText( wszAttribBuffer );
+
+ TextImage *pTextImage = m_pAttribsLabel->GetTextImage();
+ Assert( pTextImage );
+
+ pTextImage->ClearColorChangeStream();
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ Color prevCol;
+ unsigned int unCurrentTextStreamIndex = 0;
+ for ( unsigned int i = 0; i < pDescription->GetLineCount(); i++ )
+ {
+ const econ_item_description_line_t& line = pDescription->GetLine(i);
+
+ // Ignore the name line, it was added above
+ if ( ( line.unMetaType & ( kDescLineFlag_Name ) ) != 0 )
+ {
+ continue;
+ }
+
+ Color col = pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
+
+ // Output a color change if necessary.
+ if ( i == 0 || prevCol != col )
+ {
+ pTextImage->AddColorChange( col, unCurrentTextStreamIndex );
+ prevCol = col;
+ }
+
+ unCurrentTextStreamIndex += StringFuncs<locchar_t>::Length( line.sText.Get() ) + 1; // add one character to deal with newlines
+ }
+
+ int nWide, nTall;
+ pTextImage->GetContentSize( nWide, nTall );
+ m_pAttribsLabel->SetTall( nTall );
+ }
+ }
+
+ // Set equip slot
+ {
+ int nEquipSlot = pItemDef->GetDefaultLoadoutSlot();
+ if ( nEquipSlot != -1 )
+ {
+ m_pEquipSlotLabel->SetText( g_pVGuiLocalize->Find( GetItemSchema()->GetLoadoutStringsForDisplay( pItemDef->GetEquipType() )[ nEquipSlot ] ) );
+ }
+ else
+ {
+ m_pEquipSlotLabel->SetText( "" );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::UpdateModelOrIcon()
+{
+ if ( !m_pItem )
+ {
+ return;
+ }
+
+ m_pItemModel->SetItem( m_pItem );
+
+ const char *pszModelName = m_pItem->GetPlayerDisplayModel( 0, 0 );
+ if ( pszModelName )
+ {
+ MDLHandle_t hMDL = mdlcache->FindMDL( pszModelName );
+ m_pItemModel->SetMDL( hMDL, static_cast<IClientRenderable*>(m_pItem) );
+ mdlcache->Release( hMDL ); // counterbalance addref from within FindMDL
+ m_pItemModel->SetForceModelUsage( true );
+ }
+ else
+ {
+ m_pItemModel->SetInventoryImageType( CEmbeddedItemModelPanel::IMAGETYPE_LARGE );
+ m_pItemModel->LoadInventoryImage();
+ m_pItemModel->SetForceModelUsage( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFItemCardPanel::LoadResFileForCurrentItem()
+{
+ // Temp hack. New items get the new cards
+ const char *pszResFile = "Resource/UI/econ/ItemCardPanel_Series1.res";
+ if ( m_pItem )
+ {
+ const GameItemDefinition_t *pItemDef = m_pItem->GetItemDefinition();
+ if ( pItemDef )
+ {
+ const CEconItemRarityDefinition* pItemRarity = GetItemSchema()->GetRarityDefinition( pItemDef->GetRarity() );
+ if ( pItemRarity && pItemRarity->GetDBValue() > 0 )
+ {
+ pszResFile = "Resource/UI/econ/ItemCardPanel_Series2.res";
+ }
+ }
+ }
+
+ m_bAllControlsValid = false;
+
+ LoadControlSettings( pszResFile );
+
+ m_bAllControlsValid = true;
+ // Grab all the controls...
+ m_pMainContainer = FindAndVerifyControl< EditablePanel >( this, "MainContainer" );
+ m_pRarityBackgroundOverlay = FindAndVerifyControl< ImagePanel >( m_pMainContainer, "RarityBackgroundOverlay" );
+ m_pBackground = FindAndVerifyControl< ImagePanel >( m_pMainContainer, "Background" );
+ m_pGrime = FindAndVerifyControl< ImagePanel >( m_pMainContainer, "GrimeLayer" );
+ m_pCardTop = FindAndVerifyControl< EditablePanel >( m_pMainContainer, "CardTop" );
+ m_pItemModel = FindAndVerifyControl< CEmbeddedItemModelPanel >( m_pCardTop, "ItemModel" );
+ m_pRarityContainer = FindAndVerifyControl< EditablePanel >( m_pMainContainer, "RarityContainer" );
+ m_pItemName = FindAndVerifyControl< Label >( m_pRarityContainer, "ItemNameLabel" );
+ m_pRarityName = FindAndVerifyControl< Label >( m_pRarityContainer, "ItemRarityLabel" );
+ m_pClassIconContainer = FindAndVerifyControl< CRepeatingContainer >( m_pMainContainer, "ClassIconContainer" );
+ m_pInfoContainer = FindAndVerifyControl< EditablePanel >( m_pMainContainer, "InfoContainer" );
+ m_pClassLabel = FindAndVerifyControl< Label >( m_pInfoContainer, "ClassLabel" );
+ m_pTypeLabel = FindAndVerifyControl< Label >( m_pInfoContainer, "TypeLabel" );
+ m_pTypeLabelValue = FindAndVerifyControl< Label >( m_pInfoContainer, "TypeValueLabel" );
+ m_pExteriorLabel = FindAndVerifyControl< Label >( m_pInfoContainer, "ExteriorLabel" );
+ m_pExteriorLabelValue = FindAndVerifyControl< Label >( m_pInfoContainer, "ExteriorValueLabel" );
+ m_pBottomContainer = FindAndVerifyControl< EditablePanel >( m_pMainContainer, "BottomContainer" );
+ m_pBottomScrollingContainer = FindAndVerifyControl< CExScrollingEditablePanel >( m_pBottomContainer, "ScrollableBottomContainer" );
+ m_pAttribsLabel = FindAndVerifyControl< Label >( m_pBottomScrollingContainer, "AttribsLabel" );
+ m_pEquipSlotLabel = FindAndVerifyControl< Label >( this, "EquipSlotLabel" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CItemCardPanelToolTip::CItemCardPanelToolTip( Panel *parent, const char *text )
+: BaseTooltip( parent, text )
+, m_pMouseOverItemPanel( NULL )
+, m_iPositioningStrategy( IPTTP_BOTTOM_SIDE )
+{
+ m_hCurrentPanel = NULL;
+ SetTooltipDelay( 100 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CItemCardPanelToolTip::GetPosition( itempanel_tooltippos_t iTooltipPosition, CItemModelPanel *pItemPanel, int iItemX, int iItemY, int *iXPos, int *iYPos )
+{
+ switch ( iTooltipPosition )
+ {
+ case IPTTP_LEFT:
+ *iXPos = ( iItemX - m_pMouseOverItemPanel->GetWide() );
+ *iYPos = ( iItemY + pItemPanel->GetTall() * 0.5f ) - ( m_pMouseOverItemPanel->GetTall() * 0.5f );
+ break;
+ case IPTTP_RIGHT:
+ *iXPos = ( iItemX + pItemPanel->GetWide() );
+ *iYPos = ( iItemY + pItemPanel->GetTall() * 0.5f ) - ( m_pMouseOverItemPanel->GetTall() * 0.5f );
+ break;
+ }
+
+ *iYPos = Clamp( *iYPos, (int)YRES( -30 ), int( m_pParentPanel->GetTall() - m_pMouseOverItemPanel->GetTall() - YRES( 30 ) ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CItemCardPanelToolTip::ValidatePosition( CItemModelPanel *pItemPanel, int iItemX, int iItemY, int *iXPos, int *iYPos )
+{
+ if ( *iXPos < 0 )
+ return false;
+
+ if ( ( *iXPos + m_pMouseOverItemPanel->GetWide() ) > m_pParentPanel->GetWide() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CItemCardPanelToolTip::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( !ShouldLayout() )
+ return;
+
+ _isDirty = false;
+
+ CItemModelPanel *pItemPanel = m_hCurrentPanel.Get();
+ if ( m_pMouseOverItemPanel && pItemPanel && !m_pMouseOverItemPanel->IsPinned() )
+ {
+ CEconItemView *pItem = pItemPanel->GetItem();
+ if ( pItem )
+ {
+ m_pMouseOverItemPanel->SetItem( pItem );
+
+
+ int x,y;
+
+ // If the panel is somewhere in a derived class, we need to get its position in our space
+ if ( pItemPanel->GetParent() != m_pMouseOverItemPanel->GetParent() )
+ {
+ int iItemAbsX, iItemAbsY;
+ ipanel()->GetAbsPos( pItemPanel->GetVPanel(), iItemAbsX, iItemAbsY );
+ int iParentAbsX, iParentAbsY;
+ ipanel()->GetAbsPos( m_pMouseOverItemPanel->GetParent()->GetVPanel(), iParentAbsX, iParentAbsY );
+
+ x = (iItemAbsX - iParentAbsX);
+ y = (iItemAbsY - iParentAbsY);
+ }
+ else
+ {
+ pItemPanel->GetPos( x, y );
+ }
+
+ int iXPos = 0;
+ int iYPos = 0;
+
+ // Loop through the positions in our strategy, and hope we find a valid spot
+ for ( int i = 0; i < NUM_POSITIONS_PER_STRATEGY; i++ )
+ {
+ itempanel_tooltippos_t iPos = g_iTooltipStrategies[m_iPositioningStrategy][i];
+ if ( iPos != IPTTP_LEFT && iPos != IPTTP_RIGHT )
+ continue;
+
+ GetPosition( iPos, pItemPanel, x, y, &iXPos, &iYPos );
+
+ if ( ValidatePosition( pItemPanel, x, y, &iXPos, &iYPos ) )
+ break;
+ }
+
+ m_pMouseOverItemPanel->SetPos( iXPos, iYPos );
+ m_pMouseOverItemPanel->SetVisible( true );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CItemCardPanelToolTip::ShowTooltip( Panel *currentPanel )
+{
+ if ( m_pMouseOverItemPanel && currentPanel != m_hCurrentPanel.Get() )
+ {
+ CItemModelPanel *pItemPanel = assert_cast<CItemModelPanel *>(currentPanel);
+ m_hCurrentPanel.Set( pItemPanel );
+ pItemPanel->PostActionSignal( new KeyValues("ItemPanelEntered") );
+ vgui::surface()->PlaySound( "ui/item_info_mouseover.wav" );
+ }
+ BaseClass::ShowTooltip( currentPanel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CItemCardPanelToolTip::HideTooltip()
+{
+ if ( m_pMouseOverItemPanel )
+ {
+ if ( m_pMouseOverItemPanel->IsPinned() )
+ return;
+
+ m_pMouseOverItemPanel->SetVisible( false );
+ }
+
+ if ( m_hCurrentPanel )
+ {
+ m_hCurrentPanel.Get()->PostActionSignal( new KeyValues("ItemPanelExited") );
+ m_hCurrentPanel = NULL;
+ }
+}