diff options
Diffstat (limited to 'game/client/econ/store/store_page.cpp')
| -rw-r--r-- | game/client/econ/store/store_page.cpp | 2233 |
1 files changed, 2233 insertions, 0 deletions
diff --git a/game/client/econ/store/store_page.cpp b/game/client/econ/store/store_page.cpp new file mode 100644 index 0000000..a60212f --- /dev/null +++ b/game/client/econ/store/store_page.cpp @@ -0,0 +1,2233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + + +#include "cbase.h" +#include "store/store_page.h" +#include "vgui/ISurface.h" +#include "vgui/IInput.h" +#include "vgui/ILocalize.h" +#include "gamestringpool.h" +#include "econ_item_inventory.h" +#include "econ_item_system.h" +#include "item_model_panel.h" +#include "store/store_panel.h" +#include "store/store_preview_item.h" +#include "store/store_viewcart.h" +#include "rtime.h" +#include "econ_ui.h" +#include "store/store_page_new.h" +#include "gc_clientsystem.h" +#include "confirm_dialog.h" + +#ifdef TF_CLIENT_DLL +#include "c_tf_gamestats.h" +#include "c_tf_freeaccount.h" +#endif // TF_CLIENT_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +#ifdef TF_CLIENT_DLL +void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); +#endif + +DECLARE_BUILD_FACTORY( CStorePreviewItemIcon ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStoreItemControlsPanel::CStoreItemControlsPanel( vgui::Panel *pParent, const char *pPanelName, CItemModelPanel *pItemModelPanel ) +: vgui::EditablePanel( pParent, pPanelName ), + m_pItemModelPanel( pItemModelPanel ), + m_pEntry( NULL ), + m_bItemPanelEntered( false ), + m_bButtonsVisible( false ) +{ +} + +void CStoreItemControlsPanel::SetMouseHoverHandler( Panel *pHandler ) +{ + m_pMouseHoverHandler = pHandler; +} + +void CStoreItemControlsPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( + ShouldUseNewStore() ? + "Resource/UI/econ/store/v2/StoreItemControls.res" : + "Resource/UI/econ/store/v1/StoreItemControls.res" + ); +} + +const econ_store_entry_t *CStoreItemControlsPanel::GetItem() const +{ + return m_pEntry; +} + +void CStoreItemControlsPanel::SetItem( const econ_store_entry_t *pEntry ) +{ + m_pEntry = pEntry; +} + +void CStoreItemControlsPanel::SetButtonsVisible( bool bVisible ) +{ + m_bButtonsVisible = bVisible; + + for ( int i = 0; i < GetChildCount(); ++i ) + { + CExButton *pButton = dynamic_cast< CExButton* >( GetChild( i ) ); + if ( pButton ) + { + pButton->SetVisible( bVisible ); + pButton->SetArmed( false ); + } + } +} + +void CStoreItemControlsPanel::OnCursorEntered() +{ + BaseClass::OnCursorEntered(); + + if ( m_pItemModelPanel && m_pItemModelPanel->HasItem() ) + { + SetButtonsVisible( true ); + } +} + +void CStoreItemControlsPanel::OnCursorExited() +{ + BaseClass::OnCursorExited(); +} + +void CStoreItemControlsPanel::OnItemPanelEntered() +{ + m_bItemPanelEntered = true; + SetButtonsVisible( true ); +} + +void CStoreItemControlsPanel::OnItemPanelExited() +{ + m_bItemPanelEntered = false; +} + +void CStoreItemControlsPanel::OnThink() +{ + if ( !m_bItemPanelEntered ) + { + if ( !IsCursorOver() ) + { + SetButtonsVisible( false ); + } + } + + if ( m_pMouseHoverHandler.Get() ) + { + KeyValues *pMsg = new KeyValues( "StoreItemControlsPanelHover", "entered", m_bButtonsVisible ); + pMsg->SetPtr( "entry", (void *)m_pEntry ); + PostMessage( m_pMouseHoverHandler.Get(), pMsg ); + } +} + +void CStoreItemControlsPanel::OnCommand( const char *command ) +{ + if ( !Q_strnicmp( command, "addtocart", 9 ) ) + { + PostActionSignal( new KeyValues( "ItemAddToCart" ) ); + } + else if ( !Q_strnicmp( command, "preview_item", 12 ) ) + { + PostActionSignal( new KeyValues( "ItemPreview" ) ); + } + else if ( !Q_strnicmp( command, "details", 7 ) ) + { + PostActionSignal( new KeyValues( "ItemDetails" ) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePreviewItemIcon::OnItemPanelMouseReleased( vgui::Panel *panel ) +{ + PostActionSignal(new KeyValues("ItemIconSelected", "icon", m_iIconIndex)); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePricePanel::CStorePricePanel( vgui::Panel *pParent, const char *pPanelName ) + : vgui::EditablePanel( pParent, pPanelName ) +{ + m_bOldDiscountVisibility = false; + m_pPrice = NULL; + m_pDiscount = NULL; + m_pNew = NULL; + m_pSale = NULL; + m_pSaleBorder = NULL; + m_pOGPrice = NULL; + m_pCrossout = NULL; + m_pLimited = NULL; + m_pHighlighted = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePricePanel::~CStorePricePanel() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char* CStorePricePanel::GetPanelResFile() +{ + return "Resource/UI/econ/store/v1/StorePrice.res"; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePricePanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( GetPanelResFile() ); + + m_pPrice = dynamic_cast< CExLabel* >( FindChildByName( "Price" ) ); + m_pDiscount = dynamic_cast< CExLabel* >( FindChildByName( "Discount" ) ); + m_pHighlighted = dynamic_cast< CExLabel* >( FindChildByName( "Highlighted" ) ); + m_pNew = dynamic_cast< CExLabel* >( FindChildByName( "NewLarge" ) ); + if ( !m_pNew ) + { + m_pNew = dynamic_cast< CExLabel* >( FindChildByName( "New" ) ); + } + m_pSale = dynamic_cast< CExLabel* >( FindChildByName( "Sale" ) ); + m_pSaleBorder = dynamic_cast< vgui::EditablePanel* >( FindChildByName( "StorePriceBorder" ) ); + m_pOGPrice = dynamic_cast< CExLabel* >( FindChildByName( "OG_Price" ) ); + m_pCrossout = FindChildByName( "OG_Price_CrossOut" ); + + // Only support one "limited" + m_pLimited = FindChildByName( "LimitedLarge" ); + if ( !m_pLimited ) + { + m_pLimited = FindChildByName( "Limited" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePricePanel::PerformLayout() +{ + BaseClass::PerformLayout(); + + if ( m_pPrice ) + { + int contentWidth, contentHeight; + m_pPrice->GetContentSize( contentWidth, contentHeight ); + int iTextInsetX, iTextInsetY; + m_pPrice->GetTextInset( &iTextInsetX, &iTextInsetY ); + m_pPrice->SetWide( contentWidth + iTextInsetX ); + m_pPrice->SetPos( GetWide() - m_pPrice->GetWide(), GetTall() - m_pPrice->GetTall() ); + } + + if ( m_pPrice && m_pDiscount && m_pOGPrice ) + { + int contentWidth, contentHeight; + m_pDiscount->GetContentSize( contentWidth, contentHeight ); + int iTextInsetX, iTextInsetY; + m_pDiscount->GetTextInset( &iTextInsetX, &iTextInsetY ); + m_pDiscount->SetWide( contentWidth + iTextInsetX ); + m_pDiscount->SetPos( 0, GetTall() - m_pDiscount->GetTall() ); + + // Place original price in bottom-right corner, above the price label + int aPricePos[2]; + m_pPrice->GetPos( aPricePos[0], aPricePos[1] ); + m_pOGPrice->SetWide( GetWide() ); + m_pOGPrice->GetContentSize( contentWidth, contentHeight ); + int aOGPricePos[2] = { 0, aPricePos[1] - contentHeight }; + m_pOGPrice->SetPos( aOGPricePos[0], aOGPricePos[1] ); + + // Place crossout over original price, halfway down from its vertical starting position + m_pCrossout->SetBounds( + aOGPricePos[0] + m_pOGPrice->GetWide() - contentWidth, + aOGPricePos[1] + contentHeight/2, contentWidth, m_pCrossout->GetTall() + ); + } + + if ( m_pNew ) + { + int contentWidth, contentHeight; + m_pNew->GetContentSize( contentWidth, contentHeight ); + int iTextInsetX, iTextInsetY; + m_pNew->GetTextInset( &iTextInsetX, &iTextInsetY ); + m_pNew->SetWide( contentWidth + iTextInsetX ); + int iPosX, iPosY; + m_pNew->GetPos( iPosX, iPosY ); + m_pNew->SetPos( GetWide() - m_pNew->GetWide(), iPosY ); + } + + if ( m_pHighlighted ) + { + int contentWidth, contentHeight; + m_pHighlighted->GetContentSize( contentWidth, contentHeight ); + int iTextInsetX, iTextInsetY; + m_pHighlighted->GetTextInset( &iTextInsetX, &iTextInsetY ); + m_pHighlighted->SetWide( contentWidth + iTextInsetX ); + int iPosX, iPosY; + m_pHighlighted->GetPos( iPosX, iPosY ); + m_pHighlighted->SetPos( GetWide() - m_pHighlighted->GetWide(), iPosY ); + } + + if ( m_pSale ) + { + int contentWidth, contentHeight; + m_pSale->GetContentSize( contentWidth, contentHeight ); + int iTextInsetX, iTextInsetY; + m_pSale->GetTextInset( &iTextInsetX, &iTextInsetY ); + m_pSale->SetWide( contentWidth + iTextInsetX ); + int iPosX, iPosY; + m_pSale->GetPos( iPosX, iPosY ); + m_pSale->SetPos( GetWide() - m_pSale->GetWide(), iPosY ); + } + + if ( m_pLimited ) + { + int iPosX, iPosY; + Panel *pRefPanel = ( m_pSale && m_pSale->IsVisible() ) ? m_pSale : ( m_pNew && m_pNew->IsVisible() ) ? m_pNew : NULL; + if ( pRefPanel && pRefPanel->IsVisible() ) + { + pRefPanel->GetPos( iPosX, iPosY ); + m_pLimited->SetPos( GetWide() - m_pLimited->GetWide() - XRES( 3 ), iPosY + pRefPanel->GetTall() + YRES( 3 ) ); + } + else + { + m_pLimited->GetPos( iPosX, iPosY ); + m_pLimited->SetPos( GetWide() - m_pLimited->GetWide() - XRES( 3 ), iPosY ); + } + } + + if ( m_pSaleBorder ) + { + m_pSaleBorder->SetSize( GetWide(), GetTall() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePricePanel::SetPriceText( int iPrice, const char *pVariable, const econ_store_entry_t *pEntry ) +{ + if ( iPrice == 0 ) + { + if ( pEntry->m_bIsMarketItem ) + { + SetDialogVariable( pVariable, g_pVGuiLocalize->Find( "#Store_Market" ) ); + } + else + { + SetDialogVariable( pVariable, "" ); + } + return; + } + + wchar_t wzLocalizedPrice[ kLocalizedPriceSizeInChararacters ]; + MakeMoneyString( wzLocalizedPrice, ARRAYSIZE( wzLocalizedPrice ), iPrice, EconUI()->GetStorePanel()->GetCurrency() ); + + if ( pEntry->m_bIsMarketItem ) + { + wchar_t wzMarketString[96]; + g_pVGuiLocalize->ConstructString_safe( + wzMarketString, + LOCCHAR( "%s1 %s2" ), + 2, + g_pVGuiLocalize->Find( "#Store_Market" ), + wzLocalizedPrice ); + + SetDialogVariable( pVariable, wzMarketString ); + } + else + { + SetDialogVariable( pVariable, wzLocalizedPrice ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static bool IsItemPreviewed( const econ_store_entry_t *pEntry, ECurrency eCurrency ) +{ + return (pEntry->GetItemDefinitionIndex() == InventoryManager()->GetLocalInventory()->GetPreviewItemDef()) + && !pEntry->IsOnSale( eCurrency ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AddItemToCartHelper( const char *pszContext, const econ_store_entry_t *pEntry, ECartItemType eSelectedCartItemType ) +{ + Assert( pEntry ); + + CStoreCart *pCart = EconUI()->GetStorePanel()->GetCart(); + const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency(); + + // If this is the item we've previewing *and* it's the first one we've added + // to the cart then we note that it's a preview item purchase and so we may + // get a discount. + ECartItemType eCartItemType = eSelectedCartItemType == kCartItem_Purchase && IsItemPreviewed( pEntry, eCurrency ) && !pCart->ContainsItemDefinition( pEntry->GetItemDefinitionIndex() ) + ? kCartItem_TryOutUpgrade + : eSelectedCartItemType; + + pCart->AddToCart( pEntry, pszContext, eCartItemType ); + EconUI()->GetStorePanel()->OnAddToCart(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AddItemToCartHelper( const char *pszContext, item_definition_index_t unItemDef, ECartItemType eSelectedCartItemType ) +{ + const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( unItemDef ); + if ( pEntry ) + { + AddItemToCartHelper( pszContext, pEntry, eSelectedCartItemType ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePricePanel::SetItem( const econ_store_entry_t *pEntry ) +{ + const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency(); + + item_price_t unPrice = pEntry->GetCurrentPrice( eCurrency ); + SetPriceText( unPrice, "price", pEntry ); + + const bool bIsItemPreviewed = IsItemPreviewed( pEntry, eCurrency ); + + if ( bIsItemPreviewed ) + { + // Make sure we're doing the math we think we're doing -- the item isn't on sale and so + // we'll be setting a new price based on the base price. + Assert( pEntry->GetCurrentPrice( eCurrency ) == pEntry->GetBasePrice( eCurrency ) ); + Assert( unPrice == pEntry->GetBasePrice( eCurrency ) ); + + // Apply the preview period discount. + unPrice *= EconUI()->GetStorePanel()->GetPriceSheet()->GetPreviewPeriodDiscount(); + } + + item_price_t unBasePrice; + const bool bIsDiscounted = pEntry->HasDiscount( eCurrency, &unBasePrice ); + + if ( m_pDiscount && m_pOGPrice ) + { + // and discount + if ( bIsDiscounted == false ) + { + m_pDiscount->SetVisible( false ); + m_pOGPrice->SetVisible( false ); + } + else + { + SetPriceText( unBasePrice, "og_price", pEntry ); + + // set the discount and size + float flDiscountPercentage = 1.0f - ( float(unPrice) / float(unBasePrice) ); + wchar_t wszDiscount[16]; + _snwprintf( wszDiscount, ARRAYSIZE( wszDiscount ), L"-%.0f%%", flDiscountPercentage * 100.0f ); + m_pDiscount->SetText( wszDiscount ); + + m_pDiscount->SetVisible( true ); + m_pOGPrice->SetVisible( true ); + } + } + + if ( m_pCrossout && m_pOGPrice ) + { + m_pCrossout->SetVisible( bIsDiscounted ); + } + + if ( m_pNew ) + { + m_pNew->SetVisible( pEntry->m_bNew ); + } + + if ( m_pHighlighted ) + { + m_pHighlighted->SetVisible( pEntry->m_bHighlighted ); + + + } + + if ( m_pSale ) + { + bool bSaleVisible = false; + + // We don't check explicitly for "is on sale" here because other things like item previews can + // adjust the price we're going to display to the user without adjusting the actual store entry. + if ( unPrice != pEntry->GetBasePrice( eCurrency ) && ( m_pNew == NULL || !m_pNew->IsVisible() ) ) + { + if ( bIsItemPreviewed ) + { + m_pSale->SetText( "#TF_PreviewDiscount" ); + } + + m_pSale->SetVisible( true ); + bSaleVisible = true; + } + else + { + m_pSale->SetVisible( false ); + } + + if ( m_pSaleBorder ) + { + m_pSaleBorder->SetVisible( !ShouldUseNewStore() && bSaleVisible ); + } + } + + if ( m_pLimited ) + { + if ( pEntry->m_bLimited ) + { + m_pLimited->SetVisible( true ); + } + else + { + m_pLimited->SetVisible( false ); + } + } + + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePricePanel::OnStoreItemControlsPanelHover( KeyValues *data ) +{ + // We don't care if there's no discount label to deal with + if ( !m_pDiscount ) + return; + + // Should the discount label be visible? + const econ_store_entry_t *pEntry = (const econ_store_entry_t *)data->GetPtr( "entry" ); + if ( !pEntry ) + return; + + ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency(); + if ( !pEntry->HasDiscount( eCurrency, NULL ) ) + return; + + bool bEntered = data->GetInt( "entered" ) == 1; + m_pDiscount->SetVisible( !bEntered ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePage::CStorePage(Panel *parent, const CEconStoreCategoryManager::StoreCategory_t *pPageData, const char *pPreviewItemResFile ) : vgui::PropertyPage(parent, "StorePage") +{ + m_pPageData = pPageData; + + m_pItemModelPanelKVs = NULL; + m_pModelPanelLabelsKVs = NULL; + m_pCartModelPanelKVs = NULL; + m_pCartQuantityLabelKVs = NULL; + + m_pFeaturedItemPanel = NULL; + + m_pItemBackdropPanel = new EditablePanel( this, "ItemBackdrop" ); + m_pMouseOverItemPanel = new CItemModelPanel( this, "mouseoveritempanel" ); + m_pMouseOverTooltip = new CItemModelPanelToolTip( this ); + m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel ); + m_pMouseOverTooltip->SetPositioningStrategy( IPTTP_BOTTOM_SIDE ); + + if ( IsHomePage() ) + { + if ( !ShouldUseNewStore() ) + { + m_pFeaturedItemPanel = new CItemModelPanel( this, "featured_item_panel" ); + m_pFeaturedItemPanel->SetActAsButton( true, true ); + m_pFeaturedItemPanel->SetTooltip( m_pMouseOverTooltip, "" ); + } + + m_pFilterComboBox = NULL; + } + else + { + m_pFilterComboBox = new vgui::ComboBox( this, "ClassFilterComboBox", 11, false ); + m_pFilterComboBox->SetVisible( false ); + m_pFilterComboBox->AddActionSignalTarget( this ); + } + + m_pPreviewItemResFile = pPreviewItemResFile; + m_pPreviewPanel = NULL; + m_pSelectedPanel = NULL; + m_pNextPageButton = NULL; + m_pPrevPageButton = NULL; + m_pCheckoutButton = NULL; + m_pPreviewItemButton = NULL; + m_pAddToCartButtonPanel = NULL; + m_iCurrentFilter = 0; + m_pCartButton = NULL; + m_pBackpackLabel = NULL; + m_iSelectedItemDef = 0; + m_iSelectDefOnPageShow = 0; + m_iSelectPageOnPageShow = 0; + m_iOldSelectedItemDef = 0; + m_bShouldDeletePreviewPanel = false; + m_bFilterDirty = true; + + ListenForGameEvent( "cart_updated" ); + + REGISTER_COLOR_AS_OVERRIDABLE( m_colItemPanelBG, "item_panel_bgcolor" ); + REGISTER_COLOR_AS_OVERRIDABLE( m_colItemPanelBGMouseover, "item_panel_bgcolor_mouseover" ); + REGISTER_COLOR_AS_OVERRIDABLE( m_colItemPanelBGSelected, "item_panel_bgcolor_selected" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePage::~CStorePage() +{ + if ( m_pItemModelPanelKVs ) + { + m_pItemModelPanelKVs->deleteThis(); + m_pItemModelPanelKVs = NULL; + } + if ( m_pCartModelPanelKVs ) + { + m_pCartModelPanelKVs->deleteThis(); + m_pCartModelPanelKVs = NULL; + } + if ( m_pCartQuantityLabelKVs ) + { + m_pCartQuantityLabelKVs->deleteThis(); + m_pCartQuantityLabelKVs = NULL; + } + if ( m_pModelPanelLabelsKVs ) + { + m_pModelPanelLabelsKVs->deleteThis(); + m_pModelPanelLabelsKVs = NULL; + } + if ( m_bShouldDeletePreviewPanel && m_pPreviewPanel ) + { + delete m_pPreviewPanel; + m_pPreviewPanel = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnPostCreate() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *CStorePage::GetPageResFile( void ) +{ + return m_pPageData->m_pchPageRes; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePreviewItemPanel *CStorePage::CreatePreviewPanel( void ) +{ + return new CStorePreviewItemPanel( this, m_pPreviewItemResFile, "storepreviewitem", this ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + // First time through, create our preview panel + if ( ( ShouldUseNewStore() || !IsHomePage() ) && !m_pPreviewPanel ) + { + m_pPreviewPanel = CreatePreviewPanel(); + + // Force it to load it's scheme now, because it needs to be done before we set it's visibility below + m_pPreviewPanel->InvalidateLayout( false, true ); + m_pPreviewPanel->SetVisible( false ); + } + + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + #ifdef TF_CLIENT_DLL + const char *pszHoliday = UTIL_GetActiveHolidayString(); + if ( pszHoliday && pszHoliday[0] ) + { + pConditions = new KeyValues( "conditions" ); + + char szCondition[64]; + Q_snprintf( szCondition, sizeof( szCondition ), "if_%s", pszHoliday ); + AddSubKeyNamed( pConditions, szCondition ); + } +#endif + + LoadControlSettings( GetPageResFile(), NULL, NULL, pConditions ); + + if ( pConditions ) + { + pConditions->deleteThis(); + } + + m_bReapplyItemKVs = true; + FOR_EACH_VEC( m_vecItemPanels, i ) + { + SetBorderForItem( m_vecItemPanels[i].m_pItemModelPanel, false ); + } + + m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") ); + + m_pNextPageButton = dynamic_cast<CExButton*>( FindChildByName("NextPageButton") ); + m_pPrevPageButton = dynamic_cast<CExButton*>( FindChildByName("PrevPageButton") ); + m_pCheckoutButton = dynamic_cast<CExButton*>( FindChildByName("CheckoutButton") ); + m_pPreviewItemButton = dynamic_cast<CExButton*>( FindChildByName("PreviewItemButton") ); + m_pAddToCartButtonPanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName("AddToCartButton") ); + if ( m_pAddToCartButtonPanel ) + { + CExButton *pButton = dynamic_cast<CExButton*>( m_pAddToCartButtonPanel->FindChildByName("SubButton") ); + if ( pButton ) + { + pButton->AddActionSignalTarget( GetVPanel() ); + } + } + m_pCurPageLabel = dynamic_cast<vgui::Label*>( FindChildByName("CurPageLabel") ); + m_pCartButton = dynamic_cast<CExButton*>( FindChildByName("CartButton") ); + m_pBackpackLabel = dynamic_cast<vgui::Label*>( FindChildByName("BackpackSpaceLabel") ); + if ( m_pBackpackLabel ) + { + m_colBackpackOrg = m_pBackpackLabel->GetFgColor(); + } + + m_pItemDetailsButtonPanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName("ItemDetailsButton") ); + if ( m_pItemDetailsButtonPanel ) + { + CExButton *pButton = dynamic_cast<CExButton*>( m_pItemDetailsButtonPanel->FindChildByName("SubButton") ); + if ( pButton ) + { + pButton->AddActionSignalTarget( GetVPanel() ); + } + } + m_pItemPreviewButtonPanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName("ItemPreviewButton") ); + if ( m_pItemPreviewButtonPanel ) + { + CExButton *pButton = dynamic_cast<CExButton*>( m_pItemPreviewButtonPanel->FindChildByName("SubButton") ); + if ( pButton ) + { + pButton->AddActionSignalTarget( GetVPanel() ); + } + } + + m_pCartFeaturedItemImage = dynamic_cast<vgui::ImagePanel*>( FindChildByName("CartFeaturedItemSymbol") ); + if ( m_pCartFeaturedItemImage ) + { + m_pCartFeaturedItemImage->SetMouseInputEnabled( false ); + m_pCartFeaturedItemImage->SetKeyBoardInputEnabled( false ); + } + + vgui::Panel *pPanel = FindChildByName("CartImage"); + if ( pPanel ) + { + pPanel->SetMouseInputEnabled( false ); + pPanel->SetKeyBoardInputEnabled( false ); + } + pPanel = FindChildByName("FeaturedItemSymbol"); + if ( pPanel ) + { + pPanel->SetMouseInputEnabled( false ); + pPanel->SetKeyBoardInputEnabled( false ); + } + pPanel = FindChildByName("FeaturedItemLabel"); + if ( pPanel ) + { + pPanel->SetMouseInputEnabled( false ); + pPanel->SetKeyBoardInputEnabled( false ); + } + pPanel = FindChildByName("FeaturedItemPrice"); + if ( pPanel ) + { + pPanel->SetMouseInputEnabled( false ); + pPanel->SetKeyBoardInputEnabled( false ); + } + + if ( m_pFilterComboBox ) + { + vgui::HFont hFont = pScheme->GetFont( "HudFontSmallestBold", true ); + m_pFilterComboBox->SetFont( hFont ); + UpdateFilteredItems(); + UpdateFilterComboBox(); + + // Move to "All items" selected + m_pFilterComboBox->SilentActivateItemByRow( 0 ); + } + + if ( m_pItemBackdropPanel ) + { + m_pItemBackdropPanel->SetBgColor( m_colItemBackdropPanel ); + } + + SetDetailsVisible( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + m_colItemBackdropPanel = inResourceData->GetColor( "item_backdrop_color" ); + + KeyValues *pItemKV = inResourceData->FindKey( "modelpanels_kv" ); + if ( pItemKV ) + { + if ( m_pItemModelPanelKVs ) + { + m_pItemModelPanelKVs->deleteThis(); + } + m_pItemModelPanelKVs = new KeyValues("modelpanels_kv"); + pItemKV->CopySubkeys( m_pItemModelPanelKVs ); + } + + pItemKV = inResourceData->FindKey( "modelpanel_labels_kv" ); + if ( pItemKV ) + { + if ( m_pModelPanelLabelsKVs ) + { + m_pModelPanelLabelsKVs->deleteThis(); + } + m_pModelPanelLabelsKVs = new KeyValues("modelpanel_labels_kv"); + pItemKV->CopySubkeys( m_pModelPanelLabelsKVs ); + } + + pItemKV = inResourceData->FindKey( "cart_modelpanels_kv" ); + if ( pItemKV ) + { + if ( m_pCartModelPanelKVs ) + { + m_pCartModelPanelKVs->deleteThis(); + } + m_pCartModelPanelKVs = new KeyValues("cart_modelpanels_kv"); + pItemKV->CopySubkeys( m_pCartModelPanelKVs ); + } + + pItemKV = inResourceData->FindKey( "cart_labels_kv" ); + if ( pItemKV ) + { + if ( m_pCartQuantityLabelKVs ) + { + m_pCartQuantityLabelKVs->deleteThis(); + } + m_pCartQuantityLabelKVs = new KeyValues("cart_labels_kv"); + pItemKV->CopySubkeys( m_pCartQuantityLabelKVs ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::PerformLayout( void ) +{ + if ( m_bReapplyItemKVs ) + { + m_bReapplyItemKVs = false; + + FOR_EACH_VEC( m_vecItemPanels, i ) + { + if ( m_pItemModelPanelKVs ) + { + m_vecItemPanels[i].m_pItemModelPanel->ApplySettings( m_pItemModelPanelKVs ); + SetBorderForItem( m_vecItemPanels[i].m_pItemModelPanel, false ); + m_vecItemPanels[i].m_pItemModelPanel->InvalidateLayout(); + } + m_vecItemPanels[i].m_pStorePricePanel->InvalidateLayout(); + } + + if ( m_pCartModelPanelKVs ) + { + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + m_pCartModelPanels[i]->ApplySettings( m_pCartModelPanelKVs ); + SetBorderForItem( m_pCartModelPanels[i], false ); + m_pCartModelPanels[i]->InvalidateLayout(); + } + } + + if ( m_pCartQuantityLabelKVs ) + { + FOR_EACH_VEC( m_pCartQuantityLabels, i ) + { + m_pCartQuantityLabels[i]->ApplySettings( m_pCartQuantityLabelKVs ); + m_pCartQuantityLabels[i]->InvalidateLayout(); + } + } + + if ( m_pModelPanelLabelsKVs ) + { + FOR_EACH_VEC( m_pCartQuantityLabels, i ) + { + m_pCartQuantityLabels[i]->ApplySettings( m_pModelPanelLabelsKVs ); + m_pCartQuantityLabels[i]->InvalidateLayout(); + } + } + } + + BaseClass::PerformLayout(); + + FOR_EACH_VEC( m_vecItemPanels, i ) + { + CItemModelPanel *pItemModelPanel = m_vecItemPanels[i].m_pItemModelPanel; + CStorePricePanel *pItemPricePanel = m_vecItemPanels[i].m_pStorePricePanel; + CStoreItemControlsPanel *pItemControlsPanel = m_vecItemPanels[i].m_pItemControlsPanel; + pItemModelPanel->SetVisible( true ); + pItemModelPanel->SetNoItemText( "#SelectNoItemSlot" ); + + PositionItemPanel(pItemModelPanel, i ); + + int iX,iY,iW,iH; + pItemModelPanel->GetBounds( iX, iY, iW, iH ); + // Position our price label and controls + pItemPricePanel->SetVisible( pItemModelPanel->HasItem() ); + pItemPricePanel->SetBounds( iX, iY, iW, iH ); + + pItemPricePanel->InvalidateLayout( true ); + + pItemControlsPanel->SetPos( iX + m_iItemControlsXOffset, iY + iH - pItemControlsPanel->GetTall() - m_iItemControlsYOffset ); + } + + if ( m_pItemBackdropPanel && m_vecItemPanels.Count() >= 2 ) + { + CItemModelPanel *pTopLeftPanel = m_vecItemPanels.Head().m_pItemModelPanel; + CItemModelPanel *pBottomRightPanel = m_vecItemPanels.Tail().m_pItemModelPanel; + + int aItemBackdropBounds[4]; + if ( pTopLeftPanel && pBottomRightPanel ) + { + int nX, nY; + pTopLeftPanel->GetPos( nX, nY ); + + aItemBackdropBounds[0] = nX - m_iItemBackdropLeftMargin; + aItemBackdropBounds[1] = nY - m_iItemBackdropTopMargin; + + pBottomRightPanel->GetPos( nX, nY ); + aItemBackdropBounds[2] = nX + pBottomRightPanel->GetWide() + m_iItemBackdropRightMargin - aItemBackdropBounds[0]; + aItemBackdropBounds[3] = nY + pBottomRightPanel->GetTall() + m_iItemBackdropBottomMargin - aItemBackdropBounds[1]; + + m_pItemBackdropPanel->SetBounds( aItemBackdropBounds[0], aItemBackdropBounds[1], aItemBackdropBounds[2], aItemBackdropBounds[3] ); + + m_pItemBackdropPanel->SetPaintBackgroundType( m_iItemBackdropPaintBackgroundType ); + m_pItemBackdropPanel->SetZPos( m_iItemBackdropZPos ); + } + } + + if ( m_pCartModelPanels.Count() > 0 ) + { + bool bFeaturedImagePanelVisible = false; + CStoreCart *pCart = EconUI()->GetStorePanel()->GetCart(); + + int iCartX, iCartY; + m_pCartButton->GetPos( iCartX, iCartY ); + int iCartModelWide = m_pCartModelPanels[0]->GetWide(); + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + if ( m_pCartModelPanels[i]->HasItem() ) + { + m_pCartModelPanels[i]->SetVisible( true ); + m_pCartQuantityLabels[i]->SetVisible( true ); + + int iX = iCartX + m_pCartButton->GetWide() + (XRES(4) * (i+1)) + (iCartModelWide * i); + m_pCartModelPanels[i]->SetPos( iX, iCartY ); + int iY = iCartY + m_pCartModelPanels[i]->GetTall() - m_pCartQuantityLabels[i]->GetTall(); + m_pCartQuantityLabels[i]->SetPos( iX + iCartModelWide - m_pCartQuantityLabels[i]->GetWide(), iY ); + + // If we're the featured item, show it + cart_item_t *pCartItem = pCart->GetItem(i); + if ( pCartItem && ( pCartItem->pEntry == EconUI()->GetStorePanel()->GetFeaturedEntry() ) ) + { + bFeaturedImagePanelVisible = true; + + if ( m_pCartFeaturedItemImage ) + { + m_pCartFeaturedItemImage->SetPos( iX - XRES(4), iY - YRES(10) ); + } + } + } + } + + if ( m_pCartFeaturedItemImage && m_pCartFeaturedItemImage->IsVisible() != bFeaturedImagePanelVisible ) + { + m_pCartFeaturedItemImage->SetVisible( bFeaturedImagePanelVisible ); + } + } + + if ( m_pCurPageLabel ) + { + bool bMultiplePages = (GetNumPages() > 1); + m_pCurPageLabel->SetVisible( bMultiplePages ); + m_pNextPageButton->SetVisible( bMultiplePages ); + m_pPrevPageButton->SetVisible( bMultiplePages ); + if ( bMultiplePages ) + { + m_pNextPageButton->SetEnabled( m_iCurrentPage < (GetNumPages()-1) ); + m_pPrevPageButton->SetEnabled( m_iCurrentPage > 0 ); + } + } + + if ( IsHomePage() ) + { + const store_promotion_spend_for_free_item_t *pPromotion = EconUI()->GetStorePanel()->GetPriceSheet()->GetStorePromotion_SpendForFreeItem(); + wchar_t wszText[1024]; + wchar_t wszPriceThreshold[ kLocalizedPriceSizeInChararacters ]; + ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency(); + AssertMsg( eCurrency >= k_ECurrencyUSD && eCurrency < k_ECurrencyMax, "Invalid currency!" ); + + int iPriceThreshold = pPromotion->m_rgusPriceThreshold[ eCurrency ]; + MakeMoneyString( wszPriceThreshold, ARRAYSIZE( wszPriceThreshold ), iPriceThreshold, EconUI()->GetStorePanel()->GetCurrency() ); + bool bIsFreeTrial = false; +#ifdef TF_CLIENT_DLL + bIsFreeTrial = IsFreeTrialAccount(); +#endif + const char *pszLocString = bIsFreeTrial ? "#Store_FreeTrial_BonusText" : "#Store_Promotion_SpendForGift"; + const char *pszElementName = bIsFreeTrial ? "BonusTextLabel" : "PromotionLabel_BonusItem"; + + g_pVGuiLocalize->ConstructString_safe( wszText, g_pVGuiLocalize->Find( pszLocString ), 1, wszPriceThreshold ); + CExLabel *pPromotionText = dynamic_cast< CExLabel* >( FindChildByName( pszElementName, true ) ); + if ( pPromotionText ) + { + pPromotionText->SetText( wszText ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::PositionItemPanel( CItemModelPanel *pPanel, int iIndex ) +{ + CItemModelPanel *pRealPanel = m_vecItemPanels[iIndex].m_pItemModelPanel; + + int iOffsetIndex = iIndex; + int iYPosOffset = 0; + int iCenter = GetWide() * 0.5; + int iButtonX = (iOffsetIndex % GetNumColumns()); + int iButtonY = (iOffsetIndex / GetNumColumns()); + int iXPos = m_iItemXPos + (iCenter + m_iItemOffcenterX) + (iButtonX * pRealPanel->GetWide()) + (m_iItemXDelta * iButtonX); + int iYPos = m_iItemYPos + (iButtonY * pRealPanel->GetTall() ) + (m_iItemYDelta * iButtonY) + iYPosOffset; + + pRealPanel->SetPos( iXPos, iYPos ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnPageShow( void ) +{ + m_iCurrentPage = m_iSelectPageOnPageShow; + m_iSelectPageOnPageShow = 0; + + // !KLUDGE! + SetDetailsVisible( !ShouldUseNewStore() ); + + m_bReapplyItemKVs = true; + BaseClass::OnPageShow(); + + if ( !IsHomePage() ) + { + EconUI()->Gamestats_Store( IE_STORE_TAB_CHANGED, NULL, GetPageName() ); + } + + m_pMouseOverItemPanel->SetVisible( false ); + + CreateItemPanels(); + + if ( m_pFilterComboBox ) + { + SetFilter( 0 ); + m_pFilterComboBox->SilentActivateItemByRow( 0 ); +// m_pFilterComboBox->SetVisible( !IsHomePage() ); + } + + // Setup sort by newest + if ( m_pPageData && !ShouldUseNewStore() ) + { + eEconStoreSortType iSortType = kEconStoreSortType_DateNewest; + 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 ); + + UpdateFilteredItems(); + } + + UpdateModelPanels(); + + if ( m_pCheckoutButton ) + { + m_pCheckoutButton->RequestFocus(); + } + + if ( m_iSelectDefOnPageShow ) + { + m_iSelectDefOnPageShow = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CStorePricePanel* CStorePage::CreatePricePanel( int iIndex ) +{ + if ( m_pPageData && !Q_strcmp( m_pPageData->m_pchPageClass, "CStorePage_Popular" ) ) + return vgui::SETUP_PANEL( new CStorePricePanel_Popular( this, "StorePrice", iIndex + 1 ) ); + + if ( m_pPageData && !Q_strcmp( m_pPageData->m_pchPageClass, "CStorePage_New" ) ) + return vgui::SETUP_PANEL( new CStorePricePanel_New( this, "StorePrice" ) ); + + if ( m_pPageData && !Q_strcmp( m_pPageData->m_pchPageClass, "CStorePage_Bundles" ) ) + return vgui::SETUP_PANEL( new CStorePricePanel_Bundles( this, "StorePrice" ) ); + + return vgui::SETUP_PANEL( new CStorePricePanel( this, "StorePrice" ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OrderItemsForDisplay( CUtlVector<const econ_store_entry_t *>& vecItems ) const +{ + /* + // See how I tread upon all the holy concepts of OOP. + if ( m_pPageData && + !Q_strcmp( m_pPageData->m_pchPageClass, "CStorePage_Bundles" ) && + !ShouldUseNewStore() ) + { + vecItems.Sort( &ItemDisplayOrderSort_UseSortOverride ); + } + */ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::CreateItemPanels( void ) +{ + int iNumPanels = GetNumItemPanels(); + if ( m_pPageData && m_vecItemPanels.Count() < iNumPanels ) + { + for ( int i = m_vecItemPanels.Count(); i < iNumPanels; i++ ) + { + int idx = m_vecItemPanels.AddToTail(); + item_panel &itempanel = m_vecItemPanels[idx]; + CItemModelPanel *pPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, VarArgs("modelpanel%d", i) ) ); + pPanel->SetShowQuantity( true ); + pPanel->SetActAsButton( true, true ); + itempanel.m_pItemModelPanel = pPanel; + + pPanel->SetTooltip( m_pMouseOverTooltip, "" ); + + // Create our price panel too + CStorePricePanel *pPricePanel = CreatePricePanel( i ); + pPricePanel->SetMouseInputEnabled( false ); + pPricePanel->SetKeyBoardInputEnabled( false ); + itempanel.m_pStorePricePanel = pPricePanel; + + // and controls + CStoreItemControlsPanel *pControlsPanel = vgui::SETUP_PANEL( new CStoreItemControlsPanel( this, "StoreItemControls", pPanel ) ); + //pControlsPanel->AddActionSignalTarget( this ); + if ( ShouldUseNewStore() ) + { + pControlsPanel->SetMouseHoverHandler( pPricePanel ); + } + itempanel.m_pItemControlsPanel = pControlsPanel; + } + + m_EntryIndices.SetCountNonDestructively( m_vecItemPanels.Count() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnCommand( const char *command ) +{ + if ( !Q_strnicmp( command, "nextpage", 8 ) ) + { + if ( m_iCurrentPage < (GetNumPages()-1) ) + { + m_iCurrentPage++; + UpdateModelPanels(); + } + return; + } + else if ( !Q_strnicmp( command, "prevpage", 8 ) ) + { + if ( m_iCurrentPage > 0 ) + { + m_iCurrentPage--; + UpdateModelPanels(); + } + return; + } + else if ( !Q_strnicmp( command, "preview_item", 12 ) ) + { + PreviewSelectionItem(); + return; + } + else if ( !Q_strnicmp( command, "addtocart", 9 ) ) + { + AddSelectionToCart(); + return; + } + else if ( !Q_strnicmp( command, "viewcart", 8 ) ) + { + OpenStoreViewCartPanel(); + return; + } + else if ( !Q_strnicmp( command, "startshopping", 8 ) ) + { + PostMessage( EconUI()->GetStorePanel(), new KeyValues("StartShopping") ); + return; + } + else if ( !Q_strnicmp( command, "checkout", 8 ) ) + { + EconUI()->GetStorePanel()->InitiateCheckout( false ); + return; + } + else if ( !Q_stricmp( command, "show_details" ) ) + { + if ( m_pSelectedPanel ) + { + CEconItemView *pItem = m_pSelectedPanel->GetItem(); + if ( pItem ) + { + SetDetailsVisible( true ); + } + } + return; + } + else if ( !Q_stricmp( command, "show_preview" ) ) + { + SetDetailsVisible( false ); + return; + } + else if ( !Q_strnicmp( command, "marketplace", 8 ) ) + { + if ( steamapicontext && steamapicontext->SteamFriends() ) + { + steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://steamcommunity.com/market/search?appid=440" ); + } + return; + } + else if ( !Q_stricmp( command, "reloadscheme" ) ) + { + InvalidateLayout( false, true ); + SetVisible( true ); + UpdateSelectionInfoPanel(); + return; + } + else + { + engine->ClientCmd( const_cast<char *>( command ) ); + } + + BaseClass::OnCommand( command ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::FireGameEvent( IGameEvent *event ) +{ + const char * type = event->GetName(); + + if ( Q_strcmp(type, "cart_updated") == 0 ) + { + UpdateCart(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnMouseWheeled( int delta ) +{ + if ( m_vecItemPanels.Count() == 0 ) + { + // on home page, likely + return; + } + + int oldSelectionIndex = -1; + int currentSelectionIndex = -1; + + // deselect everything + FOR_EACH_VEC( m_vecItemPanels, i ) + { + if ( m_vecItemPanels[i].m_pItemModelPanel->IsSelected() ) + { + oldSelectionIndex = i; + m_vecItemPanels[i].m_pItemModelPanel->SetSelected( false ); + SetBorderForItem( m_vecItemPanels[i].m_pItemModelPanel, false ); + } + } + + // step selection ahead + if ( delta < 0 ) + { + currentSelectionIndex = oldSelectionIndex+1; + + if ( currentSelectionIndex >= m_vecItemPanels.Count() ) + { + if ( m_iCurrentPage < (GetNumPages()-1) ) + { + currentSelectionIndex = 0; + m_iCurrentPage++; + UpdateModelPanels(); + } + else + { + currentSelectionIndex = m_vecItemPanels.Count(); + } + } + else if ( !m_vecItemPanels[ currentSelectionIndex ].m_pItemModelPanel->HasItem() ) + { + // don't move into empty slots + currentSelectionIndex = oldSelectionIndex; + } + } + else if ( delta > 0 ) + { + currentSelectionIndex = oldSelectionIndex-1; + + if ( currentSelectionIndex < 0 ) + { + if ( m_iCurrentPage > 0 ) + { + currentSelectionIndex = m_vecItemPanels.Count()-1; + m_iCurrentPage--; + UpdateModelPanels(); + } + else + { + currentSelectionIndex = 0; + } + } + else if ( !m_vecItemPanels[ currentSelectionIndex ].m_pItemModelPanel->HasItem() ) + { + // don't move into empty slots + currentSelectionIndex = oldSelectionIndex; + } + } + else + { + // no actual wheel movement + return; + } + + // sanity check + currentSelectionIndex = clamp( currentSelectionIndex, 0, m_vecItemPanels.Count()-1 ); + + m_pSelectedPanel = m_vecItemPanels[ currentSelectionIndex ].m_pItemModelPanel; + m_pSelectedPanel->SetSelected( ShouldUseNewStore() ); + SetBorderForItem( m_pSelectedPanel, false ); + UpdateSelectionInfoPanel(); + + if ( currentSelectionIndex != oldSelectionIndex ) + { + vgui::surface()->PlaySound( "ui/buttonclick.wav" ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CStorePage::AssignItemToPanel( CItemModelPanel *pPanel, int iIndex ) +{ + iIndex += (m_iCurrentPage * GetNumItemPanels()); + if ( iIndex >= 0 && iIndex < m_FilteredEntries.Count() ) + { + CEconItemView ItemData; + ItemData.Init( m_FilteredEntries[iIndex]->GetItemDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); + ItemData.SetItemQuantity( m_FilteredEntries[iIndex]->GetQuantity() ); + ItemData.SetClientItemFlags( kEconItemFlagClient_Preview | kEconItemFlagClient_StoreItem ); + pPanel->SetItem( &ItemData ); + + return iIndex; + } + + pPanel->SetItem( NULL ); + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CStorePage::GetNumPages( void ) +{ + return ceil( (float)m_FilteredEntries.Count() / (float)GetNumItemPanels() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +/* static */ int CStorePage::ItemDisplayOrderSort_UseSortOverride( const econ_store_entry_t *const *ppA, const econ_store_entry_t *const *ppB ) +{ + static CSchemaAttributeDefHandle pAttribDef_StoreSortOverride( "store sort override" ); + + const GameItemDefinition_t *pDefA = ItemSystem()->GetStaticDataForItemByDefIndex( (*ppA)->GetItemDefinitionIndex() ), + *pDefB = ItemSystem()->GetStaticDataForItemByDefIndex( (*ppB)->GetItemDefinitionIndex() ); + + // We expect only items with valid definition indices to make it into the list to + // be sorted. + Assert( pDefA ); + Assert( pDefB ); + + // Sort based on: our sort key if we have one; otherwise our definition index. + float flValue; + int unSortKeyA = ( pAttribDef_StoreSortOverride && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pDefA, pAttribDef_StoreSortOverride, &flValue ) ) + ? (int)flValue + : pDefA->GetDefinitionIndex(), + unSortKeyB = ( pAttribDef_StoreSortOverride && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pDefB, pAttribDef_StoreSortOverride, &flValue ) ) + ? (int)flValue + : pDefB->GetDefinitionIndex(); + + return unSortKeyA - unSortKeyB; +} + +//----------------------------------------------------------------------------- +// Purpose: Update our internal list of entries based on our filters, and count items in each filter +//----------------------------------------------------------------------------- +void CStorePage::UpdateFilteredItems( void ) +{ + if ( !m_bFilterDirty ) + return; + + m_FilteredEntries.Purge(); + m_vecFilterCounts.SetCount( GetNumPrimaryFilters() ); + if ( !m_vecFilterCounts.Count() ) + return; + + FOR_EACH_VEC( m_vecFilterCounts, i ) + { + m_vecFilterCounts[i] = 0; + } + + for ( int i = 0; i < m_pPageData->m_vecEntries.Count(); i++ ) + { + const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( m_pPageData->m_vecEntries[i] ); + GameItemDefinition_t *pDef = ItemSystem()->GetStaticDataForItemByDefIndex( pEntry->GetItemDefinitionIndex() ); + if ( pDef ) + { + // Get a list of applicable filters for the current item definition + CUtlVector<int> filterList; + GetFiltersForDef( pDef, &filterList ); + + bool bPassesClassFilter = false; + + FOR_EACH_VEC( filterList, iFL ) + { + int iFilter = filterList[iFL]; + + m_vecFilterCounts[iFilter]++; + + if ( m_iCurrentFilter == iFilter ) + { + bPassesClassFilter = true; + } + } + + // If the item passes both filters, add it. + // NOTE: DoesEntryFilterPassSecondaryFilter() returns true by default. + if ( bPassesClassFilter && DoesEntryFilterPassSecondaryFilter( pEntry ) ) + { + m_FilteredEntries.AddToTail( pEntry ); + } + } + } + + // Sort our full list of entries however this store page wants it. + OrderItemsForDisplay( m_FilteredEntries ); + + m_bFilterDirty = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::UpdateModelPanels( void ) +{ + DeSelectAllItemPanels(); + UpdateSelectionInfoPanel(); + UpdateCart(); + + if ( m_pPageData != NULL ) + { + UpdateFilteredItems(); + UpdateFilterComboBox(); + + FOR_EACH_VEC( m_vecItemPanels, i ) + { + CItemModelPanel *pItemModelPanel = m_vecItemPanels[i].m_pItemModelPanel; + pItemModelPanel->SetShowEquipped( true ); + m_EntryIndices[i] = AssignItemToPanel( pItemModelPanel, i ); + SetBorderForItem( pItemModelPanel, false ); + + int iEntry = m_EntryIndices[i]; + if ( iEntry >= 0 && iEntry < m_FilteredEntries.Count() ) + { + // Set the price label + m_vecItemPanels[i].m_pStorePricePanel->SetItem( m_FilteredEntries[ iEntry ] ); + m_vecItemPanels[i].m_pItemControlsPanel->SetItem( m_FilteredEntries[ iEntry ] ); + } + } + } + + char szTmp[16]; + Q_snprintf(szTmp, 16, "%d/%d", m_iCurrentPage+1, GetNumPages() ); + SetDialogVariable( "backpackpage", szTmp ); + + UpdateBackpackLabel(); + + // Now layout again to position our item buttons + InvalidateLayout(); + + if ( m_pFilterComboBox ) + { + m_pFilterComboBox->GetComboButton()->SetFgColor( Color( 117,107,94,255 ) ); + m_pFilterComboBox->GetComboButton()->SetDefaultColor( Color( 117,107,94,255), Color( 0,0,0,0) ); + m_pFilterComboBox->GetComboButton()->SetArmedColor( Color( 117,107,94,255), Color( 0,0,0,0) ); + m_pFilterComboBox->GetComboButton()->SetDepressedColor( Color( 117,107,94,255), Color( 0,0,0,0) ); + } + + // If we're not the home page, start with the first item selected already + if ( m_vecItemPanels.Count() ) + { + ToggleSelectItemPanel( m_vecItemPanels[m_iSelectDefOnPageShow].m_pItemModelPanel ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnItemPanelMouseReleased( vgui::Panel *panel ) +{ + CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel ); + + if ( pItemPanel && IsVisible() && pItemPanel->HasItem() ) + { + if ( IsHomePage() ) + { + // On the homepage, they've clicked the featured item. Find it in a store tab and move to it. + PostMessage( EconUI()->GetStorePanel(), new KeyValues("FindAndSelectFeaturedItem") ); + } + else if ( !pItemPanel->IsSelected() ) + { + ToggleSelectItemPanel( pItemPanel ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnItemPanelMouseDoublePressed( vgui::Panel *panel ) +{ + if ( IsHomePage() ) + { + // On the homepage, they've clicked the featured item. Find it in a store tab and move to it. + PostMessage( EconUI()->GetStorePanel(), new KeyValues("FindAndSelectFeaturedItem") ); + return; + } + + CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel ); + + if ( pItemPanel && IsVisible() && pItemPanel->HasItem() ) + { + // Make sure this panel is selected + if ( !pItemPanel->IsSelected() ) + { + ToggleSelectItemPanel( pItemPanel ); + } + + // Double clicking on an item in the cart takes you to the view cart page + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + if ( m_pCartModelPanels[i] == pItemPanel ) + { + OpenStoreViewCartPanel(); + return; + } + } + + // Not a cart panel, so add to cart. + OnCommand("addtocart"); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::DeSelectAllItemPanels( void ) +{ + FOR_EACH_VEC( m_vecItemPanels, i ) + { + if ( m_vecItemPanels[i].m_pItemModelPanel->IsSelected() ) + { + m_vecItemPanels[i].m_pItemModelPanel->SetSelected( false ); + SetBorderForItem( m_vecItemPanels[i].m_pItemModelPanel, false ); + } + } + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + if ( m_pCartModelPanels[i]->IsSelected() ) + { + m_pCartModelPanels[i]->SetSelected( false ); + SetBorderForItem( m_pCartModelPanels[i], false ); + } + } + + m_pSelectedPanel = NULL; + if ( m_pFeaturedItemPanel && m_pFeaturedItemPanel->IsSelected() ) + { + m_pFeaturedItemPanel->SetSelected( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::ToggleSelectItemPanel( CItemModelPanel *pPanel ) +{ + if ( ShouldUseNewStore() ) + return; + + if ( pPanel->IsSelected() || !pPanel->HasItem() ) + { + pPanel->SetSelected( false ); + m_pSelectedPanel = NULL; + } + else + { + DeSelectAllItemPanels(); + pPanel->SetSelected( true ); + m_pSelectedPanel = pPanel; + } + SetBorderForItem( pPanel, false ); + UpdateSelectionInfoPanel(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::SelectItemPanel( CItemModelPanel *pPanel ) +{ + DeSelectAllItemPanels(); + pPanel->SetSelected( true ); + m_pSelectedPanel = pPanel; + SetBorderForItem( pPanel, false ); + UpdateSelectionInfoPanel(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnItemPanelEntered( vgui::Panel *panel ) +{ + CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel ); + + if ( pItemPanel && IsVisible() ) + { + CEconItemView *pItem = pItemPanel->GetItem(); + if ( !pItemPanel->IsSelected() ) + { + SetBorderForItem( pItemPanel, pItem != NULL ); + } + if ( pItemPanel->HasItem() ) + { + // make related controls visible + FOR_EACH_VEC( m_vecItemPanels, i ) + { + item_panel &itempanel = m_vecItemPanels[i]; + if ( itempanel.m_pItemModelPanel == pItemPanel ) + { + itempanel.m_pItemControlsPanel->OnItemPanelEntered(); + break; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnItemPanelExited( vgui::Panel *panel ) +{ + CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel ); + + if ( pItemPanel && IsVisible() ) + { + if ( !pItemPanel->IsSelected() ) + { + SetBorderForItem( pItemPanel, false ); + } + if ( pItemPanel->HasItem() ) + { + // make related controls visible + FOR_EACH_VEC( m_vecItemPanels, i ) + { + item_panel &itempanel = m_vecItemPanels[i]; + if ( itempanel.m_pItemModelPanel == pItemPanel ) + { + itempanel.m_pItemControlsPanel->OnItemPanelExited(); + break; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnItemAddToCart( vgui::Panel *panel ) +{ + CStoreItemControlsPanel *pControlsPanel = dynamic_cast< CStoreItemControlsPanel * >( panel ); + if ( pControlsPanel ) + { + const econ_store_entry_t *pEntry = pControlsPanel->GetItem(); + if ( pEntry ) + { + if ( !ShouldUseNewStore() ) + { + SelectItemPanel( pControlsPanel->GetItemModelPanel() ); + } + else + { +#if defined( TF_CLIENT_DLL ) + C_CTFGameStats::ImmediateWriteInterfaceEvent( "store_add_to_cart", "minibutton" ); +#endif + } + AddItemToCartHelper( GetPageName(), pEntry, kCartItem_Purchase ); + UpdateCart(); + } + + // Turn the free slots indicator red if we can't fit everything. + UpdateBackpackLabel(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::SetBorderForItem( CItemModelPanel *pItemPanel, bool bMouseOver ) +{ + if ( !pItemPanel || pItemPanel == m_pFeaturedItemPanel ) + return; + + // Store panels use backgrounds instead of borders + pItemPanel->SetBorder( NULL ); + pItemPanel->SetPaintBackgroundEnabled( true ); + + if ( pItemPanel->IsSelected() ) + { + pItemPanel->SetBgColor( m_colItemPanelBGSelected ); + } + else if ( bMouseOver ) + { + pItemPanel->SetBgColor( m_colItemPanelBGMouseover ); + } + else + { + pItemPanel->SetBgColor( m_colItemPanelBG ); + } + + const CEconStorePriceSheet *pPriceSheet = EconUI()->GetStorePanel()->GetPriceSheet(); + + if ( pItemPanel->GetItem() && pPriceSheet ) + { + const econ_store_entry_t *pEntry = pPriceSheet->GetEntry( pItemPanel->GetItem()->GetItemDefIndex() ); + + if (pEntry && pEntry->m_bHighlighted && !bMouseOver ) + { + pItemPanel->SetBorder( vgui::scheme()->GetIScheme( GetScheme() )->GetBorder( "StoreHighlightedBackgroundBorder" ) ); + pItemPanel->SetPaintBorderEnabled( true ); + pItemPanel->SetPaintBackgroundEnabled( false ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::CalculateItemButtonPos( CItemModelPanel *pItemPanel, int x, int y, int *iXPos, int *iYPos ) +{ + *iXPos = x; + *iYPos = (y + pItemPanel->GetTall() + YRES(4)); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::UpdateSelectionInfoPanel( void ) +{ + // Home page doesn't support item selections + if ( IsHomePage() ) + return; + + if ( m_pPreviewItemButton ) + { + m_pPreviewItemButton->SetVisible( false ); + } + + if ( m_pSelectedPanel ) + { + const econ_store_entry_t *pEntry = GetSelectedEntry(); + CEconItemView *pItem = m_pSelectedPanel->GetItem(); + if ( pItem && pEntry ) + { + if ( m_pPreviewItemButton ) + { + m_pPreviewItemButton->SetVisible( pEntry->CanPreview() ); + } + + m_iOldSelectedItemDef = m_iSelectedItemDef; + m_iSelectedItemDef = pItem->GetItemDefIndex(); + + if ( m_iSelectedItemDef != m_iOldSelectedItemDef ) + { + EconUI()->Gamestats_Store( IE_STORE_ITEM_SELECTED, pItem, GetPageName() ); + } + + CEconItemDefinition *pItemData = pItem->GetStaticData(); + if ( pItemData ) + { + ShowPreview( 0, pEntry ); + InvalidateLayout(); + + wchar_t wzLocalizedPrice[ kLocalizedPriceSizeInChararacters ]; + int iPrice = pEntry->GetCurrentPrice( EconUI()->GetStorePanel()->GetCurrency() ); + MakeMoneyString( wzLocalizedPrice, ARRAYSIZE( wzLocalizedPrice ), iPrice, EconUI()->GetStorePanel()->GetCurrency() ); + SetDialogVariable("selectionprice", wzLocalizedPrice ); + + if ( m_pAddToCartButtonPanel ) + { + m_pAddToCartButtonPanel->SetVisible( true ); + } + + return; + } + } + } + + SetDialogVariable("selectionprice", "" ); + + if ( m_pAddToCartButtonPanel ) + { + m_pAddToCartButtonPanel->SetVisible( false ); + } + m_iSelectedItemDef = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Called when text changes in combo box +//----------------------------------------------------------------------------- +void CStorePage::OnTextChanged( KeyValues *data ) +{ + Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); + vgui::ComboBox *pComboBox = dynamic_cast<vgui::ComboBox *>( pPanel ); + + m_bFilterDirty = true; + + if ( pComboBox == m_pFilterComboBox ) + { + // the class selection combo box changed, update class details + KeyValues *pUserData = m_pFilterComboBox->GetActiveItemUserData(); + if ( !pUserData ) + return; + + int iFilter = pUserData->GetInt( "filter", 0 ); + + // If there are no items for that class, refuse to switch + if ( iFilter && m_vecFilterCounts[iFilter] <= 0 ) + { + m_pFilterComboBox->ActivateItemByRow( m_iCurrentFilter ? m_iCurrentFilter+1 : 0 ); + return; + } + + SetFilter( iFilter ); + m_iCurrentPage = 0; + UpdateModelPanels(); + + m_pCheckoutButton->RequestFocus(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::SetFilter( int iFilter ) +{ + if ( iFilter != m_iCurrentFilter ) + m_bFilterDirty = true; + + m_iCurrentFilter = iFilter; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::ShowPreview( int iClass, const econ_store_entry_t* pEntry ) +{ + if ( !m_pPreviewPanel ) + return; + + CEconItemView itemData; + itemData.Init( m_iSelectedItemDef, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); + itemData.SetClientItemFlags( kEconItemFlagClient_Preview ); + + m_pPreviewPanel->PreviewItem( iClass, &itemData, pEntry ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::SetDetailsVisible( bool bVisible ) +{ + if ( m_pPreviewPanel ) + { + m_pPreviewPanel->SetState( bVisible ? PS_DETAILS : PS_ITEM ); + } + + if ( m_pItemPreviewButtonPanel && m_pItemDetailsButtonPanel ) + { + vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() ); + if ( bVisible ) + { + m_pItemPreviewButtonPanel->SetBorder( pScheme->GetBorder("StorePreviewTabUnselected") ); + m_pItemDetailsButtonPanel->SetBorder( pScheme->GetBorder("StorePreviewTabSelected") ); + } + else + { + m_pItemPreviewButtonPanel->SetBorder( pScheme->GetBorder("StorePreviewTabSelected") ); + m_pItemDetailsButtonPanel->SetBorder( pScheme->GetBorder("StorePreviewTabUnselected") ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CStorePage::FindAndSelectEntry( const econ_store_entry_t *pEntry ) +{ + // We can't search if we haven't created our item panels & filtered. + CreateItemPanels(); + SetFilter( FILTER_ALL_ITEMS ); + UpdateFilteredItems(); + + FOR_EACH_VEC( m_FilteredEntries, i ) + { + if ( m_FilteredEntries[i]->GetItemDefinitionIndex() == pEntry->GetItemDefinitionIndex() ) + { + // Figure out what page it'll be on + int iPage = floor( (float)i / (float)GetNumItemPanels() ); + + // Switch to that page + m_iCurrentPage = iPage; + UpdateModelPanels(); + m_iSelectPageOnPageShow = iPage; + + // Then select the item model panel for this item + FOR_EACH_VEC( m_vecItemPanels, p ) + { + CEconItemView *pItem = m_vecItemPanels[p].m_pItemModelPanel->GetItem(); + if ( pItem && pItem->GetItemDefIndex() == pEntry->GetItemDefinitionIndex() ) + { + // We can't select here, because the pageshow will stomp it. + // Remember that this is the panel we'd like to have selected. + m_iSelectDefOnPageShow = p; + break; + } + } + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const econ_store_entry_t *CStorePage::GetSelectedEntry( void ) +{ + // Get the entry for the panel. + int iEntry = -1; + + if ( m_pFeaturedItemPanel == m_pSelectedPanel ) + return EconUI()->GetStorePanel()->GetFeaturedEntry(); + + FOR_EACH_VEC( m_vecItemPanels, i ) + { + if ( m_vecItemPanels[i].m_pItemModelPanel == m_pSelectedPanel ) + { + iEntry = m_EntryIndices[i]; + if ( iEntry >= 0 && iEntry < m_FilteredEntries.Count() ) + return m_FilteredEntries[iEntry]; + } + } + + // It's probably something already in our cart. + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + if ( m_pCartModelPanels[i] == m_pSelectedPanel ) + { + CStoreCart *pCart = EconUI()->GetStorePanel()->GetCart(); + if ( i < pCart->GetNumEntries() ) + { + cart_item_t *pCartItem = pCart->GetItem(i); + return pCartItem->pEntry; + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::AddSelectionToCart( void ) +{ + if ( !m_pSelectedPanel ) + return; + + // Get the entry for the panel. + const econ_store_entry_t *pEntry = GetSelectedEntry(); + if ( pEntry ) + { + AddItemToCartHelper( GetPageName(), pEntry, kCartItem_Purchase ); + UpdateCart(); + } + + // Turn the free slots indicator red if we can't fit everything. + UpdateBackpackLabel(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::UpdateCart( void ) +{ + if ( !IsVisible() || ( !ShouldUseNewStore() && IsHomePage() ) ) + return; + + CStoreCart *pCart = EconUI()->GetStorePanel()->GetCart(); + int iNumEntriesInCart = pCart->GetNumEntries(); + + // Now update the item icons next to the cart. + if ( m_pCartModelPanels.Count() < iNumEntriesInCart ) + { + // Support a max of 10 items in the cart quickview right now + for ( int i = m_pCartModelPanels.Count(); (i < iNumEntriesInCart) && (i < m_iMaxCartModelPanels); i++ ) + { + CItemModelPanel *pPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, VarArgs("cartmodelpanel%d", i) ) ); + pPanel->SetActAsButton( true, true ); + pPanel->ApplySettings( m_pCartModelPanelKVs ); + SetBorderForItem( pPanel, false ); + m_pCartModelPanels.AddToTail( pPanel ); + + pPanel->SetTooltip( m_pMouseOverTooltip, "" ); + + CExLabel *pLabel = vgui::SETUP_PANEL( new CExLabel( this, VarArgs("cartquantitylabel%d", i), "X" ) ); + pLabel->ApplySettings( m_pCartQuantityLabelKVs ); + pLabel->SetMouseInputEnabled( false ); + pLabel->SetKeyBoardInputEnabled( false ); + m_pCartQuantityLabels.AddToTail( pLabel ); + } + } + + UpdateBackpackLabel(); + + InvalidateLayout(); + + CEconItemView *pItemData = new CEconItemView(); + + // Assign the items in the cart to the panels + FOR_EACH_VEC( m_pCartModelPanels, i ) + { + if ( i >= iNumEntriesInCart ) + { + m_pCartModelPanels[i]->SetItem( NULL ); + m_pCartModelPanels[i]->SetVisible( false ); + m_pCartQuantityLabels[i]->SetVisible( false ); + continue; + } + + cart_item_t *pCartItem = pCart->GetItem(i); + pItemData->Init( pCartItem->pEntry->GetItemDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); + pItemData->SetClientItemFlags( kEconItemFlagClient_Preview | kEconItemFlagClient_StoreItem ); + m_pCartModelPanels[i]->SetItem( pItemData ); + m_pCartModelPanels[i]->SetVisible( true ); + + m_pCartQuantityLabels[i]->SetVisible( true ); + m_pCartQuantityLabels[i]->SetText( VarArgs("%d",pCartItem->iQuantity) ); + } + + delete pItemData; + + // Update the item count + wchar_t wszCount[16]; + wchar_t wzLocalized[512]; + _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", pCart->GetTotalItems() ); + g_pVGuiLocalize->ConstructString_safe( wzLocalized, g_pVGuiLocalize->Find( "#Store_Cart" ), 1, wszCount ); + SetDialogVariable("storecart", wzLocalized ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ConVar econ_never_show_items_in_cart_count( "econ_never_show_items_in_cart_count", "1", FCVAR_DEVELOPMENTONLY ); + +void CStorePage::UpdateBackpackLabel( void ) +{ + wchar_t wszBackpackSlotCount[16]; + wchar_t wszLocalized[512]; + + // How many slots do we have free in our current backpack? This won't take into + // consideration expanders, account upgrades, etc. + const int iMaxItemCount = InventoryManager()->GetLocalInventory()->GetMaxItemCount(), + iCurItemCount = InventoryManager()->GetLocalInventory()->GetItemCount(); + AssertMsg( iMaxItemCount - iCurItemCount >= 0, "You have a negative number of backpack slots available - fix me!" ); + const int iBaseFreeSlots = MAX( 0, iMaxItemCount - iCurItemCount ); + _snwprintf( wszBackpackSlotCount, ARRAYSIZE( wszBackpackSlotCount ), L"%d", iBaseFreeSlots ); + + // Breaking out bundles into individual items, etc., how many backpack slots will the + // items in our cart take up? + const int iItemsInCart = EconUI()->GetStorePanel()->GetCart()->GetTotalConcreteItems(); + + if ( iItemsInCart == 0 || econ_never_show_items_in_cart_count.GetBool() ) + { + g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#Store_FreeBackpackSpace" ), 1, wszBackpackSlotCount ); + } + else + { + wchar_t wszCartCount[16]; + _snwprintf( wszCartCount, ARRAYSIZE( wszCartCount ), L"%d", iItemsInCart ); + +#if defined( TF_CLIENT_DLL ) + if ( IsFreeTrialAccount() ) + { + wchar_t wszUpgradeSlotCount[16]; + _snwprintf( wszUpgradeSlotCount, ARRAYSIZE( wszUpgradeSlotCount ), L"%d", DEFAULT_NUM_BACKPACK_SLOTS - DEFAULT_NUM_BACKPACK_SLOTS_FREE_TRIAL_ACCOUNT ); + + // We're a free trial account so we show the number of backpack slots we really have, + // the number of slots we get as a bonus when purchasing, and then the number of items + // in our cart. + g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#Store_FreeBackpackSpace_WithCartItems_WithUpgrade" ), 3, wszBackpackSlotCount, wszCartCount, wszUpgradeSlotCount ); + } + else +#endif // defined( TF_CLIENT_DLL ) + { + // We aren't a free trial account, so there is no account upgrade included in + // this purchase, so fall back to showing the number of items in our cart. + g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#Store_FreeBackpackSpace_WithCartItems" ), 2, wszBackpackSlotCount, wszCartCount ); + } + } + + SetDialogVariable( "freebackpackspace", wszLocalized ); + + if ( m_pBackpackLabel ) + { + const Color clrTooMany = ShouldUseNewStore() ? Color(200,80,60,255) : Color(255,0,0,255); + m_pBackpackLabel->SetFgColor( InventoryManager()->GetLocalInventory()->CanPurchaseItems( iItemsInCart ) ? m_colBackpackOrg : clrTooMany ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::UpdateFilterComboBox( void ) +{ + if ( !m_pFilterComboBox ) + return; + + m_pFilterComboBox->RemoveAll(); + + // All items + KeyValues *pKeyValues = new KeyValues( "data" ); + pKeyValues->SetInt( "filter", FILTER_ALL_ITEMS ); + m_pFilterComboBox->AddItem( "#Store_ClassFilter_None", pKeyValues ); + + pKeyValues->deleteThis(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::PreviewSelectionItem( void ) +{ + if ( !m_pSelectedPanel ) + return; + + // Get the entry for the panel. + const econ_store_entry_t *pEntry = GetSelectedEntry(); + if ( !pEntry ) + return; + + if ( !pEntry->CanPreview() ) + return; + + DoPreviewItem( pEntry->GetItemDefinitionIndex() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::DoPreviewItem( item_definition_index_t usItemDef ) +{ +#ifdef TF_CLIENT_DLL + C_CTFGameStats::ImmediateWriteInterfaceEvent( "do_try_out_item", CFmtStr( "%i", usItemDef ).Access() ); +#endif + + if ( usItemDef == InventoryManager()->GetLocalInventory()->GetPreviewItemDef() ) + { + ShowMessageBox( "#ItemPreview_AlreadyPreviewTitle", "#ItemPreview_AlreadyPreviewText", "#GameUI_OK" ); + return; + } + + // Send a message to the GC asking if this player can preview an item. + GCSDK::CGCMsg< MsgGCCheckItemPreviewStatus_t > msg( k_EMsgGCItemPreviewCheckStatus ); + msg.Body().m_unItemDefIndex = usItemDef; + + // OGS LOGGING HERE + + GCClientSystem()->BSendMessage( msg ); + + // Response is handled in item_rental_ui.cpp. +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CStorePage::OnPreviewItem( KeyValues *pData ) +{ + DoPreviewItem( pData->GetInt( "item_def_index" ) ); +} |