Counter Strike : Global Offensive Source Code
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.

1886 lines
47 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <vgui/IBorder.h>
  8. #include <vgui/IInput.h>
  9. #include <vgui/IPanel.h>
  10. #include <vgui/IScheme.h>
  11. #include <vgui/ISystem.h>
  12. #include <vgui/IVGui.h>
  13. #include <vgui/KeyCode.h>
  14. #include <keyvalues.h>
  15. #include <vgui/MouseCode.h>
  16. #include <vgui/ISurface.h>
  17. #include <vgui_controls/Button.h>
  18. #include <vgui_controls/Controls.h>
  19. #include <vgui_controls/Label.h>
  20. #include <vgui_controls/PropertySheet.h>
  21. #include <vgui_controls/ComboBox.h>
  22. #include <vgui_controls/Panel.h>
  23. #include <vgui_controls/ToolWindow.h>
  24. #include <vgui_controls/TextImage.h>
  25. #include <vgui_controls/ImagePanel.h>
  26. #include <vgui_controls/PropertyPage.h>
  27. #include "vgui_controls/AnimationController.h"
  28. #include "tier1/fmtstr.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include <tier0/memdbgon.h>
  31. #ifdef _PS3
  32. //!!BUG!! "wcsicmp is unsupported on PS3"
  33. #ifdef wcsicmp
  34. #undef wcsicmp
  35. #endif
  36. #define wcsicmp wcscmp
  37. #endif
  38. using namespace vgui;
  39. namespace vgui
  40. {
  41. class ContextLabel : public Label
  42. {
  43. DECLARE_CLASS_SIMPLE( ContextLabel, Label );
  44. public:
  45. ContextLabel( Button *parent, char const *panelName, char const *text ):
  46. BaseClass( (Panel *)parent, panelName, text ),
  47. m_pTabButton( parent )
  48. {
  49. SetBlockDragChaining( true );
  50. }
  51. virtual void OnMousePressed( MouseCode code )
  52. {
  53. if ( m_pTabButton )
  54. {
  55. m_pTabButton->FireActionSignal();
  56. }
  57. }
  58. virtual void OnMouseReleased( MouseCode code )
  59. {
  60. BaseClass::OnMouseReleased( code );
  61. if ( GetParent() )
  62. {
  63. GetParent()->OnCommand( "ShowContextMenu" );
  64. }
  65. }
  66. virtual void ApplySchemeSettings( IScheme *pScheme )
  67. {
  68. BaseClass::ApplySchemeSettings( pScheme );
  69. HFont marlett = pScheme->GetFont( "Marlett" );
  70. SetFont( marlett );
  71. SetTextInset( 0, 0 );
  72. SetContentAlignment( Label::a_northwest );
  73. if ( GetParent() )
  74. {
  75. SetFgColor( pScheme->GetColor( "Button.TextColor", GetParent()->GetFgColor() ) );
  76. SetBgColor( GetParent()->GetBgColor() );
  77. }
  78. }
  79. private:
  80. Button *m_pTabButton;
  81. };
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Helper for drag drop
  84. // Input : msglist -
  85. // Output : static PropertySheet
  86. //-----------------------------------------------------------------------------
  87. static PropertySheet *IsDroppingSheet( CUtlVector< KeyValues * >& msglist )
  88. {
  89. if ( msglist.Count() == 0 )
  90. return NULL;
  91. KeyValues *data = msglist[ 0 ];
  92. PropertySheet *sheet = reinterpret_cast< PropertySheet * >( data->GetPtr( "propertysheet" ) );
  93. if ( sheet )
  94. return sheet;
  95. return NULL;
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose: A single tab
  99. //-----------------------------------------------------------------------------
  100. class PageTab : public Button
  101. {
  102. DECLARE_CLASS_SIMPLE( PageTab, Button );
  103. private:
  104. bool _active;
  105. Color _textColor;
  106. Color _dimTextColor;
  107. int m_bMaxTabWidth;
  108. IBorder *m_pActiveBorder;
  109. IBorder *m_pNormalBorder;
  110. PropertySheet *m_pParent;
  111. Panel *m_pPage;
  112. ImagePanel *m_pImage;
  113. char *m_pszImageName;
  114. bool m_bShowContextLabel;
  115. bool m_bAttemptingDrop;
  116. ContextLabel *m_pContextLabel;
  117. long m_hoverActivatePageTime;
  118. long m_dropHoverTime;
  119. bool m_bDragDropStyle;
  120. public:
  121. PageTab(PropertySheet *parent, const char *panelName, const char *text, char const *imageName, int maxTabWidth, Panel *page, bool showContextButton, long hoverActivatePageTime = -1 ) :
  122. Button( (Panel *)parent, panelName, text),
  123. m_pActiveBorder( NULL ),
  124. m_pNormalBorder( NULL ),
  125. m_pParent( parent ),
  126. m_pPage( page ),
  127. m_pImage( 0 ),
  128. m_pszImageName( 0 ),
  129. m_bShowContextLabel( showContextButton ),
  130. m_bAttemptingDrop( false ),
  131. m_hoverActivatePageTime( hoverActivatePageTime ),
  132. m_dropHoverTime( -1 ),
  133. m_bDragDropStyle( false )
  134. {
  135. SetCommand(new KeyValues("TabPressed"));
  136. _active = false;
  137. m_bMaxTabWidth = maxTabWidth;
  138. SetDropEnabled( true );
  139. SetDragEnabled( m_pParent->IsDraggableTab() );
  140. if ( imageName )
  141. {
  142. m_pImage = new ImagePanel( this, text );
  143. int buflen = Q_strlen( imageName ) + 1;
  144. m_pszImageName = new char[ buflen ];
  145. Q_strncpy( m_pszImageName, imageName, buflen );
  146. }
  147. SetMouseClickEnabled( MOUSE_RIGHT, true );
  148. m_pContextLabel = m_bShowContextLabel ? new ContextLabel( this, "Context", "9" ) : NULL;
  149. REGISTER_COLOR_AS_OVERRIDABLE( _textColor, "selectedcolor" );
  150. REGISTER_COLOR_AS_OVERRIDABLE( _dimTextColor, "unselectedcolor" );
  151. }
  152. ~PageTab()
  153. {
  154. delete[] m_pszImageName;
  155. }
  156. void SetDragDropStyle( bool bStyle )
  157. {
  158. m_bDragDropStyle = bStyle;
  159. }
  160. virtual void Paint()
  161. {
  162. BaseClass::Paint();
  163. if ( !m_bDragDropStyle )
  164. return;
  165. int w, h;
  166. GetSize( w, h );
  167. surface()->DrawSetColor( m_pParent->GetDropFrameColor() );
  168. // Top
  169. surface()->DrawOutlinedRect( 0, 0, w, 2 );
  170. // surface()->DrawOutlinedRect( 0, 0, w, 1 );
  171. // Left
  172. surface()->DrawOutlinedRect( 0, 0, 2, h );
  173. // Right
  174. surface()->DrawOutlinedRect( w-2, 0, w, h );
  175. }
  176. virtual void OnCursorEntered()
  177. {
  178. m_dropHoverTime = system()->GetTimeMillis();
  179. }
  180. virtual void OnCursorExited()
  181. {
  182. m_dropHoverTime = -1;
  183. }
  184. virtual void OnThink()
  185. {
  186. if ( m_bAttemptingDrop && m_hoverActivatePageTime >= 0 && m_dropHoverTime >= 0 )
  187. {
  188. long hoverTime = system()->GetTimeMillis() - m_dropHoverTime;
  189. if ( hoverTime > m_hoverActivatePageTime )
  190. {
  191. FireActionSignal();
  192. SetSelected(true);
  193. Repaint();
  194. }
  195. }
  196. m_bAttemptingDrop = false;
  197. BaseClass::OnThink();
  198. }
  199. virtual bool IsDroppable( CUtlVector< KeyValues * >&msglist )
  200. {
  201. m_bAttemptingDrop = true;
  202. if ( !GetParent() )
  203. return false;
  204. PropertySheet *sheet = IsDroppingSheet( msglist );
  205. if ( sheet )
  206. return GetParent()->IsDroppable( msglist );
  207. return BaseClass::IsDroppable( msglist );
  208. }
  209. virtual void OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels )
  210. {
  211. PropertySheet *sheet = IsDroppingSheet( msglist );
  212. if ( sheet )
  213. {
  214. Panel *target = GetParent()->GetDropTarget( msglist );
  215. if ( target )
  216. {
  217. // Fixme, mouse pos could be wrong...
  218. target->OnDroppablePanelPaint( msglist, dragPanels );
  219. return;
  220. }
  221. }
  222. // Just highlight the tab if dropping onto active page via the tab
  223. BaseClass::OnDroppablePanelPaint( msglist, dragPanels );
  224. }
  225. virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist )
  226. {
  227. PropertySheet *sheet = IsDroppingSheet( msglist );
  228. // Msg( "Tab::OnPanelDropped(sheet %s)\n", sheet ? "yes" : "no" );
  229. if ( sheet )
  230. {
  231. Panel *target = GetParent()->GetDropTarget( msglist );
  232. if ( target )
  233. {
  234. // Fixme, mouse pos could be wrong...
  235. target->OnPanelDropped( msglist );
  236. }
  237. }
  238. // Defer to active page...
  239. Panel *active = m_pParent->GetActivePage();
  240. if ( !active || !active->IsDroppable( msglist ) )
  241. return;
  242. active->OnPanelDropped( msglist );
  243. }
  244. virtual void OnDragFailed( CUtlVector< KeyValues * >& msglist )
  245. {
  246. PropertySheet *sheet = IsDroppingSheet( msglist );
  247. if ( !sheet )
  248. return;
  249. // Msg( "Tab::OnDragFailed(sheet %s)\n", sheet ? "yes" : "no" );
  250. // Create a new property sheet
  251. if ( m_pParent->IsDraggableTab() )
  252. {
  253. if ( msglist.Count() == 1 )
  254. {
  255. KeyValues *data = msglist[ 0 ];
  256. int screenx = data->GetInt( "screenx" );
  257. int screeny = data->GetInt( "screeny" );
  258. // m_pParent->ScreenToLocal( screenx, screeny );
  259. if ( !m_pParent->IsWithin( screenx, screeny ) )
  260. {
  261. Panel *page = reinterpret_cast< Panel * >( data->GetPtr( "propertypage" ) );
  262. PropertySheet *sheet = reinterpret_cast< PropertySheet * >( data->GetPtr( "propertysheet" ) );
  263. char const *title = data->GetString( "tabname", "" );
  264. if ( !page || !sheet )
  265. return;
  266. // Can only create if sheet was part of a ToolWindow derived object
  267. ToolWindow *tw = dynamic_cast< ToolWindow * >( sheet->GetParent() );
  268. if ( tw )
  269. {
  270. IToolWindowFactory *factory = tw->GetToolWindowFactory();
  271. if ( factory )
  272. {
  273. bool hasContextMenu = sheet->PageHasContextMenu( page );
  274. sheet->RemovePage( page );
  275. factory->InstanceToolWindow( tw->GetParent(), sheet->ShouldShowContextButtons(), page, title, hasContextMenu );
  276. if ( sheet->GetNumPages() == 0 )
  277. {
  278. tw->MarkForDeletion();
  279. }
  280. }
  281. }
  282. }
  283. }
  284. }
  285. }
  286. virtual HCursor GetDragFailCursor( CUtlVector< KeyValues * >& msglist )
  287. {
  288. PropertySheet *sheet = IsDroppingSheet( msglist );
  289. if ( !sheet )
  290. return BaseClass::GetDragFailCursor( msglist );
  291. // Dragging a pagetab somewhere invalid will result in a new toolwindow getting created, which is perfectly valid
  292. return dc_arrow;
  293. }
  294. virtual void OnCreateDragData( KeyValues *msg )
  295. {
  296. Assert( m_pParent->IsDraggableTab() );
  297. msg->SetPtr( "propertypage", m_pPage );
  298. msg->SetPtr( "propertysheet", m_pParent );
  299. char sz[ 256 ];
  300. GetText( sz, sizeof( sz ) );
  301. msg->SetString( "tabname", sz );
  302. msg->SetString( "text", sz );
  303. }
  304. virtual void ApplySchemeSettings(IScheme *pScheme)
  305. {
  306. // set up the scheme settings
  307. Button::ApplySchemeSettings(pScheme);
  308. _textColor = GetSchemeColor("PropertySheet.SelectedTextColor", GetFgColor(), pScheme);
  309. _dimTextColor = GetSchemeColor("PropertySheet.TextColor", GetFgColor(), pScheme);
  310. m_pActiveBorder = pScheme->GetBorder("TabActiveBorder");
  311. m_pNormalBorder = pScheme->GetBorder("TabBorder");
  312. Resize();
  313. if ( m_pContextLabel )
  314. {
  315. SetTextInset( 12, 0 );
  316. }
  317. }
  318. void Resize()
  319. {
  320. if ( m_pImage )
  321. {
  322. ClearImages();
  323. m_pImage->SetImage(scheme()->GetImage(m_pszImageName, false));
  324. AddImage( m_pImage->GetImage(), 2 );
  325. int w, h;
  326. m_pImage->GetSize( w, h );
  327. w += m_pContextLabel ? 10 : 0;
  328. if ( m_pContextLabel )
  329. {
  330. m_pImage->SetPos( 10, 0 );
  331. }
  332. SetSize( w + 4, h + 2 );
  333. }
  334. else
  335. {
  336. int wide, tall;
  337. int contentWide, contentTall;
  338. GetSize(wide, tall);
  339. GetContentSize(contentWide, contentTall);
  340. wide = MAX(m_bMaxTabWidth, contentWide + 10); // 10 = 5 pixels margin on each side
  341. wide += m_pContextLabel ? 10 : 0;
  342. SetSize(wide, tall);
  343. }
  344. }
  345. virtual void ApplySettings( KeyValues *inResourceData )
  346. {
  347. BaseClass::ApplySettings(inResourceData);
  348. const char *pBorder = inResourceData->GetString("activeborder_override", "");
  349. if (*pBorder)
  350. {
  351. m_pActiveBorder = scheme()->GetIScheme(GetScheme())->GetBorder( pBorder );
  352. }
  353. pBorder = inResourceData->GetString("normalborder_override", "");
  354. if (*pBorder)
  355. {
  356. m_pNormalBorder = scheme()->GetIScheme(GetScheme())->GetBorder( pBorder );
  357. }
  358. }
  359. virtual void OnCommand( char const *cmd )
  360. {
  361. if ( !Q_stricmp( cmd, "ShowContextMenu" ) )
  362. {
  363. KeyValues *kv = new KeyValues("OpenContextMenu");
  364. kv->SetPtr( "page", m_pPage );
  365. kv->SetPtr( "contextlabel", m_pContextLabel );
  366. PostActionSignal( kv );
  367. return;
  368. }
  369. BaseClass::OnCommand( cmd );
  370. }
  371. IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
  372. {
  373. if (_active)
  374. {
  375. return m_pActiveBorder;
  376. }
  377. return m_pNormalBorder;
  378. }
  379. virtual Color GetButtonFgColor()
  380. {
  381. if (_active)
  382. {
  383. return _textColor;
  384. }
  385. else
  386. {
  387. return _dimTextColor;
  388. }
  389. }
  390. virtual void SetActive(bool state)
  391. {
  392. _active = state;
  393. SetZPos( state ? 100 : 0 );
  394. InvalidateLayout();
  395. Repaint();
  396. }
  397. virtual void SetTabWidth( int iWidth )
  398. {
  399. m_bMaxTabWidth = iWidth;
  400. InvalidateLayout();
  401. }
  402. virtual bool CanBeDefaultButton(void)
  403. {
  404. return false;
  405. }
  406. //Fire action signal when mouse is pressed down instead of on release.
  407. virtual void OnMousePressed(MouseCode code)
  408. {
  409. // check for context menu open
  410. if (!IsEnabled())
  411. return;
  412. if (!IsMouseClickEnabled(code))
  413. return;
  414. if (IsUseCaptureMouseEnabled())
  415. {
  416. {
  417. RequestFocus();
  418. FireActionSignal();
  419. SetSelected(true);
  420. Repaint();
  421. }
  422. // lock mouse input to going to this button
  423. input()->SetMouseCapture(GetVPanel());
  424. }
  425. }
  426. virtual void OnMouseReleased(MouseCode code)
  427. {
  428. // ensure mouse capture gets released
  429. if (IsUseCaptureMouseEnabled())
  430. {
  431. input()->SetMouseCapture(NULL);
  432. }
  433. // make sure the button gets unselected
  434. SetSelected(false);
  435. Repaint();
  436. if (code == MOUSE_RIGHT)
  437. {
  438. KeyValues *kv = new KeyValues("OpenContextMenu");
  439. kv->SetPtr( "page", m_pPage );
  440. kv->SetPtr( "contextlabel", m_pContextLabel );
  441. PostActionSignal( kv );
  442. }
  443. }
  444. virtual void PerformLayout()
  445. {
  446. BaseClass::PerformLayout();
  447. if ( m_pContextLabel )
  448. {
  449. int w, h;
  450. GetSize( w, h );
  451. m_pContextLabel->SetBounds( 0, 0, 10, h );
  452. }
  453. }
  454. };
  455. }; // namespace vgui
  456. //-----------------------------------------------------------------------------
  457. // Purpose: Constructor
  458. //-----------------------------------------------------------------------------
  459. PropertySheet::PropertySheet(
  460. Panel *parent,
  461. const char *panelName,
  462. bool draggableTabs /*= false*/ ) : BaseClass(parent, panelName)
  463. {
  464. _activePage = NULL;
  465. _activeTab = NULL;
  466. _tabWidth = 64;
  467. _activeTabIndex = 0;
  468. _showTabs = true;
  469. _combo = NULL;
  470. _tabFocus = false;
  471. m_flPageTransitionEffectTime = 0.0f;
  472. m_bSmallTabs = false;
  473. m_tabFont = 0;
  474. m_bDraggableTabs = draggableTabs;
  475. m_pTabKV = NULL;
  476. m_iTabHeight = 0;
  477. m_iTabHeightSmall = 0;
  478. if ( m_bDraggableTabs )
  479. {
  480. SetDropEnabled( true );
  481. }
  482. m_bKBNavigationEnabled = true;
  483. m_pDragDropTab = new PageTab( this, "dragdroptab", "", NULL, _tabWidth, NULL, false, 0 );
  484. m_pDragDropTab->SetVisible( false );
  485. m_pDragDropTab->SetDragDropStyle( true );
  486. m_nPageDropTabVisibleTime = -1;
  487. m_pTemporarilyRemoved = NULL;
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Purpose: Constructor, associates pages with a combo box
  491. //-----------------------------------------------------------------------------
  492. PropertySheet::PropertySheet(Panel *parent, const char *panelName, ComboBox *combo) : BaseClass(parent, panelName)
  493. {
  494. _activePage = NULL;
  495. _activeTab = NULL;
  496. _tabWidth = 64;
  497. _activeTabIndex = 0;
  498. _combo=combo;
  499. _combo->AddActionSignalTarget(this);
  500. _showTabs = false;
  501. _tabFocus = false;
  502. m_flPageTransitionEffectTime = 0.0f;
  503. m_bSmallTabs = false;
  504. m_tabFont = 0;
  505. m_bDraggableTabs = false;
  506. m_pTabKV = NULL;
  507. m_pDragDropTab = new PageTab( this, "dragdroptab", "", NULL, _tabWidth, NULL, false, 0 );
  508. m_pDragDropTab->SetVisible( false );
  509. m_pDragDropTab->SetDragDropStyle( true );
  510. m_nPageDropTabVisibleTime = -1;
  511. m_pTemporarilyRemoved = NULL;
  512. m_iTabHeight = 0;
  513. m_iTabHeightSmall = 0;
  514. }
  515. //-----------------------------------------------------------------------------
  516. // Purpose: Destructor
  517. //-----------------------------------------------------------------------------
  518. PropertySheet::~PropertySheet()
  519. {
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Purpose: ToolWindow uses this to drag tools from container to container by dragging the tab
  523. // Input : -
  524. // Output : Returns true on success, false on failure.
  525. //-----------------------------------------------------------------------------
  526. bool PropertySheet::IsDraggableTab() const
  527. {
  528. return m_bDraggableTabs;
  529. }
  530. void PropertySheet::SetDraggableTabs( bool state )
  531. {
  532. m_bDraggableTabs = state;
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose: Lower profile tabs
  536. // Input : state -
  537. //-----------------------------------------------------------------------------
  538. void PropertySheet::SetSmallTabs( bool state )
  539. {
  540. m_bSmallTabs = state;
  541. m_tabFont = scheme()->GetIScheme( GetScheme() )->GetFont( m_bSmallTabs ? "DefaultVerySmall" : "Default" );
  542. int c = m_PageTabs.Count();
  543. for ( int i = 0; i < c ; ++i )
  544. {
  545. PageTab *tab = m_PageTabs[ i ];
  546. Assert( tab );
  547. tab->SetFont( m_tabFont );
  548. }
  549. }
  550. void PropertySheet::SetShowTabs( bool state )
  551. {
  552. _showTabs = state;
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose:
  556. // Input : -
  557. // Output : Returns true on success, false on failure.
  558. //-----------------------------------------------------------------------------
  559. bool PropertySheet::IsSmallTabs() const
  560. {
  561. return m_bSmallTabs;
  562. }
  563. //-----------------------------------------------------------------------------
  564. // Purpose:
  565. // Input : state -
  566. //-----------------------------------------------------------------------------
  567. void PropertySheet::ShowContextButtons( bool state )
  568. {
  569. m_bContextButton = state;
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Purpose:
  573. // Input : -
  574. // Output : Returns true on success, false on failure.
  575. //-----------------------------------------------------------------------------
  576. bool PropertySheet::ShouldShowContextButtons() const
  577. {
  578. return m_bContextButton;
  579. }
  580. int PropertySheet::FindPage( Panel *page ) const
  581. {
  582. int c = m_Pages.Count();
  583. for ( int i = 0; i < c; ++i )
  584. {
  585. if ( m_Pages[ i ].page == page )
  586. return i;
  587. }
  588. return m_Pages.InvalidIndex();
  589. }
  590. void PropertySheet::SetPageTitle( Panel *page, const char *title )
  591. {
  592. if ( !page )
  593. return;
  594. int nSlot = FindPage( page );
  595. if ( nSlot == m_Pages.InvalidIndex() )
  596. return;
  597. PageTab *pTab = m_PageTabs[ nSlot ];
  598. pTab->SetText( title );
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose: adds a page to the sheet
  602. //-----------------------------------------------------------------------------
  603. void PropertySheet::AddPage(Panel *page, const char *title, char const *imageName /*= NULL*/, bool bHasContextMenu /*= false*/, int nInsertBefore /*= -1*/ )
  604. {
  605. if (!page)
  606. return;
  607. // don't add the page if we already have it
  608. int nSlot = FindPage( page );
  609. if ( nSlot != m_Pages.InvalidIndex() )
  610. {
  611. // See about re-ordering
  612. if ( nInsertBefore != -1 && ( nSlot != nInsertBefore ) )
  613. {
  614. if ( nSlot < nInsertBefore )
  615. {
  616. --nInsertBefore;
  617. }
  618. PageTab *pTab = m_PageTabs[ nSlot ];
  619. m_PageTabs.Remove( nSlot );
  620. Page_t pt = m_Pages[ nSlot ];
  621. m_Pages.Remove( nSlot );
  622. m_PageTabs.InsertBefore( nInsertBefore, pTab );
  623. m_Pages.InsertBefore( nInsertBefore, pt );
  624. InvalidateLayout();
  625. }
  626. return;
  627. }
  628. long hoverActivatePageTime = 250;
  629. PageTab *tab = new PageTab(this, CFmtStr( "tab_%s", title ), title, imageName, _tabWidth, page, m_bContextButton && bHasContextMenu, hoverActivatePageTime );
  630. if ( m_bDraggableTabs )
  631. {
  632. tab->SetDragEnabled( true );
  633. }
  634. tab->SetFont( m_tabFont );
  635. if(_showTabs)
  636. {
  637. tab->AddActionSignalTarget(this);
  638. }
  639. else if (_combo)
  640. {
  641. _combo->AddItem(title, NULL);
  642. }
  643. if ( m_pTabKV )
  644. {
  645. tab->ApplySettings( m_pTabKV );
  646. }
  647. if ( nInsertBefore == -1 )
  648. {
  649. nInsertBefore = m_PageTabs.Count();
  650. }
  651. m_PageTabs.InsertBefore( nInsertBefore, tab );
  652. Page_t info;
  653. info.page = page;
  654. info.contextMenu = m_bContextButton && bHasContextMenu;
  655. m_Pages.InsertBefore( nInsertBefore, info );
  656. page->SetParent(this);
  657. page->AddActionSignalTarget(this);
  658. PostMessage(page, new KeyValues("ResetData"));
  659. page->SetVisible(false);
  660. InvalidateLayout();
  661. if (!_activePage)
  662. {
  663. // first page becomes the active page
  664. ChangeActiveTab( 0 );
  665. if ( _activePage )
  666. {
  667. _activePage->RequestFocus( 0 );
  668. }
  669. }
  670. }
  671. //-----------------------------------------------------------------------------
  672. // Purpose:
  673. //-----------------------------------------------------------------------------
  674. void PropertySheet::SetActivePage(Panel *page)
  675. {
  676. // walk the list looking for this page
  677. int index = FindPage( page );
  678. if (!m_Pages.IsValidIndex(index))
  679. return;
  680. ChangeActiveTab(index);
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose:
  684. //-----------------------------------------------------------------------------
  685. void PropertySheet::SetTabWidth(int pixels)
  686. {
  687. _tabWidth = pixels;
  688. // Update page tabs with the new width
  689. int m = m_PageTabs.Count();
  690. for (int i=0;i<m;i++)
  691. {
  692. m_PageTabs[i]->SetTabWidth( pixels );
  693. }
  694. InvalidateLayout();
  695. }
  696. //-----------------------------------------------------------------------------
  697. // Purpose: reloads the data in all the property page
  698. //-----------------------------------------------------------------------------
  699. void PropertySheet::ResetAllData()
  700. {
  701. // iterate all the dialogs resetting them
  702. for (int i = 0; i < m_Pages.Count(); i++)
  703. {
  704. ipanel()->SendMessage(m_Pages[i].page->GetVPanel(), new KeyValues("ResetData"), GetVPanel());
  705. }
  706. }
  707. //-----------------------------------------------------------------------------
  708. // Purpose: Applies any changes made by the dialog
  709. //-----------------------------------------------------------------------------
  710. void PropertySheet::ApplyChanges()
  711. {
  712. // iterate all the dialogs resetting them
  713. for (int i = 0; i < m_Pages.Count(); i++)
  714. {
  715. ipanel()->SendMessage(m_Pages[i].page->GetVPanel(), new KeyValues("ApplyChanges"), GetVPanel());
  716. }
  717. }
  718. //-----------------------------------------------------------------------------
  719. // Purpose: gets a pointer to the currently active page
  720. //-----------------------------------------------------------------------------
  721. Panel *PropertySheet::GetActivePage()
  722. {
  723. return _activePage;
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Purpose: gets a pointer to the currently active tab
  727. //-----------------------------------------------------------------------------
  728. Panel *PropertySheet::GetActiveTab()
  729. {
  730. return _activeTab;
  731. }
  732. //-----------------------------------------------------------------------------
  733. // Purpose: gets a pointer tab "i"
  734. //-----------------------------------------------------------------------------
  735. Panel* PropertySheet::GetTab(int i)
  736. {
  737. if (i < 0 && i > m_PageTabs.Count())
  738. {
  739. return NULL;
  740. }
  741. return m_PageTabs[i];
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Purpose: returns the number of panels in the sheet
  745. //-----------------------------------------------------------------------------
  746. int PropertySheet::GetNumPages()
  747. {
  748. return m_Pages.Count();
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Purpose: returns the name contained in the active tab
  752. // Input : a text buffer to contain the output
  753. //-----------------------------------------------------------------------------
  754. void PropertySheet::GetActiveTabTitle(char *textOut, int bufferLen)
  755. {
  756. if(_activeTab) _activeTab->GetText(textOut, bufferLen);
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Purpose: returns the name contained in the active tab
  760. // Input : a text buffer to contain the output
  761. //-----------------------------------------------------------------------------
  762. bool PropertySheet::GetTabTitle(int i, char *textOut, int bufferLen)
  763. {
  764. if (i < 0 && i > m_PageTabs.Count())
  765. {
  766. return false;
  767. }
  768. m_PageTabs[i]->GetText(textOut, bufferLen);
  769. return true;
  770. }
  771. //-----------------------------------------------------------------------------
  772. // Purpose: Returns the index of the currently active page
  773. //-----------------------------------------------------------------------------
  774. int PropertySheet::GetActivePageNum()
  775. {
  776. for (int i = 0; i < m_Pages.Count(); i++)
  777. {
  778. if (m_Pages[i].page == _activePage)
  779. {
  780. return i;
  781. }
  782. }
  783. return -1;
  784. }
  785. //-----------------------------------------------------------------------------
  786. // Purpose: Forwards focus requests to current active page
  787. //-----------------------------------------------------------------------------
  788. void PropertySheet::RequestFocus(int direction)
  789. {
  790. if (direction == -1 || direction == 0)
  791. {
  792. if (_activePage)
  793. {
  794. _activePage->RequestFocus(direction);
  795. _tabFocus = false;
  796. }
  797. }
  798. else
  799. {
  800. if (_showTabs && _activeTab)
  801. {
  802. _activeTab->RequestFocus(direction);
  803. _tabFocus = true;
  804. }
  805. else if (_activePage)
  806. {
  807. _activePage->RequestFocus(direction);
  808. _tabFocus = false;
  809. }
  810. }
  811. }
  812. //-----------------------------------------------------------------------------
  813. // Purpose: moves focus back
  814. //-----------------------------------------------------------------------------
  815. bool PropertySheet::RequestFocusPrev(VPANEL panel)
  816. {
  817. if (_tabFocus || !_showTabs || !_activeTab)
  818. {
  819. _tabFocus = false;
  820. return BaseClass::RequestFocusPrev(panel);
  821. }
  822. else
  823. {
  824. if (GetVParent())
  825. {
  826. PostMessage(GetVParent(), new KeyValues("FindDefaultButton"));
  827. }
  828. _activeTab->RequestFocus(-1);
  829. _tabFocus = true;
  830. return true;
  831. }
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose: moves focus forward
  835. //-----------------------------------------------------------------------------
  836. bool PropertySheet::RequestFocusNext(VPANEL panel)
  837. {
  838. if (!_tabFocus || !_activePage)
  839. {
  840. return BaseClass::RequestFocusNext(panel);
  841. }
  842. else
  843. {
  844. if (!_activeTab)
  845. {
  846. return BaseClass::RequestFocusNext(panel);
  847. }
  848. else
  849. {
  850. _activePage->RequestFocus(1);
  851. _tabFocus = false;
  852. return true;
  853. }
  854. }
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Purpose: Gets scheme settings
  858. //-----------------------------------------------------------------------------
  859. void PropertySheet::ApplySchemeSettings(IScheme *pScheme)
  860. {
  861. // Hack Hack: This resets m_iTabHeight and m_iTabHeightSmall as if we just initialized the panel
  862. InternalInitDefaultValues( GetAnimMap() );
  863. BaseClass::ApplySchemeSettings(pScheme);
  864. // a little backwards-compatibility with old scheme files
  865. IBorder *pBorder = pScheme->GetBorder("PropertySheetBorder");
  866. if (pBorder == pScheme->GetBorder("Default"))
  867. {
  868. // get the old name
  869. pBorder = pScheme->GetBorder("RaisedBorder");
  870. }
  871. SetBorder(pBorder);
  872. m_flPageTransitionEffectTime = atof(pScheme->GetResourceString("PropertySheet.TransitionEffectTime"));
  873. m_tabFont = pScheme->GetFont( m_bSmallTabs ? "DefaultVerySmall" : "Default" );
  874. if ( m_pTabKV )
  875. {
  876. for (int i = 0; i < m_PageTabs.Count(); i++)
  877. {
  878. m_PageTabs[i]->ApplySettings( m_pTabKV );
  879. }
  880. }
  881. //=============================================================================
  882. // HPE_BEGIN:
  883. // [tj] Here, we used to use a single size variable and overwrite it when we scaled.
  884. // This led to problems when we changes resolutions, so now we recalcuate the absolute
  885. // size from the relative size each time (based on proportionality)
  886. //=============================================================================
  887. if ( IsProportional() )
  888. {
  889. m_iTabHeight = scheme()->GetProportionalScaledValueEx( GetScheme(), m_iSpecifiedTabHeight );
  890. m_iTabHeightSmall = scheme()->GetProportionalScaledValueEx( GetScheme(), m_iSpecifiedTabHeightSmall );
  891. }
  892. else
  893. {
  894. m_iTabHeight = m_iSpecifiedTabHeight;
  895. m_iTabHeightSmall = m_iSpecifiedTabHeightSmall;
  896. }
  897. //=============================================================================
  898. // HPE_END
  899. //=============================================================================
  900. }
  901. //-----------------------------------------------------------------------------
  902. // Purpose:
  903. //-----------------------------------------------------------------------------
  904. void PropertySheet::ApplySettings(KeyValues *inResourceData)
  905. {
  906. BaseClass::ApplySettings(inResourceData);
  907. KeyValues *pTabKV = inResourceData->FindKey( "tabskv" );
  908. if ( pTabKV )
  909. {
  910. if ( m_pTabKV )
  911. {
  912. m_pTabKV->deleteThis();
  913. }
  914. m_pTabKV = new KeyValues("tabkv");
  915. pTabKV->CopySubkeys( m_pTabKV );
  916. }
  917. KeyValues *pTabWidthKV = inResourceData->FindKey( "tabwidth" );
  918. if ( pTabWidthKV )
  919. {
  920. _tabWidth = scheme()->GetProportionalScaledValueEx(GetScheme(), pTabWidthKV->GetInt());
  921. for (int i = 0; i < m_PageTabs.Count(); i++)
  922. {
  923. m_PageTabs[i]->SetTabWidth( _tabWidth );
  924. }
  925. }
  926. KeyValues *pTransitionKV = inResourceData->FindKey( "transition_time" );
  927. if ( pTransitionKV )
  928. {
  929. m_flPageTransitionEffectTime = pTransitionKV->GetFloat();
  930. }
  931. }
  932. //-----------------------------------------------------------------------------
  933. // Purpose: Paint our border specially, with the tabs in mind
  934. //-----------------------------------------------------------------------------
  935. void PropertySheet::PaintBorder()
  936. {
  937. IBorder *border = GetBorder();
  938. if (!border)
  939. return;
  940. PageTab *pActive = _activeTab;
  941. if ( m_PageTabs.Find( m_pDragDropTab ) != m_PageTabs.InvalidIndex() )
  942. {
  943. pActive = m_pDragDropTab;
  944. }
  945. // draw the border, but with a break at the active tab
  946. int px = 0, py = 0, pwide = 0, ptall = 0;
  947. if (pActive)
  948. {
  949. pActive->GetBounds(px, py, pwide, ptall);
  950. ptall -= 1;
  951. }
  952. // draw the border underneath the buttons, with a break
  953. int wide, tall;
  954. GetSize(wide, tall);
  955. border->Paint(0, py + ptall, wide, tall, IBorder::SIDE_TOP, px + 1, px + pwide - 1);
  956. }
  957. // Grabs mouse coords and figures out best tab to insert "before" or -1 if insert should be at end of tab section row
  958. PageTab *PropertySheet::FindInsertBeforeTab()
  959. {
  960. int mx, my;
  961. input()->GetCursorPos( mx, my );
  962. ScreenToLocal( mx, my );
  963. int tabHeight = IsSmallTabs() ? m_iTabHeightSmall : m_iTabHeight;
  964. if ( my < 0 || my > tabHeight )
  965. return NULL;
  966. // Walk through existing tabs
  967. int c = m_PageTabs.Count();
  968. int nPrevX = 0;
  969. for ( int i = 0; i < c; ++i )
  970. {
  971. if ( m_PageTabs[ i ] == m_pTemporarilyRemoved )
  972. continue;
  973. int bounds[ 4 ];
  974. m_PageTabs[ i ]->GetBounds( bounds[ 0 ], bounds[ 1 ], bounds[ 2 ], bounds[ 3 ] );
  975. int nMidX = bounds[ 0 ] + ( bounds[ 2 ] * 0.5f );
  976. if ( mx >= nPrevX && mx <= nMidX )
  977. {
  978. if ( m_PageTabs[ i ] == m_pDragDropTab )
  979. {
  980. if ( i < c - 1 )
  981. {
  982. return m_PageTabs[ i + 1 ];
  983. }
  984. else
  985. {
  986. return NULL;
  987. }
  988. }
  989. return m_PageTabs[ i ];
  990. }
  991. nPrevX = nMidX;
  992. }
  993. return NULL;
  994. }
  995. void PropertySheet::LayoutTabs()
  996. {
  997. int x, y, wide, tall;
  998. GetBounds(x, y, wide, tall);
  999. int xtab;
  1000. int limit = m_PageTabs.Count();
  1001. xtab = m_iTabXIndent;
  1002. PageTab *pActive = _activeTab;
  1003. if ( m_PageTabs.Find( m_pDragDropTab ) != m_PageTabs.InvalidIndex() )
  1004. {
  1005. pActive = m_pDragDropTab;
  1006. }
  1007. // draw the visible tabs
  1008. if ( _showTabs )
  1009. {
  1010. int tabHeight = IsSmallTabs() ? (m_iTabHeightSmall-1) : (m_iTabHeight-1);
  1011. for (int i = 0; i < limit; i++)
  1012. {
  1013. if ( m_pTemporarilyRemoved == m_PageTabs[ i ] )
  1014. {
  1015. continue;
  1016. }
  1017. int width, tall;
  1018. m_PageTabs[i]->GetSize(width, tall);
  1019. if ( m_bTabFitText )
  1020. {
  1021. m_PageTabs[i]->SizeToContents();
  1022. width = m_PageTabs[i]->GetWide();
  1023. int iXInset, iYInset;
  1024. m_PageTabs[i]->GetTextInset( &iXInset, &iYInset );
  1025. width += (iXInset * 2);
  1026. }
  1027. if (m_PageTabs[i] == pActive)
  1028. {
  1029. // active tab is taller
  1030. pActive->SetBounds(xtab, 2, width, tabHeight);
  1031. }
  1032. else
  1033. {
  1034. m_PageTabs[i]->SetBounds(xtab, 4, width, tabHeight - 2);
  1035. }
  1036. m_PageTabs[i]->SetVisible(true);
  1037. xtab += (width + 1) + m_iTabXDelta;
  1038. }
  1039. }
  1040. else
  1041. {
  1042. for (int i = 0; i < limit; i++)
  1043. {
  1044. m_PageTabs[i]->SetVisible(false);
  1045. }
  1046. }
  1047. if ( _activeTab )
  1048. {
  1049. _activeTab->MoveToFront();
  1050. _activeTab->Repaint();
  1051. }
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose: Lays out the dialog
  1055. //-----------------------------------------------------------------------------
  1056. void PropertySheet::PerformLayout()
  1057. {
  1058. BaseClass::PerformLayout();
  1059. int x, y, wide, tall;
  1060. GetBounds(x, y, wide, tall);
  1061. for ( int i = 0; i < m_Pages.Count(); ++ i )
  1062. {
  1063. if ( m_Pages[i].page == _activePage )
  1064. {
  1065. int tabHeight = IsSmallTabs() ? m_iTabHeightSmall : m_iTabHeight;
  1066. if(_showTabs)
  1067. {
  1068. _activePage->SetBounds(0, tabHeight, wide, tall - tabHeight);
  1069. }
  1070. else
  1071. {
  1072. _activePage->SetBounds(0, 0, wide, tall );
  1073. }
  1074. _activePage->InvalidateLayout();
  1075. // ensure draw order (page drawing over all the tabs except one)
  1076. _activePage->MoveToFront();
  1077. _activePage->Repaint();
  1078. }
  1079. else
  1080. {
  1081. m_Pages[i].page->SetVisible( false );
  1082. }
  1083. }
  1084. LayoutTabs();
  1085. }
  1086. //-----------------------------------------------------------------------------
  1087. // Purpose: Switches the active panel
  1088. //-----------------------------------------------------------------------------
  1089. void PropertySheet::OnTabPressed(Panel *panel)
  1090. {
  1091. // look for the tab in the list
  1092. for (int i = 0; i < m_PageTabs.Count(); i++)
  1093. {
  1094. if (m_PageTabs[i] == panel)
  1095. {
  1096. // flip to the new tab
  1097. ChangeActiveTab(i);
  1098. return;
  1099. }
  1100. }
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose: returns the panel associated with index i
  1104. // Input : the index of the panel to return
  1105. //-----------------------------------------------------------------------------
  1106. Panel *PropertySheet::GetPage(int i)
  1107. {
  1108. if( i < 0 || i >= m_Pages.Count() )
  1109. {
  1110. return NULL;
  1111. }
  1112. return m_Pages[i].page;
  1113. }
  1114. //-----------------------------------------------------------------------------
  1115. // Purpose: disables page by name
  1116. //-----------------------------------------------------------------------------
  1117. void PropertySheet::DisablePage(const char *title)
  1118. {
  1119. SetPageEnabled(title, false);
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. // Purpose: enables page by name
  1123. //-----------------------------------------------------------------------------
  1124. void PropertySheet::EnablePage(const char *title)
  1125. {
  1126. SetPageEnabled(title, true);
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. // Purpose: enabled or disables page by name
  1130. //-----------------------------------------------------------------------------
  1131. void PropertySheet::SetPageEnabled(const char *title, bool state)
  1132. {
  1133. for (int i = 0; i < m_PageTabs.Count(); i++)
  1134. {
  1135. if (_showTabs)
  1136. {
  1137. char tmp[50];
  1138. m_PageTabs[i]->GetText(tmp,50);
  1139. if (!strnicmp(title,tmp,strlen(tmp)))
  1140. {
  1141. m_PageTabs[i]->SetEnabled(state);
  1142. }
  1143. }
  1144. else if ( _combo )
  1145. {
  1146. _combo->SetItemEnabled(title,state);
  1147. }
  1148. }
  1149. }
  1150. void PropertySheet::RemoveAllPages()
  1151. {
  1152. int c = m_Pages.Count();
  1153. for ( int i = c - 1; i >= 0 ; --i )
  1154. {
  1155. RemovePage( m_Pages[ i ].page );
  1156. }
  1157. }
  1158. void PropertySheet::DeleteAllPages()
  1159. {
  1160. int c = m_Pages.Count();
  1161. for ( int i = c - 1; i >= 0 ; --i )
  1162. {
  1163. DeletePage( m_Pages[ i ].page );
  1164. }
  1165. }
  1166. //-----------------------------------------------------------------------------
  1167. // Purpose: deletes the page associated with panel
  1168. // Input : *panel - the panel of the page to remove
  1169. //-----------------------------------------------------------------------------
  1170. void PropertySheet::RemovePage(Panel *panel)
  1171. {
  1172. int location = FindPage( panel );
  1173. if ( location == m_Pages.InvalidIndex() )
  1174. return;
  1175. // Since it's being deleted, don't animate!!!
  1176. m_hPreviouslyActivePage = NULL;
  1177. _activeTab = NULL;
  1178. // ASSUMPTION = that the number of pages equals number of tabs
  1179. if( _showTabs )
  1180. {
  1181. m_PageTabs[location]->RemoveActionSignalTarget( this );
  1182. }
  1183. // now remove the tab
  1184. PageTab *tab = m_PageTabs[ location ];
  1185. m_PageTabs.Remove( location );
  1186. tab->MarkForDeletion();
  1187. // Remove from page list
  1188. m_Pages.Remove( location );
  1189. // Unparent
  1190. panel->SetParent( (Panel *)NULL );
  1191. if ( _activePage == panel )
  1192. {
  1193. _activePage = NULL;
  1194. // if this page is currently active, backup to the page before this.
  1195. ChangeActiveTab( MAX( location - 1, 0 ) );
  1196. }
  1197. PerformLayout();
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. // Purpose: deletes the page associated with panel
  1201. // Input : *panel - the panel of the page to remove
  1202. //-----------------------------------------------------------------------------
  1203. void PropertySheet::DeletePage(Panel *panel)
  1204. {
  1205. Assert( panel );
  1206. RemovePage( panel );
  1207. panel->MarkForDeletion();
  1208. }
  1209. //-----------------------------------------------------------------------------
  1210. // Purpose: flips to the new tab, sending out all the right notifications
  1211. // flipping to a tab activates the tab.
  1212. //-----------------------------------------------------------------------------
  1213. void PropertySheet::ChangeActiveTab( int index )
  1214. {
  1215. if ( !m_Pages.IsValidIndex( index ) )
  1216. {
  1217. _activeTab = NULL;
  1218. if ( m_Pages.Count() > 0 )
  1219. {
  1220. _activePage = NULL;
  1221. ChangeActiveTab( 0 );
  1222. }
  1223. return;
  1224. }
  1225. if ( m_Pages[index].page == _activePage )
  1226. {
  1227. if ( _activeTab )
  1228. {
  1229. _activeTab->RequestFocus();
  1230. }
  1231. _tabFocus = true;
  1232. return;
  1233. }
  1234. int c = m_Pages.Count();
  1235. for ( int i = 0; i < c; ++i )
  1236. {
  1237. m_Pages[ i ].page->SetVisible( false );
  1238. }
  1239. m_hPreviouslyActivePage = _activePage;
  1240. // We're going to fade out the active page, so don't hide it yet
  1241. if (_activePage && m_flPageTransitionEffectTime)
  1242. {
  1243. _activePage->SetVisible(true);
  1244. }
  1245. // notify old page
  1246. if (_activePage)
  1247. {
  1248. ivgui()->PostMessage(_activePage->GetVPanel(), new KeyValues("PageHide"), GetVPanel());
  1249. KeyValues *msg = new KeyValues("PageTabActivated");
  1250. msg->SetPtr("panel", (Panel *)NULL);
  1251. ivgui()->PostMessage(_activePage->GetVPanel(), msg, GetVPanel());
  1252. }
  1253. if (_activeTab)
  1254. {
  1255. //_activeTabIndex=index;
  1256. _activeTab->SetActive(false);
  1257. // does the old tab have the focus?
  1258. _tabFocus = _activeTab->HasFocus();
  1259. }
  1260. else
  1261. {
  1262. _tabFocus = false;
  1263. }
  1264. // flip page
  1265. _activePage = m_Pages[index].page;
  1266. _activeTab = m_PageTabs[index];
  1267. _activeTabIndex = index;
  1268. _activePage->SetVisible(true);
  1269. _activePage->MoveToFront();
  1270. _activeTab->SetVisible(true);
  1271. _activeTab->MoveToFront();
  1272. _activeTab->SetActive(true);
  1273. if (_tabFocus)
  1274. {
  1275. // if a tab already has focused,give the new tab the focus
  1276. _activeTab->RequestFocus();
  1277. }
  1278. else
  1279. {
  1280. // otherwise, give the focus to the page
  1281. _activePage->RequestFocus();
  1282. }
  1283. if (!_showTabs && _combo)
  1284. {
  1285. _combo->ActivateItemByRow(index);
  1286. }
  1287. _activePage->MakeReadyForUse();
  1288. // transition effect
  1289. if (m_flPageTransitionEffectTime)
  1290. {
  1291. if (m_hPreviouslyActivePage.Get())
  1292. {
  1293. // fade out the previous page
  1294. GetAnimationController()->RunAnimationCommand(m_hPreviouslyActivePage, "Alpha", 0.0f, 0.0f, m_flPageTransitionEffectTime / 2, AnimationController::INTERPOLATOR_LINEAR);
  1295. }
  1296. // fade in the new page
  1297. _activePage->SetAlpha(0);
  1298. GetAnimationController()->RunAnimationCommand(_activePage, "Alpha", 255.0f, m_flPageTransitionEffectTime / 2, m_flPageTransitionEffectTime / 2, AnimationController::INTERPOLATOR_LINEAR);
  1299. }
  1300. else
  1301. {
  1302. if (m_hPreviouslyActivePage.Get())
  1303. {
  1304. // no transition, just hide the previous page
  1305. m_hPreviouslyActivePage->SetVisible(false);
  1306. }
  1307. _activePage->SetAlpha( 255 );
  1308. }
  1309. // notify
  1310. ivgui()->PostMessage(_activePage->GetVPanel(), new KeyValues("PageShow"), GetVPanel());
  1311. KeyValues *msg = new KeyValues("PageTabActivated");
  1312. msg->SetPtr("panel", (Panel *)_activeTab);
  1313. ivgui()->PostMessage(_activePage->GetVPanel(), msg, GetVPanel());
  1314. // tell parent
  1315. PostActionSignal(new KeyValues("PageChanged"));
  1316. // Repaint
  1317. InvalidateLayout();
  1318. Repaint();
  1319. }
  1320. //-----------------------------------------------------------------------------
  1321. // Purpose: Gets the panel with the specified hotkey, from the current page
  1322. //-----------------------------------------------------------------------------
  1323. Panel *PropertySheet::HasHotkey(wchar_t key)
  1324. {
  1325. if (!_activePage)
  1326. return NULL;
  1327. for (int i = 0; i < _activePage->GetChildCount(); i++)
  1328. {
  1329. Panel *hot = _activePage->GetChild(i)->HasHotkey(key);
  1330. if (hot)
  1331. {
  1332. return hot;
  1333. }
  1334. }
  1335. return NULL;
  1336. }
  1337. //-----------------------------------------------------------------------------
  1338. // Purpose: catches the opencontextmenu event
  1339. //-----------------------------------------------------------------------------
  1340. void PropertySheet::OnOpenContextMenu( KeyValues *params )
  1341. {
  1342. // tell parent
  1343. KeyValues *kv = params->MakeCopy();
  1344. PostActionSignal( kv );
  1345. Panel *page = reinterpret_cast< Panel * >( params->GetPtr( "page" ) );
  1346. if ( page )
  1347. {
  1348. PostMessage( page->GetVPanel(), params->MakeCopy() );
  1349. }
  1350. }
  1351. //-----------------------------------------------------------------------------
  1352. // Purpose: Handle key presses, through tabs.
  1353. //-----------------------------------------------------------------------------
  1354. void PropertySheet::OnKeyCodeTyped(KeyCode code)
  1355. {
  1356. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  1357. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  1358. bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
  1359. if ( ctrl && shift && alt && code == KEY_B)
  1360. {
  1361. // enable build mode
  1362. EditablePanel *ep = dynamic_cast< EditablePanel * >( GetActivePage() );
  1363. if ( ep )
  1364. {
  1365. ep->ActivateBuildMode();
  1366. return;
  1367. }
  1368. }
  1369. if ( IsKBNavigationEnabled() )
  1370. {
  1371. switch (code)
  1372. {
  1373. // for now left and right arrows just open or close submenus if they are there.
  1374. case KEY_RIGHT:
  1375. {
  1376. ChangeActiveTab(_activeTabIndex+1);
  1377. break;
  1378. }
  1379. case KEY_LEFT:
  1380. {
  1381. ChangeActiveTab(_activeTabIndex-1);
  1382. break;
  1383. }
  1384. default:
  1385. BaseClass::OnKeyCodeTyped(code);
  1386. break;
  1387. }
  1388. }
  1389. else
  1390. {
  1391. BaseClass::OnKeyCodeTyped(code);
  1392. }
  1393. }
  1394. //-----------------------------------------------------------------------------
  1395. // Purpose: Called by the associated combo box (if in that mode), changes the current panel
  1396. //-----------------------------------------------------------------------------
  1397. void PropertySheet::OnTextChanged(Panel *panel,const wchar_t *wszText)
  1398. {
  1399. if ( panel == _combo )
  1400. {
  1401. wchar_t tabText[30];
  1402. for(int i = 0 ; i < m_PageTabs.Count() ; i++ )
  1403. {
  1404. tabText[0] = 0;
  1405. m_PageTabs[i]->GetText(tabText,30);
  1406. if ( !wcsicmp(wszText,tabText) )
  1407. {
  1408. ChangeActiveTab(i);
  1409. }
  1410. }
  1411. }
  1412. }
  1413. //-----------------------------------------------------------------------------
  1414. // Purpose:
  1415. //-----------------------------------------------------------------------------
  1416. void PropertySheet::OnCommand(const char *command)
  1417. {
  1418. // propogate the close command to our parent
  1419. if (!stricmp(command, "Close") && GetVParent())
  1420. {
  1421. CallParentFunction(new KeyValues("Command", "command", command));
  1422. }
  1423. }
  1424. //-----------------------------------------------------------------------------
  1425. // Purpose:
  1426. //-----------------------------------------------------------------------------
  1427. void PropertySheet::OnApplyButtonEnable()
  1428. {
  1429. // tell parent
  1430. PostActionSignal(new KeyValues("ApplyButtonEnable"));
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Purpose:
  1434. //-----------------------------------------------------------------------------
  1435. void PropertySheet::OnCurrentDefaultButtonSet( vgui::VPANEL defaultButton )
  1436. {
  1437. // forward the message up
  1438. if (GetVParent())
  1439. {
  1440. KeyValues *msg = new KeyValues("CurrentDefaultButtonSet");
  1441. msg->SetInt("button", ivgui()->PanelToHandle( defaultButton ) );
  1442. PostMessage(GetVParent(), msg);
  1443. }
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. // Purpose:
  1447. //-----------------------------------------------------------------------------
  1448. void PropertySheet::OnDefaultButtonSet( VPANEL defaultButton )
  1449. {
  1450. // forward the message up
  1451. if (GetVParent())
  1452. {
  1453. KeyValues *msg = new KeyValues("DefaultButtonSet");
  1454. msg->SetInt("button", ivgui()->PanelToHandle( defaultButton ) );
  1455. PostMessage(GetVParent(), msg);
  1456. }
  1457. }
  1458. //-----------------------------------------------------------------------------
  1459. // Purpose:
  1460. //-----------------------------------------------------------------------------
  1461. void PropertySheet::OnFindDefaultButton()
  1462. {
  1463. if (GetVParent())
  1464. {
  1465. PostMessage(GetVParent(), new KeyValues("FindDefaultButton"));
  1466. }
  1467. }
  1468. bool PropertySheet::PageHasContextMenu( Panel *page ) const
  1469. {
  1470. int pageNum = FindPage( page );
  1471. if ( pageNum == m_Pages.InvalidIndex() )
  1472. return false;
  1473. return m_Pages[ pageNum ].contextMenu;
  1474. }
  1475. void PropertySheet::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
  1476. {
  1477. PageTab *pBefore = FindInsertBeforeTab();
  1478. ClearPageDropTab();
  1479. if ( msglist.Count() != 1 )
  1480. {
  1481. return;
  1482. }
  1483. PropertySheet *sheet = IsDroppingSheet( msglist );
  1484. // Msg( "PropertySheet::OnPanelDropped(sheet %s)\n", sheet ? "yes" : "no" );
  1485. if ( !sheet )
  1486. {
  1487. // Defer to active page
  1488. if ( _activePage && _activePage->IsDropEnabled() )
  1489. {
  1490. _activePage->OnPanelDropped( msglist );
  1491. }
  1492. return;
  1493. }
  1494. KeyValues *data = msglist[ 0 ];
  1495. Panel *page = reinterpret_cast< Panel * >( data->GetPtr( "propertypage" ) );
  1496. char const *title = data->GetString( "tabname", "" );
  1497. if ( !page || !sheet )
  1498. return;
  1499. // Can only create if sheet was part of a ToolWindow derived object
  1500. ToolWindow *tw = dynamic_cast< ToolWindow * >( sheet->GetParent() );
  1501. if ( tw )
  1502. {
  1503. IToolWindowFactory *factory = tw->GetToolWindowFactory();
  1504. if ( factory )
  1505. {
  1506. bool showContext = sheet->PageHasContextMenu( page );
  1507. sheet->RemovePage( page );
  1508. if ( sheet->GetNumPages() == 0 )
  1509. {
  1510. tw->MarkForDeletion();
  1511. }
  1512. int nSlot = pBefore ? m_PageTabs.Find( pBefore ) : -1;
  1513. AddPage( page, title, NULL, showContext, nSlot );
  1514. SetActivePage( page );
  1515. }
  1516. }
  1517. }
  1518. bool PropertySheet::IsDroppable( CUtlVector< KeyValues * >& msglist )
  1519. {
  1520. if ( !m_bDraggableTabs )
  1521. return false;
  1522. if ( msglist.Count() != 1 )
  1523. {
  1524. return false;
  1525. }
  1526. int mx, my;
  1527. input()->GetCursorPos( mx, my );
  1528. ScreenToLocal( mx, my );
  1529. int tabHeight = IsSmallTabs() ? m_iTabHeightSmall : m_iTabHeight;
  1530. if ( my > tabHeight )
  1531. return false;
  1532. PropertySheet *sheet = IsDroppingSheet( msglist );
  1533. if ( !sheet )
  1534. {
  1535. return false;
  1536. }
  1537. KeyValues *data = msglist[ 0 ];
  1538. char const *text = data->GetString( "tabname", "" );
  1539. Panel *page = reinterpret_cast< Panel * >( data->GetPtr( "propertypage" ) );
  1540. if ( !page )
  1541. return false;
  1542. AddPageDropTab( text, page );
  1543. return true;
  1544. }
  1545. // Mouse is now over a droppable panel
  1546. void PropertySheet::OnDroppablePanelPaint( CUtlVector< KeyValues * >& msglist, CUtlVector< Panel * >& dragPanels )
  1547. {
  1548. if ( m_nPageDropTabVisibleTime != -1 )
  1549. {
  1550. // Extend timeout
  1551. m_nPageDropTabVisibleTime = system()->GetTimeMillis();
  1552. }
  1553. // Convert this panel's bounds to screen space
  1554. int x, y, w, h;
  1555. GetSize( w, h );
  1556. int tabHeight = IsSmallTabs() ? m_iTabHeightSmall : m_iTabHeight;
  1557. h = tabHeight + 4;
  1558. x = y = 0;
  1559. LocalToScreen( x, y );
  1560. Color clr;
  1561. clr = GetDropFrameColor();
  1562. surface()->DrawSetColor( clr );
  1563. // Draw 2 pixel frame
  1564. surface()->DrawOutlinedRect( x-1, y-1, x + w+1, y + h+1 );
  1565. clr[ 3 ] *= 0.5f;
  1566. surface()->DrawSetColor( clr );
  1567. surface()->DrawOutlinedRect( x, y, x + w, y + h );
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // Purpose:
  1571. // Input : state -
  1572. //-----------------------------------------------------------------------------
  1573. void PropertySheet::SetKBNavigationEnabled( bool state )
  1574. {
  1575. m_bKBNavigationEnabled = state;
  1576. }
  1577. //-----------------------------------------------------------------------------
  1578. // Purpose:
  1579. // Input : -
  1580. // Output : Returns true on success, false on failure.
  1581. //-----------------------------------------------------------------------------
  1582. bool PropertySheet::IsKBNavigationEnabled() const
  1583. {
  1584. return m_bKBNavigationEnabled;
  1585. }
  1586. void PropertySheet::AddPageDropTab( char const *pTabName, Panel *pPage )
  1587. {
  1588. //if ( m_nPageDropTabVisibleTime != -1 )
  1589. // return;
  1590. m_PageTabs.FindAndRemove( m_pDragDropTab );
  1591. m_pDragDropTab->SetText( pTabName );
  1592. m_pDragDropTab->Resize();
  1593. m_pDragDropTab->SetVisible( true );
  1594. int nPageSlot = FindPage( pPage );
  1595. if ( nPageSlot != -1 )
  1596. {
  1597. m_pTemporarilyRemoved = m_PageTabs[ nPageSlot ];
  1598. m_pTemporarilyRemoved->SetVisible( false );
  1599. LayoutTabs();
  1600. }
  1601. PageTab *pBefore = FindInsertBeforeTab();
  1602. int nSlot = pBefore ? m_PageTabs.Find( pBefore ) : -1;
  1603. // Msg( "Add tab %s at slot %d\n", pTabName, nSlot );
  1604. if ( nSlot == -1 )
  1605. {
  1606. m_PageTabs.AddToTail( m_pDragDropTab );
  1607. }
  1608. else
  1609. {
  1610. m_PageTabs.InsertBefore( nSlot, m_pDragDropTab );
  1611. }
  1612. LayoutTabs();
  1613. m_nPageDropTabVisibleTime = system()->GetTimeMillis();
  1614. }
  1615. void PropertySheet::ClearPageDropTab()
  1616. {
  1617. // Msg( "Clearing page drop tab\n" );
  1618. m_nPageDropTabVisibleTime = -1;
  1619. m_PageTabs.FindAndRemove( m_pDragDropTab );
  1620. m_pDragDropTab->SetVisible( false );
  1621. if ( m_pTemporarilyRemoved )
  1622. {
  1623. m_pTemporarilyRemoved->SetVisible( true );
  1624. m_pTemporarilyRemoved = NULL;
  1625. }
  1626. LayoutTabs();
  1627. }
  1628. void PropertySheet::OnThink()
  1629. {
  1630. BaseClass::OnThink();
  1631. if ( m_nPageDropTabVisibleTime == -1 )
  1632. return;
  1633. if ( system()->GetTimeMillis() <= ( m_nPageDropTabVisibleTime + 100 ) )
  1634. return;
  1635. ClearPageDropTab();
  1636. }