summaryrefslogtreecommitdiff
path: root/game/client/econ/econ_controls.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/econ/econ_controls.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/econ/econ_controls.cpp')
-rw-r--r--game/client/econ/econ_controls.cpp2382
1 files changed, 2382 insertions, 0 deletions
diff --git a/game/client/econ/econ_controls.cpp b/game/client/econ/econ_controls.cpp
new file mode 100644
index 0000000..c78dd36
--- /dev/null
+++ b/game/client/econ/econ_controls.cpp
@@ -0,0 +1,2382 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+
+#include "ienginevgui.h"
+#include <vgui_controls/ScrollBarSlider.h>
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+#include "econ_controls.h"
+#include "vgui_controls/TextImage.h"
+#include "vgui_controls/PropertyPage.h"
+#include "econ_item_system.h"
+#include "econ_item_tools.h"
+#include "iachievementmgr.h"
+#include "econ_item_description.h"
+
+#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
+#include "tf_shareddefs.h"
+#endif
+
+using namespace vgui;
+
+DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExButton, CExButton );
+DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExImageButton, CExImageButton );
+DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExLabel, CExLabel );
+DECLARE_BUILD_FACTORY( CExRichText );
+DECLARE_BUILD_FACTORY( CRichTextWithScrollbarBorders );
+DECLARE_BUILD_FACTORY( CEconItemDetailsRichText );
+DECLARE_BUILD_FACTORY( CExplanationPopup );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool SetChildPanelVisible( vgui::Panel *pParent, const char *pChildName, bool bVisible, bool bSearchForChildRecursively )
+{
+ vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
+ if ( pPanel )
+ {
+ if ( pPanel->IsVisible() != bVisible )
+ {
+ pPanel->SetVisible( bVisible );
+ }
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool SetChildPanelEnabled( vgui::Panel *pParent, const char *pChildName, bool bEnabled, bool bSearchForChildRecursively )
+{
+ vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
+ if ( pPanel )
+ {
+ if ( pPanel->IsEnabled() != bEnabled )
+ {
+ pPanel->SetEnabled( bEnabled );
+ }
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool SetChildButtonSelected( vgui::Panel *pParent, const char *pChildName, bool bSelected, bool bSearchForChildRecursively )
+{
+ vgui::Button *pPanel = dynamic_cast< vgui::Button* >( pParent->FindChildByName( pChildName, bSearchForChildRecursively ) );
+ if ( pPanel )
+ {
+ if ( pPanel->IsSelected() != bSelected )
+ {
+ pPanel->SetSelected( bSelected );
+ }
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool IsChildButtonSelected( vgui::Panel *pParent, const char *pChildName, bool bSearchForChildRecursively )
+{
+ vgui::Button *pPanel = dynamic_cast< vgui::Button* >( pParent->FindChildByName( pChildName, bSearchForChildRecursively ) );
+ if ( pPanel )
+ {
+ return pPanel->IsSelected();
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool AddChildActionSignalTarget( vgui::Panel *pParent, const char *pChildName, Panel *messageTarget, bool bSearchForChildRecursively )
+{
+ vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
+ if ( pPanel )
+ {
+ pPanel->AddActionSignalTarget( messageTarget );
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool SetXToRed( vgui::Label *pPanel )
+{
+ if ( !pPanel )
+ return false;
+
+ wchar_t wszConfirmText[256];
+ pPanel->GetText( wszConfirmText, sizeof( wszConfirmText ) );
+
+ if ( ( wszConfirmText[0] == L'x' || wszConfirmText[0] == L'X' ) && wszConfirmText[1] == L' ' )
+ {
+ pPanel->GetTextImage()->ClearColorChangeStream();
+ pPanel->GetTextImage()->AddColorChange( Color(200,80,60,255), 0 );
+ pPanel->GetTextImage()->AddColorChange( pPanel->GetFgColor(), 1 );
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExButton::CExButton( Panel *parent, const char *name, const char *text, vgui::Panel *pActionSignalTarget, const char *cmd ) : Button( parent, name, text, pActionSignalTarget, cmd )
+{
+ m_szFont[0] = '\0';
+ m_szColor[0] = '\0';
+ m_pArmedBorder = NULL;
+ m_pDefaultBorderOverride = NULL;
+ m_pSelectedBorder = NULL;
+ m_pDisabledBorder = NULL;
+ m_bbCursorEnterExitEvent = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExButton::CExButton( Panel *parent, const char *name, const wchar_t *wszText, vgui::Panel *pActionSignalTarget, const char *cmd ) : Button( parent, name, wszText, pActionSignalTarget, cmd )
+{
+ m_szFont[0] = '\0';
+ m_szColor[0] = '\0';
+ m_pArmedBorder = NULL;
+ m_pDefaultBorderOverride = NULL;
+ m_pSelectedBorder = NULL;
+ m_pDisabledBorder = NULL;
+ m_bbCursorEnterExitEvent = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ SetFontStr( inResourceData->GetString( "font", "Default" ) );
+ SetColorStr( inResourceData->GetString( "fgcolor", "Button.TextColor" ) );
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ const char *pszBorder = inResourceData->GetString( "border_default", "" );
+ if ( *pszBorder )
+ {
+ m_pDefaultBorderOverride = pScheme->GetBorder( pszBorder );
+ }
+
+ pszBorder = inResourceData->GetString( "border_armed", "" );
+ if ( *pszBorder )
+ {
+ m_pArmedBorder = pScheme->GetBorder( pszBorder );
+ }
+
+ pszBorder = inResourceData->GetString( "border_disabled", "" );
+ if ( *pszBorder )
+ {
+ m_pDisabledBorder = pScheme->GetBorder( pszBorder );
+ }
+
+ const char *pszSelectedBorder = inResourceData->GetString( "border_selected", "" );
+ if ( *pszSelectedBorder )
+ {
+ m_pSelectedBorder = pScheme->GetBorder( pszSelectedBorder );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+vgui::IBorder *CExButton::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
+{
+ if ( !IsEnabled() && m_pDisabledBorder )
+ return m_pDisabledBorder;
+
+ if ( selected && m_pSelectedBorder )
+ return m_pSelectedBorder;
+
+ if ( armed && m_pArmedBorder )
+ return m_pArmedBorder;
+
+ if ( m_pDefaultBorderOverride )
+ return m_pDefaultBorderOverride;
+
+ return BaseClass::GetBorder( depressed, armed, selected, keyfocus );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::SetFontStr( const char *pFont )
+{
+ V_strcpy_safe( m_szFont, pFont );
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ SetFont( pScheme->GetFont( m_szFont, true ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::SetColorStr( const char *pColor )
+{
+ V_strcpy_safe( m_szColor, pColor );
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ SetFgColor( pScheme->GetColor( m_szColor, Color( 255, 255, 255, 255 ) ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::OnMouseFocusTicked()
+{
+ BaseClass::OnMouseFocusTicked();
+
+ if ( m_hMouseTickTarget )
+ {
+ KeyValues *pMessage = new KeyValues("MouseFocusTicked");
+ vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
+ pMessage->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::OnCursorEntered()
+{
+ BaseClass::OnCursorEntered();
+
+ if ( m_hMouseTickTarget && m_bbCursorEnterExitEvent )
+ {
+ KeyValues *pMessage = new KeyValues("CursorEntered");
+ vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
+ pMessage->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExButton::OnCursorExited()
+{
+ BaseClass::OnCursorExited();
+
+ if ( m_hMouseTickTarget && m_bbCursorEnterExitEvent )
+ {
+ KeyValues *pMessage = new KeyValues("CursorExited");
+ vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
+ pMessage->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExImageButton::CExImageButton( Panel *parent, const char *name, const char *text, vgui::Panel *pActionSignalTarget, const char *cmd ) : CExButton( parent, name, text, pActionSignalTarget, cmd )
+{
+ m_ImageDrawColor = Color(255,255,255,255);
+ m_ImageArmedColor = Color(255,255,255,255);
+ m_ImageDepressedColor = Color(255,255,255,255);
+ m_ImageDisabledColor = Color(255,255,255,255);
+ m_ImageSelectedColor = Color(255,255,255,255);
+ m_pEmbeddedImagePanel = new vgui::ImagePanel( this, "SubImage" );
+ m_szImageDefault[0] = '\0';
+ m_szImageArmed[0] = '\0';
+ m_szImageSelected[0] = '\0';
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExImageButton::CExImageButton( Panel *parent, const char *name, const wchar_t *wszText, vgui::Panel *pActionSignalTarget, const char *cmd ) : CExButton( parent, name, wszText, pActionSignalTarget, cmd )
+{
+ m_ImageDrawColor = Color(255,255,255,255);
+ m_ImageArmedColor = Color(255,255,255,255);
+ m_ImageDepressedColor = Color(255,255,255,255);
+ m_ImageDisabledColor = Color(255,255,255,255);
+ m_ImageSelectedColor = Color(255,255,255,255);
+ m_pEmbeddedImagePanel = new vgui::ImagePanel( this, "SubImage" );
+ m_szImageDefault[0] = '\0';
+ m_szImageArmed[0] = '\0';
+ m_szImageSelected[0] = '\0';
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExImageButton::~CExImageButton( void )
+{
+ m_pEmbeddedImagePanel->MarkForDeletion();
+ m_pEmbeddedImagePanel = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ int r,g,b,a;
+
+ const char *pszDrawColor = inResourceData->GetString("image_drawcolor", "");
+ if (*pszDrawColor)
+ {
+ if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ {
+ m_ImageDrawColor = Color(r, g, b, a);
+ }
+ }
+
+ pszDrawColor = inResourceData->GetString("image_armedcolor", "");
+ if (*pszDrawColor)
+ {
+ if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ {
+ m_ImageArmedColor = Color(r, g, b, a);
+ }
+ }
+
+ pszDrawColor = inResourceData->GetString("image_depressedcolor", "");
+ if (*pszDrawColor)
+ {
+ if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ {
+ m_ImageDepressedColor = Color(r, g, b, a);
+ }
+ }
+
+ pszDrawColor = inResourceData->GetString("image_disabledcolor", "");
+ if (*pszDrawColor)
+ {
+ if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ {
+ m_ImageDisabledColor = Color(r, g, b, a);
+ }
+ }
+
+ pszDrawColor = inResourceData->GetString( "image_selectedcolor", "" );
+ if (*pszDrawColor)
+ {
+ if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ {
+ m_ImageSelectedColor = Color(r, g, b, a);
+ }
+ }
+
+ KeyValues *pButtonKV = inResourceData->FindKey( "SubImage" );
+ if ( pButtonKV )
+ {
+ m_pEmbeddedImagePanel->ApplySettings( pButtonKV );
+ }
+
+ const char *pszImageDefault = inResourceData->GetString("image_default", "");
+ if (*pszImageDefault)
+ {
+ SetImageDefault( pszImageDefault );
+ }
+
+ const char *pszImageArmed = inResourceData->GetString("image_armed", "");
+ if (*pszImageArmed)
+ {
+ SetImageArmed( pszImageArmed );
+ }
+
+ const char *pszImageSelected = inResourceData->GetString("image_selected", "");
+ if (*pszImageSelected)
+ {
+ SetImageSelected( pszImageSelected );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Color CExImageButton::GetImageColor( void )
+{
+ if ( !IsEnabled() )
+ return m_ImageDisabledColor;
+ if ( IsSelected() )
+ return m_ImageSelectedColor;
+ if ( IsDepressed() )
+ return m_ImageDepressedColor;
+ if ( IsArmed() )
+ return m_ImageArmedColor;
+ return m_ImageDrawColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_pEmbeddedImagePanel->SetMouseInputEnabled( false );
+ m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetArmed(bool state)
+{
+ BaseClass::SetArmed( state );
+
+ if ( m_pEmbeddedImagePanel )
+ {
+ m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
+
+ const char *pszImage = state ? m_szImageArmed : m_szImageDefault;
+ if ( *pszImage )
+ {
+ SetSubImage( pszImage );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetEnabled(bool state)
+{
+ BaseClass::SetEnabled( state );
+
+ if ( m_pEmbeddedImagePanel )
+ {
+ m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetSelected(bool state)
+{
+ BaseClass::SetSelected( state );
+
+ if ( m_pEmbeddedImagePanel )
+ {
+ m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
+
+ const char *pszImage = state ? m_szImageSelected : m_szImageDefault;
+ if ( *pszImage )
+ {
+ SetSubImage( pszImage );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetSubImage( const char *pszImage )
+{
+ m_pEmbeddedImagePanel->SetImage( pszImage );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetImageDefault( const char *pszImageDefault )
+{
+ V_strcpy_safe( m_szImageDefault, pszImageDefault );
+ if ( !IsArmed() )
+ {
+ SetSubImage( pszImageDefault );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetImageArmed( const char *pszImageArmed )
+{
+ V_strcpy_safe( m_szImageArmed, pszImageArmed );
+ if ( IsArmed() )
+ {
+ SetSubImage( m_szImageArmed );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExImageButton::SetImageSelected( const char *pszImageSelected )
+{
+ V_strcpy_safe( m_szImageSelected, pszImageSelected );
+ if ( IsSelected() )
+ {
+ SetSubImage( m_szImageSelected );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExLabel::CExLabel( Panel *parent, const char *name, const char *text ) : Label( parent, name, text )
+{
+ m_szColor[0] = '\0';
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExLabel::CExLabel( Panel *parent, const char *name, const wchar_t *wszText ) : Label( parent, name, wszText )
+{
+ m_szColor[0] = '\0';
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExLabel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ SetColorStr( inResourceData->GetString( "fgcolor", "Label.TextColor" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExLabel::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // Reapply our custom color, so we stomp the base scheme's
+ SetColorStr( m_szColor );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExLabel::SetColorStr( const char *pColor )
+{
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ SetColorStr( pScheme->GetColor( pColor, Color( 0, 255, 0, 255 ) ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExLabel::SetColorStr( Color cColor )
+{
+ Q_snprintf( m_szColor, ARRAYSIZE(m_szColor), "%d %d %d %d", cColor.r(), cColor.g(), cColor.b(), cColor.a() );
+ SetFgColor( cColor );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExRichText::CExRichText( Panel *parent, const char *name ) : RichText( parent, name )
+{
+ m_szFont[0] = '\0';
+ m_szColor[0] = '\0';
+ m_szImageUpArrow[0] = '\0';
+ m_szImageDownArrow[0] = '\0';
+ m_szImageLine[0] = '\0';
+ m_szImageBox[0] = '\0';
+ m_bUseImageBorders = false;
+ m_pBox = NULL;
+ m_pLine = NULL;
+
+ SetCursor(dc_arrow);
+
+ m_pUpArrow = new CExImageButton( this, "UpArrow", "" );
+ if ( m_pUpArrow )
+ {
+ m_pUpArrow->AddActionSignalTarget( _vertScrollBar );
+ m_pUpArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 0));
+ m_pUpArrow->GetImage()->SetShouldScaleImage( true );
+ m_pUpArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ m_pUpArrow->SetAlpha( 255 );
+ m_pUpArrow->SetPaintBackgroundEnabled( false );
+ m_pUpArrow->SetVisible( false );
+ }
+
+ m_pDownArrow = new CExImageButton( this, "DownArrow", "" );
+ if ( m_pDownArrow )
+ {
+ m_pDownArrow->AddActionSignalTarget( _vertScrollBar );
+ m_pDownArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 1));
+ m_pDownArrow->GetImage()->SetShouldScaleImage( true );
+ m_pDownArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ m_pDownArrow->SetAlpha( 255 );
+ m_pDownArrow->SetPaintBackgroundEnabled( false );
+ m_pDownArrow->SetVisible( false );
+ }
+
+ _vertScrollBar->SetOverriddenButtons( m_pUpArrow, m_pDownArrow );
+ m_pUpArrow->PassMouseTicksTo( _vertScrollBar );
+ m_pDownArrow->PassMouseTicksTo( _vertScrollBar );
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::CreateImagePanels( void )
+{
+ if ( m_pBox || m_pLine )
+ return;
+
+ if ( m_bUseImageBorders )
+ {
+ m_pLine = new vgui::Panel( this, "Line" );
+ m_pBox = new vgui::Panel( this, "Box" );
+ }
+ else
+ {
+ m_pLine = new vgui::ImagePanel( this, "Line" );
+ m_pBox = new vgui::ImagePanel( this, "Box" );
+
+ dynamic_cast<vgui::ImagePanel *>(m_pBox)->SetShouldScaleImage( true );
+ dynamic_cast<vgui::ImagePanel *>(m_pLine)->SetShouldScaleImage( true );
+ }
+ m_pBox->SetVisible( false );
+ m_pLine->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ SetFontStr( inResourceData->GetString( "font", "Default" ) );
+ SetColorStr( inResourceData->GetString( "fgcolor", "RichText.TextColor" ) );
+
+ SetCustomImage( m_pUpArrow->GetImage(), inResourceData->GetString( "image_up_arrow", "chalkboard_scroll_up" ), m_szImageUpArrow );
+ SetCustomImage( m_pDownArrow->GetImage(), inResourceData->GetString( "image_down_arrow", "chalkboard_scroll_down" ), m_szImageDownArrow );
+ SetCustomImage( m_pLine, inResourceData->GetString( "image_line", "chalkboard_scroll_line" ), m_szImageLine );
+ SetCustomImage( m_pBox, inResourceData->GetString( "image_box", "chalkboard_scroll_box" ), m_szImageBox );
+
+ const char *pszMouseover = inResourceData->GetString( "image_up_arrow_mouseover", NULL );
+ if ( pszMouseover )
+ {
+ m_pUpArrow->SetImageArmed( pszMouseover );
+ m_pUpArrow->SetImageDefault( m_szImageUpArrow );
+ }
+ pszMouseover = inResourceData->GetString( "image_down_arrow_mouseover", NULL );
+ if ( pszMouseover )
+ {
+ m_pDownArrow->SetImageArmed( pszMouseover );
+ m_pDownArrow->SetImageDefault( m_szImageDownArrow );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetFontStr( const char *pFont )
+{
+ if ( pFont != m_szFont )
+ {
+ V_strcpy_safe( m_szFont, pFont );
+ }
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ SetFont( pScheme->GetFont( m_szFont, true ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetColorStr( const char *pColor )
+{
+ if ( pColor != m_szColor )
+ {
+ V_strcpy_safe( m_szColor, pColor );
+ }
+
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ SetFgColor( pScheme->GetColor( m_szColor, Color( 255, 255, 255, 255 ) ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetCustomImage( vgui::Panel *pImage, const char *pszImage, char *pszStorage )
+{
+ if ( pszStorage )
+ {
+ V_strcpy( pszStorage, pszImage );
+ }
+ if ( !pImage )
+ return;
+
+ if ( m_bUseImageBorders )
+ {
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ IBorder *pBorder = pScheme->GetBorder( pszImage );
+
+ if ( pBorder )
+ {
+ pImage->SetBorder( pBorder );
+ return;
+ }
+ }
+
+ vgui::ImagePanel *pImagePanel = dynamic_cast<vgui::ImagePanel *>(pImage);
+ if ( pImagePanel )
+ {
+ pImagePanel->SetImage( pszImage );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::ApplySchemeSettings( IScheme *pScheme )
+{
+ CreateImagePanels();
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // Reapply any custom font/color, so we stomp the base scheme's
+ SetFontStr( m_szFont );
+ SetColorStr( m_szColor );
+ SetCustomImage( m_pUpArrow->GetImage(), m_szImageUpArrow, NULL );
+ SetCustomImage( m_pDownArrow->GetImage(), m_szImageDownArrow, NULL );
+ SetCustomImage( m_pLine, m_szImageLine, NULL );
+ SetCustomImage( m_pBox, m_szImageBox, NULL );
+
+ SetBorder( pScheme->GetBorder( "NoBorder" ) );
+ SetBgColor( pScheme->GetColor( "Blank", Color( 0,0,0,0 ) ) );
+ SetPanelInteractive( false );
+ SetUnusedScrollbarInvisible( true );
+
+ if ( m_pDownArrow )
+ {
+ m_pDownArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ }
+
+ if ( m_pUpArrow )
+ {
+ m_pUpArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ }
+
+ SetScrollBarImagesVisible( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( _vertScrollBar )
+ {
+ _vertScrollBar->SetZPos( 500 );
+ m_pUpArrow->SetZPos( 501 );
+ m_pDownArrow->SetZPos( 501 );
+
+ // turn off painting the vertical scrollbar
+ _vertScrollBar->SetPaintBackgroundEnabled( false );
+ _vertScrollBar->SetPaintBorderEnabled( false );
+ _vertScrollBar->SetPaintEnabled( false );
+ _vertScrollBar->SetScrollbarButtonsVisible( false );
+ _vertScrollBar->GetButton(0)->SetMouseInputEnabled( false );
+ _vertScrollBar->GetButton(1)->SetMouseInputEnabled( false );
+
+ if ( _vertScrollBar->IsVisible() )
+ {
+ int nMin, nMax;
+ _vertScrollBar->GetRange( nMin, nMax );
+ _vertScrollBar->SetValue( nMin );
+
+ int nScrollbarWide = _vertScrollBar->GetWide();
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ if ( m_pUpArrow )
+ {
+ m_pUpArrow->SetBounds( wide - nScrollbarWide, 0, nScrollbarWide, nScrollbarWide );
+ m_pUpArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide );
+ }
+
+ if ( m_pLine )
+ {
+ m_pLine->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, tall - ( 2 * nScrollbarWide ) );
+ }
+
+ if ( m_pBox )
+ {
+ m_pBox->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, nScrollbarWide );
+ }
+
+ if ( m_pDownArrow )
+ {
+ m_pDownArrow->SetBounds( wide - nScrollbarWide, tall - nScrollbarWide, nScrollbarWide, nScrollbarWide );
+ m_pDownArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide );
+ }
+
+ SetScrollBarImagesVisible( false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetText( const wchar_t *text )
+{
+ wchar_t buffer[2048];
+ Q_wcsncpy( buffer, text, sizeof( buffer ) );
+
+ // transform '\r' to ' ' to eliminate double-spacing on line returns
+ for ( wchar_t *ch = buffer; *ch != 0; ch++ )
+ {
+ if ( *ch == '\r' )
+ {
+ *ch = ' ';
+ }
+ }
+
+ BaseClass::SetText( buffer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetText( const char *text )
+{
+ char buffer[2048];
+ Q_strncpy( buffer, text, sizeof( buffer ) );
+
+ // transform '\r' to ' ' to eliminate double-spacing on line returns
+ for ( char *ch = buffer; *ch != 0; ch++ )
+ {
+ if ( *ch == '\r' )
+ {
+ *ch = ' ';
+ }
+ }
+
+ BaseClass::SetText( buffer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::SetScrollBarImagesVisible( bool visible )
+{
+ if ( m_pDownArrow && m_pDownArrow->IsVisible() != visible )
+ {
+ m_pDownArrow->SetVisible( visible );
+ m_pDownArrow->SetEnabled( visible );
+ }
+
+ if ( m_pUpArrow && m_pUpArrow->IsVisible() != visible )
+ {
+ m_pUpArrow->SetVisible( visible );
+ m_pUpArrow->SetEnabled( visible );
+ }
+
+ if ( m_pLine && m_pLine->IsVisible() != visible )
+ {
+ m_pLine->SetVisible( visible );
+ }
+
+ if ( m_pBox && m_pBox->IsVisible() != visible )
+ {
+ m_pBox->SetVisible( visible );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExRichText::OnTick()
+{
+ if ( !IsVisible() )
+ return;
+
+ if ( m_pDownArrow && m_pUpArrow && m_pLine && m_pBox )
+ {
+ if ( _vertScrollBar && _vertScrollBar->IsVisible() )
+ {
+ // turn on our own images
+ SetScrollBarImagesVisible ( true );
+
+ // set the alpha on the up arrow
+ int nMin, nMax;
+ _vertScrollBar->GetRange( nMin, nMax );
+ int nScrollPos = _vertScrollBar->GetValue();
+ int nRangeWindow = _vertScrollBar->GetRangeWindow();
+ int nBottom = nMax - nRangeWindow;
+ if ( nBottom < 0 )
+ {
+ nBottom = 0;
+ }
+
+ // set the alpha on the up arrow
+ int nAlpha = ( nScrollPos - nMin <= 0 ) ? 90 : 255;
+ m_pUpArrow->SetAlpha( nAlpha );
+
+ // set the alpha on the down arrow
+ nAlpha = ( nScrollPos >= nBottom ) ? 90 : 255;
+ m_pDownArrow->SetAlpha( nAlpha );
+
+ ScrollBarSlider *pSlider = _vertScrollBar->GetSlider();
+ if ( pSlider && pSlider->GetRangeWindow() > 0 )
+ {
+ int x, y, w, t, min, max;
+ m_pLine->GetBounds( x, y, w, t );
+ pSlider->GetNobPos( min, max );
+
+ m_pBox->SetBounds( x, y + min, w, ( max - min ) );
+ }
+ }
+ else
+ {
+ // turn off our images
+ SetScrollBarImagesVisible ( false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Rich text control that knows how to fill itself with information
+// that describes a specific item definition.
+//-----------------------------------------------------------------------------
+CEconItemDetailsRichText::CEconItemDetailsRichText( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName ),
+ m_bAllowItemSetLinks( false ),
+ m_bLimitedItem( false ),
+ m_hLinkFont( INVALID_FONT )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ const char *pszHighlightColor = inResourceData->GetString( "highlight_color", "Orange" );
+ const char *pszItemSetColor = inResourceData->GetString( "itemset_color", "Blue" );
+ const char *pszLinkColor = inResourceData->GetString( "link_color", "LightOrange" );
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ m_colTextHighlight = pScheme->GetColor( pszHighlightColor, Color( 255, 255, 255, 255 ) );
+ m_colItemSet = pScheme->GetColor( pszItemSetColor, Color( 255, 255, 255, 255 ) );
+ m_colLink = pScheme->GetColor( pszLinkColor, Color( 255, 255, 255, 255 ) );
+ m_hLinkFont = pScheme->GetFont( "Link", true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetUnderlineFont( m_hLinkFont );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::UpdateDetailsForItem( const CEconItemDefinition *pDef )
+{
+ SetText( "" );
+
+ if ( !m_ToolList.Count() )
+ {
+ UpdateToolList();
+ }
+
+ DataText_AppendStoreFlags( pDef );
+ DataText_AppendItemData( pDef );
+ DataText_AppendAttributeData( pDef );
+ DataText_AppendUsageData( pDef );
+ DataText_AppendToolUsage( pDef );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::AddDataText( const char *pszText, bool bAddPostLines, const wchar_t *wpszArg, const wchar_t *wpszArg2, const int *pItemDefIndex )
+{
+ static wchar_t wszConstructedString[4096];
+ static wchar_t wszText[4096];
+
+ if ( pszText[0] != '#' )
+ {
+ InsertString( pszText );
+ return;
+ }
+
+ wchar_t *pLocText = g_pVGuiLocalize->Find( pszText );
+ if ( wpszArg && pLocText )
+ {
+ if ( wpszArg2 )
+ {
+ g_pVGuiLocalize->ConstructString_safe( wszConstructedString, pLocText, 2, wpszArg, wpszArg2 );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConstructString_safe( wszConstructedString, pLocText, 1, wpszArg );
+ }
+ pLocText = wszConstructedString;
+ }
+
+ if ( pLocText )
+ {
+ enum
+ {
+ STATE_COLOR_NORMAL = 1,
+ STATE_COLOR_HINT,
+ STATE_COLOR_ITEMSET,
+ STATE_LINK_START,
+ STATE_LINK_STOP,
+ };
+
+ Color color = GetFgColor();
+ Color newColor = color;
+ int startIdx = 0;
+ int endIdx = 0;
+ bool bContinue = true;
+ bool bInLink = false;
+ while ( bContinue )
+ {
+ bool bSetText = false;
+ bool bEnd = false;
+
+ switch ( pLocText[endIdx] )
+ {
+ case 0:
+ bContinue = false;
+ bSetText = true;
+ bEnd = true;
+ break;
+ case STATE_COLOR_NORMAL:
+ newColor = GetFgColor();
+ bSetText = true;
+ break;
+ case STATE_COLOR_HINT:
+ newColor = m_colTextHighlight;
+ bSetText = true;
+ break;
+ case STATE_COLOR_ITEMSET:
+ newColor = m_colItemSet;
+ bSetText = true;
+ break;
+ case STATE_LINK_START:
+ bInLink = true;
+ break;
+ }
+
+ if ( startIdx != endIdx )
+ {
+ if ( bSetText )
+ {
+ // copy the colored text to wide
+ int len = endIdx - startIdx + 1;
+ wcsncpy( wszText, pLocText + startIdx, len );
+ wszText[len-1] = 0;
+
+ // If the next character isn't the end of a link, insert the string
+ if ( bInLink && pItemDefIndex )
+ {
+ InsertItemLink( wszText, *pItemDefIndex, &color );
+ }
+ else
+ {
+ InsertColorChange( color );
+ InsertString( wszText );
+ }
+ bInLink = false;
+ color = newColor;
+
+ // skip past the color change character
+ startIdx = endIdx + 1;
+ }
+ }
+ ++endIdx;
+ }
+
+ if ( bAddPostLines )
+ {
+ InsertString( L"\n\n" );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendUsageData( const CEconItemDefinition *pBaseDef )
+{
+ // Don't show class/slot usage for class/slot tokens
+ if ( pBaseDef->GetItemClass() && ( !V_strcmp( pBaseDef->GetItemClass(), "class_token" ) || !V_strcmp( pBaseDef->GetItemClass(), "slot_token" ) ) )
+ return;
+
+#if defined(TF_DLL) || defined(TF_CLIENT_DLL)
+ const CTFItemDefinition *pDef = dynamic_cast< const CTFItemDefinition *>( pBaseDef );
+ if ( !pDef )
+ return;
+
+ // Class usage
+ if ( pDef->CanBeUsedByAllClasses() )
+ {
+ if ( pDef->GetBundleInfo() != NULL )
+ {
+ AddDataText( "#TF_Armory_Item_ClassUsageAllBundle", false );
+ }
+ else
+ {
+ AddDataText( "#TF_Armory_Item_ClassUsageAll", false );
+ }
+ AddDataText( "\n" );
+ }
+ else
+ {
+ bool bFirst = true;
+ for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
+ {
+ if ( pDef->CanBeUsedByClass(i) )
+ {
+ if ( bFirst )
+ {
+ bFirst = false;
+
+ if ( pDef->GetBundleInfo() != NULL )
+ {
+ AddDataText( "#TF_Armory_Item_ClassUsageBundle", false );
+ }
+ else
+ {
+ AddDataText( "#TF_Armory_Item_ClassUsage", false );
+ }
+ }
+ else
+ {
+ AddDataText( ", " );
+ }
+
+ const wchar_t *pwszClassName = g_pVGuiLocalize->Find( g_aPlayerClassNames[i] );
+ if ( pwszClassName )
+ {
+ InsertColorChange( m_colTextHighlight );
+ InsertString( pwszClassName );
+ InsertColorChange( GetFgColor() );
+ }
+ }
+ }
+ if ( !bFirst )
+ {
+ AddDataText( ".\n" );
+ }
+ }
+
+ // Slot usage. First, find out if everyone uses it in the same slot, or whether it's used in different slots per class
+ bool bHasPerClassSlots = false;
+ int iDefaultSlot = pDef->GetDefaultLoadoutSlot();
+ for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
+ {
+ if ( !pDef->CanBeUsedByClass(i) )
+ continue;
+
+ int iClassSlot = pDef->GetLoadoutSlot(i);
+ if ( iClassSlot != iDefaultSlot )
+ {
+ bHasPerClassSlots = true;
+ break;
+ }
+ }
+ // Now print the easy line, or the per-class lines
+ if ( !bHasPerClassSlots )
+ {
+ if ( iDefaultSlot != -1 )
+ {
+ AddDataText( "#TF_Armory_Item_SlotUsageAll", true, g_pVGuiLocalize->Find( ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pDef->GetEquipType() )[iDefaultSlot] ) );
+ }
+ }
+ else
+ {
+ bool bFirst = true;
+ for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
+ {
+ if ( !pDef->CanBeUsedByClass(i) )
+ continue;
+
+ if ( bFirst )
+ {
+ bFirst = false;
+ AddDataText( "#TF_Armory_Item_SlotUsageClassHeader", false );
+ }
+ else
+ {
+ AddDataText( ", " );
+ }
+
+ int iClassSlot = pDef->GetLoadoutSlot(i);
+ AddDataText( "#TF_Armory_Item_SlotUsageClass", false, g_pVGuiLocalize->Find( ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pDef->GetEquipType() )[iClassSlot] ), g_pVGuiLocalize->Find( g_aPlayerClassNames[i] ) );
+ }
+ if ( !bFirst )
+ {
+ AddDataText( ".\n\n" );
+ }
+ }
+#endif // #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendToolUsage( const CEconItemDefinition *pDef )
+{
+ // Loop through the tools, and list any that can be applied to this item
+ bool bFirstTool = true;
+ for ( int i = 0; i < m_ToolList.Count(); i++ )
+ {
+ const GameItemDefinition_t *pToolDef = dynamic_cast<const GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( m_ToolList[i] ) );
+
+ if ( !CEconSharedToolSupport::ToolCanApplyToDefinition( pToolDef, dynamic_cast<const GameItemDefinition_t *>( pDef ) ) )
+ continue;
+
+ if ( bFirstTool )
+ {
+ bFirstTool = false;
+ AddDataText( "#TF_Armory_Item_ToolUsage", false );
+ }
+ else
+ {
+ AddDataText( ", " );
+ }
+
+ // Create a link to the item
+ {
+ // we need an econ item view here for just the item name
+ CEconItemView tmpTool;
+ tmpTool.Init( m_ToolList[i], AE_USE_SCRIPT_VALUE, AE_USE_SCRIPT_VALUE, true );
+
+ InsertItemLink( tmpTool.GetItemName(), pToolDef->GetDefinitionIndex() );
+ }
+ }
+ if ( !bFirstTool )
+ {
+ AddDataText( ".\n" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendStoreFlags( const CEconItemDefinition *pDef )
+{
+ if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
+ return;
+
+ const bool bHolidayRestriction = pDef->GetHolidayRestriction() != NULL && V_strlen( pDef->GetHolidayRestriction() ) > 0;
+ if ( bHolidayRestriction )
+ {
+ wchar_t *pRestrictedText = g_pVGuiLocalize->Find( "#Store_HolidayRestrictionText" );
+
+ if ( pRestrictedText )
+ {
+ InsertColorChange( Color( 200, 80, 60, 255 ) );
+ InsertString( pRestrictedText );
+ InsertString( L".\n\n" );
+ }
+ }
+
+ if ( m_bLimitedItem )
+ {
+ wchar_t *pLocText = bHolidayRestriction
+ ? g_pVGuiLocalize->Find( "#TF_Armory_Item_Limited_Holiday" )
+ : g_pVGuiLocalize->Find( "#TF_Armory_Item_Limited" );
+
+ if ( pLocText )
+ {
+ InsertColorChange( Color( 255, 140, 0, 255 ) );
+ InsertString ( pLocText );
+ InsertString( L"\n\n" );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendItemData( const CEconItemDefinition *pDef )
+{
+ if ( !GetItemSchema() )
+ return;
+
+ // Start by looking for a specified armory desc string
+ const char *pDesc = pDef->GetArmoryDescString();
+ if ( pDesc && pDesc[0] )
+ {
+ const ArmoryStringDict_t &ArmoryItemData = ItemSystem()->GetItemSchema()->GetArmoryDataItems();
+
+ // Tokenize it, and look for localization strings for each token
+ CUtlVector< char * > vecArmoryKeys;
+ Q_SplitString( pDesc, " ", vecArmoryKeys );
+ FOR_EACH_VEC( vecArmoryKeys, i )
+ {
+ int iIdx = ArmoryItemData.Find( vecArmoryKeys[i] );
+ if ( ArmoryItemData.IsValidIndex( iIdx ) )
+ {
+ const char *pLoc = ArmoryItemData.Element( iIdx ).Get();
+ AddDataText( pLoc );
+ }
+ }
+ vecArmoryKeys.PurgeAndDeleteElements();
+ }
+
+ // Is this item part of a set?
+ if ( pDef->GetItemSetDefinition() )
+ {
+ DataText_AppendSetData( pDef );
+ }
+
+ if ( pDef->GetBundleInfo() != NULL )
+ {
+ DataText_AppendBundleData( pDef );
+ }
+
+ // Does this item type have data associated with it?
+ const ArmoryStringDict_t &ArmoryItemTypeData = GetItemSchema()->GetArmoryDataItemTypes();
+ int iIdx = ArmoryItemTypeData.Find( pDef->GetItemTypeName() );
+ if ( ArmoryItemTypeData.IsValidIndex( iIdx ) )
+ {
+ const char *pLoc = ArmoryItemTypeData.Element( iIdx ).Get();
+ AddDataText( pLoc );
+ }
+
+ // Does this item class have data associated with it?
+ const ArmoryStringDict_t &ArmoryItemClassData = GetItemSchema()->GetArmoryDataItemClasses();
+ iIdx = pDef->GetItemClass() ? ArmoryItemClassData.Find( pDef->GetItemClass() ) : ArmoryItemClassData.InvalidIndex();
+ if ( ArmoryItemClassData.IsValidIndex( iIdx ) )
+ {
+ if ( !pDef->GetDefinitionKey( "hack_disable_armory_type_desc" ) )
+ {
+ const char *pLoc = ArmoryItemClassData.Element( iIdx ).Get();
+ AddDataText( pLoc );
+ }
+ }
+
+ // Can this item be earned by an achievement?
+ const AchievementAward_t *pAchievementAward = GetItemSchema()->GetAchievementRewardByDefIndex( pDef->GetDefinitionIndex() );
+ if( pAchievementAward )
+ {
+ wchar_t *pszAchName = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievementAward->m_sNativeName.String() );
+ if ( pszAchName )
+ {
+ AddDataText( "#TF_Armory_Item_AchievementReward", true, pszAchName );
+ }
+ }
+
+ // Is this a Holiday item?
+ if ( pDef->GetHolidayRestriction() )
+ {
+ AddDataText( "#TF_Armory_Item_HolidayRestriction" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendBundleData( const CEconItemDefinition *pDef )
+{
+ bool bFirstItem = true;
+
+ const bundleinfo_t *pBundleInfo = pDef->GetBundleInfo();
+ FOR_EACH_VEC( pBundleInfo->vecItemDefs, i )
+ {
+ CEconItemDefinition *pBundledItem = pBundleInfo->vecItemDefs[i];
+ if ( pBundledItem )
+ {
+ if ( bFirstItem )
+ {
+ bFirstItem = false;
+ AddDataText( "#TF_Armory_Item_Bundle", false );
+ }
+ else
+ {
+ AddDataText( ", " );
+ }
+
+ CEconItemView bundleItemData;
+ bundleItemData.Init( pBundledItem->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+
+ InsertItemLink( bundleItemData.GetItemName(), bundleItemData.GetItemDefIndex() );
+ }
+ }
+
+ if ( !bFirstItem )
+ {
+ AddDataText( ".\n\n" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendAttributeData( const CEconItemDefinition *pDef )
+{
+ if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
+ return;
+
+ const ArmoryStringDict_t &ArmoryAttribData = ItemSystem()->GetItemSchema()->GetArmoryDataAttributes();
+
+ CVarBitVec m_AttribsShown;
+ m_AttribsShown.Resize( ArmoryAttribData.Count() );
+ m_AttribsShown.ClearAll();
+
+ const CUtlVector<static_attrib_t> &vecStaticAttribs = pDef->GetStaticAttributes();
+ FOR_EACH_VEC( vecStaticAttribs, i )
+ {
+ const static_attrib_t &attrib = vecStaticAttribs[i];
+ CEconItemAttributeDefinition *pAttributeDef = ItemSystem()->GetStaticDataForAttributeByDefIndex( attrib.iDefIndex );
+ if ( !pAttributeDef )
+ continue;
+ if ( pAttributeDef->IsHidden() )
+ continue;
+
+ const char *pDesc = pAttributeDef->GetArmoryDescString();
+ if ( !pDesc || !pDesc[0] )
+ continue;
+
+ // Tokenize it, and look for localization strings for each token
+ CUtlVector< char * > vecArmoryKeys;
+ Q_SplitString( pDesc, " ", vecArmoryKeys );
+ FOR_EACH_VEC( vecArmoryKeys, iKey )
+ {
+ int iIdx = ArmoryAttribData.Find( vecArmoryKeys[iKey] );
+ if ( ArmoryAttribData.IsValidIndex( iIdx ) )
+ {
+ if ( m_AttribsShown[iIdx] == false )
+ {
+ const char *pLoc = ArmoryAttribData.Element( iIdx ).Get();
+ AddDataText( pLoc );
+
+ m_AttribsShown.Set( iIdx );
+ }
+ }
+ }
+
+ vecArmoryKeys.PurgeAndDeleteElements();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::DataText_AppendSetData( const CEconItemDefinition *pDef )
+{
+ if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
+ return;
+
+ CEconItemSchema *pSchema = ItemSystem()->GetItemSchema();
+ if ( pSchema )
+ {
+ const CEconItemSetDefinition *pItemSet = pDef->GetItemSetDefinition();
+ if ( pItemSet )
+ {
+ // Does this set provide bonus attributes when completely worn?
+ if ( pItemSet->m_iAttributes.Count() > 0 )
+ {
+ // Used for grabbing display colors.
+ vgui::HScheme hScheme = vgui::scheme()->GetScheme( "ClientScheme" );
+ vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( hScheme );
+
+ Assert( pScheme );
+
+ // Insert the set description
+ wchar_t *pLocText = g_pVGuiLocalize->Find( pItemSet->m_pszLocalizedName );
+ AddDataText( "#TF_Armory_Item_InSet", false, pLocText, NULL, m_bAllowItemSetLinks ? &pItemSet->m_iBundleItemDef : NULL );
+
+ for ( int i = 0; i < pItemSet->m_iAttributes.Count(); i++ )
+ {
+ const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( pItemSet->m_iAttributes[i].m_iAttribDefIndex );
+ if ( !pAttrDef )
+ continue;
+
+ CEconAttributeDescription AttrDesc( GLocalizationProvider(), pAttrDef, pItemSet->m_iAttributes[i].m_flValue );
+ if ( !AttrDesc.GetDescription().IsEmpty() )
+ {
+ InsertColorChange( pScheme->GetColor( GetColorNameForAttribColor( AttrDesc.GetDefaultColor() ), Color(255, 255, 255, 255) ) );
+ AddDataText( " " );
+ InsertString( AttrDesc.GetDescription().Get() );
+ AddDataText( "\n" );
+ }
+ }
+
+ AddDataText( "\n" );
+ }
+ // This set is visual and provides no additional bonuses when worn completely.
+ else
+ {
+ // Insert the set description
+ wchar_t *pLocText = g_pVGuiLocalize->Find( pItemSet->m_pszLocalizedName );
+ AddDataText( "#TF_Armory_Item_InSet_NoBonus", false, pLocText, NULL, m_bAllowItemSetLinks ? &pItemSet->m_iBundleItemDef : NULL );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::UpdateToolList( void )
+{
+ m_ToolList.Purge();
+
+ // Find all the tool types in our items list
+ const CEconItemSchema::ToolsItemDefinitionMap_t &mapItemDefs = ItemSystem()->GetItemSchema()->GetToolsItemDefinitionMap();
+ FOR_EACH_MAP( mapItemDefs, i )
+ {
+ const CEconItemDefinition *pDef = mapItemDefs[i];
+ if ( !pDef->GetItemClass() )
+ continue;
+
+ if ( !pDef->IsTool() )
+ continue;
+
+ const IEconTool *pEconTool = pDef->GetEconTool();
+ if ( !pEconTool )
+ continue;
+
+ if ( !pEconTool->ShouldDisplayAsUseableOnItemsInArmory() )
+ continue;
+
+ // Now make sure it doesn't have the same type as an existing tool
+ bool bAlreadyFound = false;
+
+ FOR_EACH_VEC( m_ToolList, tool )
+ {
+ CEconItemDefinition *pOtherDef = ItemSystem()->GetStaticDataForItemByDefIndex( m_ToolList[tool] );
+ Assert( pOtherDef );
+
+ const IEconTool *pOtherEconTool = pOtherDef->GetEconTool();
+ Assert( pOtherEconTool );
+
+ bAlreadyFound = !V_strcmp( pEconTool->GetTypeName(), pOtherEconTool->GetTypeName() );
+ if ( bAlreadyFound )
+ {
+ break;
+ }
+ }
+
+ if ( !bAlreadyFound )
+ {
+ m_ToolList.AddToTail( pDef->GetDefinitionIndex() );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEconItemDetailsRichText::InsertItemLink( const wchar_t *pwzItemName, int iItemDef, Color *pColorOverride )
+{
+ char szTmpToolName[256];
+ ::ILocalize::ConvertUnicodeToANSI(pwzItemName, szTmpToolName, sizeof( szTmpToolName ));
+ char szToolStoreURL[256];
+ V_snprintf( szToolStoreURL, sizeof( szToolStoreURL ), "<a href=item://%u>%s</a>", iItemDef, szTmpToolName );
+ InsertPossibleURLString( szToolStoreURL, pColorOverride ? *pColorOverride : m_colLink, GetFgColor() );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExplanationPopup::CExplanationPopup(Panel *parent, const char *panelName) : vgui::EditablePanel( parent, panelName )
+{
+ m_pCallout = new CExplanationPopupCalloutArrow( parent );
+ m_pCallout->SetVisible( false );
+ m_pCallout->SetAutoDelete( false );
+
+ m_szPrevExplanation[0] = '\0';
+ m_szNextExplanation[0] = '\0';
+ m_bFinishedPopup = false;
+
+ ListenForGameEvent( "gameui_hidden" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CExplanationPopup::~CExplanationPopup( void )
+{
+ m_pCallout->MarkForDeletion();
+ m_pCallout = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::OnCommand( const char *command )
+{
+ if ( !Q_stricmp( command, "close" ) )
+ {
+ Hide( 0 );
+ }
+ else if ( !Q_stricmp( command, "nextexplanation" ) )
+ {
+ Hide( 1 );
+ }
+ else if ( !Q_stricmp( command, "prevexplanation" ) )
+ {
+ Hide( -1 );
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::Hide( int iExplanationDelta )
+{
+ int iPos = m_iPositionInChain;
+ const char *pszMoveTo = NULL;
+ if ( iExplanationDelta == -1 )
+ {
+ if ( !m_szPrevExplanation || m_szPrevExplanation[ 0 ] == '\0' )
+ return;
+
+ pszMoveTo = m_szPrevExplanation;
+ iPos--;
+ }
+ else if ( iExplanationDelta == 1 )
+ {
+ if ( !m_szNextExplanation || m_szNextExplanation[ 0 ] == '\0' )
+ return;
+
+ pszMoveTo = m_szNextExplanation;
+ iPos++;
+ }
+
+ SetVisible( false );
+ m_pCallout->SetVisible( false );
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+
+ if ( m_bForceClose )
+ {
+ TFModalStack()->PopModal( this );
+ }
+
+ if ( iExplanationDelta == 0 )
+ {
+ if ( GetParent() )
+ {
+ GetParent()->NavigateTo();
+ }
+
+ return;
+ }
+
+ CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( GetParent()->FindChildByName( pszMoveTo ) );
+ if ( pPopup )
+ {
+ pPopup->Popup( iPos, m_iTotalInChain );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::Popup( int iPosition, int iTotalPanels )
+{
+ // Parent this to our parent. Doing it in our constructor doesn't work because
+ // the parent passed in there hasn't been initialized properly.
+ m_pCallout->SetParent( GetParent() );
+ m_pCallout->SetZPos( GetZPos() - 1 );
+
+ if ( m_bForceClose )
+ {
+ TFModalStack()->PushModal( this );
+ }
+
+ // If they don't specify X,Y,W,H, we start tiny on the callout position
+ if ( !m_iStartX && !m_iStartY )
+ {
+ m_iStartX = m_iCalloutInParentsX;
+ m_iStartY = m_iCalloutInParentsY;
+ }
+ if ( !m_iStartW && !m_iStartH )
+ {
+ m_iStartW = 1;
+ m_iStartH = 1;
+ }
+
+ // If we weren't given a position, we're the first in a chain. Figure out
+ // how many there are in the total chain.
+ m_iPositionInChain = iPosition;
+ m_iTotalInChain = iTotalPanels;
+ if ( !m_iTotalInChain )
+ {
+ m_iTotalInChain = 0;
+ m_iPositionInChain = 1;
+ CExplanationPopup *pPopup = this;
+ while ( pPopup )
+ {
+ m_iTotalInChain++;
+
+ const char *pszNext = pPopup->GetNextExplanation();
+ if ( !pszNext[0] )
+ break;
+
+ const char *pszPrev = pPopup->GetName();
+ pPopup = dynamic_cast<CExplanationPopup*>( GetParent()->FindChildByName( pszNext ) );
+ if ( pPopup )
+ {
+ pPopup->SetPrevExplanation( pszPrev );
+ }
+ }
+ }
+
+ // Now assemble our position label
+ char szTmp[16];
+ Q_snprintf(szTmp, 16, "%d/%d", m_iPositionInChain, m_iTotalInChain );
+ SetDialogVariable( "explanationnumber", szTmp );
+
+ SetBounds( m_iStartX, m_iStartY, m_iStartW, m_iStartH );
+ SetVisible( true );
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ m_flStartTime = Plat_FloatTime();
+ m_flEndTime = m_flStartTime + 0.5;
+ m_bFinishedPopup = false;
+
+ // If our endX & endW is going to result in us being off the side of the screen, move back on
+ if ( m_iEndX < 0 )
+ {
+ m_iEndX = XRES(5);
+ }
+ else if ( (m_iEndX + m_iEndW) > ScreenWidth() )
+ {
+ m_iEndX = ScreenWidth() - m_iEndW - XRES(5);
+ }
+
+ // Figure out what side of the bubble we should have the arrow attached to
+ m_iCalloutSide = EXC_SIDE_TOP;
+ Vector vecCallout( m_iCalloutInParentsX, m_iCalloutInParentsY, 0 );
+ Vector vecMins( m_iEndX, m_iEndY, 0 );
+ Vector vecMaxs( m_iEndX + m_iEndW, m_iEndY + m_iEndH, 0 );
+ Vector vecPoint;
+ CalcClosestPointOnAABB( vecMins, vecMaxs, vecCallout, vecPoint );
+
+ if ( vecPoint.x == vecMins.x && vecCallout.x != vecMins.x )
+ {
+ m_iCalloutSide = EXC_SIDE_LEFT;
+ }
+ else if ( vecPoint.y == vecMins.y && vecCallout.y != vecMins.y )
+ {
+ m_iCalloutSide = EXC_SIDE_TOP;
+ }
+ else if ( vecPoint.x == vecMaxs.x && vecCallout.x != vecMaxs.x )
+ {
+ m_iCalloutSide = EXC_SIDE_RIGHT;
+ }
+ else
+ {
+ m_iCalloutSide = EXC_SIDE_BOTTOM;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::OnTick( void )
+{
+ float flElapsed = Plat_FloatTime() - m_flStartTime;
+ float flTotal = m_flEndTime - m_flStartTime;
+ float flBias = Bias( RemapValClamped( flElapsed, 0.f, flTotal, 0.f, 1.f ), 0.7f );
+ flElapsed = flTotal * flBias;
+
+ if ( flElapsed >= flTotal )
+ {
+ //vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ if ( !m_bFinishedPopup )
+ {
+ SetBounds( m_iEndX, m_iEndY, m_iEndW, m_iEndH );
+ PositionCallout( 1.0 );
+ m_bFinishedPopup = true;
+ }
+
+ // If we've lost focus, or been hidden, release our modal lock
+ if ( !ipanel()->IsFullyVisible( GetVPanel() ))
+ {
+ Hide(0);
+ }
+ return;
+ }
+
+ int iExpandW = XRES(30);
+ int iExpandH = YRES(30);
+ int iExpandedW = m_iEndW + iExpandW;
+ int iExpandedH = m_iEndH + iExpandH;
+ int iExpandedX = m_iEndX - (iExpandW * 0.5);
+ int iExpandedY = m_iEndY - (iExpandH * 0.5);
+
+ int iW, iH, iX, iY;
+ float flExpandTime = (flTotal * 0.66);
+
+ PositionCallout( RemapVal( flElapsed, 0, flTotal, 0, 1 ) );
+
+// iW = RemapValClamped( flElapsed, 0, flTotal, m_iStartW, m_iEndW );
+// iH = RemapValClamped( flElapsed, 0, flTotal, m_iStartH, m_iEndH );
+// iX = RemapValClamped( flElapsed, 0, flTotal, m_iStartX, m_iEndX );
+// iY = RemapValClamped( flElapsed, 0, flTotal, m_iStartY, m_iEndY );
+// SetBounds( iX, iY, iW, iH );
+// return;
+
+ if ( flElapsed < flExpandTime )
+ {
+ // Expand to greater than the end size
+ iW = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartW, iExpandedW );
+ iH = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartH, iExpandedH );
+ iX = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartX, iExpandedX );
+ iY = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartY, iExpandedY );
+ }
+ else
+ {
+ // Contract to the end size
+ iW = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedW, m_iEndW );
+ iH = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedH, m_iEndH );
+ iX = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedX, m_iEndX );
+ iY = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedY, m_iEndY );
+ }
+ SetBounds( iX, iY, iW, iH );
+}
+
+void CExplanationPopup::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( IsVisible() && m_pCallout && m_pCallout->IsVisible() )
+ {
+ // swallow all keys
+ if ( code == KEY_ESCAPE )
+ {
+ OnCommand( "close" );
+ return;
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( IsVisible() && m_pCallout && m_pCallout->IsVisible() )
+ {
+ ButtonCode_t nButtonCode = GetBaseButtonCode( code );
+
+ // swallow all keys
+ if ( nButtonCode == KEY_XBUTTON_B )
+ {
+ OnCommand( "close" );
+ return;
+ }
+ else if ( nButtonCode == KEY_XBUTTON_LEFT ||
+ nButtonCode == KEY_XSTICK1_LEFT ||
+ nButtonCode == KEY_XSTICK2_LEFT ||
+ code == KEY_LEFT )
+ {
+ OnCommand( "prevexplanation" );
+ return;
+ }
+ else if ( nButtonCode == KEY_XBUTTON_RIGHT ||
+ nButtonCode == KEY_XSTICK1_RIGHT ||
+ nButtonCode == KEY_XSTICK2_RIGHT ||
+ code == KEY_RIGHT )
+ {
+ OnCommand( "nextexplanation" );
+ return;
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::PositionCallout( float flElapsed )
+{
+ // Size and position the callout
+ if ( !m_pCallout->IsVisible() )
+ {
+ m_pCallout->SetVisible( true );
+ }
+
+ int iCalloutSize = 20;
+ int iIndent = 15;
+
+ int iMyPos[2];
+ GetPos( iMyPos[0], iMyPos[1] );
+ int iMySize[2];
+ iMySize[0] = GetWide();
+ iMySize[1] = GetTall();
+
+ int iCalloutPos[2];
+ iCalloutPos[0] = m_iCalloutInParentsX;
+ iCalloutPos[1] = m_iCalloutInParentsY;
+
+ // We need to figure out the three corners of the callout triangle, in parent space
+ int iArrowA[2];
+ int iArrowB[2];
+ int iW, iH, iX, iY;
+
+ // Determine which axis the arrow's extruding along
+ int x = (m_iCalloutSide == EXC_SIDE_TOP || m_iCalloutSide == EXC_SIDE_BOTTOM) ? 0 : 1;
+ int y = !x;
+
+ // Figure out where the center will be of the arrow on the edge that the arrow's extruding (ensure it's always somewhat indented from the corners)
+ iArrowA[x] = iMyPos[x] + clamp( iCalloutPos[x] - iMyPos[x] - XRES(iCalloutSize * 0.5), XRES(iIndent), iMySize[x] - XRES(iIndent) - XRES(iCalloutSize) );
+ iArrowB[x] = iArrowA[x] + XRES(iCalloutSize);
+ iArrowA[y] = iMyPos[y] + (( iCalloutPos[y] > iMyPos[y] ) ? iMySize[y] : 0);
+ iArrowB[y] = iMyPos[y] + (( iCalloutPos[y] > iMyPos[y] ) ? iMySize[y] : 0);
+
+ // Slide the arrow out towards the callout over time.
+ for ( int i = 0; i < 2; i++ )
+ {
+ iCalloutPos[i] = RemapValClamped( flElapsed, 0, 1, iArrowA[i] + (iArrowB[i] - iArrowA[i]), iCalloutPos[i] );
+ }
+
+ // Assemble a bounding box that contains the arrow points
+ iX = MIN( MIN( iCalloutPos[0], iArrowA[0] ), iArrowB[0] );
+ iW = MAX( MAX( iCalloutPos[0], iArrowA[0] ), iArrowB[0] ) - iX;
+ iY = MIN( MIN( iCalloutPos[1], iArrowA[1] ), iArrowB[1] );
+ iH = MAX( MAX( iCalloutPos[1], iArrowA[1] ), iArrowB[1] ) - iY;
+ m_pCallout->SetBounds( iX, iY, iW+1, iH+1 );
+
+ //Msg("CALLOUT: %d %d, %d %d\n", iX,iY,iW,iH );
+
+ // Tell the callout where its points are, so it can draw the triangle (make sure the triangle is facing the camera)
+ if ( m_iCalloutSide == EXC_SIDE_TOP || m_iCalloutSide == EXC_SIDE_RIGHT )
+ {
+ m_pCallout->SetArrowPoints( iCalloutPos[0]-iX, iCalloutPos[1]-iY, iArrowB[0]-iX, iArrowB[1]-iY, iArrowA[0]-iX, iArrowA[1]-iY );
+ }
+ else
+ {
+ m_pCallout->SetArrowPoints( iCalloutPos[0]-iX, iCalloutPos[1]-iY, iArrowA[0]-iX, iArrowA[1]-iY, iArrowB[0]-iX, iArrowB[1]-iY );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopupCalloutArrow::Paint( void )
+{
+ int x,y;
+ vgui::ipanel()->GetAbsPos(GetVPanel(), x,y );
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( materials->FindMaterial( "vgui/callout_tail", TEXTURE_GROUP_OTHER ), NULL );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh();
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
+
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.TexCoord2f( 0, 1.0,0.5 );
+ meshBuilder.Position3f( x + m_iArrowA[0], y + m_iArrowA[1], 1 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.TexCoord2f( 0, 0,1 );
+ meshBuilder.Position3f( x + m_iArrowB[0], y + m_iArrowB[1], 1 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.TexCoord2f( 0, 0,0 );
+ meshBuilder.Position3f( x + m_iArrowC[0], y + m_iArrowC[1], 1 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+// vgui::surface()->DrawSetColor( Color(0,255,0,255) );
+// vgui::surface()->DrawLine( m_iArrowA[0], m_iArrowA[1], m_iArrowB[0], m_iArrowB[1] );
+// vgui::surface()->DrawLine( m_iArrowA[0], m_iArrowA[1], m_iArrowC[0], m_iArrowC[1] );
+// vgui::surface()->DrawLine( m_iArrowB[0], m_iArrowB[1], m_iArrowC[0], m_iArrowC[1] );
+// vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ Q_strncpy( m_szNextExplanation, inResourceData->GetString( "next_explanation", "" ), sizeof( m_szNextExplanation ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::SetPrevExplanation( const char *pszPrev )
+{
+ m_szPrevExplanation[0] = '\0';
+ if ( pszPrev && pszPrev[0] )
+ {
+ Q_strncpy( m_szPrevExplanation, pszPrev, sizeof( m_szPrevExplanation ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CExplanationPopup::FireGameEvent( IGameEvent *event )
+{
+ const char * type = event->GetName();
+
+ if ( Q_strcmp(type, "gameui_hidden") == 0 )
+ {
+ if ( IsVisible() )
+ {
+ Hide( 0 );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPanelModalStack g_ModalStack;
+CPanelModalStack *TFModalStack( void )
+{
+ return &g_ModalStack;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelModalStack::PushModal( vgui::Panel *pDialog )
+{
+ VPanelHandle hHandle;
+ hHandle.Set( pDialog->GetVPanel() );
+
+ FOR_EACH_VEC( m_pDialogs, i )
+ {
+ if ( m_pDialogs[i] == hHandle )
+ return;
+ }
+
+ m_pDialogs.AddToHead( hHandle );
+
+ vgui::input()->SetAppModalSurface( pDialog->GetVPanel() );
+ pDialog->RequestFocus();
+ pDialog->MoveToFront();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelModalStack::PopModal( vgui::Panel *pDialog )
+{
+ bool bFound = false;
+ FOR_EACH_VEC_BACK( m_pDialogs, i )
+ {
+ if ( m_pDialogs[i].Get() == pDialog->GetVPanel() )
+ {
+ PopModal( i );
+ bFound = true;
+ }
+ }
+
+ AssertMsg( bFound, "CPanelModalStack::PopModal() failed to find the given dialog." );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelModalStack::PopModal( int iIdx )
+{
+ bool bRecalcLock = false;
+
+ // Only release the modal lock if we had it
+ VPANEL hPanel = vgui::input()->GetAppModalSurface();
+ if ( !hPanel || m_pDialogs[iIdx].Get() == hPanel )
+ {
+ bRecalcLock = true;
+ }
+
+ m_pDialogs.Remove(iIdx);
+
+ if ( bRecalcLock )
+ {
+ if ( m_pDialogs.Count() )
+ {
+ vgui::input()->SetAppModalSurface( m_pDialogs[0] );
+ }
+ else
+ {
+ vgui::input()->SetAppModalSurface( NULL );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelModalStack::Update( void )
+{
+ if ( m_pDialogs.Count() <= 0 )
+ return;
+
+ // Don't run this logic if the game UI isn't visible
+ if ( !enginevgui->IsGameUIVisible() )
+ return;
+
+ // Safety check: If the app model surface dialog is in our list, make sure it's usable
+ VPANEL hPanel = vgui::input()->GetAppModalSurface();
+
+ FOR_EACH_VEC_BACK( m_pDialogs, i )
+ {
+ // Pop dialogs that didn't correctly remove themselves on delete
+ if ( m_pDialogs[i].Get() == 0 )
+ {
+ PopModal( i );
+ continue;
+ }
+
+ if ( m_pDialogs[i].Get() == hPanel )
+ {
+ Assert( vgui::ipanel()->IsFullyVisible(hPanel) );
+
+ // Backup hack: If our modal window is no longer visible, make it visible
+ if ( !vgui::ipanel()->IsFullyVisible(hPanel) )
+ {
+ vgui::ipanel()->SetVisible( hPanel, true );
+ vgui::ipanel()->MoveToFront( hPanel );
+ vgui::ipanel()->RequestFocus( hPanel );
+
+ // Make sure all our parents are visible too
+ VPANEL hParent = vgui::ipanel()->GetParent( hPanel );
+ while ( hParent != INVALID_PANEL )
+ {
+ vgui::Panel *pParentPanel = vgui::ipanel()->GetPanel(hParent, "ClientDLL");
+ if ( !pParentPanel )
+ break;
+
+ vgui::ipanel()->SetVisible( hParent, true );
+ hParent = vgui::ipanel()->GetParent( hParent );
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+vgui::VPanelHandle CPanelModalStack::Top()
+{
+ if ( m_pDialogs.Count() == 0 )
+ {
+ return VPanelHandle(); // Defaults to INVALID_PANEL
+ }
+
+ return m_pDialogs[0];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CPanelModalStack::IsEmpty() const
+{
+ return m_pDialogs.Count() == 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CGenericWaitingDialog::CGenericWaitingDialog( vgui::Panel *pParent )
+ : BaseClass( pParent, "GenericWaitingDialog" )
+ , m_bAnimateEllipses(false)
+ , m_iNumEllipses(0)
+{
+ if ( pParent == NULL )
+ {
+ vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
+ SetScheme(scheme);
+ SetProportional( true );
+ }
+}
+
+void CGenericWaitingDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( GetResFile(), GetResFilePathId() );
+}
+
+void CGenericWaitingDialog::Close()
+{
+ OnCommand( "close" );
+}
+
+void CGenericWaitingDialog::OnCommand( const char *command )
+{
+ bool bClose = false;
+
+ if ( !Q_stricmp( command, "close" ) )
+ {
+ bClose = true;
+ }
+ else if ( !Q_stricmp( command, "user_close" ) )
+ {
+ OnUserClose();
+ bClose = true;
+ }
+
+ if ( bClose )
+ {
+ TFModalStack()->PopModal( this );
+ SetVisible( false );
+ MarkForDeletion();
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void CGenericWaitingDialog::OnTick( void )
+{
+ BaseClass::OnTick();
+
+ if ( !IsVisible() )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+
+ if ( m_bAnimateEllipses )
+ {
+ m_iNumEllipses = ((m_iNumEllipses+1) % 4);
+
+ switch ( m_iNumEllipses )
+ {
+ case 3: SetDialogVariable( "ellipses", L"..." ); break;
+ case 2: SetDialogVariable( "ellipses", L".." ); break;
+ case 1: SetDialogVariable( "ellipses", L"." ); break;
+ default: SetDialogVariable( "ellipses", L"" ); break;
+ }
+ }
+
+ if ( m_timer.HasStarted() )
+ {
+ // @note Tom Bui: showing 0 is weird, so just show nothing...
+ int iSecondsRemaining = (int)m_timer.GetRemainingTime();
+ if ( iSecondsRemaining == 0 )
+ {
+ SetDialogVariable( "duration", "" );
+ }
+ else
+ {
+ SetDialogVariable( "duration", iSecondsRemaining );
+ }
+ if ( m_timer.IsElapsed() )
+ {
+ OnCommand( "close" );
+ OnTimeout();
+ }
+ }
+}
+
+void CGenericWaitingDialog::ShowStatusUpdate( bool bAnimateEllipses, bool bAllowClose, float flMaxWaitTime )
+{
+ CExButton *pButton = dynamic_cast<CExButton*>( FindChildByName("CloseButton") );
+ if ( pButton )
+ {
+ pButton->SetVisible( bAllowClose );
+ pButton->SetEnabled( bAllowClose );
+ }
+
+ m_bAnimateEllipses = bAnimateEllipses;
+ if ( flMaxWaitTime > 0 )
+ {
+ m_timer.Start( flMaxWaitTime );
+ SetDialogVariable( "duration", (int)flMaxWaitTime );
+ }
+ else
+ {
+ m_timer.Invalidate();
+ SetDialogVariable( "duration", L"" );
+ }
+
+ if ( m_bAnimateEllipses )
+ {
+ m_iNumEllipses = 0;
+ }
+
+ if ( flMaxWaitTime > 0 || m_bAnimateEllipses )
+ {
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 500 );
+ }
+
+ SetDialogVariable( "ellipses", L"" );
+}
+
+void CGenericWaitingDialog::OnTimeout()
+{
+}
+
+void CGenericWaitingDialog::OnUserClose()
+{
+}
+
+static vgui::DHANDLE< CGenericWaitingDialog > g_WaitingDialog;
+
+void ShowWaitingDialog( CGenericWaitingDialog *pWaitingDialog, const char* pUpdateText, bool bAnimate, bool bShowCancel, float flMaxDuration )
+{
+ CloseWaitingDialog();
+ if ( pWaitingDialog )
+ {
+ g_WaitingDialog = vgui::SETUP_PANEL( pWaitingDialog );
+ g_WaitingDialog->SetVisible( true );
+ g_WaitingDialog->MakePopup();
+ g_WaitingDialog->MoveToFront();
+ g_WaitingDialog->SetKeyBoardInputEnabled(true);
+ g_WaitingDialog->SetMouseInputEnabled(true);
+ TFModalStack()->PushModal( g_WaitingDialog );
+
+ if ( pUpdateText != NULL )
+ {
+ g_WaitingDialog->SetDialogVariable( "updatetext", g_pVGuiLocalize->Find( pUpdateText ) );
+ }
+ g_WaitingDialog->ShowStatusUpdate( bAnimate, bShowCancel, flMaxDuration );
+ }
+}
+
+void CloseWaitingDialog()
+{
+ if ( g_WaitingDialog.Get() )
+ {
+ g_WaitingDialog->Close();
+ g_WaitingDialog = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------