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.

2854 lines
66 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #define PROTECTED_THINGS_DISABLE
  9. #include <vgui/Cursor.h>
  10. #include <vgui/IScheme.h>
  11. #include <vgui/IInput.h>
  12. #include <vgui/IPanel.h>
  13. #include <vgui/ISurface.h>
  14. #include <vgui/ISystem.h>
  15. #include <vgui/IVGui.h>
  16. #include <vgui/KeyCode.h>
  17. #include <KeyValues.h>
  18. #include <vgui/MouseCode.h>
  19. #include <vgui_controls/TreeView.h>
  20. #include <vgui_controls/ScrollBar.h>
  21. #include <vgui_controls/TextEntry.h>
  22. #include <vgui_controls/Label.h>
  23. #include <vgui_controls/Button.h>
  24. #include <vgui_controls/TextImage.h>
  25. #include <vgui_controls/ImageList.h>
  26. #include <vgui_controls/ImagePanel.h>
  27. #include "tier1/utlstring.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include <tier0/memdbgon.h>
  30. #ifndef max
  31. #define max(a,b) (((a) > (b)) ? (a) : (b))
  32. #endif
  33. using namespace vgui;
  34. enum
  35. {
  36. WINDOW_BORDER_WIDTH=2 // the width of the window's border
  37. };
  38. #define TREE_INDENT_AMOUNT 20
  39. namespace vgui
  40. {
  41. //-----------------------------------------------------------------------------
  42. // Purpose: Displays an editable text field for the text control
  43. //-----------------------------------------------------------------------------
  44. class TreeNodeText : public TextEntry
  45. {
  46. DECLARE_CLASS_SIMPLE( TreeNodeText, TextEntry );
  47. public:
  48. TreeNodeText(Panel *parent, const char *panelName, TreeView *tree) : BaseClass(parent, panelName), m_pTree( tree )
  49. {
  50. m_bEditingInPlace = false;
  51. m_bLabelEditingAllowed = false;
  52. SetDragEnabled( false );
  53. SetDropEnabled( false );
  54. AddActionSignalTarget( this );
  55. m_bArmForEditing = false;
  56. m_bWaitingForRelease = false;
  57. m_lArmingTime = 0L;
  58. SetAllowKeyBindingChainToParent( true );
  59. }
  60. MESSAGE_FUNC( OnTextChanged, "TextChanged" )
  61. {
  62. GetParent()->InvalidateLayout();
  63. }
  64. bool IsKeyRebound( KeyCode code, int modifiers )
  65. {
  66. // If in editing mode, don't try and chain keypresses
  67. if ( m_bEditingInPlace )
  68. {
  69. return false;
  70. }
  71. return BaseClass::IsKeyRebound( code, modifiers );
  72. }
  73. virtual void PaintBackground()
  74. {
  75. BaseClass::PaintBackground();
  76. if ( !m_bLabelEditingAllowed )
  77. return;
  78. if ( !m_bEditingInPlace )
  79. return;
  80. int w, h;
  81. GetSize( w, h );
  82. surface()->DrawSetColor( GetFgColor() );
  83. surface()->DrawOutlinedRect( 0, 0, w, h );
  84. }
  85. virtual void ApplySchemeSettings(IScheme *pScheme)
  86. {
  87. TextEntry::ApplySchemeSettings(pScheme);
  88. SetBorder(NULL);
  89. SetCursor(dc_arrow);
  90. }
  91. virtual void OnKeyCodeTyped(KeyCode code)
  92. {
  93. if ( m_bEditingInPlace )
  94. {
  95. if ( code == KEY_ENTER )
  96. {
  97. FinishEditingInPlace();
  98. }
  99. else if ( code == KEY_ESCAPE )
  100. {
  101. FinishEditingInPlace( true );
  102. }
  103. else
  104. {
  105. BaseClass::OnKeyCodeTyped( code );
  106. }
  107. return;
  108. }
  109. else if ( code == KEY_ENTER && IsLabelEditingAllowed() )
  110. {
  111. EnterEditingInPlace();
  112. }
  113. else
  114. {
  115. // let parent deal with it (don't chain back to TextEntry)
  116. CallParentFunction(new KeyValues("KeyCodeTyped", "code", code));
  117. }
  118. }
  119. #define CLICK_TO_EDIT_DELAY_MSEC 500
  120. virtual void OnTick()
  121. {
  122. BaseClass::OnTick();
  123. if ( m_bArmForEditing )
  124. {
  125. long msecSinceArming = system()->GetTimeMillis() - m_lArmingTime;
  126. if ( msecSinceArming > CLICK_TO_EDIT_DELAY_MSEC )
  127. {
  128. m_bArmForEditing = false;
  129. m_bWaitingForRelease = false;
  130. ivgui()->RemoveTickSignal( GetVPanel() );
  131. EnterEditingInPlace();
  132. }
  133. }
  134. }
  135. virtual void OnMouseReleased( MouseCode code )
  136. {
  137. if ( m_bEditingInPlace )
  138. {
  139. BaseClass::OnMouseReleased( code );
  140. return;
  141. }
  142. else
  143. {
  144. if ( m_bWaitingForRelease && !IsBeingDragged() )
  145. {
  146. m_bArmForEditing = true;
  147. m_bWaitingForRelease = false;
  148. m_lArmingTime = system()->GetTimeMillis();
  149. ivgui()->AddTickSignal( GetVPanel() );
  150. }
  151. else
  152. {
  153. m_bWaitingForRelease = false;
  154. }
  155. }
  156. // let parent deal with it
  157. CallParentFunction(new KeyValues("MouseReleased", "code", code));
  158. }
  159. virtual void OnCursorMoved( int x, int y )
  160. {
  161. // let parent deal with it
  162. CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
  163. }
  164. virtual void OnMousePressed(MouseCode code)
  165. {
  166. if ( m_bEditingInPlace )
  167. {
  168. BaseClass::OnMousePressed( code );
  169. return;
  170. }
  171. else
  172. {
  173. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  174. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  175. // make sure there is only one item selected
  176. // before "WaitingForRelease" which leads to label editing.
  177. CUtlVector< int > list;
  178. m_pTree->GetSelectedItems( list );
  179. bool bIsOnlyOneItemSelected = ( list.Count() == 1 );
  180. if ( !shift &&
  181. !ctrl &&
  182. !m_bArmForEditing &&
  183. IsLabelEditingAllowed() &&
  184. bIsOnlyOneItemSelected &&
  185. IsTextFullySelected() &&
  186. !IsBeingDragged() )
  187. {
  188. m_bWaitingForRelease = true;
  189. }
  190. }
  191. // let parent deal with it
  192. CallParentFunction(new KeyValues("MousePressed", "code", code));
  193. }
  194. void SetLabelEditingAllowed( bool state )
  195. {
  196. m_bLabelEditingAllowed = state;
  197. }
  198. bool IsLabelEditingAllowed()
  199. {
  200. return m_bLabelEditingAllowed;
  201. }
  202. virtual void OnMouseDoublePressed(MouseCode code)
  203. {
  204. // Once we are editing, double pressing shouldn't chain up
  205. if ( m_bEditingInPlace )
  206. {
  207. BaseClass::OnMouseDoublePressed( code );
  208. return;
  209. }
  210. if ( m_bArmForEditing )
  211. {
  212. m_bArmForEditing = false;
  213. m_bWaitingForRelease = false;
  214. ivgui()->RemoveTickSignal( GetVPanel() );
  215. }
  216. CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
  217. }
  218. void EnterEditingInPlace()
  219. {
  220. if ( m_bEditingInPlace )
  221. return;
  222. m_bEditingInPlace = true;
  223. char buf[ 1024 ];
  224. GetText( buf, sizeof( buf ) );
  225. m_OriginalText = buf;
  226. SetCursor(dc_ibeam);
  227. SetEditable( true );
  228. SelectNone();
  229. GotoTextEnd();
  230. RequestFocus();
  231. SelectAllText(false);
  232. m_pTree->SetLabelBeingEdited( true );
  233. }
  234. void FinishEditingInPlace( bool revert = false )
  235. {
  236. if ( !m_bEditingInPlace )
  237. return;
  238. m_pTree->SetLabelBeingEdited( false );
  239. SetEditable( false );
  240. SetCursor(dc_arrow);
  241. m_bEditingInPlace = false;
  242. char buf[ 1024 ];
  243. GetText( buf, sizeof( buf ) );
  244. // Not actually changed...
  245. if ( !Q_strcmp( buf, m_OriginalText.Get() ) )
  246. return;
  247. if ( revert )
  248. {
  249. SetText( m_OriginalText.Get() );
  250. GetParent()->InvalidateLayout();
  251. }
  252. else
  253. {
  254. KeyValues *kv = new KeyValues( "LabelChanged", "original", m_OriginalText.Get(), "changed", buf );
  255. PostActionSignal( kv );
  256. }
  257. }
  258. virtual void OnKillFocus()
  259. {
  260. BaseClass::OnKillFocus();
  261. FinishEditingInPlace();
  262. }
  263. virtual void OnMouseWheeled(int delta)
  264. {
  265. if ( m_bEditingInPlace )
  266. {
  267. BaseClass::OnMouseWheeled( delta );
  268. return;
  269. }
  270. CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
  271. }
  272. // editable - cursor normal, and ability to edit text
  273. bool IsBeingEdited() const
  274. {
  275. return m_bEditingInPlace;
  276. }
  277. private:
  278. bool m_bEditingInPlace;
  279. CUtlString m_OriginalText;
  280. bool m_bLabelEditingAllowed;
  281. bool m_bArmForEditing;
  282. bool m_bWaitingForRelease;
  283. long m_lArmingTime;
  284. TreeView *m_pTree;
  285. };
  286. //-----------------------------------------------------------------------------
  287. // Purpose: icon for the tree node (folder icon, file icon, etc.)
  288. //-----------------------------------------------------------------------------
  289. class TreeNodeImage : public ImagePanel
  290. {
  291. public:
  292. TreeNodeImage(Panel *parent, const char *name) : ImagePanel(parent, name)
  293. {
  294. SetBlockDragChaining( true );
  295. }
  296. //!! this could possibly be changed to just disallow mouse input on the image panel
  297. virtual void OnMousePressed(MouseCode code)
  298. {
  299. // let parent deal with it
  300. CallParentFunction(new KeyValues("MousePressed", "code", code));
  301. }
  302. virtual void OnMouseDoublePressed(MouseCode code)
  303. {
  304. // let parent deal with it
  305. CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
  306. }
  307. virtual void OnMouseWheeled(int delta)
  308. {
  309. // let parent deal with it
  310. CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
  311. }
  312. virtual void OnCursorMoved( int x, int y )
  313. {
  314. // let parent deal with it
  315. CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
  316. }
  317. };
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Scrollable area of the tree control, holds the tree itself only
  320. //-----------------------------------------------------------------------------
  321. class TreeViewSubPanel : public Panel
  322. {
  323. public:
  324. TreeViewSubPanel(Panel *parent) : Panel(parent) {}
  325. virtual void ApplySchemeSettings(IScheme *pScheme)
  326. {
  327. Panel::ApplySchemeSettings(pScheme);
  328. SetBorder(NULL);
  329. }
  330. virtual void OnMouseWheeled(int delta)
  331. {
  332. // let parent deal with it
  333. CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
  334. }
  335. virtual void OnMousePressed(MouseCode code)
  336. {
  337. // let parent deal with it
  338. CallParentFunction(new KeyValues("MousePressed", "code", code));
  339. }
  340. virtual void OnMouseDoublePressed(MouseCode code)
  341. {
  342. // let parent deal with it
  343. CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
  344. }
  345. virtual void OnCursorMoved( int x, int y )
  346. {
  347. // let parent deal with it
  348. CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
  349. }
  350. };
  351. //-----------------------------------------------------------------------------
  352. // Purpose: A single entry in the tree
  353. //-----------------------------------------------------------------------------
  354. class TreeNode : public Panel
  355. {
  356. DECLARE_CLASS_SIMPLE( TreeNode, Panel );
  357. public:
  358. TreeNode(Panel *parent, TreeView *pTreeView);
  359. ~TreeNode();
  360. void SetText(const char *pszText);
  361. void SetFont(HFont font);
  362. void SetKeyValues(KeyValues *data);
  363. bool IsSelected();
  364. // currently unused, could be re-used if necessary
  365. // bool IsInFocus();
  366. virtual void PaintBackground();
  367. virtual void PerformLayout();
  368. TreeNode *GetParentNode();
  369. int GetChildrenCount();
  370. void ClearChildren();
  371. int ComputeInsertionPosition( TreeNode *pChild );
  372. int FindChild( TreeNode *pChild );
  373. void AddChild(TreeNode *pChild);
  374. void SetNodeExpanded(bool bExpanded);
  375. bool IsExpanded();
  376. int CountVisibleNodes();
  377. void CalculateVisibleMaxWidth();
  378. void OnChildWidthChange();
  379. int GetMaxChildrenWidth();
  380. int GetVisibleMaxWidth();
  381. int GetDepth();
  382. bool HasParent(TreeNode *pTreeNode);
  383. bool IsBeingDisplayed();
  384. virtual void SetVisible(bool state);
  385. virtual void Paint();
  386. virtual void ApplySchemeSettings(IScheme *pScheme);
  387. virtual void SetBgColor( Color color );
  388. virtual void SetFgColor( Color color );
  389. virtual void OnSetFocus();
  390. void SelectPrevChild(TreeNode *pCurrentChild);
  391. void SelectNextChild(TreeNode *pCurrentChild);
  392. int GetPrevChildItemIndex( TreeNode *pCurrentChild );
  393. int GetNextChildItemIndex( TreeNode *pCurrentChild );
  394. virtual void ClosePreviousParents( TreeNode *pPreviousParent );
  395. virtual void StepInto( bool bClosePrevious=true );
  396. virtual void StepOut( bool bClosePrevious=true );
  397. virtual void StepOver( bool bClosePrevious=true );
  398. virtual void OnKeyCodeTyped(KeyCode code);
  399. virtual void OnMouseWheeled(int delta);
  400. virtual void OnMousePressed( MouseCode code);
  401. virtual void OnMouseReleased( MouseCode code);
  402. virtual void OnCursorMoved( int x, int y );
  403. virtual bool IsDragEnabled() const;
  404. void PositionAndSetVisibleNodes(int &nStart, int &nCount, int x, int &y);
  405. // counts items above this item including itself
  406. int CountVisibleIndex();
  407. virtual void OnCreateDragData( KeyValues *msg );
  408. // For handling multiple selections...
  409. virtual void OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles );
  410. virtual void OnMouseDoublePressed( MouseCode code );
  411. TreeNode *FindItemUnderMouse( int &nStart, int& nCount, int x, int &y, int mx, int my );
  412. MESSAGE_FUNC_PARAMS( OnLabelChanged, "LabelChanged", data );
  413. void EditLabel();
  414. void SetLabelEditingAllowed( bool state );
  415. bool IsLabelEditingAllowed() const;
  416. virtual bool IsDroppable( CUtlVector< KeyValues * >& msglist );
  417. virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist );
  418. virtual HCursor GetDropCursor( CUtlVector< KeyValues * >& msglist );
  419. virtual bool GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist );
  420. void FindNodesInRange( CUtlVector< TreeNode * >& list, int startIndex, int endIndex );
  421. void RemoveChildren();
  422. void SetSelectionTextColor( const Color& clr );
  423. void SetSelectionBgColor( const Color& clr );
  424. void SetSelectionUnfocusedBgColor( const Color& clr );
  425. public:
  426. int m_ItemIndex;
  427. int m_ParentIndex;
  428. KeyValues *m_pData;
  429. CUtlVector<TreeNode *> m_Children;
  430. bool m_bExpand;
  431. private:
  432. void FindNodesInRange_R( CUtlVector< TreeNode * >& list, bool& finished, bool& foundStart, int startIndex, int endIndex );
  433. int m_iNodeWidth;
  434. int m_iMaxVisibleWidth;
  435. TreeNodeText *m_pText;
  436. TextImage *m_pExpandImage;
  437. TreeNodeImage *m_pImagePanel;
  438. bool m_bExpandableWithoutChildren;
  439. TreeView *m_pTreeView;
  440. int m_nClickedItem;
  441. bool m_bClickedSelected;
  442. };
  443. TreeNode::TreeNode(Panel *parent, TreeView *pTreeView) :
  444. BaseClass(parent, "TreeNode" ),
  445. m_nClickedItem( 0 ),
  446. m_bClickedSelected( false )
  447. {
  448. m_pData = NULL;
  449. m_pTreeView = pTreeView;
  450. m_ItemIndex = -1;
  451. m_iNodeWidth = 0;
  452. m_iMaxVisibleWidth = 0;
  453. m_pExpandImage = new TextImage("+");
  454. m_pExpandImage->SetPos(3, 1);
  455. m_pImagePanel = new TreeNodeImage(this, "TreeImage");
  456. m_pImagePanel->SetPos(TREE_INDENT_AMOUNT, 3);
  457. m_pText = new TreeNodeText(this, "TreeNodeText",pTreeView);
  458. m_pText->SetMultiline(false);
  459. m_pText->SetEditable(false);
  460. m_pText->SetPos(TREE_INDENT_AMOUNT*2, 0);
  461. m_pText->AddActionSignalTarget( this );
  462. m_bExpand = false;
  463. m_bExpandableWithoutChildren = false;
  464. }
  465. TreeNode::~TreeNode()
  466. {
  467. delete m_pExpandImage;
  468. if ( m_pData )
  469. {
  470. m_pData->deleteThis();
  471. }
  472. }
  473. void TreeNode::SetText(const char *pszText)
  474. {
  475. m_pText->SetText(pszText);
  476. InvalidateLayout();
  477. }
  478. void TreeNode::SetLabelEditingAllowed( bool state )
  479. {
  480. Assert( m_pTreeView->IsLabelEditingAllowed() );
  481. m_pText->SetLabelEditingAllowed( state );
  482. }
  483. bool TreeNode::IsLabelEditingAllowed() const
  484. {
  485. return m_pText->IsLabelEditingAllowed();
  486. }
  487. bool TreeNode::GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist )
  488. {
  489. return m_pTreeView->GetItemDropContextMenu( m_ItemIndex, menu, msglist );
  490. }
  491. bool TreeNode::IsDroppable( CUtlVector< KeyValues * >& msglist )
  492. {
  493. return m_pTreeView->IsItemDroppable( m_ItemIndex, msglist );
  494. }
  495. void TreeNode::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
  496. {
  497. m_pTreeView->OnItemDropped( m_ItemIndex, msglist );
  498. }
  499. HCursor TreeNode::GetDropCursor( CUtlVector< KeyValues * >& msglist )
  500. {
  501. return m_pTreeView->GetItemDropCursor( m_ItemIndex, msglist );
  502. }
  503. void TreeNode::OnCreateDragData( KeyValues *msg )
  504. {
  505. // make sure the dragged item appears selected,
  506. // on the off chance it appears deselected by a cntl mousedown
  507. m_pTreeView->AddSelectedItem( m_ItemIndex, false );
  508. m_pTreeView->GenerateDragDataForItem( m_ItemIndex, msg );
  509. }
  510. // For handling multiple selections...
  511. void TreeNode::OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles )
  512. {
  513. CUtlVector< int > list;
  514. m_pTreeView->GetSelectedItems( list );
  515. int c = list.Count();
  516. // walk this in reverse order so that panels are in order of selection
  517. // even though GetSelectedItems returns items in reverse selection order
  518. for ( int i = c - 1; i >= 0; --i )
  519. {
  520. int itemIndex = list[ i ];
  521. // Skip self
  522. if ( itemIndex == m_ItemIndex )
  523. continue;
  524. dragabbles.AddToTail( ( Panel * )m_pTreeView->GetItem( itemIndex ) );
  525. }
  526. }
  527. void TreeNode::OnLabelChanged( KeyValues *data )
  528. {
  529. char const *oldString = data->GetString( "original" );
  530. char const *newString = data->GetString( "changed" );
  531. if ( m_pTreeView->IsLabelEditingAllowed() )
  532. {
  533. m_pTreeView->OnLabelChanged( m_ItemIndex, oldString, newString );
  534. }
  535. }
  536. void TreeNode::EditLabel()
  537. {
  538. if ( m_pText->IsLabelEditingAllowed() &&
  539. !m_pText->IsBeingEdited() )
  540. {
  541. m_pText->EnterEditingInPlace();
  542. }
  543. }
  544. void TreeNode::SetFont(HFont font)
  545. {
  546. Assert( font );
  547. if ( !font )
  548. return;
  549. m_pText->SetFont(font);
  550. m_pExpandImage->SetFont(font);
  551. InvalidateLayout();
  552. int i;
  553. for (i=0;i<GetChildrenCount();i++)
  554. {
  555. m_Children[i]->SetFont(font);
  556. }
  557. }
  558. void TreeNode::SetKeyValues(KeyValues *data)
  559. {
  560. if ( m_pData != data )
  561. {
  562. if (m_pData)
  563. {
  564. m_pData->deleteThis();
  565. }
  566. m_pData = data->MakeCopy();
  567. }
  568. // set text
  569. m_pText->SetText(data->GetString("Text", ""));
  570. m_bExpandableWithoutChildren = data->GetInt("Expand");
  571. InvalidateLayout();
  572. }
  573. bool TreeNode::IsSelected()
  574. {
  575. return m_pTreeView->IsItemSelected( m_ItemIndex );
  576. }
  577. void TreeNode::PaintBackground()
  578. {
  579. if ( !m_pText->IsBeingEdited() )
  580. {
  581. // setup panel drawing
  582. if ( IsSelected() )
  583. {
  584. m_pText->SelectAllText(false);
  585. }
  586. else
  587. {
  588. m_pText->SelectNoText();
  589. }
  590. }
  591. BaseClass::PaintBackground();
  592. }
  593. // currently unused, could be re-used if necessary
  594. /*
  595. bool TreeNode::IsInFocus()
  596. {
  597. // check if our parent or one of it's children has focus
  598. VPANEL focus = input()->GetFocus();
  599. return (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())));
  600. }
  601. */
  602. void TreeNode::PerformLayout()
  603. {
  604. BaseClass::PerformLayout();
  605. int width = 0;
  606. if (m_pData->GetInt("SelectedImage", 0) == 0 &&
  607. m_pData->GetInt("Image", 0) == 0)
  608. {
  609. width = TREE_INDENT_AMOUNT;
  610. }
  611. else
  612. {
  613. width = TREE_INDENT_AMOUNT * 2;
  614. }
  615. m_pText->SetPos(width, 0);
  616. int contentWide, contentTall;
  617. m_pText->SetToFullWidth();
  618. m_pText->GetSize(contentWide, contentTall);
  619. contentWide += 10;
  620. m_pText->SetSize( contentWide, m_pTreeView->GetRowHeight() );
  621. width += contentWide;
  622. SetSize(width, m_pTreeView->GetRowHeight());
  623. m_iNodeWidth = width;
  624. CalculateVisibleMaxWidth();
  625. }
  626. TreeNode *TreeNode::GetParentNode()
  627. {
  628. if (m_pTreeView->m_NodeList.IsValidIndex(m_ParentIndex))
  629. {
  630. return m_pTreeView->m_NodeList[m_ParentIndex];
  631. }
  632. return NULL;
  633. }
  634. int TreeNode::GetChildrenCount()
  635. {
  636. return m_Children.Count();
  637. }
  638. int TreeNode::ComputeInsertionPosition( TreeNode *pChild )
  639. {
  640. if ( !m_pTreeView->m_pSortFunc )
  641. {
  642. return GetChildrenCount() - 1;
  643. }
  644. int start = 0, end = GetChildrenCount() - 1;
  645. while (start <= end)
  646. {
  647. int mid = (start + end) >> 1;
  648. if ( m_pTreeView->m_pSortFunc( m_Children[mid]->m_pData, pChild->m_pData ) )
  649. {
  650. start = mid + 1;
  651. }
  652. else if ( m_pTreeView->m_pSortFunc( pChild->m_pData, m_Children[mid]->m_pData ) )
  653. {
  654. end = mid - 1;
  655. }
  656. else
  657. {
  658. return mid;
  659. }
  660. }
  661. return end;
  662. }
  663. int TreeNode::FindChild( TreeNode *pChild )
  664. {
  665. if ( !m_pTreeView->m_pSortFunc )
  666. {
  667. AssertMsg( 0, "This code has never been tested. Is it correct?" );
  668. for ( int i = 0; i < GetChildrenCount(); ++i )
  669. {
  670. if ( m_Children[i] == pChild )
  671. return i;
  672. }
  673. return -1;
  674. }
  675. // Find the first entry <= to the child
  676. int start = 0, end = GetChildrenCount() - 1;
  677. while (start <= end)
  678. {
  679. int mid = (start + end) >> 1;
  680. if ( m_Children[mid] == pChild )
  681. return mid;
  682. if ( m_pTreeView->m_pSortFunc( m_Children[mid]->m_pData, pChild->m_pData ) )
  683. {
  684. start = mid + 1;
  685. }
  686. else
  687. {
  688. end = mid - 1;
  689. }
  690. }
  691. int nMax = GetChildrenCount();
  692. while( end < nMax )
  693. {
  694. // Stop when we reach a child that has a different value
  695. if ( m_pTreeView->m_pSortFunc( pChild->m_pData, m_Children[end]->m_pData ) )
  696. return -1;
  697. if ( m_Children[end] == pChild )
  698. return end;
  699. ++end;
  700. }
  701. return -1;
  702. }
  703. void TreeNode::AddChild(TreeNode *pChild)
  704. {
  705. int i = ComputeInsertionPosition( pChild );
  706. m_Children.InsertAfter( i, pChild );
  707. }
  708. void TreeNode::SetNodeExpanded(bool bExpanded)
  709. {
  710. m_bExpand = bExpanded;
  711. if (m_bExpand)
  712. {
  713. // see if we have any child nodes
  714. if (GetChildrenCount() < 1)
  715. {
  716. // we need to get our children from the control
  717. m_pTreeView->GenerateChildrenOfNode(m_ItemIndex);
  718. // if we still don't have any children, then hide the expand button
  719. if (GetChildrenCount() < 1)
  720. {
  721. m_bExpand = false;
  722. m_bExpandableWithoutChildren = false;
  723. m_pTreeView->InvalidateLayout();
  724. return;
  725. }
  726. }
  727. m_pExpandImage->SetText("-");
  728. }
  729. else
  730. {
  731. m_pExpandImage->SetText("+");
  732. if ( m_bExpandableWithoutChildren && GetChildrenCount() > 0 )
  733. {
  734. m_pTreeView->RemoveChildrenOfNode( m_ItemIndex );
  735. }
  736. // check if we've closed down on one of our children, if so, we get the focus
  737. int selectedItem = m_pTreeView->GetFirstSelectedItem();
  738. if (selectedItem != -1 && m_pTreeView->m_NodeList[selectedItem]->HasParent(this))
  739. {
  740. m_pTreeView->AddSelectedItem( m_ItemIndex, true );
  741. }
  742. }
  743. CalculateVisibleMaxWidth();
  744. m_pTreeView->InvalidateLayout();
  745. }
  746. bool TreeNode::IsExpanded()
  747. {
  748. return m_bExpand;
  749. }
  750. int TreeNode::CountVisibleNodes()
  751. {
  752. int count = 1; // count myself
  753. if (m_bExpand)
  754. {
  755. int i;
  756. for (i=0;i<m_Children.Count();i++)
  757. {
  758. count += m_Children[i]->CountVisibleNodes();
  759. }
  760. }
  761. return count;
  762. }
  763. void TreeNode::CalculateVisibleMaxWidth()
  764. {
  765. int width;
  766. if (m_bExpand)
  767. {
  768. int childMaxWidth = GetMaxChildrenWidth();
  769. childMaxWidth += TREE_INDENT_AMOUNT;
  770. width = max(childMaxWidth, m_iNodeWidth);
  771. }
  772. else
  773. {
  774. width = m_iNodeWidth;
  775. }
  776. if (width != m_iMaxVisibleWidth)
  777. {
  778. m_iMaxVisibleWidth = width;
  779. if (GetParentNode())
  780. {
  781. GetParentNode()->OnChildWidthChange();
  782. }
  783. else
  784. {
  785. m_pTreeView->InvalidateLayout();
  786. }
  787. }
  788. }
  789. void TreeNode::OnChildWidthChange()
  790. {
  791. CalculateVisibleMaxWidth();
  792. }
  793. int TreeNode::GetMaxChildrenWidth()
  794. {
  795. int maxWidth = 0;
  796. int i;
  797. for (i=0;i<GetChildrenCount();i++)
  798. {
  799. int childWidth = m_Children[i]->GetVisibleMaxWidth();
  800. if (childWidth > maxWidth)
  801. {
  802. maxWidth = childWidth;
  803. }
  804. }
  805. return maxWidth;
  806. }
  807. int TreeNode::GetVisibleMaxWidth()
  808. {
  809. return m_iMaxVisibleWidth;
  810. }
  811. int TreeNode::GetDepth()
  812. {
  813. int depth = 0;
  814. TreeNode *pParent = GetParentNode();
  815. while (pParent)
  816. {
  817. depth++;
  818. pParent = pParent->GetParentNode();
  819. }
  820. return depth;
  821. }
  822. bool TreeNode::HasParent(TreeNode *pTreeNode)
  823. {
  824. TreeNode *pParent = GetParentNode();
  825. while (pParent)
  826. {
  827. if (pParent == pTreeNode)
  828. return true;
  829. pParent = pParent->GetParentNode();
  830. }
  831. return false;
  832. }
  833. bool TreeNode::IsBeingDisplayed()
  834. {
  835. TreeNode *pParent = GetParentNode();
  836. while (pParent)
  837. {
  838. // our parents aren't showing us
  839. if (!pParent->m_bExpand)
  840. return false;
  841. pParent = pParent->GetParentNode();
  842. }
  843. return true;
  844. }
  845. void TreeNode::SetVisible(bool state)
  846. {
  847. BaseClass::SetVisible(state);
  848. bool bChildrenVisible = state && m_bExpand;
  849. int i;
  850. for (i=0;i<GetChildrenCount();i++)
  851. {
  852. m_Children[i]->SetVisible(bChildrenVisible);
  853. }
  854. }
  855. void TreeNode::Paint()
  856. {
  857. if (GetChildrenCount() > 0 || m_bExpandableWithoutChildren)
  858. {
  859. m_pExpandImage->Paint();
  860. }
  861. // set image
  862. int imageIndex = 0;
  863. if (IsSelected())
  864. {
  865. imageIndex = m_pData->GetInt("SelectedImage", 0);
  866. }
  867. else
  868. {
  869. imageIndex = m_pData->GetInt("Image", 0);
  870. }
  871. if (imageIndex)
  872. {
  873. IImage *pImage = m_pTreeView->GetImage(imageIndex);
  874. if (pImage)
  875. {
  876. m_pImagePanel->SetImage(pImage);
  877. }
  878. m_pImagePanel->Paint();
  879. }
  880. m_pText->Paint();
  881. }
  882. void TreeNode::ApplySchemeSettings(IScheme *pScheme)
  883. {
  884. BaseClass::ApplySchemeSettings(pScheme);
  885. SetBorder( NULL );
  886. SetFgColor( m_pTreeView->GetFgColor() );
  887. SetBgColor( m_pTreeView->GetBgColor() );
  888. SetFont( m_pTreeView->GetFont() );
  889. }
  890. void TreeNode::SetSelectionTextColor( const Color& clr )
  891. {
  892. if ( m_pText )
  893. {
  894. m_pText->SetSelectionTextColor( clr );
  895. }
  896. }
  897. void TreeNode::SetSelectionBgColor( const Color& clr )
  898. {
  899. if ( m_pText )
  900. {
  901. m_pText->SetSelectionBgColor( clr );
  902. }
  903. }
  904. void TreeNode::SetSelectionUnfocusedBgColor( const Color& clr )
  905. {
  906. if ( m_pText )
  907. {
  908. m_pText->SetSelectionUnfocusedBgColor( clr );
  909. }
  910. }
  911. void TreeNode::SetBgColor( Color color )
  912. {
  913. BaseClass::SetBgColor( color );
  914. if ( m_pText )
  915. {
  916. m_pText->SetBgColor( color );
  917. }
  918. }
  919. void TreeNode::SetFgColor( Color color )
  920. {
  921. BaseClass::SetFgColor( color );
  922. if ( m_pText )
  923. {
  924. m_pText->SetFgColor( color );
  925. }
  926. }
  927. void TreeNode::OnSetFocus()
  928. {
  929. m_pText->RequestFocus();
  930. }
  931. int TreeNode::GetPrevChildItemIndex( TreeNode *pCurrentChild )
  932. {
  933. int i;
  934. for (i=0;i<GetChildrenCount();i++)
  935. {
  936. if ( m_Children[i] == pCurrentChild )
  937. {
  938. if ( i <= 0 )
  939. return -1;
  940. TreeNode *pChild = m_Children[i-1];
  941. return pChild->m_ItemIndex;
  942. }
  943. }
  944. return -1;
  945. }
  946. int TreeNode::GetNextChildItemIndex( TreeNode *pCurrentChild )
  947. {
  948. int i;
  949. for (i=0;i<GetChildrenCount();i++)
  950. {
  951. if ( m_Children[i] == pCurrentChild )
  952. {
  953. if ( i >= GetChildrenCount() - 1 )
  954. return -1;
  955. TreeNode *pChild = m_Children[i+1];
  956. return pChild->m_ItemIndex;
  957. }
  958. }
  959. return -1;
  960. }
  961. void TreeNode::SelectPrevChild(TreeNode *pCurrentChild)
  962. {
  963. int i;
  964. for (i=0;i<GetChildrenCount();i++)
  965. {
  966. if (m_Children[i] == pCurrentChild)
  967. break;
  968. }
  969. // this shouldn't happen
  970. if (i == GetChildrenCount())
  971. {
  972. Assert(0);
  973. return;
  974. }
  975. // were we on the first child?
  976. if (i == 0)
  977. {
  978. // if so, then we take over!
  979. m_pTreeView->AddSelectedItem( m_ItemIndex, true );
  980. }
  981. else
  982. {
  983. // see if we need to find a grandchild of the previous sibling
  984. TreeNode *pChild = m_Children[i-1];
  985. // if this child is expanded with children, then we have to find the last child
  986. while (pChild->m_bExpand && pChild->GetChildrenCount()>0)
  987. {
  988. // find the last child
  989. pChild = pChild->m_Children[pChild->GetChildrenCount()-1];
  990. }
  991. m_pTreeView->AddSelectedItem( pChild->m_ItemIndex, true );
  992. }
  993. }
  994. void TreeNode::SelectNextChild(TreeNode *pCurrentChild)
  995. {
  996. int i;
  997. for (i=0;i<GetChildrenCount();i++)
  998. {
  999. if (m_Children[i] == pCurrentChild)
  1000. break;
  1001. }
  1002. // this shouldn't happen
  1003. if (i == GetChildrenCount())
  1004. {
  1005. Assert(0);
  1006. return;
  1007. }
  1008. // were we on the last child?
  1009. if (i == GetChildrenCount() - 1)
  1010. {
  1011. // tell our parent to get the next child
  1012. if (GetParentNode())
  1013. {
  1014. GetParentNode()->SelectNextChild(this);
  1015. }
  1016. }
  1017. else
  1018. {
  1019. m_pTreeView->AddSelectedItem( m_Children[i+1]->m_ItemIndex, true );
  1020. }
  1021. }
  1022. void TreeNode::ClosePreviousParents( TreeNode *pPreviousParent )
  1023. {
  1024. // close up all the open nodes we've just stepped out of.
  1025. CUtlVector< int > selected;
  1026. m_pTreeView->GetSelectedItems( selected );
  1027. if ( selected.Count() == 0 )
  1028. {
  1029. Assert( 0 );
  1030. return;
  1031. }
  1032. // Most recently clicked item
  1033. TreeNode *selectedItem = m_pTreeView->GetItem( selected[ 0 ] );
  1034. TreeNode *pNewParent = selectedItem->GetParentNode();
  1035. if ( pPreviousParent && pNewParent )
  1036. {
  1037. while ( pPreviousParent->m_ItemIndex > pNewParent->m_ItemIndex )
  1038. {
  1039. pPreviousParent->SetNodeExpanded(false);
  1040. pPreviousParent = pPreviousParent->GetParentNode();
  1041. }
  1042. }
  1043. }
  1044. void TreeNode::StepInto( bool bClosePrevious )
  1045. {
  1046. if ( !m_bExpand )
  1047. {
  1048. SetNodeExpanded(true);
  1049. }
  1050. if ( ( GetChildrenCount() > 0 ) && m_bExpand )
  1051. {
  1052. m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
  1053. }
  1054. else if ( GetParentNode() )
  1055. {
  1056. TreeNode *pParent = GetParentNode();
  1057. pParent->SelectNextChild(this);
  1058. if ( bClosePrevious )
  1059. {
  1060. ClosePreviousParents( pParent );
  1061. }
  1062. }
  1063. }
  1064. void TreeNode::StepOut( bool bClosePrevious )
  1065. {
  1066. TreeNode *pParent = GetParentNode();
  1067. if ( pParent )
  1068. {
  1069. m_pTreeView->AddSelectedItem( pParent->m_ItemIndex, true );
  1070. if ( pParent->GetParentNode() )
  1071. {
  1072. pParent->GetParentNode()->SelectNextChild(pParent);
  1073. }
  1074. if ( bClosePrevious )
  1075. {
  1076. ClosePreviousParents( pParent );
  1077. }
  1078. else
  1079. {
  1080. pParent->SetNodeExpanded(true);
  1081. }
  1082. }
  1083. }
  1084. void TreeNode::StepOver( bool bClosePrevious )
  1085. {
  1086. TreeNode *pParent = GetParentNode();
  1087. if ( pParent )
  1088. {
  1089. GetParentNode()->SelectNextChild(this);
  1090. if ( bClosePrevious )
  1091. {
  1092. ClosePreviousParents( pParent );
  1093. }
  1094. }
  1095. }
  1096. void TreeNode::OnKeyCodeTyped(KeyCode code)
  1097. {
  1098. switch (code)
  1099. {
  1100. case KEY_LEFT:
  1101. {
  1102. if (m_bExpand && GetChildrenCount() > 0)
  1103. {
  1104. SetNodeExpanded(false);
  1105. }
  1106. else
  1107. {
  1108. if (GetParentNode())
  1109. {
  1110. m_pTreeView->AddSelectedItem( GetParentNode()->m_ItemIndex, true );
  1111. }
  1112. }
  1113. break;
  1114. }
  1115. case KEY_RIGHT:
  1116. {
  1117. if (!m_bExpand)
  1118. {
  1119. SetNodeExpanded(true);
  1120. }
  1121. else if (GetChildrenCount() > 0)
  1122. {
  1123. m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
  1124. }
  1125. break;
  1126. }
  1127. case KEY_UP:
  1128. {
  1129. if (GetParentNode())
  1130. {
  1131. GetParentNode()->SelectPrevChild(this);
  1132. }
  1133. break;
  1134. }
  1135. case KEY_DOWN:
  1136. {
  1137. if (GetChildrenCount() > 0 && m_bExpand)
  1138. {
  1139. m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
  1140. }
  1141. else if (GetParentNode())
  1142. {
  1143. GetParentNode()->SelectNextChild(this);
  1144. }
  1145. break;
  1146. }
  1147. case KEY_SPACE:
  1148. {
  1149. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  1150. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  1151. bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
  1152. if ( shift )
  1153. {
  1154. StepOut( !ctrl );
  1155. }
  1156. else if ( alt )
  1157. {
  1158. StepOver( !ctrl );
  1159. }
  1160. else
  1161. {
  1162. StepInto( !ctrl );
  1163. }
  1164. break;
  1165. }
  1166. case KEY_I:
  1167. {
  1168. StepInto();
  1169. break;
  1170. }
  1171. case KEY_U:
  1172. {
  1173. StepOut();
  1174. break;
  1175. }
  1176. case KEY_O:
  1177. {
  1178. StepOver();
  1179. break;
  1180. }
  1181. case KEY_ESCAPE:
  1182. {
  1183. if ( m_pTreeView->GetSelectedItemCount() > 0 )
  1184. {
  1185. m_pTreeView->ClearSelection();
  1186. }
  1187. else
  1188. {
  1189. BaseClass::OnKeyCodeTyped(code);
  1190. }
  1191. }
  1192. break;
  1193. case KEY_A:
  1194. {
  1195. bool ctrldown = input()->IsKeyDown( KEY_LCONTROL ) || input()->IsKeyDown( KEY_RCONTROL );
  1196. if ( ctrldown )
  1197. {
  1198. m_pTreeView->SelectAll();
  1199. }
  1200. else
  1201. {
  1202. BaseClass::OnKeyCodeTyped(code);
  1203. }
  1204. }
  1205. break;
  1206. default:
  1207. BaseClass::OnKeyCodeTyped(code);
  1208. return;
  1209. }
  1210. }
  1211. void TreeNode::OnMouseWheeled(int delta)
  1212. {
  1213. CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
  1214. }
  1215. void TreeNode::OnMouseDoublePressed( MouseCode code )
  1216. {
  1217. int x, y;
  1218. input()->GetCursorPos(x, y);
  1219. if (code == MOUSE_LEFT)
  1220. {
  1221. ScreenToLocal(x, y);
  1222. if (x > TREE_INDENT_AMOUNT)
  1223. {
  1224. SetNodeExpanded(!m_bExpand);
  1225. }
  1226. }
  1227. }
  1228. bool TreeNode::IsDragEnabled() const
  1229. {
  1230. int x, y;
  1231. input()->GetCursorPos(x, y);
  1232. ((TreeNode *)this)->ScreenToLocal(x, y);
  1233. if ( x < TREE_INDENT_AMOUNT )
  1234. return false;
  1235. return BaseClass::IsDragEnabled();
  1236. }
  1237. void TreeNode::OnMouseReleased(MouseCode code)
  1238. {
  1239. BaseClass::OnMouseReleased( code );
  1240. if ( input()->GetMouseCapture() == GetVPanel() )
  1241. {
  1242. input()->SetMouseCapture( NULL );
  1243. return;
  1244. }
  1245. int x, y;
  1246. input()->GetCursorPos(x, y);
  1247. ScreenToLocal(x, y);
  1248. if ( x < TREE_INDENT_AMOUNT )
  1249. return;
  1250. bool ctrldown = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  1251. bool shiftdown = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  1252. if ( !ctrldown && !shiftdown && ( code == MOUSE_LEFT ) )
  1253. {
  1254. m_pTreeView->AddSelectedItem( m_ItemIndex, true );
  1255. }
  1256. }
  1257. void TreeNode::OnCursorMoved( int x, int y )
  1258. {
  1259. if ( input()->GetMouseCapture() != GetVPanel() )
  1260. return;
  1261. LocalToScreen( x, y );
  1262. m_pTreeView->ScreenToLocal( x, y );
  1263. int newItem = m_pTreeView->FindItemUnderMouse( x, y );
  1264. if ( newItem == -1 )
  1265. {
  1266. // Fixme: Figure out best item
  1267. return;
  1268. }
  1269. int startItem = m_nClickedItem;
  1270. int endItem = newItem;
  1271. if ( startItem > endItem )
  1272. {
  1273. int temp = startItem;
  1274. startItem = endItem;
  1275. endItem = temp;
  1276. }
  1277. CUtlVector< TreeNode * > list;
  1278. m_pTreeView->m_pRootNode->FindNodesInRange( list, startItem, endItem );
  1279. int c = list.Count();
  1280. for ( int i = 0; i < c; ++i )
  1281. {
  1282. TreeNode *item = list[ i ];
  1283. if ( m_bClickedSelected )
  1284. {
  1285. m_pTreeView->AddSelectedItem( item->m_ItemIndex, false );
  1286. }
  1287. else
  1288. {
  1289. m_pTreeView->RemoveSelectedItem( item->m_ItemIndex );
  1290. }
  1291. }
  1292. }
  1293. void TreeNode::OnMousePressed( MouseCode code)
  1294. {
  1295. BaseClass::OnMousePressed( code );
  1296. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  1297. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  1298. int x, y;
  1299. input()->GetCursorPos(x, y);
  1300. bool bExpandTree = m_pTreeView->m_bLeftClickExpandsTree;
  1301. if ( code == MOUSE_LEFT )
  1302. {
  1303. ScreenToLocal(x, y);
  1304. if ( x < TREE_INDENT_AMOUNT )
  1305. {
  1306. if ( bExpandTree )
  1307. {
  1308. SetNodeExpanded(!m_bExpand);
  1309. }
  1310. // m_pTreeView->SetSelectedItem(m_ItemIndex); // explorer doesn't actually select item when it expands an item
  1311. // purposely commented out in case we want to change the behavior
  1312. }
  1313. else
  1314. {
  1315. m_nClickedItem = m_ItemIndex;
  1316. if ( m_pTreeView->IsMultipleItemDragEnabled() )
  1317. {
  1318. input()->SetMouseCapture( GetVPanel() );
  1319. }
  1320. if ( shift )
  1321. {
  1322. m_pTreeView->RangeSelectItems( m_ItemIndex );
  1323. }
  1324. else
  1325. {
  1326. if ( !IsSelected() || ctrl )
  1327. {
  1328. if ( IsSelected() && ctrl )
  1329. {
  1330. m_pTreeView->RemoveSelectedItem( m_ItemIndex );
  1331. }
  1332. else
  1333. {
  1334. m_pTreeView->AddSelectedItem( m_ItemIndex, !ctrl );
  1335. }
  1336. }
  1337. else if ( IsSelected() && m_pTreeView->IsMultipleItemDragEnabled() )
  1338. {
  1339. m_pTreeView->AddSelectedItem( m_ItemIndex, !shift );
  1340. }
  1341. }
  1342. m_bClickedSelected = m_pTreeView->IsItemSelected( m_ItemIndex );
  1343. }
  1344. }
  1345. else if (code == MOUSE_RIGHT)
  1346. {
  1347. // context menu selection
  1348. // If the item was selected, leave selected items alone, otherwise make it the only selected item
  1349. if ( !m_pTreeView->IsItemSelected( m_ItemIndex ) )
  1350. {
  1351. m_pTreeView->AddSelectedItem( m_ItemIndex, true );
  1352. }
  1353. // ask parent to context menu
  1354. m_pTreeView->GenerateContextMenu(m_ItemIndex, x, y);
  1355. }
  1356. }
  1357. void TreeNode::RemoveChildren()
  1358. {
  1359. int c = m_Children.Count();
  1360. for ( int i = c - 1 ; i >= 0 ; --i )
  1361. {
  1362. m_pTreeView->RemoveItem( m_Children[ i ]->m_ItemIndex, false, true );
  1363. }
  1364. m_Children.RemoveAll();
  1365. }
  1366. void TreeNode::FindNodesInRange( CUtlVector< TreeNode * >& list, int startIndex, int endIndex )
  1367. {
  1368. list.RemoveAll();
  1369. bool finished = false;
  1370. bool foundstart = false;
  1371. FindNodesInRange_R( list, finished, foundstart, startIndex, endIndex );
  1372. }
  1373. void TreeNode::FindNodesInRange_R( CUtlVector< TreeNode * >& list, bool& finished, bool& foundStart, int startIndex, int endIndex )
  1374. {
  1375. if ( finished )
  1376. return;
  1377. if ( foundStart == true )
  1378. {
  1379. list.AddToTail( this );
  1380. if ( m_ItemIndex == startIndex || m_ItemIndex == endIndex )
  1381. {
  1382. finished = true;
  1383. return;
  1384. }
  1385. }
  1386. else if ( m_ItemIndex == startIndex || m_ItemIndex == endIndex )
  1387. {
  1388. foundStart = true;
  1389. list.AddToTail( this );
  1390. if ( startIndex == endIndex )
  1391. {
  1392. finished = true;
  1393. return;
  1394. }
  1395. }
  1396. if ( !m_bExpand )
  1397. return;
  1398. int i;
  1399. int c = GetChildrenCount();
  1400. for (i=0;i<c;i++)
  1401. {
  1402. m_Children[i]->FindNodesInRange_R( list, finished, foundStart, startIndex, endIndex );
  1403. }
  1404. }
  1405. void TreeNode::PositionAndSetVisibleNodes(int &nStart, int &nCount, int x, int &y)
  1406. {
  1407. // position ourselves
  1408. if (nStart == 0)
  1409. {
  1410. BaseClass::SetVisible(true);
  1411. SetPos(x, y);
  1412. y += m_pTreeView->GetRowHeight(); // m_nRowHeight
  1413. nCount--;
  1414. }
  1415. else // still looking for first element
  1416. {
  1417. nStart--;
  1418. BaseClass::SetVisible(false);
  1419. }
  1420. x += TREE_INDENT_AMOUNT;
  1421. int i;
  1422. for (i=0;i<GetChildrenCount();i++)
  1423. {
  1424. if (nCount > 0 && m_bExpand)
  1425. {
  1426. m_Children[i]->PositionAndSetVisibleNodes(nStart, nCount, x, y);
  1427. }
  1428. else
  1429. {
  1430. m_Children[i]->SetVisible(false); // this will make all grand children hidden as well
  1431. }
  1432. }
  1433. }
  1434. TreeNode *TreeNode::FindItemUnderMouse( int &nStart, int& nCount, int x, int &y, int mx, int my )
  1435. {
  1436. // position ourselves
  1437. if (nStart == 0)
  1438. {
  1439. int posx, posy;
  1440. GetPos(posx, posy);
  1441. if ( my >= posy && my < posy + m_pTreeView->GetRowHeight() )
  1442. {
  1443. return this;
  1444. }
  1445. y += m_pTreeView->GetRowHeight();
  1446. nCount--;
  1447. }
  1448. else // still looking for first element
  1449. {
  1450. nStart--;
  1451. }
  1452. x += TREE_INDENT_AMOUNT;
  1453. int i;
  1454. for (i=0;i<GetChildrenCount();i++)
  1455. {
  1456. if (nCount > 0 && m_bExpand)
  1457. {
  1458. TreeNode *child = m_Children[i]->FindItemUnderMouse(nStart, nCount, x, y, mx, my);
  1459. if ( child != NULL )
  1460. {
  1461. return child;
  1462. }
  1463. }
  1464. }
  1465. return NULL;
  1466. }
  1467. // counts items above this item including itself
  1468. int TreeNode::CountVisibleIndex()
  1469. {
  1470. int nCount = 1; // myself
  1471. if (GetParentNode())
  1472. {
  1473. int i;
  1474. for (i=0;i<GetParentNode()->GetChildrenCount();i++)
  1475. {
  1476. if (GetParentNode()->m_Children[i] == this)
  1477. break;
  1478. nCount += GetParentNode()->m_Children[i]->CountVisibleNodes();
  1479. }
  1480. return nCount + GetParentNode()->CountVisibleIndex();
  1481. }
  1482. else
  1483. return nCount;
  1484. }
  1485. }; // namespace vgui
  1486. DECLARE_BUILD_FACTORY( TreeView );
  1487. //-----------------------------------------------------------------------------
  1488. // Purpose:
  1489. //-----------------------------------------------------------------------------
  1490. TreeView::TreeView(Panel *parent, const char *panelName) : Panel(parent, panelName)
  1491. {
  1492. m_bScrollbarExternal[ 0 ] = m_bScrollbarExternal[ 1 ] = false;
  1493. m_nRowHeight = 20;
  1494. m_pRootNode = NULL;
  1495. m_pImageList = NULL;
  1496. m_pSortFunc = NULL;
  1497. m_Font = 0;
  1498. m_pSubPanel = new TreeViewSubPanel(this);
  1499. m_pSubPanel->SetVisible(true);
  1500. m_pSubPanel->SetPos(0,0);
  1501. m_pHorzScrollBar = new ScrollBar(this, "HorizScrollBar", false);
  1502. m_pHorzScrollBar->AddActionSignalTarget(this);
  1503. m_pHorzScrollBar->SetVisible(false);
  1504. m_pVertScrollBar = new ScrollBar(this, "VertScrollBar", true);
  1505. m_pVertScrollBar->SetVisible(false);
  1506. m_pVertScrollBar->AddActionSignalTarget(this);
  1507. m_bAllowLabelEditing = false;
  1508. m_bDragEnabledItems = false;
  1509. m_bDeleteImageListWhenDone = false;
  1510. m_bLabelBeingEdited = false;
  1511. m_bMultipleItemDragging = false;
  1512. m_bLeftClickExpandsTree = true;
  1513. m_bAllowMultipleSelections = false;
  1514. m_nMostRecentlySelectedItem = -1;
  1515. }
  1516. //-----------------------------------------------------------------------------
  1517. // Purpose:
  1518. //-----------------------------------------------------------------------------
  1519. TreeView::~TreeView()
  1520. {
  1521. CleanUpImageList();
  1522. }
  1523. //-----------------------------------------------------------------------------
  1524. // Clean up the image list
  1525. //-----------------------------------------------------------------------------
  1526. void TreeView::CleanUpImageList( )
  1527. {
  1528. if ( m_pImageList )
  1529. {
  1530. if ( m_bDeleteImageListWhenDone )
  1531. {
  1532. delete m_pImageList;
  1533. }
  1534. m_pImageList = NULL;
  1535. }
  1536. }
  1537. //-----------------------------------------------------------------------------
  1538. // Purpose:
  1539. //-----------------------------------------------------------------------------
  1540. void TreeView::SetSortFunc(TreeViewSortFunc_t pSortFunc)
  1541. {
  1542. m_pSortFunc = pSortFunc;
  1543. }
  1544. HFont TreeView::GetFont()
  1545. {
  1546. return m_Font;
  1547. }
  1548. //-----------------------------------------------------------------------------
  1549. // Purpose:
  1550. //-----------------------------------------------------------------------------
  1551. void TreeView::SetFont(HFont font)
  1552. {
  1553. Assert( font );
  1554. if ( !font )
  1555. return;
  1556. m_Font = font;
  1557. m_nRowHeight = surface()->GetFontTall(font) + 2;
  1558. if (m_pRootNode)
  1559. {
  1560. m_pRootNode->SetFont(font);
  1561. }
  1562. InvalidateLayout();
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // Purpose:
  1566. //-----------------------------------------------------------------------------
  1567. int TreeView::GetRowHeight()
  1568. {
  1569. return m_nRowHeight;
  1570. }
  1571. //-----------------------------------------------------------------------------
  1572. // Purpose:
  1573. //-----------------------------------------------------------------------------
  1574. int TreeView::GetVisibleMaxWidth()
  1575. {
  1576. if (m_pRootNode)
  1577. {
  1578. return m_pRootNode->GetVisibleMaxWidth();
  1579. }
  1580. else
  1581. {
  1582. return 0;
  1583. }
  1584. }
  1585. //-----------------------------------------------------------------------------
  1586. // Purpose:
  1587. //-----------------------------------------------------------------------------
  1588. int TreeView::AddItem(KeyValues *data, int parentItemIndex)
  1589. {
  1590. Assert(parentItemIndex == -1 || m_NodeList.IsValidIndex(parentItemIndex));
  1591. TreeNode *pTreeNode = new TreeNode(m_pSubPanel, this);
  1592. pTreeNode->SetDragEnabled( m_bDragEnabledItems );
  1593. pTreeNode->m_ItemIndex = m_NodeList.AddToTail(pTreeNode);
  1594. pTreeNode->SetKeyValues(data);
  1595. if ( m_Font != 0 )
  1596. {
  1597. pTreeNode->SetFont( m_Font );
  1598. }
  1599. pTreeNode->SetBgColor( GetBgColor() );
  1600. if ( data->GetInt( "droppable", 0 ) != 0 )
  1601. {
  1602. float flContextDelay = data->GetFloat( "drophoverdelay" );
  1603. if ( flContextDelay )
  1604. {
  1605. pTreeNode->SetDropEnabled( true, flContextDelay );
  1606. }
  1607. else
  1608. {
  1609. pTreeNode->SetDropEnabled( true );
  1610. }
  1611. }
  1612. // there can be only one root
  1613. if (parentItemIndex == -1)
  1614. {
  1615. Assert(m_pRootNode == NULL);
  1616. m_pRootNode = pTreeNode;
  1617. pTreeNode->m_ParentIndex = -1;
  1618. }
  1619. else
  1620. {
  1621. pTreeNode->m_ParentIndex = parentItemIndex;
  1622. // add to parent list
  1623. pTreeNode->GetParentNode()->AddChild(pTreeNode);
  1624. }
  1625. SETUP_PANEL( pTreeNode );
  1626. return pTreeNode->m_ItemIndex;
  1627. }
  1628. int TreeView::GetRootItemIndex()
  1629. {
  1630. if ( m_pRootNode )
  1631. return m_pRootNode->m_ItemIndex;
  1632. else
  1633. return -1;
  1634. }
  1635. int TreeView::GetNumChildren( int itemIndex )
  1636. {
  1637. if ( itemIndex == -1 )
  1638. return 0;
  1639. return m_NodeList[itemIndex]->m_Children.Count();
  1640. }
  1641. int TreeView::GetChild( int iParentItemIndex, int iChild )
  1642. {
  1643. return m_NodeList[iParentItemIndex]->m_Children[iChild]->m_ItemIndex;
  1644. }
  1645. //-----------------------------------------------------------------------------
  1646. // Purpose:
  1647. // Input : itemIndex -
  1648. // Output : TreeNode
  1649. //-----------------------------------------------------------------------------
  1650. TreeNode *TreeView::GetItem( int itemIndex )
  1651. {
  1652. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  1653. {
  1654. Assert( 0 );
  1655. return NULL;
  1656. }
  1657. return m_NodeList[ itemIndex ];
  1658. }
  1659. //-----------------------------------------------------------------------------
  1660. // Purpose:
  1661. //-----------------------------------------------------------------------------
  1662. int TreeView::GetItemCount(void)
  1663. {
  1664. return m_NodeList.Count();
  1665. }
  1666. //-----------------------------------------------------------------------------
  1667. // Purpose:
  1668. //-----------------------------------------------------------------------------
  1669. KeyValues* TreeView::GetItemData(int itemIndex)
  1670. {
  1671. if (!m_NodeList.IsValidIndex(itemIndex))
  1672. return NULL;
  1673. else
  1674. return m_NodeList[itemIndex]->m_pData;
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. // Purpose:
  1678. //-----------------------------------------------------------------------------
  1679. void TreeView::RemoveItem(int itemIndex, bool bPromoteChildren, bool bFullDelete )
  1680. {
  1681. // HACK: there's a bug with RemoveItem where panels are lingering. This gets around it temporarily.
  1682. // FIXME: Negative item indices is a bogus interface method!
  1683. // because what if you want to recursively remove everything under node 0?
  1684. // Use the bFullDelete parameter instead.
  1685. if ( itemIndex < 0 )
  1686. {
  1687. itemIndex = -itemIndex;
  1688. bFullDelete = true;
  1689. }
  1690. if (!m_NodeList.IsValidIndex(itemIndex))
  1691. return;
  1692. TreeNode *pNode = m_NodeList[itemIndex];
  1693. TreeNode *pParent = pNode->GetParentNode();
  1694. // are we promoting the children
  1695. if (bPromoteChildren && pParent)
  1696. {
  1697. int i;
  1698. for (i=0;i<pNode->GetChildrenCount();i++)
  1699. {
  1700. TreeNode *pChild = pNode->m_Children[i];
  1701. pChild->m_ParentIndex = pParent->m_ItemIndex;
  1702. }
  1703. }
  1704. else
  1705. {
  1706. // delete our children
  1707. if ( bFullDelete )
  1708. {
  1709. while ( pNode->GetChildrenCount() )
  1710. RemoveItem( -pNode->m_Children[0]->m_ItemIndex, false );
  1711. }
  1712. else
  1713. {
  1714. int i;
  1715. for (i=0;i<pNode->GetChildrenCount();i++)
  1716. {
  1717. TreeNode *pDeleteChild = pNode->m_Children[i];
  1718. RemoveItem(pDeleteChild->m_ItemIndex, false);
  1719. }
  1720. }
  1721. }
  1722. // remove from our parent's children list
  1723. if (pParent)
  1724. {
  1725. pParent->m_Children.FindAndRemove(pNode);
  1726. }
  1727. // finally get rid of ourselves from the main list
  1728. m_NodeList.Remove(itemIndex);
  1729. if ( bFullDelete )
  1730. delete pNode;
  1731. else
  1732. pNode->MarkForDeletion();
  1733. // Make sure we don't leave ourselves with an invalid selected item.
  1734. m_SelectedItems.FindAndRemove( pNode );
  1735. }
  1736. //-----------------------------------------------------------------------------
  1737. // Purpose:
  1738. //-----------------------------------------------------------------------------
  1739. void TreeView::RemoveAll()
  1740. {
  1741. int i;
  1742. for (i=0;i<m_NodeList.MaxElementIndex();i++)
  1743. {
  1744. if (!m_NodeList.IsValidIndex(i))
  1745. continue;
  1746. m_NodeList[i]->MarkForDeletion();
  1747. }
  1748. m_NodeList.RemoveAll();
  1749. m_pRootNode = NULL;
  1750. ClearSelection();
  1751. }
  1752. //-----------------------------------------------------------------------------
  1753. // Purpose:
  1754. //-----------------------------------------------------------------------------
  1755. bool TreeView::ModifyItem(int itemIndex, KeyValues *data)
  1756. {
  1757. if (!m_NodeList.IsValidIndex(itemIndex))
  1758. return false;
  1759. TreeNode *pNode = m_NodeList[itemIndex];
  1760. TreeNode *pParent = pNode->GetParentNode();
  1761. bool bReSort = ( m_pSortFunc && pParent );
  1762. int nChildIndex = -1;
  1763. if ( bReSort )
  1764. {
  1765. nChildIndex = pParent->FindChild( pNode );
  1766. }
  1767. pNode->SetKeyValues(data);
  1768. // Changing the data can cause it to re-sort
  1769. if ( bReSort )
  1770. {
  1771. int nChildren = pParent->GetChildrenCount();
  1772. bool bLeftBad = (nChildIndex > 0) && m_pSortFunc( pNode->m_pData, pParent->m_Children[nChildIndex-1]->m_pData );
  1773. bool bRightBad = (nChildIndex < nChildren - 1) && m_pSortFunc( pParent->m_Children[nChildIndex+1]->m_pData, pNode->m_pData );
  1774. if ( bLeftBad || bRightBad )
  1775. {
  1776. pParent->m_Children.Remove( nChildIndex );
  1777. pParent->AddChild( pNode );
  1778. }
  1779. }
  1780. InvalidateLayout();
  1781. return true;
  1782. }
  1783. //-----------------------------------------------------------------------------
  1784. // Purpose: set the selection colors of an element in the tree view
  1785. //-----------------------------------------------------------------------------
  1786. void TreeView::SetItemSelectionTextColor( int itemIndex, const Color& clr )
  1787. {
  1788. Assert( m_NodeList.IsValidIndex(itemIndex) );
  1789. if ( !m_NodeList.IsValidIndex(itemIndex) )
  1790. return;
  1791. TreeNode *pNode = m_NodeList[itemIndex];
  1792. pNode->SetSelectionTextColor( clr );
  1793. }
  1794. void TreeView::SetItemSelectionBgColor( int itemIndex, const Color& clr )
  1795. {
  1796. Assert( m_NodeList.IsValidIndex(itemIndex) );
  1797. if ( !m_NodeList.IsValidIndex(itemIndex) )
  1798. return;
  1799. TreeNode *pNode = m_NodeList[itemIndex];
  1800. pNode->SetSelectionBgColor( clr );
  1801. }
  1802. void TreeView::SetItemSelectionUnfocusedBgColor( int itemIndex, const Color& clr )
  1803. {
  1804. Assert( m_NodeList.IsValidIndex(itemIndex) );
  1805. if ( !m_NodeList.IsValidIndex(itemIndex) )
  1806. return;
  1807. TreeNode *pNode = m_NodeList[itemIndex];
  1808. pNode->SetSelectionUnfocusedBgColor( clr );
  1809. }
  1810. //-----------------------------------------------------------------------------
  1811. // Purpose: set the fg color of an element in the tree view
  1812. //-----------------------------------------------------------------------------
  1813. void TreeView::SetItemFgColor(int itemIndex, const Color& color)
  1814. {
  1815. Assert( m_NodeList.IsValidIndex(itemIndex) );
  1816. if ( !m_NodeList.IsValidIndex(itemIndex) )
  1817. return;
  1818. TreeNode *pNode = m_NodeList[itemIndex];
  1819. pNode->SetFgColor( color );
  1820. }
  1821. //-----------------------------------------------------------------------------
  1822. // Purpose: set the bg color of an element in the tree view
  1823. //-----------------------------------------------------------------------------
  1824. void TreeView::SetItemBgColor(int itemIndex, const Color& color)
  1825. {
  1826. Assert( m_NodeList.IsValidIndex(itemIndex) );
  1827. if ( !m_NodeList.IsValidIndex(itemIndex) )
  1828. return;
  1829. TreeNode *pNode = m_NodeList[itemIndex];
  1830. pNode->SetBgColor( color );
  1831. }
  1832. //-----------------------------------------------------------------------------
  1833. // Purpose:
  1834. //-----------------------------------------------------------------------------
  1835. int TreeView::GetItemParent(int itemIndex)
  1836. {
  1837. return m_NodeList[itemIndex]->m_ParentIndex;
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. // Purpose:
  1841. //-----------------------------------------------------------------------------
  1842. void TreeView::SetImageList(ImageList *imageList, bool deleteImageListWhenDone)
  1843. {
  1844. CleanUpImageList();
  1845. m_pImageList = imageList;
  1846. m_bDeleteImageListWhenDone = deleteImageListWhenDone;
  1847. }
  1848. //-----------------------------------------------------------------------------
  1849. // Purpose:
  1850. //-----------------------------------------------------------------------------
  1851. IImage *TreeView::GetImage(int index)
  1852. {
  1853. return m_pImageList->GetImage(index);
  1854. }
  1855. //-----------------------------------------------------------------------------
  1856. // Purpose:
  1857. //-----------------------------------------------------------------------------
  1858. void TreeView::GetSelectedItems( CUtlVector< int >& list )
  1859. {
  1860. list.RemoveAll();
  1861. int c = m_SelectedItems.Count();
  1862. for ( int i = 0 ; i < c; ++i )
  1863. {
  1864. list.AddToTail( m_SelectedItems[ i ]->m_ItemIndex );
  1865. }
  1866. }
  1867. //-----------------------------------------------------------------------------
  1868. // Purpose:
  1869. //-----------------------------------------------------------------------------
  1870. void TreeView::GetSelectedItemData( CUtlVector< KeyValues * >& list )
  1871. {
  1872. list.RemoveAll();
  1873. int c = m_SelectedItems.Count();
  1874. for ( int i = 0 ; i < c; ++i )
  1875. {
  1876. list.AddToTail( m_SelectedItems[ i ]->m_pData );
  1877. }
  1878. }
  1879. //-----------------------------------------------------------------------------
  1880. // Purpose:
  1881. //-----------------------------------------------------------------------------
  1882. bool TreeView::IsItemIDValid(int itemIndex)
  1883. {
  1884. return m_NodeList.IsValidIndex(itemIndex);
  1885. }
  1886. //-----------------------------------------------------------------------------
  1887. // Purpose:
  1888. //-----------------------------------------------------------------------------
  1889. int TreeView::GetHighestItemID()
  1890. {
  1891. return m_NodeList.MaxElementIndex();
  1892. }
  1893. //-----------------------------------------------------------------------------
  1894. // Purpose:
  1895. //-----------------------------------------------------------------------------
  1896. void TreeView::ExpandItem(int itemIndex, bool bExpand)
  1897. {
  1898. if (!m_NodeList.IsValidIndex(itemIndex))
  1899. return;
  1900. m_NodeList[itemIndex]->SetNodeExpanded(bExpand);
  1901. InvalidateLayout();
  1902. }
  1903. bool TreeView::IsItemExpanded( int itemIndex )
  1904. {
  1905. if (!m_NodeList.IsValidIndex(itemIndex))
  1906. return false;
  1907. return m_NodeList[itemIndex]->IsExpanded();
  1908. }
  1909. //-----------------------------------------------------------------------------
  1910. // Purpose: Scrolls the list according to the mouse wheel movement
  1911. //-----------------------------------------------------------------------------
  1912. void TreeView::OnMouseWheeled(int delta)
  1913. {
  1914. if ( !m_pVertScrollBar->IsVisible() )
  1915. {
  1916. return;
  1917. }
  1918. int val = m_pVertScrollBar->GetValue();
  1919. val -= (delta * 3);
  1920. m_pVertScrollBar->SetValue(val);
  1921. }
  1922. //-----------------------------------------------------------------------------
  1923. // Purpose:
  1924. //-----------------------------------------------------------------------------
  1925. void TreeView::OnSizeChanged(int wide, int tall)
  1926. {
  1927. BaseClass::OnSizeChanged(wide, tall);
  1928. InvalidateLayout();
  1929. Repaint();
  1930. }
  1931. void TreeView::GetScrollBarSize( bool vertical, int& w, int& h )
  1932. {
  1933. int idx = vertical ? 0 : 1;
  1934. if ( m_bScrollbarExternal[ idx ] )
  1935. {
  1936. w = h = 0;
  1937. return;
  1938. }
  1939. if ( vertical )
  1940. {
  1941. m_pVertScrollBar->GetSize( w, h );
  1942. }
  1943. else
  1944. {
  1945. m_pHorzScrollBar->GetSize( w, h );
  1946. }
  1947. }
  1948. //-----------------------------------------------------------------------------
  1949. // Purpose:
  1950. //-----------------------------------------------------------------------------
  1951. void TreeView::PerformLayout()
  1952. {
  1953. int wide, tall;
  1954. GetSize( wide, tall );
  1955. if ( !m_pRootNode )
  1956. {
  1957. m_pSubPanel->SetSize( wide, tall );
  1958. return;
  1959. }
  1960. int sbhw, sbhh;
  1961. GetScrollBarSize( false, sbhw, sbhh );
  1962. int sbvw, sbvh;
  1963. GetScrollBarSize( true, sbvw, sbvh );
  1964. bool vbarNeeded = false;
  1965. bool hbarNeeded = false;
  1966. // okay we have to check if we need either scroll bars, since if we need one
  1967. // it might make it necessary to have the other one
  1968. int nodesVisible = tall / m_nRowHeight;
  1969. // count the number of visible items
  1970. int visibleItemCount = m_pRootNode->CountVisibleNodes();
  1971. int maxWidth = m_pRootNode->GetVisibleMaxWidth() + 10; // 10 pixel buffer
  1972. vbarNeeded = visibleItemCount > nodesVisible;
  1973. if (!vbarNeeded)
  1974. {
  1975. if (maxWidth > wide)
  1976. {
  1977. hbarNeeded = true;
  1978. // recalculate if vbar is needed now
  1979. // double check that we really don't need it
  1980. nodesVisible = (tall - sbhh) / m_nRowHeight;
  1981. vbarNeeded = visibleItemCount > nodesVisible;
  1982. }
  1983. }
  1984. else
  1985. {
  1986. // we've got the vertical bar here, so shrink the width
  1987. hbarNeeded = maxWidth > (wide - (sbvw+2));
  1988. if (hbarNeeded)
  1989. {
  1990. nodesVisible = (tall - sbhh) / m_nRowHeight;
  1991. }
  1992. }
  1993. int subPanelWidth = wide;
  1994. int subPanelHeight = tall;
  1995. int vbarPos = 0;
  1996. if (vbarNeeded)
  1997. {
  1998. subPanelWidth -= (sbvw + 2);
  1999. int barSize = tall;
  2000. if (hbarNeeded)
  2001. {
  2002. barSize -= sbhh;
  2003. }
  2004. //!! need to make it recalculate scroll positions
  2005. m_pVertScrollBar->SetVisible(true);
  2006. m_pVertScrollBar->SetEnabled(false);
  2007. m_pVertScrollBar->SetRangeWindow( nodesVisible );
  2008. m_pVertScrollBar->SetRange( 0, visibleItemCount);
  2009. m_pVertScrollBar->SetButtonPressedScrollValue( 1 );
  2010. if ( !m_bScrollbarExternal[ 0 ] )
  2011. {
  2012. m_pVertScrollBar->SetPos(wide - (sbvw + WINDOW_BORDER_WIDTH), 0);
  2013. m_pVertScrollBar->SetSize(sbvw, barSize - 2);
  2014. }
  2015. // need to figure out
  2016. vbarPos = m_pVertScrollBar->GetValue();
  2017. }
  2018. else
  2019. {
  2020. m_pVertScrollBar->SetVisible(false);
  2021. m_pVertScrollBar->SetValue( 0 );
  2022. }
  2023. int hbarPos = 0;
  2024. if (hbarNeeded)
  2025. {
  2026. subPanelHeight -= (sbhh + 2);
  2027. int barSize = wide;
  2028. if (vbarNeeded)
  2029. {
  2030. barSize -= sbvw;
  2031. }
  2032. m_pHorzScrollBar->SetVisible(true);
  2033. m_pHorzScrollBar->SetEnabled(false);
  2034. m_pHorzScrollBar->SetRangeWindow( barSize );
  2035. m_pHorzScrollBar->SetRange( 0, maxWidth);
  2036. m_pHorzScrollBar->SetButtonPressedScrollValue( 10 );
  2037. if ( !m_bScrollbarExternal[ 1 ] )
  2038. {
  2039. m_pHorzScrollBar->SetPos(0, tall - (sbhh + WINDOW_BORDER_WIDTH));
  2040. m_pHorzScrollBar->SetSize(barSize - 2, sbhh);
  2041. }
  2042. hbarPos = m_pHorzScrollBar->GetValue();
  2043. }
  2044. else
  2045. {
  2046. m_pHorzScrollBar->SetVisible(false);
  2047. m_pHorzScrollBar->SetValue( 0 );
  2048. }
  2049. m_pSubPanel->SetSize(subPanelWidth, subPanelHeight);
  2050. int y = 0;
  2051. m_pRootNode->PositionAndSetVisibleNodes(vbarPos, visibleItemCount, -hbarPos, y);
  2052. Repaint();
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. // Purpose:
  2056. //-----------------------------------------------------------------------------
  2057. void TreeView::MakeItemVisible(int itemIndex)
  2058. {
  2059. // first make sure that all parents are expanded
  2060. TreeNode *pNode = m_NodeList[itemIndex];
  2061. TreeNode *pParent = pNode->GetParentNode();
  2062. while (pParent)
  2063. {
  2064. if (!pParent->m_bExpand)
  2065. {
  2066. pParent->SetNodeExpanded(true);
  2067. }
  2068. pParent = pParent->GetParentNode();
  2069. }
  2070. // recalculate scroll bar due to possible exapnsion
  2071. PerformLayout();
  2072. if (!m_pVertScrollBar->IsVisible())
  2073. return;
  2074. int visibleIndex = pNode->CountVisibleIndex()-1;
  2075. int range = m_pVertScrollBar->GetRangeWindow();
  2076. int vbarPos = m_pVertScrollBar->GetValue();
  2077. // do we need to scroll up or down?
  2078. if (visibleIndex < vbarPos)
  2079. {
  2080. m_pVertScrollBar->SetValue(visibleIndex);
  2081. }
  2082. else if (visibleIndex+1 > vbarPos+range)
  2083. {
  2084. m_pVertScrollBar->SetValue(visibleIndex+1-range);
  2085. }
  2086. InvalidateLayout();
  2087. }
  2088. void TreeView::GetVBarInfo( int &top, int &nItemsVisible, bool& hbarVisible )
  2089. {
  2090. int wide, tall;
  2091. GetSize( wide, tall );
  2092. nItemsVisible = tall / m_nRowHeight;
  2093. if ( m_pVertScrollBar->IsVisible() )
  2094. {
  2095. top = m_pVertScrollBar->GetValue();
  2096. }
  2097. else
  2098. {
  2099. top = 0;
  2100. }
  2101. hbarVisible = m_pHorzScrollBar->IsVisible();
  2102. }
  2103. //-----------------------------------------------------------------------------
  2104. // Purpose:
  2105. //-----------------------------------------------------------------------------
  2106. void TreeView::ApplySchemeSettings(IScheme *pScheme)
  2107. {
  2108. BaseClass::ApplySchemeSettings(pScheme);
  2109. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  2110. SetBgColor(GetSchemeColor("TreeView.BgColor", GetSchemeColor("WindowDisabledBgColor", pScheme), pScheme));
  2111. SetFont( pScheme->GetFont( "Default", IsProportional() ) );
  2112. m_pSubPanel->SetBgColor( GetBgColor() );
  2113. }
  2114. //-----------------------------------------------------------------------------
  2115. // Purpose:
  2116. //-----------------------------------------------------------------------------
  2117. void TreeView::SetBgColor( Color color )
  2118. {
  2119. BaseClass::SetBgColor( color );
  2120. m_pSubPanel->SetBgColor( color );
  2121. }
  2122. //-----------------------------------------------------------------------------
  2123. // Purpose:
  2124. //-----------------------------------------------------------------------------
  2125. void TreeView::OnSliderMoved( int position )
  2126. {
  2127. InvalidateLayout();
  2128. Repaint();
  2129. }
  2130. void TreeView::GenerateDragDataForItem( int itemIndex, KeyValues *msg )
  2131. {
  2132. // Implemented by subclassed TreeView
  2133. }
  2134. void TreeView::SetDragEnabledItems( bool state )
  2135. {
  2136. m_bDragEnabledItems = state;
  2137. }
  2138. void TreeView::OnLabelChanged( int itemIndex, char const *oldString, char const *newString )
  2139. {
  2140. }
  2141. bool TreeView::IsLabelEditingAllowed() const
  2142. {
  2143. return m_bAllowLabelEditing;
  2144. }
  2145. void TreeView::SetLabelBeingEdited( bool state )
  2146. {
  2147. m_bLabelBeingEdited = state;
  2148. }
  2149. bool TreeView::IsLabelBeingEdited() const
  2150. {
  2151. return m_bLabelBeingEdited;
  2152. }
  2153. void TreeView::SetAllowLabelEditing( bool state )
  2154. {
  2155. m_bAllowLabelEditing = state;
  2156. }
  2157. void TreeView::EnableExpandTreeOnLeftClick( bool bEnable )
  2158. {
  2159. m_bLeftClickExpandsTree = bEnable;
  2160. }
  2161. int TreeView::FindItemUnderMouse( int mx, int my )
  2162. {
  2163. mx = clamp( mx, 0, GetWide() - 1 );
  2164. my = clamp( my, 0, GetTall() - 1 );
  2165. if ( mx >= TREE_INDENT_AMOUNT )
  2166. {
  2167. // Find what's under this position
  2168. // need to figure out
  2169. int vbarPos = m_pVertScrollBar->IsVisible() ? m_pVertScrollBar->GetValue() : 0;
  2170. int hbarPos = m_pHorzScrollBar->IsVisible() ? m_pHorzScrollBar->GetValue() : 0;
  2171. int count = m_pRootNode->CountVisibleNodes();
  2172. int y = 0;
  2173. TreeNode *item = m_pRootNode->FindItemUnderMouse( vbarPos, count, -hbarPos, y, mx, my );
  2174. if ( item )
  2175. {
  2176. return item->m_ItemIndex;
  2177. }
  2178. }
  2179. return -1;
  2180. }
  2181. void TreeView::OnMousePressed( MouseCode code )
  2182. {
  2183. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  2184. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  2185. // Try to map mouse position to a row
  2186. if ( code == MOUSE_LEFT && m_pRootNode )
  2187. {
  2188. int mx, my;
  2189. input()->GetCursorPos( mx, my );
  2190. ScreenToLocal( mx, my );
  2191. if ( mx >= TREE_INDENT_AMOUNT )
  2192. {
  2193. // Find what's under this position
  2194. // need to figure out
  2195. int vbarPos = m_pVertScrollBar->IsVisible() ? m_pVertScrollBar->GetValue() : 0;
  2196. int hbarPos = m_pHorzScrollBar->IsVisible() ? m_pHorzScrollBar->GetValue() : 0;
  2197. int count = m_pRootNode->CountVisibleNodes();
  2198. int y = 0;
  2199. TreeNode *item = m_pRootNode->FindItemUnderMouse( vbarPos, count, -hbarPos, y, mx, my );
  2200. if ( item )
  2201. {
  2202. if ( !item->IsSelected() )
  2203. {
  2204. AddSelectedItem( item->m_ItemIndex, !ctrl && !shift );
  2205. }
  2206. return;
  2207. }
  2208. else
  2209. {
  2210. ClearSelection();
  2211. }
  2212. }
  2213. }
  2214. BaseClass::OnMousePressed( code );
  2215. }
  2216. //-----------------------------------------------------------------------------
  2217. // Purpose:
  2218. // Input : state -
  2219. //-----------------------------------------------------------------------------
  2220. void TreeView::SetAllowMultipleSelections( bool state )
  2221. {
  2222. m_bAllowMultipleSelections = state;
  2223. }
  2224. //-----------------------------------------------------------------------------
  2225. // Purpose:
  2226. // Input : -
  2227. // Output : Returns true on success, false on failure.
  2228. //-----------------------------------------------------------------------------
  2229. bool TreeView::IsMultipleSelectionAllowed() const
  2230. {
  2231. return m_bAllowMultipleSelections;
  2232. }
  2233. //-----------------------------------------------------------------------------
  2234. // Purpose:
  2235. // Input : -
  2236. // Output : int
  2237. //-----------------------------------------------------------------------------
  2238. int TreeView::GetSelectedItemCount() const
  2239. {
  2240. return m_SelectedItems.Count();
  2241. }
  2242. //-----------------------------------------------------------------------------
  2243. // Purpose:
  2244. // Input : -
  2245. //-----------------------------------------------------------------------------
  2246. void TreeView::ClearSelection()
  2247. {
  2248. m_SelectedItems.RemoveAll();
  2249. m_nMostRecentlySelectedItem = -1;
  2250. PostActionSignal( new KeyValues( "TreeViewItemSelectionCleared" ) );
  2251. }
  2252. void TreeView::RangeSelectItems( int endItem )
  2253. {
  2254. int startItem = m_nMostRecentlySelectedItem;
  2255. ClearSelection();
  2256. m_nMostRecentlySelectedItem = startItem;
  2257. if ( !m_NodeList.IsValidIndex( startItem ) )
  2258. {
  2259. AddSelectedItem( endItem, false );
  2260. return;
  2261. }
  2262. Assert( m_NodeList.IsValidIndex( endItem ) );
  2263. if ( !m_pRootNode )
  2264. {
  2265. return;
  2266. }
  2267. CUtlVector< TreeNode * > list;
  2268. m_pRootNode->FindNodesInRange( list, startItem, endItem );
  2269. int c = list.Count();
  2270. for ( int i = 0; i < c; ++i )
  2271. {
  2272. TreeNode *item = list[ i ];
  2273. AddSelectedItem( item->m_ItemIndex, false );
  2274. }
  2275. }
  2276. void TreeView::FindNodesInRange( int startItem, int endItem, CUtlVector< int >& itemIndices )
  2277. {
  2278. CUtlVector< TreeNode * > nodes;
  2279. m_pRootNode->FindNodesInRange( nodes, startItem, endItem );
  2280. int c = nodes.Count();
  2281. for ( int i = 0; i < c; ++i )
  2282. {
  2283. TreeNode *item = nodes[ i ];
  2284. itemIndices.AddToTail( item->m_ItemIndex );
  2285. }
  2286. }
  2287. void TreeView::RemoveSelectedItem( int itemIndex )
  2288. {
  2289. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2290. return;
  2291. TreeNode *sel = m_NodeList[ itemIndex ];
  2292. Assert( sel );
  2293. int slot = m_SelectedItems.Find( sel );
  2294. if ( slot != m_SelectedItems.InvalidIndex() )
  2295. {
  2296. m_SelectedItems.Remove( slot );
  2297. PostActionSignal( new KeyValues( "TreeViewItemDeselected", "itemIndex", itemIndex ) );
  2298. m_nMostRecentlySelectedItem = itemIndex;
  2299. }
  2300. }
  2301. //-----------------------------------------------------------------------------
  2302. // Purpose:
  2303. //-----------------------------------------------------------------------------
  2304. void TreeView::AddSelectedItem( int itemIndex, bool clearCurrentSelection, bool requestFocus /* = true */, bool bMakeItemVisible /*= true*/ )
  2305. {
  2306. if ( clearCurrentSelection )
  2307. {
  2308. ClearSelection();
  2309. }
  2310. // Assume it's bogus
  2311. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2312. return;
  2313. TreeNode *sel = m_NodeList[ itemIndex ];
  2314. Assert( sel );
  2315. if ( requestFocus )
  2316. {
  2317. sel->RequestFocus();
  2318. }
  2319. // Item 0 is most recently selected!!!
  2320. int slot = m_SelectedItems.Find( sel );
  2321. if ( slot == m_SelectedItems.InvalidIndex() )
  2322. {
  2323. m_SelectedItems.AddToHead( sel );
  2324. }
  2325. else if ( slot != 0 )
  2326. {
  2327. m_SelectedItems.Remove( slot );
  2328. m_SelectedItems.AddToHead( sel );
  2329. }
  2330. if ( bMakeItemVisible )
  2331. {
  2332. MakeItemVisible( itemIndex );
  2333. }
  2334. PostActionSignal( new KeyValues( "TreeViewItemSelected", "itemIndex", itemIndex ) );
  2335. InvalidateLayout();
  2336. if ( clearCurrentSelection )
  2337. {
  2338. m_nMostRecentlySelectedItem = itemIndex;
  2339. }
  2340. }
  2341. //-----------------------------------------------------------------------------
  2342. // Purpose:
  2343. // Input : -
  2344. // Output : int
  2345. //-----------------------------------------------------------------------------
  2346. int TreeView::GetFirstSelectedItem() const
  2347. {
  2348. if ( m_SelectedItems.Count() <= 0 )
  2349. return -1;
  2350. return m_SelectedItems[ 0 ]->m_ItemIndex;
  2351. }
  2352. //-----------------------------------------------------------------------------
  2353. // Purpose:
  2354. // Input : itemIndex -
  2355. // Output : Returns true on success, false on failure.
  2356. //-----------------------------------------------------------------------------
  2357. bool TreeView::IsItemSelected( int itemIndex )
  2358. {
  2359. // Assume it's bogus
  2360. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2361. return false;
  2362. TreeNode *sel = m_NodeList[ itemIndex ];
  2363. return m_SelectedItems.Find( sel ) != m_SelectedItems.InvalidIndex();
  2364. }
  2365. void TreeView::SetLabelEditingAllowed( int itemIndex, bool state )
  2366. {
  2367. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2368. return;
  2369. TreeNode *sel = m_NodeList[ itemIndex ];
  2370. sel->SetLabelEditingAllowed( state );
  2371. }
  2372. void TreeView::StartEditingLabel( int itemIndex )
  2373. {
  2374. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2375. return;
  2376. Assert( IsLabelEditingAllowed() );
  2377. TreeNode *sel = m_NodeList[ itemIndex ];
  2378. Assert( sel->IsLabelEditingAllowed() );
  2379. if ( !sel->IsLabelEditingAllowed() )
  2380. return;
  2381. sel->EditLabel();
  2382. }
  2383. int TreeView::GetPrevChildItemIndex( int itemIndex )
  2384. {
  2385. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2386. return -1;
  2387. TreeNode *sel = m_NodeList[ itemIndex ];
  2388. TreeNode *parent = sel->GetParentNode();
  2389. if ( !parent )
  2390. return -1;
  2391. return parent->GetPrevChildItemIndex( sel );
  2392. }
  2393. int TreeView::GetNextChildItemIndex( int itemIndex )
  2394. {
  2395. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2396. return -1;
  2397. TreeNode *sel = m_NodeList[ itemIndex ];
  2398. TreeNode *parent = sel->GetParentNode();
  2399. if ( !parent )
  2400. return -1;
  2401. return parent->GetNextChildItemIndex( sel );
  2402. }
  2403. bool TreeView::IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist )
  2404. {
  2405. // Derived classes should implement
  2406. return false;
  2407. }
  2408. void TreeView::OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist )
  2409. {
  2410. }
  2411. bool TreeView::GetItemDropContextMenu( int itemIndex, Menu *menu, CUtlVector< KeyValues * >& msglist )
  2412. {
  2413. return false;
  2414. }
  2415. HCursor TreeView::GetItemDropCursor( int itemIndex, CUtlVector< KeyValues * >& msglist )
  2416. {
  2417. return dc_arrow;
  2418. }
  2419. void TreeView::RemoveChildrenOfNode( int itemIndex )
  2420. {
  2421. if ( !m_NodeList.IsValidIndex( itemIndex ) )
  2422. return;
  2423. TreeNode *node = m_NodeList[ itemIndex ];
  2424. node->RemoveChildren();
  2425. }
  2426. ScrollBar *TreeView::SetScrollBarExternal( bool vertical, Panel *newParent )
  2427. {
  2428. if ( vertical )
  2429. {
  2430. m_bScrollbarExternal[ 0 ] = true;
  2431. m_pVertScrollBar->SetParent( newParent );
  2432. return m_pVertScrollBar;
  2433. }
  2434. m_bScrollbarExternal[ 1 ] = true;
  2435. m_pHorzScrollBar->SetParent( newParent );
  2436. return m_pHorzScrollBar;
  2437. }
  2438. // if this is set, then clicking on one row and dragging will select a run or items, etc.
  2439. void TreeView::SetMultipleItemDragEnabled( bool state )
  2440. {
  2441. m_bMultipleItemDragging = state;
  2442. }
  2443. bool TreeView::IsMultipleItemDragEnabled() const
  2444. {
  2445. return m_bMultipleItemDragging;
  2446. }
  2447. void TreeView::SelectAll()
  2448. {
  2449. m_SelectedItems.RemoveAll();
  2450. FOR_EACH_LL( m_NodeList, i )
  2451. {
  2452. m_SelectedItems.AddToTail( m_NodeList[ i ] );
  2453. }
  2454. PostActionSignal( new KeyValues( "TreeViewItemSelected", "itemIndex", GetRootItemIndex() ) );
  2455. InvalidateLayout();
  2456. }