|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "dme_controls/BaseAnimSetControlGroupPanel.h"
#include "vgui_controls/TreeView.h"
#include "vgui_controls/Menu.h"
#include "tier1/KeyValues.h"
#include "movieobjects/dmeanimationset.h"
#include "dme_controls/BaseAnimSetAttributeSliderPanel.h"
#include "dme_controls/BaseAnimationSetEditor.h"
#include "dme_controls/dmecontrols_utils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Shows the tree view of the animation groups
//-----------------------------------------------------------------------------
class CAnimGroupTree : public TreeView { DECLARE_CLASS_SIMPLE( CAnimGroupTree, TreeView ); public: CAnimGroupTree( Panel *parent, const char *panelName, CBaseAnimSetControlGroupPanel *groupPanel ); virtual ~CAnimGroupTree();
virtual bool IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist ); virtual void OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist ); virtual void GenerateContextMenu( int itemIndex, int x, int y );
private: MESSAGE_FUNC( OnImportAnimation, "ImportAnimation" );
void CleanupContextMenu();
vgui::DHANDLE< vgui::Menu > m_hContextMenu; CBaseAnimSetControlGroupPanel *m_pGroupPanel; };
CAnimGroupTree::CAnimGroupTree( Panel *parent, const char *panelName, CBaseAnimSetControlGroupPanel *groupPanel ) : BaseClass( parent, panelName ), m_pGroupPanel( groupPanel ) { }
CAnimGroupTree::~CAnimGroupTree() { CleanupContextMenu(); }
void CAnimGroupTree::CleanupContextMenu() { if ( m_hContextMenu.Get() ) { delete m_hContextMenu.Get(); m_hContextMenu = NULL; } }
bool CAnimGroupTree::IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist ) { if ( msglist.Count() != 1 ) return false;
KeyValues *data = msglist[ 0 ]; if ( !data ) return false;
if ( !data->FindKey( "color" ) ) return false;
KeyValues *itemData = GetItemData( itemIndex ); if ( !itemData->FindKey( "handle" ) ) return false; DmElementHandle_t handle = (DmElementHandle_t)itemData->GetInt( "handle" ); if ( handle == DMELEMENT_HANDLE_INVALID ) return false;
return true; }
void CAnimGroupTree::OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist ) { if ( !IsItemDroppable( itemIndex, msglist ) ) return;
KeyValues *data = msglist[ 0 ]; if ( !data ) return;
KeyValues *itemData = GetItemData( itemIndex );
CDmElement *group = GetElementKeyValue< CDmElement >( itemData, "handle" ); Assert( m_pGroupPanel ); Color clr = data->GetColor( "color" ); SetItemFgColor( itemIndex, clr ); SetItemSelectionTextColor( itemIndex, clr );
if ( group ) { CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Change Group Color" ); group->SetValue< Color >( "treeColor", clr ); } }
void CAnimGroupTree::OnImportAnimation() { PostMessage( m_pGroupPanel->m_hEditor, new KeyValues( "ImportAnimation", "visibleOnly", "1" ), 0.0f ); }
// override to open a custom context menu on a node being selected and right-clicked
void CAnimGroupTree::GenerateContextMenu( int itemIndex, int x, int y ) { CleanupContextMenu(); m_hContextMenu = new Menu( this, "ActionMenu" ); m_hContextMenu->AddMenuItem( "#ImportAnimation", new KeyValues( "ImportAnimation" ), this ); Menu::PlaceContextMenu( this, m_hContextMenu.Get() ); }
CBaseAnimSetControlGroupPanel::CBaseAnimSetControlGroupPanel( vgui::Panel *parent, const char *className, CBaseAnimationSetEditor *editor ) : BaseClass( parent, className ), m_bStartItemWasSelected( false ), m_SliderNames( 0, 0, true ) { m_hEditor = editor; m_hGroups = new CAnimGroupTree( this, "AnimSetGroups", this ); m_hGroups->SetMultipleItemDragEnabled( true ); m_hGroups->SetAutoResize ( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); m_hGroups->SetAllowMultipleSelections( true ); }
CBaseAnimSetControlGroupPanel::~CBaseAnimSetControlGroupPanel() { }
static int AddItemToTree( TreeView *tv, const char *label, int parentIndex, const Color& fg, int groupNumber, int handle ) { Color bgColor( 128, 128, 128, 128 );
KeyValues *kv = new KeyValues( "item", "text", label ); kv->SetInt( "groupNumber", groupNumber ); kv->SetInt( "droppable", 1 ); kv->SetInt( "handle", handle ); int idx = tv->AddItem( kv, parentIndex ); tv->SetItemFgColor( idx, fg ); tv->SetItemSelectionTextColor( idx, fg ); tv->SetItemSelectionBgColor( idx, bgColor ); tv->SetItemSelectionUnfocusedBgColor( idx, bgColor );
tv->RemoveSelectedItem( idx ); tv->ExpandItem( idx, false );
kv->deleteThis();
return idx; }
void CBaseAnimSetControlGroupPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); m_hGroups->SetFont( pScheme->GetFont( "DefaultBold", IsProportional() ) ); }
void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelectionCleared() { // We check the entire group manually
OnTreeViewItemSelected( -1 ); }
void CBaseAnimSetControlGroupPanel::OnTreeViewItemDeselected( int itemIndex ) { OnTreeViewItemSelected( -1 ); }
void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelected( int itemIndex ) { if ( !m_AnimSet.Get() ) return;
// Build the list of selected groups, and notify the attribute slider panel
CUtlVector< int > selection; m_hGroups->GetSelectedItems( selection );
const CDmaElementArray<> &groups = m_AnimSet->GetSelectionGroups(); int groupCount = groups.Count();
int i; int rootIndex = m_hGroups->GetRootItemIndex();
bool selectionHasRoot = false; for ( i = 0 ; i < selection.Count(); ++i ) { if ( selection[ i ] == rootIndex ) { selectionHasRoot = true; break; } }
m_SliderNames.RemoveAll();
if ( selectionHasRoot ) { for ( i = 0; i < groups.Count(); ++i ) { CDmElement *element = groups[ i ]; if ( !element ) continue;
const CDmrStringArray array( element, "selectedControls" ); if ( array.IsValid() ) { for ( int j = 0 ; j < array.Count(); ++j ) { const char *sliderName = array[ j ]; if ( sliderName && *sliderName ) { m_SliderNames.AddString( sliderName ); } } } } } else { for ( i = 0 ; i < selection.Count(); ++i ) { if ( selection[ i ] == rootIndex ) continue;
KeyValues *kv = m_hGroups->GetItemData( selection[ i ] ); if ( !kv ) continue;
int groupNumber = kv->GetInt( "groupNumber" ); if ( groupNumber < 0 || groupNumber >= groupCount ) { const char *sliderName = kv->GetString( "text" ); if ( sliderName && *sliderName ) { m_SliderNames.AddString( sliderName ); } continue; }
CDmElement *element = groups[ groupNumber ]; if ( !element ) continue;
const CDmrStringArray array( element, "selectedControls" ); if ( array.IsValid() ) { for ( int j = 0 ; j < array.Count(); ++j ) { const char *sliderName = array[ j ]; if ( sliderName && *sliderName ) { m_SliderNames.AddString( sliderName ); } } } } }
// now notify the attribute slider panel
CBaseAnimSetAttributeSliderPanel *attSliders = m_hEditor->GetAttributeSlider(); if ( attSliders ) { attSliders->SetVisibleControlsForSelectionGroup( m_SliderNames ); } }
void CBaseAnimSetControlGroupPanel::ChangeAnimationSet( CDmeAnimationSet *newAnimSet ) { bool changed = m_AnimSet.Get() != newAnimSet ? true : false;
m_AnimSet = newAnimSet;
if ( !m_AnimSet.Get() ) { m_hGroups->RemoveAll(); m_hSelectableIndices.RemoveAll(); m_GroupList.RemoveAll(); return; }
// Compare groups
bool bRebuildGroups = false; const CDmaElementArray< CDmElement > &groups = m_AnimSet->GetSelectionGroups(); int c = groups.Count(); if ( c != m_GroupList.Count() ) { bRebuildGroups = true; } else { for ( int i = 0; i < c; ++i ) { CDmElement *group = groups[ i ]; if ( group == m_GroupList[ i ].Get() ) { continue; }
bRebuildGroups = true; break; } }
if ( bRebuildGroups ) { m_hGroups->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultBold", IsProportional() ) );
// Build a tree of every open item in the tree view
OpenItemTree_t openItems; int nRootIndex = m_hGroups->GetRootItemIndex(); if ( nRootIndex != -1 ) { BuildOpenItemList( openItems, openItems.InvalidIndex(), nRootIndex ); }
m_hGroups->RemoveAll(); m_hSelectableIndices.RemoveAll(); m_GroupList.RemoveAll();
// Create root
int rootIndex = AddItemToTree( m_hGroups, "root", -1, Color( 128, 128, 128, 255 ), -1, (int)DMELEMENT_HANDLE_INVALID );
Color defaultColor( 0, 128, 255, 255 );
CAppUndoScopeGuard *guard = NULL;
for ( int i = 0; i < c; ++i ) { CDmElement *group = groups[ i ]; if ( !group->HasAttribute( "treeColor" ) ) { if ( !guard ) { guard = new CAppUndoScopeGuard( NOTIFY_SETDIRTYFLAG, "Set Default Colors" ); } group->SetValue< Color >( "treeColor", defaultColor ); } int groupIndex = AddItemToTree( m_hGroups, group->GetName(), rootIndex, group->GetValue< Color >( "treeColor" ), i, (int)group->GetHandle() );
const CDmrStringArray array( group, "selectedControls" ); if ( array.IsValid() ) { for ( int j = 0 ; j < array.Count(); ++j ) { AddItemToTree( m_hGroups, array[ j ], groupIndex, Color( 200, 200, 200, 255 ), -1, (int)DMELEMENT_HANDLE_INVALID ); } } m_hSelectableIndices.AddToTail( groupIndex );
m_GroupList.AddToTail( group->GetHandle() ); }
if ( ( nRootIndex >= 0 ) && ( rootIndex >= 0 ) && !changed ) { // Iterate through all previously open items and expand them if they exist
if ( openItems.Root() != openItems.InvalidIndex() ) { ExpandOpenItems( openItems, openItems.Root(), rootIndex, true ); } } else { m_hGroups->ExpandItem( rootIndex, true ); }
if ( guard ) { delete guard; } }
if ( changed ) { for ( int i = 0; i < m_hSelectableIndices.Count(); ++i ) {
m_hGroups->AddSelectedItem( m_hSelectableIndices[ i ], false, // don't clear selection
true, // put focus on tree
false ); // don't expand tree to make all of these visible...
} } }
//-----------------------------------------------------------------------------
// Expands all items in the open item tree if they exist
//-----------------------------------------------------------------------------
void CBaseAnimSetControlGroupPanel::ExpandOpenItems( OpenItemTree_t &tree, int nOpenTreeIndex, int nItemIndex, bool makeVisible ) { int i = tree.FirstChild( nOpenTreeIndex ); if ( nOpenTreeIndex != tree.InvalidIndex() ) { TreeInfo_t& info = tree[ nOpenTreeIndex ]; if ( info.m_nFlags & EP_EXPANDED ) { // Expand the item
m_hGroups->ExpandItem( nItemIndex , true ); } if ( info.m_nFlags & EP_SELECTED ) { m_hGroups->AddSelectedItem( nItemIndex, false, false ); if ( makeVisible ) { m_hGroups->MakeItemVisible( nItemIndex ); } } }
while ( i != tree.InvalidIndex() ) { TreeInfo_t& info = tree[ i ]; // Look for a match
int nChildIndex = FindTreeItem( nItemIndex, info.m_Item ); if ( nChildIndex != -1 ) { ExpandOpenItems( tree, i, nChildIndex, makeVisible ); } else { if ( info.m_nFlags & EP_SELECTED ) { // Look for preserved item
nChildIndex = FindTreeItem( nItemIndex, info.m_Item ); if ( nChildIndex != -1 ) { m_hGroups->AddSelectedItem( nChildIndex, false, false ); if ( makeVisible ) { m_hGroups->MakeItemVisible( nChildIndex ); } } } } i = tree.NextSibling( i ); } }
void CBaseAnimSetControlGroupPanel::FillInDataForItem( TreeItem_t &item, int nItemIndex ) { KeyValues *data = m_hGroups->GetItemData( nItemIndex ); if ( !data ) return;
item.m_pAttributeName = data->GetString( "text" ); }
//-----------------------------------------------------------------------------
// Builds a list of open items
//-----------------------------------------------------------------------------
void CBaseAnimSetControlGroupPanel::BuildOpenItemList( OpenItemTree_t &tree, int nParent, int nItemIndex ) { KeyValues *data = m_hGroups->GetItemData( nItemIndex ); if ( !data ) return;
bool expanded = m_hGroups->IsItemExpanded( nItemIndex ); bool selected = m_hGroups->IsItemSelected( nItemIndex );
int flags = 0; if ( expanded ) { flags |= EP_EXPANDED; } if ( selected ) { flags |= EP_SELECTED; }
int nChild = tree.InsertChildAfter( nParent, tree.InvalidIndex() ); TreeInfo_t &info = tree[nChild]; FillInDataForItem( info.m_Item, nItemIndex ); info.m_nFlags = flags;
// Deal with children
int nCount = m_hGroups->GetNumChildren( nItemIndex ); for ( int i = 0; i < nCount; ++i ) { int nChildIndex = m_hGroups->GetChild( nItemIndex, i ); BuildOpenItemList( tree, nChild, nChildIndex ); } } //-----------------------------------------------------------------------------
// Finds the tree index of a child matching the particular element + attribute
//-----------------------------------------------------------------------------
int CBaseAnimSetControlGroupPanel::FindTreeItem( int nParentIndex, const TreeItem_t &info ) { // Look for a match
int nCount = m_hGroups->GetNumChildren( nParentIndex ); for ( int i = nCount; --i >= 0; ) { int nChildIndex = m_hGroups->GetChild( nParentIndex, i ); KeyValues *data = m_hGroups->GetItemData( nChildIndex ); Assert( data );
const char *pAttributeName = data->GetString( "text" ); if ( !Q_stricmp( pAttributeName, info.m_pAttributeName ) ) { return nChildIndex; } } return -1; }
|