524 lines
13 KiB
C++
524 lines
13 KiB
C++
|
//========= 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;
|
||
|
}
|