summaryrefslogtreecommitdiff
path: root/game/client/tf/vgui/store
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/vgui/store')
-rw-r--r--game/client/tf/vgui/store/tf_store.cpp7
-rw-r--r--game/client/tf/vgui/store/tf_store.h12
-rw-r--r--game/client/tf/vgui/store/tf_store_page_base.cpp278
-rw-r--r--game/client/tf/vgui/store/tf_store_page_base.h121
-rw-r--r--game/client/tf/vgui/store/tf_store_panel_base.cpp133
-rw-r--r--game/client/tf/vgui/store/tf_store_panel_base.h54
-rw-r--r--game/client/tf/vgui/store/tf_store_preview_item_base.cpp1183
-rw-r--r--game/client/tf/vgui/store/tf_store_preview_item_base.h102
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_page.cpp96
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_page.h39
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_page_maps.cpp30
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_page_maps.h33
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_panel.cpp69
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_panel.h38
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_preview_item.cpp100
-rw-r--r--game/client/tf/vgui/store/v1/tf_store_preview_item.h41
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.cpp83
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.h36
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_page2.cpp849
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_page2.h82
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_page_maps2.cpp59
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_page_maps2.h35
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_panel2.cpp109
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_panel2.h41
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_preview_item2.cpp1367
-rw-r--r--game/client/tf/vgui/store/v2/tf_store_preview_item2.h177
26 files changed, 5174 insertions, 0 deletions
diff --git a/game/client/tf/vgui/store/tf_store.cpp b/game/client/tf/vgui/store/tf_store.cpp
new file mode 100644
index 0000000..d1a827b
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store.cpp
@@ -0,0 +1,7 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//=======================================================================================//
+
+
+#include "cbase.h"
+#include "store/tf_store.h"
diff --git a/game/client/tf/vgui/store/tf_store.h b/game/client/tf/vgui/store/tf_store.h
new file mode 100644
index 0000000..67c83d2
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store.h
@@ -0,0 +1,12 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//=======================================================================================//
+
+#ifndef TF_STORE_H
+#define TF_STORE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#endif // TF_STORE_H
diff --git a/game/client/tf/vgui/store/tf_store_page_base.cpp b/game/client/tf/vgui/store/tf_store_page_base.cpp
new file mode 100644
index 0000000..ee867e8
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_page_base.cpp
@@ -0,0 +1,278 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/tf_store_page_base.h"
+//#include "store/v1/tf_store_preview_item.h"
+#include "econ_item_inventory.h"
+#include "store/store_viewcart.h"
+#include "c_tf_freeaccount.h"
+#include "rtime.h"
+#include "econ_ui.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+extern const char *g_aPlayerClassNames[TF_CLASS_MENU_BUTTONS];
+
+const char *g_szClassFilterStrings[] =
+{
+ "", // Undefined
+ "#Store_Items_Scout",
+ "#Store_Items_Sniper",
+ "#Store_Items_Soldier",
+ "#Store_Items_Demoman",
+ "#Store_Items_Medic",
+ "#Store_Items_HWGuy",
+ "#Store_Items_Pyro",
+ "#Store_Items_Spy",
+ "#Store_Items_Engineer"
+};
+
+DECLARE_BUILD_FACTORY( CStorePreviewClassIcon );
+
+ConVar tf_explanations_store( "tf_explanations_store", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePageBase::CTFStorePageBase(Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile ) : CStorePage(parent, pPageData, pPreviewItemResFile)
+{
+ m_flStartExplanationsAt = 0;
+
+ // TF has an option for each class, all class items, all items, and an unowned item option. Let's make sure they all fit.
+ if ( m_pFilterComboBox )
+ {
+ m_pFilterComboBox->SetNumberOfEditLines( 12 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::OnPageShow( void )
+{
+ BaseClass::OnPageShow();
+
+ // If this is the first time we've opened the store, start the armory explanations
+ if ( !tf_explanations_store.GetBool() && m_pPageData )
+ {
+ m_flStartExplanationsAt = engine->Time() + 0.5;
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::OnCommand( const char *command )
+{
+ if ( !Q_stricmp( command, "show_explanations" ) )
+ {
+ if ( !m_flStartExplanationsAt )
+ {
+ m_flStartExplanationsAt = engine->Time();
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+ }
+ RequestFocus();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters )
+{
+ pVecFilters->AddToTail( FILTER_ALL_ITEMS );
+
+ // Add item to unowned filter only if it doesn't belong to these categories.
+ const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( pDef->GetDefinitionIndex() );
+ if( !pEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_Tools ) &&
+ !pEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_Maps ) &&
+ !pEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_Bundles ) &&
+ !pEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_Collections ) )
+ {
+ bool bItemOwned = false;
+ int iCount = InventoryManager()->GetLocalInventory()->GetItemCount();
+ for ( int i = 0; i < iCount; i++ )
+ {
+ if ( InventoryManager()->GetLocalInventory()->GetItem( i )->GetItemDefIndex() == pDef->GetDefinitionIndex() )
+ {
+ bItemOwned = true;
+ break;
+ }
+ }
+
+ if ( !bItemOwned )
+ {
+ pVecFilters->AddToTail( FILTER_UNOWNED_ITEMS );
+ }
+ }
+
+ if ( pDef->CanBeUsedByAllClasses() )
+ pVecFilters->AddToTail( FILTER_ALLCLASS_ITEMS );
+
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
+ {
+ if ( pDef->CanBeUsedByClass( iClass ) )
+ pVecFilters->AddToTail( iClass );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::OnItemDetails( vgui::Panel *panel )
+{
+ CStoreItemControlsPanel *pControlsPanel = dynamic_cast< CStoreItemControlsPanel * >( panel );
+ if ( pControlsPanel )
+ {
+ const econ_store_entry_t *pEntry = pControlsPanel->GetItem();
+ if ( pEntry )
+ {
+ SelectItemPanel( pControlsPanel->GetItemModelPanel() );
+ PostMessage( EconUI()->GetStorePanel(), new KeyValues("ArmoryOpened", "itemdef", pEntry->GetItemDefinitionIndex() ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::ShowPreview( int iClass, const econ_store_entry_t* pEntry )
+{
+ if ( iClass < TF_FIRST_NORMAL_CLASS || iClass >= TF_LAST_NORMAL_CLASS )
+ {
+ iClass = TF_CLASS_SCOUT;
+ }
+
+ BaseClass::ShowPreview( iClass, pEntry );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::UpdateFilterComboBox( void )
+{
+ if ( !m_pFilterComboBox )
+ return;
+
+ wchar_t wzLocalized[256];
+ wchar_t wszCount[16];
+
+ m_pFilterComboBox->RemoveAll();
+
+ // All items
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetInt( "filter", FILTER_ALL_ITEMS );
+ m_pFilterComboBox->AddItem( "#Store_ClassFilter_None", pKeyValues );
+
+#if NEWFILTER
+ // All classes
+ int nCount = m_pPrimaryFilter->GetCountForFilterItem( FILTER_ALLCLASS_ITEMS );
+ if ( nCount )
+ {
+ pKeyValues->SetInt( "filter", FILTER_ALLCLASS_ITEMS );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", nCount );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( "#Store_ClassFilter_AllClasses" ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+
+ // Individual classes
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
+ {
+ nCount = m_pPrimaryFilter->GetCountForFilterItem( iClass );
+ if ( !nCount )
+ continue;
+
+ pKeyValues->SetInt( "filter", iClass );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", nCount );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( g_szClassFilterStrings[iClass] ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+
+ // Unowned item filter
+ nCount = m_pPrimaryFilter->GetCountForFilterItem( FILTER_UNOWNED_ITEMS );
+ if ( nCount )
+ {
+ pKeyValues->SetInt( "filter", FILTER_UNOWNED_ITEMS );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", nCount );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( "#Store_Items_Unowned" ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+
+#else
+ // All classes
+ if ( m_vecFilterCounts[FILTER_ALLCLASS_ITEMS] )
+ {
+ pKeyValues->SetInt( "filter", FILTER_ALLCLASS_ITEMS );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", m_vecFilterCounts[FILTER_ALLCLASS_ITEMS] );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( "#Store_ClassFilter_AllClasses" ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+
+ // Individual classes
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
+ {
+ if ( m_vecFilterCounts[iClass] == 0 )
+ continue;
+
+ pKeyValues->SetInt( "filter", iClass );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", m_vecFilterCounts[iClass] );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( g_szClassFilterStrings[iClass] ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+
+ // Unowned item filter
+ if ( m_vecFilterCounts[FILTER_UNOWNED_ITEMS] )
+ {
+ pKeyValues->SetInt( "filter", FILTER_UNOWNED_ITEMS );
+
+ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", m_vecFilterCounts[FILTER_UNOWNED_ITEMS] );
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( "#Store_Items_Unowned" ), 1, wszCount );
+ m_pFilterComboBox->AddItem( wzLocalized, pKeyValues );
+ }
+#endif
+
+ pKeyValues->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePageBase::OnTick( void )
+{
+ BaseClass::OnTick();
+
+ if ( m_flStartExplanationsAt && m_flStartExplanationsAt < engine->Time() )
+ {
+ m_flStartExplanationsAt = 0;
+
+ tf_explanations_store.SetValue( 1 );
+
+ CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") );
+ if ( pPopup )
+ {
+ pPopup->Popup();
+ }
+ }
+
+ if ( !m_flStartExplanationsAt )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+}
+
diff --git a/game/client/tf/vgui/store/tf_store_page_base.h b/game/client/tf/vgui/store/tf_store_page_base.h
new file mode 100644
index 0000000..9a4bcbe
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_page_base.h
@@ -0,0 +1,121 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PAGE_H
+#define TF_STORE_PAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <game/client/iviewport.h>
+#include "vgui_controls/PropertyPage.h"
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/ImagePanel.h>
+#include "econ_controls.h"
+#include "econ_ui.h"
+#include "econ_store.h"
+#include "item_model_panel.h"
+#include "store/store_page.h"
+#include "tf_shareddefs.h"
+
+class CItemModelPanel;
+class CItemModelPanelToolTip;
+class CTFPlayerModelPanel;
+class CStorePreviewItemPanel;
+class CStoreItemControlsPanel;
+
+extern const char *g_pszTipsClassImages[];
+
+#define FILTER_ALLCLASS_ITEMS TF_LAST_NORMAL_CLASS
+#define FILTER_UNOWNED_ITEMS (TF_LAST_NORMAL_CLASS + 1)
+
+//-----------------------------------------------------------------------------
+// Purpose: A player class preview icon in the store's item preview panel
+//-----------------------------------------------------------------------------
+class CStorePreviewClassIcon : public CBaseStorePreviewIcon
+{
+ DECLARE_CLASS_SIMPLE( CStorePreviewClassIcon, CBaseStorePreviewIcon );
+public:
+ CStorePreviewClassIcon( vgui::Panel *parent, const char *name ) : CBaseStorePreviewIcon(parent,name)
+ {
+ m_pImagePanel = new vgui::ImagePanel( this, "classimage" );
+ m_pImagePanel->SetShouldScaleImage( true );
+ m_pImagePanel->SetMouseInputEnabled( false );
+ m_pImagePanel->SetKeyBoardInputEnabled( false );
+ m_iClass = 0;
+ }
+
+ virtual void OnCursorEntered()
+ {
+ BaseClass::OnCursorEntered();
+ PostActionSignal(new KeyValues("ShowClassIconMouseover", "class", m_iClass));
+ }
+ virtual void OnCursorExited()
+ {
+ BaseClass::OnCursorExited();
+ PostActionSignal(new KeyValues("HideClassIconMouseover"));
+ }
+ virtual void OnMouseReleased(vgui::MouseCode code)
+ {
+ BaseClass::OnMouseReleased(code);
+ PostActionSignal(new KeyValues("ClassIconSelected", "class", m_iClass));
+ }
+
+ virtual void SetInternalImageBounds( int iX, int iY, int iWide, int iTall )
+ {
+ m_pImagePanel->SetBounds( iX, iY, iWide, iTall );
+ }
+
+ void SetClass( int iClass )
+ {
+ if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass < TF_LAST_NORMAL_CLASS )
+ {
+ m_pImagePanel->SetImage( g_pszTipsClassImages[iClass] );
+ }
+ else
+ {
+ m_pImagePanel->SetImage( "class_portraits/all_class" );
+ }
+ m_iClass = iClass;
+ }
+
+ int GetClass( void ) { return m_iClass; }
+
+private:
+ vgui::ImagePanel *m_pImagePanel;
+ int m_iClass;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePageBase : public CStorePage
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePageBase, CStorePage );
+protected:
+ // CTFStorePageBase should not be instantiated directly
+ CTFStorePageBase( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile = NULL );
+
+public:
+
+ virtual void OnCommand( const char *command );
+ virtual void ShowPreview( int iClass, const econ_store_entry_t* pEntry );
+
+ MESSAGE_FUNC( OnPageShow, "PageShow" );
+ MESSAGE_FUNC_PTR( OnItemDetails, "ItemDetails", panel );
+
+ virtual void UpdateFilterComboBox( void );
+ virtual void GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters );
+ virtual void OnTick( void );
+ virtual int GetNumPrimaryFilters( void ) { return FILTER_UNOWNED_ITEMS+1; }
+
+protected:
+ float m_flStartExplanationsAt;
+};
+
+#endif // TF_STORE_PAGE_H
diff --git a/game/client/tf/vgui/store/tf_store_panel_base.cpp b/game/client/tf/vgui/store/tf_store_panel_base.cpp
new file mode 100644
index 0000000..5a80fbb
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_panel_base.cpp
@@ -0,0 +1,133 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/tf_store_panel_base.h"
+#include "vgui/IInput.h"
+#include "iclientmode.h"
+#include "econ_item_system.h"
+#include "econ_notifications.h"
+#include "c_tf_freeaccount.h"
+#include <vgui_controls/AnimationController.h>
+#include "charinfo_armory_subpanel.h"
+#include "backpack_panel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+class CServerNotConnectedToSteamDialog;
+CServerNotConnectedToSteamDialog *OpenServerNotConnectedToSteamDialog( vgui::Panel *pParent );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFBaseStorePanel::CTFBaseStorePanel( Panel *parent ) : CStorePanel(parent)
+{
+ m_pArmoryPanel = new CArmoryPanel( this, "armory_panel" );
+ m_pNotificationsPresentPanel = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pNotificationsPresentPanel = FindChildByName( "NotificationsPresentPanel" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::OnArmoryOpened( KeyValues *data )
+{
+ int iItemDef = data->GetInt( "itemdef", 0 );
+
+ // If it's a bundle, open the armory to a custom page showing all the items in the bundle
+ CEconItemDefinition *pDef = ItemSystem()->GetStaticDataForItemByDefIndex( iItemDef );
+ if ( pDef )
+ {
+ const bundleinfo_t *pBundleInfo = pDef->GetBundleInfo();
+ if ( pBundleInfo )
+ {
+ CUtlVector<item_definition_index_t> vecItems;
+ FOR_EACH_VEC( pBundleInfo->vecItemDefs, j )
+ {
+ if ( pBundleInfo->vecItemDefs[j] )
+ {
+ vecItems.AddToTail( pBundleInfo->vecItemDefs[j]->GetDefinitionIndex() );
+ }
+ }
+
+ m_pArmoryPanel->ShowPanel( pDef->GetItemBaseName(), &vecItems );
+ m_pArmoryPanel->MoveToFront();
+ return;
+ }
+ }
+
+ m_pArmoryPanel->ShowPanel( iItemDef );
+ m_pArmoryPanel->MoveToFront();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::OnArmoryClosed( void )
+{
+ PostMessage( m_pArmoryPanel, new KeyValues("Closing") );
+ m_pArmoryPanel->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::OnThink()
+{
+ bool bShouldBeVisible = NotificationQueue_GetNumNotifications() != 0;
+ if ( m_pNotificationsPresentPanel != NULL && m_pNotificationsPresentPanel->IsVisible() != bShouldBeVisible )
+ {
+ m_pNotificationsPresentPanel->SetVisible( bShouldBeVisible );
+ if ( bShouldBeVisible )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "NotificationsPresentBlink" );
+ }
+ else
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "NotificationsPresentBlinkStop" );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::PostTransactionCompleted( void )
+{
+ // pop this dialog up
+ if ( NeedsToChooseMostHelpfulFriend() )
+ {
+ // update main menu
+ IGameEvent *event = gameeventmanager->CreateEvent( "store_pricesheet_updated" );
+ if ( event )
+ {
+ gameeventmanager->FireEventClientSide( event );
+ }
+ }
+
+ EconUI()->GetBackpackPanel()->CheckForQuickOpenKey();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFBaseStorePanel::SetTransactionID( uint64 inID )
+{
+ BaseClass::SetTransactionID( inID );
+
+ EconUI()->GetBackpackPanel()->SetCurrentTransactionID( inID );
+} \ No newline at end of file
diff --git a/game/client/tf/vgui/store/tf_store_panel_base.h b/game/client/tf/vgui/store/tf_store_panel_base.h
new file mode 100644
index 0000000..33a7082
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_panel_base.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PANEL_BASE_H
+#define TF_STORE_PANEL_BASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/store_panel.h"
+
+class CArmoryPanel;
+class CStorePage;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFBaseStorePanel : public CStorePanel
+{
+ DECLARE_CLASS_SIMPLE( CTFBaseStorePanel, CStorePanel );
+protected:
+ // CTFBaseStorePanel should not be instantiated directly
+ CTFBaseStorePanel( Panel *parent );
+
+public:
+ // UI Layout
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnThink();
+
+ // GC Management
+ virtual void PostTransactionCompleted( void );
+
+ // Cart Management
+ CStoreCart *GetCart( void ) { return &m_Cart; }
+ void ShowStorePanel( void );
+ void InitiateCheckout( void );
+ void CheckoutCancel( void );
+
+ virtual void SetTransactionID( uint64 inID ) OVERRIDE;
+
+ // Armory management
+ MESSAGE_FUNC_PARAMS( OnArmoryOpened, "ArmoryOpened", data );
+ MESSAGE_FUNC( OnArmoryClosed, "ArmoryClosed" );
+
+private:
+ CArmoryPanel *m_pArmoryPanel;
+ vgui::Panel *m_pNotificationsPresentPanel;
+};
+
+#endif // TF_STORE_PANEL_BASE_H
diff --git a/game/client/tf/vgui/store/tf_store_preview_item_base.cpp b/game/client/tf/vgui/store/tf_store_preview_item_base.cpp
new file mode 100644
index 0000000..9f6e2b3
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_preview_item_base.cpp
@@ -0,0 +1,1183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/tf_store_preview_item_base.h"
+#include "store/store_page.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include "gamestringpool.h"
+#include "tf_item_inventory.h"
+#include "tf_playermodelpanel.h"
+#include "econ_item_system.h"
+#include "item_model_panel.h"
+#include "c_tf_gamestats.h"
+#include "econ_ui.h"
+#include "econ_item_tools.h"
+#include "vgui_controls/MenuItem.h"
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePreviewItemPanelBase::CTFStorePreviewItemPanelBase( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner )
+: CStorePreviewItemPanel( pParent, pResFile, "storepreviewitem", pOwner )
+{
+ ResetHandles();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::ResetHandles( void )
+{
+ m_pPlayerModelPanel = NULL;
+ m_iCurrentClass = TF_CLASS_SCOUT;
+ m_iCurrentHeldItem = 0;
+ m_pClassIconMouseoverLabel = NULL;
+ m_pRotRightButton = NULL;
+ m_pRotLeftButton = NULL;
+ m_pNextWeaponButton = NULL;
+ m_pZoomButton = NULL;
+ m_pOptionsButton = NULL;
+ m_pTeamButton = NULL;
+ m_pDataTextRichText = NULL;
+ m_iCurrentIconPosition = 0;
+ m_iState = PS_ITEM;
+ m_unPaintDef = 0;
+ m_unPaintRGB0 = 0;
+ m_unPaintRGB1 = 0;
+ m_pPaintNameLabel = NULL;
+ m_pStyleNameLabel = NULL;
+ m_pCustomizeMenu = NULL;
+ m_pClassIcons.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetCycleLabelText( vgui::Label *pTargetLabel, const char *pCycleText )
+{
+ if ( pTargetLabel )
+ {
+ pTargetLabel->SetText( pCycleText );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ ResetHandles();
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pPlayerModelPanel = dynamic_cast<CTFPlayerModelPanel*>( FindChildByName("classmodelpanel") );
+ m_pClassIconMouseoverLabel = dynamic_cast<vgui::Label*>( FindChildByName("ClassUsageMouseoverLabel") );
+ m_pRotRightButton = dynamic_cast<CExButton*>( FindChildByName("RotRightButton") );
+ m_pRotLeftButton = dynamic_cast<CExButton*>( FindChildByName("RotLeftButton") );
+ m_pNextWeaponButton = dynamic_cast<CExButton*>( FindChildByName("NextWeaponButton") );
+ m_pZoomButton = dynamic_cast<CExButton*>( FindChildByName("ZoomButton") );
+ m_pOptionsButton = dynamic_cast<CExButton*>( FindChildByName("OptionsButton") );
+ m_pTeamButton = dynamic_cast<CExButton*>( FindChildByName("TeamButton") );
+ m_pPaintNameLabel = dynamic_cast<vgui::Label*>( FindChildByName("PaintNameLabel") );
+ m_pStyleNameLabel = dynamic_cast<vgui::Label*>( FindChildByName("StyleNameLabel") );
+
+ if ( m_pClassIconMouseoverLabel )
+ {
+ m_pClassIconMouseoverLabel->SetVisible( false );
+ }
+
+ // Find all the class images
+ CStorePreviewClassIcon *pClassImage = NULL;
+ int iIcon = 1;
+ do
+ {
+ pClassImage = dynamic_cast<CStorePreviewClassIcon*>( FindChildByName( VarArgs("ClassUsageImage%d",iIcon)) );
+ if ( pClassImage )
+ {
+ m_pClassIcons.AddToTail( pClassImage );
+ }
+ iIcon++;
+ } while ( pClassImage );
+
+ // Update our class icons. Hide them all first. The code below will unhide ones used.
+ for ( int i = 0; i < m_pClassIcons.Count(); i++ )
+ {
+ m_pClassIcons[i]->SetVisible( false );
+ }
+
+ SetState( PS_ITEM );
+
+ m_vecPaintCans.Purge();
+ const CEconItemSchema::ToolsItemDefinitionMap_t &toolDefs = GetItemSchema()->GetToolsItemDefinitionMap();
+
+ // Store all of the active paint can item defs
+ FOR_EACH_MAP_FAST( toolDefs, i )
+ {
+ const CEconItemDefinition *pItemDef = toolDefs[i];
+
+ // ignore everything that is not a paint can tool
+ const IEconTool *pEconTool = pItemDef->GetEconTool();
+ if ( pEconTool && !V_strcmp( pEconTool->GetTypeName(), "paint_can" ) )
+ {
+ m_vecPaintCans.AddToTail( pItemDef->GetDefinitionIndex() );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ // center the icons (we need to redo some of the work of CStorePreviewItemPanel, because we
+ // center the base item icons along with our TF specific class ones)
+ int iNumItemIcons = 0;
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ if ( m_pItemIcons[i]->IsVisible() )
+ {
+ ++iNumItemIcons;
+ }
+ }
+ int iNumClassIcons = 0;
+ FOR_EACH_VEC( m_pClassIcons, i )
+ {
+ if ( m_pClassIcons[i]->IsVisible() )
+ {
+ ++iNumClassIcons;
+ }
+ }
+ if ( iNumItemIcons || iNumClassIcons )
+ {
+ int iCenterX = GetWide() / 2;
+ int interval = XRES(2);
+ int totalWidth = (iNumItemIcons * m_pItemIcons[0]->GetWide()) + (iNumClassIcons * m_pClassIcons[0]->GetWide()) + (interval * (iNumItemIcons + iNumClassIcons - 1));
+ int iX = iCenterX - ( totalWidth / 2 );
+
+ int posX, posY;
+ m_pItemIcons[0]->GetPos( posX, posY );
+
+ int iButton = 0;
+ for ( int i = 0; i < m_pItemIcons.Count(); i++ )
+ {
+ if ( m_pItemIcons[i]->IsVisible() )
+ {
+ m_pItemIcons[i]->SetPos( iX, posY );
+ iX += m_pItemIcons[i]->GetWide() + interval;
+
+ iButton++;
+ }
+ }
+
+ for ( int i = 0; i < m_pClassIcons.Count(); i++ )
+ {
+ if ( m_pClassIcons[i]->IsVisible() )
+ {
+ m_pClassIcons[i]->SetPos( iX, posY );
+ iX += m_pClassIcons[i]->GetWide() + interval;
+
+ iButton++;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static bool IsAnythingPaintable( const CUtlVector<CEconItemView*>& vecItems )
+{
+ FOR_EACH_VEC( vecItems, i )
+ {
+ if ( vecItems[i]->GetStaticData()->GetCapabilities() & ITEM_CAP_PAINTABLE )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static void UpdatePaintColorsForTeam( CTFPlayerModelPanel *pPlayerModelPanel, uint32 unRGB0, uint32 unRGB1 )
+{
+ Assert( pPlayerModelPanel );
+
+ static CSchemaAttributeDefHandle pAttrDef_ItemTintRGB( "set item tint RGB" );
+
+ if ( !pAttrDef_ItemTintRGB )
+ return;
+
+ const CUtlVector<CEconItemView*> &items = pPlayerModelPanel->GetCarriedItems();
+ if ( !IsAnythingPaintable( items ) )
+ return;
+
+ for ( int i=0; i<items.Count(); ++i )
+ {
+ if ( items[i]->GetStaticData()->GetCapabilities() & ITEM_CAP_PAINTABLE )
+ {
+ items[i]->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_ItemTintRGB, pPlayerModelPanel->GetTeam() == TF_TEAM_RED ? unRGB0 : unRGB1 );
+ items[i]->InvalidateColor();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::OnCommand( const char *command )
+{
+ if ( !Q_strnicmp( command, "team_toggle", 11 ) )
+ {
+ if ( m_pPlayerModelPanel )
+ {
+ m_pPlayerModelPanel->SetTeam( m_pPlayerModelPanel->GetTeam() == TF_TEAM_RED ? TF_TEAM_BLUE : TF_TEAM_RED );
+ }
+
+ // Also toggle team paint color if necessary.
+ if ( m_unPaintRGB0 != m_unPaintRGB1 )
+ {
+ UpdatePaintColorsForTeam( m_pPlayerModelPanel, m_unPaintRGB0, m_unPaintRGB1 );
+ }
+ }
+ else if ( !Q_strnicmp( command, "zoom_toggle", 11 ) )
+ {
+ if ( m_pPlayerModelPanel )
+ {
+ m_pPlayerModelPanel->ToggleZoom();
+ }
+ }
+ else if ( !Q_strnicmp( command, "paint_toggle", 12 ) )
+ {
+ CyclePaint();
+ }
+ else if ( !Q_strnicmp( command, "set_red", 7 ) )
+ {
+ if ( m_pPlayerModelPanel )
+ {
+ m_pPlayerModelPanel->SetSkin( 0 );
+ }
+ return;
+ }
+ else if ( !Q_strnicmp( command, "set_blu", 7 ) )
+ {
+ if ( m_pPlayerModelPanel )
+ {
+ m_pPlayerModelPanel->SetSkin( 1 );
+ }
+ return;
+ }
+ else if ( !Q_strnicmp( command, "next_weapon", 11 ) )
+ {
+ if ( m_pPlayerModelPanel )
+ {
+ const CUtlVector<CEconItemView*> &items = m_pPlayerModelPanel->GetCarriedItems();
+ int iLastItem = m_iCurrentHeldItem;
+ do
+ {
+ m_iCurrentHeldItem = ( m_iCurrentHeldItem + 1 ) % items.Count();
+ } while ( m_iCurrentHeldItem != iLastItem && m_pPlayerModelPanel->HoldItem( m_iCurrentHeldItem ) == false );
+ }
+ m_pPlayerModelPanel->SetTeam( m_pPlayerModelPanel->GetTeam() );
+ return;
+ }
+ else if ( !Q_strnicmp( command, "next_style", 10 ) )
+ {
+ CycleStyle();
+ return;
+ }
+ else if ( V_strncasecmp( command, "SetPaint", V_strlen( "SetPaint" ) ) == 0 )
+ {
+ item_definition_index_t iItemDef = V_atoi( &command[ V_strlen( "SetPaint" ) ] );
+ SetPaint( iItemDef );
+ }
+ else if ( V_strncasecmp( command, "SetStyle", V_strlen( "SetStyle" ) ) == 0 )
+ {
+ style_index_t unStyle = V_atoi( &command[ V_strlen( "SetStyle" ) ] );
+ SetStyle( unStyle );
+ }
+ else if ( V_strncasecmp( command, "SetUnusual", V_strlen( "SetUnusual" ) ) == 0 )
+ {
+ int iUnusual = V_atoi( &command[ V_strlen( "SetUnusual" ) ] );
+ SetUnusual( iUnusual );
+ }
+ else if ( FStrEq( command, "options" ) )
+ {
+ UpdateCustomizeMenu();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::OnClassIconSelected( KeyValues *data )
+{
+ int iClass = data->GetInt( "class", 0 );
+ if ( iClass < TF_FIRST_NORMAL_CLASS || iClass >= TF_LAST_NORMAL_CLASS )
+ {
+ iClass = TF_CLASS_SCOUT;
+ }
+ m_iCurrentClass = iClass;
+ UpdateModelPanel();
+
+ SetState( PS_PLAYER );
+
+// C_CTF_GameStats.Event_Store( IE_STORE_ITEM_PREVIEWED, NULL, NULL, m_iCurrentClass );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetPlayerModelVisible( bool bVisible )
+{
+ if( m_pPlayerModelPanel )
+ {
+ m_pPlayerModelPanel->SetVisible( bVisible );
+ if ( m_pRotRightButton )
+ {
+ m_pRotRightButton->SetVisible( bVisible );
+ }
+ if ( m_pRotLeftButton )
+ {
+ m_pRotLeftButton->SetVisible( bVisible );
+ }
+ UpdatePlayerModelButtons();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry )
+{
+ m_iCurrentClass = 0;
+ BaseClass::PreviewItem( iClass, pItem, pEntry );
+
+ UpdateModelPanel();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetState( preview_state_t iState )
+{
+ BaseClass::SetState( iState );
+ SetPlayerModelVisible( m_iState == PS_PLAYER );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTFStorePreviewItemPanelBase::GetPreviewTeam() const
+{
+ return m_pPlayerModelPanel
+ ? m_pPlayerModelPanel->GetTeam()
+ : TF_TEAM_RED;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateIcons( void )
+{
+ // Don't bother calling back to the base class UpdateIcons, because
+ // we'd need to redo it all with the class icons factored in.
+
+ bool bAdditionalIcons = false;
+
+ // Do the item icons first
+ if ( m_iState == PS_DETAILS )
+ {
+ // Show as many of the items in the bundle as possible
+ const CEconItemDefinition *pItemData = m_item.GetItemDefinition();
+ if ( pItemData )
+ {
+ const bundleinfo_t *pBundleInfo = pItemData->GetBundleInfo();
+ if ( pBundleInfo )
+ {
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ // If we haven't scrolled, the first item is the bundle itself
+ if ( m_iCurrentIconPosition == 0 && i == 0 )
+ {
+ m_pItemIcons[0]->SetItem( 0, &m_item );
+ continue;
+ }
+
+ int iItemPos = (i - 1 + m_iCurrentIconPosition);
+ if ( pBundleInfo->vecItemDefs.Count() > iItemPos && pBundleInfo->vecItemDefs[iItemPos] )
+ {
+ m_pItemIcons[i]->SetItem( i, pBundleInfo->vecItemDefs[iItemPos]->GetDefinitionIndex() );
+ m_pItemIcons[i]->SetVisible( true );
+ }
+ else
+ {
+ m_pItemIcons[i]->SetVisible( false );
+ }
+ }
+
+ bAdditionalIcons = (m_iCurrentIconPosition + m_pItemIcons.Count()) <= pBundleInfo->vecItemDefs.Count();
+ }
+ else if ( m_pItemIcons.Count() )
+ {
+ m_pItemIcons[0]->SetVisible( true );
+ m_pItemIcons[0]->SetItem( 0, &m_item );
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ if ( i != 0 )
+ {
+ m_pItemIcons[i]->SetVisible( false );
+ }
+ }
+ }
+ }
+
+ // Hide all the class icons
+ for ( int i = 0; i < m_pClassIcons.Count(); i++ )
+ {
+ m_pClassIcons[i]->SetVisible( false );
+ }
+ }
+ else
+ {
+ // Hide all item icons first (but not the first if we haven't scrolled)
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ m_pItemIcons[i]->SetVisible( m_iCurrentIconPosition == 0 && i == 0 );
+ }
+
+ // First icon is always the store entry (item/bundle), if we haven't scrolled right
+ if ( m_iCurrentIconPosition == 0 && m_pItemIcons.Count() )
+ {
+ m_pItemIcons[0]->SetItem( 0, &m_item );
+ }
+
+ // Then do the class icons
+ const CTFItemDefinition *pItemData = m_item.GetItemDefinition();
+ if ( pItemData )
+ {
+ int iButton = 0;
+ int iMaxButtons = m_pClassIcons.Count();
+ int iNumClasses = (TF_LAST_NORMAL_CLASS - TF_FIRST_NORMAL_CLASS);
+ // we show one less class icon when the item is visible
+ if ( iMaxButtons < iNumClasses && m_iCurrentIconPosition == 0 )
+ {
+ iMaxButtons -= 1;
+ }
+ for ( int iClass = TF_FIRST_NORMAL_CLASS + m_iCurrentIconPosition; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
+ {
+ if ( !pItemData->CanBeUsedByClass(iClass) )
+ continue;
+
+ // Run out of buttons?
+ if ( iButton >= iMaxButtons )
+ {
+ bAdditionalIcons = true;
+ break;
+ }
+
+ m_pClassIcons[iButton]->SetVisible( true );
+ m_pClassIcons[iButton]->SetClass(iClass);
+ iButton++;
+
+ if ( !m_iCurrentClass )
+ {
+ m_iCurrentClass = iClass;
+ }
+ }
+ for ( ; iButton < m_pClassIcons.Count(); ++iButton )
+ {
+ m_pClassIcons[iButton]->SetVisible( false );
+ }
+ }
+ }
+
+ if( m_pIconsMoveLeftButton )
+ m_pIconsMoveLeftButton->SetVisible( (m_iCurrentIconPosition > 0) );
+ if( m_pIconsMoveRightButton )
+ m_pIconsMoveRightButton->SetVisible( bAdditionalIcons );
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::OnTick( void )
+{
+ BaseClass::OnTick();
+
+ if ( !IsVisible() )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ return;
+ }
+
+ if ( m_iCurrentRotation )
+ {
+ m_pPlayerModelPanel->RotateYaw( m_iCurrentRotation );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateModelPanel()
+{
+ if ( m_pPlayerModelPanel )
+ {
+ m_iCurrentHeldItem = 0;
+ m_pPlayerModelPanel->SetToPlayerClass( m_iCurrentClass, false );
+ m_pPlayerModelPanel->ClearCarriedItems();
+
+
+ if ( m_item.IsValid() )
+ {
+ CTFItemDefinition *pItemDef = m_item.GetStaticData();
+ if ( pItemDef->GetBundleInfo() != NULL )
+ {
+ const bundleinfo_t *pBundleInfo = pItemDef->GetBundleInfo();
+ FOR_EACH_VEC( pBundleInfo->vecItemDefs, i )
+ {
+ CTFItemDefinition *pBundledItem = dynamic_cast<CTFItemDefinition *>( pBundleInfo->vecItemDefs[i] );
+ if ( pBundledItem && pBundledItem->CanBeUsedByClass( m_iCurrentClass ) )
+ {
+ CEconItemView bundleItemData;
+ bundleItemData.Init( pBundledItem->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+ bundleItemData.SetClientItemFlags( kEconItemFlagClient_Preview );
+ int iItemIdx = m_pPlayerModelPanel->AddCarriedItem( &bundleItemData );
+ // try to hold it
+ if ( m_pPlayerModelPanel->HoldItem( iItemIdx ) )
+ {
+ m_iCurrentHeldItem = iItemIdx;
+ }
+ }
+ }
+ }
+ else
+ {
+ m_pPlayerModelPanel->AddCarriedItem( &m_item );
+
+ // Now make sure we're holding it if it's a non-wearable
+ int iLoadoutSlot = m_item.GetStaticData()->GetLoadoutSlot( m_iCurrentClass );
+ m_pPlayerModelPanel->HoldItemInSlot( iLoadoutSlot );
+ }
+ }
+
+ UpdatePlayerModelButtons();
+
+ // Fix a problem where changing the class would change the preview mesh but wouldn't
+ // update the paint. This is a hack and won't work if we have multi-class styles or
+ // just about anything else.
+ CyclePaint( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdatePlayerModelButtons()
+{
+ UpdateOptionsButton();
+ UpdateNextWeaponButton();
+ UpdateZoomButton();
+ UpdateTeamButton();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateCustomizeMenu( void )
+{
+ if ( m_pCustomizeMenu )
+ {
+ delete m_pCustomizeMenu;
+ m_pCustomizeMenu = NULL;
+ }
+
+ if ( !m_pPlayerModelPanel->IsVisible() )
+ return;
+
+ if ( !m_pOptionsButton || !m_pOptionsButton->IsVisible() )
+ return;
+
+ if ( !m_item.IsValid() )
+ return;
+
+ m_pCustomizeMenu = new Menu( this, "CustomizeMenu" );
+ MenuBuilder contextMenuBuilder( m_pCustomizeMenu, this );
+ const char *pszContextMenuBorder = "NotificationDefault";
+ const char *pszContextMenuFont = "HudFontMediumSecondary";
+ m_pCustomizeMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ m_pCustomizeMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+
+ // Add paint options sub menu
+ {
+ Menu *pPaintSubMenu = NULL;
+ FOR_EACH_VEC( m_vecPaintCans, i )
+ {
+ item_definition_index_t paintItemDefIndex = m_vecPaintCans[ i ];
+ GameItemDefinition_t * pPaintCanDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( paintItemDefIndex ) );
+ if ( !CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pPaintCanDef ), m_item.GetStaticData() ) )
+ continue;
+
+ if ( pPaintSubMenu == NULL )
+ {
+ pPaintSubMenu = new Menu( this, "PaintSubMenu" );
+ pPaintSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pPaintSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_Paint", pPaintSubMenu, "customization" );
+ }
+
+ wchar_t wBuff[256] = { 0 };
+ V_swprintf_safe( wBuff, L" %ls", g_pVGuiLocalize->Find( pPaintCanDef->GetItemBaseName() ) );
+ int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "SetPaint%d", paintItemDefIndex ) ), this );
+ vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( wBuff );
+ pMenuItem->InvalidateLayout( true, false );
+
+ uint32 unPaintRGB0 = 0;
+ uint32 unPaintRGB1 = 0;
+
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB2( "set item tint RGB 2" );
+
+ float fRGB = 0.0f;
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB, &fRGB ) && fRGB != 0.0f )
+ {
+ unPaintRGB0 = fRGB;
+
+ // We may or may not have a secondary paint color as well. If we don't, we just use the primary
+ // paint color to fill both slots.
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB2, &fRGB ) )
+ {
+ unPaintRGB1 = fRGB;
+ }
+ else
+ {
+ unPaintRGB1 = unPaintRGB0;
+ }
+ }
+
+ CItemMaterialCustomizationIconPanel *pCustomPanel = new CItemMaterialCustomizationIconPanel( pMenuItem, "paint" );
+ pCustomPanel->SetZPos( -100 );
+ pCustomPanel->SetTall( 30 );
+ pCustomPanel->SetWide( 30 );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( (unPaintRGB0 & 0xFF0000) >> 16, 0, 255 ), clamp( (unPaintRGB0 & 0xFF00) >> 8, 0, 255 ), clamp( (unPaintRGB0 & 0xFF), 0, 255 ), 255 ) );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( (unPaintRGB1 & 0xFF0000) >> 16, 0, 255 ), clamp( (unPaintRGB1 & 0xFF00) >> 8, 0, 255 ), clamp( (unPaintRGB1 & 0xFF), 0, 255 ), 255 ) );
+ }
+ }
+
+ // Add style
+ {
+ Menu *pStyleSubMenu = NULL;
+ if ( m_item.GetStaticData()->GetNumSelectableStyles() > 1 )
+ {
+ for ( style_index_t unStyle=0; unStyle<m_item.GetStaticData()->GetNumStyles(); ++unStyle )
+ {
+ const CEconStyleInfo *pStyle = m_item.GetStaticData()->GetStyleInfo( unStyle );
+ if ( !pStyle )
+ continue;
+
+ if ( !pStyle->IsSelectable() )
+ continue;
+
+ if ( pStyleSubMenu == NULL )
+ {
+ pStyleSubMenu = new Menu( this, "StyleSubMenu" );
+ pStyleSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pStyleSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_Style", pStyleSubMenu, "customization" );
+ }
+
+ int nIndex = pStyleSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "SetStyle%d", unStyle ) ), this );
+ vgui::MenuItem *pMenuItem = pStyleSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( pStyle->GetName() );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+ }
+ }
+
+ // Add unusual
+ {
+ const CUtlVector< int > *pUnusualList = GetUnusualList();
+ if ( pUnusualList )
+ {
+ Menu *pUnusualSubMenu = NULL;
+ for ( int i=0; i<pUnusualList->Count(); ++i )
+ {
+ if ( pUnusualSubMenu == NULL )
+ {
+ pUnusualSubMenu = new Menu( this, "UnusualSubMenu" );
+ pUnusualSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pUnusualSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_Unusual", pUnusualSubMenu, "customization" );
+ }
+
+ int iParticleIndex = pUnusualList->Element( i );
+ int nIndex = pUnusualSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "SetUnusual%d", iParticleIndex ) ), this );
+ vgui::MenuItem *pMenuItem = pUnusualSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( GetItemSchema()->GetParticleSystemLocalizedName( iParticleIndex ) );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+ }
+ }
+
+ int nX, nY;
+ g_pVGuiInput->GetCursorPosition( nX, nY );
+ m_pCustomizeMenu->SetPos( nX - 1, nY - 1 );
+
+ m_pCustomizeMenu->SetVisible(true);
+ m_pCustomizeMenu->AddActionSignalTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateOptionsButton( void )
+{
+ if ( !m_pOptionsButton )
+ return;
+
+ m_pOptionsButton->SetVisible( false );
+
+ if ( !m_pPlayerModelPanel->IsVisible() )
+ return;
+
+ if ( !m_item.IsValid() )
+ return;
+
+ const CEconItemDefinition *pItemData = m_item.GetItemDefinition();
+ if ( !pItemData )
+ return;
+
+ bool bVisible = false;
+
+ // Is the selected item paintable
+ if ( pItemData->GetCapabilities() & ITEM_CAP_PAINTABLE )
+ {
+ bVisible = true;
+ }
+ // has multiple styles?
+ else if ( pItemData->GetNumSelectableStyles() > 1 )
+ {
+ bVisible = true;
+ }
+ // can have unusual?
+ else if ( GetUnusualList() != NULL )
+ {
+ bVisible = true;
+ }
+
+ m_pOptionsButton->SetVisible( bVisible );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateZoomButton( void )
+{
+ if ( !m_pZoomButton )
+ return;
+
+ m_pZoomButton->SetVisible( m_pPlayerModelPanel->IsVisible() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateTeamButton( void )
+{
+ if ( !m_pTeamButton )
+ return;
+
+ m_pTeamButton->SetVisible( m_pPlayerModelPanel->IsVisible() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::UpdateNextWeaponButton( void )
+{
+ if ( !m_pNextWeaponButton )
+ return;
+
+ if ( !m_pPlayerModelPanel->IsVisible() )
+ {
+ m_pNextWeaponButton->SetVisible( false );
+ return;
+ }
+
+ bool bShowNextWeaponsButton = false;
+ const CUtlVector<CEconItemView*> &items = m_pPlayerModelPanel->GetCarriedItems();
+ int iNumItemsArray[CLASS_LOADOUT_POSITION_COUNT];
+ memset( iNumItemsArray, 0, sizeof( iNumItemsArray ) );
+ FOR_EACH_VEC( items, i )
+ {
+ CEconItemView *pItem = items[i];
+ int iLoadoutSlot = pItem->GetStaticData()->GetLoadoutSlot( m_iCurrentClass );
+ if ( iLoadoutSlot >= 0 && iLoadoutSlot < CLASS_LOADOUT_POSITION_COUNT )
+ {
+ ++iNumItemsArray[iLoadoutSlot];
+ }
+ }
+ bShowNextWeaponsButton |= iNumItemsArray[LOADOUT_POSITION_PRIMARY] + iNumItemsArray[LOADOUT_POSITION_SECONDARY] + iNumItemsArray[LOADOUT_POSITION_MELEE] > 1;
+
+ m_pNextWeaponButton->SetVisible( bShowNextWeaponsButton );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::OnHideClassIconMouseover( void )
+{
+ if ( m_pClassIconMouseoverLabel )
+ {
+ m_pClassIconMouseoverLabel->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::OnShowClassIconMouseover( KeyValues *data )
+{
+ if ( m_pClassIconMouseoverLabel )
+ {
+ const CEconItemDefinition *pItemData = m_item.GetItemDefinition();
+ bool bIsABundle = pItemData ? (pItemData->GetBundleInfo() != NULL) : false;
+
+ // Set the text to the correct string
+ int iClass = data->GetInt( "class", 0 );
+ if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass < TF_LAST_NORMAL_CLASS )
+ {
+ wchar_t wzLocalized[256];
+ const char *pszLocString = bIsABundle ? "#Store_ClassImageMouseoverBundle" : "#Store_ClassImageMouseover";
+ g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( pszLocString ), 1, g_pVGuiLocalize->Find( g_aPlayerClassNames[iClass] ) );
+ m_pClassIconMouseoverLabel->SetText( wzLocalized );
+ }
+ else
+ {
+ const char *pszLocString = bIsABundle ? "#Store_ClassImageMouseoverAllBundle" : "#Store_ClassImageMouseoverAll";
+ m_pClassIconMouseoverLabel->SetText( pszLocString );
+ }
+
+ m_pClassIconMouseoverLabel->SetVisible( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::CycleStyle( void )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ // Find and cycle the style based on the first item we're previewing that has
+ // styles. If we are previewing multiple items at the same time where more than
+ // one of them has styles, we'll only cycle through the names/options of the
+ // first one in the list.
+ CEconItemView *pPreviewItemView = NULL;
+
+ const CUtlVector<CEconItemView*> &vecItems = m_pPlayerModelPanel->GetCarriedItems();
+ FOR_EACH_VEC( vecItems, i )
+ {
+ CEconItemView *pItem = vecItems[i];
+ if ( pItem->GetStaticData()->GetNumStyles() && ( pItem->GetFlags() & kEconItemFlagClient_Preview ) )
+ {
+ pPreviewItemView = pItem;
+ break;
+ }
+ }
+
+ if ( !pPreviewItemView )
+ return;
+
+ // Cycle.
+ style_index_t unStyleCount = pPreviewItemView->GetStaticData()->GetNumStyles();
+ Assert( unStyleCount >= 1 );
+
+ style_index_t unStyle = pPreviewItemView->GetItemStyle();
+ // Default to style 0 if we're getting an invalid index
+ unStyle = unStyle == INVALID_STYLE_INDEX ? 0 : unStyle;
+
+ // Try to find the next selectable style
+ const CEconStyleInfo *pStyle = NULL;
+ style_index_t unStartingStyle = unStyle;
+ do
+ {
+ unStyle = (unStyle + 1) % unStyleCount;
+ pStyle = pPreviewItemView->GetStaticData()->GetStyleInfo( unStyle );
+ Assert( pStyle );
+ }
+ while ( unStyle != unStartingStyle && ( !pStyle || !pStyle->IsSelectable() ) );
+
+ pPreviewItemView->SetItemStyleOverride( unStyle );
+ SetCycleLabelText( m_pStyleNameLabel, pStyle->GetName() );
+
+ // Re-equip our held item. This causes all of our equipped items to get reloaded, and thus
+ // their styles updated
+ m_pPlayerModelPanel->SwitchHeldItemTo( m_pPlayerModelPanel->GetHeldItem() );
+ m_pPlayerModelPanel->UpdatePreviewVisuals();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetPaint( item_definition_index_t iItemDef )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ if ( !IsAnythingPaintable( m_pPlayerModelPanel->GetCarriedItems() ) )
+ return;
+
+ static CSchemaAttributeDefHandle pAttribDef_Paint( "set item tint RGB" );
+ static CSchemaAttributeDefHandle pAttribDef_Paint2( "set item tint RGB 2" );
+
+ // Find the next paint color.
+ const CEconItemSchema::SortedItemDefinitionMap_t &mapDefs = GetItemSchema()->GetSortedItemDefinitionMap();
+
+ m_unPaintRGB0 = 0;
+ m_unPaintRGB1 = 0;
+
+ if ( iItemDef != INVALID_ITEM_DEF_INDEX )
+ {
+ int iteratorName = mapDefs.FirstInorder();
+ while ( iteratorName != mapDefs.InvalidIndex() )
+ {
+ // Find the next sub
+ int iIndex = mapDefs[iteratorName]->GetDefinitionIndex();
+ if ( iIndex == iItemDef )
+ {
+ // Is this definition something that has paint attributes on it?
+ const CEconItemDefinition *pData = mapDefs[iteratorName];
+
+ float fRGB = 0.0f;
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pData, pAttribDef_Paint, &fRGB ) && fRGB != 0.0f )
+ {
+ m_unPaintRGB0 = fRGB;
+
+ // We may or may not have a secondary paint color as well. If we don't, we just use the primary
+ // paint color to fill both slots.
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pData, pAttribDef_Paint2, &fRGB ) )
+ {
+ m_unPaintRGB1 = fRGB;
+ }
+ else
+ {
+ m_unPaintRGB1 = m_unPaintRGB0;
+ }
+
+ m_unPaintDef = pData->GetDefinitionIndex();
+ SetCycleLabelText( m_pPaintNameLabel, pData->GetItemBaseName() );
+ }
+ else
+ {
+ Warning( "CTFStorePreviewItemPanelBase::SetPaint iItemDef[%d] is not paint item", iItemDef );
+ }
+
+ break;
+ }
+
+ iteratorName = mapDefs.NextInorder( iteratorName );
+ }
+ }
+
+ if ( m_unPaintRGB0 == 0 )
+ {
+ m_unPaintDef = 0;
+ SetCycleLabelText( m_pPaintNameLabel, "#Store_NoPaint" );
+ }
+
+ UpdatePaintColorsForTeam( m_pPlayerModelPanel, m_unPaintRGB0, m_unPaintRGB1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetStyle( style_index_t unStyle )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ // Find and cycle the style based on the first item we're previewing that has
+ // styles. If we are previewing multiple items at the same time where more than
+ // one of them has styles, we'll only cycle through the names/options of the
+ // first one in the list.
+ CEconItemView *pPreviewItemView = NULL;
+
+ const CUtlVector<CEconItemView*> &vecItems = m_pPlayerModelPanel->GetCarriedItems();
+ FOR_EACH_VEC( vecItems, i )
+ {
+ CEconItemView *pItem = vecItems[i];
+ if ( pItem->GetStaticData()->GetNumSelectableStyles() > 1 )
+ {
+ pPreviewItemView = pItem;
+ break;
+ }
+ }
+
+ if ( !pPreviewItemView )
+ return;
+
+ pPreviewItemView->SetItemStyleOverride( unStyle );
+ const CEconStyleInfo *pStyle = pPreviewItemView->GetStaticData()->GetStyleInfo( unStyle );
+ Assert( pStyle && pStyle->IsSelectable() );
+ if ( pStyle )
+ {
+ SetCycleLabelText( m_pStyleNameLabel, pStyle->GetName() );
+ }
+
+ // Re-equip our held item. This causes all of our equipped items to get reloaded, and thus
+ // their styles updated
+ m_pPlayerModelPanel->SwitchHeldItemTo( m_pPlayerModelPanel->GetHeldItem() );
+ m_pPlayerModelPanel->UpdatePreviewVisuals();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::SetUnusual( uint32 iUnusualIndex )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
+ static CSchemaAttributeDefHandle pAttrDef_OnTauntAttachParticleIndex( "on taunt attach particle index" );
+ const CUtlVector<CEconItemView*> &vecItems = m_pPlayerModelPanel->GetCarriedItems();
+
+ FOR_EACH_VEC( vecItems, i )
+ {
+ CEconItemView *pItem = vecItems[i];
+ if ( pItem->GetStaticData()->GetTauntData() )
+ {
+ const float& value_as_float = (float&)iUnusualIndex;
+ pItem->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_OnTauntAttachParticleIndex, value_as_float );
+ }
+ else
+ {
+ pItem->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_AttachParticleEffect, iUnusualIndex );
+ }
+ }
+ m_pPlayerModelPanel->InvalidateParticleEffects();
+ m_pPlayerModelPanel->SwitchHeldItemTo( m_pPlayerModelPanel->GetHeldItem() );
+}
+
+
+const CUtlVector< int > *CTFStorePreviewItemPanelBase::GetUnusualList() const
+{
+ if ( !AllowUnusualPreview() )
+ return NULL;
+
+ int iLoadoutSlot = m_item.GetStaticData()->GetLoadoutSlot( m_iCurrentClass );
+ if ( IsValidPickupWeaponSlot( iLoadoutSlot ) )
+ {
+ return GetItemSchema()->GetWeaponUnusualParticleIndexes();
+ }
+ // is hat or whole head?
+ else if ( m_item.GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "hat" ) || m_item.GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "whole_head" ) )
+ {
+ return GetItemSchema()->GetCosmeticUnusualParticleIndexes();
+ }
+ else if ( IsTauntSlot( iLoadoutSlot ) )
+ {
+ return GetItemSchema()->GetTauntUnusualParticleIndexes();
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanelBase::CyclePaint( bool bActuallyCycle )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ if ( !IsAnythingPaintable( m_pPlayerModelPanel->GetCarriedItems() ) )
+ return;
+
+ static CSchemaAttributeDefHandle pAttribDef_Paint( "set item tint RGB" );
+ static CSchemaAttributeDefHandle pAttribDef_Paint2( "set item tint RGB 2" );
+
+ // Find the next paint color.
+ const CEconItemSchema::SortedItemDefinitionMap_t &mapDefs = GetItemSchema()->GetSortedItemDefinitionMap();
+
+ m_unPaintRGB0 = 0;
+ m_unPaintRGB1 = 0;
+
+ if ( bActuallyCycle || m_unPaintDef > 0 )
+ {
+ int iteratorName = mapDefs.FirstInorder();
+ while ( iteratorName != mapDefs.InvalidIndex() )
+ {
+ // Find the next sub
+ int iIndex = mapDefs[iteratorName]->GetDefinitionIndex();
+ if ( bActuallyCycle ? iIndex > m_unPaintDef : iIndex >= m_unPaintDef )
+ {
+ // Is this definition something that has paint attributes on it?
+ const CEconItemDefinition *pData = mapDefs[iteratorName];
+
+ float fRGB = 0.0f;
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pData, pAttribDef_Paint, &fRGB ) && fRGB != 0.0f )
+ {
+ if ( V_strstr( pData->GetItemBaseName(), "Halloween" ) )
+ {
+ iteratorName = mapDefs.NextInorder( iteratorName );
+ continue;
+ }
+
+ m_unPaintRGB0 = fRGB;
+
+ // We may or may not have a secondary paint color as well. If we don't, we just use the primary
+ // paint color to fill both slots.
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pData, pAttribDef_Paint2, &fRGB ) )
+ {
+ m_unPaintRGB1 = fRGB;
+ }
+ else
+ {
+ m_unPaintRGB1 = m_unPaintRGB0;
+ }
+
+ m_unPaintDef = pData->GetDefinitionIndex();
+ SetCycleLabelText( m_pPaintNameLabel, pData->GetItemBaseName() );
+ break;
+ }
+ }
+
+ iteratorName = mapDefs.NextInorder( iteratorName );
+ }
+ }
+
+ if ( m_unPaintRGB0 == 0 )
+ {
+ m_unPaintDef = 0;
+ SetCycleLabelText( m_pPaintNameLabel, "#Store_NoPaint" );
+ }
+
+ UpdatePaintColorsForTeam( m_pPlayerModelPanel, m_unPaintRGB0, m_unPaintRGB1 );
+}
diff --git a/game/client/tf/vgui/store/tf_store_preview_item_base.h b/game/client/tf/vgui/store/tf_store_preview_item_base.h
new file mode 100644
index 0000000..cd382a0
--- /dev/null
+++ b/game/client/tf/vgui/store/tf_store_preview_item_base.h
@@ -0,0 +1,102 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PREVIEW_ITEM_BASE_H
+#define TF_STORE_PREVIEW_ITEM_BASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include "store/store_preview_item.h"
+#include "store/v1/tf_store_page.h"
+#include "tf_shareddefs.h"
+#include "tf_hud_mainmenuoverride.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePreviewItemPanelBase : public CStorePreviewItemPanel
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePreviewItemPanelBase, CStorePreviewItemPanel );
+protected:
+ // CTFStorePreviewItemPanelBase should not be intantiated directly
+ CTFStorePreviewItemPanelBase( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner );
+
+public:
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+ virtual void PerformLayout( void );
+ virtual void OnTick( void );
+
+ virtual void PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry=NULL ) OVERRIDE;
+ virtual void SetState( preview_state_t iState );
+
+ virtual int GetPreviewTeam() const;
+
+ MESSAGE_FUNC_PARAMS( OnClassIconSelected, "ClassIconSelected", data );
+ MESSAGE_FUNC( OnHideClassIconMouseover, "HideClassIconMouseover" );
+ MESSAGE_FUNC_PARAMS( OnShowClassIconMouseover, "ShowClassIconMouseover", data );
+
+protected:
+ void UpdateModelPanel();
+ virtual void SetPlayerModelVisible( bool bVisible );
+ virtual void UpdatePlayerModelButtons( void );
+ virtual void UpdateCustomizeMenu( void );
+ void UpdateOptionsButton( void );
+ void UpdateNextWeaponButton( void );
+ void UpdateZoomButton( void );
+ void UpdateTeamButton( void );
+ virtual void UpdateIcons( void );
+
+ void SetPaint( item_definition_index_t iItemDef );
+ void SetStyle( style_index_t unStyle );
+ void SetUnusual( uint32 iUnusualIndex );
+ const CUtlVector< int > *GetUnusualList() const;
+ virtual bool AllowUnusualPreview() const
+ {
+#ifdef STAGING_ONLY
+ // we want to be able to use this everywhere in staging for testing purpose
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ void CyclePaint( bool bActuallyCycle = true );
+ void CycleStyle( void );
+ void ResetHandles( void );
+
+ // This can be overridden to capture *any* "cycle text" that is being set, so one generic label can be used
+ // by a derived class if needed. Base version just sets the label's text.
+ virtual void SetCycleLabelText( vgui::Label *pTargetLabel, const char *pCycleText );
+
+ vgui::Label *m_pClassIconMouseoverLabel;
+ CTFPlayerModelPanel *m_pPlayerModelPanel;
+ CUtlVector<CStorePreviewClassIcon*> m_pClassIcons;
+
+ int m_iCurrentClass;
+ int m_iCurrentHeldItem;
+
+ item_definition_index_t m_unPaintDef;
+ uint32 m_unPaintRGB0;
+ uint32 m_unPaintRGB1;
+
+ CExButton *m_pRotRightButton;
+ CExButton *m_pRotLeftButton;
+ CExButton *m_pNextWeaponButton;
+ CExButton *m_pZoomButton;
+ CExButton *m_pOptionsButton;
+ CExButton *m_pTeamButton;
+ vgui::Label *m_pPaintNameLabel;
+ vgui::Label *m_pStyleNameLabel;
+
+ Menu *m_pCustomizeMenu;
+ CUtlVector< item_definition_index_t > m_vecPaintCans;
+};
+
+#endif // TF_STORE_PREVIEW_ITEM_H
diff --git a/game/client/tf/vgui/store/v1/tf_store_page.cpp b/game/client/tf/vgui/store/v1/tf_store_page.cpp
new file mode 100644
index 0000000..9d55a9c
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_page.cpp
@@ -0,0 +1,96 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v1/tf_store_page.h"
+#include "store/v1/tf_store_preview_item.h"
+#include "c_tf_freeaccount.h"
+#include "store/store_panel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePage1::CTFStorePage1(Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile ) : BaseClass(parent, pPageData, pPreviewItemResFile)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CTFStorePage1::GetPageResFile( void )
+{
+ Assert( !"No code should currently reference the old store!" );
+
+ return m_pPageData->m_pchPageRes;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::OnPageShow( void )
+{
+ BaseClass::OnPageShow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::OnItemDetails( vgui::Panel *panel )
+{
+ BaseClass::OnItemDetails( panel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::ShowPreview( int iClass, const econ_store_entry_t* pEntry )
+{
+ BaseClass::ShowPreview( iClass, pEntry );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::UpdateFilterComboBox( void )
+{
+ BaseClass::UpdateFilterComboBox();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters )
+{
+ return BaseClass::GetFiltersForDef( pDef, pVecFilters );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage1::OnTick( void )
+{
+ BaseClass::OnTick();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CStorePreviewItemPanel *CTFStorePage1::CreatePreviewPanel( void )
+{
+ return new CTFStorePreviewItemPanel1( this, m_pPreviewItemResFile, "storepreviewitem", this );
+}
diff --git a/game/client/tf/vgui/store/v1/tf_store_page.h b/game/client/tf/vgui/store/v1/tf_store_page.h
new file mode 100644
index 0000000..814bc01
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_page.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PAGE1_H
+#define TF_STORE_PAGE1_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_page_base.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePage1 : public CTFStorePageBase
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePage1, CTFStorePageBase );
+public:
+ CTFStorePage1( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile = NULL );
+
+ virtual const char *GetPageResFile( void );
+ virtual void OnCommand( const char *command );
+ virtual void ShowPreview( int iClass, const econ_store_entry_t* pEntry );
+
+ MESSAGE_FUNC( OnPageShow, "PageShow" );
+ MESSAGE_FUNC_PTR( OnItemDetails, "ItemDetails", panel );
+
+ virtual void UpdateFilterComboBox( void );
+ virtual void GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters );
+ virtual void OnTick( void );
+
+ virtual CStorePreviewItemPanel *CreatePreviewPanel( void );
+};
+
+#endif // TF_STORE_PAGE1_H
diff --git a/game/client/tf/vgui/store/v1/tf_store_page_maps.cpp b/game/client/tf/vgui/store/v1/tf_store_page_maps.cpp
new file mode 100644
index 0000000..4b8a895
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_page_maps.cpp
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v1/tf_store_page_maps.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePage_Maps::CTFStorePage_Maps( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData )
+: BaseClass( parent, pPageData, "Resource/UI/econ/store/v1/StorePreviewItemPanel_Maps.res" )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage_Maps::OnPageShow()
+{
+ BaseClass::OnPageShow();
+
+ SetDetailsVisible( false );
+} \ No newline at end of file
diff --git a/game/client/tf/vgui/store/v1/tf_store_page_maps.h b/game/client/tf/vgui/store/v1/tf_store_page_maps.h
new file mode 100644
index 0000000..30fc0dc
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_page_maps.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef STORE_PAGE_MAPS_H
+#define STORE_PAGE_MAPS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/v1/tf_store_page.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePage_Maps : public CTFStorePage1
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePage_Maps, CTFStorePage1 );
+public:
+ CTFStorePage_Maps( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData );
+ virtual ~CTFStorePage_Maps() {}
+
+ virtual const char* GetPageResFile() { return "Resource/UI/econ/store/v1/StorePage_Maps.res"; }
+
+ virtual void OnPageShow( void );
+
+protected:
+};
+
+#endif // STORE_PAGE_MAPS_H
diff --git a/game/client/tf/vgui/store/v1/tf_store_panel.cpp b/game/client/tf/vgui/store/v1/tf_store_panel.cpp
new file mode 100644
index 0000000..4daf037
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_panel.cpp
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v1/tf_store_page.h"
+#include "store/v1/tf_store_panel.h"
+#include "store/store_page_halloween.h"
+#include "store/store_page_new.h"
+#include "store/v1/tf_store_page_maps.h"
+#include "store/store_viewcart.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePanel1::CTFStorePanel1( vgui::Panel *parent ) : CTFBaseStorePanel(parent)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel1::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel1::OnThink()
+{
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel1::PostTransactionCompleted( void )
+{
+ BaseClass::PostTransactionCompleted();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Static store page factory.
+//-----------------------------------------------------------------------------
+CStorePage *CTFStorePanel1::CreateStorePage( const CEconStoreCategoryManager::StoreCategory_t *pPageData )
+{
+ if ( pPageData )
+ {
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_SpecialPromo" ) )
+ return new CTFStorePage_SpecialPromo( this, pPageData );
+
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_Maps" ) )
+ return new CTFStorePage_Maps( this, pPageData );
+
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_Popular" ) )
+ return new CTFStorePage_Popular( this, pPageData );
+ }
+
+ // Default, standard store page.
+ return new CTFStorePage1( this, pPageData );
+}
diff --git a/game/client/tf/vgui/store/v1/tf_store_panel.h b/game/client/tf/vgui/store/v1/tf_store_panel.h
new file mode 100644
index 0000000..cac6b00
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_panel.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PANEL1_H
+#define TF_STORE_PANEL1_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_panel_base.h"
+
+class CStorePage;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePanel1 : public CTFBaseStorePanel
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePanel1, CTFBaseStorePanel );
+public:
+ CTFStorePanel1( vgui::Panel *parent );
+
+ // UI Layout
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnThink();
+
+ // GC Management
+ virtual void PostTransactionCompleted( void );
+
+private:
+ virtual CStorePage *CreateStorePage( const CEconStoreCategoryManager::StoreCategory_t *pPageData );
+};
+
+#endif // TF_STORE_PANEL1_H
diff --git a/game/client/tf/vgui/store/v1/tf_store_preview_item.cpp b/game/client/tf/vgui/store/v1/tf_store_preview_item.cpp
new file mode 100644
index 0000000..7f23513
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_preview_item.cpp
@@ -0,0 +1,100 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v1/tf_store_preview_item.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePreviewItemPanel1::CTFStorePreviewItemPanel1( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner )
+: BaseClass( pParent, pResFile, "storepreviewitem", pOwner )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::OnClassIconSelected( KeyValues *data )
+{
+ BaseClass::OnClassIconSelected( data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::OnHideClassIconMouseover( void )
+{
+ BaseClass::OnHideClassIconMouseover();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::OnShowClassIconMouseover( KeyValues *data )
+{
+ BaseClass::OnShowClassIconMouseover( data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry )
+{
+ BaseClass::PreviewItem( iClass, pItem, pEntry );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::SetState( preview_state_t iState )
+{
+ BaseClass::SetState( iState );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::UpdateIcons( void )
+{
+ BaseClass::UpdateIcons();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel1::OnTick( void )
+{
+ BaseClass::OnTick();
+}
diff --git a/game/client/tf/vgui/store/v1/tf_store_preview_item.h b/game/client/tf/vgui/store/v1/tf_store_preview_item.h
new file mode 100644
index 0000000..02994c4
--- /dev/null
+++ b/game/client/tf/vgui/store/v1/tf_store_preview_item.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PREVIEW_ITEM1_H
+#define TF_STORE_PREVIEW_ITEM1_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_preview_item_base.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePreviewItemPanel1 : public CTFStorePreviewItemPanelBase
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePreviewItemPanel1, CTFStorePreviewItemPanelBase );
+public:
+ CTFStorePreviewItemPanel1( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+ virtual void PerformLayout( void );
+ virtual void OnTick( void );
+
+ virtual void PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry=NULL ) OVERRIDE;
+ virtual void SetState( preview_state_t iState );
+
+ MESSAGE_FUNC_PARAMS( OnClassIconSelected, "ClassIconSelected", data );
+ MESSAGE_FUNC( OnHideClassIconMouseover, "HideClassIconMouseover" );
+ MESSAGE_FUNC_PARAMS( OnShowClassIconMouseover, "ShowClassIconMouseover", data );
+
+private:
+ virtual void UpdateIcons( void );
+};
+
+#endif // TF_STORE_PREVIEW_ITEM1_H
diff --git a/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.cpp b/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.cpp
new file mode 100644
index 0000000..1ee55a8
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.cpp
@@ -0,0 +1,83 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v2/tf_store_mapstamps_info_dialog.h"
+#include "tf_mouseforwardingpanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+DECLARE_BUILD_FACTORY( CTFMapStampsInfoDialog );
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFMapStampsInfoDialog::CTFMapStampsInfoDialog( vgui::Panel *pParent, const char *pName )
+: BaseClass( pParent, "MapStampsInfoDialog" )
+{
+ m_pBgPanel = new CMouseMessageForwardingPanel( this, "BgPanel" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFMapStampsInfoDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "Resource/UI/econ/store/v2/StoreMapStampsInfoDialog.res" );
+
+ m_pDlgFrame = dynamic_cast<EditablePanel *>( FindChildByName( "DialogFrame" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFMapStampsInfoDialog::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFMapStampsInfoDialog::OnCommand( const char *command )
+{
+ if ( !V_strnicmp( command, "close", 5 ) )
+ {
+ DoClose();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFMapStampsInfoDialog::OnMouseReleased(MouseCode code)
+{
+ BaseClass::OnMouseReleased( code );
+
+ if ( m_pDlgFrame && !m_pDlgFrame->IsCursorOver() )
+ {
+ DoClose();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFMapStampsInfoDialog::DoClose()
+{
+ SetVisible( false );
+ MarkForDeletion();
+} \ No newline at end of file
diff --git a/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.h b/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.h
new file mode 100644
index 0000000..7486e8c
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_mapstamps_info_dialog.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_MAPS_INFO_DIALOG_H
+#define TF_MAPS_INFO_DIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/EditablePanel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFMapStampsInfoDialog : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CTFMapStampsInfoDialog, vgui::EditablePanel );
+public:
+ CTFMapStampsInfoDialog( vgui::Panel *pParent, const char *pName = "" );
+
+ void DoClose();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+ virtual void PerformLayout( void );
+ virtual void OnMouseReleased(vgui::MouseCode code);
+
+ Panel *m_pBgPanel;
+ EditablePanel *m_pDlgFrame;
+};
+
+#endif // TF_MAPS_INFO_DIALOG_H
diff --git a/game/client/tf/vgui/store/v2/tf_store_page2.cpp b/game/client/tf/vgui/store/v2/tf_store_page2.cpp
new file mode 100644
index 0000000..c7ac2f2
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_page2.cpp
@@ -0,0 +1,849 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v2/tf_store_page2.h"
+#include "store/v2/tf_store_preview_item2.h"
+#include "c_tf_freeaccount.h"
+#include "store/store_panel.h"
+#include "store/tf_store.h"
+#include "navigationpanel.h"
+#include "econ/store/store_page_new.h"
+#include "econ_item_system.h"
+#include "c_tf_gamestats.h"
+#include "vgui_controls/TextImage.h"
+#include "econ_item_description.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+static const int kNumSortTypes = 5;
+ItemSortTypeData_t g_StoreSortTypes[ kNumSortTypes ] =
+{
+ { "#Store_SortType_DateNewest", kEconStoreSortType_DateNewest },
+ { "#Store_SortType_DateOldest", kEconStoreSortType_DateOldest },
+ { "#Store_SortType_HighestPrice", kEconStoreSortType_Price_HighestToLowest },
+ { "#Store_SortType_LowestPrice", kEconStoreSortType_Price_LowestToHighest },
+ { "#Store_SortType_Alphabetical", kEconStoreSortType_Name_AToZ },
+};
+
+class CClassFilterTooltip : public vgui::BaseTooltip
+{
+public:
+ CClassFilterTooltip( CTFStorePage2 *pStorePage )
+ : BaseTooltip( pStorePage )
+ , m_pStorePage( pStorePage )
+ {
+ }
+
+ CTFStorePage2 *m_pStorePage;
+
+ virtual void SetText(const char *text)
+ {
+ m_pStorePage->m_pClassFilterTooltipLabel->SetText( text );
+ }
+
+ virtual void ShowTooltip(Panel *currentPanel)
+ {
+ int x = 0;
+ int y = currentPanel->GetTall();
+ currentPanel->LocalToScreen( x, y );
+ m_pStorePage->ScreenToLocal( x, y );
+
+ // The tooltip wants to be centered around the given panel, but it's constrained by the left and right boundaries
+ // of the navigation panel.
+ if ( m_pStorePage->m_pClassFilterButtons )
+ {
+ // Right side of tooltip should not pass right boundary of nav panel
+ int aClassFilterNavPos[2] = { 0, 0 };
+ m_pStorePage->m_pClassFilterButtons->GetPos( aClassFilterNavPos[0], aClassFilterNavPos[1] );
+ const int nTipWide = m_pStorePage->m_pClassFilterTooltipLabel->GetWide();
+ x = clamp(
+ x + ( currentPanel->GetWide() - nTipWide ) / 2,
+ aClassFilterNavPos[0],
+ aClassFilterNavPos[0] + m_pStorePage->m_pClassFilterButtons->GetWide() - nTipWide );
+ }
+
+ m_pStorePage->m_pClassFilterTooltipLabel->SetPos( x, y );
+ m_pStorePage->m_pClassFilterTooltipLabel->SetVisible( true );
+ }
+ virtual void HideTooltip()
+ {
+ m_pStorePage->m_pClassFilterTooltipLabel->SetVisible( false );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePage2::CTFStorePage2(Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile )
+: BaseClass( parent, pPageData, pPreviewItemResFile ),
+ m_pSubcategoriesFilterCombo( NULL ),
+ m_pSortByCombo( NULL ),
+ m_pHomeCategoryTabs( NULL ),
+ m_pClassFilterButtons( NULL ),
+ m_pNameFilterTextEntry( NULL ),
+ m_pSubcategoriesFilterLabel( NULL ),
+ m_iCurrentSubcategory( 2 ), // Switch to Featured items tab on home page when store launches; BRETT SAID I COULD DO THIS
+ m_pClassFilterTooltipLabel( NULL ),
+ m_pClassFilterTooltip( NULL ),
+ m_flFilterItemTime( 0.0f )
+{
+ const CEconStorePriceSheet *pPriceSheet = EconUI()->GetStorePanel()->GetPriceSheet();
+
+ if ( IsHomePage() )
+ {
+ bool bAtLeastOneItemIsOnSale = false;
+ if ( pPriceSheet )
+ {
+ const CEconStorePriceSheet::StoreEntryMap_t& mapStoreEntries = pPriceSheet->GetEntries();
+ FOR_EACH_MAP_FAST( mapStoreEntries, i )
+ {
+ if ( mapStoreEntries[i].IsOnSale( EconUI()->GetStorePanel()->GetCurrency() ) )
+ {
+ bAtLeastOneItemIsOnSale = true;
+ break;
+ }
+ }
+ }
+
+ m_pHomeCategoryTabs = new CNavigationPanel( this, "ItemCategoryTabs" );
+
+ FOR_EACH_VEC( m_pPageData->m_vecSubcategories, i )
+ {
+ // Skip over adding the "On Sale!" tab if no items are currently on sale.
+ const char *pchName = m_pPageData->m_vecSubcategories[i]->m_pchName;
+ bool bIsOnSaleCategory = m_pPageData->m_vecSubcategories[i]->m_unID == CEconStoreCategoryManager::k_CategoryID_OnSale;
+
+ // Skip over the "Top Sellers" tab as we're replacing it with the 'Starter Packs' tab for now
+ bool bIsPopularCategory = m_pPageData->m_vecSubcategories[i]->m_unID == CEconStoreCategoryManager::k_CategoryID_Popular;
+
+ // Skip over the "New" tab as we're replacing it with the 'Featured' tab for now
+ bool bIsNew = m_pPageData->m_vecSubcategories[i]->m_unID == CEconStoreCategoryManager::k_CategoryID_New;
+
+ // We include all of the sale items in the Featured tab currently, so we don't need to add these categories back in at the moment
+ bAtLeastOneItemIsOnSale = false;
+
+ if ( ( !bIsPopularCategory && !bIsOnSaleCategory && !bIsNew ) || ( bAtLeastOneItemIsOnSale && bIsOnSaleCategory ) )
+ {
+ m_pHomeCategoryTabs->AddButton( i, pchName );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+CTFStorePage2::~CTFStorePage2()
+{
+ delete m_pClassFilterTooltip;
+ m_pClassFilterTooltip = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnPostCreate()
+{
+ BaseClass::OnPostCreate();
+
+ m_bShouldDeletePreviewPanel = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFStorePage2::HasSubcategories() const
+{
+ return m_pPageData && m_pPageData->HasSubcategories();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( m_pSubcategoriesFilterCombo )
+ {
+ m_pSubcategoriesFilterCombo->SetVisible( HasSubcategories() );
+ }
+
+ if ( m_pSubcategoriesFilterLabel )
+ {
+ m_pSubcategoriesFilterLabel->SetVisible( HasSubcategories() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pNameFilterTextEntry = FindControl<vgui::TextEntry>( "NameFilterTextEntry" );
+ if ( m_pNameFilterTextEntry )
+ {
+ m_pNameFilterTextEntry->AddActionSignalTarget( this );
+ }
+
+ m_pSortByCombo = dynamic_cast< ComboBox * >( FindChildByName( "SortFilterComboBox" ) );
+ if ( m_pSortByCombo )
+ {
+ m_pSortByCombo->RemoveAll();
+ vgui::HFont hFont = pScheme->GetFont( "HudFontSmallestBold", true );
+ m_pSortByCombo->SetFont( hFont );
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ for ( int i = 0; i < ARRAYSIZE(g_StoreSortTypes); i++ )
+ {
+ pKeyValues->SetInt( "sortby", i );
+ m_pSortByCombo->AddItem( g_StoreSortTypes[i].szSortDesc, pKeyValues );
+ }
+ pKeyValues->deleteThis();
+ m_pSortByCombo->ActivateItemByRow( 0 );
+ }
+
+ m_pSubcategoriesFilterCombo = dynamic_cast< ComboBox * >( FindChildByName( "SubcategoryFilterComboBox" ) );
+ if ( m_pSubcategoriesFilterCombo )
+ {
+ vgui::HFont hFont = pScheme->GetFont( "HudFontSmallestBold", true );
+ m_pSubcategoriesFilterCombo->SetFont( hFont );
+
+ m_pSubcategoriesFilterCombo->RemoveAll();
+
+ if ( m_pPageData )
+ {
+ // Add "all items" explicitly
+ KeyValuesAD kvAllItems( "data" );
+ kvAllItems->SetInt( "index", GetNumSubcategories() );
+ m_pSubcategoriesFilterCombo->AddItem( "#Store_ClassFilter_None", kvAllItems );
+
+ FOR_EACH_VEC( m_pPageData->m_vecSubcategories, i )
+ {
+ KeyValues *pData = new KeyValues( "data" );
+ pData->SetInt( "index", i );
+
+ m_pSubcategoriesFilterCombo->AddItem( m_pPageData->m_vecSubcategories[i]->m_pchName, pData );
+
+ pData->deleteThis();
+ }
+ }
+
+ // Move to "All items" selected
+ m_pSubcategoriesFilterCombo->ActivateItemByRow( 0 );
+
+ m_pSubcategoriesFilterCombo->GetComboButton()->SetFgColor( Color( 117,107,94,255 ) );
+ m_pSubcategoriesFilterCombo->GetComboButton()->SetDefaultColor( Color( 117,107,94,255), Color( 0,0,0,0) );
+ m_pSubcategoriesFilterCombo->GetComboButton()->SetArmedColor( Color( 117,107,94,255), Color( 0,0,0,0) );
+ m_pSubcategoriesFilterCombo->GetComboButton()->SetDepressedColor( Color( 117,107,94,255), Color( 0,0,0,0) );
+ }
+
+ m_pClassFilterButtons = dynamic_cast< CNavigationPanel * >( FindChildByName( "ClassFilterNavPanel" ) );
+ m_pSubcategoriesFilterLabel = dynamic_cast< CExLabel * >( FindChildByName( "SubcategoryFiltersLabel" ) );
+
+ m_pClassFilterTooltipLabel = dynamic_cast< CExLabel * >( FindChildByName( "ClassFilterTooltipLabel" ) );
+ if ( m_pClassFilterTooltipLabel && m_pClassFilterButtons )
+ {
+ m_pClassFilterTooltip = new CClassFilterTooltip(this);
+ for ( int i = 0 ; i < m_pClassFilterButtons->NumButtons() ; ++i )
+ {
+ CExButton *pButton = m_pClassFilterButtons->GetButton( i );
+ CUtlString sSaveText = pButton->GetEffectiveTooltipText();
+ pButton->SetTooltip( m_pClassFilterTooltip, sSaveText );
+ }
+ }
+
+ // Setup title text in home page
+ if ( IsHomePage() && g_pVGuiLocalize )
+ {
+ CExLabel *pTitleLabel = dynamic_cast<CExLabel *>( FindChildByName( "TitleLabel" ) );
+ wchar_t *pHomePageTitle = g_pVGuiLocalize->Find( "#Store_HomePageTitle" );
+ wchar_t *pRedText = g_pVGuiLocalize->Find( "#Store_HomePageTitleRedText" );
+
+ if ( pTitleLabel && pHomePageTitle && pRedText )
+ {
+ const store_promotion_spend_for_free_item_t *pPromotion = EconUI()->GetStorePanel()->GetPriceSheet()->GetStorePromotion_SpendForFreeItem();
+
+ ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();
+ AssertMsg( eCurrency >= k_ECurrencyUSD && eCurrency < k_ECurrencyMax, "Invalid currency!" );
+ int iPriceThreshold = pPromotion->m_rgusPriceThreshold[ eCurrency ];
+ wchar_t wszPriceThreshold[ kLocalizedPriceSizeInChararacters ];
+ MakeMoneyString( wszPriceThreshold, ARRAYSIZE( wszPriceThreshold ), iPriceThreshold, EconUI()->GetStorePanel()->GetCurrency() );
+
+ static wchar_t wszText[512];
+ g_pVGuiLocalize->ConstructString_safe( wszText, pHomePageTitle, 2, pRedText, wszPriceThreshold );
+
+ pTitleLabel->SetText( wszText );
+ TextImage *pTextImage = pTitleLabel->GetTextImage();
+ const wchar_t *pFound = wcsstr( wszText, pRedText );
+ if ( pTextImage && pFound )
+ {
+ const int iRedTextPos = pFound - wszText;
+ const int nRedTextLen = wcslen( pRedText );
+ pTextImage->ClearColorChangeStream();
+ pTextImage->AddColorChange( Color(200,80,60,255), iRedTextPos );
+ pTextImage->AddColorChange( pTitleLabel->GetFgColor(), iRedTextPos + nRedTextLen );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CTFStorePage2::GetPageResFile( void )
+{
+ if ( IsHomePage() )
+ {
+ Assert( ShouldUseNewStore() );
+
+ return "Resource/UI/econ/store/v2/StoreHome_Premium.res";
+ }
+
+ return m_pPageData->m_pchPageRes;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnPageShow( void )
+{
+ BaseClass::OnPageShow();
+
+ if ( m_pClassFilterButtons )
+ {
+ m_pClassFilterButtons->UpdateButtonSelectionStates( 0 );
+ }
+
+ ClearNameFilter( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnItemDetails( vgui::Panel *panel )
+{
+ CStoreItemControlsPanel *pControlsPanel = dynamic_cast< CStoreItemControlsPanel * >( panel );
+ if ( pControlsPanel )
+ {
+ const econ_store_entry_t *pEntry = pControlsPanel->GetItem();
+ if ( pEntry && m_pPreviewPanel )
+ {
+ ShowPreviewWindow( pEntry->GetItemDefinitionIndex() );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnItemDefDetails( KeyValues *pData )
+{
+ ShowPreviewWindow( pData->GetInt("ItemDefIndex", -1) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::ShowPreviewWindow( item_definition_index_t usDefIndex )
+{
+ if ( m_pPreviewPanel )
+ {
+ CEconItemView itemData;
+ itemData.Init( usDefIndex, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+ itemData.SetClientItemFlags( kEconItemFlagClient_Preview );
+
+ m_pPreviewPanel->PreviewItem( 0, &itemData );
+ m_pPreviewPanel->SetState( PS_ITEM ); // Adding this, since without it, only the item icon shows up
+ m_pPreviewPanel->SetVisible( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnNavButtonSelected( KeyValues *pData )
+{
+ Panel *pPanel = (Panel *)pData->GetPtr( "panel" );
+
+ if ( pPanel == m_pClassFilterButtons )
+ {
+ const int iFilter = pData->GetInt( "userdata", -1 ); AssertMsg( iFilter >= 0, "Bad filter" );
+ if ( iFilter < 0 )
+ return;
+
+ SetFilter( iFilter );
+ m_iCurrentPage = 0;
+ UpdateModelPanels();
+
+ if ( m_pCheckoutButton )
+ {
+ m_pCheckoutButton->RequestFocus();
+ }
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_page_2_nav(class)", CFmtStr( "%i", iFilter ).Access() );
+ }
+ else if ( pPanel == m_pHomeCategoryTabs )
+ {
+ int iSelectedTab = pData->GetInt( "userdata", -1 );
+ if ( iSelectedTab < 0 )
+ return;
+
+ if ( !m_pPageData || !m_pPageData->m_vecSubcategories.IsValidIndex( iSelectedTab ) )
+ return;
+
+ m_iCurrentSubcategory = iSelectedTab;
+
+ FOR_EACH_VEC( m_vecItemPanels, i )
+ {
+ // Delete the old one
+ m_vecItemPanels[i].m_pStorePricePanel->MarkForDeletion();
+
+ // Create a new one and cache it
+ CStorePricePanel *pPricePanel = CreatePricePanel( i );
+ pPricePanel->InvalidateLayout();
+ pPricePanel->SetMouseInputEnabled( false );
+ pPricePanel->SetKeyBoardInputEnabled( false );
+
+ m_vecItemPanels[i].m_pStorePricePanel = pPricePanel;
+
+ // Setup the mouse handler
+ m_vecItemPanels[i].m_pItemControlsPanel->SetMouseHoverHandler( pPricePanel );
+ }
+
+ m_iCurrentPage = 0;
+
+ UpdateFilteredItems();
+ UpdateModelPanels();
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_page_2_nav(category)", CFmtStr( "%i", iSelectedTab ).Access() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when text changes in combo box
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
+
+ vgui::TextEntry *pTextEntry = dynamic_cast<vgui::TextEntry *>( pPanel );
+
+ if ( pTextEntry )
+ {
+ if ( pTextEntry == m_pNameFilterTextEntry )
+ {
+ m_wNameFilter.RemoveAll();
+ if ( m_pNameFilterTextEntry->GetTextLength() )
+ {
+ m_wNameFilter.EnsureCount( m_pNameFilterTextEntry->GetTextLength() + 1 );
+ m_pNameFilterTextEntry->GetText( m_wNameFilter.Base(), m_wNameFilter.Count() * sizeof(wchar_t) );
+ V_wcslower( m_wNameFilter.Base() );
+ }
+ m_flFilterItemTime = gpGlobals->curtime + 0.5f;
+ return;
+ }
+ }
+
+ vgui::ComboBox *pComboBox = dynamic_cast<vgui::ComboBox *>( pPanel );
+
+ if ( pComboBox )
+ {
+ if ( pComboBox == m_pSubcategoriesFilterCombo )
+ {
+ // the class selection combo box changed, update class details
+ KeyValues *pUserData = m_pSubcategoriesFilterCombo->GetActiveItemUserData();
+ if ( !pUserData )
+ return;
+
+ // Update current subcategory filter
+ m_iCurrentSubcategory = pUserData->GetInt( "index", 0 );
+ m_bFilterDirty = true;
+
+ m_iCurrentPage = 0;
+ UpdateModelPanels();
+
+ if ( m_pCheckoutButton )
+ {
+ m_pCheckoutButton->RequestFocus();
+ }
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_page_2_nav(subcategories)", CFmtStr( "%i", m_iCurrentSubcategory ).Access() );
+ }
+
+ else if ( pComboBox == m_pSortByCombo )
+ {
+ // the class selection combo box changed, update class details
+ KeyValues *pUserData = m_pSortByCombo->GetActiveItemUserData();
+ if ( !pUserData )
+ return;
+
+ int iSortTypeSelectionIndex = pUserData->GetInt( "sortby", -1 );
+ m_bFilterDirty = true;
+ if ( iSortTypeSelectionIndex >= 0 )
+ {
+ eEconStoreSortType iSortType = (eEconStoreSortType)g_StoreSortTypes[iSortTypeSelectionIndex].iSortType;
+
+ UpdateFilteredItems();
+ UpdateModelPanels();
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_page_2_nav(sort_by)", CFmtStr( "%i", iSortType ).Access() );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters )
+{
+ BaseClass::GetFiltersForDef( pDef, pVecFilters );
+}
+
+bool CTFStorePage2::FindAndSelectEntry( const econ_store_entry_t *pEntry )
+{
+ m_iCurrentSubcategory = GetAllSubcategoriesIndex();
+ m_bFilterDirty = true;
+ if ( BaseClass::FindAndSelectEntry( pEntry ) )
+ {
+ ivgui()->PostMessage( GetVPanel(), new KeyValues( "ItemDefDetails", "ItemDefIndex", pEntry->GetItemDefinitionIndex() ), GetVPanel() );
+ return true;
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::ClearNameFilter( bool bUpdateModelPanels )
+{
+ // don't do anything if we don't have any filter
+ if ( m_wNameFilter.Count() == 0 )
+ return;
+
+ m_wNameFilter.RemoveAll();
+ if( m_pNameFilterTextEntry )
+ {
+ m_pNameFilterTextEntry->SetText( "" );
+ }
+
+ if ( bUpdateModelPanels )
+ {
+ m_flFilterItemTime = gpGlobals->curtime + 0.1f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTFStorePage2::GetAllSubcategoriesIndex() const
+{
+ return m_pPageData ? m_pPageData->GetNumSubcategories() : 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::UpdateFilteredItems()
+{
+ if ( m_bFilterDirty )
+ {
+ // Make sure list of unfiltered items is sorted
+ m_pSortByCombo = dynamic_cast< ComboBox * >( FindChildByName( "SortFilterComboBox" ) );
+ if ( m_pSortByCombo )
+ {
+ KeyValues *pUserData = m_pSortByCombo->GetActiveItemUserData();
+ if ( pUserData )
+ {
+ int iSortTypeSelectionIndex = pUserData->GetInt( "sortby", -1 );
+ if ( iSortTypeSelectionIndex >= 0 )
+ {
+ eEconStoreSortType iSortType = (eEconStoreSortType)g_StoreSortTypes[iSortTypeSelectionIndex].iSortType;
+ CEconStorePriceSheet *pPriceSheet = EconUI()->GetStorePanel()->GetPriceSheetForEdit();
+ pPriceSheet->SetEconStoreSortType( iSortType );
+
+ CEconStoreCategoryManager::StoreCategory_t *pPageData = const_cast< CEconStoreCategoryManager::StoreCategory_t * >( m_pPageData );
+ pPageData->m_vecEntries.SetLessContext( pPriceSheet );
+ pPageData->m_vecEntries.RedoSort( true );
+ }
+ }
+ }
+ }
+
+ if ( !IsHomePage() )
+ {
+ BaseClass::UpdateFilteredItems();
+ return;
+ }
+
+ m_FilteredEntries.Purge();
+
+ // Subcategories on the home page are special cases, as they aren't based on
+ // an item's tags.
+ const StoreCategoryID_t unSubcategoryID = m_pPageData->m_vecSubcategories[ m_iCurrentSubcategory ]->m_unID;
+
+ CStorePanel *pStorePanel = EconUI()->GetStorePanel();
+ if ( !pStorePanel )
+ return;
+
+ FOR_EACH_VEC( m_vecItemPanels, idx )
+ {
+ m_vecItemPanels[idx].m_pItemModelPanel->SetShowQuantity( unSubcategoryID != CEconStoreCategoryManager::k_CategoryID_Popular );
+ }
+
+ if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_Popular )
+ {
+ const CUtlVector<uint32>& popularItems = pStorePanel->GetPopularItems();
+ for ( int i = 0; i < MIN( m_vecItemPanels.Count(), popularItems.Count() ); ++i )
+ {
+ const econ_store_entry_t *pEntry = pStorePanel->GetPriceSheet()->GetEntry( popularItems[i] );
+ m_FilteredEntries.AddToTail( pEntry );
+ }
+ }
+ else if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_New )
+ {
+ // Add all new items
+ const CUtlMap< uint16, econ_store_entry_t > &mapEntries = pStorePanel->GetPriceSheet()->GetEntries();
+ FOR_EACH_MAP_FAST( mapEntries, i )
+ {
+ const econ_store_entry_t *pCurEntry = &mapEntries[i];
+ if ( pCurEntry->m_bNew )
+ {
+ m_FilteredEntries.AddToTail( pCurEntry );
+ }
+ }
+ }
+ else if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_OnSale )
+ {
+ ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();
+
+ // Add all entries that are on sale
+ const CEconStorePriceSheet::StoreEntryMap_t &mapEntries = pStorePanel->GetPriceSheet()->GetEntries();
+ FOR_EACH_MAP_FAST( mapEntries, i )
+ {
+ const econ_store_entry_t *pCurEntry = &mapEntries[i];
+
+ if ( pCurEntry->IsOnSale( eCurrency ) )
+ {
+ m_FilteredEntries.AddToTail( pCurEntry );
+ }
+ }
+ }
+ else if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_Featured )
+ {
+ const CEconStorePriceSheet::FeaturedItems_t& vecFeaturedItems = pStorePanel->GetPriceSheet()->GetFeaturedItems();
+ FOR_EACH_VEC( vecFeaturedItems, i )
+ {
+ const econ_store_entry_t *pEntry = pStorePanel->GetPriceSheet()->GetEntry( vecFeaturedItems[i] );
+ if ( pEntry )
+ {
+ m_FilteredEntries.AddToTail( pEntry );
+ }
+ else
+ {
+ AssertMsg( 0, "trying to add featured item that's not in the store price sheet.\n" );
+ }
+ }
+ }
+ else if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_ClassBundles )
+ {
+ // Let's find the class bundles
+ const CEconStorePriceSheet::StoreEntryMap_t &mapEntries = pStorePanel->GetPriceSheet()->GetEntries();
+ FOR_EACH_MAP_FAST( mapEntries, i )
+ {
+ const econ_store_entry_t *pCurEntry = &mapEntries[i];
+
+ if ( pCurEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_ClassBundles ) )
+ {
+ m_FilteredEntries.AddToTail( pCurEntry );
+ }
+ }
+
+ // Sort by date to get the weapon bundles before the keyless crates
+ //extern int ItemNameSortComparator( const econ_store_entry_t *const *ppEntryA, const econ_store_entry_t *const *ppEntryB );
+ extern int FirstSaleDateSortComparator( const econ_store_entry_t *const *ppItemA, const econ_store_entry_t *const *ppItemB );
+
+ m_FilteredEntries.Sort( &FirstSaleDateSortComparator );
+
+ }
+ else if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_Taunts )
+ {
+ const CEconStorePriceSheet::StoreEntryMap_t &mapEntries = pStorePanel->GetPriceSheet()->GetEntries();
+ FOR_EACH_MAP_FAST( mapEntries, i )
+ {
+ const econ_store_entry_t *pCurEntry = &mapEntries[i];
+
+ if ( pCurEntry->IsListedInCategory( CEconStoreCategoryManager::k_CategoryID_Taunts ) )
+ {
+ m_FilteredEntries.AddToTail( pCurEntry );
+ }
+ }
+ }
+ else
+ {
+ AssertMsg( 0, "Subcategory has no defined behavior in code" );
+ }
+
+ // If we're either "New" category or the "On Sale" category or the "Taunts" category, sort our contents
+ // by sale date.
+ if ( unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_New || unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_OnSale || unSubcategoryID == CEconStoreCategoryManager::k_CategoryID_Taunts )
+ {
+ extern int FirstSaleDateSortComparator( const econ_store_entry_t *const *ppItemA, const econ_store_entry_t *const *ppItemB );
+
+ m_FilteredEntries.Sort( &FirstSaleDateSortComparator );
+ }
+
+ m_bFilterDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFStorePage2::DoesEntryFilterPassSecondaryFilter( const econ_store_entry_t *pEntry )
+{
+ if ( !DoesEntryFilterPassSubcategoryFilter( pEntry ) )
+ {
+ return false;
+ }
+
+ if ( m_wNameFilter.Count() > 0 )
+ {
+ CEconItemView itemData;
+ itemData.Init( pEntry->GetItemDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+ itemData.SetClientItemFlags( kEconItemFlagClient_Preview | kEconItemFlagClient_StoreItem );
+ return DoesItemPassSearchFilter( itemData.GetDescription(), m_wNameFilter.Base() );
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFStorePage2::DoesEntryFilterPassSubcategoryFilter( const econ_store_entry_t *pEntry )
+{
+ Assert( pEntry );
+ Assert( m_pPageData );
+
+ // Make sure pages without subcategories can still function
+ if ( !HasSubcategories() )
+ return true;
+
+ // "All subcategories" item selected?
+ if ( m_iCurrentSubcategory == GetAllSubcategoriesIndex() )
+ return true;
+
+ if ( !m_pPageData->m_vecSubcategories.IsValidIndex( m_iCurrentSubcategory ) )
+ return false;
+
+ // Get the subcategory ID
+ const StoreCategoryID_t unSubCategoryID = m_pPageData->m_vecSubcategories[ m_iCurrentSubcategory ]->m_unID;
+
+ // If the store entry is covered by the currently selected category, return true.
+// return pEntry->m_vecTagIds.Find( unSubCategoryID ) != pEntry->m_vecTagIds.InvalidIndex();
+ return pEntry->IsListedInCategory( unSubCategoryID );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::UpdateFilterComboBox( void )
+{
+ BaseClass::UpdateFilterComboBox();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnThink( void )
+{
+ BaseClass::OnThink();
+
+ if ( m_flFilterItemTime && gpGlobals->curtime >= m_flFilterItemTime )
+ {
+ m_bFilterDirty = true;
+ UpdateFilteredItems();
+ UpdateModelPanels();
+ m_flFilterItemTime = 0.0f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CStorePreviewItemPanel *CTFStorePage2::CreatePreviewPanel( void )
+{
+ return new CTFStorePreviewItemPanel2( EconUI()->GetStorePanel(), m_pPreviewItemResFile, "storepreviewitem", this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CStorePricePanel* CTFStorePage2::CreatePricePanel( int iIndex )
+{
+ if ( m_pPageData &&
+ m_pPageData->m_bIsHome &&
+ HasSubcategories() &&
+ m_pPageData->m_vecSubcategories.IsValidIndex( m_iCurrentSubcategory ) &&
+ m_pPageData->m_vecSubcategories[ m_iCurrentSubcategory ]->m_unID == CEconStoreCategoryManager::k_CategoryID_Popular )
+ {
+ return vgui::SETUP_PANEL( new CStorePricePanel_Popular( this, "StorePrice", iIndex + 1 ) );
+ }
+
+ return BaseClass::CreatePricePanel( iIndex );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnAddItemToCart( KeyValues *pData )
+{
+ item_definition_index_t iItemDef = (item_definition_index_t)pData->GetInt( "item_def", INVALID_ITEM_DEF_INDEX );
+
+ AddItemToCartHelper( GetPageName(), iItemDef, (ECartItemType)pData->GetInt( "cart_add_type", kCartItem_Purchase ) );
+ UpdateCart();
+
+ // Turn the free slots indicator red if we can't fit everything.
+ UpdateBackpackLabel();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnItemPanelMouseReleased( vgui::Panel *panel )
+{
+ CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
+ if ( pItemPanel && IsVisible() && pItemPanel->HasItem() )
+ {
+ FOR_EACH_VEC( m_vecItemPanels, i )
+ {
+ if ( m_vecItemPanels[i].m_pItemModelPanel == pItemPanel )
+ {
+ ShowPreviewWindow( m_vecItemPanels[i].m_pItemModelPanel->GetItem()->GetItemDefIndex() );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage2::OnItemPanelMouseDoublePressed( vgui::Panel *panel )
+{
+ // Do nothing
+}
diff --git a/game/client/tf/vgui/store/v2/tf_store_page2.h b/game/client/tf/vgui/store/v2/tf_store_page2.h
new file mode 100644
index 0000000..8c25c92
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_page2.h
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PAGE2_H
+#define TF_STORE_PAGE2_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_page_base.h"
+
+class CNavigationPanel;
+class CClassFilterTooltip;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePage2 : public CTFStorePageBase
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePage2, CTFStorePageBase );
+public:
+ CTFStorePage2( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile = NULL );
+ ~CTFStorePage2();
+
+ virtual void OnPostCreate();
+
+ bool HasSubcategories() const;
+ int GetNumSubcategories() const { return m_pPageData ? m_pPageData->m_vecSubcategories.Count() : 0; }
+
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual const char *GetPageResFile( void );
+ virtual void OnCommand( const char *command );
+
+ MESSAGE_FUNC( OnPageShow, "PageShow" );
+ MESSAGE_FUNC_PTR( OnItemDetails, "ItemDetails", panel );
+ MESSAGE_FUNC_PARAMS( OnItemDefDetails, "ItemDefDetails", pData );
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", pData );
+ MESSAGE_FUNC_PARAMS( OnNavButtonSelected, "NavButtonSelected", pData );
+ MESSAGE_FUNC_PARAMS( OnAddItemToCart, "AddItemToCart", data ); // Comes from preview panel
+ MESSAGE_FUNC_PTR( OnItemPanelMouseDoublePressed, "ItemPanelMouseDoublePressed", panel );
+ MESSAGE_FUNC_PTR( OnItemPanelMouseReleased, "ItemPanelMouseReleased", panel ); // Comes from CStoreItemControlsPanel
+
+ virtual bool DoesEntryFilterPassSecondaryFilter( const econ_store_entry_t *pEntry );
+ bool DoesEntryFilterPassSubcategoryFilter( const econ_store_entry_t *pEntry );
+
+ virtual void UpdateFilteredItems( void );
+ virtual void UpdateFilterComboBox( void );
+ virtual void GetFiltersForDef( GameItemDefinition_t *pDef, CUtlVector<int> *pVecFilters );
+ virtual void OnThink( void );
+ virtual bool FindAndSelectEntry( const econ_store_entry_t *pEntry );
+
+ void ClearNameFilter( bool bUpdateModelPanels );
+
+ virtual CStorePreviewItemPanel *CreatePreviewPanel( void );
+ virtual CStorePricePanel* CreatePricePanel( int iIndex );
+
+ void ShowPreviewWindow( item_definition_index_t usDefIndex );
+ int GetAllSubcategoriesIndex() const;
+
+ vgui::TextEntry *m_pNameFilterTextEntry;
+ CExLabel *m_pSubcategoriesFilterLabel;
+ vgui::ComboBox *m_pSubcategoriesFilterCombo;
+ vgui::ComboBox *m_pSortByCombo;
+ CNavigationPanel *m_pHomeCategoryTabs;
+ CNavigationPanel *m_pClassFilterButtons;
+ CExLabel *m_pClassFilterTooltipLabel;
+ CClassFilterTooltip *m_pClassFilterTooltip;
+
+ int m_iCurrentSubcategory;
+ CUtlVector<wchar_t> m_wNameFilter;
+ float m_flFilterItemTime;
+
+ friend class CClassFilterTooltip;
+};
+
+#endif // TF_STORE_PAGE2_H
diff --git a/game/client/tf/vgui/store/v2/tf_store_page_maps2.cpp b/game/client/tf/vgui/store/v2/tf_store_page_maps2.cpp
new file mode 100644
index 0000000..3fb0ccd
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_page_maps2.cpp
@@ -0,0 +1,59 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v2/tf_store_page_maps2.h"
+#include "store/v2/tf_store_mapstamps_info_dialog.h"
+#include "store/store_panel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePage_Maps2::CTFStorePage_Maps2( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData )
+: BaseClass( parent, pPageData, "Resource/UI/econ/store/v2/StorePreviewItemPanel_Maps.res" )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage_Maps2::OnPageShow()
+{
+ BaseClass::OnPageShow();
+
+ SetDetailsVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage_Maps2::OnCommand( const char *command )
+{
+ if ( !V_strnicmp( command, "maps_learnmore", 14 ) )
+ {
+ DisplayMapStampsDialog();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePage_Maps2::DisplayMapStampsDialog()
+{
+ CTFMapStampsInfoDialog *pDlg = vgui::SETUP_PANEL( new CTFMapStampsInfoDialog( EconUI()->GetStorePanel() ) );
+ pDlg->SetVisible( true );
+ pDlg->InvalidateLayout( true, true );
+ pDlg->SetKeyBoardInputEnabled(true);
+ pDlg->SetMouseInputEnabled(true);
+}
diff --git a/game/client/tf/vgui/store/v2/tf_store_page_maps2.h b/game/client/tf/vgui/store/v2/tf_store_page_maps2.h
new file mode 100644
index 0000000..567ea5d
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_page_maps2.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef STORE_PAGE_MAPS2_H
+#define STORE_PAGE_MAPS2_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/v2/tf_store_page2.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePage_Maps2 : public CTFStorePage2
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePage_Maps2, CTFStorePage2 );
+public:
+ CTFStorePage_Maps2( Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData );
+ virtual ~CTFStorePage_Maps2() {}
+
+ virtual const char* GetPageResFile() { return "Resource/UI/econ/store/v2/StorePage_Maps.res"; }
+
+protected:
+ virtual void OnCommand( const char *command );
+ virtual void OnPageShow( void );
+
+ void DisplayMapStampsDialog();
+};
+
+#endif // STORE_PAGE_MAPS2_H
diff --git a/game/client/tf/vgui/store/v2/tf_store_panel2.cpp b/game/client/tf/vgui/store/v2/tf_store_panel2.cpp
new file mode 100644
index 0000000..89fa857
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_panel2.cpp
@@ -0,0 +1,109 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v2/tf_store_panel2.h"
+#include "store/v2/tf_store_page2.h"
+#include "store/v2/tf_store_page_maps2.h"
+#include "store/store_page_halloween.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePanel2::CTFStorePanel2( vgui::Panel *parent ) : CTFBaseStorePanel(parent)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel2::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel2::ShowPanel( bool bShow )
+{
+ BaseClass::ShowPanel( bShow );
+
+ // Base class should turn this on
+ if ( bShow && m_bOGSLogging )
+ {
+ EconUI()->Gamestats_Store( IE_STORE2_ENTERED );
+ }
+
+ Panel *pCheckOutButton = FindChildByName( "CheckOutButton" );
+ if ( pCheckOutButton )
+ {
+ pCheckOutButton->RequestFocus();
+ }
+}
+
+void CTFStorePanel2::OnAddToCart( void )
+{
+ Panel *pCheckOutButton = FindChildByName( "CheckOutButton" );
+ if ( pCheckOutButton )
+ {
+ pCheckOutButton->RequestFocus();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel2::OnThink()
+{
+ BaseClass::OnThink();
+}
+
+void CTFStorePanel2::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // ESC cancels
+ if ( code == KEY_XBUTTON_B )
+ {
+ OnCommand( "close" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePanel2::PostTransactionCompleted( void )
+{
+ BaseClass::PostTransactionCompleted();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Static store page factory.
+//-----------------------------------------------------------------------------
+CStorePage *CTFStorePanel2::CreateStorePage( const CEconStoreCategoryManager::StoreCategory_t *pPageData )
+{
+ if ( pPageData )
+ {
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_SpecialPromo" ) )
+ return new CTFStorePage_SpecialPromo( this, pPageData );
+
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_Maps" ) )
+ return new CTFStorePage_Maps2( this, pPageData );
+
+ if ( !Q_strcmp( pPageData->m_pchPageClass, "CStorePage_Popular" ) )
+ return new CTFStorePage_Popular( this, pPageData );
+ }
+
+ // Default, standard store page.
+ return new CTFStorePage2( this, pPageData );
+}
diff --git a/game/client/tf/vgui/store/v2/tf_store_panel2.h b/game/client/tf/vgui/store/v2/tf_store_panel2.h
new file mode 100644
index 0000000..4364706
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_panel2.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PANEL2_H
+#define TF_STORE_PANEL2_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_panel_base.h"
+
+class CStorePage;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePanel2 : public CTFBaseStorePanel
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePanel2, CTFBaseStorePanel );
+public:
+ CTFStorePanel2( vgui::Panel *parent );
+
+ // UI Layout
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnThink();
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void ShowPanel( bool bShow );
+ virtual void OnAddToCart( void );
+
+ // GC Management
+ virtual void PostTransactionCompleted( void );
+
+private:
+ virtual CStorePage *CreateStorePage( const CEconStoreCategoryManager::StoreCategory_t *pPageData );
+};
+
+#endif // TF_STORE_PANEL2_H
diff --git a/game/client/tf/vgui/store/v2/tf_store_preview_item2.cpp b/game/client/tf/vgui/store/v2/tf_store_preview_item2.cpp
new file mode 100644
index 0000000..c213e10
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_preview_item2.cpp
@@ -0,0 +1,1367 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "store/v2/tf_store_preview_item2.h"
+#include "econ_item_description.h"
+#include "vgui_controls/TextImage.h"
+#include "vgui_controls/ScrollBar.h"
+#include "vgui_controls/ScrollBarSlider.h"
+#include "vgui/IInput.h"
+#include "tf_item_schema.h"
+#include "econ_item_system.h"
+#include "store/store_panel.h"
+#include "c_tf_gamestats.h"
+#include "tf_playermodelpanel.h"
+#include "navigationpanel.h"
+#include "tf_mouseforwardingpanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+inline float LerpScale( float flIn, float flInMin, float flInMax, float flOutMin, float flOutMax )
+{
+ float flDenom = flInMax - flInMin;
+ if ( flDenom == 0.0f )
+ return 0.0f;
+
+ float t = clamp( ( flIn - flInMin ) / flDenom, 0.0f, 1.0f );
+ return Lerp( t, flOutMin, flOutMax );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+inline float SCurve( float t )
+{
+ t = clamp( t, 0.0f, 1.0f );
+ return t * t * (3 - 2*t);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CFullscreenStorePreviewItem::CFullscreenStorePreviewItem( vgui::Panel *pParent, EditablePanel *pOwner )
+: BaseClass( pParent, "FullscreenStorePreview" ),
+ m_iItemDef( INVALID_ITEM_ID ),
+ m_pCycleTextLabel( NULL ),
+ m_pTeamNavPanel( NULL ),
+ m_pPreviewButton( NULL ),
+ m_pRotLeftButton( NULL ),
+ m_pRotRightButton( NULL ),
+ m_pZoomButton( NULL ),
+ m_pOverlayPanel( NULL ),
+ m_flGoFullscreenStartTime( 0.0f ),
+ m_flLastMouseMoveTime( 0.0f ),
+ m_bIsHalloweenOrFullmoonOnlyItem( false )
+{
+ m_hOwner = pOwner;
+}
+
+void CFullscreenStorePreviewItem::SetItemDef( itemid_t iItemDef )
+{
+ m_iItemDef = iItemDef;
+
+ CStorePanel *pStorePanel = EconUI()->GetStorePanel();
+ if ( pStorePanel )
+ {
+ const CEconStorePriceSheet *pPriceSheet = pStorePanel->GetPriceSheet();
+ CExButton *pPreviewButton = dynamic_cast<CExButton *>( FindChildByName( "TryItOutButton" ) );
+ if ( pPriceSheet && pPreviewButton )
+ {
+ const econ_store_entry_t *pStoreEntry = pPriceSheet->GetEntry( m_iItemDef );
+ pPreviewButton->SetVisible( pStoreEntry && pStoreEntry->CanPreview() );
+ }
+ }
+}
+
+void CFullscreenStorePreviewItem::GoFullscreen( CTFPlayerModelPanel *pPlayerModelPanel )
+{
+ m_Stats.Clear();
+
+ m_flGoFullscreenStartTime = gpGlobals->realtime;
+
+ SetAlpha( 0 );
+ SetVisible( true );
+ MoveToFront();
+
+ m_pPlayerModelPanel = pPlayerModelPanel;
+
+ if ( !m_pPlayerModelPanel.Get() )
+ return;
+
+ // Cache old player model panel bounds and such
+ m_pPlayerModelPanel->GetBounds( m_OldModelState.m_aPlayerModelPanelBounds[0], m_OldModelState.m_aPlayerModelPanelBounds[1], m_OldModelState.m_aPlayerModelPanelBounds[2], m_OldModelState.m_aPlayerModelPanelBounds[3] );
+ m_OldModelState.m_vecPlayerPos = m_pPlayerModelPanel->m_vecPlayerPos;
+ m_OldModelState.m_bZoomed = m_pPlayerModelPanel->IsZoomed();
+
+ // Fullscreen panel is new parent
+ m_pPlayerModelPanel->SetParent( this );
+
+ // Get team state
+ if ( m_pTeamNavPanel )
+ {
+ m_pTeamNavPanel->UpdateButtonSelectionStates( m_pPlayerModelPanel->GetTeam() == TF_TEAM_RED ? 0 : 1 );
+ }
+}
+
+void CFullscreenStorePreviewItem::ExitFullscreen()
+{
+ if ( !m_hOwner.Get() )
+ return;
+
+ if ( m_pPlayerModelPanel.Get() )
+ {
+ m_pPlayerModelPanel->SetParent( m_hOwner.Get() );
+ m_pPlayerModelPanel->SetBounds( m_OldModelState.m_aPlayerModelPanelBounds[0], m_OldModelState.m_aPlayerModelPanelBounds[1], m_OldModelState.m_aPlayerModelPanelBounds[2], m_OldModelState.m_aPlayerModelPanelBounds[3] );
+
+ // Reset the player position to it's pre-fullscreen location, but add on any zoom delta if needed.
+ const Vector vecZoomOffset = m_OldModelState.m_bZoomed != m_pPlayerModelPanel->IsZoomed() ? m_pPlayerModelPanel->GetZoomOffset() : vec3_origin;
+ m_pPlayerModelPanel->m_vecPlayerPos = m_OldModelState.m_vecPlayerPos + vecZoomOffset;
+ }
+
+ m_flGoFullscreenStartTime = 0.0f;
+ SetVisible( false );
+
+ PostMessage( m_hOwner.Get(), new KeyValues( "ExitFullscreen" ) );
+}
+
+bool CFullscreenStorePreviewItem::IsFullscreenMode()
+{
+ return IsVisible();
+}
+
+void CFullscreenStorePreviewItem::OnNavButtonSelected( KeyValues *pData )
+{
+ const int iTeam = pData->GetInt( "userdata", -1 ); AssertMsg( iTeam >= 0, "Bad filter" );
+ if ( iTeam < 0 )
+ return;
+
+ if ( !m_pPlayerModelPanel.Get() )
+ return;
+
+ m_pPlayerModelPanel->SetTeam( iTeam );
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "team_switch_%s(store_preview_item_panel_fullscreen)", iTeam == TF_TEAM_RED ? "red" : "blu" );
+}
+
+void CFullscreenStorePreviewItem::OnThink()
+{
+ BaseClass::OnThink();
+
+ if ( m_flGoFullscreenStartTime == 0.0f )
+ {
+ SetVisible( false );
+ return;
+ }
+
+ // We are fading, or already faded in
+ SetVisible( true );
+
+ // Keep track of mouse movement - if the mouse button is down, force the mouse-moving state so we
+ // don't end up fading out while the player is rotating or clicking-and-holding anywhere else
+ int nMouseX, nMouseY;
+ vgui::input()->GetCursorPos( nMouseX, nMouseY );
+ bool bMouseMoved = false;
+ const bool bMouseButtonDown = vgui::input()->IsMouseDown( MOUSE_LEFT );
+ const bool bForceMouseMoving = bMouseButtonDown;
+ if ( bForceMouseMoving || nMouseX != m_nLastMouseX || nMouseY != m_nLastMouseY )
+ {
+ bMouseMoved = true;
+ m_nLastMouseX = nMouseX;
+ m_nLastMouseY = nMouseY;
+ m_flLastMouseMoveTime = gpGlobals->realtime;
+ }
+
+ // Fade in the button blocker if the mouse has been idle for some period of time
+ if ( m_pOverlayPanel )
+ {
+ const float flButtonBlockerFade = SCurve(
+ LerpScale(
+ gpGlobals->realtime,
+ m_flLastMouseMoveTime + m_flUiFadeoutTime,
+ m_flLastMouseMoveTime + m_flUiFadeoutTime + m_flUiFadeoutDuration,
+ 0.0f,
+ 1.0f
+ )
+ );
+
+ m_pOverlayPanel->SetVisible( flButtonBlockerFade > 0.0f );
+
+ m_pOverlayPanel->SetAlpha( (int)( 255 * flButtonBlockerFade ) );
+
+ // Set to layer above overlay panel, so it will always be visible
+ m_pPlayerModelPanel->SetZPos( flButtonBlockerFade > 0.0f ? ( m_pOverlayPanel->GetZPos() + 1 ) : 0 );
+ }
+
+ const float flFade = SCurve(
+ LerpScale(
+ gpGlobals->realtime,
+ m_flGoFullscreenStartTime,
+ m_flGoFullscreenStartTime + m_flFullscreenFadeToBlackDuration,
+ 0.0f,
+ 1.0f
+ )
+ );
+
+ SetAlpha( (int)( 255 * flFade ) );
+
+ if ( !m_pPlayerModelPanel.Get() )
+ return;
+
+ // Resize 3D model panel
+ const int aDstBounds[4] = { 0, 0, ScreenWidth(), ScreenHeight() };
+ const int aBounds[4] = {
+ Lerp( flFade, m_OldModelState.m_aPlayerModelPanelBounds[0], aDstBounds[0] ),
+ Lerp( flFade, m_OldModelState.m_aPlayerModelPanelBounds[1], aDstBounds[1] ),
+ Lerp( flFade, m_OldModelState.m_aPlayerModelPanelBounds[2], aDstBounds[2] ),
+ Lerp( flFade, m_OldModelState.m_aPlayerModelPanelBounds[3], aDstBounds[3] )
+ };
+ m_pPlayerModelPanel->SetBounds( aBounds[0], aBounds[1], aBounds[2], aBounds[3] );
+
+ if ( flFade < 0.999f )
+ {
+ const Vector vecZoomOffset = m_pPlayerModelPanel->IsZoomed() ? m_pPlayerModelPanel->GetZoomOffset() : vec3_origin;
+ const Vector vecFullscreenOrigin( m_flModelPanelOriginX, m_flModelPanelOriginY, m_flModelPanelOriginZ );
+ m_pPlayerModelPanel->m_vecPlayerPos = Lerp( flFade, m_OldModelState.m_vecPlayerPos, vecFullscreenOrigin + vecZoomOffset );
+ }
+
+ if ( m_pZoomButton )
+ {
+ m_pZoomButton->SetEnabled( flFade == 1.0f );
+ }
+
+ if ( bMouseButtonDown && m_pRotLeftButton && m_pRotRightButton )
+ {
+ float flDeltaAngle = 0;
+ const float kScale = 100.0f;
+ if ( m_pRotLeftButton->IsWithin( nMouseX, nMouseY ) )
+ {
+ flDeltaAngle = -gpGlobals->frametime * kScale;
+ }
+ else if ( m_pRotRightButton->IsWithin( nMouseX, nMouseY ) )
+ {
+ flDeltaAngle = gpGlobals->frametime * kScale;
+ }
+
+ m_pPlayerModelPanel->RotateYaw( flDeltaAngle );
+
+ // Accumulate time rotation buttons are being pressed for stat tracking
+ m_Stats.m_flRotationTime += gpGlobals->frametime;
+ }
+}
+
+void CFullscreenStorePreviewItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "Resource/UI/econ/store/v2/StorePreviewItemPanel_Fullscreen.res" );
+
+ m_pOverlayPanel = dynamic_cast<EditablePanel *>( FindChildByName( "OverlayPanel" ) );
+ m_pRotLeftButton = dynamic_cast<CExButton *>( FindChildByName( "RotateLeftButton" ) );
+ m_pRotRightButton = dynamic_cast<CExButton *>( FindChildByName( "RotateRightButton" ) );
+ m_pZoomButton = dynamic_cast<CExButton *>( FindChildByName( "ZoomButton" ) );
+ m_pTeamNavPanel = dynamic_cast<CNavigationPanel *>( FindChildByName( "TeamNavPanel" ) );
+}
+
+void CFullscreenStorePreviewItem::OnCommand( const char *command )
+{
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "on_command(store_preview_item_panel_fullscreen)", command );
+
+ if ( !V_strnicmp( command, "close", 6 ) )
+ {
+ ExitFullscreen();
+ return;
+ }
+
+ if ( m_hOwner.Get() )
+ {
+ // Let the owner handle the command
+ m_hOwner->OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFStorePreviewItemPanel2::CTFStorePreviewItemPanel2( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner )
+: BaseClass( pParent, pResFile, "storepreviewitem", pOwner )
+{
+ m_pScrollBar = new ScrollBar( this, "ScrollBar", true );
+ m_pScrollBar->AddActionSignalTarget( this );
+
+ m_pFullscreenPanel = new CFullscreenStorePreviewItem( this, this );
+ m_pFullscreenPanel->AddActionSignalTarget( this );
+
+ m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) );
+ m_pMouseOverTooltip = new CItemModelPanelToolTip( this );
+ m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel );
+ m_pMouseOverTooltip->SetPositioningStrategy( IPTTP_BOTTOM_SIDE );
+ m_pMouseOverItemPanel->MoveToFront();
+
+ m_pItemViewData = NULL;
+ m_pSOEconItemData = NULL;
+ Clear();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::Clear()
+{
+ m_pPlayerModelPanel = NULL;
+
+ m_pPreviewButton = NULL;
+ m_pDialogFrame = NULL;
+ m_pPreviewViewportBg = NULL;
+ m_pItemNameLabel = NULL;
+ m_pAttributesLabel = NULL;
+ m_pItemCollectionHighlight = NULL;
+ m_pDetailsView = NULL;
+ m_pDetailsViewChild = NULL; // Scrollable
+ m_pItemWikiPageButton = NULL;
+ m_pTeamNavPanel = NULL;
+ m_pCycleTextLabel = NULL;
+ m_pScrollableChild = NULL;
+ m_pGoFullscreenButton = NULL;
+ m_nNumAttribLinesAdded = 0;
+ m_bArmoryTextAdded = false;
+ m_nNumAttribLinesAdded = 0;
+ m_iSliderPos = 0;
+ m_aClickPos[0] = m_aClickPos[1] = 0;
+ m_bCloseOnUp = false;
+ m_bMouseWasDown = false;
+ m_bIsHalloweenOrFullmoonOnlyItem = false;
+
+ for ( int i = 0; i < ARRAYSIZE( m_pAddRentalToCartButtons ); i++ )
+ {
+ m_pAddRentalToCartButtons[i] = NULL;
+ }
+
+ m_vecReferenceItemPanels.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ Clear();
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ // Strip tooltips.
+ // We have all the same data already
+ m_pItemIcons[i]->GetItemPanel()->SetTooltip( NULL, NULL );
+ }
+
+ m_pDialogFrame = dynamic_cast<EditablePanel *>( FindChildByName( "DialogFrame" ) );
+ m_pPreviewButton = dynamic_cast<CExButton *>( FindChildByName( "TryItOutButton" ) );
+ m_pCycleTextLabel = dynamic_cast<CExLabel *>( FindChildByName( "CycleTextLabel" ) );
+ m_pGoFullscreenButton = dynamic_cast<CExImageButton *>( FindChildByName( "GoFullscreenButton" ) );
+
+ COMPILE_TIME_ASSERT( ARRAYSIZE( m_pAddRentalToCartButtons ) == 3 );
+#ifdef ENABLE_STORE_RENTAL_BACKEND
+ m_pAddRentalToCartButtons[0] = dynamic_cast<CExButton *>( FindChildByName( "AddRentalToCartButton_1Day" ) );
+ m_pAddRentalToCartButtons[1] = dynamic_cast<CExButton *>( FindChildByName( "AddRentalToCartButton_3Day" ) );
+ m_pAddRentalToCartButtons[2] = dynamic_cast<CExButton *>( FindChildByName( "AddRentalToCartButton_7Day" ) );
+#endif
+
+ if ( m_pDialogFrame )
+ {
+ m_pPreviewViewportBg = dynamic_cast<EditablePanel *>( m_pDialogFrame->FindChildByName( "PreviewViewportBg" ) );
+ m_pItemNameLabel = dynamic_cast<CExLabel *>( m_pDialogFrame->FindChildByName( "ItemNameLabel" ) );
+ m_pDetailsView = dynamic_cast<EditablePanel *>( m_pDialogFrame->FindChildByName( "DetailsView" ) );
+
+ if ( m_pDetailsView )
+ {
+ m_pDetailsViewChild = dynamic_cast<EditablePanel *>( m_pDetailsView->FindChildByName( "ScrollableChild" ) );
+
+ if ( !m_pDetailsViewChild )
+ {
+ m_pDetailsViewChild = m_pDetailsView;
+ }
+
+ m_pAttributesLabel = dynamic_cast<CExLabel *>( m_pDetailsViewChild->FindChildByName( "AttributesLabel" ) );
+ m_pItemCollectionHighlight = dynamic_cast<EditablePanel *>( m_pDetailsViewChild->FindChildByName( "collectionhighlight" ) );
+ if ( m_pItemCollectionHighlight )
+ {
+ m_pItemCollectionHighlight->InvalidateLayout( true, true );
+ }
+ m_pItemWikiPageButton = dynamic_cast<CExButton *>( m_pDetailsViewChild->FindChildByName( "ItemWikiPageButton" ) );
+
+ if ( m_pItemWikiPageButton )
+ {
+ m_pItemWikiPageButton->AddActionSignalTarget( this );
+ }
+ }
+ }
+
+ m_pTeamNavPanel = dynamic_cast<CNavigationPanel *>( FindChildByName( "TeamNavPanel" ) );
+
+ m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") );
+
+ SetState( PS_ITEM );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given two controls A and B, place B such that it is (nXOffset,nYOffset)
+// pixels offset from A, using it's content width or height, depending on bVertical.
+// pControlNameA can be NULL, in which case zeros will be used as the offset.
+//-----------------------------------------------------------------------------
+int CTFStorePreviewItemPanel2::PlaceControl( Panel *pParent, const char *pControlNameA, const char *pControlNameB, int nOffset, bool bVertical, bool bSizeAToContents/*=true*/, bool bUseContentSize/*=true*/ )
+{
+ if ( !pParent || !pControlNameB )
+ {
+ AssertMsg( 0, "Bad!" );
+ return 0;
+ }
+
+ Label *pControlA = pControlNameA ? dynamic_cast<Label *>( pParent->FindChildByName( pControlNameA ) ) : NULL;
+ Label *pControlB = dynamic_cast<Label *>( pParent->FindChildByName( pControlNameB ) );
+ if ( !pControlB )
+ {
+ return 0;
+ }
+
+ if ( !pControlA && bVertical )
+ {
+ pControlA = m_pLastNewLineControl;
+ }
+
+ int aSize[2] = { 0, 0 };
+ int aPos[2] = { 0, 0 };
+ if ( pControlA )
+ {
+ pControlA->SetVisible( true );
+
+ if ( bSizeAToContents )
+ {
+ pControlA->SizeToContents();
+ pControlA->InvalidateLayout( true );
+ }
+
+ if ( bUseContentSize )
+ {
+ pControlA->GetContentSize( aSize[0], aSize[1] );
+ }
+ else
+ {
+ pControlA->GetSize( aSize[0], aSize[1] );
+ }
+
+ pControlA->GetPos( aPos[0], aPos[1] );
+ }
+
+ int aOffset[2] = { 0, 0 };
+ if ( bVertical )
+ {
+ aOffset[1] = aSize[1] + nOffset;
+ }
+ else
+ {
+ aOffset[0] = aSize[0] + nOffset;
+ }
+
+ // NOTE: We add in the slider position here
+ pControlB->SetPos( aPos[0] + aOffset[0], aPos[1] + aOffset[1] );
+
+ pControlB->SetVisible( true );
+
+#if _DEBUG
+ /*
+ Msg( "control A: %s size: w=%i h=%i pos: (%i, %i)\n", pControlNameA, aSize[0], aSize[1], aPos[0], aPos[1] );
+ int x,y;
+ pControlB->GetPos(x,y);
+ Msg( "control B: %s pos: (%i, %i)\n", pControlNameB, x,y );
+ */
+#endif
+
+ if ( bVertical )
+ {
+ m_pLastNewLineControl = pControlB;
+ }
+
+ m_nViewMaxHeight = MAX( m_nViewMaxHeight, aPos[1] + aOffset[1] + pControlB->GetTall() );
+ return m_nViewMaxHeight;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::PerformLayout( void )
+{
+// BaseClass::PerformLayout(); // We override completely here
+
+ // center the icons (we need to redo some of the work of CStorePreviewItemPanel, because we
+ // center the base item icons along with our TF specific class ones)
+ int iNumItemIcons = 0;
+ FOR_EACH_VEC( m_pItemIcons, i )
+ {
+ if ( m_pItemIcons[i]->IsVisible() )
+ {
+ ++iNumItemIcons;
+ }
+ }
+
+ int iNumClassIcons = 0;
+ FOR_EACH_VEC( m_pClassIcons, i )
+ {
+ if ( m_pClassIcons[i]->IsVisible() )
+ {
+ ++iNumClassIcons;
+ }
+ }
+
+ if ( m_pDialogFrame && ( iNumItemIcons || iNumClassIcons ) )
+ {
+ int aDialogFramePos[2];
+ m_pDialogFrame->GetPos( aDialogFramePos[0], aDialogFramePos[1] );
+
+ int iCenterX = aDialogFramePos[0] + m_pDialogFrame->GetWide() / 4;
+ int interval = XRES(2);
+ int totalWidth = (iNumItemIcons > 0 ? iNumItemIcons * m_pItemIcons[0]->GetWide() : 0) + (iNumClassIcons * m_pClassIcons[0]->GetWide()) + (interval * (iNumItemIcons + iNumClassIcons - 1));
+ int iX = iCenterX - ( totalWidth / 2 );
+
+ int posX, posY;
+ if ( iNumItemIcons > 0 )
+ {
+ m_pItemIcons[0]->GetPos( posX, posY );
+ }
+ else
+ {
+ m_pClassIcons[0]->GetPos( posX, posY );
+ }
+
+ int iButton = 0;
+ for ( int i = 0; i < m_pItemIcons.Count(); i++ )
+ {
+ if ( m_pItemIcons[i]->IsVisible() )
+ {
+ m_pItemIcons[i]->SetPos( iX, posY );
+ iX += m_pItemIcons[i]->GetWide() + interval;
+
+ iButton++;
+ }
+ }
+
+ for ( int i = 0; i < m_pClassIcons.Count(); i++ )
+ {
+ if ( m_pClassIcons[i]->IsVisible() )
+ {
+ m_pClassIcons[i]->SetPos( iX, posY );
+ iX += m_pClassIcons[i]->GetWide() + interval;
+
+ iButton++;
+ }
+ }
+ }
+
+ if ( !m_pPreviewViewportBg || !m_pItemNameLabel || !m_pDetailsViewChild || !m_pDetailsView || !m_pDialogFrame )
+ {
+ m_pScrollBar->SetVisible( false );
+ return;
+ }
+
+ // Make sure we size the item name in case it needs multiple lines.
+ m_pItemNameLabel->SizeToContents();
+ m_pItemNameLabel->InvalidateLayout( true );
+ if ( m_pItemNameLabel && m_item.IsValid() )
+ {
+ const CEconItemRarityDefinition* pItemRarity = GetItemSchema()->GetRarityDefinition( m_item.GetItemDefinition()->GetRarity() );
+
+ // Setup the rarity color overlay
+ {
+ Color color( 255, 255, 255, 255 );
+ if ( pItemRarity )
+ {
+ attrib_colors_t attribColor = pItemRarity->GetAttribColor();
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ color = pScheme->GetColor( GetColorNameForAttribColor( attribColor ), Color( 255, 255, 255, 255 ) );
+ }
+ m_pItemNameLabel->SetColorStr( color );
+ }
+ }
+
+ int aItemNameLabelPos[2];
+ m_pItemNameLabel->GetPos( aItemNameLabelPos[0], aItemNameLabelPos[1] );
+
+ // This is the item label's new bottom y coordinate after it's been sized
+ const int nNewYRelativeToDlgFrame = aItemNameLabelPos[1] + m_pItemNameLabel->GetTall();
+
+ // Set ypos for details view and scroll bar
+ int aDetailsViewPos[2];
+ m_pDetailsView->GetPos( aDetailsViewPos[0], aDetailsViewPos[1] );
+ m_pDetailsView->SetPos( aDetailsViewPos[0], nNewYRelativeToDlgFrame );
+
+ int aDialogFramePos[2];
+ m_pDialogFrame->GetPos( aDialogFramePos[0], aDialogFramePos[1] );
+
+ if ( m_pScrollBar )
+ {
+ int aScrollBar[2];
+ m_pScrollBar->GetPos( aScrollBar[0], aScrollBar[1] );
+ m_pScrollBar->SetPos( aScrollBar[0], nNewYRelativeToDlgFrame + aDialogFramePos[1] );
+ }
+
+ int nNewHeight = m_pPreviewViewportBg->GetTall() - m_pItemNameLabel->GetTall();
+ m_pDetailsView->SetTall( nNewHeight );
+ if ( m_pScrollBar )
+ {
+ m_pScrollBar->SetTall( nNewHeight );
+ }
+
+ // Place paint and style buttons
+ CUtlVector<CExButton *> vecVisibleButtons;
+ const int nNumPossibilyVisibleWeapons = 1;
+ CExButton *pPossiblyVisibleButtons[nNumPossibilyVisibleWeapons] = { m_pNextWeaponButton };
+ for ( int i = 0; i < nNumPossibilyVisibleWeapons; ++i )
+ {
+ CExButton *pCurButton = pPossiblyVisibleButtons[i];
+ if ( !pCurButton || !pCurButton->IsVisible() )
+ continue;
+
+ vecVisibleButtons.AddToTail( pCurButton );
+ }
+
+ int nNumButtonsNeeded = vecVisibleButtons.Count();
+ if ( nNumButtonsNeeded )
+ {
+ // Center however many buttons we need to along the top of the viewport
+ int aViewportPos[2];
+ m_pPreviewViewportBg->GetPos( aViewportPos[0], aViewportPos[1] );
+ for ( int i = 0; i < nNumButtonsNeeded; ++i )
+ {
+ CExButton *pCurButton = vecVisibleButtons[i];
+ pCurButton->SetPos( aDialogFramePos[0] + aViewportPos[0] + ( i + 1 ) * m_pPreviewViewportBg->GetWide() / ( nNumButtonsNeeded + 1 ) - m_iControlButtonWidth / 2, m_iControlButtonY );
+ pCurButton->SetSize( m_iControlButtonWidth, m_iControlButtonHeight );
+ }
+ }
+
+ m_pLastNewLineControl = NULL;
+ m_nViewMaxHeight = 0;
+
+ PlaceControl( m_pDetailsViewChild, NULL, "ItemLevelInfoLabel", m_iSmallVerticalBreakSize, true );
+
+ if ( m_bIsHalloweenOrFullmoonOnlyItem )
+ {
+ PlaceControl( m_pDetailsViewChild, "ItemLevelInfoLabel", "RestrictionsLabel", m_iMediumVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "RestrictionsLabel", "RestrictionsTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "RestrictionsLabel", "UsedByLabel", m_iSmallVerticalBreakSize, true );
+ }
+ else
+ {
+ PlaceControl( m_pDetailsViewChild, "ItemLevelInfoLabel", "UsedByLabel", m_iMediumVerticalBreakSize, true );
+ }
+
+ PlaceControl( m_pDetailsViewChild, "UsedByLabel", "UsedByTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "UsedByLabel", "SlotLabel", m_iSmallVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "SlotLabel", "SlotTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "SlotLabel", "PriceLabel", m_iBigVerticalBreakSize, true );
+
+ if ( m_bArmoryTextAdded )
+ {
+ PlaceControl( m_pDetailsViewChild, "PriceLabel", "ArmoryTextLabel", m_iBigVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "ArmoryTextLabel", "AttributesLabel", m_iBigVerticalBreakSize, true );
+ }
+ else
+ {
+ PlaceControl( m_pDetailsViewChild, "PriceLabel", "AttributesLabel", m_iBigVerticalBreakSize, true );
+ }
+
+ PlaceControl( m_pDetailsViewChild, m_nNumAttribLinesAdded == 0 ? "PriceLabel" : "AttributesLabel", "ItemWikiPageButton", m_iBigVerticalBreakSize, true );
+
+ PlaceControl( m_pDetailsViewChild, "ItemWikiPageButton", "TradableLabel", m_iBigVerticalBreakSize, true, false, false );
+ PlaceControl( m_pDetailsViewChild, "TradableLabel", "TradableTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "TradableLabel", "CraftableLabel", m_iSmallVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "CraftableLabel", "CraftableTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "CraftableLabel", "GiftableLabel", m_iSmallVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "GiftableLabel", "GiftableTextLabel", m_iHorizontalBreakSize, false );
+ PlaceControl( m_pDetailsViewChild, "GiftableLabel", "NameableLabel", m_iSmallVerticalBreakSize, true );
+ PlaceControl( m_pDetailsViewChild, "NameableLabel", "NameableTextLabel", m_iHorizontalBreakSize, false );
+
+ if ( m_pScrollBar )
+ {
+ m_pScrollBar->SetVisible( true );
+ m_pScrollBar->InvalidateLayout( true );
+ m_pScrollBar->SetRange( 0, m_nViewMaxHeight );
+ m_pScrollBar->SetRangeWindow( m_pScrollBar->GetTall() );
+
+ m_pDetailsViewChild->SetTall( m_nViewMaxHeight );
+ UpdateScrollableChild();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::UpdateScrollableChild()
+{
+ m_pDetailsViewChild->SetPos( 0, -m_iSliderPos );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnCommand( const char *command )
+{
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "on_command(store_preview_item_panel)", command );
+
+ if ( !V_strnicmp( command, "closex", 5 ) )
+ {
+ // This is just a way for us to differentiate between 'x' button being pressed vs.
+ // the "back" button vs. clicking outside the preview window.
+ DoClose();
+ }
+ else if ( !V_strnicmp( command, "tryitout", 8 ) )
+ {
+ // OGS data gets written elsewhere for this event
+ PostMessage( m_pOwner, new KeyValues( "PreviewItem", "item_def_index", m_item.GetItemDefIndex() ) );
+ DoClose();
+ }
+ else if ( !V_strnicmp( command, "addtocart", 9 )
+#ifdef ENABLE_STORE_RENTAL_BACKEND
+ || !V_strnicmp( command, "addrentaltocart", 15 )
+#endif
+ )
+ {
+#ifdef ENABLE_STORE_RENTAL_BACKEND
+ ECartItemType eCartItemType = !V_stricmp( command, "addrentaltocart_1day" )
+ ? kCartItem_Rental_1Day
+ : !V_stricmp( command, "addrentaltocart_3day" )
+ ? kCartItem_Rental_3Day
+ : !V_stricmp( command, "addrentaltocart_7day" )
+ ? kCartItem_Rental_7Day
+ : kCartItem_Purchase;
+#else
+ ECartItemType eCartItemType = kCartItem_Purchase;
+#endif
+
+ KeyValues *pParams = new KeyValues( "AddItemToCart" );
+ pParams->SetInt( "item_def", m_item.GetItemDefIndex() );
+ pParams->SetInt( "cart_add_type", eCartItemType );
+ PostMessage( m_pOwner, pParams );
+ DoClose();
+ }
+ else if ( !V_strnicmp( command, "viewwikipage", 12 ) )
+ {
+ if ( steamapicontext && steamapicontext->SteamFriends() && m_pItemFullImage )
+ {
+ CEconItemView *pItem = m_pItemFullImage->GetItem();
+ if ( pItem->IsValid() )
+ {
+ // Determine which language we should use
+ char uilanguage[ 64 ];
+ uilanguage[0] = 0;
+ engine->GetUILanguage( uilanguage, sizeof( uilanguage ) );
+ ELanguage iLang = PchLanguageToELanguage( uilanguage );
+
+ char szURL[512];
+ Q_snprintf( szURL, sizeof(szURL), "http://wiki.teamfortress.com/scripts/itemredirect.php?id=%d&lang=%s", pItem->GetItemDefIndex(), GetLanguageICUName( iLang ) );
+ steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
+
+ C_CTF_GameStats.Event_Catalog( IE_ARMORY_BROWSE_WIKI, NULL, pItem );
+ }
+ }
+ }
+ else if ( !V_strnicmp( command, "team_", 5 ) )
+ {
+ const char *pTeam = command + 5;
+ if ( !V_strnicmp( pTeam, "red", 3 ) )
+ {
+ m_pPlayerModelPanel->SetTeam( TF_TEAM_RED );
+ }
+ else
+ {
+ m_pPlayerModelPanel->SetTeam( TF_TEAM_BLUE );
+ }
+ }
+ else if ( !V_strnicmp( command, "gofullscreen", 11 ) )
+ {
+ if ( m_pFullscreenPanel )
+ {
+ m_pFullscreenPanel->GoFullscreen( m_pPlayerModelPanel );
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnClassIconSelected( KeyValues *data )
+{
+ BaseClass::OnClassIconSelected( data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnHideClassIconMouseover( void )
+{
+ BaseClass::OnHideClassIconMouseover();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnShowClassIconMouseover( KeyValues *data )
+{
+ // We decided not to show the "this item is
+ // usable by the [Class name]" tooltip.
+ //BaseClass::OnShowClassIconMouseover( data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::PreviewItemCopy( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry )
+{
+ // Make a copy of SO data since it comes from the market and will fall out of scope
+ if ( m_pItemViewData )
+ {
+ delete m_pItemViewData;
+ m_pItemViewData = NULL;
+ }
+
+ if ( m_pSOEconItemData )
+ {
+ delete m_pSOEconItemData;
+ m_pSOEconItemData = NULL;
+ }
+
+ m_pItemViewData = new CEconItemView( *pItem );
+ m_pSOEconItemData = new CEconItem( *pItem->GetSOCData() );
+ m_pItemViewData->SetNonSOEconItem( m_pSOEconItemData );
+ PreviewItem( iClass, m_pItemViewData, pEntry );
+}
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry )
+{
+ BaseClass::PreviewItem( iClass, pItem, pEntry );
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_preview_item_panel(preview_item)", CFmtStr( "%i", m_item.GetItemDefIndex() ).Access() );
+
+ // Reload the .res file right now, since we need to make sure the item name label, on which all other controls
+ // base their position, is valid.
+ InvalidateLayout( true, true );
+
+ // Update the fullscreen item def index
+ if ( m_pFullscreenPanel )
+ {
+ m_pFullscreenPanel->SetItemDef( m_item.GetItemDefIndex() );
+ }
+
+ // If we didn't have a store entry passed in, look for one.
+ if ( !pEntry )
+ {
+ CStorePanel *pStorePanel = EconUI()->GetStorePanel();
+ if ( pStorePanel )
+ {
+ pEntry = pStorePanel->GetPriceSheet()->GetEntry( m_item.GetItemDefIndex() );
+ }
+ }
+
+ if ( m_pDialogFrame && m_pDetailsView && m_pItemFullImage && m_pItemFullImage->GetItem() && m_pAttributesLabel )
+ {
+ const CEconItemView *pFullItem = m_pItemFullImage->GetItem();
+ const CEconItemDefinition *pBaseDef = pFullItem->GetItemDefinition();
+ const CTFItemDefinition *pDef = dynamic_cast<const CTFItemDefinition *>( pBaseDef );
+
+ if ( pFullItem && pDef )
+ {
+ m_pDialogFrame->SetDialogVariable( "itemname", pFullItem->GetItemName() );
+
+ // Holiday restrictions?
+ const char *pHolidayRestriction = pDef->GetHolidayRestriction() ? pDef->GetHolidayRestriction() : "";
+ m_bIsHalloweenOrFullmoonOnlyItem = StringHasPrefix( pHolidayRestriction, "halloween" );
+
+ CTFItemSchema *pSchema = ItemSystem()->GetItemSchema();
+ if ( pSchema )
+ {
+ // Build a list of classes by which this item can be used
+ const CBitVec<LOADOUT_COUNT> *pbvClassUsability = pDef->GetClassUsability();
+
+ const int kClassNamesSize = 512;
+ wchar_t wszClassNames[ kClassNamesSize ] = L"";
+ int nClassAdded = 0;
+ bool bAllClasses = true;
+ for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; ++i )
+ {
+ if ( !pbvClassUsability->IsBitSet( i ) )
+ {
+ bAllClasses = false;
+ break;
+ }
+ }
+
+ if ( bAllClasses )
+ {
+ m_pDetailsViewChild->SetDialogVariable( "used_by_classes", g_pVGuiLocalize->Find( "#Store_ItemDesc_AllClasses" ) );
+ }
+ else
+ {
+ for ( int i = 0; i < LOADOUT_COUNT; ++i )
+ {
+ if ( pbvClassUsability->IsBitSet( i ) )
+ {
+ V_wcscat_safe( wszClassNames, nClassAdded++ == 0 ? L"" : L", " ); // add empty lines everywhere except before the first line
+ V_wcscat_safe( wszClassNames, g_pVGuiLocalize->Find( g_aPlayerClassNames[i] ) );
+ }
+ }
+ m_pDetailsViewChild->SetDialogVariable( "used_by_classes", wszClassNames );
+ }
+
+ // Setup the slot string
+ const CUtlVector< const char * > &vecLoadoutStrings = pSchema->GetLoadoutStrings( pDef->GetEquipType() );
+ const int iSlot = pDef->GetDefaultLoadoutSlot();
+ const bool bSlotValid = vecLoadoutStrings.IsValidIndex( iSlot );
+ m_pDetailsViewChild->SetDialogVariable( "slot", g_pVGuiLocalize->Find( bSlotValid ? CFmtStr( "#LoadoutSlot_%s", vecLoadoutStrings[iSlot] ).Access() : "#Store_ItemDesc_Slot_None" ) );
+
+ // Make an attempt to display tradability accurately even though we don't have an item to pull from.
+ static CSchemaAttributeDefHandle pAttrib_CannotTrade( "cannot trade" );
+ Assert( pAttrib_CannotTrade );
+
+ // Get localized versions of "yes" and "no"
+ const wchar_t *pYesNo[2] = {
+ g_pVGuiLocalize->Find( "#Store_ItemDesc_Yes" ),
+ g_pVGuiLocalize->Find( "#Store_ItemDesc_No" )
+ };
+ bool bIsMapStamp = pDef->GetItemClass() && !V_strncmp( pDef->GetItemClass(), "map_token", 9 );
+ bool bIsTradeable = bIsMapStamp || FindAttribute( pDef, pAttrib_CannotTrade )
+ ? pYesNo[ 1 ]
+ : g_pVGuiLocalize->Find( "#Attrib_Store_TradableAfterDate" );
+
+ m_pDetailsViewChild->SetDialogVariable( "giftable", bIsTradeable );
+ m_pDetailsViewChild->SetDialogVariable( "nameable", ( pDef->GetCapabilities() & ITEM_CAP_NAMEABLE ) != 0 ? pYesNo[0] : pYesNo[1] );
+
+ m_pDetailsViewChild->SetDialogVariable( "tradable", bIsTradeable );
+
+ // No store-bought items are craftable, but items that were going to be tradable would show as craftable because
+ // they weren't real items with a real origin that would prevent them from being crafted. In the short term it makes
+ // more sense to just force this to always display "false" because at least it will never be wrong.
+ m_pDetailsViewChild->SetDialogVariable( "craftable", pDef->IsBundle()
+ ? g_pVGuiLocalize->Find( "#Attrib_CannotCraftWeapons" )
+ : pDef->GetCapabilities() & ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED
+ ? pYesNo[0]
+ : pYesNo[1] );
+
+ // Setup price
+ if ( pEntry )
+ {
+ ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();
+
+ int iTotalPrice = pEntry->GetCurrentPrice( eCurrency );
+ wchar_t wzLocalizedPrice[ kLocalizedPriceSizeInChararacters ];
+ MakeMoneyString( wzLocalizedPrice, ARRAYSIZE( wzLocalizedPrice ), iTotalPrice, eCurrency );
+
+#ifdef ENABLE_STORE_RENTAL_BACKEND
+ const wchar_t *pwsRentalPriceFormat = GLocalizationProvider()->Find( "#TF_Store_RentalPriceFormat" );
+ if ( pEntry->IsRentable() && pwsRentalPriceFormat )
+ {
+ wchar_t wzRentalLocalizedPrice[ kLocalizedPriceSizeInChararacters ];
+ MakeMoneyString( wzRentalLocalizedPrice, ARRAYSIZE( wzRentalLocalizedPrice ), pEntry->GetRentalPriceScale() * iTotalPrice, eCurrency )
+
+ wchar_t wzLocalizedPriceString[96];
+ ::ILocalize::ConstructString_safe( wzLocalizedPriceString, pwsRentalPriceFormat, 2, wzLocalizedPrice, wzRentalLocalizedPrice );
+ m_pDetailsViewChild->SetDialogVariable( "price", wzLocalizedPriceString );
+ }
+ else
+#endif
+ {
+ if ( pEntry->m_bIsMarketItem )
+ {
+ if ( iTotalPrice != 0 )
+ {
+ wchar_t wzMarketString[96];
+ g_pVGuiLocalize->ConstructString_safe(
+ wzMarketString,
+ LOCCHAR( "%s1 %s2" ),
+ 2,
+ g_pVGuiLocalize->Find( "#Store_StartingAt" ),
+ wzLocalizedPrice );
+
+ m_pDetailsViewChild->SetDialogVariable( "price", wzMarketString );
+ }
+ else
+ {
+ m_pDetailsViewChild->SetDialogVariable( "price", "..." );
+ }
+ }
+ else
+ {
+ // if market item. Prefix 'Starting at'
+ m_pDetailsViewChild->SetDialogVariable( "price", wzLocalizedPrice );
+ }
+ }
+ }
+
+ // Show/hide rental button.
+ for ( int i = 0; i < ARRAYSIZE( m_pAddRentalToCartButtons ); i++ )
+ {
+ if ( m_pAddRentalToCartButtons[i] )
+ {
+ m_pAddRentalToCartButtons[i]->SetVisible( pEntry && pEntry->IsRentable() );
+ }
+ }
+ }
+
+ // Final label value for our armory description text block.
+ const wchar_t *pwszLabelValue = L"";
+ m_bArmoryTextAdded = false;
+
+ const char *pszArmoryDescString = pDef->GetArmoryDescString();
+ if ( pszArmoryDescString )
+ {
+ const ArmoryStringDict_t& ArmoryKeys = GetItemSchema()->GetArmoryDataItems();
+ const ArmoryStringDict_t::IndexType_t armoryIndex = ArmoryKeys.Find( pszArmoryDescString );
+
+ if ( ArmoryKeys.IsValidIndex( armoryIndex ) )
+ {
+ const char *pszArmoryDescLocalizationKey = ArmoryKeys[ armoryIndex ].Get();
+
+ pwszLabelValue = g_pVGuiLocalize->Find( pszArmoryDescLocalizationKey );
+ m_bArmoryTextAdded = true;
+ }
+ }
+
+ m_pDetailsViewChild->SetDialogVariable( "armory_text", pwszLabelValue );
+ }
+
+ // clear all old reference item panels before adding new ones
+ FOR_EACH_VEC( m_vecReferenceItemPanels, i )
+ {
+ m_vecReferenceItemPanels[i]->MarkForDeletion();
+ }
+ m_vecReferenceItemPanels.RemoveAll();
+ int iReferenceItemHeight = 0;
+
+ const CEconItemDescription *pDescription = m_pItemFullImage->GetItem()->GetDescription();
+ if ( pDescription )
+ {
+ TextImage *pAttributesTextImage = m_pAttributesLabel->GetTextImage(); // This pointer already verified above
+ pAttributesTextImage->ClearColorChangeStream();
+
+ const int kAttribBufferSize = 4 * 1024;
+ wchar_t wszAttribBuffer[ kAttribBufferSize ] = L"";
+
+ int iAttribLine = 0;
+ m_nNumAttribLinesAdded = 0;
+ Color clrPrev( 0, 0, 0, 0 );
+ uint32 unCurrentTextStreamIndex = 0;
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+ int iFontHeight = surface()->GetFontTall( m_pAttributesLabel->GetFont() );
+
+ if ( m_pItemCollectionHighlight )
+ {
+ m_pItemCollectionHighlight->SetVisible( false );
+ }
+
+ iReferenceItemHeight = iFontHeight;
+
+ int iAttributePanelX, iAttributePanelY;
+ m_pAttributesLabel->GetPos( iAttributePanelX, iAttributePanelY );
+
+ for ( uint32 i = 0; i < pDescription->GetLineCount(); ++i )
+ {
+ const econ_item_description_line_t& line = pDescription->GetLine(i);
+ int nLineLength = StringFuncs<locchar_t>::Length( line.sText.Get() );
+ if ( ( line.unMetaType & kDescLineFlag_Type ) != 0 )
+ {
+ m_pDetailsViewChild->SetDialogVariable( "item_level_info", line.sText.Get() );
+ }
+ else if ( ( line.unMetaType & kDescLineFlagSet_DisplayInAttributeBlock ) != 0 && m_pAttributesLabel )
+ {
+ ++iAttribLine;
+
+ // current collection item line
+ bool bIsCurrentCollectionItem = ( line.unMetaType & kDescLineFlag_CollectionCurrentItem ) != 0;
+ // use bg color as text color for current item for a better highlight
+ Color col = bIsCurrentCollectionItem ? Color( 0, 0, 0, 255 ) : pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
+
+ // Output a color change if necessary.
+ if ( i == 0 || clrPrev != col )
+ {
+ pAttributesTextImage->AddColorChange( col, unCurrentTextStreamIndex );
+ clrPrev = col;
+ }
+
+ // Current line highlight
+ if ( bIsCurrentCollectionItem && m_pItemCollectionHighlight )
+ {
+ // use text color as bg color for the current item for a better highlight
+ Color bgColor = pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
+
+ // Get the current ypos
+ int x, y;
+ m_pAttributesLabel->GetPos( x, y );
+ m_pItemCollectionHighlight->SetPos( x, y + ( iAttribLine - 1 ) * iFontHeight );
+ m_pItemCollectionHighlight->SetBgColor( bgColor );
+ m_pItemCollectionHighlight->SetVisible( bIsCurrentCollectionItem );
+ }
+
+ if ( ( line.unMetaType & ( kDescLineFlag_Name | kDescLineFlag_Type ) ) == 0 )
+ {
+ V_wcscat_safe( wszAttribBuffer, m_nNumAttribLinesAdded++ == 0 ? L"" : L"\n" ); // add empty lines everywhere except before the first line
+ V_wcscat_safe( wszAttribBuffer, line.sText.Get() );
+ unCurrentTextStreamIndex += nLineLength + 1; // add one character to deal with newlines
+ }
+
+ if ( line.unDefIndex != INVALID_ITEM_DEF_INDEX )
+ {
+ // set text and recalculate the size now to compute for button pos
+ m_pAttributesLabel->SetText( wszAttribBuffer );
+ m_pAttributesLabel->SizeToContents();
+
+ CItemModelPanel* pItemModelPanel = new CItemModelPanel( m_pAttributesLabel, CFmtStr( "reference_item_%d", m_vecReferenceItemPanels.Count() ) );
+ pItemModelPanel->SetActAsButton( true, true );
+ pItemModelPanel->SetAutoDelete( true );
+
+ pItemModelPanel->SetPos( 0, m_pAttributesLabel->GetTall() - iFontHeight );
+ pItemModelPanel->SetZPos( m_pAttributesLabel->GetZPos() + 1 );
+
+ CEconItemView itemData;
+ itemData.Init( line.unDefIndex, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+ itemData.SetClientItemFlags( kEconItemFlagClient_Preview );
+ pItemModelPanel->SetItem( &itemData );
+ pItemModelPanel->MakeFakeButton();
+
+ pItemModelPanel->SetTooltip( m_pMouseOverTooltip, "" );
+
+ m_vecReferenceItemPanels.AddToTail( pItemModelPanel );
+ }
+ }
+ }
+
+ // Make sure our string is NUL-terminated.
+ wszAttribBuffer[ kAttribBufferSize-1 ] = 0;
+
+ m_pAttributesLabel->SetText( wszAttribBuffer );
+ }
+
+ // match the highlight width to attribute width
+ if ( m_pItemCollectionHighlight && m_pItemCollectionHighlight->IsVisible() )
+ {
+ m_pAttributesLabel->SizeToContents();
+ m_pItemCollectionHighlight->SetWide( m_pAttributesLabel->GetWide() );
+ }
+
+ if ( m_vecReferenceItemPanels.Count() )
+ {
+ m_pAttributesLabel->SizeToContents();
+ FOR_EACH_VEC( m_vecReferenceItemPanels, i )
+ {
+ m_vecReferenceItemPanels[i]->SetSize( m_pAttributesLabel->GetWide(), iReferenceItemHeight );
+ }
+ }
+
+ // Get PerformLayout() called, now that we have text in our controls - without this, SizeToContents() sizes all the labels as tall and narrow.
+ InvalidateLayout( true );
+ }
+
+ // Set the visibility of the "Try it now!" button based on whether we as a client think this item should be able
+ // to be previewed.
+ const CEconStorePriceSheet *pPriceSheet = EconUI()->GetStorePanel()->GetPriceSheet();
+ if ( pPriceSheet && m_pPreviewButton )
+ {
+ const econ_store_entry_t *pStoreEntry = pPriceSheet->GetEntry( m_item.GetItemDefIndex() );
+ m_pPreviewButton->SetVisible( pStoreEntry && pStoreEntry->CanPreview() );
+ }
+
+ m_pItemFullImage->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::SetState( preview_state_t iState )
+{
+ BaseClass::SetState( iState );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::UpdateIcons( void )
+{
+ BaseClass::UpdateIcons();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::UpdatePlayerModelButtons()
+{
+ BaseClass::UpdatePlayerModelButtons();
+
+ if ( m_pPlayerModelPanel )
+ {
+ if ( m_pTeamNavPanel )
+ {
+ m_pTeamNavPanel->SetVisible( m_pPlayerModelPanel->IsVisible() );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::SetPlayerModelVisible( bool bVisible )
+{
+ BaseClass::SetPlayerModelVisible( bVisible );
+
+ if ( m_pCycleTextLabel )
+ {
+ m_pCycleTextLabel->SetVisible( bVisible );
+ }
+
+ if ( m_pGoFullscreenButton )
+ {
+ m_pGoFullscreenButton->SetVisible( bVisible );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::SetCycleLabelText( vgui::Label *pTargetLabel, const char *pCycleText )
+{
+ BaseClass::SetCycleLabelText( pTargetLabel, pCycleText );
+
+ if ( m_pCycleTextLabel )
+ {
+ const wchar_t *pwszText = g_pVGuiLocalize->Find( pCycleText );
+ m_pCycleTextLabel->SetText( pwszText ? pwszText : L"" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnNavButtonSelected( KeyValues *pData )
+{
+ const int iTeam = pData->GetInt( "userdata", -1 ); AssertMsg( iTeam >= 0, "Bad filter" );
+ if ( iTeam < 0 )
+ return;
+
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ m_pPlayerModelPanel->SetTeam( iTeam );
+ CyclePaint( false );
+
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "team_switch(store_preview_item_panel)", iTeam == TF_TEAM_RED ? "red" : "blu" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnExitFullscreen( KeyValues *pData )
+{
+ if ( !m_pPlayerModelPanel )
+ return;
+
+ // If team or class changed in fullscreen mode, update our ui components here
+ if ( m_pTeamNavPanel )
+ {
+ m_pTeamNavPanel->UpdateButtonSelectionStates( m_pPlayerModelPanel->GetTeam() == TF_TEAM_RED ? 0 : 1 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnTick( void )
+{
+ BaseClass::OnTick();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnMouseWheeled( int delta )
+{
+ if ( !m_pScrollBar )
+ return;
+
+ int val = m_pScrollBar->GetValue();
+ val -= (delta * 50);
+ m_pScrollBar->SetValue( val );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnSliderMoved( int position )
+{
+ m_iSliderPos = position;
+ UpdateScrollableChild();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::OnThink()
+{
+ BaseClass::OnThink();
+
+ Assert( IsVisible() );
+
+ // If the user clicks outside of the dialog frame, close the preview, like
+ // many web sites do on the internet.
+ bool bMouseDown = vgui::input()->IsMouseDown( MOUSE_LEFT );
+
+ // User just clicked?
+ if ( !m_pFullscreenPanel || !m_pFullscreenPanel->IsFullscreenMode() )
+ {
+ if ( !m_bMouseWasDown && bMouseDown )
+ {
+ vgui::input()->GetCursorPos( m_aClickPos[0], m_aClickPos[1] );
+ m_bMouseWasDown = true;
+ }
+ else if ( m_pDialogFrame && bMouseDown && !m_pDialogFrame->IsWithin( m_aClickPos[0], m_aClickPos[1] ) )
+ {
+ //m_bCloseOnUp = true;
+ }
+ else if ( !bMouseDown )
+ {
+ if ( m_bCloseOnUp )
+ {
+ C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_preview_item_panel", "close_from_outside_click" );
+
+ DoClose();
+ }
+ m_bCloseOnUp = false;
+ m_bMouseWasDown = false;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFStorePreviewItemPanel2::DoClose()
+{
+ if ( m_pFullscreenPanel )
+ {
+ m_pFullscreenPanel->ExitFullscreen();
+ }
+
+ OnClose();
+
+ SetVisible( false );
+}
diff --git a/game/client/tf/vgui/store/v2/tf_store_preview_item2.h b/game/client/tf/vgui/store/v2/tf_store_preview_item2.h
new file mode 100644
index 0000000..05f0657
--- /dev/null
+++ b/game/client/tf/vgui/store/v2/tf_store_preview_item2.h
@@ -0,0 +1,177 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TF_STORE_PREVIEW_ITEM2_H
+#define TF_STORE_PREVIEW_ITEM2_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "store/tf_store_preview_item_base.h"
+
+namespace vgui
+{
+ class ScrollBar;
+};
+class CNavigationPanel;
+class CExLabel;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CFullscreenStorePreviewItem : public EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CFullscreenStorePreviewItem, EditablePanel );
+public:
+ CFullscreenStorePreviewItem( vgui::Panel *pParent, EditablePanel *pOwner );
+
+ void SetItemDef( itemid_t iItemDef );
+
+ void GoFullscreen( CTFPlayerModelPanel *pPlayerModelPanel );
+ void ExitFullscreen();
+ bool IsFullscreenMode();
+
+private:
+ MESSAGE_FUNC_PARAMS( OnNavButtonSelected, "NavButtonSelected", pData );
+
+ virtual void OnThink();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+
+ itemid_t m_iItemDef;
+
+ CExLabel *m_pCycleTextLabel;
+ CNavigationPanel *m_pTeamNavPanel;
+ CExButton *m_pPreviewButton;
+
+ struct ModelState_t
+ {
+ int m_aPlayerModelPanelBounds[4];
+ Vector m_vecPlayerPos;
+ bool m_bZoomed;
+ }
+ m_OldModelState;
+
+ struct Stats_t
+ {
+ Stats_t() { Clear(); }
+ void Clear() { V_memset( this, 0, sizeof( Stats_t ) ); }
+
+ float m_flRotationTime;
+ }
+ m_Stats;
+
+ float m_flGoFullscreenStartTime;
+ bool m_bIsHalloweenOrFullmoonOnlyItem;
+ vgui::DHANDLE< CTFPlayerModelPanel > m_pPlayerModelPanel;
+
+ CExButton *m_pZoomButton;
+ CExButton *m_pRotLeftButton;
+ CExButton *m_pRotRightButton;
+
+ EditablePanel *m_pOverlayPanel;
+
+ PHandle m_hOwner;
+
+ int m_nLastMouseX;
+ int m_nLastMouseY;
+ float m_flLastMouseMoveTime;
+
+ CPanelAnimationVar( float, m_flFullscreenFadeToBlackDuration, "fullscreen_fade_to_black_duration", "1.0" );
+ CPanelAnimationVar( float, m_flModelPanelOriginX, "fullscreen_modelpanel_origin_x", "170" );
+ CPanelAnimationVar( float, m_flModelPanelOriginY, "fullscreen_modelpanel_origin_y", "0" );
+ CPanelAnimationVar( float, m_flModelPanelOriginZ, "fullscreen_modelpanel_origin_z", "-36" );
+ CPanelAnimationVar( float, m_flUiFadeoutTime, "ui_fadeout_time", "5.0" );
+ CPanelAnimationVar( float, m_flUiFadeoutDuration, "ui_fadeout_duration", "1.0" );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTFStorePreviewItemPanel2 : public CTFStorePreviewItemPanelBase
+{
+ DECLARE_CLASS_SIMPLE( CTFStorePreviewItemPanel2, CTFStorePreviewItemPanelBase );
+public:
+ CTFStorePreviewItemPanel2( vgui::Panel *pParent, const char *pResFile, const char *pPanelName, CStorePage *pOwner );
+
+ virtual void PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry=NULL ) OVERRIDE;
+ void PreviewItemCopy( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry=NULL );
+ virtual void SetState( preview_state_t iState );
+
+ MESSAGE_FUNC_PARAMS( OnClassIconSelected, "ClassIconSelected", data );
+ MESSAGE_FUNC( OnHideClassIconMouseover, "HideClassIconMouseover" );
+ MESSAGE_FUNC_PARAMS( OnShowClassIconMouseover, "ShowClassIconMouseover", data );
+
+protected:
+ virtual void OnThink();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+ virtual void PerformLayout( void );
+ virtual void OnTick( void );
+ virtual void OnMouseWheeled( int delta );
+
+ int PlaceControl( Panel *pParent, const char *pControlNameA, const char *pControlNameB, int nOffset, bool bVertical,
+ bool bSizeAToContents = true, bool bUseContentSize = true );
+ void DoClose();
+ void Clear();
+ void UpdateScrollableChild();
+
+ virtual void SetPlayerModelVisible( bool bVisible );
+ virtual void UpdateIcons( void );
+ virtual void UpdatePlayerModelButtons( void );
+ virtual void SetCycleLabelText( vgui::Label *pTargetLabel, const char *pCycleText );
+
+ MESSAGE_FUNC_PARAMS( OnNavButtonSelected, "NavButtonSelected", pData );
+ MESSAGE_FUNC_PARAMS( OnExitFullscreen, "ExitFullscreen", pData );
+
+ Label *m_pLastNewLineControl;
+ EditablePanel *m_pDialogFrame; /// The background border
+ EditablePanel *m_pPreviewViewportBg;
+ CExLabel *m_pItemNameLabel;
+ CExLabel *m_pAttributesLabel;
+ vgui::EditablePanel *m_pItemCollectionHighlight;
+ CExLabel *m_pCycleTextLabel;
+ int m_nNumAttribLinesAdded;
+ bool m_bArmoryTextAdded;
+ EditablePanel *m_pDetailsView;
+ EditablePanel *m_pDetailsViewChild;
+ CExButton *m_pAddRentalToCartButtons[3];
+ EditablePanel *m_pScrollableChild;
+ ScrollBar *m_pScrollBar;
+ int m_iSliderPos;
+ bool m_bCloseOnUp;
+ bool m_bMouseWasDown;
+ int m_aClickPos[2];
+ CExButton *m_pItemWikiPageButton;
+ CNavigationPanel *m_pTeamNavPanel;
+ CExButton *m_pPreviewButton;
+ CExImageButton *m_pGoFullscreenButton;
+ int m_nViewMaxHeight;
+
+ CFullscreenStorePreviewItem *m_pFullscreenPanel;
+ bool m_bIsHalloweenOrFullmoonOnlyItem;
+
+ CEconItemView *m_pItemViewData;
+ CEconItem *m_pSOEconItemData;
+
+ // mouse over reference item tooltip
+ CItemModelPanel *m_pMouseOverItemPanel;
+ CItemModelPanelToolTip *m_pMouseOverTooltip;
+ CUtlVector< CItemModelPanel* > m_vecReferenceItemPanels;
+
+ CPanelAnimationVarAliasType( int, m_iSmallVerticalBreakSize, "small_vertical_break_size", "0", "proportional_ypos" );
+ CPanelAnimationVarAliasType( int, m_iMediumVerticalBreakSize, "medium_vertical_break_size", "0", "proportional_ypos" );
+ CPanelAnimationVarAliasType( int, m_iBigVerticalBreakSize, "big_vertical_break_size", "0", "proportional_ypos" );
+ CPanelAnimationVarAliasType( int, m_iHorizontalBreakSize, "horizontal_break_size", "0", "proportional_xpos" );
+ CPanelAnimationVarAliasType( int, m_iControlButtonWidth, "control_button_width", "0", "proportional_xpos" );
+ CPanelAnimationVarAliasType( int, m_iControlButtonHeight, "control_button_height", "0", "proportional_ypos" );
+ CPanelAnimationVarAliasType( int, m_iControlButtonY, "control_button_y", "0", "proportional_ypos" );
+
+ MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position );
+};
+
+#endif // TF_STORE_PREVIEW_ITEM2_H