source-engine/vgui2/dme_controls/BaseAnimSetControlGroupPanel.cpp

524 lines
13 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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;
}