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.

855 lines
28 KiB

  1. //====== Copyright � 1996-2008, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Implementation of the CDmeControlGroup class. The CDmeControlGroup
  4. // class provides hierarchical grouping of animation controls and used for
  5. // selection of the animation set controls.
  6. //
  7. //=============================================================================
  8. #include "movieobjects/dmecontrolgroup.h"
  9. #include "movieobjects/dmetransform.h"
  10. #include "movieobjects/dmetransformcontrol.h"
  11. #include "movieobjects/dmeanimationset.h"
  12. #include "datamodel/dmelementfactoryhelper.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-------------------------------------------------------------------------------------------------
  16. // Expose this class to the scene database
  17. //-------------------------------------------------------------------------------------------------
  18. IMPLEMENT_ELEMENT_FACTORY( DmeControlGroup, CDmeControlGroup );
  19. //-------------------------------------------------------------------------------------------------
  20. // Purpose: Provide post construction processing.
  21. //-------------------------------------------------------------------------------------------------
  22. void CDmeControlGroup::OnConstruction()
  23. {
  24. m_Children.Init( this, "children" );
  25. m_Controls.Init( this, "controls" );
  26. m_GroupColor.InitAndSet( this, "groupColor", Color( 200, 200, 200, 255 ) );
  27. m_ControlColor.InitAndSet( this, "controlColor", Color( 200, 200, 200, 255 ) );
  28. m_Visible.InitAndSet( this, "visible", true );
  29. m_Selectable.InitAndSet( this, "selectable", true );
  30. m_Snappable.InitAndSet( this, "snappable", true );
  31. }
  32. //-------------------------------------------------------------------------------------------------
  33. // Purpose: Provide processing and cleanup before shutdown
  34. //-------------------------------------------------------------------------------------------------
  35. void CDmeControlGroup::OnDestruction()
  36. {
  37. }
  38. //-------------------------------------------------------------------------------------------------
  39. // Purpose: Add a the provided control to the group, if the control is currently in another group
  40. // it will be removed from the other group first.
  41. //-------------------------------------------------------------------------------------------------
  42. void CDmeControlGroup::AddControl( CDmElement *pControl, const CDmElement *pInsertBeforeControl )
  43. {
  44. if ( pControl == NULL )
  45. return;
  46. // Remove the control from any group it is currently in.
  47. CDmeControlGroup *pCurrentGroup = FindGroupContainingControl( pControl );
  48. if ( pCurrentGroup )
  49. {
  50. pCurrentGroup->RemoveControl( pControl );
  51. }
  52. // If a insert location control was specified find it in the list of controls
  53. int nInsertLocation = m_Controls.InvalidIndex();
  54. if ( pInsertBeforeControl )
  55. {
  56. nInsertLocation = m_Controls.Find( pInsertBeforeControl );
  57. }
  58. // Add the control to the group
  59. if ( nInsertLocation != m_Controls.InvalidIndex() )
  60. {
  61. m_Controls.InsertBefore( nInsertLocation, pControl );
  62. }
  63. else
  64. {
  65. m_Controls.AddToTail( pControl );
  66. }
  67. }
  68. //-------------------------------------------------------------------------------------------------
  69. // Purpose: Remove a control from the group. This will only search the immediate group for the
  70. // specified control and remove it. It will not remove the control if it is in a child of this
  71. // group. Returns false if the control was not found.
  72. //-------------------------------------------------------------------------------------------------
  73. bool CDmeControlGroup::RemoveControl( const CDmElement *pControl )
  74. {
  75. if ( pControl == NULL )
  76. return false;
  77. int nControls = m_Controls.Count();
  78. for ( int iControl = 0; iControl < nControls; ++iControl )
  79. {
  80. if ( pControl == m_Controls[ iControl ] )
  81. {
  82. m_Controls.Remove( iControl );
  83. return true;
  84. }
  85. }
  86. return false;
  87. }
  88. //-------------------------------------------------------------------------------------------------
  89. // Purpose: Get a flat list of all of the controls in the group. If the recursive flag is true
  90. // a flat list of all of the controls in the entire sub-tree of the group will be returned. If
  91. // the recursive flag is false on
  92. //-------------------------------------------------------------------------------------------------
  93. void CDmeControlGroup::GetControlsInGroup( CUtlVector< CDmElement* > &controlList, bool recursive ) const
  94. {
  95. // If the recursive flag is set add all of the controls
  96. // of the entire tree of each child group within the group.
  97. if ( recursive )
  98. {
  99. int nChildren = m_Children.Count();
  100. for ( int iChild = 0; iChild < nChildren; ++iChild )
  101. {
  102. CDmeControlGroup *pChild = m_Children[ iChild ];
  103. if ( pChild )
  104. {
  105. pChild->GetControlsInGroup( controlList, true );
  106. }
  107. }
  108. }
  109. // Add the controls from this group.
  110. int nControls = m_Controls.Count();
  111. for ( int iControl = 0; iControl < nControls; ++iControl )
  112. {
  113. CDmElement *pControl = m_Controls[ iControl ];
  114. if ( pControl )
  115. {
  116. controlList.AddToTail( pControl );
  117. }
  118. }
  119. }
  120. //-------------------------------------------------------------------------------------------------
  121. // Purpose: Find a control with the specified name within the group. If the recursive flag is true
  122. // the entire sub-tree of the group will be searched, otherwise only the immediate control will
  123. // be searched for the group. If the parent group pointer is provided it will be returned with the
  124. // group to which the control belongs directly.
  125. //-------------------------------------------------------------------------------------------------
  126. CDmElement *CDmeControlGroup::FindControlByName( const char *pchName, bool recursive, CDmeControlGroup **pParentGroup )
  127. {
  128. // Search the controls contained directly by the group for one with the specified name.
  129. int nControls = m_Controls.Count();
  130. for ( int iControl = 0; iControl < nControls; ++iControl )
  131. {
  132. CDmElement *pControl = m_Controls[ iControl ];
  133. if ( pControl )
  134. {
  135. if ( V_stricmp( pControl->GetName(), pchName ) == 0 )
  136. {
  137. if ( pParentGroup )
  138. {
  139. *pParentGroup = this;
  140. }
  141. return pControl;
  142. }
  143. }
  144. }
  145. // If the control was not found in the controls contained directly by the group
  146. // search the children and their sub-trees if the recursive flag is true.
  147. if ( recursive )
  148. {
  149. int nChildren = m_Children.Count();
  150. for ( int iChild = 0; iChild < nChildren; ++iChild )
  151. {
  152. CDmeControlGroup *pChild = m_Children[ iChild ];
  153. if ( pChild )
  154. {
  155. CDmElement *pControl = pChild->FindControlByName( pchName, true, pParentGroup );
  156. if ( pControl )
  157. return pControl;
  158. }
  159. }
  160. }
  161. return NULL;
  162. }
  163. //-------------------------------------------------------------------------------------------------
  164. // Purpose: Find the group to which the specified control belongs, if any. This function searches
  165. // for any control groups which reference the specified control. It simply returns the first one
  166. // it finds, as a control should only every belong to a single control group.
  167. //-------------------------------------------------------------------------------------------------
  168. CDmeControlGroup *CDmeControlGroup::FindGroupContainingControl( const CDmElement* pControl )
  169. {
  170. return FindReferringElement< CDmeControlGroup >( pControl, "controls" );
  171. }
  172. //-------------------------------------------------------------------------------------------------
  173. // Purpose: Make the specified group a child of this group. The group will be removed from the
  174. // child list of any other group to which it may currently belong.
  175. //-------------------------------------------------------------------------------------------------
  176. void CDmeControlGroup::AddChild( CDmeControlGroup *pGroup, const CDmeControlGroup *pInsertBeforeGroup )
  177. {
  178. // Can't make a group its own child
  179. Assert( pGroup != this );
  180. if ( pGroup == this )
  181. return;
  182. // Remove the group from its current control group if it belongs one.
  183. CDmeControlGroup *pParentGroup = pGroup->FindParent();
  184. if ( pParentGroup )
  185. {
  186. pParentGroup->RemoveChild( pGroup );
  187. }
  188. // If a insert location group was specified find it in the list of children
  189. int nInsertLocation = m_Children.InvalidIndex();
  190. if ( pInsertBeforeGroup )
  191. {
  192. nInsertLocation = m_Children.Find( pInsertBeforeGroup );
  193. }
  194. // Add the specified group as child of this group.
  195. if ( nInsertLocation != m_Children.InvalidIndex() )
  196. {
  197. m_Children.InsertBefore( nInsertLocation, pGroup );
  198. }
  199. else
  200. {
  201. m_Children.AddToTail( pGroup );
  202. }
  203. }
  204. //-------------------------------------------------------------------------------------------------
  205. // Purpose: Remove the specified child group. Searches the immediate children of the node for the
  206. // specified group and removes it from the child list if the group is found. Returns true if the
  207. // group is found, false if the group is not found.
  208. //-------------------------------------------------------------------------------------------------
  209. bool CDmeControlGroup::RemoveChild( const CDmeControlGroup *pGroup )
  210. {
  211. int nChildren = m_Children.Count();
  212. for ( int iChild = 0; iChild < nChildren; ++iChild )
  213. {
  214. if ( m_Children[ iChild ] == pGroup )
  215. {
  216. m_Children.Remove( iChild );
  217. return true;
  218. }
  219. }
  220. return false;
  221. }
  222. //-------------------------------------------------------------------------------------------------
  223. // Purpose: Move the specified child group to the top of the list
  224. //-------------------------------------------------------------------------------------------------
  225. void CDmeControlGroup::MoveChildToTop( const CDmeControlGroup *pGroup )
  226. {
  227. // Make sure the group is actually a child, and move it
  228. // to the top of the list if it is not already there.
  229. int nChildren = m_Children.Count();
  230. for ( int iChild = 1; iChild < nChildren; ++iChild )
  231. {
  232. if ( m_Children[ iChild ] == pGroup )
  233. {
  234. CDmeControlGroup *pChild = m_Children[ iChild ];
  235. m_Children.Remove( iChild );
  236. m_Children.InsertBefore( 0, pChild );
  237. break;
  238. }
  239. }
  240. }
  241. //-------------------------------------------------------------------------------------------------
  242. // Purpose: Move the specified child group to the bottom of the list
  243. //-------------------------------------------------------------------------------------------------
  244. void CDmeControlGroup::MoveChildToBottom( const CDmeControlGroup *pGroup )
  245. {
  246. // Make sure the group is actually a child, and move it
  247. // to the bottom of the list if it is not already there.
  248. int nChildren = m_Children.Count();
  249. for ( int iChild = 0; iChild < (nChildren - 1); ++iChild )
  250. {
  251. if ( m_Children[ iChild ] == pGroup )
  252. {
  253. CDmeControlGroup *pChild = m_Children[ iChild ];
  254. m_Children.Remove( iChild );
  255. m_Children.AddToTail( pChild );
  256. break;
  257. }
  258. }
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Compare the two groups by name for an ascending sort
  262. //-----------------------------------------------------------------------------
  263. int CDmeControlGroup::CompareByNameAscending( CDmeControlGroup * const *pGroupA, CDmeControlGroup * const *pGroupB )
  264. {
  265. return V_stricmp( (*pGroupA)->GetName(), (*pGroupB)->GetName() );
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Compare the two groups by name for a descending sort
  269. //-----------------------------------------------------------------------------
  270. int CDmeControlGroup::CompareByNameDecending( CDmeControlGroup * const *pGroupA, CDmeControlGroup * const *pGroupB )
  271. {
  272. return V_stricmp( (*pGroupB)->GetName(), (*pGroupA)->GetName() );
  273. }
  274. //-------------------------------------------------------------------------------------------------
  275. // Sore the children by name
  276. //-------------------------------------------------------------------------------------------------
  277. void CDmeControlGroup::SortChildrenByName( bool bAscending )
  278. {
  279. // Copy the children into a temporary array to be sorted.
  280. int nNumChildren = m_Children.Count();
  281. CUtlVector< CDmeControlGroup * > sortedList( 0, nNumChildren );
  282. for ( int iChild = 0; iChild < nNumChildren; ++iChild )
  283. {
  284. CDmeControlGroup *pGroup = m_Children[ iChild ];
  285. if ( pGroup )
  286. {
  287. sortedList.AddToTail( pGroup );
  288. }
  289. }
  290. // Sort the temporary array in ascending or descending order
  291. if ( bAscending )
  292. {
  293. sortedList.Sort( CompareByNameAscending );
  294. }
  295. else
  296. {
  297. sortedList.Sort( CompareByNameDecending );
  298. }
  299. // Remove all of the children from the original list and then add them back in sorted order
  300. m_Children.RemoveAll();
  301. int nNumSorted = sortedList.Count();
  302. for ( int iChild = 0; iChild < nNumSorted; ++iChild )
  303. {
  304. CDmeControlGroup *pGroup = sortedList[ iChild ];
  305. if ( pGroup )
  306. {
  307. m_Children.AddToTail( pGroup );
  308. }
  309. }
  310. }
  311. //-------------------------------------------------------------------------------------------------
  312. // Determine if the group has child of the specified name
  313. //-------------------------------------------------------------------------------------------------
  314. bool CDmeControlGroup::HasChildGroup( const char *pchName, bool recursive )
  315. {
  316. if ( FindChildByName( pchName, recursive ) == NULL )
  317. return false;
  318. return true;
  319. }
  320. //-------------------------------------------------------------------------------------------------
  321. // Purpose: Find the child group with the specified name. If the recursive flag is true the entire
  322. // sub-tree of the group will be searched, otherwise only the immediate children of the group will
  323. // be searched for the specified child. If a parent group pointer is provided it will be returned
  324. // with the immediate parent in which the child was located.
  325. //-------------------------------------------------------------------------------------------------
  326. CDmeControlGroup *CDmeControlGroup::FindChildByName( const char *pchName, bool recursive, CDmeControlGroup **pParentGroup )
  327. {
  328. // Search the immediate children for a group with the specified name.
  329. int nChildren = m_Children.Count();
  330. for ( int iChild = 0; iChild < nChildren; ++iChild )
  331. {
  332. CDmeControlGroup *pChild = m_Children[ iChild ];
  333. if ( pChild )
  334. {
  335. if ( V_stricmp( pChild->GetName(), pchName ) == 0 )
  336. {
  337. if ( pParentGroup )
  338. {
  339. *pParentGroup = this;
  340. }
  341. return pChild;
  342. }
  343. }
  344. }
  345. // If the group was not found in the immediate children of the current group and the recursive
  346. // flag is set, search the sub-trees of all the children for the specified group.
  347. if ( recursive )
  348. {
  349. for ( int iChild = 0; iChild < nChildren; ++iChild )
  350. {
  351. CDmeControlGroup *pChild = m_Children[ iChild ];
  352. if ( pChild )
  353. {
  354. CDmeControlGroup *pGroup = pChild->FindChildByName( pchName, true, pParentGroup );
  355. if ( pGroup )
  356. return pGroup;
  357. }
  358. }
  359. }
  360. return NULL;
  361. }
  362. //-------------------------------------------------------------------------------------------------
  363. // Purpose: Find the parent of the group. Searches for groups which reference this group as a
  364. // child. Each group is allowed to be the child of only one group, so the first group found is
  365. // returned.
  366. //-------------------------------------------------------------------------------------------------
  367. CDmeControlGroup *CDmeControlGroup::FindParent() const
  368. {
  369. const static CUtlSymbolLarge symChildren = g_pDataModel->GetSymbol( "children" );
  370. CDmeControlGroup *pParent = FindReferringElement< CDmeControlGroup >( this, symChildren );
  371. return pParent;
  372. }
  373. //-------------------------------------------------------------------------------------------------
  374. // Determine if this group is an ancestor of the specified group
  375. //-------------------------------------------------------------------------------------------------
  376. bool CDmeControlGroup::IsAncestorOfGroup( const CDmeControlGroup *pGroup ) const
  377. {
  378. if ( pGroup == NULL )
  379. return false;
  380. const CDmeControlGroup *pCurrentGroup = pGroup;
  381. const CDmeControlGroup *pParent = pGroup->FindParent();
  382. while ( pParent )
  383. {
  384. if ( pParent == this )
  385. return true;
  386. pCurrentGroup = pParent;
  387. pParent = pParent->FindParent();
  388. Assert( pCurrentGroup != pParent );
  389. if ( pCurrentGroup == pParent )
  390. break;
  391. }
  392. return false;
  393. }
  394. //-------------------------------------------------------------------------------------------------
  395. // Create a control group with the provided name and add it to the specified parent. If a child of
  396. // the specified name already exists it will be returned and no new group will be created.
  397. //-------------------------------------------------------------------------------------------------
  398. CDmeControlGroup *CDmeControlGroup::CreateControlGroup( const char *pchName )
  399. {
  400. CDmeControlGroup *pExistingGroup = FindChildByName( pchName, false );
  401. if ( pExistingGroup )
  402. return pExistingGroup;
  403. // Create the new control group with the specified name
  404. CDmeControlGroup *pNewGroup = CreateElement< CDmeControlGroup >( pchName, GetFileId() );
  405. // Add the group to as a child of this group
  406. AddChild( pNewGroup );
  407. return pNewGroup;
  408. }
  409. //-------------------------------------------------------------------------------------------------
  410. // Purpose: Get a flat list of all of the groups in sub-tree of the group
  411. //-------------------------------------------------------------------------------------------------
  412. void CDmeControlGroup::GetAllChildren( CUtlVector< DmElementHandle_t > &childGroupList ) const
  413. {
  414. int nChildren = m_Children.Count();
  415. for ( int iChild = 0; iChild < nChildren; ++iChild )
  416. {
  417. CDmeControlGroup *pChild = m_Children[ iChild ];
  418. if ( pChild )
  419. {
  420. childGroupList.AddToTail( pChild->GetHandle() );
  421. pChild->GetAllChildren( childGroupList );
  422. }
  423. }
  424. }
  425. //-------------------------------------------------------------------------------------------------
  426. // Recursively destroy the children of the specified group which have no controls or sub groups
  427. //-------------------------------------------------------------------------------------------------
  428. bool CDmeControlGroup::DestroyEmptyChildren_R( CDmeControlGroup *pGroup )
  429. {
  430. int nNumChildren = pGroup->m_Children.Count();
  431. // Build a list of the children which are empty and should be destroyed. This
  432. // process will recursively remove empty children of the children so that if
  433. // a child has only empty sub-children then it will still be removed.
  434. CUtlVector< CDmeControlGroup * > childrenToDestroy( 0, nNumChildren );
  435. for ( int iChild = 0; iChild < nNumChildren; ++iChild )
  436. {
  437. CDmeControlGroup *pChild = pGroup->m_Children[ iChild ];
  438. if ( pChild )
  439. {
  440. if ( DestroyEmptyChildren_R( pChild ) )
  441. {
  442. childrenToDestroy.AddToTail( pChild );
  443. }
  444. }
  445. }
  446. // Destroy the empty children
  447. int nNumToDestroy = childrenToDestroy.Count();
  448. for ( int iChild = 0; iChild < nNumToDestroy; ++iChild )
  449. {
  450. CDmeControlGroup *pChild = childrenToDestroy[ iChild ];
  451. pGroup->RemoveChild( pChild );
  452. }
  453. // If this node is now empty return true indicating that it may be destroyed
  454. return ( ( pGroup->m_Children.Count() == 0 ) && ( pGroup->m_Controls.Count() == 0 ) );
  455. }
  456. //-------------------------------------------------------------------------------------------------
  457. // Destroy all of the empty children of the group, will not destroy this group even it is empty.
  458. //-------------------------------------------------------------------------------------------------
  459. void CDmeControlGroup::DestroyEmptyChildren()
  460. {
  461. DestroyEmptyChildren_R( this );
  462. }
  463. //-------------------------------------------------------------------------------------------------
  464. // Purpose: Destroy the control group, moving all of its children and controls into this node
  465. //-------------------------------------------------------------------------------------------------
  466. void CDmeControlGroup::DestroyGroup( CDmeControlGroup *pGroup, CDmeControlGroup *pRecipient, bool recursive )
  467. {
  468. if ( pGroup == NULL )
  469. return;
  470. // Remove the group from its parent
  471. CDmeControlGroup *pParent = pGroup->FindParent();
  472. if ( pParent )
  473. {
  474. pParent->RemoveChild( pGroup );
  475. if ( pRecipient == NULL )
  476. {
  477. pRecipient = pParent;
  478. }
  479. }
  480. // Destroy the group and all of its children if specified
  481. DestroyGroup_R( pGroup, pRecipient, recursive );
  482. }
  483. //-------------------------------------------------------------------------------------------------
  484. // Purpose: Recursively destroy the child groups of the specified group and and the controls to the
  485. // specified recipient group
  486. //-------------------------------------------------------------------------------------------------
  487. void CDmeControlGroup::DestroyGroup_R( CDmeControlGroup *pGroup, CDmeControlGroup *pRecipient, bool recursive )
  488. {
  489. if ( pGroup == NULL )
  490. return;
  491. // If the group is not empty there must be a recipient to receive its controls and groups
  492. if ( pRecipient == NULL && !pGroup->IsEmpty() )
  493. {
  494. Assert( pGroup->IsEmpty() || pRecipient );
  495. return;
  496. }
  497. // Iterate through the children, if recursive destroy the
  498. // children otherwise copy the children to the recipient.
  499. int nChildren = pGroup->m_Children.Count();
  500. for ( int iChild = 0; iChild < nChildren; ++iChild )
  501. {
  502. CDmeControlGroup *pChild = pGroup->m_Children[ iChild ];
  503. if ( pChild )
  504. {
  505. if ( recursive )
  506. {
  507. DestroyGroup_R( pChild, pRecipient, true );
  508. }
  509. else
  510. {
  511. pRecipient->m_Children.AddToTail( pChild );
  512. }
  513. }
  514. }
  515. // Copy all the controls of the node into the recipient
  516. int nControls = pGroup->m_Controls.Count();
  517. for ( int iControl = 0; iControl < nControls; ++iControl )
  518. {
  519. CDmElement *pControl = pGroup->m_Controls[ iControl ];
  520. pRecipient->m_Controls.AddToTail( pControl );
  521. }
  522. // Destroy the group
  523. DestroyElement( pGroup );
  524. }
  525. //-------------------------------------------------------------------------------------------------
  526. // Remove all of the children and controls from the group
  527. //-------------------------------------------------------------------------------------------------
  528. void CDmeControlGroup::RemoveAllChildrenAndControls()
  529. {
  530. m_Children.RemoveAll();
  531. m_Controls.RemoveAll();
  532. }
  533. //-------------------------------------------------------------------------------------------------
  534. // Purpose: Set the color of the group, this is the color that is used when displaying the group in
  535. // the user interface.
  536. //-------------------------------------------------------------------------------------------------
  537. void CDmeControlGroup::SetGroupColor( const Color &groupColor, bool bRecursive )
  538. {
  539. m_GroupColor = groupColor;
  540. if ( !bRecursive )
  541. return;
  542. int nChildren = m_Children.Count();
  543. for ( int iChild = 0; iChild < nChildren; ++iChild )
  544. {
  545. if ( m_Children[ iChild ] )
  546. {
  547. m_Children[ iChild ]->SetGroupColor( groupColor, true );
  548. }
  549. }
  550. }
  551. //-------------------------------------------------------------------------------------------------
  552. // Purpose: Set the color to be used on the controls of the group
  553. //-------------------------------------------------------------------------------------------------
  554. void CDmeControlGroup::SetControlColor( const Color &controlColor, bool bRecursive )
  555. {
  556. m_ControlColor = controlColor;
  557. if ( !bRecursive )
  558. return;
  559. int nChildren = m_Children.Count();
  560. for ( int iChild = 0; iChild < nChildren; ++iChild )
  561. {
  562. if ( m_Children[ iChild ] )
  563. {
  564. m_Children[ iChild ]->SetControlColor( controlColor, true );
  565. }
  566. }
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Set the visible state of the group
  570. //-----------------------------------------------------------------------------
  571. void CDmeControlGroup::SetVisible( bool bVisible )
  572. {
  573. m_Visible = bVisible;
  574. }
  575. //-----------------------------------------------------------------------------
  576. // Enable or disable selection of the controls
  577. //-----------------------------------------------------------------------------
  578. void CDmeControlGroup::SetSelectable( bool bSelectable )
  579. {
  580. m_Selectable = bSelectable;
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Enable or disable control snapping
  584. //-----------------------------------------------------------------------------
  585. void CDmeControlGroup::SetSnappable( bool bSnappable )
  586. {
  587. m_Snappable = bSnappable;
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Purpose: Determine if there are any controls or children in the group
  591. //-----------------------------------------------------------------------------
  592. bool CDmeControlGroup::IsEmpty() const
  593. {
  594. if ( m_Controls.Count() > 0 ) return false;
  595. if ( m_Children.Count() > 0 ) return false;
  596. return true;
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Is the group visible
  600. //-----------------------------------------------------------------------------
  601. bool CDmeControlGroup::IsVisible() const
  602. {
  603. CDmeControlGroup *pParent = FindParent();
  604. if ( pParent && !pParent->IsVisible() )
  605. return false;
  606. return m_Visible;
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Can controls in the group be selected in the viewport
  610. //-----------------------------------------------------------------------------
  611. bool CDmeControlGroup::IsSelectable() const
  612. {
  613. CDmeControlGroup *pParent = FindParent();
  614. if ( pParent && !pParent->IsSelectable() )
  615. return false;
  616. return m_Selectable;
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Can controls in the group be snapped to in the viewport
  620. //-----------------------------------------------------------------------------
  621. bool CDmeControlGroup::IsSnappable() const
  622. {
  623. CDmeControlGroup *pParent = FindParent();
  624. if ( pParent && !pParent->IsSnappable() )
  625. return false;
  626. return m_Snappable;
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Find the shared ancestor between this control group and the specified control
  630. // group. Will return NULL if groups are not in the same tree and do not share a
  631. // common ancestor. If one group is an ancestor of the other group then that
  632. // group will be returned, so result may be one of the nodes which is not
  633. // technically an ancestor of that node.
  634. //-----------------------------------------------------------------------------
  635. CDmeControlGroup *CDmeControlGroup::FindCommonAncestor( CDmeControlGroup *pControlGroupB )
  636. {
  637. CDmeControlGroup *pControlGroupA = this;
  638. // If the specified group is this group then
  639. // the common ancestor is the group itself.
  640. if ( pControlGroupA == pControlGroupB )
  641. return pControlGroupA;
  642. // Build the path from each group to the root
  643. CUtlVector< CDmeControlGroup * > pathToGroupA;
  644. CUtlVector< CDmeControlGroup * > pathToGroupB;
  645. pControlGroupA->BuildPathFromRoot( pathToGroupA );
  646. pControlGroupB->BuildPathFromRoot( pathToGroupB );
  647. // Now walk each of the the paths until they diverge
  648. CDmeControlGroup *pCommonGroup = NULL;
  649. int nNumSteps = MIN( pathToGroupA.Count(), pathToGroupB.Count() );
  650. int iStep = 0;
  651. while ( iStep < nNumSteps )
  652. {
  653. if ( pathToGroupA[ iStep ] != pathToGroupB[ iStep ] )
  654. break;
  655. pCommonGroup = pathToGroupA[ iStep ];
  656. ++iStep;
  657. }
  658. return pCommonGroup;
  659. }
  660. //-----------------------------------------------------------------------------
  661. // Find the root control group which this control group is in the sub tree of.
  662. //-----------------------------------------------------------------------------
  663. CDmeControlGroup *CDmeControlGroup::FindRootControlGroup()
  664. {
  665. CDmeControlGroup *pCurrent = this;
  666. CDmeControlGroup *pParent = pCurrent->FindParent();
  667. while ( pParent )
  668. {
  669. pCurrent = pParent;
  670. pParent = pParent->FindParent();
  671. }
  672. return pCurrent;
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Build a list of the control group that form the path to the root of the tree
  676. // to which the control group belongs
  677. //-----------------------------------------------------------------------------
  678. void CDmeControlGroup::BuildPathFromRoot( CUtlVector< CDmeControlGroup * > &pathToGroup )
  679. {
  680. CUtlVector< CDmeControlGroup * > pathToRoot( 0, 16 );
  681. CDmeControlGroup *pCurrent = this;
  682. while ( pCurrent )
  683. {
  684. pathToRoot.AddToTail( pCurrent );
  685. pCurrent = pCurrent->FindParent();
  686. }
  687. int nNumGroups = pathToRoot.Count();
  688. pathToGroup.SetCount( nNumGroups );
  689. for ( int iGroup = 0; iGroup < nNumGroups; ++iGroup )
  690. {
  691. pathToGroup[ iGroup ] = pathToRoot[ nNumGroups - 1 - iGroup ];
  692. }
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Find the animation set associated with the control group
  696. //-----------------------------------------------------------------------------
  697. CDmeAnimationSet *CDmeControlGroup::FindAnimationSet( bool bSearchAncestors ) const
  698. {
  699. const static CUtlSymbolLarge symRootControlGroup = g_pDataModel->GetSymbol( "rootControlGroup" );
  700. const CDmeControlGroup *pCurrent = this;
  701. while ( pCurrent )
  702. {
  703. CDmeAnimationSet *pAnimationSet = FindReferringElement< CDmeAnimationSet >( pCurrent, symRootControlGroup );
  704. if ( pAnimationSet != NULL )
  705. return pAnimationSet;
  706. if ( bSearchAncestors == false )
  707. break;
  708. const CDmeControlGroup *pParent = pCurrent->FindParent();
  709. if ( pCurrent == pParent )
  710. break;
  711. pCurrent = pParent;
  712. }
  713. return NULL;
  714. }