Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3097 lines
73 KiB

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