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.

1675 lines
42 KiB

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