Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3933 lines
120 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "vgui/IInput.h"
  8. #include <vgui/IVGui.h>
  9. #include <vgui/IScheme.h>
  10. #include "item_model_panel.h"
  11. #include "iclientmode.h"
  12. #include "baseviewport.h"
  13. #include "econ_entity.h"
  14. #include "gamestringpool.h"
  15. #include "vgui_controls/TextImage.h"
  16. #include "vgui_controls/Label.h"
  17. #include "vgui_controls/Button.h"
  18. #include "econ_item_system.h"
  19. #include "ienginevgui.h"
  20. #include "VGuiMatSurface/IMatSystemSurface.h"
  21. #include "renderparm.h"
  22. #include "vgui_controls/ScalableImagePanel.h"
  23. #include "engine/IEngineSound.h"
  24. #include "econ/tool_items/tool_items.h"
  25. #include "econ_item_description.h"
  26. #include "econ_item_tools.h"
  27. #include "tool_items/custom_texture_cache.h"
  28. #include "econ_dynamic_recipe.h"
  29. #include "materialsystem/imaterialvar.h"
  30. #include "materialsystem/itexturecompositor.h"
  31. #include "bone_setup.h"
  32. #include "animation.h"
  33. #include "iconrenderreceiver.h"
  34. #ifdef TF_CLIENT_DLL
  35. #include "tf_shareddefs.h"
  36. #include "tf_gamerules.h"
  37. #endif // TF_CLIENT_DLL
  38. #include "KeyValues.h"
  39. ConVar tf_time_loading_item_panels( "tf_time_loading_item_panels", "0.0005", FCVAR_ARCHIVE, "The time to spend per frame loading data for item panels" );
  40. #ifdef STAGING_ONLY
  41. ConVar tf_paint_kit_show_unique_icon( "tf_paint_kit_show_unique_icon", "1" );
  42. ConVar tf_test_loading_panels( "tf_test_loading_panels", "0" );
  43. ConVar tf_force_highres_item_image( "tf_force_highres_item_image", "0" );
  44. ConVar tf_unique_icon_perf_debug( "tf_unique_icon_perf_debug", "0" );
  45. #endif
  46. const char* g_ItemModelPanelRenderTargetNames[] =
  47. {
  48. "_rt_ItemModelPanel0",
  49. "_rt_ItemModelPanel1",
  50. "_rt_ItemModelPanel2"
  51. };
  52. COMPILE_TIME_ASSERT( ITEM_MODEL_IMAGE_CACHE_SIZE == ARRAYSIZE( g_ItemModelPanelRenderTargetNames ) );
  53. CItemMaterialCustomizationIconPanel::CItemMaterialCustomizationIconPanel( vgui::Panel *pParent, const char *pName )
  54. : BaseClass( pParent, pName )
  55. {
  56. m_iPaintSplat = -1;
  57. }
  58. CItemMaterialCustomizationIconPanel::~CItemMaterialCustomizationIconPanel()
  59. {
  60. if ( vgui::surface() )
  61. {
  62. if ( m_iPaintSplat != -1 )
  63. {
  64. vgui::surface()->DestroyTextureID( m_iPaintSplat );
  65. m_iPaintSplat = -1;
  66. }
  67. }
  68. }
  69. // Custom painting
  70. void CItemMaterialCustomizationIconPanel::PaintBackground( void )
  71. {
  72. // Draw custom texture, if we have one
  73. if ( m_hUGCId != 0 )
  74. {
  75. // Request it from the cache, and get filename, if it's downloaded
  76. // and ready
  77. int iCustomTexture = GetCustomTextureGuiHandle( m_hUGCId );
  78. if ( iCustomTexture != 0 )
  79. {
  80. surface()->DrawSetTexture( iCustomTexture );
  81. DrawQuad( 0, 1 );
  82. surface()->DrawSetColor(COLOR_WHITE);
  83. }
  84. }
  85. for ( int i = 0; i < m_colPaintColors.Size(); i++ )
  86. {
  87. const Color& c = m_colPaintColors[i];
  88. if ( m_iPaintSplat == -1 )
  89. {
  90. m_iPaintSplat = surface()->CreateNewTextureID();
  91. surface()->DrawSetTextureFile( m_iPaintSplat, "vgui/backpack_jewel_paint_splatter", true, false);
  92. }
  93. surface()->DrawSetTexture( m_iPaintSplat );
  94. surface()->DrawSetColor( c.r(), c.g(), c.b(), GetAlpha() );
  95. DrawQuad( i, m_colPaintColors.Size() );
  96. surface()->DrawSetColor(COLOR_WHITE);
  97. }
  98. // Clean up
  99. vgui::surface()->DrawSetTexture(0);
  100. }
  101. // Draw a quad that fills our extents
  102. void CItemMaterialCustomizationIconPanel::DrawQuad( int iSubtileIndex, int iSubtileCount )
  103. {
  104. int iWide, iTall;
  105. GetSize( iWide, iTall );
  106. // All of this math is to accomplish the following: allow us to split our single "icon"
  107. // into some number of equivalent columns. Then take each column and angle the divider so
  108. // it goes from the left image to the right image:
  109. //
  110. // +-----+-----+ +------+----+
  111. // | | | | / |
  112. // | | | | | |
  113. // | | | | / |
  114. // +-----+-----+ +--- +------+
  115. //
  116. // ...because the angle is prettier than a straight vertical cut.
  117. //
  118. // My hope is that this code is so awful I'm never allowed to write UI code again.
  119. float fXScale = 1.0f / (float)iSubtileCount,
  120. fXOffsetL = (float)iSubtileIndex * fXScale,
  121. fXOffsetR = (float)(iSubtileIndex + 1) * fXScale,
  122. fXUpperLowerOffset = fXScale * 0.65f;
  123. // We shift our coordinates on the top slightly to the right (by fXUpperLowerOffset) and on
  124. // the bottom slightly to the left (also by fXUpperLowerOffset). The far left side can't move
  125. // away from 0 and the far right side can't move away from 1, so the edge case handling makes
  126. // this look uglier than it really is.
  127. float fXUL = iSubtileIndex == 0 ? fXOffsetL : fXOffsetL + fXUpperLowerOffset,
  128. fXUR = iSubtileIndex == iSubtileCount - 1 ? fXOffsetR : fXOffsetR + fXUpperLowerOffset,
  129. fXBL = iSubtileIndex == 0 ? fXOffsetL : fXOffsetL - fXUpperLowerOffset,
  130. fXBR = iSubtileIndex == iSubtileCount - 1 ? fXOffsetR : fXOffsetR - fXUpperLowerOffset;
  131. Vector2D uv11( fXUL, 0.0f );
  132. Vector2D uv21( fXUR, 0.0f );
  133. Vector2D uv22( fXBR, 1.0f );
  134. Vector2D uv12( fXBL, 1.0f );
  135. vgui::Vertex_t verts[4];
  136. verts[0].Init( Vector2D( iWide * fXUL, 0 ), uv11 );
  137. verts[1].Init( Vector2D( iWide * fXUR, 0 ), uv21 );
  138. verts[2].Init( Vector2D( iWide * fXBR, iTall ), uv22 );
  139. verts[3].Init( Vector2D( iWide * fXBL, iTall ), uv12 );
  140. vgui::surface()->DrawTexturedPolygon( 4, verts );
  141. }
  142. DECLARE_BUILD_FACTORY( CItemModelPanel );
  143. DECLARE_BUILD_FACTORY( CEmbeddedItemModelPanel );
  144. DECLARE_BUILD_FACTORY( CItemMaterialCustomizationIconPanel );
  145. item_model_cache_t g_ItemModelImageCache[ITEM_MODEL_IMAGE_CACHE_SIZE];
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. //-----------------------------------------------------------------------------
  149. CEmbeddedItemModelPanel::CEmbeddedItemModelPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
  150. {
  151. m_bUseItemRenderTarget = false;
  152. m_bForceUseModel = false;
  153. m_pItem = NULL;
  154. m_pszToolTargetItemImage = NULL;
  155. m_iTextureID = -1;
  156. m_iToolTargetItemTextureID = -1;
  157. m_iOverlayTextureIDs.SetLessFunc( DefLessFunc(int) );
  158. m_iOverlayTextureIDs.Purge();
  159. m_bImageNotLoaded = false;
  160. m_bGreyedOut = false;
  161. m_bModelIsHidden = false;
  162. m_bUseRenderTargetAsIcon = false;
  163. m_bWeaponAllowInspect = false;
  164. m_pCachedWeaponIcon = NULL;
  165. m_pCachedWeaponMaterial = NULL;
  166. m_iCachedTextureID = -1;
  167. m_flModelRotateYawSpeed = 0;
  168. m_bUsePedestal = false;
  169. m_bOfflineIconGeneration = false;
  170. m_pItemParticle = NULL;
  171. #ifdef STAGING_ONLY
  172. m_flStartUpdateTime = 0.0;
  173. #endif // STAGING_ONLY
  174. }
  175. CEmbeddedItemModelPanel::~CEmbeddedItemModelPanel()
  176. {
  177. CleanUpCachedWeaponIcon();
  178. SafeDeleteParticleData( &m_pItemParticle );
  179. }
  180. void CEmbeddedItemModelPanel::CleanUpCachedWeaponIcon()
  181. {
  182. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  183. SafeRelease( &m_pCachedWeaponIcon );
  184. SafeRelease( &m_pCachedWeaponMaterial );
  185. if ( m_iCachedTextureID != -1 )
  186. {
  187. surface()->DeleteTextureByID( m_iCachedTextureID );
  188. m_iCachedTextureID = -1;
  189. }
  190. // If we match a cache here, clear it so we redraw once when we appear.
  191. for ( int i = 0; i < ITEM_MODEL_IMAGE_CACHE_SIZE; i++ )
  192. {
  193. bool bMatch = g_ItemModelImageCache[i].m_hModelPanelLock.Get() == this;
  194. if ( bMatch )
  195. {
  196. g_ItemModelImageCache[i].Clear();
  197. }
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. //-----------------------------------------------------------------------------
  203. void CEmbeddedItemModelPanel::UpdateCameraForIcon()
  204. {
  205. if ( m_iCameraAttachment == -1 )
  206. return;
  207. studiohdr_t *pItemStudioHdr = m_RootMDL.m_MDL.GetStudioHdr();
  208. if ( pItemStudioHdr )
  209. {
  210. matrix3x4_t matBoneToWorld[MAXSTUDIOBONES];
  211. m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, MAXSTUDIOBONES, matBoneToWorld );
  212. // Get attachment transform
  213. mstudioattachment_t attach = pItemStudioHdr->pAttachment( m_iCameraAttachment );
  214. matrix3x4_t matLocalToWorld;
  215. ConcatTransforms( matBoneToWorld[ attach.localbone ], attach.local, matLocalToWorld );
  216. QAngle angCameraAngles;
  217. Vector vecCameraPos;
  218. MatrixAngles( matLocalToWorld, angCameraAngles, vecCameraPos );
  219. SetCameraOffset( vec3_origin );
  220. SetCameraPositionAndAngles( vecCameraPos, angCameraAngles );
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. void CEmbeddedItemModelPanel::SetItem( CEconItemView *pItem )
  227. {
  228. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  229. m_iTextureID = -1;
  230. m_iToolTargetItemTextureID = -1;
  231. m_iOverlayTextureIDs.Purge();
  232. CleanUpCachedWeaponIcon();
  233. SafeDeleteParticleData( &m_pItemParticle );
  234. // reset all models
  235. SetMDL( MDLHANDLE_INVALID );
  236. m_ItemModel.m_bDisabled = true;
  237. m_ItemModel.m_MDL.SetMDL( MDLHANDLE_INVALID );
  238. m_StatTrackModel.m_bDisabled = true;
  239. m_StatTrackModel.m_MDL.SetMDL( MDLHANDLE_INVALID );
  240. m_AttachedModels.Purge();
  241. m_iCameraAttachment = -1;
  242. m_pItem = pItem;
  243. if ( !m_pItem )
  244. return;
  245. const char* pszInventoryImage = m_pItem->IsValid() ? m_pItem->GetInventoryImage() : NULL;
  246. if ( ( pszInventoryImage && pszInventoryImage[0] && !g_pMaterialSystem->IsMaterialLoaded( pszInventoryImage ) )
  247. #ifdef STAGING_ONLY
  248. || tf_test_loading_panels.GetBool()
  249. #endif
  250. )
  251. {
  252. m_bImageNotLoaded = true;
  253. }
  254. if ( !m_pItem->IsValid() )
  255. return;
  256. float flValue;
  257. static CSchemaAttributeDefHandle pAttrib_ToolTarget( "tool target item" );
  258. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( m_pItem, pAttrib_ToolTarget, &flValue ) )
  259. {
  260. const CEconItemDefinition *pTargetDef = GetItemSchema()->GetItemDefinition( flValue );
  261. m_pszToolTargetItemImage = pTargetDef->GetInventoryImage();
  262. }
  263. else
  264. {
  265. m_pszToolTargetItemImage = NULL;
  266. }
  267. #ifdef STAGING_ONLY
  268. if ( tf_paint_kit_show_unique_icon.GetBool() )
  269. #endif // STAGING_ONLY
  270. {
  271. float flInspect = 0;
  272. static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
  273. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( m_pItem, pAttrib_WeaponAllowInspect, &flInspect ) )
  274. {
  275. m_bWeaponAllowInspect = flInspect != 0;
  276. #ifdef STAGING_ONLY
  277. if ( m_flStartUpdateTime == 0 )
  278. m_flStartUpdateTime = Plat_FloatTime();
  279. #endif // STAGING_ONLY
  280. }
  281. else
  282. {
  283. m_bWeaponAllowInspect = false;
  284. #ifdef STAGING_ONLY
  285. m_flStartUpdateTime = 0.0;
  286. #endif // STAGING_ONLY
  287. }
  288. }
  289. float flUseCacheIcon = 0.f;
  290. static CSchemaAttributeDefHandle pAttrib_UseModelCacheIcon( "use_model_cache_icon" );
  291. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( m_pItem, pAttrib_UseModelCacheIcon, &flUseCacheIcon ) && flUseCacheIcon != 0.f )
  292. {
  293. m_bUseRenderTargetAsIcon = true;
  294. }
  295. else
  296. {
  297. m_bUseRenderTargetAsIcon = false;
  298. }
  299. if ( !m_bModelIsHidden )
  300. {
  301. if ( !m_pItem->GetInventoryImage() || IsForcingModelUsage() || m_bWeaponAllowInspect || UseRenderTargetAsIcon() )
  302. {
  303. const char *pszModelName = m_pItem->GetPlayerDisplayModel( 0, 0 );
  304. if ( pszModelName )
  305. {
  306. CMDL *pMDL = NULL;
  307. #ifndef PORTAL2 // DOTA COME BACK
  308. if ( m_bUsePedestal )
  309. {
  310. MDLHandle_t hPedestalMDL = mdlcache->FindMDL( "models/weapons/pedestal/pedestal.mdl" );
  311. SetMDL( hPedestalMDL, NULL );
  312. mdlcache->Release( hPedestalMDL ); // counterbalance addref from within FindMDL
  313. MDLHandle_t hItemMDL = mdlcache->FindMDL( pszModelName );
  314. if ( mdlcache->IsErrorModel( hItemMDL ) )
  315. {
  316. hItemMDL = MDLHANDLE_INVALID;
  317. }
  318. m_ItemModel.m_MDL.SetMDL( hItemMDL );
  319. mdlcache->Release( hItemMDL ); // counterbalance addref from within FindMDL
  320. pMDL = &m_ItemModel.m_MDL;
  321. }
  322. else
  323. {
  324. MDLHandle_t hMDL = mdlcache->FindMDL( pszModelName );
  325. SetMDL( hMDL, static_cast<IClientRenderable*>( m_pItem ) );
  326. mdlcache->Release( hMDL ); // counterbalance addref from within FindMDL
  327. pMDL = &m_RootMDL.m_MDL;
  328. }
  329. #endif
  330. if ( pMDL )
  331. {
  332. studiohdr_t *pItemStudioHdr = pMDL->GetStudioHdr();
  333. if ( pItemStudioHdr )
  334. {
  335. // Get the appropriate attachment
  336. CStudioHdr HDR( pItemStudioHdr, g_pMDLCache );
  337. if ( m_bUsePedestal )
  338. {
  339. m_iPedestalAttachment = Studio_FindAttachment( &HDR, "pedestal_0" );
  340. if ( m_iPedestalAttachment != -1 )
  341. {
  342. m_ItemModel.m_MDL.m_pProxyData = static_cast<IClientRenderable*>(m_pItem);
  343. m_ItemModel.m_bDisabled = false;
  344. m_ItemModel.m_MDL.m_nSequence = ACT_IDLE;
  345. SetIdentityMatrix( m_ItemModel.m_MDLToWorld );
  346. }
  347. }
  348. else
  349. {
  350. m_iCameraAttachment = Studio_FindAttachment( &HDR, "icon_camera" );
  351. UpdateCameraForIcon();
  352. }
  353. // should we override this model bodygroup
  354. const CEconStyleInfo *pStyle = m_pItem->GetItemDefinition()->GetStyleInfo( m_pItem->GetStyle() );
  355. if ( pStyle && pStyle->GetBodygroupName() != NULL )
  356. {
  357. int iBodyGroup = ::FindBodygroupByName( &HDR, pStyle->GetBodygroupName() );
  358. if ( iBodyGroup != -1 )
  359. {
  360. ::SetBodygroup( &HDR, pMDL->m_nBody, iBodyGroup, pStyle->GetBodygroupSubmodelIndex() );
  361. }
  362. }
  363. }
  364. }
  365. // Attach Models
  366. // Attach the models for the item
  367. {
  368. int iTeam = m_pItem->GetItemDefinition()->GetBestVisualTeamData( m_pItem->GetTeamNumber() );
  369. {
  370. // Set attached models if viewable third-person.
  371. const int iNumAttachedModels = m_pItem->GetItemDefinition()->GetNumAttachedModels( iTeam );
  372. for ( int i = 0; i < iNumAttachedModels; ++i )
  373. {
  374. attachedmodel_t *pModel = m_pItem->GetItemDefinition()->GetAttachedModelData( iTeam, i );
  375. LoadAttachedModel( pModel );
  376. }
  377. }
  378. // Festive
  379. static CSchemaAttributeDefHandle pAttr_is_festivized( "is_festivized" );
  380. if ( pAttr_is_festivized && m_pItem->FindAttribute( pAttr_is_festivized ) )
  381. {
  382. const int iNumAttachedModels = m_pItem->GetItemDefinition()->GetNumAttachedModelsFestivized( iTeam );
  383. for ( int i = 0; i < iNumAttachedModels; ++i )
  384. {
  385. attachedmodel_t *pModel = m_pItem->GetItemDefinition()->GetAttachedModelDataFestivized( iTeam, i );
  386. LoadAttachedModel( pModel );
  387. }
  388. }
  389. }
  390. // Stattrak
  391. CAttribute_String attrModule;
  392. static CSchemaAttributeDefHandle pAttr_module( "weapon_uses_stattrak_module" );
  393. if ( m_pItem->FindAttribute( pAttr_module, &attrModule ) && attrModule.has_value() )
  394. {
  395. // Allow for already strange items
  396. bool bIsStrange = false;
  397. if ( m_pItem->GetQuality() == AE_STRANGE )
  398. {
  399. bIsStrange = true;
  400. }
  401. if ( !bIsStrange )
  402. {
  403. // Go over the attributes of the item, if it has any strange attributes the item is strange and don't apply
  404. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  405. {
  406. if ( m_pItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
  407. {
  408. bIsStrange = true;
  409. break;
  410. }
  411. }
  412. }
  413. if ( bIsStrange )
  414. {
  415. static CSchemaAttributeDefHandle pAttr_moduleScale( "weapon_stattrak_module_scale" );
  416. // Does it have a stat track module
  417. m_flStatTrackScale = 1.0f;
  418. uint32 unFloatAsUint32 = 1;
  419. if ( m_pItem->FindAttribute( pAttr_moduleScale, &unFloatAsUint32 ) )
  420. {
  421. m_flStatTrackScale = (float&)unFloatAsUint32;
  422. }
  423. MDLHandle_t hStatTrackMDL = mdlcache->FindMDL( "models/weapons/c_models/stattrack.mdl" );
  424. if ( mdlcache->IsErrorModel( hStatTrackMDL ) )
  425. {
  426. hStatTrackMDL = MDLHANDLE_INVALID;
  427. }
  428. m_StatTrackModel.m_MDL.SetMDL( hStatTrackMDL );
  429. mdlcache->Release( hStatTrackMDL ); // counterbalance addref from within FindMDL
  430. m_StatTrackModel.m_MDL.m_pProxyData = static_cast<IClientRenderable*>(pItem);
  431. m_StatTrackModel.m_bDisabled = false;
  432. m_StatTrackModel.m_MDL.m_nSequence = ACT_IDLE;
  433. SetIdentityMatrix( m_StatTrackModel.m_MDLToWorld );
  434. }
  435. }
  436. int iTeam = GetLocalPlayerTeam(),
  437. iSkin = iTeam;
  438. #ifdef TF_CLIENT_DLL
  439. // If we aren't in a game we default to previewing the red team skin.
  440. if ( iTeam == TEAM_UNASSIGNED )
  441. {
  442. iTeam = TF_TEAM_RED;
  443. }
  444. #endif // TF_CLIENT_DLL
  445. if ( iSkin != TEAM_UNASSIGNED )
  446. {
  447. // Use the first skin for the first team, and the second skin for the other (but default to 0)
  448. iSkin = (iSkin == (FIRST_GAME_TEAM+1)) ? 1 : 0;
  449. }
  450. // Handle styles/visuals overriding the skin.
  451. int iOverrideSkin = m_pItem->GetSkin( iTeam );
  452. if ( iOverrideSkin != -1 )
  453. {
  454. iSkin = iOverrideSkin;
  455. }
  456. SetSkin( iSkin );
  457. if ( m_bUsePedestal )
  458. {
  459. m_ItemModel.m_MDL.m_nSkin = iSkin;
  460. }
  461. }
  462. }
  463. }
  464. }
  465. void CEmbeddedItemModelPanel::LoadAttachedModel( attachedmodel_t *pModel )
  466. {
  467. if ( !( pModel->m_iModelDisplayFlags & kAttachedModelDisplayFlag_WorldModel ) )
  468. return;
  469. if ( !pModel->m_pszModelName )
  470. {
  471. Warning( "econ item definition '%s' attachment has no model\n", m_pItem->GetItemDefinition()->GetDefinitionName() );
  472. return;
  473. }
  474. int iIndex = m_AttachedModels.AddToTail();
  475. MDLHandle_t hMDL = mdlcache->FindMDL( pModel->m_pszModelName );
  476. if ( mdlcache->IsErrorModel( hMDL ) )
  477. {
  478. hMDL = MDLHANDLE_INVALID;
  479. }
  480. m_AttachedModels[iIndex].m_MDL.SetMDL( hMDL );
  481. mdlcache->Release( hMDL ); // counterbalance addref from within FindMDL
  482. m_AttachedModels[iIndex].m_MDL.m_pProxyData = static_cast<IClientRenderable*>( m_pItem );
  483. m_AttachedModels[iIndex].m_bDisabled = false;
  484. m_AttachedModels[iIndex].m_MDL.m_nSequence = ACT_IDLE;
  485. SetIdentityMatrix( m_AttachedModels[iIndex].m_MDLToWorld );
  486. }
  487. bool CEmbeddedItemModelPanel::IsLoadingWeaponSkin( void ) const
  488. {
  489. static ConVarRef mat_dxlevel( "mat_dxlevel" );
  490. if ( mat_dxlevel.GetInt() < 90 )
  491. return false;
  492. if ( m_bForceUseModel )
  493. return false;
  494. if ( m_pItem && m_pItem->IsValid() )
  495. {
  496. if ( m_bWeaponAllowInspect && m_pItem->GetCustomPainkKitDefinition() )
  497. {
  498. return m_pItem->GetWeaponSkinBaseCompositor() != NULL || !m_pCachedWeaponIcon || !m_pCachedWeaponIcon->GetTexture();
  499. }
  500. else if ( UseRenderTargetAsIcon() )
  501. {
  502. return !m_pCachedWeaponIcon || !m_pCachedWeaponIcon->GetTexture();
  503. }
  504. }
  505. return false;
  506. }
  507. bool CEmbeddedItemModelPanel::IsImageNotLoaded( void ) const
  508. {
  509. if ( m_bForceUseModel )
  510. return false;
  511. if ( m_bImageNotLoaded && m_pItem && m_pItem->IsValid() )
  512. return true;
  513. return false;
  514. }
  515. IMaterial* GetMaterialForImage( CEmbeddedItemModelPanel::InventoryImageType_t eImageType, const char* pszBaseName )
  516. {
  517. IMaterial *pMaterial = NULL;
  518. Assert( pszBaseName );
  519. if ( !pszBaseName )
  520. return NULL;
  521. #ifdef STAGING_ONLY
  522. if ( eImageType == CEmbeddedItemModelPanel::IMAGETYPE_SMALL && tf_force_highres_item_image.GetBool() )
  523. {
  524. eImageType = CEmbeddedItemModelPanel::IMAGETYPE_LARGE;
  525. }
  526. #endif // STAGING_ONLY
  527. switch ( eImageType )
  528. {
  529. case CEmbeddedItemModelPanel::IMAGETYPE_SMALL:
  530. pMaterial = g_pMaterialSystem->FindMaterial( pszBaseName, TEXTURE_GROUP_VGUI );
  531. break;
  532. case CEmbeddedItemModelPanel::IMAGETYPE_DETAILED:
  533. pMaterial = g_pMaterialSystem->FindMaterial( CFmtStr("%s_detail",pszBaseName).Access(), TEXTURE_GROUP_VGUI, false );
  534. break;
  535. case CEmbeddedItemModelPanel::IMAGETYPE_LARGE:
  536. pMaterial = g_pMaterialSystem->FindMaterial( CFmtStr("%s_large",pszBaseName).Access(), TEXTURE_GROUP_VGUI );
  537. break;
  538. default:
  539. Assert(0);
  540. }
  541. Assert( pMaterial && !IsErrorMaterial( pMaterial ) );
  542. return pMaterial;
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Purpose:
  546. //-----------------------------------------------------------------------------
  547. void CEmbeddedItemModelPanel::LoadInventoryImage()
  548. {
  549. InventoryImageType_t type = (InventoryImageType_t)m_iInventoryImageType;
  550. if ( m_iInventoryImageType == IMAGETYPE_DETAILED && !m_pItem->GetStaticData()->HasDetailedIcon() )
  551. {
  552. type = IMAGETYPE_LARGE;
  553. }
  554. GetMaterialForImage( type, m_pItem->GetInventoryImage() );
  555. m_bImageNotLoaded = false;
  556. m_iTextureID = -1;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose:
  560. //-----------------------------------------------------------------------------
  561. void CEmbeddedItemModelPanel::PerformLayout( void )
  562. {
  563. BaseClass::PerformLayout();
  564. CleanUpCachedWeaponIcon();
  565. // Nive the "player pos" to the defined distance
  566. if ( m_pItem && m_pItem->IsValid() )
  567. {
  568. if ( m_bUsePedestal )
  569. {
  570. Vector vecOffset = m_BMPResData.m_vecOriginOffset;
  571. vecOffset.x = m_pItem->GetItemDefinition()->GetInspectPanelDistance();
  572. // reset model angle and pos to initial values
  573. SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecOffset );
  574. }
  575. else if ( m_iCameraAttachment != -1 )
  576. {
  577. UpdateCameraForIcon();
  578. }
  579. }
  580. }
  581. #ifdef STAGING_ONLY
  582. static double s_min_time = FLT_MAX;
  583. static double s_max_time = 0.f;
  584. static double s_total_time = 0.f;
  585. #endif // STAGING_ONLY
  586. //-----------------------------------------------------------------------------
  587. // Purpose:
  588. //-----------------------------------------------------------------------------
  589. void CEmbeddedItemModelPanel::Paint( void )
  590. {
  591. if ( !m_pItem || !m_pItem->IsValid() )
  592. return;
  593. if ( m_bModelIsHidden )
  594. {
  595. BaseClass::Paint();
  596. return;
  597. }
  598. // Don't even try to render backpack icon if we're not loaded
  599. if ( m_bImageNotLoaded && !m_bWeaponAllowInspect && !UseRenderTargetAsIcon() )
  600. return;
  601. const char *pszInventoryImage = m_pItem->GetInventoryImage();
  602. CMatRenderContextPtr pRenderContext( materials );
  603. int iWidth = GetWide();
  604. int iHeight = GetTall();
  605. float flTexW = 1.0;
  606. float flTexH = 1.0;
  607. float flTexX = 0.0;
  608. float flTexY = 0.0;
  609. int x = 0;
  610. int y = 0;
  611. // First, try and use the inventory image instead of the model.
  612. bool bIsLoadingWeaponSkin = IsLoadingWeaponSkin();
  613. int iTexture = -1;
  614. if ( !bIsLoadingWeaponSkin && !m_bForceUseModel )
  615. {
  616. // should we override material with cache texture
  617. if ( m_pCachedWeaponIcon && m_pCachedWeaponIcon->GetTexture() )
  618. {
  619. // Clear out the composited texture--we're finished with it.
  620. m_pItem->SetWeaponSkinBase( NULL );
  621. // The compositor should have been cleaned up by the material proxy.
  622. Assert( m_pItem->GetWeaponSkinBaseCompositor() == NULL );
  623. if ( !m_pCachedWeaponMaterial && g_pMaterialSystem )
  624. {
  625. const char *pszTextureName = m_pCachedWeaponIcon->GetTexture()->GetName();
  626. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  627. pVMTKeyValues->SetString( "$basetexture", pszTextureName );
  628. pVMTKeyValues->SetInt( "$translucent", 1 );
  629. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  630. IMaterial *pMaterial = g_pMaterialSystem->FindProceduralMaterial( pszTextureName, TEXTURE_GROUP_VGUI, pVMTKeyValues );
  631. SafeAssign( &m_pCachedWeaponMaterial, pMaterial );
  632. bool bFound = false;
  633. IMaterialVar *pVar = m_pCachedWeaponMaterial->FindVar( "$basetexture", &bFound );
  634. if ( bFound && pVar )
  635. {
  636. pVar->SetTextureValue( m_pCachedWeaponIcon->GetTexture() );
  637. m_pCachedWeaponMaterial->RefreshPreservingMaterialVars();
  638. }
  639. }
  640. if ( m_iCachedTextureID == -1 )
  641. {
  642. //m_pCachedWeaponIcon->GetTexture()->SaveToFile( CFmtStr( "%d_weapon_skin_cache.tga", m_pItem->GetItemDefIndex() ) );
  643. m_iCachedTextureID = g_pMatSystemSurface->DrawGetTextureId( m_pCachedWeaponIcon->GetTexture() );
  644. g_pMatSystemSurface->DrawSetTextureMaterial( m_iCachedTextureID, m_pCachedWeaponMaterial );
  645. }
  646. iTexture = m_iCachedTextureID;
  647. x = 0;
  648. y = 0;
  649. flTexX = flTexY = 0.f;
  650. int iMappingWidth = m_pCachedWeaponMaterial->GetMappingWidth();
  651. int iMappingHeight = m_pCachedWeaponMaterial->GetMappingHeight();
  652. if ( iWidth > iMappingWidth || iHeight > iMappingHeight )
  653. {
  654. flTexW = 1.f;
  655. flTexH = 1.f;
  656. }
  657. else
  658. {
  659. flTexW = (float)iWidth / iMappingWidth;
  660. flTexH = (float)iHeight / iMappingHeight;
  661. }
  662. #ifdef STAGING_ONLY
  663. if ( tf_unique_icon_perf_debug.GetBool() && m_flStartUpdateTime != 0 )
  664. {
  665. double flTimeTaken = Plat_FloatTime() - m_flStartUpdateTime;
  666. m_flStartUpdateTime = 0.0;
  667. s_min_time = MIN( s_min_time, flTimeTaken );
  668. s_max_time = MAX( s_max_time, flTimeTaken );
  669. s_total_time += flTimeTaken;
  670. DevMsg( "took %.3f with min %.3f max %.3f with total %.3f\n", flTimeTaken, s_min_time, s_max_time, s_total_time );
  671. }
  672. #endif // STAGING_ONLY
  673. }
  674. else if ( pszInventoryImage )
  675. {
  676. // Look up the material (use the large one if we've been told to)
  677. IMaterial *pMaterial = GetMaterialForImage( (CEmbeddedItemModelPanel::InventoryImageType_t)m_iInventoryImageType, pszInventoryImage );
  678. int iCenter[2];
  679. iCenter[0] = x + (iWidth * 0.5);
  680. iCenter[1] = y + (iHeight * 0.5);
  681. // Maintain image aspect ratios. Fit to height.
  682. int iPosition[2] = {0,0};
  683. int iSize[2] = {0,0};
  684. m_pItem->GetInventoryImageData( iPosition, iSize );
  685. if ( m_bForceSquareImage )
  686. {
  687. iSize[0] = MAX( iSize[0], iSize[1] );
  688. iSize[1] = iSize[0];
  689. }
  690. if ( !iSize[0] && !iSize[1] )
  691. {
  692. iSize[0] = pMaterial->GetMappingWidth();
  693. iSize[1] = pMaterial->GetMappingHeight();
  694. }
  695. else
  696. {
  697. bool bForceHighRes = false;
  698. #ifdef STAGING_ONLY
  699. bForceHighRes = tf_force_highres_item_image.GetBool();
  700. #endif // STAGING_ONLY
  701. if ( m_iInventoryImageType != IMAGETYPE_SMALL || bForceHighRes )
  702. {
  703. // Normal is 128*128, large is 512x512
  704. iSize[0] *= 4;
  705. iSize[1] *= 4;
  706. }
  707. flTexW = ((float)iSize[0] / (float)pMaterial->GetMappingWidth());
  708. flTexH = ((float)iSize[1] / (float)pMaterial->GetMappingHeight());
  709. flTexX = ( 1.0 - flTexW ) * 0.5;
  710. flTexY = ( 1.0 - flTexH ) * 0.5;
  711. }
  712. if ( iPosition[0] || iPosition[1] )
  713. {
  714. x += XRES(iPosition[0]);
  715. y += YRES(iPosition[1]);
  716. }
  717. float flRatio = ((float)iSize[0] / (float)iSize[1]);
  718. if ( flRatio != ((float)iWidth / (float)iHeight) )
  719. {
  720. // Fit to the height
  721. int iCenterX = x + (iWidth * 0.5);
  722. iWidth = iHeight * flRatio;
  723. x = iCenterX - (iWidth * 0.5);
  724. }
  725. // Reload our texture, if we need to
  726. if ( m_iTextureID == -1 )
  727. {
  728. m_iTextureID = vgui::surface()->DrawGetTextureId( pMaterial->GetName() );
  729. // If we didn't find it, create a new one
  730. if ( m_iTextureID == -1 )
  731. {
  732. m_iTextureID = vgui::surface()->CreateNewTextureID();
  733. g_pMatSystemSurface->DrawSetTextureMaterial( m_iTextureID, pMaterial );
  734. }
  735. }
  736. iTexture = m_iTextureID;
  737. }
  738. }
  739. // draw texture if we have a valid texture
  740. if ( iTexture != -1 )
  741. {
  742. surface()->DrawSetTexture( iTexture );
  743. if ( m_bGreyedOut )
  744. {
  745. surface()->DrawSetColor( 96, 96, 96, 255 );
  746. }
  747. else
  748. {
  749. surface()->DrawSetColor( 255, 255, 255, 255 );
  750. }
  751. surface()->DrawTexturedSubRect( x, y, x + iWidth, y + iHeight, flTexX, flTexY, flTexX + flTexW, flTexY + flTexH );
  752. // Draw the overlay image now, and tint it by the tint attribute (if we have one)
  753. for ( int i=0; i<m_pItem->GetInventoryOverlayImageCount(); i++ )
  754. {
  755. const char *pszInventoryOverlayImage = m_pItem->GetInventoryOverlayImage( i );
  756. IMaterial *pOverlayMaterial = GetMaterialForImage( (CEmbeddedItemModelPanel::InventoryImageType_t)m_iInventoryImageType, pszInventoryOverlayImage );
  757. if ( !pOverlayMaterial )
  758. continue;
  759. int iTextureIDIdx = m_iOverlayTextureIDs.Find(i);
  760. if ( (iTextureIDIdx == m_iOverlayTextureIDs.InvalidIndex()
  761. || m_iOverlayTextureIDs[iTextureIDIdx] == -1 ) )
  762. {
  763. int iTextureID = vgui::surface()->DrawGetTextureId( pOverlayMaterial->GetName() );
  764. // If we didn't find it, create a new one
  765. if ( iTextureID == -1 )
  766. {
  767. iTextureID = vgui::surface()->CreateNewTextureID();
  768. g_pMatSystemSurface->DrawSetTextureMaterial( iTextureID, pOverlayMaterial );
  769. }
  770. m_iOverlayTextureIDs.Insert( i, iTextureID );
  771. }
  772. surface()->DrawSetTexture( m_iOverlayTextureIDs[m_iOverlayTextureIDs.Find( i )] );
  773. int iRGB = m_pItem->GetModifiedRGBValue( i == 0 );
  774. Color col;
  775. col.SetColor( clamp( (iRGB & 0xFF0000) >> 16, 0, 255 ), clamp( (iRGB & 0xFF00) >> 8, 0, 255 ), clamp( (iRGB & 0xFF), 0, 255 ), 255 );
  776. // Dim this color if the item is currently greyed out
  777. float flColorScale = m_bGreyedOut ? 96.f / 255.f : 1.f;
  778. col.SetColor( col.r() * flColorScale, col.g() * flColorScale, col.b() * flColorScale, col.a() );
  779. surface()->DrawSetColor( col );
  780. surface()->DrawTexturedSubRect( x, y, x + iWidth, y + iHeight, flTexX, flTexY, flTexX + flTexW, flTexY + flTexH );
  781. }
  782. // Draw strangifier item on top of strangifier bottles
  783. if ( m_pszToolTargetItemImage && m_pszToolTargetItemImage[0] )
  784. {
  785. IMaterial* pToolTargetItemMaterial = GetMaterialForImage( (CEmbeddedItemModelPanel::InventoryImageType_t)m_iInventoryImageType, m_pszToolTargetItemImage );
  786. if ( m_iToolTargetItemTextureID == -1 )
  787. {
  788. m_iToolTargetItemTextureID = vgui::surface()->DrawGetTextureId( pToolTargetItemMaterial->GetName() );
  789. // If we didn't find it, create a new one
  790. if ( m_iToolTargetItemTextureID == -1 )
  791. {
  792. m_iToolTargetItemTextureID = vgui::surface()->CreateNewTextureID();
  793. g_pMatSystemSurface->DrawSetTextureMaterial( m_iToolTargetItemTextureID, pToolTargetItemMaterial );
  794. }
  795. CAttribute_String attrToolTargetItemIconOffset;
  796. static CSchemaAttributeDefHandle pAttrDef_ToolTargetItemIconOffset( "tool_target_item_icon_offset" );
  797. if ( m_pItem->FindAttribute( pAttrDef_ToolTargetItemIconOffset, &attrToolTargetItemIconOffset ) && attrToolTargetItemIconOffset.has_value() )
  798. {
  799. UTIL_StringToVector( m_vecToolTargetItemImageOffset.Base(), attrToolTargetItemIconOffset.value().c_str() );
  800. }
  801. }
  802. surface()->DrawSetTexture( m_iToolTargetItemTextureID );
  803. int iStrangeX = x + ( iWidth * m_vecToolTargetItemImageOffset.x );
  804. int iStrangeY = y + ( iHeight * m_vecToolTargetItemImageOffset.y );
  805. float flScale = m_vecToolTargetItemImageOffset.z;
  806. surface()->DrawTexturedSubRect( iStrangeX,
  807. iStrangeY,
  808. iStrangeX + (iWidth * flScale),
  809. iStrangeY + (iHeight * flScale),
  810. flTexX,
  811. flTexY,
  812. flTexX + (flTexW ),
  813. flTexY + (flTexH ) );
  814. }
  815. return;
  816. }
  817. item_model_cache_t *pCacheRenderTarget = NULL;
  818. const char *pszCacheRenderTargetName = NULL;
  819. // find available render target
  820. for ( int i=0; i<ITEM_MODEL_IMAGE_CACHE_SIZE; ++i )
  821. {
  822. CEmbeddedItemModelPanel *pLockPanel = g_ItemModelImageCache[i].m_hModelPanelLock.Get();
  823. // found available render target?
  824. if ( pLockPanel == NULL )
  825. {
  826. pszCacheRenderTargetName = m_bOfflineIconGeneration ? "offline_icon_generation" : g_ItemModelPanelRenderTargetNames[i];
  827. pCacheRenderTarget = &g_ItemModelImageCache[i];
  828. break;
  829. }
  830. else
  831. {
  832. // waiting for async copy to finish
  833. if ( pLockPanel->m_pCachedWeaponIcon && pLockPanel->m_pCachedWeaponIcon->GetTexture() )
  834. {
  835. g_ItemModelImageCache[i].Clear();
  836. pszCacheRenderTargetName = m_bOfflineIconGeneration ? "offline_icon_generation" : g_ItemModelPanelRenderTargetNames[i];
  837. pCacheRenderTarget = &g_ItemModelImageCache[i];
  838. break;
  839. }
  840. }
  841. }
  842. // can't find available cache render target, don't do anything
  843. if ( !pszCacheRenderTargetName || !pCacheRenderTarget )
  844. {
  845. BaseClass::Paint();
  846. return;
  847. }
  848. // Turn off depth-write to dest alpha so that we get white there instead. The code that uses
  849. // the render target needs a mask of where stuff was rendered.
  850. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, false );
  851. bool bUseRenderTarget = !m_bForceUseModel && ( UseRenderTargetAsIcon() || bIsLoadingWeaponSkin );
  852. bool bRenderToTexture = m_bRenderToTexture;
  853. if ( bUseRenderTarget )
  854. {
  855. g_pMatSystemSurface->Set3DPaintTempRenderTarget( pszCacheRenderTargetName );
  856. }
  857. else if ( m_bUseParticle )
  858. {
  859. // we want to render particle with this model. don't render to texture
  860. m_bRenderToTexture = false;
  861. }
  862. // make sure the weapon skin is ready before we render the model
  863. bool bDrawWeaponWithSkin = bIsLoadingWeaponSkin && m_pCachedWeaponIcon == NULL && m_pItem->GetWeaponSkinBase();
  864. m_pItem->SetWeaponSkinBaseCreateFlags( TEX_COMPOSITE_CREATE_FLAGS_NO_COMPRESSION | TEX_COMPOSITE_CREATE_FLAGS_NO_MIPMAPS );
  865. BaseClass::Paint();
  866. m_bRenderToTexture = bRenderToTexture;
  867. // copy the rendered weapon skin from the render target
  868. if ( !m_bForceUseModel && ( UseRenderTargetAsIcon() || bDrawWeaponWithSkin ) && !m_pCachedWeaponIcon )
  869. {
  870. char buffer[_MAX_PATH];
  871. V_sprintf_safe( buffer, "proc/icon/item%d_id%lld_w%d_h%d", m_pItem->GetItemDefIndex(), m_pItem->GetID(), iWidth, iHeight );
  872. SafeAssign( &m_pCachedWeaponIcon, new CIconRenderReceiver() );
  873. // If the icon still exists in the material system, don't bother regenerating it.
  874. if ( materials->IsTextureLoaded( buffer ) )
  875. {
  876. ITexture* resTexture = materials->FindTexture( buffer, TEXTURE_GROUP_RUNTIME_COMPOSITE, false, 0 );
  877. if ( resTexture && resTexture->IsError() == false )
  878. {
  879. m_pCachedWeaponIcon->OnAsyncCreateComplete( resTexture, NULL );
  880. }
  881. }
  882. else
  883. {
  884. // No icon available yet, need to create it.
  885. ITexture *pRenderTarget = g_pMaterialSystem->FindTexture( pszCacheRenderTargetName, TEXTURE_GROUP_RENDER_TARGET );
  886. if ( pRenderTarget )
  887. {
  888. pRenderContext->AsyncCreateTextureFromRenderTarget( pRenderTarget, buffer, IMAGE_FORMAT_RGBA8888, false, 0, m_pCachedWeaponIcon, NULL );
  889. pCacheRenderTarget->iItemID = m_pItem->GetItemID();
  890. pCacheRenderTarget->iItemDefinitionIndex = m_pItem->GetItemDefIndex();
  891. pCacheRenderTarget->iWidth = iWidth;
  892. pCacheRenderTarget->iHeight = iHeight;
  893. pCacheRenderTarget->m_hModelPanelLock = this;
  894. }
  895. }
  896. }
  897. if ( bUseRenderTarget )
  898. {
  899. g_pMatSystemSurface->Reset3DPaintTempRenderTarget();
  900. }
  901. if ( m_flModelRotateYawSpeed != 0 )
  902. {
  903. m_angPlayer[YAW] += m_flModelRotateYawSpeed * gpGlobals->frametime;
  904. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  905. }
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Purpose:
  909. //-----------------------------------------------------------------------------
  910. ITexture *CEmbeddedItemModelPanel::GetCachedGeneratedIcon()
  911. {
  912. return m_pCachedWeaponIcon ? m_pCachedWeaponIcon->GetTexture() : NULL;
  913. }
  914. //-----------------------------------------------------------------------------
  915. // Purpose:
  916. //-----------------------------------------------------------------------------
  917. bool CEmbeddedItemModelPanel::UpdateParticle(
  918. IMatRenderContext *pRenderContext,
  919. CStudioHdr *pStudioHdr,
  920. MDLHandle_t mdlHandle,
  921. matrix3x4_t *pWorldMatrix
  922. )
  923. {
  924. if ( !m_bUseParticle )
  925. return false;
  926. if ( m_pItemParticle && m_pItemParticle->m_bIsUpdateToDate )
  927. return false;
  928. if ( !m_pItem || !m_pItem->IsValid() )
  929. return false;
  930. attachedparticlesystem_t *pParticleSystem = NULL;
  931. // do community_sparkle effect if this is a community item?
  932. const int iQualityParticleType = m_pItem->GetQualityParticleType();
  933. if ( iQualityParticleType > 0 )
  934. {
  935. pParticleSystem = GetItemSchema()->GetAttributeControlledParticleSystem( iQualityParticleType );
  936. }
  937. if ( !pParticleSystem )
  938. {
  939. // does this hat even have a particle effect
  940. static CSchemaAttributeDefHandle pAttrDef_AttachParticleEffect( "attach particle effect" );
  941. uint32 iValue = 0;
  942. if ( !m_pItem->FindAttribute( pAttrDef_AttachParticleEffect, &iValue ) )
  943. {
  944. return false;
  945. }
  946. const float& value_as_float = (float&)iValue;
  947. pParticleSystem = GetItemSchema()->GetAttributeControlledParticleSystem( value_as_float );
  948. }
  949. // failed to find any particle effect
  950. if ( !pParticleSystem )
  951. {
  952. return false;
  953. }
  954. // Team Color
  955. if ( m_pItem->GetTeamNumber() == TF_TEAM_BLUE && V_stristr( pParticleSystem->pszSystemName, "_teamcolor_red" ))
  956. {
  957. static char pBlue[256];
  958. V_StrSubst( pParticleSystem->pszSystemName, "_teamcolor_red", "_teamcolor_blue", pBlue, 256 );
  959. pParticleSystem = GetItemSchema()->FindAttributeControlledParticleSystem( pBlue );
  960. if ( !pParticleSystem )
  961. {
  962. return false;
  963. }
  964. }
  965. // if this thing has a bip_head or prp_helmet (aka a hat)
  966. int iBone = Studio_BoneIndexByName( pStudioHdr, "bip_head" );
  967. if ( iBone < 0 )
  968. {
  969. iBone = Studio_BoneIndexByName( pStudioHdr, "prp_helmet" );
  970. if ( iBone < 0 )
  971. {
  972. iBone = Studio_BoneIndexByName( pStudioHdr, "prp_hat" );
  973. }
  974. }
  975. // default to root
  976. if ( iBone < 0 )
  977. {
  978. iBone = 0;
  979. }
  980. // Get Use Head Origin
  981. CUtlVector< int > vecAttachments;
  982. static CSchemaAttributeDefHandle pAttrDef_UseHead( "particle effect use head origin" );
  983. uint32 iUseHead = 0;
  984. if ( !m_pItem->FindAttribute( pAttrDef_UseHead, &iUseHead ) || !iUseHead == 0 )
  985. {
  986. // not using head? try searching for attachment points
  987. for ( int i=0; i<ARRAYSIZE( pParticleSystem->pszControlPoints ); ++i )
  988. {
  989. const char *pszAttachmentName = pParticleSystem->pszControlPoints[i];
  990. if ( pszAttachmentName && pszAttachmentName[0] )
  991. {
  992. int iAttachment = Studio_FindAttachment( pStudioHdr, pszAttachmentName );
  993. if ( iAttachment < 0 )
  994. continue;
  995. vecAttachments.AddToTail( iAttachment );
  996. }
  997. }
  998. }
  999. static char pszFullname[256];
  1000. const char* pszSystemName = pParticleSystem->pszSystemName;
  1001. // Weapon Remap for a Base Effect to be used on a specific weapon
  1002. if ( pParticleSystem->bUseSuffixName && m_pItem && m_pItem->GetItemDefinition()->GetParticleSuffix() )
  1003. {
  1004. V_strcpy_safe( pszFullname, pParticleSystem->pszSystemName );
  1005. V_strcat_safe( pszFullname, "_" );
  1006. V_strcat_safe( pszFullname, m_pItem->GetItemDefinition()->GetParticleSuffix() );
  1007. pszSystemName = pszFullname;
  1008. }
  1009. // Update the Particles and render them
  1010. if ( m_pItemParticle )
  1011. {
  1012. // Check if its a new particle system
  1013. if ( V_strcmp( m_pItemParticle->m_pParticleSystem->GetName(), pszSystemName ) )
  1014. {
  1015. SafeDeleteParticleData( &m_pItemParticle );
  1016. m_pItemParticle = CreateParticleData( pszSystemName );
  1017. }
  1018. }
  1019. else
  1020. {
  1021. // create
  1022. m_pItemParticle = CreateParticleData( pszSystemName );
  1023. }
  1024. // Particle system does not exist
  1025. if ( !m_pItemParticle )
  1026. return false;
  1027. // Get offset if it exists (and if we're using head offset)
  1028. static CSchemaAttributeDefHandle pAttrDef_VerticalOffset( "particle effect vertical offset" );
  1029. uint32 iOffset = 0;
  1030. Vector vecParticleOffset( 0, 0, 0 );
  1031. if ( iUseHead > 0 && m_pItem->FindAttribute( pAttrDef_VerticalOffset, &iOffset ) )
  1032. {
  1033. vecParticleOffset.z = (float&)iOffset;
  1034. }
  1035. m_pItemParticle->UpdateControlPoints( pStudioHdr, pWorldMatrix, vecAttachments, 0, vecParticleOffset );
  1036. return true;
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // Purpose:
  1040. //-----------------------------------------------------------------------------
  1041. bool CEmbeddedItemModelPanel::RenderStatTrack( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix )
  1042. {
  1043. // Draw the merge MDLs.
  1044. if ( !m_StatTrackModel.m_bDisabled )
  1045. {
  1046. matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES];
  1047. // Get the merge studio header.
  1048. studiohdr_t *pStatTrackStudioHdr = m_StatTrackModel.m_MDL.GetStudioHdr();
  1049. matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0];
  1050. // If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because
  1051. // it'll crash trying to pull data from the missing header.
  1052. if ( pStatTrackStudioHdr != NULL )
  1053. {
  1054. CStudioHdr mergeHdr( pStatTrackStudioHdr, g_pMDLCache );
  1055. m_StatTrackModel.m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, pStudioHdr, pWorldMatrix, m_StatTrackModel.m_MDLToWorld );
  1056. for ( int i=0; i<mergeHdr.numbones(); ++i )
  1057. {
  1058. MatrixScaleBy( m_flStatTrackScale, pMergeBoneToWorld[i] );
  1059. }
  1060. m_StatTrackModel.m_MDL.Draw( m_StatTrackModel.m_MDLToWorld, pMergeBoneToWorld );
  1061. }
  1062. return true;
  1063. }
  1064. return false;
  1065. }
  1066. bool CEmbeddedItemModelPanel::RenderAttachedModels( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix )
  1067. {
  1068. // Draw the merge MDLs.
  1069. FOR_EACH_VEC( m_AttachedModels, iModel )
  1070. {
  1071. matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES];
  1072. // Get the merge studio header.
  1073. studiohdr_t *pAttachedStudioHdr = m_AttachedModels[iModel].m_MDL.GetStudioHdr();
  1074. matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0];
  1075. // If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because
  1076. // it'll crash trying to pull data from the missing header.
  1077. if ( pAttachedStudioHdr != NULL )
  1078. {
  1079. CStudioHdr mergeHdr( pAttachedStudioHdr, g_pMDLCache );
  1080. m_AttachedModels[iModel].m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, pStudioHdr, pWorldMatrix, m_AttachedModels[iModel].m_MDLToWorld );
  1081. m_AttachedModels[iModel].m_MDL.Draw( m_AttachedModels[iModel].m_MDLToWorld, pMergeBoneToWorld );
  1082. }
  1083. }
  1084. return true;
  1085. }
  1086. //-----------------------------------------------------------------------------
  1087. // Purpose:
  1088. //-----------------------------------------------------------------------------
  1089. void CEmbeddedItemModelPanel::RenderingRootModel( IMatRenderContext *pRenderContext, CStudioHdr *pStudioHdr, MDLHandle_t mdlHandle, matrix3x4_t *pWorldMatrix )
  1090. {
  1091. // No model? Bail
  1092. if ( m_ItemModel.m_bDisabled )
  1093. {
  1094. // no model means not using pedestal. just use pStudioHdr to find the attachment points
  1095. UpdateParticle( pRenderContext, pStudioHdr, mdlHandle, pWorldMatrix );
  1096. RenderStatTrack( pStudioHdr, pWorldMatrix );
  1097. RenderAttachedModels( pStudioHdr, pWorldMatrix );
  1098. return;
  1099. }
  1100. studiohdr_t *pItemStudioHdr = m_ItemModel.m_MDL.GetStudioHdr();
  1101. if ( pItemStudioHdr != NULL )
  1102. {
  1103. matrix3x4_t matIdentity;
  1104. SetIdentityMatrix( matIdentity );
  1105. matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( pItemStudioHdr->numbones );
  1106. m_ItemModel.m_MDL.SetUpBones( matIdentity, pItemStudioHdr->numbones, pBoneToWorld );
  1107. // Get attachment transform
  1108. mstudioattachment_t attach = pItemStudioHdr->pAttachment( m_iPedestalAttachment );
  1109. matrix3x4_t matLocalToWorld;
  1110. matrix3x4_t matWorldToLocal;
  1111. matrix3x4_t matTransform;
  1112. ConcatTransforms( pBoneToWorld[ attach.localbone ], attach.local, matLocalToWorld );
  1113. MatrixInvert( matLocalToWorld, matWorldToLocal );
  1114. ConcatTransforms( m_RootMDL.m_MDLToWorld, matWorldToLocal, matTransform );
  1115. m_ItemModel.m_MDL.SetUpBones( matTransform, pItemStudioHdr->numbones, pBoneToWorld );
  1116. g_pStudioRender->UnlockBoneMatrices();
  1117. IMaterial* pOverrideMaterial = GetOverrideMaterial( m_ItemModel.m_MDL.GetMDL() );
  1118. if ( pOverrideMaterial != NULL )
  1119. g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial );
  1120. m_ItemModel.m_MDL.Draw( m_ItemModel.m_MDLToWorld, pBoneToWorld );
  1121. if ( pOverrideMaterial != NULL )
  1122. g_pStudioRender->ForcedMaterialOverride( NULL );
  1123. CStudioHdr HDR( pItemStudioHdr, g_pMDLCache );
  1124. // update particle with the actual item model pItemStudioHdr
  1125. UpdateParticle( pRenderContext, &HDR, mdlHandle, pBoneToWorld );
  1126. RenderStatTrack( &HDR, pBoneToWorld );
  1127. RenderAttachedModels( &HDR, pBoneToWorld );
  1128. }
  1129. }
  1130. //-----------------------------------------------------------------------------
  1131. // Purpose:
  1132. //-----------------------------------------------------------------------------
  1133. IMaterial *CEmbeddedItemModelPanel::GetOverrideMaterial( MDLHandle_t mdlHandle )
  1134. {
  1135. // This matches the check in RenderingRootModel, if we're not on a pedestal
  1136. // then we expect mdlHandle to not match m_ItemModel and that's fine--we should
  1137. // just get the override from the m_pItem
  1138. if ( !m_ItemModel.m_bDisabled && m_ItemModel.m_MDL.GetMDL() != mdlHandle )
  1139. return NULL;
  1140. if ( !m_pItem )
  1141. return NULL;
  1142. int iTeam = GetLocalPlayerTeam();
  1143. #ifdef TF_CLIENT_DLL
  1144. // If we aren't in a game we default to previewing the red team skin.
  1145. if ( iTeam == TEAM_UNASSIGNED )
  1146. {
  1147. iTeam = TF_TEAM_RED;
  1148. }
  1149. #endif
  1150. return m_pItem->GetMaterialOverride( iTeam );
  1151. }
  1152. float CItemModelPanel::sm_flLoadingTimeThisFrame = 0.0f;
  1153. int CItemModelPanel::sm_nCurrentDecriptionUpdateFrame = 0;
  1154. CItemModelPanel::eLoadingType_t CItemModelPanel::se_CurrentLoadingTask = LOADING_ICONS;
  1155. int CItemModelPanel::sai_NumLoadingRequests[NUM_LOADING_TYPES] = {0,0,0};
  1156. //-----------------------------------------------------------------------------
  1157. // Purpose:
  1158. //-----------------------------------------------------------------------------
  1159. CItemModelPanel::CItemModelPanel( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name )
  1160. {
  1161. m_pModelPanel = NULL;
  1162. m_pItemNameLabel = NULL;
  1163. m_pPaintIcon = NULL;
  1164. m_pTF2Icon = NULL;
  1165. m_pItemAttribLabel = NULL;
  1166. m_pItemCollectionNameLabel = NULL;
  1167. m_pItemCollectionListLabel = NULL;
  1168. m_pItemCollectionHighlight = NULL;
  1169. m_pItemEquippedLabel = NULL;
  1170. m_pItemQuantityLabel = NULL;
  1171. m_pVisionRestrictionImage = NULL;
  1172. m_pIsStrangeImage = NULL;
  1173. m_pIsUnusualImage = NULL;
  1174. m_pIsLoanerImage = NULL;
  1175. m_pSeriesLabel = NULL;
  1176. m_pMainContentContainer = NULL;
  1177. m_pLoadingSpinner = NULL;
  1178. // m_ItemData = NULL;
  1179. m_nCollectionItemLoaded = LOADED_COLLECTION_NONE;
  1180. m_pFontNameSmallest = vgui::INVALID_FONT;
  1181. m_pFontNameSmall = vgui::INVALID_FONT;
  1182. m_pFontNameLarge = vgui::INVALID_FONT;
  1183. m_pFontAttribSmallest = vgui::INVALID_FONT;
  1184. m_pFontAttribSmall = vgui::INVALID_FONT;
  1185. m_pFontAttribLarge = vgui::INVALID_FONT;
  1186. m_pszNoItemText = NULL;
  1187. m_pwcNoItemText = NULL;
  1188. m_pwcNoItemAttrib = NULL;
  1189. REGISTER_COLOR_AS_OVERRIDABLE( m_NoItemTextColor, "noitem_textcolor" );
  1190. m_bClickable = false;
  1191. m_bMouseOver = false;
  1192. m_bSelected = false;
  1193. m_bShowEquipped = false;
  1194. m_bForceShowEquipped = false;
  1195. m_bShowQuantity = false;
  1196. m_pszGreyedOutReason = NULL;
  1197. m_bShowGreyedOutTooltip = false;
  1198. m_bShouldSendPanelEnterExits = false;
  1199. m_bContainedItem = false;
  1200. m_bShowOthersGiftWrappedItems = false;
  1201. m_bDescriptionDirty = false;
  1202. m_nRecipeMatchingIndex = 0;
  1203. m_pContainedItemPanel = NULL;
  1204. m_bFakeButton = false;
  1205. m_mapMatchingAttributes.SetLessFunc( DefLessFunc( attrib_definition_index_t ) );
  1206. SetActAsButton( false, false );
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. // Purpose:
  1210. //-----------------------------------------------------------------------------
  1211. CItemModelPanel::~CItemModelPanel( void )
  1212. {
  1213. CleanupNoItemWChars();
  1214. }
  1215. //-----------------------------------------------------------------------------
  1216. // Purpose:
  1217. //-----------------------------------------------------------------------------
  1218. void CItemModelPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  1219. {
  1220. BaseClass::ApplySchemeSettings( pScheme );
  1221. // These pointers must be zeroed here because their memory may be freed
  1222. // by LoadControlSettings *and* if they remain non-zero they may be dereferenced
  1223. // before LoadControlSettings returns. This causes reliable crashes if you
  1224. // go to the store, shop, change resolutions, then return to the store -- and
  1225. // if you use pageheap/AppVerifier.
  1226. // This set of pointers is simply the set of pointers that are initialized after
  1227. // LoadControlSettings.
  1228. m_pModelPanel = NULL;
  1229. m_pItemNameLabel = NULL;
  1230. m_pItemAttribLabel = NULL;
  1231. m_pItemCollectionNameLabel = NULL;
  1232. m_pItemCollectionListLabel = NULL;
  1233. m_pItemEquippedLabel = NULL;
  1234. m_pItemQuantityLabel = NULL;
  1235. m_pVisionRestrictionImage = NULL;
  1236. m_pIsStrangeImage = NULL;
  1237. m_pIsUnusualImage = NULL;
  1238. m_pIsLoanerImage = NULL;
  1239. m_pSeriesLabel = NULL;
  1240. m_pMatchesLabel = NULL;
  1241. m_pPaintIcon = NULL;
  1242. m_pTF2Icon = NULL;
  1243. m_pFontNameSmallest = NULL;
  1244. m_pFontNameSmall = NULL;
  1245. m_pFontNameLarge = NULL;
  1246. m_pFontNameLarger = NULL;
  1247. m_pFontAttribSmallest = NULL;
  1248. m_pFontAttribSmall = NULL;
  1249. m_pFontAttribLarge = NULL;
  1250. m_pFontAttribLarger = NULL;
  1251. m_pContainedItemPanel = NULL;
  1252. m_pMainContentContainer = NULL;
  1253. m_pLoadingSpinner = NULL;
  1254. m_nCollectionItemLoaded = LOADED_COLLECTION_NONE;
  1255. LoadResFileForCurrentItem( true );
  1256. m_pFontNameSmallest = pScheme->GetFont( "ItemFontNameSmallest", true );
  1257. m_pFontNameSmall = pScheme->GetFont( "ItemFontNameSmall", true );
  1258. m_pFontNameLarge = pScheme->GetFont( "ItemFontNameLarge", true );
  1259. m_pFontNameLarger = pScheme->GetFont( "ItemFontNameLarger", true );
  1260. m_pFontAttribSmallest = pScheme->GetFont( "ItemFontAttribSmallest", true );
  1261. m_pFontAttribSmall = pScheme->GetFont( "ItemFontAttribSmallv2", true );
  1262. m_pFontAttribLarge = pScheme->GetFont( "ItemFontAttribLarge", true );
  1263. m_pFontAttribLarger = pScheme->GetFont( "ItemFontAttribLarger", true );
  1264. if ( m_bContainedItem )
  1265. {
  1266. // SetBorder( pScheme->GetBorder("TFThinLineBorder") );
  1267. }
  1268. else
  1269. {
  1270. SetBorder( pScheme->GetBorder( "TFFatLineBorder" ) );
  1271. }
  1272. if ( m_pModelPanel )
  1273. {
  1274. m_pModelPanel->SetBorder( pScheme->GetBorder( "TFFatLineBorder" ) );
  1275. }
  1276. }
  1277. void CItemModelPanel::ApplySettings( KeyValues *inResourceData )
  1278. {
  1279. if ( !inResourceData )
  1280. return;
  1281. BaseClass::ApplySettings( inResourceData );
  1282. // Pass the itemmodelpanel KVs to the actual model panel
  1283. KeyValues* pItemModelPanelKVs = inResourceData->FindKey( "itemmodelpanel" );
  1284. if ( m_pModelPanel && pItemModelPanelKVs )
  1285. {
  1286. m_pModelPanel->ApplySettings( pItemModelPanelKVs );
  1287. }
  1288. // We can get our settings applied AFTER we've already setup our
  1289. // panel, so re-update.
  1290. UpdatePanels();
  1291. }
  1292. void CItemModelPanel::LoadResFileForCurrentItem( bool bForceLoad )
  1293. {
  1294. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1295. bool bCollectionMouseover = ( m_bIsMouseOverPanel && GetItem() && GetItem()->GetItemDefinition()->GetItemCollectionDefinition() );
  1296. if ( bCollectionMouseover )
  1297. {
  1298. float flInspect = 0;
  1299. static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
  1300. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( GetItem(), pAttrib_WeaponAllowInspect, &flInspect ) && flInspect != 0.f )
  1301. {
  1302. if ( bForceLoad || m_nCollectionItemLoaded != LOADED_COLLECTION_WEAPON )
  1303. {
  1304. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s ItemModelPanelCollectionItem", __FUNCTION__ );
  1305. LoadControlSettings( "Resource/UI/econ/ItemModelPanelCollectionItem.res" );
  1306. m_nCollectionItemLoaded = LOADED_COLLECTION_WEAPON;
  1307. }
  1308. }
  1309. else
  1310. {
  1311. if ( bForceLoad || m_nCollectionItemLoaded != LOADED_COLLECTION_COSMETIC )
  1312. {
  1313. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s ItemModelPanelCollectionCosmeticItem", __FUNCTION__ );
  1314. LoadControlSettings( "Resource/UI/econ/ItemModelPanelCollectionCosmeticItem.res" );
  1315. m_nCollectionItemLoaded = LOADED_COLLECTION_COSMETIC;
  1316. }
  1317. }
  1318. m_bHideModel = false; // Hack
  1319. }
  1320. else
  1321. {
  1322. if ( bForceLoad || m_nCollectionItemLoaded != LOADED_COLLECTION_NONE )
  1323. {
  1324. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s ItemModelPanel", __FUNCTION__ );
  1325. LoadControlSettings( "Resource/UI/econ/ItemModelPanel.res" );
  1326. }
  1327. m_bHideModel = m_bHideModelDefault;
  1328. m_nCollectionItemLoaded = LOADED_COLLECTION_NONE;
  1329. }
  1330. m_pModelPanel = dynamic_cast<CEmbeddedItemModelPanel*>( FindChildByName( "itemmodelpanel", true ) );
  1331. SetModelIsHidden( m_bHideModel );
  1332. if ( m_bIsMouseOverPanel && m_pModelPanel )
  1333. {
  1334. m_pModelPanel->SetInventoryImageType( CEmbeddedItemModelPanel::IMAGETYPE_LARGE );
  1335. }
  1336. m_pItemNameLabel = dynamic_cast<CExLabel*>( FindChildByName( "namelabel", true ) );
  1337. m_pItemAttribLabel = dynamic_cast<vgui::Label*>( FindChildByName( "attriblabel", true ) );
  1338. m_pItemCollectionNameLabel = dynamic_cast<CExLabel*>( FindChildByName( "collectionnamelabel", true ) );
  1339. m_pItemCollectionListLabel = dynamic_cast<vgui::Label*>( FindChildByName( "collectionlistlabel", true ) );
  1340. m_pItemCollectionHighlight = dynamic_cast<vgui::EditablePanel*>( FindChildByName( "collectionhighlight", true ) );
  1341. m_pItemEquippedLabel = dynamic_cast<vgui::Label*>( FindChildByName( "equippedlabel", true ) );
  1342. m_pItemQuantityLabel = dynamic_cast<vgui::Label*>( FindChildByName( "quantitylabel", true ) );
  1343. m_pVisionRestrictionImage = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "vision_restriction_icon", true ) );
  1344. m_pIsStrangeImage = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "is_strange_icon", true ) );
  1345. m_pIsUnusualImage = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "is_unusual_icon", true ) );
  1346. m_pIsLoanerImage = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "is_loaner_icon", true ) );
  1347. m_pSeriesLabel = dynamic_cast<vgui::Label*>( FindChildByName( "serieslabel", true ) );
  1348. m_pMatchesLabel = dynamic_cast<vgui::Label*>( FindChildByName( "matcheslabel", true ) );
  1349. m_pMainContentContainer = dynamic_cast<vgui::EditablePanel*>( FindChildByName( "MainContentsContainer" ) );
  1350. m_pLoadingSpinner = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "LoadingSpinner" ) );
  1351. if ( m_pItemEquippedLabel )
  1352. {
  1353. m_pItemEquippedLabel->SetKeyBoardInputEnabled( false );
  1354. m_pItemEquippedLabel->SetMouseInputEnabled( false );
  1355. }
  1356. if ( m_pItemQuantityLabel )
  1357. {
  1358. m_pItemQuantityLabel->SetKeyBoardInputEnabled( false );
  1359. m_pItemQuantityLabel->SetMouseInputEnabled( false );
  1360. }
  1361. if ( m_pVisionRestrictionImage )
  1362. {
  1363. m_pVisionRestrictionImage->SetKeyBoardInputEnabled( false );
  1364. m_pVisionRestrictionImage->SetMouseInputEnabled( false );
  1365. }
  1366. if ( m_pIsStrangeImage )
  1367. {
  1368. m_pIsStrangeImage->SetKeyBoardInputEnabled( false );
  1369. m_pIsStrangeImage->SetMouseInputEnabled( false );
  1370. }
  1371. if ( m_pIsUnusualImage )
  1372. {
  1373. m_pIsUnusualImage->SetKeyBoardInputEnabled( false );
  1374. m_pIsUnusualImage->SetMouseInputEnabled( false );
  1375. }
  1376. if ( m_pIsLoanerImage )
  1377. {
  1378. m_pIsLoanerImage->SetKeyBoardInputEnabled( false );
  1379. m_pIsLoanerImage->SetMouseInputEnabled( false );
  1380. }
  1381. if ( m_pSeriesLabel )
  1382. {
  1383. m_pSeriesLabel->SetKeyBoardInputEnabled( false );
  1384. m_pSeriesLabel->SetMouseInputEnabled( false );
  1385. }
  1386. if ( m_pMatchesLabel )
  1387. {
  1388. m_pMatchesLabel->SetKeyBoardInputEnabled( false );
  1389. m_pMatchesLabel->SetMouseInputEnabled( false );
  1390. }
  1391. m_pPaintIcon = dynamic_cast<CItemMaterialCustomizationIconPanel*>( FindChildByName( "paint_icon", true ) );
  1392. if ( m_pPaintIcon )
  1393. {
  1394. m_pPaintIcon->SetMouseInputEnabled( false );
  1395. }
  1396. m_pTF2Icon = dynamic_cast<vgui::ScalableImagePanel*>( FindChildByName( "tf2_icon", true ) );
  1397. if ( m_pTF2Icon )
  1398. {
  1399. m_pTF2Icon->SetMouseInputEnabled( false );
  1400. }
  1401. if ( m_bContainedItem )
  1402. {
  1403. SetPaintBackgroundEnabled( true );
  1404. }
  1405. else
  1406. {
  1407. SetPaintBackgroundEnabled( false );
  1408. }
  1409. if ( m_pModelPanel )
  1410. {
  1411. m_pModelPanel->SetBgColor( Color( 0, 0, 0, 255 ) );
  1412. m_pModelPanel->AddActionSignalTarget( this );
  1413. m_pModelPanel->SetMouseInputEnabled( false );
  1414. }
  1415. if ( m_pItemNameLabel )
  1416. {
  1417. m_OrgItemTextColor = m_pItemNameLabel->GetFgColor();
  1418. m_pItemNameLabel->SetMouseInputEnabled( false );
  1419. m_pItemNameLabel->AddActionSignalTarget( this );
  1420. m_pItemNameLabel->InvalidateLayout( true, true );
  1421. }
  1422. if ( m_pItemAttribLabel )
  1423. {
  1424. m_pItemAttribLabel->SetMouseInputEnabled( false );
  1425. m_pItemAttribLabel->AddActionSignalTarget( this );
  1426. m_pItemAttribLabel->InvalidateLayout( true, true );
  1427. }
  1428. if ( m_pItemCollectionNameLabel )
  1429. {
  1430. m_pItemCollectionNameLabel->SetMouseInputEnabled( false );
  1431. m_pItemCollectionNameLabel->AddActionSignalTarget( this );
  1432. m_pItemCollectionNameLabel->InvalidateLayout( true, true );
  1433. }
  1434. if ( m_pItemCollectionListLabel )
  1435. {
  1436. m_pItemCollectionListLabel->SetMouseInputEnabled( false );
  1437. m_pItemCollectionListLabel->AddActionSignalTarget( this );
  1438. m_pItemCollectionListLabel->InvalidateLayout( true, true );
  1439. }
  1440. if ( m_pItemCollectionHighlight )
  1441. {
  1442. m_pItemCollectionHighlight->SetMouseInputEnabled( false );
  1443. m_pItemCollectionHighlight->AddActionSignalTarget( this );
  1444. m_pItemCollectionHighlight->InvalidateLayout( true, true );
  1445. }
  1446. m_pContainedItemPanel = dynamic_cast<CItemModelPanel*>( FindChildByName( "contained_item_panel", true ) );
  1447. // Dont eat mouse input
  1448. if ( m_pMainContentContainer )
  1449. {
  1450. m_pMainContentContainer->SetMouseInputEnabled( false );
  1451. }
  1452. UpdatePanels();
  1453. }
  1454. //-----------------------------------------------------------------------------
  1455. // Purpose:
  1456. //-----------------------------------------------------------------------------
  1457. void CItemModelPanel::PerformLayout( void )
  1458. {
  1459. int w,h;
  1460. GetSize( w, h );
  1461. w = m_iBaseWide ? m_iBaseWide : w;
  1462. h = m_iBaseTall ? m_iBaseTall : h;
  1463. int iTextW = GetAttribWide(w);
  1464. int iModelW = m_iModelWide && m_iModelWide < w ? m_iModelWide : w;
  1465. int iModelT = m_iModelTall && m_iModelTall < h ? m_iModelTall : h;
  1466. int iModelX = m_bModelCenterX ? ( ( w - iModelW ) * 0.5 ) : m_iModelXPos;
  1467. int iModelY = m_bModelCenterY ? ( ( h - iModelT ) * 0.5 ) : m_iModelYPos;
  1468. ResizeLabels();
  1469. if ( m_pModelPanel )
  1470. {
  1471. m_pModelPanel->SetBounds( iModelX, iModelY, iModelW, iModelT );
  1472. }
  1473. if ( m_pLoadingSpinner )
  1474. {
  1475. int nWidthHeight = Max( iModelW, iModelT );
  1476. int xOffset = int( w / 2.f ) - int( nWidthHeight / 2.f );
  1477. int yOffset = int( h / 2.f ) - int( nWidthHeight / 2.f );
  1478. m_pLoadingSpinner->SetBounds( xOffset, yOffset, nWidthHeight, nWidthHeight );
  1479. }
  1480. if ( m_bNoItemFullPanel )
  1481. {
  1482. // We want the "no item" text to use the entire panel, and hide the attribs entirely
  1483. if ( m_pItemNameLabel && m_pItemAttribLabel )
  1484. {
  1485. m_pItemNameLabel->SetBounds( XRES(4), 0, GetWide() - XRES(8), GetTall() );
  1486. }
  1487. }
  1488. else if ( m_pItemNameLabel && m_pItemAttribLabel && !m_bModelOnly )
  1489. {
  1490. // Force the labels to layout now, and get their height.
  1491. m_pItemNameLabel->InvalidateLayout( true );
  1492. m_pItemAttribLabel->InvalidateLayout( true );
  1493. m_pItemNameLabel->SizeToContents();
  1494. m_pItemAttribLabel->SizeToContents();
  1495. if ( m_pItemCollectionNameLabel )
  1496. {
  1497. m_pItemCollectionNameLabel->InvalidateLayout( true );
  1498. m_pItemCollectionNameLabel->SizeToContents();
  1499. }
  1500. if ( m_pItemCollectionListLabel )
  1501. {
  1502. m_pItemCollectionListLabel->InvalidateLayout( true );
  1503. m_pItemCollectionListLabel->SizeToContents();
  1504. }
  1505. // "" strings still size themselves as one font-heighth tall, but 0 wide. If there's no
  1506. // text in the attribute, we want 0 tall as well, so we don't get blank lines.
  1507. int iCollectionTall = m_pItemCollectionListLabel ? m_pItemCollectionListLabel->GetTall() : 0;
  1508. int iAttribTall = (m_pItemAttribLabel->GetWide() ? m_pItemAttribLabel->GetTall() : 0);
  1509. iAttribTall = Max( iAttribTall, iCollectionTall );
  1510. int iNameTall = m_pItemNameLabel->GetTall();
  1511. int iCollectionNameTall = m_pItemCollectionNameLabel ? m_pItemCollectionNameLabel->GetTall() : 0;
  1512. if ( m_bAttribOnly )
  1513. {
  1514. iNameTall = 0;
  1515. }
  1516. if ( m_bTextCenterX )
  1517. {
  1518. m_pItemNameLabel->SetSize( iTextW, iNameTall );
  1519. m_pItemAttribLabel->SetSize( iTextW, iAttribTall );
  1520. }
  1521. else if ( m_iTextYPos )
  1522. {
  1523. m_pItemNameLabel->SetSize( iTextW, iNameTall );
  1524. m_pItemAttribLabel->SetSize( iTextW, (m_pItemAttribLabel->GetWide() ? m_pItemAttribLabel->GetTall() : 0) );
  1525. if ( m_pItemCollectionNameLabel )
  1526. m_pItemCollectionNameLabel->SetSize( iTextW, iCollectionNameTall );
  1527. if ( m_pItemCollectionListLabel )
  1528. m_pItemCollectionListLabel->SetSize( iTextW, iCollectionTall );
  1529. }
  1530. else if ( m_bTextCenter )
  1531. {
  1532. m_pItemNameLabel->SetSize( iTextW, iNameTall );
  1533. m_pItemAttribLabel->SetSize( iTextW, iAttribTall );
  1534. }
  1535. else
  1536. {
  1537. m_pItemNameLabel->SetSize( iTextW, iNameTall );
  1538. m_pItemAttribLabel->SetSize( iTextW, iAttribTall );
  1539. }
  1540. m_pItemNameLabel->InvalidateLayout( true );
  1541. // Force attrib layout to update now in its new size.
  1542. m_pItemAttribLabel->InvalidateLayout( true );
  1543. m_pItemAttribLabel->SizeToContents();
  1544. // Reget sizes, wtf
  1545. iCollectionTall = m_pItemCollectionListLabel ? m_pItemCollectionListLabel->GetTall() : 0;
  1546. iAttribTall = ( m_pItemAttribLabel->GetWide() ? m_pItemAttribLabel->GetTall() : 0 );
  1547. // HACK: Now we resize it again. Sets our height properly. Ridiculous.
  1548. m_pItemAttribLabel->SetSize( iTextW, iAttribTall );
  1549. m_pItemNameLabel->SetSize( iTextW, iNameTall );
  1550. // Ignore attributes if we're only showing the name
  1551. if ( m_bNameOnly || (!HasItem() && m_pszNoItemText && m_pszNoItemText[0]) )
  1552. {
  1553. iAttribTall = 0;
  1554. }
  1555. int iLabelOffset = 0;
  1556. if ( m_bResizeToText )
  1557. {
  1558. h = m_iTextYPos + iNameTall + iAttribTall + m_iHPadding;
  1559. // Must be at least tall enough to fit the image (if visible)
  1560. if ( !m_bHideModel )
  1561. {
  1562. //h = MAX( h, (iModelT + (iModelY * 2)) );
  1563. h = Max( h + iModelT + iModelY, m_iTextYPos + iCollectionNameTall + iCollectionTall + m_iHPadding);
  1564. iLabelOffset = iModelT + iModelY;
  1565. }
  1566. }
  1567. // If we don't have a specific X pos, or attrib width, indent ourselves
  1568. int iTextXPos = (m_iTextXPos || m_iTextWide) ? m_iTextXPos : ATTRIB_LABEL_INDENT;
  1569. if ( iCollectionNameTall && iCollectionTall && m_iTextXPosCollection )
  1570. {
  1571. iTextXPos = m_iTextXPosCollection;
  1572. }
  1573. // Position the name label now we know where our attrib label is
  1574. // If we've got a Y pos, use it. Otherwise, stack up from the bottom of the panel.
  1575. if ( m_bTextCenterX )
  1576. {
  1577. m_pItemNameLabel->SizeToContents();
  1578. m_pItemAttribLabel->SizeToContents();
  1579. m_pItemNameLabel->SetPos( ( w - m_pItemNameLabel->GetWide() ) * 0.5f, m_iTextYPos + iLabelOffset );
  1580. m_pItemAttribLabel->SetPos( ( w - m_pItemAttribLabel->GetWide() ) * 0.5f, m_iTextYPos + iNameTall + iLabelOffset );
  1581. }
  1582. else if ( m_iTextYPos )
  1583. {
  1584. m_pItemNameLabel->SetPos( iTextXPos, m_iTextYPos + iLabelOffset );
  1585. m_pItemAttribLabel->SetPos( iTextXPos, m_iTextYPos + iNameTall + iLabelOffset);
  1586. if ( m_pItemCollectionNameLabel )
  1587. m_pItemCollectionNameLabel->SetPos( m_iCollectionListXPos, m_iTextYPos );
  1588. if ( m_pItemCollectionListLabel )
  1589. m_pItemCollectionListLabel->SetPos( m_iCollectionListXPos, m_iTextYPos + iCollectionNameTall );
  1590. }
  1591. else if ( m_bTextCenter )
  1592. {
  1593. int iYTop = (h - (iNameTall + iAttribTall)) * 0.5;
  1594. if ( iYTop < 0 )
  1595. {
  1596. iYTop = 0;
  1597. }
  1598. m_pItemNameLabel->SetPos( iTextXPos, iYTop );
  1599. m_pItemAttribLabel->SetPos( iTextXPos, iYTop + iNameTall );
  1600. //m_pItemCollectionLabel->SetPos( iTextXPos + iTextW, iYTop );
  1601. }
  1602. else
  1603. {
  1604. int iOffsetY = (m_iTextYOffset != 0) ? m_iTextYOffset : YRES(8);
  1605. m_pItemNameLabel->SetPos( iTextXPos, h - iAttribTall - iNameTall - iOffsetY + m_iHPadding );
  1606. m_pItemAttribLabel->SetPos( iTextXPos, h - iAttribTall - iOffsetY + m_iHPadding );
  1607. //m_pItemCollectionLabel->SetPos( iTextXPos + iTextW, h - iAttribTall - iNameTall - iOffsetY + m_iHPadding );
  1608. }
  1609. if ( m_bResizeToText )
  1610. {
  1611. if ( m_bIsMouseOverPanel && GetItem() && GetItem()->GetItemDefinition()->GetItemCollectionDefinition() && !m_bHideCollectionPanel )
  1612. {
  1613. if ( m_pItemCollectionListLabel && m_pItemCollectionNameLabel && m_pItemCollectionHighlight )
  1614. {
  1615. m_pItemCollectionListLabel->SizeToContents();
  1616. m_pItemCollectionNameLabel->SizeToContents();
  1617. int iContentW = Max( m_pItemCollectionNameLabel->GetWide(), m_pItemCollectionListLabel->GetWide() );
  1618. w = iContentW + m_iCollectionListXPos + m_iTextXPosCollection;
  1619. m_pItemCollectionHighlight->SetWide( iContentW );
  1620. }
  1621. }
  1622. SetSize( w, h );
  1623. }
  1624. }
  1625. // pin icons to top right corner
  1626. int xpos = m_iBaseWide - XRES(1);
  1627. int ypos = YRES(1);
  1628. if ( m_pPaintIcon && m_pPaintIcon->IsVisible() )
  1629. {
  1630. m_pPaintIcon->SetPos( xpos - m_pPaintIcon->GetWide(), ypos );
  1631. ypos += m_pPaintIcon->GetTall() * 0.9;
  1632. }
  1633. if ( m_pTF2Icon && m_pTF2Icon->IsVisible() )
  1634. {
  1635. m_pTF2Icon->SetPos( xpos - m_pTF2Icon->GetWide() + m_iTF2IconOffsetX, ypos + m_iTF2IconOffsetY );
  1636. ypos += m_pTF2Icon->GetTall() * 0.9;
  1637. }
  1638. if ( m_pVisionRestrictionImage && m_pVisionRestrictionImage->IsVisible() )
  1639. {
  1640. m_pVisionRestrictionImage->SetPos( xpos - m_pVisionRestrictionImage->GetWide(), ypos );
  1641. ypos += m_pVisionRestrictionImage->GetTall() * 0.9;
  1642. }
  1643. if ( m_pIsUnusualImage && m_pIsUnusualImage->IsVisible() )
  1644. {
  1645. m_pIsUnusualImage->SetPos( xpos - m_pIsUnusualImage->GetWide(), ypos );
  1646. ypos += m_pIsUnusualImage->GetTall() * 0.9;
  1647. }
  1648. if ( m_pIsStrangeImage && m_pIsStrangeImage->IsVisible() )
  1649. {
  1650. m_pIsStrangeImage->SetPos( xpos - m_pIsStrangeImage->GetWide(), ypos );
  1651. ypos += m_pIsStrangeImage->GetTall() * 0.9;
  1652. }
  1653. if ( m_pIsLoanerImage && m_pIsLoanerImage->IsVisible() )
  1654. {
  1655. m_pIsLoanerImage->SetPos( xpos - m_pIsLoanerImage->GetWide(), ypos );
  1656. ypos += m_pIsLoanerImage->GetTall() * 0.9;
  1657. }
  1658. if ( m_pItemNameLabel )
  1659. {
  1660. //m_pItemNameLabel->SetContentAlignment( (vgui::Label::Alignment) m_iNameLabelAlignment );
  1661. }
  1662. if ( m_bModelOnly )
  1663. {
  1664. if ( m_pItemNameLabel )
  1665. {
  1666. m_pItemNameLabel->SetVisible( false );
  1667. }
  1668. if ( m_pItemAttribLabel )
  1669. {
  1670. m_pItemAttribLabel->SetVisible( false );
  1671. }
  1672. if ( m_pItemCollectionNameLabel )
  1673. {
  1674. m_pItemCollectionNameLabel->SetVisible( false );
  1675. }
  1676. if ( m_pItemCollectionListLabel )
  1677. {
  1678. m_pItemCollectionListLabel->SetVisible( false );
  1679. }
  1680. if ( m_pItemCollectionHighlight )
  1681. {
  1682. m_pItemCollectionHighlight->SetVisible( false );
  1683. }
  1684. }
  1685. BaseClass::PerformLayout();
  1686. }
  1687. //-----------------------------------------------------------------------------
  1688. // Purpose:
  1689. //-----------------------------------------------------------------------------
  1690. void CItemModelPanel::PaintTraverse( bool forceRepaint, bool allowForce )
  1691. {
  1692. if ( m_bFakeButton )
  1693. return;
  1694. BaseClass::PaintTraverse( forceRepaint, allowForce );
  1695. }
  1696. //-----------------------------------------------------------------------------
  1697. // Purpose:
  1698. //-----------------------------------------------------------------------------
  1699. void CItemModelPanel::OnSizeChanged( int newWide, int newTall )
  1700. {
  1701. BaseClass::OnSizeChanged( newWide, newTall );
  1702. InvalidateLayout( true );
  1703. if ( m_bModelOnly )
  1704. return;
  1705. if ( m_pItemNameLabel && m_pItemNameLabel->GetTextImage() )
  1706. {
  1707. m_pItemNameLabel->GetTextImage()->RecalculateNewLinePositions();
  1708. }
  1709. if ( m_pItemAttribLabel && m_pItemAttribLabel->GetTextImage() )
  1710. {
  1711. m_pItemAttribLabel->GetTextImage()->RecalculateNewLinePositions();
  1712. }
  1713. if ( m_pItemCollectionNameLabel && m_pItemCollectionNameLabel->GetTextImage() )
  1714. {
  1715. m_pItemCollectionNameLabel->GetTextImage()->RecalculateNewLinePositions();
  1716. }
  1717. if ( m_pItemCollectionListLabel && m_pItemCollectionListLabel->GetTextImage() )
  1718. {
  1719. m_pItemCollectionListLabel->GetTextImage()->RecalculateNewLinePositions();
  1720. }
  1721. }
  1722. //-----------------------------------------------------------------------------
  1723. // Purpose:
  1724. //-----------------------------------------------------------------------------
  1725. void CItemModelPanel::ResizeLabels( void )
  1726. {
  1727. if ( !m_pItemNameLabel || !m_pItemAttribLabel || m_bModelOnly )
  1728. return;
  1729. int w,h;
  1730. GetSize( w, h );
  1731. int iTextW = GetAttribWide(w);
  1732. if ( m_iMaxTextHeight )
  1733. {
  1734. h = m_iMaxTextHeight;
  1735. }
  1736. // HACK to get the item model panel on the main menu to have its fonts.
  1737. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  1738. if ( !m_pFontNameSmallest )
  1739. m_pFontNameSmallest = pScheme->GetFont( "ItemFontNameSmallest", true );
  1740. if ( !m_pFontNameSmall )
  1741. m_pFontNameSmall = pScheme->GetFont( "ItemFontNameSmall", true );
  1742. if ( !m_pFontNameLarge )
  1743. m_pFontNameLarge = pScheme->GetFont( "ItemFontNameLarge", true );
  1744. if ( !m_pFontNameLarger )
  1745. m_pFontNameLarger = pScheme->GetFont( "ItemFontNameLarger", true );
  1746. if ( !m_pFontAttribSmallest )
  1747. m_pFontAttribSmallest = pScheme->GetFont( "ItemFontAttribSmallest", true );
  1748. if ( !m_pFontAttribSmall )
  1749. m_pFontAttribSmall = pScheme->GetFont( "ItemFontAttribSmallv2", true );
  1750. if ( !m_pFontAttribLarge )
  1751. m_pFontAttribLarge = pScheme->GetFont( "ItemFontAttribLarge", true );
  1752. if ( !m_pFontAttribLarger )
  1753. m_pFontAttribLarger = pScheme->GetFont( "ItemFontAttribLarger", true );
  1754. if ( m_iForceTextSize && m_iForceTextSize <= 4 )
  1755. {
  1756. // Leave center wrap on if the noitem text is getting to use the whole panel
  1757. if ( !m_bNoItemFullPanel )
  1758. {
  1759. m_pItemNameLabel->SetCenterWrap( false );
  1760. }
  1761. m_pItemNameLabel->InvalidateLayout( true, true );
  1762. m_pItemAttribLabel->InvalidateLayout( true, true );
  1763. if ( m_pItemCollectionNameLabel )
  1764. m_pItemCollectionNameLabel->InvalidateLayout( true, true );
  1765. if ( m_pItemCollectionListLabel )
  1766. m_pItemCollectionListLabel->InvalidateLayout( true, true );
  1767. switch ( m_iForceTextSize )
  1768. {
  1769. case 1:
  1770. m_pItemNameLabel->SetFont( m_pFontNameLarge );
  1771. m_pItemAttribLabel->SetFont( m_pFontAttribLarge );
  1772. if ( m_pItemCollectionNameLabel )
  1773. m_pItemCollectionNameLabel->SetFont( m_pFontNameLarge );
  1774. if ( m_pItemCollectionListLabel )
  1775. m_pItemCollectionListLabel->SetFont( m_pFontAttribLarge );
  1776. break;
  1777. case 2:
  1778. m_pItemNameLabel->SetFont( m_pFontNameSmall );
  1779. m_pItemAttribLabel->SetFont( m_pFontAttribSmall );
  1780. if ( m_pItemCollectionNameLabel )
  1781. m_pItemCollectionNameLabel->SetFont( m_pFontNameSmall );
  1782. if ( m_pItemCollectionListLabel )
  1783. m_pItemCollectionListLabel->SetFont( m_pFontAttribSmall );
  1784. break;
  1785. case 3:
  1786. m_pItemNameLabel->SetFont( m_pFontNameSmallest );
  1787. m_pItemAttribLabel->SetFont( m_pFontAttribSmallest );
  1788. if ( m_pItemCollectionNameLabel )
  1789. m_pItemCollectionNameLabel->SetFont( m_pFontNameSmallest );
  1790. if ( m_pItemCollectionListLabel )
  1791. m_pItemCollectionListLabel->SetFont( m_pFontAttribSmallest );
  1792. break;
  1793. case 4:
  1794. m_pItemNameLabel->SetFont( m_pFontNameLarger );
  1795. m_pItemAttribLabel->SetFont( m_pFontAttribLarger );
  1796. if ( m_pItemCollectionNameLabel )
  1797. m_pItemCollectionNameLabel->SetFont( m_pFontNameLarger );
  1798. if ( m_pItemCollectionListLabel )
  1799. m_pItemCollectionListLabel->SetFont( m_pFontAttribLarger );
  1800. break;
  1801. }
  1802. m_pItemNameLabel->SizeToContents();
  1803. m_pItemAttribLabel->SizeToContents();
  1804. if ( m_pItemCollectionNameLabel )
  1805. m_pItemCollectionNameLabel->SizeToContents();
  1806. if ( m_pItemCollectionListLabel )
  1807. m_pItemCollectionListLabel->SizeToContents();
  1808. }
  1809. else
  1810. {
  1811. m_pItemNameLabel->SetFont( m_pFontNameLarge );
  1812. m_pItemNameLabel->SetCenterWrap( false );
  1813. m_pItemNameLabel->SizeToContents();
  1814. m_pItemAttribLabel->SetFont( m_pFontAttribLarge );
  1815. m_pItemAttribLabel->SizeToContents();
  1816. if ( m_pItemCollectionNameLabel )
  1817. {
  1818. m_pItemCollectionNameLabel->SetFont( m_pFontNameLarge );
  1819. m_pItemCollectionNameLabel->SetCenterWrap( false );
  1820. m_pItemCollectionNameLabel->SizeToContents();
  1821. }
  1822. if ( m_pItemCollectionListLabel )
  1823. {
  1824. m_pItemCollectionListLabel->SetFont( m_pFontAttribLarge );
  1825. m_pItemCollectionListLabel->SizeToContents();
  1826. }
  1827. if ( !m_bResizeToText )
  1828. {
  1829. int iAttribTall = m_pItemAttribLabel->GetWide() ? m_pItemAttribLabel->GetTall() : 0;
  1830. int iNameTall = m_bAttribOnly ? 0 : m_pItemNameLabel->GetTall();
  1831. int iTotalH = iAttribTall + iNameTall;
  1832. // If these fonts won't fit, use the smaller ones
  1833. if ( m_pItemNameLabel->GetWide() > iTextW || (!m_bNameOnly && m_pItemAttribLabel->GetWide() > iTextW) || (iTotalH > h) )
  1834. {
  1835. m_pItemNameLabel->SetFont( m_pFontNameSmall );
  1836. m_pItemAttribLabel->SetFont( m_pFontAttribSmall );
  1837. m_pItemNameLabel->InvalidateLayout( true );
  1838. m_pItemNameLabel->SizeToContents();
  1839. iAttribTall = m_pItemAttribLabel->GetWide() ? m_pItemAttribLabel->GetTall() : 0;
  1840. iNameTall = m_pItemNameLabel->GetTall();
  1841. iTotalH = iAttribTall + iNameTall;
  1842. // If they don't fit, go to the smallest
  1843. if ( m_pItemNameLabel->GetWide() > iTextW || (!m_bNameOnly && m_pItemAttribLabel->GetWide() > iTextW) || (iTotalH > h) )
  1844. {
  1845. m_pItemNameLabel->SetFont( m_pFontNameSmallest );
  1846. m_pItemAttribLabel->SetFont( m_pFontAttribSmallest );
  1847. m_pItemNameLabel->InvalidateLayout( true );
  1848. m_pItemNameLabel->SizeToContents();
  1849. }
  1850. }
  1851. }
  1852. }
  1853. // If it still doesn't fit, turn on wrap and pray
  1854. if ( m_pItemNameLabel->GetWide() > iTextW )
  1855. {
  1856. m_pItemNameLabel->SetCenterWrap( true );
  1857. }
  1858. if ( m_pItemAttribLabel->GetWide() > iTextW )
  1859. {
  1860. m_pItemAttribLabel->SetWrap( true );
  1861. }
  1862. // Now restore the sizes
  1863. m_pItemNameLabel->SetSize( iTextW, m_pItemNameLabel->GetTall() );
  1864. m_pItemAttribLabel->SetSize( iTextW, m_pItemAttribLabel->GetTall() );
  1865. if ( m_pItemEquippedLabel )
  1866. {
  1867. m_pItemEquippedLabel->SetPos( GetWide() - m_pItemEquippedLabel->GetWide() - m_iEquippedInsetX, GetTall() - m_pItemEquippedLabel->GetTall() - m_iEquippedInsetY );
  1868. }
  1869. }
  1870. //-----------------------------------------------------------------------------
  1871. // Purpose:
  1872. //-----------------------------------------------------------------------------
  1873. void CItemModelPanel::SetItem( const CEconItemView *pItem )
  1874. {
  1875. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1876. HideContainedItemPanel();
  1877. bool bMatch = false;
  1878. if ( pItem && pItem->IsValid() )
  1879. {
  1880. if ( m_ItemData.IsValid() )
  1881. {
  1882. if ( m_ItemData.GetItemID() != INVALID_ITEM_ID )
  1883. {
  1884. bool bUseIndexCompare = false;
  1885. #ifdef TF_CLIENT_DLL
  1886. if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  1887. {
  1888. if ( ( m_ItemData.GetItemID() == 1 ) && ( m_ItemData.GetItemID() == pItem->GetItemID() ) )
  1889. {
  1890. // Items the bots carry in MvM all have itemID of 1, so we need to compare the item index
  1891. bUseIndexCompare = true;
  1892. }
  1893. }
  1894. #endif
  1895. if ( bUseIndexCompare )
  1896. {
  1897. bMatch = m_ItemData.GetItemDefIndex() == pItem->GetItemDefIndex();
  1898. }
  1899. else
  1900. {
  1901. // Our current item is non-base. We need to match global indices.
  1902. bMatch = ( m_ItemData.GetItemID() == pItem->GetItemID() );
  1903. }
  1904. }
  1905. else if ( pItem->GetItemID() == INVALID_ITEM_ID )
  1906. {
  1907. static CSchemaFieldHandle<CEconItemAttributeDefinition> pAttrib_ToolTarget( "tool target item" );
  1908. bMatch &= pItem->FindAttribute( pAttrib_ToolTarget );
  1909. // Our current item is a base item. Our new item needs to be base too, and match item indices and quality
  1910. bMatch &= ( m_ItemData.GetItemDefIndex() == pItem->GetItemDefIndex() ) &&
  1911. ( m_ItemData.GetItemQuality() == pItem->GetItemQuality() ) &&
  1912. ( m_ItemData.GetSOCData() == pItem->GetSOCData() );
  1913. }
  1914. }
  1915. // if we match item so far, check for strange
  1916. if ( bMatch )
  1917. {
  1918. // Are we tracking alternate stats as well?
  1919. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  1920. {
  1921. const CEconItemAttributeDefinition *pKillEaterAltAttrDef = GetKillEaterAttr_Score( i ),
  1922. *pKillEaterAltScoreTypeAttrDef = GetKillEaterAttr_Type( i );
  1923. if ( !pKillEaterAltAttrDef || !pKillEaterAltScoreTypeAttrDef )
  1924. continue;
  1925. uint32 unNewScore = 0;
  1926. uint32 unOldScore = 0;
  1927. bool bNewFoundAttr = pItem->FindAttribute( pKillEaterAltAttrDef, &unNewScore );
  1928. bool bOldFoundAttr = m_ItemData.FindAttribute( pKillEaterAltAttrDef, &unOldScore );
  1929. if ( bNewFoundAttr != bOldFoundAttr || unNewScore != unOldScore )
  1930. {
  1931. // different score
  1932. bMatch = false;
  1933. break;
  1934. }
  1935. float flNewType = 0.f;
  1936. float flOldType = 0.f;
  1937. bNewFoundAttr = FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pKillEaterAltScoreTypeAttrDef, &flNewType );
  1938. bOldFoundAttr = FindAttribute_UnsafeBitwiseCast<attrib_value_t>( &m_ItemData, pKillEaterAltScoreTypeAttrDef, &flOldType );
  1939. if ( bNewFoundAttr != bOldFoundAttr || flNewType != flOldType )
  1940. {
  1941. // different score
  1942. bMatch = false;
  1943. break;
  1944. }
  1945. }
  1946. }
  1947. if ( !bMatch )
  1948. {
  1949. // cancel weapon skin composition for old item
  1950. if ( m_ItemData.IsValid() )
  1951. {
  1952. m_ItemData.CancelWeaponSkinComposite();
  1953. }
  1954. m_ItemData = *pItem;
  1955. if ( m_bIsMouseOverPanel )
  1956. {
  1957. LoadResFileForCurrentItem( false );
  1958. }
  1959. // If the item hasn't built its attribute string, go ahead and do that.
  1960. m_ItemData.SetGrayedOutReason( GetGreyedOutReason() );
  1961. }
  1962. else
  1963. {
  1964. // The rest of the data may match, but we still need the inventory position updates
  1965. m_ItemData.SetInventoryPosition( pItem->GetInventoryPosition() );
  1966. }
  1967. ShowContainedItemPanel( pItem );
  1968. }
  1969. else
  1970. {
  1971. // cancel weapon skin composition for old item
  1972. if ( m_ItemData.IsValid() )
  1973. {
  1974. m_ItemData.CancelWeaponSkinComposite();
  1975. }
  1976. else
  1977. {
  1978. bMatch = true;
  1979. }
  1980. m_ItemData.GetAttributeList()->DestroyAllAttributes();
  1981. m_ItemData.Invalidate();
  1982. }
  1983. // only update panels when item is not matched
  1984. if ( !bMatch )
  1985. {
  1986. UpdatePanels();
  1987. }
  1988. // TODO: Update only description for strange item in the same panel
  1989. }
  1990. //-----------------------------------------------------------------------------
  1991. // Purpose:
  1992. //-----------------------------------------------------------------------------
  1993. void CItemModelPanel::Dragged( bool bDragging )
  1994. {
  1995. if ( m_pContainedItemPanel )
  1996. {
  1997. if ( bDragging )
  1998. {
  1999. m_pContainedItemPanel->SetActAsButton( false, false );
  2000. m_pContainedItemPanel->SetVisible( false );
  2001. }
  2002. }
  2003. }
  2004. //-----------------------------------------------------------------------------
  2005. // Purpose:
  2006. //-----------------------------------------------------------------------------
  2007. void CItemModelPanel::ShowContainedItemPanel( const CEconItemView *pItem )
  2008. {
  2009. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2010. // If this item contains another item, create an interior item model panel.
  2011. if ( pItem->GetSOCData() && pItem->GetSOCData()->GetInteriorItem() && m_pContainedItemPanel )
  2012. {
  2013. if ( !m_pContainedItemPanel->IsContainedItem() )
  2014. {
  2015. m_pContainedItemPanel->SetContainedItem( true );
  2016. m_pContainedItemPanel->InvalidateLayout( false, true );
  2017. }
  2018. CEconItem *pInteriorItem = pItem->GetSOCData()->GetInteriorItem();
  2019. if ( !pInteriorItem )
  2020. return;
  2021. const IEconTool *pEconTool = pItem->GetItemDefinition()
  2022. ? pItem->GetItemDefinition()->GetEconTool()
  2023. : NULL;
  2024. if ( !pEconTool )
  2025. return;
  2026. if ( !pEconTool->ShouldShowContainedItemPanel( pItem ) )
  2027. {
  2028. // Only show this to non-local, non-wrapping players if we've been told to (usually in trading panel)
  2029. if ( !m_bShowOthersGiftWrappedItems )
  2030. return;
  2031. }
  2032. SetNeedsToLoad();
  2033. m_pContainedItemPanel->SetEconItem( pInteriorItem );
  2034. m_pContainedItemPanel->SetVisible( true );
  2035. m_pContainedItemPanel->SetActAsButton( false, true );
  2036. m_pContainedItemPanel->SetTooltip( GetTooltip(), "" );
  2037. }
  2038. }
  2039. //-----------------------------------------------------------------------------
  2040. // Purpose:
  2041. //-----------------------------------------------------------------------------
  2042. void CItemModelPanel::HideContainedItemPanel()
  2043. {
  2044. if ( m_pContainedItemPanel && m_pContainedItemPanel->IsVisible() )
  2045. {
  2046. m_pContainedItemPanel->SetActAsButton( false, false );
  2047. m_pContainedItemPanel->SetVisible( false );
  2048. }
  2049. }
  2050. //-----------------------------------------------------------------------------
  2051. // Purpose:
  2052. //-----------------------------------------------------------------------------
  2053. void CItemModelPanel::SetEconItem( CEconItem* pItem )
  2054. {
  2055. m_ItemData.SetItemDefIndex( pItem->GetDefinitionIndex() );
  2056. m_ItemData.SetItemQuality( pItem->GetQuality() );
  2057. m_ItemData.SetItemLevel( pItem->GetItemLevel() );
  2058. m_ItemData.SetItemID( pItem->GetItemID() );
  2059. m_ItemData.SetNonSOEconItem( pItem );
  2060. m_ItemData.SetInitialized( true );
  2061. #ifdef CLIENT_DLL
  2062. m_ItemData.SetIsTradeItem( false );
  2063. m_ItemData.SetItemQuantity( pItem->GetQuantity() );
  2064. #endif
  2065. m_ItemData.GetAttributeList()->DestroyAllAttributes();
  2066. if ( m_pModelPanel )
  2067. {
  2068. m_pModelPanel->SetItem( &m_ItemData );
  2069. }
  2070. }
  2071. //-----------------------------------------------------------------------------
  2072. // Purpose:
  2073. //-----------------------------------------------------------------------------
  2074. void CItemModelPanel::SetNoItemText( const char *pszText )
  2075. {
  2076. m_pszNoItemText = pszText;
  2077. CleanupNoItemWChars();
  2078. if ( !HasItem() )
  2079. {
  2080. UpdatePanels();
  2081. }
  2082. }
  2083. //-----------------------------------------------------------------------------
  2084. // Purpose:
  2085. //-----------------------------------------------------------------------------
  2086. void CItemModelPanel::CleanupNoItemWChars( void )
  2087. {
  2088. if ( m_pwcNoItemText )
  2089. {
  2090. delete m_pwcNoItemText;
  2091. m_pwcNoItemText = NULL;
  2092. }
  2093. if ( m_pwcNoItemAttrib )
  2094. {
  2095. delete m_pwcNoItemAttrib;
  2096. m_pwcNoItemAttrib = NULL;
  2097. }
  2098. }
  2099. //-----------------------------------------------------------------------------
  2100. // Purpose:
  2101. //-----------------------------------------------------------------------------
  2102. bool CItemModelPanel::UpdateSeriesLabel()
  2103. {
  2104. // hijacking m_bShowQuantity here to indicate "show things where the quantity counter goes", in this case meaning "show crate series indicator"
  2105. if ( m_pSeriesLabel && m_bShowQuantity )
  2106. {
  2107. static CSchemaAttributeDefHandle pAttrDef_CrateSeries( "set supply crate series" );
  2108. static CSchemaAttributeDefHandle pAttrDef_HideSeries( "hide crate series number" );
  2109. float fCrateSeries;
  2110. if ( pAttrDef_CrateSeries && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( &m_ItemData, pAttrDef_CrateSeries, &fCrateSeries ) && pAttrDef_HideSeries && !m_ItemData.FindAttribute( pAttrDef_HideSeries ) )
  2111. {
  2112. wchar_t wszSeries[16]=L"";
  2113. _snwprintf( wszSeries, ARRAYSIZE( wszSeries ), L"#%i", (int)fCrateSeries );
  2114. m_pSeriesLabel->SetVisible( true );
  2115. m_pSeriesLabel->SetText( wszSeries );
  2116. return true;
  2117. }
  2118. else
  2119. {
  2120. m_pSeriesLabel->SetVisible( false );
  2121. return false;
  2122. }
  2123. }
  2124. return false;
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. // Purpose: Read through a few items and see if they match the recipe's criteria
  2128. // Show elipses while still tallying. Remove our tick once all items
  2129. // are tallied.
  2130. //-----------------------------------------------------------------------------
  2131. bool CItemModelPanel::CheckRecipeMatches()
  2132. {
  2133. // Don't do this if either we or our parent are invisible
  2134. if( !IsVisible() || ( GetParent() && !GetParent()->IsVisible() ) )
  2135. return false;
  2136. const IEconTool* pTool = m_ItemData.GetStaticData()->GetEconTool();
  2137. // If this isnt a dynamic recipe tool, dont show or do any of this
  2138. if( !pTool
  2139. || V_stricmp( m_ItemData.GetStaticData()->GetEconTool()->GetTypeName() , "dynamic_recipe")
  2140. || m_ItemData.GetStaticData()->GetDefaultLoadoutSlot() != INVALID_EQUIPPED_SLOT )
  2141. {
  2142. if( m_pMatchesLabel )
  2143. {
  2144. m_pMatchesLabel->SetVisible( false );
  2145. }
  2146. return false;
  2147. }
  2148. bool bStillWorking = true;
  2149. if( m_pMatchesLabel && m_bShowQuantity )
  2150. {
  2151. CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();
  2152. if ( pLocalInv == NULL )
  2153. return false;
  2154. // We still need to match recipe components
  2155. if ( m_nRecipeMatchingIndex < pLocalInv->GetItemCount() )
  2156. sai_NumLoadingRequests[LOADING_RECIPE_MATCHES]++;
  2157. if ( se_CurrentLoadingTask == LOADING_RECIPE_MATCHES )
  2158. {
  2159. // Go through our entire backpack and check for matches, but only go through a few at a time
  2160. while ( m_nRecipeMatchingIndex < pLocalInv->GetItemCount() && sm_flLoadingTimeThisFrame < tf_time_loading_item_panels.GetFloat() )
  2161. {
  2162. // Mark this time
  2163. float flTime = Plat_FloatTime();
  2164. CEconItemView *pItem = pLocalInv->GetItem( m_nRecipeMatchingIndex );
  2165. Assert( pItem );
  2166. // Check each item
  2167. CRecipeComponentMatchingIterator matchingIterator( &m_ItemData, pItem );
  2168. m_ItemData.IterateAttributes( &matchingIterator );
  2169. const CUtlVector< const CEconItemAttributeDefinition* >& matchingAttribs = matchingIterator.GetMatchingComponentInputs();
  2170. Assert( matchingAttribs.Count() <= 1 );
  2171. FOR_EACH_VEC( matchingAttribs, j )
  2172. {
  2173. CAttribute_DynamicRecipeComponent value;
  2174. const CEconItemAttributeDefinition* pAttrib = matchingAttribs[j];
  2175. attrib_definition_index_t nIndex = pAttrib->GetDefinitionIndex();
  2176. m_ItemData.FindAttribute( pAttrib, &value );
  2177. // Add this entry if it doesnt exist in out map yet
  2178. if( m_mapMatchingAttributes.Find( nIndex ) == m_mapMatchingAttributes.InvalidIndex() )
  2179. {
  2180. m_mapMatchingAttributes.Insert( nIndex );
  2181. m_mapMatchingAttributes[ m_mapMatchingAttributes.Find( nIndex ) ] = 0;
  2182. }
  2183. // Increment this value if it's less than the max needed
  2184. int &nCount = m_mapMatchingAttributes[ m_mapMatchingAttributes.Find( nIndex ) ];
  2185. if( (unsigned)nCount < ( value.num_required() - value.num_fulfilled() ) )
  2186. {
  2187. ++nCount;
  2188. }
  2189. }
  2190. m_nRecipeMatchingIndex++;
  2191. // Accumulate time
  2192. sm_flLoadingTimeThisFrame += ( Plat_FloatTime() - flTime );
  2193. }
  2194. }
  2195. bStillWorking = m_nRecipeMatchingIndex != pLocalInv->GetItemCount();
  2196. wchar_t wszMatches[16]=L"...";
  2197. if( !bStillWorking )
  2198. {
  2199. CRecipeComponentMatchingIterator matchingIterator( &m_ItemData, NULL );
  2200. m_ItemData.IterateAttributes( &matchingIterator );
  2201. int nTotalAttribs = matchingIterator.GetTotalInputs() - matchingIterator.GetInputsFulfilled();
  2202. int nMatchingAttribs = 0;
  2203. unsigned short index = m_mapMatchingAttributes.FirstInorder();
  2204. while( index != m_mapMatchingAttributes.InvalidIndex() )
  2205. {
  2206. nMatchingAttribs += m_mapMatchingAttributes[ index ];
  2207. index = m_mapMatchingAttributes.NextInorder( index );
  2208. }
  2209. // Fill out the actual number of matches
  2210. _snwprintf( wszMatches, ARRAYSIZE( wszMatches ), L"%i/%i", nMatchingAttribs, nTotalAttribs );
  2211. }
  2212. m_pMatchesLabel->SetVisible( true );
  2213. m_pMatchesLabel->SetText( wszMatches );
  2214. }
  2215. return bStillWorking;
  2216. }
  2217. void CItemModelPanel::UpdateDescription()
  2218. {
  2219. if ( !m_bDescriptionDirty )
  2220. return;
  2221. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2222. m_bDescriptionDirty = false;
  2223. enum { kAttribBufferSize = 4 * 1024 };
  2224. wchar_t wszAttribBuffer[ kAttribBufferSize ] = L"";
  2225. enum { kCollectionBufferSize = 4 * 1024 };
  2226. wchar_t wszCollectionListBuffer[kCollectionBufferSize] = L"";
  2227. wchar_t wszCollectionNameBuffer[512] = L"";
  2228. if ( !m_bNameOnly )
  2229. {
  2230. const CEconItemDescription *pDescription = m_ItemData.GetDescription();
  2231. if ( pDescription )
  2232. {
  2233. unsigned int unWrittenLines = 0;
  2234. unsigned int unWrittenCollectionLines = 0;
  2235. for ( unsigned int i = 0; i < pDescription->GetLineCount(); i++ )
  2236. {
  2237. const econ_item_description_line_t& line = pDescription->GetLine(i);
  2238. // m_bSpecialAttributesOnly, only show purple and orange text, ignore rest
  2239. if ( m_bSpecialAttributesOnly )
  2240. {
  2241. if ( line.eColor == ATTRIB_COL_UNUSUAL || line.eColor == ATTRIB_COL_STRANGE )
  2242. {
  2243. V_wcscat_safe( wszAttribBuffer, unWrittenLines++ == 0 ? L"" : L"\n" ); // add empty lines everywhere except before the first line
  2244. V_wcscat_safe( wszAttribBuffer, line.sText.Get() );
  2245. }
  2246. }
  2247. else if ( ( line.unMetaType & kDescLineFlag_CollectionName ) != 0 )
  2248. {
  2249. // Ignore name spacers
  2250. if ( !( line.unMetaType & kDescLineFlag_Empty) )
  2251. {
  2252. V_wcscat_safe( wszCollectionNameBuffer, line.sText.Get() );
  2253. }
  2254. }
  2255. else if ( ( line.unMetaType & kDescLineFlag_Collection ) != 0 )
  2256. {
  2257. V_wcscat_safe( wszCollectionListBuffer, unWrittenCollectionLines++ == 0 ? L"" : L"\n" ); // add empty lines everywhere except before the first line
  2258. V_wcscat_safe( wszCollectionListBuffer, line.sText.Get() );
  2259. }
  2260. else if ( (line.unMetaType & kDescLineFlag_Name ) == 0 )
  2261. {
  2262. V_wcscat_safe( wszAttribBuffer, unWrittenLines++ == 0 ? L"" : L"\n" ); // add empty lines everywhere except before the first line
  2263. V_wcscat_safe( wszAttribBuffer, line.sText.Get() );
  2264. }
  2265. }
  2266. // If we have an unknown name, we should try to rebuild for "awhile"
  2267. m_bDescriptionDirty |= pDescription->HasUnknownPlayer();
  2268. }
  2269. }
  2270. if( m_pMainContentContainer )
  2271. {
  2272. m_pMainContentContainer->SetDialogVariable( "attriblist", wszAttribBuffer );
  2273. m_pMainContentContainer->SetDialogVariable( "collectionname", wszCollectionNameBuffer );
  2274. m_pMainContentContainer->SetDialogVariable( "collectionlist", wszCollectionListBuffer );
  2275. m_pMainContentContainer->SetDialogVariable( "itemname", m_ItemData.GetItemName() );
  2276. }
  2277. if ( m_pItemNameLabel )
  2278. {
  2279. // Set the name to the quality color
  2280. // Rarity Econ Colorization
  2281. EEconItemQuality eQuality = (EEconItemQuality)m_ItemData.GetItemQuality();
  2282. if ( GetItemSchema()->GetRarityColor( m_ItemData.GetItemDefinition()->GetRarity() ) && eQuality != AE_SELFMADE )
  2283. {
  2284. m_pItemNameLabel->SetColorStr( GetItemSchema()->GetRarityColor( m_ItemData.GetItemDefinition()->GetRarity() ) );
  2285. }
  2286. else
  2287. {
  2288. const char *pszQualityColorString = EconQuality_GetColorString( eQuality );
  2289. if ( m_ItemData.IsValid() && !m_bStandardTextColor && pszQualityColorString )
  2290. {
  2291. m_pItemNameLabel->SetColorStr( pszQualityColorString );
  2292. }
  2293. else
  2294. {
  2295. m_pItemNameLabel->SetColorStr( m_OrgItemTextColor );
  2296. }
  2297. }
  2298. m_pItemNameLabel->SetVisible( !m_bAttribOnly );
  2299. }
  2300. if ( m_pItemAttribLabel )
  2301. {
  2302. m_pItemAttribLabel->SetVisible( !m_bNameOnly );
  2303. }
  2304. bool bCollectionVisible = m_bHideCollectionPanel ? false : !m_bNameOnly;
  2305. if ( m_pItemCollectionNameLabel )
  2306. {
  2307. m_pItemCollectionNameLabel->SetVisible( bCollectionVisible );
  2308. }
  2309. if ( m_pItemCollectionListLabel )
  2310. {
  2311. m_pItemCollectionListLabel->SetVisible( bCollectionVisible );
  2312. }
  2313. if ( m_pItemCollectionHighlight )
  2314. {
  2315. m_pItemCollectionHighlight->SetVisible( bCollectionVisible );
  2316. }
  2317. InvalidateLayout( true );
  2318. // Now that we've built the attribute description, give the attribute colors to our label
  2319. if ( m_pItemAttribLabel && !m_bNameOnly && m_pItemAttribLabel->GetTextImage() && m_ItemData.GetDescription() )
  2320. {
  2321. const CEconItemDescription *pDescription = m_ItemData.GetDescription();
  2322. vgui::TextImage *pAttrTextImage = m_pItemAttribLabel->GetTextImage();
  2323. pAttrTextImage->ClearColorChangeStream();
  2324. vgui::TextImage *pCollectionNameTextImage = m_pItemCollectionNameLabel ? m_pItemCollectionNameLabel->GetTextImage() : NULL;
  2325. if ( pCollectionNameTextImage )
  2326. pCollectionNameTextImage->ClearColorChangeStream();
  2327. vgui::TextImage *pCollectionListTextImage = m_pItemCollectionListLabel ? m_pItemCollectionListLabel->GetTextImage() : NULL;
  2328. if ( pCollectionListTextImage )
  2329. pCollectionListTextImage->ClearColorChangeStream();
  2330. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  2331. Color prevAttrColor(0,0,0);
  2332. Color prevCollectionColor(0,0,0);
  2333. unsigned int unCurrentAttrTextStreamIndex = 0;
  2334. unsigned int unCurrentCollectionNameTextStreamIndex = 0;
  2335. unsigned int unCurrentCollectionListTextStreamIndex = 0;
  2336. int iCollectionLineCount = 0;
  2337. if ( m_pItemCollectionHighlight )
  2338. {
  2339. m_pItemCollectionHighlight->SetVisible( false );
  2340. }
  2341. for ( unsigned int i = 0; i < pDescription->GetLineCount(); i++ )
  2342. {
  2343. const econ_item_description_line_t& line = pDescription->GetLine(i);
  2344. // Ignore the name line, it was added above
  2345. if ( ( line.unMetaType & kDescLineFlag_Name ) != 0 )
  2346. {
  2347. continue;
  2348. }
  2349. // collection
  2350. int fontHeight = surface()->GetFontTall( m_pFontAttribSmall );
  2351. if ( ( line.unMetaType & (kDescLineFlag_Collection | kDescLineFlag_CollectionName | kDescLineFlag_CollectionCurrentItem ) ) != 0 && pCollectionNameTextImage && pCollectionListTextImage )
  2352. {
  2353. bool bIsCollectionName = ( line.unMetaType & kDescLineFlag_CollectionName ) != 0;
  2354. vgui::TextImage *pTextImage = bIsCollectionName ? pCollectionNameTextImage : pCollectionListTextImage;
  2355. unsigned int &unCurrentCollectionTextStreamIndex = bIsCollectionName ? unCurrentCollectionNameTextStreamIndex : unCurrentCollectionListTextStreamIndex;
  2356. bool bIsCurrentItem = ( line.unMetaType & kDescLineFlag_CollectionCurrentItem ) != 0;
  2357. // use bg color as text color for current item for a better highlight
  2358. Color col = bIsCurrentItem ? Color( 0, 0, 0, 255 ) : pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
  2359. // Output a color change if necessary.
  2360. if ( i == 0 || prevCollectionColor != col )
  2361. {
  2362. pTextImage->AddColorChange( col, unCurrentCollectionTextStreamIndex );
  2363. prevCollectionColor = col;
  2364. }
  2365. unCurrentCollectionTextStreamIndex += StringFuncs<locchar_t>::Length( line.sText.Get() ) + 1; // add one character to deal with newlines
  2366. if ( bIsCollectionName )
  2367. {
  2368. continue;
  2369. }
  2370. // Current line highlight
  2371. if ( bIsCurrentItem && m_pItemCollectionHighlight )
  2372. {
  2373. // use text color as bg color for the current item for a better highlight
  2374. Color bgColor = pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
  2375. // Get the current ypos
  2376. int x, y;
  2377. m_pItemCollectionListLabel->GetPos( x, y );
  2378. m_pItemCollectionHighlight->SetPos( x, y + iCollectionLineCount * fontHeight );
  2379. m_pItemCollectionHighlight->SetBgColor( bgColor );
  2380. m_pItemCollectionHighlight->SetVisible( bCollectionVisible );
  2381. }
  2382. iCollectionLineCount++;
  2383. }
  2384. else
  2385. {
  2386. Color col = pScheme->GetColor( GetColorNameForAttribColor( line.eColor ), Color( 255, 255, 255, 255 ) );
  2387. // m_bSpecialAttributesOnly, only show purple and orange text, ignore rest
  2388. if ( m_bSpecialAttributesOnly )
  2389. {
  2390. if ( ( line.eColor != ATTRIB_COL_UNUSUAL && line.eColor != ATTRIB_COL_STRANGE ) )
  2391. {
  2392. continue;
  2393. }
  2394. }
  2395. // Output a color change if necessary.
  2396. if ( i == 0 || prevAttrColor != col )
  2397. {
  2398. pAttrTextImage->AddColorChange( col, unCurrentAttrTextStreamIndex );
  2399. prevAttrColor = col;
  2400. }
  2401. unCurrentAttrTextStreamIndex += StringFuncs<locchar_t>::Length( line.sText.Get() ) + 1; // add one character to deal with newlines
  2402. }
  2403. }
  2404. }
  2405. }
  2406. //-----------------------------------------------------------------------------
  2407. // Purpose:
  2408. //-----------------------------------------------------------------------------
  2409. void CItemModelPanel::DirtyDescription()
  2410. {
  2411. m_bDescriptionDirty = true;
  2412. if ( HasItem() )
  2413. GetItem()->OnAttributeValuesChanged();
  2414. }
  2415. //-----------------------------------------------------------------------------
  2416. // Purpose:
  2417. //-----------------------------------------------------------------------------
  2418. bool CItemModelPanel::UpdateMatchesLabel()
  2419. {
  2420. const IEconTool* pTool = m_ItemData.GetStaticData()->GetEconTool();
  2421. if( !pTool || Q_stricmp( m_ItemData.GetStaticData()->GetEconTool()->GetTypeName() , "dynamic_recipe") )
  2422. {
  2423. return false;
  2424. }
  2425. m_nRecipeMatchingIndex = 0;
  2426. m_mapMatchingAttributes.Purge();
  2427. SetNeedsToLoad();
  2428. return true;
  2429. }
  2430. //-----------------------------------------------------------------------------
  2431. // Purpose:
  2432. //-----------------------------------------------------------------------------
  2433. bool CItemModelPanel::UpdateQuantityLabel()
  2434. {
  2435. if ( m_pItemQuantityLabel )
  2436. {
  2437. bool bVisible = m_bShowQuantity && m_ItemData.GetStaticData() != NULL;
  2438. if ( bVisible )
  2439. {
  2440. const IEconTool *pEconTool = m_ItemData.GetStaticData()->GetEconTool();
  2441. if ( pEconTool && pEconTool->ShouldDisplayQuantity( &m_ItemData ) )
  2442. {
  2443. wchar_t wszQuantity[16]=L"";
  2444. _snwprintf( wszQuantity, ARRAYSIZE( wszQuantity ), L"%i", m_ItemData.GetQuantity() );
  2445. m_pItemQuantityLabel->SetVisible( true );
  2446. m_pItemQuantityLabel->SetText( wszQuantity );
  2447. }
  2448. else
  2449. {
  2450. bVisible = false;
  2451. }
  2452. }
  2453. m_pItemQuantityLabel->SetVisible( bVisible );
  2454. return true;
  2455. }
  2456. return false;
  2457. }
  2458. //--------------------------------------------------------------------------------------------------------
  2459. /**
  2460. * Simple utility function to allocate memory and duplicate a wide string
  2461. */
  2462. inline wchar_t *CloneWString( const wchar_t *str )
  2463. {
  2464. const int nLen = V_wcslen(str)+1;
  2465. wchar_t *cloneStr = new wchar_t [ nLen ];
  2466. const int nSize = nLen * sizeof( wchar_t );
  2467. V_wcsncpy( cloneStr, str, nSize );
  2468. return cloneStr;
  2469. }
  2470. //-----------------------------------------------------------------------------
  2471. // Purpose:
  2472. //-----------------------------------------------------------------------------
  2473. void CItemModelPanel::SetNoItemText( const wchar_t *pwszTitleOverride, const wchar_t *pwszAttribs, int iNegAttribsBegin )
  2474. {
  2475. static CSchemaColorDefHandle pColorDef_DescAttribPositive( "desc_attrib_positive" );
  2476. static CSchemaColorDefHandle pColorDef_DescAttribNegative( "ItemAttribNegative" );
  2477. CleanupNoItemWChars();
  2478. m_pwcNoItemText = CloneWString( pwszTitleOverride );
  2479. m_pszNoItemText = NULL;
  2480. if ( pwszAttribs )
  2481. {
  2482. m_pwcNoItemAttrib = CloneWString( pwszAttribs );
  2483. if ( m_pItemAttribLabel && m_pItemAttribLabel->GetTextImage() )
  2484. {
  2485. m_pItemAttribLabel->GetTextImage()->ClearColorChangeStream();
  2486. if ( iNegAttribsBegin )
  2487. {
  2488. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  2489. if ( pColorDef_DescAttribPositive )
  2490. {
  2491. Color col = pScheme->GetColor( pColorDef_DescAttribPositive->GetColorName(), Color(255,255,255,255) );
  2492. m_pItemAttribLabel->GetTextImage()->AddColorChange( col, 0 );
  2493. }
  2494. if ( pColorDef_DescAttribNegative )
  2495. {
  2496. Color col = pScheme->GetColor( pColorDef_DescAttribNegative->GetColorName(), Color(255,255,255,255) );
  2497. m_pItemAttribLabel->GetTextImage()->AddColorChange( col, iNegAttribsBegin );
  2498. }
  2499. }
  2500. }
  2501. }
  2502. if ( !HasItem() )
  2503. {
  2504. UpdatePanels();
  2505. }
  2506. }
  2507. //-----------------------------------------------------------------------------
  2508. // Purpose:
  2509. //-----------------------------------------------------------------------------
  2510. void CItemModelPanel::HideAllModifierIcons()
  2511. {
  2512. if ( m_pPaintIcon )
  2513. {
  2514. m_pPaintIcon->SetVisible( false );
  2515. }
  2516. if ( m_pTF2Icon )
  2517. {
  2518. m_pTF2Icon->SetVisible( false );
  2519. }
  2520. if ( m_pItemEquippedLabel )
  2521. {
  2522. m_pItemEquippedLabel->SetVisible( false );
  2523. }
  2524. if ( m_pItemQuantityLabel )
  2525. {
  2526. m_pItemQuantityLabel->SetVisible( false );
  2527. }
  2528. if ( m_pVisionRestrictionImage )
  2529. {
  2530. m_pVisionRestrictionImage->SetVisible( false );
  2531. }
  2532. if ( m_pIsStrangeImage )
  2533. {
  2534. m_pIsStrangeImage->SetVisible( false );
  2535. }
  2536. if ( m_pIsUnusualImage )
  2537. {
  2538. m_pIsUnusualImage->SetVisible( false );
  2539. }
  2540. if ( m_pIsLoanerImage )
  2541. {
  2542. m_pIsLoanerImage->SetVisible( false );
  2543. }
  2544. if ( m_pSeriesLabel )
  2545. {
  2546. m_pSeriesLabel->SetVisible( false );
  2547. }
  2548. if ( m_pMatchesLabel )
  2549. {
  2550. m_pMatchesLabel->SetVisible( false );
  2551. }
  2552. if ( m_pItemEquippedLabel && m_bForceShowEquipped )
  2553. {
  2554. m_pItemEquippedLabel->SetVisible( m_bForceShowEquipped );
  2555. }
  2556. }
  2557. //-----------------------------------------------------------------------------
  2558. // Purpose:
  2559. //-----------------------------------------------------------------------------
  2560. void CItemModelPanel::UpdatePanels( void )
  2561. {
  2562. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2563. if ( !m_pModelPanel )
  2564. return;
  2565. m_pModelPanel->SetModelHidden( m_bHideModel );
  2566. // By default we dont need a tick.
  2567. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  2568. // Default to loading icons
  2569. se_CurrentLoadingTask = LOADING_ICONS;
  2570. m_pModelPanel->SetItem( &m_ItemData );
  2571. // We need to load if our image isn't in memory already.
  2572. if ( !m_bHideModel && ( m_pModelPanel->IsImageNotLoaded() || m_pModelPanel->IsLoadingWeaponSkin() ) )
  2573. {
  2574. if ( m_pMainContentContainer )
  2575. {
  2576. m_pMainContentContainer->SetVisible( false );
  2577. }
  2578. // Show the spinner
  2579. if ( m_pLoadingSpinner )
  2580. {
  2581. m_pLoadingSpinner->SetVisible( true );
  2582. }
  2583. SetNeedsToLoad();
  2584. }
  2585. else
  2586. {
  2587. // hide the spinner
  2588. if ( m_pLoadingSpinner )
  2589. {
  2590. m_pLoadingSpinner->SetVisible( false );
  2591. }
  2592. }
  2593. if ( !HasItem() )
  2594. {
  2595. if ( m_bModelOnly )
  2596. {
  2597. if ( m_pItemNameLabel )
  2598. {
  2599. m_pItemNameLabel->SetVisible( false );
  2600. }
  2601. if ( m_pItemAttribLabel )
  2602. {
  2603. m_pItemAttribLabel->SetVisible( false );
  2604. }
  2605. }
  2606. else
  2607. {
  2608. if ( m_pItemNameLabel )
  2609. {
  2610. const wchar_t *wcNOText = NULL;
  2611. if ( m_pszNoItemText && m_pszNoItemText[0] )
  2612. {
  2613. wcNOText = g_pVGuiLocalize->Find( m_pszNoItemText );
  2614. }
  2615. else if ( m_pwcNoItemText )
  2616. {
  2617. wcNOText = m_pwcNoItemText;
  2618. }
  2619. if ( wcNOText && wcNOText[0] )
  2620. {
  2621. if ( m_pMainContentContainer )
  2622. m_pMainContentContainer->SetDialogVariable( "itemname", wcNOText );
  2623. m_pItemNameLabel->SetVisible( true );
  2624. m_pItemNameLabel->SetColorStr( m_NoItemTextColor );
  2625. m_pItemNameLabel->InvalidateLayout(true,true);
  2626. if ( m_iForceTextSize && m_iForceTextSize <= 3 )
  2627. {
  2628. // Leave center wrap on if the noitem text is getting to use the whole panel
  2629. if ( !m_bNoItemFullPanel )
  2630. {
  2631. m_pItemNameLabel->SetCenterWrap( false );
  2632. }
  2633. switch ( m_iForceTextSize )
  2634. {
  2635. case 1:
  2636. m_pItemNameLabel->SetFont( m_pFontNameLarge );
  2637. break;
  2638. case 2:
  2639. m_pItemNameLabel->SetFont( m_pFontNameSmall );
  2640. break;
  2641. case 3:
  2642. m_pItemNameLabel->SetFont( m_pFontNameSmallest );
  2643. break;
  2644. }
  2645. }
  2646. }
  2647. else
  2648. {
  2649. m_pItemNameLabel->SetVisible( false );
  2650. }
  2651. }
  2652. if ( !m_bNameOnly && m_pwcNoItemAttrib )
  2653. {
  2654. if ( m_pMainContentContainer )
  2655. m_pMainContentContainer->SetDialogVariable( "attriblist", m_pwcNoItemAttrib );
  2656. if ( m_pItemAttribLabel && !m_pItemAttribLabel->IsVisible() )
  2657. {
  2658. m_pItemAttribLabel->SetVisible( true );
  2659. }
  2660. }
  2661. else
  2662. {
  2663. if ( m_pItemAttribLabel && m_pItemAttribLabel->IsVisible() )
  2664. {
  2665. m_pItemAttribLabel->SetVisible( false );
  2666. }
  2667. }
  2668. }
  2669. HideAllModifierIcons();
  2670. return;
  2671. }
  2672. if ( m_bHideModifierIcons )
  2673. {
  2674. HideAllModifierIcons();
  2675. return;
  2676. }
  2677. if ( m_pPaintIcon )
  2678. {
  2679. m_pPaintIcon->SetVisible( false );
  2680. if ( !m_bHideModel && !m_bHidePaintIcon )
  2681. {
  2682. // Empty out our list of paint colors. We may or may not put things back in -- an empty
  2683. // list at the end means "don't draw the paint icon".
  2684. m_pPaintIcon->m_colPaintColors.RemoveAll();
  2685. // Fetch custom texture, if any
  2686. m_pPaintIcon->m_hUGCId = m_ItemData.GetCustomUserTextureID();
  2687. if ( m_pPaintIcon->m_hUGCId != 0 )
  2688. m_pPaintIcon->SetVisible( true );
  2689. // Don't show paint icons on any tools, their icon contains the color
  2690. const bool bIsEconTool = m_ItemData.GetItemDefinition()->IsTool();
  2691. // Has the item been painted?
  2692. int iRGB0 = m_ItemData.GetModifiedRGBValue( false ),
  2693. iRGB1 = m_ItemData.GetModifiedRGBValue( true );
  2694. if ( !bIsEconTool && (iRGB0 != 0 || iRGB1 != 0))
  2695. {
  2696. m_pPaintIcon->SetVisible( true );
  2697. m_pPaintIcon->m_colPaintColors.AddToTail( Color( clamp( (iRGB0 & 0xFF0000) >> 16, 0, 255 ), clamp( (iRGB0 & 0xFF00) >> 8, 0, 255 ), clamp( (iRGB0 & 0xFF), 0, 255 ), 255 ) );
  2698. if ( iRGB0 != iRGB1 )
  2699. {
  2700. m_pPaintIcon->m_colPaintColors.AddToTail( Color( clamp( (iRGB1 & 0xFF0000) >> 16, 0, 255 ), clamp( (iRGB1 & 0xFF00) >> 8, 0, 255 ), clamp( (iRGB1 & 0xFF), 0, 255 ), 255 ) );
  2701. }
  2702. }
  2703. }
  2704. }
  2705. if ( m_pTF2Icon )
  2706. {
  2707. if ( m_bHideModel || m_bHidePaintIcon )
  2708. {
  2709. m_pTF2Icon->SetVisible( false );
  2710. }
  2711. else
  2712. {
  2713. m_pTF2Icon->SetVisible( m_ItemData.GetSOCData() && m_ItemData.GetSOCData()->IsForeign() );
  2714. }
  2715. }
  2716. if ( m_bNoItemFullPanel )
  2717. {
  2718. // If we're a noitem-fullpanel mode, we don't show strings when we have an item.
  2719. m_pItemNameLabel->SetVisible( false );
  2720. m_pItemAttribLabel->SetVisible( false );
  2721. }
  2722. else if ( m_bModelOnly )
  2723. {
  2724. if ( m_pItemNameLabel )
  2725. {
  2726. m_pItemNameLabel->SetVisible( false );
  2727. }
  2728. if ( m_pItemAttribLabel )
  2729. {
  2730. m_pItemAttribLabel->SetVisible( false );
  2731. }
  2732. }
  2733. else
  2734. {
  2735. // deferred description loading
  2736. m_bDescriptionDirty = true;
  2737. SetNeedsToLoad();
  2738. if ( m_pMainContentContainer )
  2739. m_pMainContentContainer->SetDialogVariable( "itemname", "" );
  2740. }
  2741. if ( m_pItemEquippedLabel )
  2742. {
  2743. m_pItemEquippedLabel->SetVisible( m_bForceShowEquipped || (m_bShowEquipped && IsEquipped()) );
  2744. }
  2745. // Hide all of these labels
  2746. if( m_pMatchesLabel )
  2747. {
  2748. m_pMatchesLabel->SetVisible( false );
  2749. }
  2750. if( m_pSeriesLabel )
  2751. {
  2752. m_pSeriesLabel->SetVisible( false );
  2753. }
  2754. if( m_pItemQuantityLabel )
  2755. {
  2756. m_pItemQuantityLabel->SetVisible( false );
  2757. }
  2758. // Update that number in the top right
  2759. if ( !UpdateMatchesLabel() )
  2760. {
  2761. if ( !UpdateSeriesLabel() )
  2762. {
  2763. UpdateQuantityLabel();
  2764. }
  2765. }
  2766. if ( m_pVisionRestrictionImage )
  2767. {
  2768. int nVisionFilterFlags = 0;
  2769. const CEconItemDefinition *pData = m_ItemData.GetItemDefinition();
  2770. if ( !m_bModelOnly && pData )
  2771. {
  2772. nVisionFilterFlags = pData->GetVisionFilterFlags();
  2773. // Add support for all the holidays and "vision" mode restrictions
  2774. if ( pData->GetHolidayRestriction() )
  2775. {
  2776. int iHolidayRestriction = UTIL_GetHolidayForString( pData->GetHolidayRestriction() );
  2777. switch ( iHolidayRestriction )
  2778. {
  2779. default:
  2780. case kHoliday_None:
  2781. case kHoliday_TFBirthday:
  2782. case kHoliday_Christmas:
  2783. case kHoliday_Valentines:
  2784. case kHoliday_MeetThePyro:
  2785. case kHoliday_AprilFools:
  2786. case kHoliday_EOTL:
  2787. case kHoliday_CommunityUpdate:
  2788. break;
  2789. case kHoliday_Halloween:
  2790. case kHoliday_FullMoon:
  2791. case kHoliday_HalloweenOrFullMoon:
  2792. case kHoliday_HalloweenOrFullMoonOrValentines:
  2793. #ifdef TF_CLIENT_DLL
  2794. nVisionFilterFlags |= TF_VISION_FILTER_HALLOWEEN;
  2795. #endif
  2796. break;
  2797. }
  2798. }
  2799. }
  2800. switch ( nVisionFilterFlags )
  2801. {
  2802. default:
  2803. AssertMsg1( false, "Unexpected vision restriction flags %d", nVisionFilterFlags );
  2804. case 0:
  2805. m_pVisionRestrictionImage->SetVisible( false );
  2806. break;
  2807. #ifdef TF_CLIENT_DLL
  2808. case 1:
  2809. m_pVisionRestrictionImage->SetImage( "viewmode_pyrovision" );
  2810. m_pVisionRestrictionImage->SetVisible( true );
  2811. break;
  2812. case 2:
  2813. // Check if most players who have not specifically opted in will see the item.
  2814. if ( TFGameRules() ? TFGameRules()->IsHolidayActive( kHoliday_HalloweenOrFullMoon ) : TF_IsHolidayActive( kHoliday_HalloweenOrFullMoon ) )
  2815. {
  2816. m_pVisionRestrictionImage->SetImage( "viewmode_spooky" );
  2817. }
  2818. else
  2819. {
  2820. m_pVisionRestrictionImage->SetImage( "viewmode_spooky_off" );
  2821. }
  2822. m_pVisionRestrictionImage->SetVisible( true );
  2823. break;
  2824. case 4:
  2825. m_pVisionRestrictionImage->SetVisible( false );
  2826. break;
  2827. #endif
  2828. }
  2829. }
  2830. // Strange Icon
  2831. static CSchemaAttributeDefHandle pAttrDef_StatTrakModule( "weapon_uses_stattrak_module" );
  2832. if ( m_pIsStrangeImage )
  2833. {
  2834. m_pIsStrangeImage->SetVisible( false );
  2835. if ( !m_bIsMouseOverPanel )
  2836. {
  2837. // Allow for already strange items
  2838. bool bIsStrange = false;
  2839. if ( m_ItemData.GetQuality() == AE_STRANGE )
  2840. {
  2841. bIsStrange = true;
  2842. }
  2843. if ( !bIsStrange )
  2844. {
  2845. // Go over the attributes of the item, if it has any strange attributes the item is strange and don't apply
  2846. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  2847. {
  2848. if ( m_ItemData.FindAttribute( GetKillEaterAttr_Score( i ) ) )
  2849. {
  2850. bIsStrange = true;
  2851. break;
  2852. }
  2853. }
  2854. }
  2855. if ( bIsStrange )
  2856. {
  2857. if ( pAttrDef_StatTrakModule && m_ItemData.FindAttribute( pAttrDef_StatTrakModule ) )
  2858. {
  2859. m_pIsStrangeImage->SetImage( "viewmode_statclock" );
  2860. }
  2861. else
  2862. {
  2863. m_pIsStrangeImage->SetImage( "viewmode_strange" );
  2864. }
  2865. m_pIsStrangeImage->SetVisible( true );
  2866. }
  2867. }
  2868. }
  2869. // Unusual Icon
  2870. if ( m_pIsUnusualImage )
  2871. {
  2872. m_pIsUnusualImage->SetVisible( false );
  2873. static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
  2874. static CSchemaAttributeDefHandle pAttrDef_TauntParticle( "on taunt attach particle index" );
  2875. if ( pAttrDef_ParticleEffect && pAttrDef_TauntParticle && !m_bIsMouseOverPanel )
  2876. {
  2877. // Cant use quality cause of old legacy items. Quality is just a quick test
  2878. if ( m_ItemData.FindAttribute( pAttrDef_ParticleEffect ) || m_ItemData.FindAttribute( pAttrDef_TauntParticle ) )
  2879. {
  2880. m_pIsUnusualImage->SetImage( "viewmode_unusual" );
  2881. m_pIsUnusualImage->SetVisible( true );
  2882. }
  2883. }
  2884. }
  2885. if ( m_pIsLoanerImage )
  2886. {
  2887. m_pIsLoanerImage->SetVisible( false );
  2888. if ( !m_bIsMouseOverPanel && GetAssociatedQuestItemID( &m_ItemData ) != INVALID_ITEM_ID )
  2889. {
  2890. m_pIsLoanerImage->SetImage( "viewmode_loaner" );
  2891. m_pIsLoanerImage->SetVisible( true );
  2892. }
  2893. }
  2894. InvalidateLayout();
  2895. }
  2896. //-----------------------------------------------------------------------------
  2897. // Purpose:
  2898. //-----------------------------------------------------------------------------
  2899. bool CItemModelPanel::IsEquipped( void )
  2900. {
  2901. if ( !HasItem() )
  2902. return false;
  2903. return m_ItemData.IsEquipped();
  2904. }
  2905. //-----------------------------------------------------------------------------
  2906. // Purpose:
  2907. //-----------------------------------------------------------------------------
  2908. void CItemModelPanel::SetGreyedOut( const char *pszGreyedOutReason )
  2909. {
  2910. m_pszGreyedOutReason = pszGreyedOutReason;
  2911. if ( m_pModelPanel )
  2912. {
  2913. m_pModelPanel->SetGreyedOut( m_pszGreyedOutReason != NULL );
  2914. }
  2915. UpdateEquippedLabel();
  2916. }
  2917. //-----------------------------------------------------------------------------
  2918. // Purpose:
  2919. //-----------------------------------------------------------------------------
  2920. bool CItemModelPanel::HasItem( void )
  2921. {
  2922. return m_ItemData.IsValid();
  2923. }
  2924. void CItemModelPanel::SetModelIsHidden( bool bHideModel )
  2925. {
  2926. m_bHideModel = bHideModel;
  2927. if ( m_pModelPanel )
  2928. {
  2929. m_pModelPanel->SetModelHidden( bHideModel );
  2930. }
  2931. }
  2932. void CItemModelPanel::OnTick()
  2933. {
  2934. bool bStillWorking = LoadData();
  2935. if ( m_pContainedItemPanel )
  2936. {
  2937. bStillWorking |= m_pContainedItemPanel->LoadData();
  2938. }
  2939. // If we're done working, we dont need to tick anymore
  2940. if ( !bStillWorking )
  2941. {
  2942. LoadDataCompleted();
  2943. }
  2944. BaseClass::OnTick();
  2945. }
  2946. void CItemModelPanel::SetNeedsToLoad()
  2947. {
  2948. vgui::ivgui()->AddTickSignalToHead( GetVPanel() );
  2949. }
  2950. bool CItemModelPanel::LoadData()
  2951. {
  2952. // Different frame?
  2953. if ( sm_nCurrentDecriptionUpdateFrame != gpGlobals->framecount )
  2954. {
  2955. // Reset
  2956. sm_nCurrentDecriptionUpdateFrame = gpGlobals->framecount;
  2957. sm_flLoadingTimeThisFrame = 0.f;
  2958. // Figure out which loading we're going to do. We want to load
  2959. // certain things sooner (visual things, ie icons) than we start
  2960. // figuring out recipe matches.
  2961. eLoadingType_t type = NUM_LOADING_TYPES;
  2962. for( int i=0; i < NUM_LOADING_TYPES; ++i )
  2963. {
  2964. if ( sai_NumLoadingRequests[i] > 0 && eLoadingType_t(i) < type )
  2965. {
  2966. type = eLoadingType_t(i);
  2967. }
  2968. sai_NumLoadingRequests[i] = 0;
  2969. }
  2970. se_CurrentLoadingTask = type;
  2971. }
  2972. bool bStillWorking = CheckRecipeMatches();
  2973. if ( !m_bHideModel && m_pModelPanel )
  2974. {
  2975. bool bImageLoaded = true;
  2976. bool bLoadingWeaponSkin = m_pModelPanel->IsLoadingWeaponSkin();
  2977. bool bLoadingBackpackIcon = m_pModelPanel->IsImageNotLoaded();
  2978. if ( bLoadingWeaponSkin || bLoadingBackpackIcon )
  2979. {
  2980. // We still need to load icons
  2981. sai_NumLoadingRequests[LOADING_ICONS]++;
  2982. if ( sm_flLoadingTimeThisFrame < tf_time_loading_item_panels.GetFloat() && se_CurrentLoadingTask == LOADING_ICONS )
  2983. {
  2984. float flTime = Plat_FloatTime();
  2985. // no need to load texture if we're doing composite weapon skin
  2986. if ( bLoadingWeaponSkin )
  2987. {
  2988. g_pMatSystemSurface->BeginSkinCompositionPainting();
  2989. m_pModelPanel->Paint();
  2990. g_pMatSystemSurface->EndSkinCompositionPainting();
  2991. }
  2992. if ( bLoadingBackpackIcon )
  2993. {
  2994. m_pModelPanel->LoadInventoryImage();
  2995. }
  2996. // Accumulate time
  2997. sm_flLoadingTimeThisFrame += ( Plat_FloatTime() - flTime );
  2998. }
  2999. bStillWorking = m_pModelPanel->IsLoadingWeaponSkin() || m_pModelPanel->IsImageNotLoaded();
  3000. bImageLoaded = !bStillWorking;
  3001. }
  3002. // Hide the spinner and show the main container
  3003. if ( bImageLoaded )
  3004. {
  3005. if ( m_pMainContentContainer && !m_pMainContentContainer->IsVisible() )
  3006. {
  3007. m_pMainContentContainer->SetVisible( true );
  3008. }
  3009. if ( m_pLoadingSpinner && m_pLoadingSpinner->IsVisible() )
  3010. {
  3011. m_pLoadingSpinner->SetVisible( false );
  3012. }
  3013. }
  3014. }
  3015. if ( m_bDescriptionDirty && !IsContainedItem() )
  3016. {
  3017. // We still need to load our description
  3018. sai_NumLoadingRequests[LOADING_DESCRIPTIONS]++;
  3019. // Check if we're clear to update. We only want to eat up a little slice of time.
  3020. if ( sm_flLoadingTimeThisFrame < tf_time_loading_item_panels.GetFloat() && se_CurrentLoadingTask == LOADING_DESCRIPTIONS )
  3021. {
  3022. float flTime = Plat_FloatTime();
  3023. // Update!
  3024. UpdateDescription();
  3025. // Accumulate time
  3026. sm_flLoadingTimeThisFrame += ( Plat_FloatTime() - flTime );
  3027. }
  3028. bStillWorking |= m_bDescriptionDirty;
  3029. }
  3030. return bStillWorking;
  3031. }
  3032. void CItemModelPanel::LoadDataCompleted()
  3033. {
  3034. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  3035. }
  3036. //-----------------------------------------------------------------------------
  3037. // Purpose:
  3038. //-----------------------------------------------------------------------------
  3039. void CItemModelPanel::SetActAsButton( bool bClickable, bool bMouseOver )
  3040. {
  3041. m_bClickable = bClickable;
  3042. m_bMouseOver = bMouseOver;
  3043. SetMouseInputEnabled( m_bClickable || m_bMouseOver );
  3044. }
  3045. void CItemModelPanel::NavigateTo()
  3046. {
  3047. BaseClass::NavigateTo();
  3048. if ( IsPC() )
  3049. {
  3050. RequestFocus( 0 );
  3051. }
  3052. }
  3053. void CItemModelPanel::NavigateFrom()
  3054. {
  3055. BaseClass::NavigateFrom();
  3056. }
  3057. //-----------------------------------------------------------------------------
  3058. // Purpose:
  3059. //-----------------------------------------------------------------------------
  3060. void CItemModelPanel::OnCursorEntered( void )
  3061. {
  3062. if ( !m_bMouseOver )
  3063. return;
  3064. if ( m_bShouldSendPanelEnterExits )
  3065. {
  3066. PostActionSignal( new KeyValues("ItemPanelEntered") );
  3067. }
  3068. if ( IsEnabled() && !IsSelected() )
  3069. {
  3070. NavigateTo();
  3071. }
  3072. }
  3073. //-----------------------------------------------------------------------------
  3074. // Purpose:
  3075. //-----------------------------------------------------------------------------
  3076. void CItemModelPanel::OnCursorExited( void )
  3077. {
  3078. if ( !m_bMouseOver )
  3079. return;
  3080. if ( m_bShouldSendPanelEnterExits )
  3081. {
  3082. PostActionSignal( new KeyValues("ItemPanelExited") );
  3083. }
  3084. if ( IsSelected() )
  3085. {
  3086. NavigateFrom();
  3087. }
  3088. }
  3089. //-----------------------------------------------------------------------------
  3090. // Purpose:
  3091. //-----------------------------------------------------------------------------
  3092. extern ISoundEmitterSystemBase *soundemitterbase;
  3093. void CItemModelPanel::OnMousePressed(vgui::MouseCode code)
  3094. {
  3095. if ( code == MOUSE_RIGHT )
  3096. {
  3097. PostActionSignal( new KeyValues("ItemPanelMouseRightRelease") );
  3098. }
  3099. if ( !m_bClickable || code != MOUSE_LEFT )
  3100. return;
  3101. PostActionSignal( new KeyValues("ItemPanelMousePressed") );
  3102. // audible feedback
  3103. const char *soundFilename = "ui/buttonclick.wav";
  3104. if ( m_bUseItemSounds )
  3105. {
  3106. CEconItemView *item = GetItem();
  3107. if ( item )
  3108. {
  3109. soundFilename = item->GetDefinitionString( "mouse_pressed_sound", "ui/item_default_pickup.wav" );
  3110. }
  3111. }
  3112. const char *pszSound = UTIL_GetRandomSoundFromEntry( soundFilename );
  3113. if ( pszSound && pszSound[0] )
  3114. {
  3115. vgui::surface()->PlaySound( pszSound );
  3116. }
  3117. }
  3118. //-----------------------------------------------------------------------------
  3119. // Purpose:
  3120. //-----------------------------------------------------------------------------
  3121. void CItemModelPanel::OnMouseReleased(vgui::MouseCode code)
  3122. {
  3123. if ( !m_bClickable || code != MOUSE_LEFT )
  3124. return;
  3125. PostActionSignal( new KeyValues("ItemPanelMouseReleased") );
  3126. // audible feedback
  3127. // we're not using item sounds here because they are better handled by the drag/drop code elsewhere
  3128. if ( !m_bUseItemSounds )
  3129. {
  3130. vgui::surface()->PlaySound( "ui/buttonclickrelease.wav" );
  3131. }
  3132. }
  3133. //-----------------------------------------------------------------------------
  3134. // Purpose:
  3135. //-----------------------------------------------------------------------------
  3136. void CItemModelPanel::OnMouseDoublePressed(vgui::MouseCode code)
  3137. {
  3138. if ( !m_bClickable || code != MOUSE_LEFT )
  3139. return;
  3140. PostActionSignal( new KeyValues("ItemPanelMouseDoublePressed") );
  3141. // audible feedback
  3142. const char *soundFilename = "ui/buttonclickrelease.wav";
  3143. if ( m_bUseItemSounds )
  3144. {
  3145. CEconItemView *item = GetItem();
  3146. if ( item )
  3147. {
  3148. soundFilename = item->GetDefinitionString( "mouse_double_pressed_sound", "ui/item_default_drop.wav" );
  3149. }
  3150. }
  3151. vgui::surface()->PlaySound( soundFilename );
  3152. }
  3153. //-----------------------------------------------------------------------------
  3154. // Purpose:
  3155. //-----------------------------------------------------------------------------
  3156. void CItemModelPanel::OnCursorMoved( int x, int y )
  3157. {
  3158. if ( !m_bClickable )
  3159. return;
  3160. // Add our own xpos/ypos offset
  3161. int iXPos;
  3162. int iYPos;
  3163. GetPos( iXPos, iYPos );
  3164. PostActionSignal( new KeyValues("ItemPanelCursorMoved", "x", x + iXPos, "y", y + iYPos) );
  3165. }
  3166. void CItemModelPanel::OnKeyCodePressed( vgui::KeyCode code )
  3167. {
  3168. BaseClass::OnKeyCodePressed( code );
  3169. }
  3170. //-----------------------------------------------------------------------------
  3171. // Purpose:
  3172. //-----------------------------------------------------------------------------
  3173. void CItemModelPanel::OnCommand( const char *command )
  3174. {
  3175. if ( FStrEq( command, "sellitem" ) )
  3176. {
  3177. if ( HasItem() && steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
  3178. {
  3179. const char *pszPrefix = "";
  3180. if ( GetUniverse() == k_EUniverseBeta )
  3181. {
  3182. pszPrefix = "beta.";
  3183. }
  3184. uint32 nAssetContext = 2; // k_EEconContextBackpack
  3185. char szURL[512];
  3186. V_snprintf( szURL, sizeof(szURL), "http://%ssteamcommunity.com/my/inventory/?sellOnLoad=1#%d_%d_%llu", pszPrefix, engine->GetAppID(), nAssetContext, GetItem()->GetItemID() );
  3187. steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
  3188. }
  3189. }
  3190. }
  3191. //-----------------------------------------------------------------------------
  3192. // Purpose:
  3193. //-----------------------------------------------------------------------------
  3194. void CItemModelPanel::UpdateEquippedLabel( void )
  3195. {
  3196. if ( !m_pItemEquippedLabel )
  3197. return;
  3198. if ( IsGreyedOut() )
  3199. {
  3200. m_pItemEquippedLabel->SetFgColor( Color(96,96,96,255) );
  3201. }
  3202. else
  3203. {
  3204. m_pItemEquippedLabel->SetFgColor( Color(200,80,60,255) );
  3205. }
  3206. }
  3207. //-----------------------------------------------------------------------------
  3208. // Purpose:
  3209. //-----------------------------------------------------------------------------
  3210. void CItemModelPanel::SetSkin( int iSkin )
  3211. {
  3212. if ( m_pModelPanel )
  3213. {
  3214. m_pModelPanel->SetSkin( iSkin );
  3215. }
  3216. }
  3217. itempanel_tooltippos_t g_iTooltipStrategies[NUM_IPTTP_STRATEGIES][NUM_POSITIONS_PER_STRATEGY] =
  3218. {
  3219. { IPTTP_LEFT, IPTTP_LEFT_CENTERED, IPTTP_ABOVE, IPTTP_BELOW, IPTTP_RIGHT_CENTERED, IPTTP_RIGHT }, // IPTTP_LEFT_SIDE
  3220. { IPTTP_RIGHT, IPTTP_RIGHT_CENTERED, IPTTP_ABOVE, IPTTP_BELOW, IPTTP_LEFT_CENTERED, IPTTP_LEFT }, // IPTTP_RIGHT_SIDE
  3221. { IPTTP_ABOVE, IPTTP_LEFT_CENTERED, IPTTP_RIGHT_CENTERED, IPTTP_LEFT, IPTTP_RIGHT, IPTTP_ABOVE }, // IPTTP_TOP_SIDE
  3222. { IPTTP_BELOW, IPTTP_LEFT_CENTERED, IPTTP_RIGHT_CENTERED, IPTTP_LEFT, IPTTP_RIGHT, IPTTP_ABOVE }, // IPTTP_BOTTOM_SIDE
  3223. };
  3224. //-----------------------------------------------------------------------------
  3225. // Purpose:
  3226. //-----------------------------------------------------------------------------
  3227. CItemModelPanelToolTip::CItemModelPanelToolTip( vgui::Panel *parent, const char *text )
  3228. : vgui::BaseTooltip( parent, text )
  3229. , m_pMouseOverItemPanel( NULL )
  3230. , m_iPositioningStrategy( IPTTP_BOTTOM_SIDE )
  3231. {
  3232. m_hCurrentPanel = NULL;
  3233. SetTooltipDelay( 100 );
  3234. }
  3235. //-----------------------------------------------------------------------------
  3236. // Purpose:
  3237. //-----------------------------------------------------------------------------
  3238. void CItemModelPanelToolTip::GetPosition( itempanel_tooltippos_t iTooltipPosition, CItemModelPanel *pItemPanel, int iItemX, int iItemY, int *iXPos, int *iYPos )
  3239. {
  3240. switch ( iTooltipPosition )
  3241. {
  3242. case IPTTP_LEFT:
  3243. *iXPos = (iItemX - m_pMouseOverItemPanel->GetWide() + XRES(18));
  3244. *iYPos = iItemY - YRES(7);
  3245. break;
  3246. case IPTTP_RIGHT:
  3247. *iXPos = (iItemX + pItemPanel->GetWide() - XRES(20));
  3248. *iYPos = iItemY - YRES(7);
  3249. break;
  3250. case IPTTP_LEFT_CENTERED:
  3251. *iXPos = (iItemX - m_pMouseOverItemPanel->GetWide()) - XRES(4);
  3252. *iYPos = (iItemY - (m_pMouseOverItemPanel->GetTall() * 0.5));
  3253. break;
  3254. case IPTTP_RIGHT_CENTERED:
  3255. *iXPos = (iItemX + pItemPanel->GetWide()) + XRES(4);
  3256. *iYPos = (iItemY - (m_pMouseOverItemPanel->GetTall() * 0.5));
  3257. break;
  3258. case IPTTP_ABOVE:
  3259. *iXPos = (iItemX + (pItemPanel->GetWide() * 0.5)) - (m_pMouseOverItemPanel->GetWide() * 0.5);
  3260. *iYPos = (iItemY - m_pMouseOverItemPanel->GetTall() - YRES(4));
  3261. break;
  3262. case IPTTP_BELOW:
  3263. *iXPos = (iItemX + (pItemPanel->GetWide() * 0.5)) - (m_pMouseOverItemPanel->GetWide() * 0.5);
  3264. *iYPos = (iItemY + pItemPanel->GetTall() + YRES(4));
  3265. break;
  3266. }
  3267. }
  3268. //-----------------------------------------------------------------------------
  3269. // Purpose:
  3270. //-----------------------------------------------------------------------------
  3271. bool CItemModelPanelToolTip::ValidatePosition( CItemModelPanel *pItemPanel, int iItemX, int iItemY, int *iXPos, int *iYPos )
  3272. {
  3273. bool bSucceeded = true;
  3274. // Make sure the popup stays onscreen.
  3275. if ( *iXPos < 0 )
  3276. {
  3277. *iXPos = 0;
  3278. }
  3279. else if ( (*iXPos + m_pMouseOverItemPanel->GetWide()) > m_pParentPanel->GetWide() )
  3280. {
  3281. int iXPosNew = m_pParentPanel->GetWide() - m_pMouseOverItemPanel->GetWide();
  3282. // make sure it is still on the screen
  3283. if ( iXPosNew >= 0 )
  3284. {
  3285. *iXPos = iXPosNew;
  3286. }
  3287. else
  3288. {
  3289. bSucceeded = false;
  3290. }
  3291. }
  3292. if ( *iYPos < 0 )
  3293. {
  3294. *iYPos = 0;
  3295. }
  3296. else if ( (*iYPos + m_pMouseOverItemPanel->GetTall() + YRES(32)) > m_pParentPanel->GetTall() )
  3297. {
  3298. // Move it up above our item
  3299. int iYPosNew = iItemY - m_pMouseOverItemPanel->GetTall() - YRES(4);
  3300. // make sure it is still on the screen
  3301. if ( iYPosNew >= 0 )
  3302. {
  3303. *iYPos = iYPosNew;
  3304. }
  3305. else
  3306. {
  3307. bSucceeded = false;
  3308. }
  3309. }
  3310. if ( bSucceeded )
  3311. {
  3312. // We also fail if moving it to keep it on screen moved it over the item panel itself
  3313. Vector2D vecToolTipMin, vecToolTipMax, vecItemMin, vecItemMax;
  3314. vecToolTipMin.x = *iXPos;
  3315. vecToolTipMin.y = *iYPos;
  3316. vecToolTipMax.x = vecToolTipMin.x + m_pMouseOverItemPanel->GetWide();
  3317. vecToolTipMax.y = vecToolTipMin.y + m_pMouseOverItemPanel->GetTall();
  3318. vecItemMin.x = iItemX;
  3319. vecItemMin.y = iItemY;
  3320. vecItemMax.x = vecItemMin.x + m_hCurrentPanel->GetWide();
  3321. vecItemMax.y = vecItemMin.y + m_hCurrentPanel->GetTall();
  3322. bSucceeded = !( vecToolTipMin.x < vecItemMax.x && vecToolTipMax.x > vecItemMin.x && vecToolTipMin.y < vecItemMax.y && vecToolTipMax.y > vecItemMin.y );
  3323. }
  3324. return bSucceeded;
  3325. }
  3326. //-----------------------------------------------------------------------------
  3327. // Purpose:
  3328. //-----------------------------------------------------------------------------
  3329. void CItemModelPanelToolTip::PerformLayout()
  3330. {
  3331. BaseClass::PerformLayout();
  3332. if ( !ShouldLayout() )
  3333. return;
  3334. _isDirty = false;
  3335. CItemModelPanel *pItemPanel = m_hCurrentPanel.Get();
  3336. if ( m_pMouseOverItemPanel && pItemPanel )
  3337. {
  3338. CEconItemView *pItem = pItemPanel->GetItem();
  3339. if ( pItem && pItemPanel->ShouldShowTooltip() /*&& !IsIgnoringItemPanelEnters()*/ )
  3340. {
  3341. m_pMouseOverItemPanel->SetGreyedOut( pItemPanel->GetGreyedOutReason() );
  3342. m_pMouseOverItemPanel->SetItem( pItem );
  3343. m_pMouseOverItemPanel->DirtyDescription(); // Force rebuilding the description when we first display
  3344. m_pMouseOverItemPanel->UpdateDescription();
  3345. m_pMouseOverItemPanel->HideContainedItemPanel();
  3346. m_pMouseOverItemPanel->InvalidateLayout(true);
  3347. int x,y;
  3348. // If the panel is somewhere in a derived class, we need to get its position in our space
  3349. if ( pItemPanel->GetParent() != m_pMouseOverItemPanel->GetParent() )
  3350. {
  3351. int iItemAbsX, iItemAbsY;
  3352. vgui::ipanel()->GetAbsPos( pItemPanel->GetVPanel(), iItemAbsX, iItemAbsY );
  3353. int iParentAbsX, iParentAbsY;
  3354. vgui::ipanel()->GetAbsPos( m_pMouseOverItemPanel->GetParent()->GetVPanel(), iParentAbsX, iParentAbsY );
  3355. x = (iItemAbsX - iParentAbsX);
  3356. y = (iItemAbsY - iParentAbsY);
  3357. }
  3358. else
  3359. {
  3360. pItemPanel->GetPos( x, y );
  3361. }
  3362. int iXPos = 0;
  3363. int iYPos = 0;
  3364. // Loop through the positions in our strategy, and hope we find a valid spot
  3365. for ( int i = 0; i < NUM_POSITIONS_PER_STRATEGY; i++ )
  3366. {
  3367. itempanel_tooltippos_t iPos = g_iTooltipStrategies[m_iPositioningStrategy][i];
  3368. GetPosition( iPos, pItemPanel, x, y, &iXPos, &iYPos );
  3369. if ( ValidatePosition( pItemPanel, x, y, &iXPos, &iYPos ) )
  3370. break;
  3371. }
  3372. m_pMouseOverItemPanel->SetPos( iXPos, iYPos );
  3373. m_pMouseOverItemPanel->SetVisible( true );
  3374. }
  3375. }
  3376. }
  3377. //-----------------------------------------------------------------------------
  3378. // Purpose:
  3379. //-----------------------------------------------------------------------------
  3380. void CItemModelPanelToolTip::ShowTooltip( Panel *currentPanel )
  3381. {
  3382. if ( m_pMouseOverItemPanel && currentPanel != m_hCurrentPanel.Get() )
  3383. {
  3384. CItemModelPanel *pItemPanel = assert_cast<CItemModelPanel *>(currentPanel);
  3385. m_hCurrentPanel.Set( pItemPanel );
  3386. pItemPanel->PostActionSignal( new KeyValues("ItemPanelEntered") );
  3387. vgui::surface()->PlaySound( "ui/item_info_mouseover.wav" );
  3388. m_pMouseOverItemPanel->HideContainedItemPanel();
  3389. }
  3390. BaseClass::ShowTooltip( currentPanel );
  3391. }
  3392. //-----------------------------------------------------------------------------
  3393. // Purpose:
  3394. //-----------------------------------------------------------------------------
  3395. void CItemModelPanelToolTip::HideTooltip()
  3396. {
  3397. if ( m_pMouseOverItemPanel )
  3398. {
  3399. m_pMouseOverItemPanel->SetVisible( false );
  3400. }
  3401. if ( m_hCurrentPanel )
  3402. {
  3403. m_hCurrentPanel.Get()->PostActionSignal( new KeyValues("ItemPanelExited") );
  3404. m_hCurrentPanel = NULL;
  3405. }
  3406. }