Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

523 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dme_controls/BaseAnimSetControlGroupPanel.h"
  7. #include "vgui_controls/TreeView.h"
  8. #include "vgui_controls/Menu.h"
  9. #include "tier1/KeyValues.h"
  10. #include "movieobjects/dmeanimationset.h"
  11. #include "dme_controls/BaseAnimSetAttributeSliderPanel.h"
  12. #include "dme_controls/BaseAnimationSetEditor.h"
  13. #include "dme_controls/dmecontrols_utils.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. using namespace vgui;
  17. //-----------------------------------------------------------------------------
  18. // Shows the tree view of the animation groups
  19. //-----------------------------------------------------------------------------
  20. class CAnimGroupTree : public TreeView
  21. {
  22. DECLARE_CLASS_SIMPLE( CAnimGroupTree, TreeView );
  23. public:
  24. CAnimGroupTree( Panel *parent, const char *panelName, CBaseAnimSetControlGroupPanel *groupPanel );
  25. virtual ~CAnimGroupTree();
  26. virtual bool IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist );
  27. virtual void OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist );
  28. virtual void GenerateContextMenu( int itemIndex, int x, int y );
  29. private:
  30. MESSAGE_FUNC( OnImportAnimation, "ImportAnimation" );
  31. void CleanupContextMenu();
  32. vgui::DHANDLE< vgui::Menu > m_hContextMenu;
  33. CBaseAnimSetControlGroupPanel *m_pGroupPanel;
  34. };
  35. CAnimGroupTree::CAnimGroupTree( Panel *parent, const char *panelName, CBaseAnimSetControlGroupPanel *groupPanel ) :
  36. BaseClass( parent, panelName ),
  37. m_pGroupPanel( groupPanel )
  38. {
  39. }
  40. CAnimGroupTree::~CAnimGroupTree()
  41. {
  42. CleanupContextMenu();
  43. }
  44. void CAnimGroupTree::CleanupContextMenu()
  45. {
  46. if ( m_hContextMenu.Get() )
  47. {
  48. delete m_hContextMenu.Get();
  49. m_hContextMenu = NULL;
  50. }
  51. }
  52. bool CAnimGroupTree::IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist )
  53. {
  54. if ( msglist.Count() != 1 )
  55. return false;
  56. KeyValues *data = msglist[ 0 ];
  57. if ( !data )
  58. return false;
  59. if ( !data->FindKey( "color" ) )
  60. return false;
  61. KeyValues *itemData = GetItemData( itemIndex );
  62. if ( !itemData->FindKey( "handle" ) )
  63. return false;
  64. DmElementHandle_t handle = (DmElementHandle_t)itemData->GetInt( "handle" );
  65. if ( handle == DMELEMENT_HANDLE_INVALID )
  66. return false;
  67. return true;
  68. }
  69. void CAnimGroupTree::OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist )
  70. {
  71. if ( !IsItemDroppable( itemIndex, msglist ) )
  72. return;
  73. KeyValues *data = msglist[ 0 ];
  74. if ( !data )
  75. return;
  76. KeyValues *itemData = GetItemData( itemIndex );
  77. CDmElement *group = GetElementKeyValue< CDmElement >( itemData, "handle" );
  78. Assert( m_pGroupPanel );
  79. Color clr = data->GetColor( "color" );
  80. SetItemFgColor( itemIndex, clr );
  81. SetItemSelectionTextColor( itemIndex, clr );
  82. if ( group )
  83. {
  84. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Change Group Color" );
  85. group->SetValue< Color >( "treeColor", clr );
  86. }
  87. }
  88. void CAnimGroupTree::OnImportAnimation()
  89. {
  90. PostMessage( m_pGroupPanel->m_hEditor, new KeyValues( "ImportAnimation", "visibleOnly", "1" ), 0.0f );
  91. }
  92. // override to open a custom context menu on a node being selected and right-clicked
  93. void CAnimGroupTree::GenerateContextMenu( int itemIndex, int x, int y )
  94. {
  95. CleanupContextMenu();
  96. m_hContextMenu = new Menu( this, "ActionMenu" );
  97. m_hContextMenu->AddMenuItem( "#ImportAnimation", new KeyValues( "ImportAnimation" ), this );
  98. Menu::PlaceContextMenu( this, m_hContextMenu.Get() );
  99. }
  100. CBaseAnimSetControlGroupPanel::CBaseAnimSetControlGroupPanel( vgui::Panel *parent, const char *className, CBaseAnimationSetEditor *editor ) :
  101. BaseClass( parent, className ),
  102. m_bStartItemWasSelected( false ),
  103. m_SliderNames( 0, 0, true )
  104. {
  105. m_hEditor = editor;
  106. m_hGroups = new CAnimGroupTree( this, "AnimSetGroups", this );
  107. m_hGroups->SetMultipleItemDragEnabled( true );
  108. m_hGroups->SetAutoResize
  109. (
  110. Panel::PIN_TOPLEFT,
  111. Panel::AUTORESIZE_DOWNANDRIGHT,
  112. 0, 0,
  113. 0, 0
  114. );
  115. m_hGroups->SetAllowMultipleSelections( true );
  116. }
  117. CBaseAnimSetControlGroupPanel::~CBaseAnimSetControlGroupPanel()
  118. {
  119. }
  120. static int AddItemToTree( TreeView *tv, const char *label, int parentIndex, const Color& fg, int groupNumber, int handle )
  121. {
  122. Color bgColor( 128, 128, 128, 128 );
  123. KeyValues *kv = new KeyValues( "item", "text", label );
  124. kv->SetInt( "groupNumber", groupNumber );
  125. kv->SetInt( "droppable", 1 );
  126. kv->SetInt( "handle", handle );
  127. int idx = tv->AddItem( kv, parentIndex );
  128. tv->SetItemFgColor( idx, fg );
  129. tv->SetItemSelectionTextColor( idx, fg );
  130. tv->SetItemSelectionBgColor( idx, bgColor );
  131. tv->SetItemSelectionUnfocusedBgColor( idx, bgColor );
  132. tv->RemoveSelectedItem( idx );
  133. tv->ExpandItem( idx, false );
  134. kv->deleteThis();
  135. return idx;
  136. }
  137. void CBaseAnimSetControlGroupPanel::ApplySchemeSettings( IScheme *pScheme )
  138. {
  139. BaseClass::ApplySchemeSettings( pScheme );
  140. m_hGroups->SetFont( pScheme->GetFont( "DefaultBold", IsProportional() ) );
  141. }
  142. void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelectionCleared()
  143. {
  144. // We check the entire group manually
  145. OnTreeViewItemSelected( -1 );
  146. }
  147. void CBaseAnimSetControlGroupPanel::OnTreeViewItemDeselected( int itemIndex )
  148. {
  149. OnTreeViewItemSelected( -1 );
  150. }
  151. void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelected( int itemIndex )
  152. {
  153. if ( !m_AnimSet.Get() )
  154. return;
  155. // Build the list of selected groups, and notify the attribute slider panel
  156. CUtlVector< int > selection;
  157. m_hGroups->GetSelectedItems( selection );
  158. const CDmaElementArray<> &groups = m_AnimSet->GetSelectionGroups();
  159. int groupCount = groups.Count();
  160. int i;
  161. int rootIndex = m_hGroups->GetRootItemIndex();
  162. bool selectionHasRoot = false;
  163. for ( i = 0 ; i < selection.Count(); ++i )
  164. {
  165. if ( selection[ i ] == rootIndex )
  166. {
  167. selectionHasRoot = true;
  168. break;
  169. }
  170. }
  171. m_SliderNames.RemoveAll();
  172. if ( selectionHasRoot )
  173. {
  174. for ( i = 0; i < groups.Count(); ++i )
  175. {
  176. CDmElement *element = groups[ i ];
  177. if ( !element )
  178. continue;
  179. const CDmrStringArray array( element, "selectedControls" );
  180. if ( array.IsValid() )
  181. {
  182. for ( int j = 0 ; j < array.Count(); ++j )
  183. {
  184. const char *sliderName = array[ j ];
  185. if ( sliderName && *sliderName )
  186. {
  187. m_SliderNames.AddString( sliderName );
  188. }
  189. }
  190. }
  191. }
  192. }
  193. else
  194. {
  195. for ( i = 0 ; i < selection.Count(); ++i )
  196. {
  197. if ( selection[ i ] == rootIndex )
  198. continue;
  199. KeyValues *kv = m_hGroups->GetItemData( selection[ i ] );
  200. if ( !kv )
  201. continue;
  202. int groupNumber = kv->GetInt( "groupNumber" );
  203. if ( groupNumber < 0 || groupNumber >= groupCount )
  204. {
  205. const char *sliderName = kv->GetString( "text" );
  206. if ( sliderName && *sliderName )
  207. {
  208. m_SliderNames.AddString( sliderName );
  209. }
  210. continue;
  211. }
  212. CDmElement *element = groups[ groupNumber ];
  213. if ( !element )
  214. continue;
  215. const CDmrStringArray array( element, "selectedControls" );
  216. if ( array.IsValid() )
  217. {
  218. for ( int j = 0 ; j < array.Count(); ++j )
  219. {
  220. const char *sliderName = array[ j ];
  221. if ( sliderName && *sliderName )
  222. {
  223. m_SliderNames.AddString( sliderName );
  224. }
  225. }
  226. }
  227. }
  228. }
  229. // now notify the attribute slider panel
  230. CBaseAnimSetAttributeSliderPanel *attSliders = m_hEditor->GetAttributeSlider();
  231. if ( attSliders )
  232. {
  233. attSliders->SetVisibleControlsForSelectionGroup( m_SliderNames );
  234. }
  235. }
  236. void CBaseAnimSetControlGroupPanel::ChangeAnimationSet( CDmeAnimationSet *newAnimSet )
  237. {
  238. bool changed = m_AnimSet.Get() != newAnimSet ? true : false;
  239. m_AnimSet = newAnimSet;
  240. if ( !m_AnimSet.Get() )
  241. {
  242. m_hGroups->RemoveAll();
  243. m_hSelectableIndices.RemoveAll();
  244. m_GroupList.RemoveAll();
  245. return;
  246. }
  247. // Compare groups
  248. bool bRebuildGroups = false;
  249. const CDmaElementArray< CDmElement > &groups = m_AnimSet->GetSelectionGroups();
  250. int c = groups.Count();
  251. if ( c != m_GroupList.Count() )
  252. {
  253. bRebuildGroups = true;
  254. }
  255. else
  256. {
  257. for ( int i = 0; i < c; ++i )
  258. {
  259. CDmElement *group = groups[ i ];
  260. if ( group == m_GroupList[ i ].Get() )
  261. {
  262. continue;
  263. }
  264. bRebuildGroups = true;
  265. break;
  266. }
  267. }
  268. if ( bRebuildGroups )
  269. {
  270. m_hGroups->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultBold", IsProportional() ) );
  271. // Build a tree of every open item in the tree view
  272. OpenItemTree_t openItems;
  273. int nRootIndex = m_hGroups->GetRootItemIndex();
  274. if ( nRootIndex != -1 )
  275. {
  276. BuildOpenItemList( openItems, openItems.InvalidIndex(), nRootIndex );
  277. }
  278. m_hGroups->RemoveAll();
  279. m_hSelectableIndices.RemoveAll();
  280. m_GroupList.RemoveAll();
  281. // Create root
  282. int rootIndex = AddItemToTree( m_hGroups, "root", -1, Color( 128, 128, 128, 255 ), -1, (int)DMELEMENT_HANDLE_INVALID );
  283. Color defaultColor( 0, 128, 255, 255 );
  284. CAppUndoScopeGuard *guard = NULL;
  285. for ( int i = 0; i < c; ++i )
  286. {
  287. CDmElement *group = groups[ i ];
  288. if ( !group->HasAttribute( "treeColor" ) )
  289. {
  290. if ( !guard )
  291. {
  292. guard = new CAppUndoScopeGuard( NOTIFY_SETDIRTYFLAG, "Set Default Colors" );
  293. }
  294. group->SetValue< Color >( "treeColor", defaultColor );
  295. }
  296. int groupIndex = AddItemToTree( m_hGroups, group->GetName(), rootIndex, group->GetValue< Color >( "treeColor" ), i, (int)group->GetHandle() );
  297. const CDmrStringArray array( group, "selectedControls" );
  298. if ( array.IsValid() )
  299. {
  300. for ( int j = 0 ; j < array.Count(); ++j )
  301. {
  302. AddItemToTree( m_hGroups, array[ j ], groupIndex, Color( 200, 200, 200, 255 ), -1, (int)DMELEMENT_HANDLE_INVALID );
  303. }
  304. }
  305. m_hSelectableIndices.AddToTail( groupIndex );
  306. m_GroupList.AddToTail( group->GetHandle() );
  307. }
  308. if ( ( nRootIndex >= 0 ) && ( rootIndex >= 0 ) && !changed )
  309. {
  310. // Iterate through all previously open items and expand them if they exist
  311. if ( openItems.Root() != openItems.InvalidIndex() )
  312. {
  313. ExpandOpenItems( openItems, openItems.Root(), rootIndex, true );
  314. }
  315. }
  316. else
  317. {
  318. m_hGroups->ExpandItem( rootIndex, true );
  319. }
  320. if ( guard )
  321. {
  322. delete guard;
  323. }
  324. }
  325. if ( changed )
  326. {
  327. for ( int i = 0; i < m_hSelectableIndices.Count(); ++i )
  328. {
  329. m_hGroups->AddSelectedItem( m_hSelectableIndices[ i ],
  330. false, // don't clear selection
  331. true, // put focus on tree
  332. false ); // don't expand tree to make all of these visible...
  333. }
  334. }
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Expands all items in the open item tree if they exist
  338. //-----------------------------------------------------------------------------
  339. void CBaseAnimSetControlGroupPanel::ExpandOpenItems( OpenItemTree_t &tree, int nOpenTreeIndex, int nItemIndex, bool makeVisible )
  340. {
  341. int i = tree.FirstChild( nOpenTreeIndex );
  342. if ( nOpenTreeIndex != tree.InvalidIndex() )
  343. {
  344. TreeInfo_t& info = tree[ nOpenTreeIndex ];
  345. if ( info.m_nFlags & EP_EXPANDED )
  346. {
  347. // Expand the item
  348. m_hGroups->ExpandItem( nItemIndex , true );
  349. }
  350. if ( info.m_nFlags & EP_SELECTED )
  351. {
  352. m_hGroups->AddSelectedItem( nItemIndex, false, false );
  353. if ( makeVisible )
  354. {
  355. m_hGroups->MakeItemVisible( nItemIndex );
  356. }
  357. }
  358. }
  359. while ( i != tree.InvalidIndex() )
  360. {
  361. TreeInfo_t& info = tree[ i ];
  362. // Look for a match
  363. int nChildIndex = FindTreeItem( nItemIndex, info.m_Item );
  364. if ( nChildIndex != -1 )
  365. {
  366. ExpandOpenItems( tree, i, nChildIndex, makeVisible );
  367. }
  368. else
  369. {
  370. if ( info.m_nFlags & EP_SELECTED )
  371. {
  372. // Look for preserved item
  373. nChildIndex = FindTreeItem( nItemIndex, info.m_Item );
  374. if ( nChildIndex != -1 )
  375. {
  376. m_hGroups->AddSelectedItem( nChildIndex, false, false );
  377. if ( makeVisible )
  378. {
  379. m_hGroups->MakeItemVisible( nChildIndex );
  380. }
  381. }
  382. }
  383. }
  384. i = tree.NextSibling( i );
  385. }
  386. }
  387. void CBaseAnimSetControlGroupPanel::FillInDataForItem( TreeItem_t &item, int nItemIndex )
  388. {
  389. KeyValues *data = m_hGroups->GetItemData( nItemIndex );
  390. if ( !data )
  391. return;
  392. item.m_pAttributeName = data->GetString( "text" );
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Builds a list of open items
  396. //-----------------------------------------------------------------------------
  397. void CBaseAnimSetControlGroupPanel::BuildOpenItemList( OpenItemTree_t &tree, int nParent, int nItemIndex )
  398. {
  399. KeyValues *data = m_hGroups->GetItemData( nItemIndex );
  400. if ( !data )
  401. return;
  402. bool expanded = m_hGroups->IsItemExpanded( nItemIndex );
  403. bool selected = m_hGroups->IsItemSelected( nItemIndex );
  404. int flags = 0;
  405. if ( expanded )
  406. {
  407. flags |= EP_EXPANDED;
  408. }
  409. if ( selected )
  410. {
  411. flags |= EP_SELECTED;
  412. }
  413. int nChild = tree.InsertChildAfter( nParent, tree.InvalidIndex() );
  414. TreeInfo_t &info = tree[nChild];
  415. FillInDataForItem( info.m_Item, nItemIndex );
  416. info.m_nFlags = flags;
  417. // Deal with children
  418. int nCount = m_hGroups->GetNumChildren( nItemIndex );
  419. for ( int i = 0; i < nCount; ++i )
  420. {
  421. int nChildIndex = m_hGroups->GetChild( nItemIndex, i );
  422. BuildOpenItemList( tree, nChild, nChildIndex );
  423. }
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Finds the tree index of a child matching the particular element + attribute
  427. //-----------------------------------------------------------------------------
  428. int CBaseAnimSetControlGroupPanel::FindTreeItem( int nParentIndex, const TreeItem_t &info )
  429. {
  430. // Look for a match
  431. int nCount = m_hGroups->GetNumChildren( nParentIndex );
  432. for ( int i = nCount; --i >= 0; )
  433. {
  434. int nChildIndex = m_hGroups->GetChild( nParentIndex, i );
  435. KeyValues *data = m_hGroups->GetItemData( nChildIndex );
  436. Assert( data );
  437. const char *pAttributeName = data->GetString( "text" );
  438. if ( !Q_stricmp( pAttributeName, info.m_pAttributeName ) )
  439. {
  440. return nChildIndex;
  441. }
  442. }
  443. return -1;
  444. }