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.
1994 lines
64 KiB
1994 lines
64 KiB
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
#include "dme_controls/BaseAnimSetControlGroupPanel.h"
|
|
#include "vgui_controls/TreeView.h"
|
|
#include "vgui_controls/Menu.h"
|
|
#include "vgui_controls/Button.h"
|
|
#include "vgui_controls/ImageList.h"
|
|
#include "vgui_controls/Tooltip.h"
|
|
#include "tier1/KeyValues.h"
|
|
#include "movieobjects/dmeanimationset.h"
|
|
#include "movieobjects/dmegamemodel.h"
|
|
#include "movieobjects/dmerig.h"
|
|
#include "movieobjects/dmetransformcontrol.h"
|
|
#include "dme_controls/BaseAnimSetAttributeSliderPanel.h"
|
|
#include "dme_controls/BaseAnimationSetEditor.h"
|
|
#include "dme_controls/dmecontrols_utils.h"
|
|
#include "vgui/ISystem.h"
|
|
#include "vgui/ISurface.h"
|
|
#include "vgui/IInput.h"
|
|
#include "vgui/IVGui.h"
|
|
#include "vgui/ILocalize.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
using namespace vgui;
|
|
|
|
enum StateIcons_t
|
|
{
|
|
STATE_ICON_WORK_CAMERA_PARENT_ACTIVE,
|
|
STATE_ICON_WORK_CAMERA_PARENT_HIDDEN,
|
|
STATE_ICON_DAG_LOCKED,
|
|
STATE_ICON_DAG_LOCKED_PARTIAL,
|
|
STATE_ICON_DAG_LOCKED_WORLD,
|
|
STATE_ICON_DAG_LOCKED_WORLD_PARTIAL,
|
|
STATE_ICON_COUNT
|
|
};
|
|
|
|
enum StateIconSetType_t
|
|
{
|
|
STATE_ICON_SET_INVALID,
|
|
STATE_ICON_SET_GROUP,
|
|
STATE_ICON_SET_CONTROL_POSITION,
|
|
STATE_ICON_SET_CONTROL_ROTATION,
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A panel containing a set of icons providing information about the state of
|
|
// an animation group tree item.
|
|
//-----------------------------------------------------------------------------
|
|
class CAnimGroupStateIconSet : public Panel
|
|
{
|
|
DECLARE_CLASS_SIMPLE( CAnimGroupStateIconSet, Panel );
|
|
|
|
|
|
// The sole purpose of the icon button is to allow right clicks
|
|
// to be handled and used for context menu creation.
|
|
class IconButton : public Button
|
|
{
|
|
DECLARE_CLASS_SIMPLE( IconButton, Button );
|
|
|
|
public:
|
|
IconButton( CAnimGroupStateIconSet *pIconSet, const char *pName )
|
|
: Button( pIconSet, pName, "" )
|
|
, m_pIconSet( pIconSet )
|
|
{}
|
|
|
|
void OnMousePressed( MouseCode code )
|
|
{
|
|
if ( code == MOUSE_RIGHT )
|
|
{
|
|
m_pIconSet->IconButtonRightClick();
|
|
return;
|
|
}
|
|
BaseClass::OnMousePressed( code );
|
|
}
|
|
|
|
CAnimGroupStateIconSet *const m_pIconSet;
|
|
};
|
|
|
|
|
|
public:
|
|
|
|
CAnimGroupStateIconSet( Panel *pParent, const char *pchName, StateIconSetType_t stateType, CDmeDag *pDag, ImageList &imageList, const int *pImageIndexMap );
|
|
|
|
virtual void ApplySchemeSettings( IScheme *pScheme );
|
|
virtual void PerformLayout();
|
|
virtual bool IsDroppable( CUtlVector< KeyValues * > &msglist );
|
|
virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist );
|
|
|
|
void IconButtonRightClick();
|
|
|
|
void UpdateState();
|
|
|
|
private:
|
|
|
|
MESSAGE_FUNC( OnLockDagButton, "LockDagButton" );
|
|
|
|
static const CDmeDag *GetDagFromDragElement( CDmElement *pElement );
|
|
|
|
static const int LOCKED_TOOLTIP_DELAY = 750;
|
|
static const int UNLOCKED_TOOLTIP_DELAY = 1500;
|
|
|
|
ImageList &m_ImageList;
|
|
const int *const m_pImageIndexMap;
|
|
const int m_StateType;
|
|
CDmeDag *m_pDag;
|
|
IconButton *m_pLockButton;
|
|
};
|
|
|
|
|
|
CAnimGroupStateIconSet::CAnimGroupStateIconSet( Panel *pParent, const char *pchName, StateIconSetType_t itemType, CDmeDag *pDag, ImageList &imageList, const int *pImageIndexMap )
|
|
: BaseClass( pParent, "AnimGroupStateIconSet" )
|
|
, m_ImageList( imageList )
|
|
, m_pImageIndexMap( pImageIndexMap )
|
|
, m_StateType( itemType )
|
|
, m_pDag( pDag )
|
|
, m_pLockButton( NULL )
|
|
{
|
|
m_pLockButton = new IconButton( this, "LockButton" );
|
|
m_pLockButton->SetVisible( true );
|
|
m_pLockButton->AddActionSignalTarget( this );
|
|
m_pLockButton->SetCommand( new KeyValues( "LockDagButton" ) );
|
|
m_pLockButton->SetKeyBoardInputEnabled( false );
|
|
|
|
vgui::BaseTooltip *pTooltip = m_pLockButton->GetTooltip();
|
|
if ( pTooltip )
|
|
{
|
|
pTooltip->SetTooltipDelay( UNLOCKED_TOOLTIP_DELAY );
|
|
pTooltip->SetText( "#LockButtonTip" );
|
|
pTooltip->SetTooltipFormatToSingleLine();
|
|
}
|
|
|
|
SetDropEnabled( true );
|
|
}
|
|
|
|
|
|
void CAnimGroupStateIconSet::ApplySchemeSettings( IScheme *pScheme )
|
|
{
|
|
BaseClass::ApplySchemeSettings( pScheme );
|
|
|
|
Color buttonColor = pScheme->GetColor( "Frame.BgColor", Color( 0, 0, 0, 0 ) );
|
|
SetBgColor( buttonColor );
|
|
|
|
if ( m_pLockButton )
|
|
{
|
|
m_pLockButton->SetDefaultBorder( pScheme->GetBorder( "DepressedBorder" ) );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
void CAnimGroupStateIconSet::PerformLayout()
|
|
{
|
|
int nHeight = GetTall();
|
|
|
|
if ( m_pLockButton )
|
|
{
|
|
m_pLockButton->SetBounds( 1, 1, nHeight - 1, nHeight - 1 );
|
|
}
|
|
}
|
|
|
|
|
|
const CDmeDag *CAnimGroupStateIconSet::GetDagFromDragElement( CDmElement *pElement )
|
|
{
|
|
if ( pElement == NULL )
|
|
return NULL;
|
|
|
|
const CDmeDag *pDag = NULL;
|
|
|
|
CDmeTransformControl *pTransformControl = CastElement< CDmeTransformControl >( pElement );
|
|
if ( pTransformControl )
|
|
{
|
|
pDag = pTransformControl->GetDag();
|
|
}
|
|
else
|
|
{
|
|
pDag = CastElement< CDmeDag >( pElement );
|
|
}
|
|
|
|
return pDag;
|
|
}
|
|
|
|
|
|
bool CAnimGroupStateIconSet::IsDroppable( CUtlVector< KeyValues * > &msglist )
|
|
{
|
|
int nCount = msglist.Count();
|
|
if ( nCount != 1 )
|
|
return false;
|
|
|
|
KeyValues *pData = msglist[ 0 ];
|
|
CDmElement *pElement = GetElementKeyValue< CDmElement >( pData, "dmeelement" );
|
|
|
|
const CDmeDag *pParentDag = GetDagFromDragElement( pElement );
|
|
if ( pParentDag == NULL )
|
|
return false;
|
|
|
|
// Can't parent a dag to is child
|
|
if ( m_pDag->IsAncestorOfDag( pParentDag ) )
|
|
return false;
|
|
|
|
// Can't parent a dag to itself.
|
|
if ( m_pDag == pParentDag )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CAnimGroupStateIconSet::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
|
|
{
|
|
int nCount = msglist.Count();
|
|
if ( nCount == 1 )
|
|
{
|
|
KeyValues *pData = msglist[ 0 ];
|
|
CDmElement *pElement = GetElementKeyValue< CDmElement >( pData, "dmeelement" );
|
|
const CDmElement *pParentDag = GetDagFromDragElement( pElement );
|
|
|
|
if ( pParentDag )
|
|
{
|
|
bool bPosition = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_POSITION ) );
|
|
bool bRotation = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_ROTATION ) );
|
|
|
|
KeyValues *pMsgKv = new KeyValues( "SetOverrideParent" );
|
|
pMsgKv->SetInt( "targetDag", m_pDag->GetHandle() );
|
|
pMsgKv->SetInt( "parentDag", pParentDag->GetHandle() );
|
|
pMsgKv->SetBool( "position", bPosition );
|
|
pMsgKv->SetBool( "rotation", bRotation );
|
|
PostMessage( GetParent(), pMsgKv, 0.0f );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAnimGroupStateIconSet::IconButtonRightClick()
|
|
{
|
|
bool bPosition = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_POSITION ) );
|
|
bool bRotation = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_ROTATION ) );
|
|
|
|
KeyValues *pMsgKv = new KeyValues( "OpenLockContextMenu" );
|
|
pMsgKv->SetInt( "targetDag", m_pDag->GetHandle() );
|
|
pMsgKv->SetBool( "position", bPosition );
|
|
pMsgKv->SetBool( "rotation", bRotation );
|
|
|
|
PostMessage( GetParent(), pMsgKv, 0.0f );
|
|
}
|
|
|
|
|
|
void CAnimGroupStateIconSet::UpdateState()
|
|
{
|
|
if ( m_pDag == NULL )
|
|
return;
|
|
|
|
m_pLockButton->ClearImages();
|
|
|
|
vgui::BaseTooltip *pTooltip = m_pLockButton->GetTooltip();
|
|
|
|
bool bPos = false;
|
|
bool bRot = false;
|
|
const CDmeDag *pOverrideParent = m_pDag->GetOverrideParent( bPos, bRot, true );
|
|
|
|
if ( pOverrideParent != NULL )
|
|
{
|
|
bool bLockedToWorld = ( pOverrideParent->GetParent() == NULL );
|
|
int nFullLockedIcon = bLockedToWorld ? STATE_ICON_DAG_LOCKED_WORLD : STATE_ICON_DAG_LOCKED;
|
|
int nPartialLockedIcon = bLockedToWorld ? STATE_ICON_DAG_LOCKED_WORLD_PARTIAL : STATE_ICON_DAG_LOCKED_PARTIAL;
|
|
|
|
// Change the image to the grayed out version if both position and rotation are not overridden
|
|
int nImageIndex = 0;
|
|
|
|
if ( m_StateType == STATE_ICON_SET_GROUP )
|
|
{
|
|
nImageIndex = ( bPos && bRot ) ? m_pImageIndexMap[ nFullLockedIcon ] : m_pImageIndexMap[ nPartialLockedIcon ];
|
|
}
|
|
else if ( ( ( m_StateType == STATE_ICON_SET_CONTROL_POSITION ) && bPos ) ||
|
|
( ( m_StateType == STATE_ICON_SET_CONTROL_ROTATION ) && bRot ) )
|
|
{
|
|
nImageIndex = m_pImageIndexMap[ nFullLockedIcon ];
|
|
}
|
|
|
|
// Update the image of on the button
|
|
vgui::IImage *pLockImage = m_ImageList.GetImage( nImageIndex );
|
|
m_pLockButton->AddImage( pLockImage, 0 );
|
|
|
|
// Update the tool tip text describing what dag is new parent
|
|
if ( pTooltip )
|
|
{
|
|
if ( bLockedToWorld )
|
|
{
|
|
pTooltip->SetText( "#LockedToWorld" );
|
|
}
|
|
else
|
|
{
|
|
const wchar_t *pLabel = g_pVGuiLocalize->Find( "#LockedTo" );
|
|
if ( pLabel )
|
|
{
|
|
char itemText[ 32 ];
|
|
char tipText[ 64 ];
|
|
g_pVGuiLocalize->ConvertUnicodeToANSI( pLabel, itemText, sizeof( itemText ) );
|
|
V_snprintf( tipText, sizeof( tipText ), "%s %s", itemText, pOverrideParent->GetName() );
|
|
pTooltip->SetText( tipText );
|
|
}
|
|
}
|
|
|
|
pTooltip->SetTooltipDelay( LOCKED_TOOLTIP_DELAY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTooltip->SetTooltipDelay( UNLOCKED_TOOLTIP_DELAY );
|
|
pTooltip->SetText( "#LockButtonTip" );
|
|
}
|
|
}
|
|
|
|
|
|
void CAnimGroupStateIconSet::OnLockDagButton()
|
|
{
|
|
if ( m_pDag )
|
|
{
|
|
bool bPosition = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_POSITION ) );
|
|
bool bRotation = ( ( m_StateType == STATE_ICON_SET_GROUP ) || ( m_StateType == STATE_ICON_SET_CONTROL_ROTATION ) );
|
|
|
|
KeyValues *pMsgKv = new KeyValues( "ToggleDagLock" );
|
|
pMsgKv->SetInt( "targetDag", m_pDag->GetHandle() );
|
|
pMsgKv->SetBool( "position", bPosition );
|
|
pMsgKv->SetBool( "rotation", bRotation );
|
|
PostMessage( GetParent(), pMsgKv, 0.0f );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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, bool bStateInterface );
|
|
virtual ~CAnimGroupTree();
|
|
|
|
virtual bool IsItemDroppable( int itemIndex, bool bInsertBefore, CUtlVector< KeyValues * >& msglist );
|
|
virtual void OnItemDropped( int itemIndex, bool bInsertBefore, CUtlVector< KeyValues * >& msglist );
|
|
virtual bool CanCurrentlyEditLabel( int nItemIndex ) const;
|
|
virtual void OnLabelChanged( int nItemIndex, char const *pOldString, char const *pNewString );
|
|
virtual void GetSelectedItemsForDrag( int nPrimaryDragItem, CUtlVector< int >& list );
|
|
virtual void GenerateDragDataForItem( int itemIndex, KeyValues *msg );
|
|
virtual void GenerateContextMenu( int itemIndex, int x, int y );
|
|
virtual void GenerateChildrenOfNode(int itemIndex);
|
|
|
|
virtual void RemoveItem(int itemIndex, bool bPromoteChildren, bool bRecursivelyRemove = false );
|
|
virtual void RemoveAll();
|
|
|
|
virtual void ApplySchemeSettings( IScheme *pScheme );
|
|
virtual void PaintBackground();
|
|
virtual void PerformLayout();
|
|
|
|
virtual void OnTick();
|
|
|
|
virtual void OnMousePressed( MouseCode code );
|
|
|
|
// Item add helpers
|
|
int AddAnimationSetToTree( CDmeAnimationSet *pAnimSet );
|
|
int AddControlGroupToTree( int parentIndex, CDmeControlGroup *pControlGroup, CDmeControlGroup *pParentGroup, CDmeAnimationSet *pAnimSet );
|
|
int AddControlToTree( int parentIndex, CDmElement *pControl, CDmeControlGroup *pControlGroup, CDmeAnimationSet *pAnimSet );
|
|
void AddTransformComponentsToTree( int parentIndex, CDmeTransformControl *pTransformControl, CDmeControlGroup *pControlGroup, CDmeAnimationSet *pAnimSet, TransformComponent_t nComponentFlags );
|
|
|
|
CDmElement *GetTreeItemData( int nTreeIndex, AnimTreeItemType_t *pItemType = NULL,
|
|
CDmeAnimationSet **ppParentAnimationSet = NULL,
|
|
CDmeControlGroup **ppParentControlGroup = NULL ) const;
|
|
|
|
// Get the component flags associated with the specified item
|
|
TransformComponent_t GetItemComponentFlags( int nTreeIndex ) const;
|
|
|
|
// Get the control group associated with the specified tree item
|
|
CDmeControlGroup *GetControlGroupForTreeItem( int nTreeItemIndex ) const;
|
|
|
|
// Get the state icon set panel associated with the specified tree item
|
|
CAnimGroupStateIconSet *GetTreeItemStateIconSet( int nTreeItemIndex );
|
|
|
|
// Get the dag node associated with the specified tree item
|
|
CDmeDag *GetDagForTreeItem( int nTreeItemIndex ) const;
|
|
|
|
// Find the child of the specified item which has the specified element as its "handle" value
|
|
int FindChildItemForElement( int nParentIndex, const CDmElement *pElement, TransformComponent_t nComponentFlags = TRANSFORM_COMPONENT_NONE );
|
|
|
|
// Find the index of the the tree view item that has the specified element as its "handle" value
|
|
int FindItemForElement( const CDmElement *pElement, TransformComponent_t nComponentFlags = TRANSFORM_COMPONENT_NONE );
|
|
|
|
// Build the tree view items from the root down to the specified animation set
|
|
int BuildTreeToAnimationSet( CDmeAnimationSet *pAnimationSet );
|
|
|
|
// Build the tree view items from the root down to the specified control group
|
|
int BuildTreeToGroup( CDmeControlGroup *pGroup, CDmeAnimationSet *pAnimationSet );
|
|
|
|
// Build the tree view items from the root down to the specified control
|
|
void BuildTreeToControl( const CDmElement *pElement, TransformComponent_t nComponentFlags );
|
|
|
|
// Set the selection state on the specified item
|
|
void SetItemSelectionState( int nItemIndex, SelectionState_t selectionState );
|
|
|
|
// Get the selection state of the specified item
|
|
SelectionState_t GetItemSelectionState( int nItemIndex ) const;
|
|
|
|
// Get a list of the controls which are fully selected and whose parents are not fully selected
|
|
void GetSelectionRootItems( CUtlVector< int > &selectedItems ) const;
|
|
|
|
private:
|
|
|
|
MESSAGE_FUNC( OnClearWorkCameraParent, "ClearWorkCameraParent" );
|
|
MESSAGE_FUNC_INT( OnResetTransformPivot, "OnResetTransformPivot", viewCenter );
|
|
MESSAGE_FUNC_PARAMS( OnToggleDagLock, "ToggleDagLock", params );
|
|
MESSAGE_FUNC_PARAMS( OnSetOverrideParent, "SetOverrideParent", params );
|
|
MESSAGE_FUNC_PARAMS( OnOpenLockContextMenu, "OpenLockContextMenu", params );
|
|
|
|
|
|
void CleanupContextMenu();
|
|
|
|
virtual void OnContextMenuSelection( int itemIndex );
|
|
|
|
int AddItemToTree(
|
|
AnimTreeItemType_t itemType,
|
|
const char *label,
|
|
int parentIndex,
|
|
const Color& fg,
|
|
CDmElement *pElement,
|
|
CDmeAnimationSet *pAnimSet,
|
|
CDmeControlGroup *pControlGroup,
|
|
bool bExpandable,
|
|
SelectionState_t selection,
|
|
TransformComponent_t nComponentFlags );
|
|
|
|
Color ModifyColorByGroupState( const Color &baseColor, CDmeControlGroup *pControlGroup );
|
|
void AddDmeControlGroup( int nParentItemIndex, CDmeAnimationSet *pAnimationSet, CDmeControlGroup *pGroup );
|
|
bool VisibleControlsBelow_R( CDmeControlGroup *pGroup );
|
|
|
|
static bool CanAddDragIntoGroup( const CDmeControlGroup *pTargetGroup, const CDmElement *pTargetElement, const CDmElement *pDragElement, bool bInsertBefore );
|
|
|
|
static SelectionState_t GetSelectionStateForFlags( int nBaseFlags, int nSelectionFlags );
|
|
|
|
vgui::DHANDLE< vgui::Menu > m_hContextMenu;
|
|
CBaseAnimSetControlGroupPanel *m_pGroupPanel;
|
|
|
|
Button *m_pWorkCameraParentButton;
|
|
ImageList m_Images;
|
|
int m_StateIconIndices[ STATE_ICON_COUNT ];
|
|
|
|
Color m_RootColor;
|
|
Color m_StateColumnColor;
|
|
int m_nStateColumnWidth;
|
|
bool m_bStateInterface;
|
|
};
|
|
|
|
CAnimGroupTree::CAnimGroupTree( Panel *parent, const char *panelName, CBaseAnimSetControlGroupPanel *groupPanel, bool bStateInterface ) :
|
|
BaseClass( parent, panelName ),
|
|
m_pGroupPanel( groupPanel ),
|
|
m_Images( false ),
|
|
m_RootColor( 128, 128, 128, 255 ),
|
|
m_StateColumnColor( 0, 0, 0, 0 ),
|
|
m_nStateColumnWidth( 0 ),
|
|
m_bStateInterface( bStateInterface )
|
|
{
|
|
if ( m_bStateInterface )
|
|
{
|
|
m_nStateColumnWidth = 20;
|
|
SetTreeIndent( m_nStateColumnWidth - 2 );
|
|
}
|
|
|
|
SetShowRootNode( false );
|
|
SetDragEnabledItems( true );
|
|
SetAllowLabelEditing( true );
|
|
SetEnableInsertDropLocation( true );
|
|
|
|
m_pWorkCameraParentButton = new Button( this, "workCameraParent", "" );
|
|
m_pWorkCameraParentButton->SetVisible( false );
|
|
m_pWorkCameraParentButton->AddActionSignalTarget( this );
|
|
m_pWorkCameraParentButton->SetCommand( new KeyValues( "ClearWorkCameraParent" ) );
|
|
m_pWorkCameraParentButton->SetKeyBoardInputEnabled( false );
|
|
|
|
m_StateIconIndices[ STATE_ICON_WORK_CAMERA_PARENT_ACTIVE ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_referenceframe_active", false ) );
|
|
m_StateIconIndices[ STATE_ICON_WORK_CAMERA_PARENT_HIDDEN ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_referenceframe_active_hidden", false ) );
|
|
m_StateIconIndices[ STATE_ICON_DAG_LOCKED ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_dag_locked", false ) );
|
|
m_StateIconIndices[ STATE_ICON_DAG_LOCKED_PARTIAL ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_dag_locked_grey", false ) );
|
|
m_StateIconIndices[ STATE_ICON_DAG_LOCKED_WORLD ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_dag_locked_world", false ) );
|
|
m_StateIconIndices[ STATE_ICON_DAG_LOCKED_WORLD_PARTIAL ] = m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_dag_locked_world_grey", false ) );
|
|
|
|
ivgui()->AddTickSignal( GetVPanel(), 0 );
|
|
}
|
|
|
|
CAnimGroupTree::~CAnimGroupTree()
|
|
{
|
|
CleanupContextMenu();
|
|
}
|
|
|
|
void CAnimGroupTree::ApplySchemeSettings( IScheme *pScheme )
|
|
{
|
|
BaseClass::ApplySchemeSettings( pScheme );
|
|
m_RootColor = pScheme->GetColor( "AnimSet.RootColor", Color( 128, 128, 128, 255 ) );
|
|
m_StateColumnColor = pScheme->GetColor( "Frame.BgColor", Color( 0, 0, 0, 0 ) );
|
|
SetFont( pScheme->GetFont( "DefaultBold", IsProportional() ) );
|
|
}
|
|
|
|
int CAnimGroupTree::AddAnimationSetToTree( CDmeAnimationSet *pAnimSet )
|
|
{
|
|
// Don't add the animation set if the root control group is not visible
|
|
CDmeControlGroup *pRootGroup = pAnimSet->GetRootControlGroup();
|
|
if ( !m_pGroupPanel->m_pController->IsControlGroupVisible( pRootGroup ) )
|
|
return -1;
|
|
|
|
int parentIndex = GetRootItemIndex();
|
|
SelectionState_t selection = m_pGroupPanel->m_pController->GetSelectionState( pAnimSet );
|
|
|
|
Color groupColor = ModifyColorByGroupState( m_RootColor, pRootGroup );
|
|
|
|
return AddItemToTree( ANIMTREE_ITEM_ANIMSET, pAnimSet->GetName(), parentIndex, groupColor, pAnimSet, pAnimSet, NULL, true, selection, TRANSFORM_COMPONENT_NONE );
|
|
}
|
|
|
|
int CAnimGroupTree::AddControlGroupToTree( int parentIndex, CDmeControlGroup *pControlGroup, CDmeControlGroup *pParentGroup, CDmeAnimationSet *pAnimSet )
|
|
{
|
|
SelectionState_t selection = m_pGroupPanel->m_pController->GetSelectionState( pControlGroup );
|
|
|
|
Color groupColor = ModifyColorByGroupState( pControlGroup->GroupColor(), pControlGroup );
|
|
|
|
return AddItemToTree( ANIMTREE_ITEM_GROUP, pControlGroup->GetName(), parentIndex, groupColor, pControlGroup, pAnimSet, pParentGroup, true, selection, TRANSFORM_COMPONENT_NONE );
|
|
}
|
|
|
|
int CAnimGroupTree::AddControlToTree( int parentIndex, CDmElement *pControl, CDmeControlGroup *pControlGroup, CDmeAnimationSet *pAnimSet )
|
|
{
|
|
SelectionState_t selection = m_pGroupPanel->m_pController->GetSelectionState( pControl );
|
|
bool bTransformControl = pControl->IsA( CDmeTransformControl::GetStaticTypeSymbol() );
|
|
TransformComponent_t nComponentFlags = bTransformControl ? TRANSFORM_COMPONENT_ALL : TRANSFORM_COMPONENT_NONE;
|
|
|
|
Color controlColor = ModifyColorByGroupState( pControlGroup->ControlColor(), pControlGroup );
|
|
|
|
return AddItemToTree( ANIMTREE_ITEM_CONTROL, pControl->GetName(), parentIndex, controlColor, pControl, pAnimSet, pControlGroup, bTransformControl, selection, nComponentFlags );
|
|
}
|
|
|
|
|
|
SelectionState_t CAnimGroupTree::GetSelectionStateForFlags( int nBaseFlags, int nSelectionFlags )
|
|
{
|
|
int nMaskedFlags = nBaseFlags & nSelectionFlags;
|
|
|
|
if ( nMaskedFlags == nBaseFlags )
|
|
return SEL_ALL;
|
|
|
|
return ( ( nMaskedFlags > 0 ) ? SEL_SOME : SEL_NONE );
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::AddTransformComponentsToTree( int nParentIndex, CDmeTransformControl *pControl, CDmeControlGroup *pControlGroup, CDmeAnimationSet *pAnimSet, TransformComponent_t nParentComponentFlags )
|
|
{
|
|
int nSelectionFlags = m_pGroupPanel->m_pController->GetSelectionComponentFlags( pControl );
|
|
const char *pName = pControl->GetName();
|
|
|
|
Color color = ModifyColorByGroupState( pControlGroup->ControlColor(), pControlGroup );
|
|
|
|
if ( nParentComponentFlags == TRANSFORM_COMPONENT_ALL )
|
|
{
|
|
SelectionState_t posSelection = GetSelectionStateForFlags( TRANSFORM_COMPONENT_POSITION, nSelectionFlags );
|
|
SelectionState_t rotSelection = GetSelectionStateForFlags( TRANSFORM_COMPONENT_ROTATION, nSelectionFlags );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - pos", pName ), nParentIndex, color, pControl, pAnimSet, pControlGroup, true, posSelection, TRANSFORM_COMPONENT_POSITION );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - rot", pName ), nParentIndex, color, pControl, pAnimSet, pControlGroup, true, rotSelection, TRANSFORM_COMPONENT_ROTATION );
|
|
}
|
|
else if ( nParentComponentFlags == TRANSFORM_COMPONENT_POSITION )
|
|
{
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - pos.x", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_POSITION_X, nSelectionFlags ), TRANSFORM_COMPONENT_POSITION_X );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - pos.y", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_POSITION_Y, nSelectionFlags ), TRANSFORM_COMPONENT_POSITION_Y );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - pos.z", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_POSITION_Z, nSelectionFlags ), TRANSFORM_COMPONENT_POSITION_Z );
|
|
}
|
|
else if ( nParentComponentFlags == TRANSFORM_COMPONENT_ROTATION )
|
|
{
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - rot.x", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_ROTATION_X, nSelectionFlags ), TRANSFORM_COMPONENT_ROTATION_X );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - rot.y", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_ROTATION_Y, nSelectionFlags ), TRANSFORM_COMPONENT_ROTATION_Y );
|
|
AddItemToTree( ANIMTREE_ITEM_COMPONENT, CFmtStr( "%s - rot.z", pName ), nParentIndex, color, pControl, pAnimSet, NULL, false, GetSelectionStateForFlags( TRANSFORM_COMPONENT_ROTATION_Z, nSelectionFlags ), TRANSFORM_COMPONENT_ROTATION_Z );
|
|
}
|
|
}
|
|
|
|
|
|
Color CAnimGroupTree::ModifyColorByGroupState( const Color &baseColor, CDmeControlGroup *pControlGroup )
|
|
{
|
|
Color groupColor = baseColor;
|
|
int nAlpha = ( pControlGroup->IsSelectable() && pControlGroup->IsVisible() ) ? 255 : 64;
|
|
groupColor.SetColor( groupColor.r(), groupColor.g(), groupColor.b(), nAlpha );
|
|
return groupColor;
|
|
}
|
|
|
|
|
|
int CAnimGroupTree::AddItemToTree( AnimTreeItemType_t itemType, const char *label, int parentIndex, const Color& fg, CDmElement *pElement, CDmeAnimationSet *pAnimSet, CDmeControlGroup *pControlGroup, bool bExpandable, SelectionState_t selection, TransformComponent_t nComponentFlags )
|
|
{
|
|
DmElementHandle_t hElement = pElement ? pElement->GetHandle() : DMELEMENT_HANDLE_INVALID;
|
|
DmElementHandle_t hAnimSet = pAnimSet ? pAnimSet->GetHandle() : DMELEMENT_HANDLE_INVALID;
|
|
DmElementHandle_t hControlGroup = pControlGroup ? pControlGroup->GetHandle() : DMELEMENT_HANDLE_INVALID;
|
|
|
|
KeyValues *kv = new KeyValues( "item", "text", label );
|
|
kv->SetInt( "droppable", 1 );
|
|
kv->SetInt( "itemType", ( int )itemType );
|
|
kv->SetInt( "handle", ( int )hElement );
|
|
kv->SetInt( "animset", ( int )hAnimSet );
|
|
kv->SetInt( "controlgroup", ( int )hControlGroup );
|
|
kv->SetInt( "selection", ( int )selection );
|
|
kv->SetInt( "componentFlags", ( int )nComponentFlags );
|
|
kv->SetInt( "Expand", bExpandable ? 1 : 0 );
|
|
|
|
CDmeTransformControl *pTransformControl = CastElement< CDmeTransformControl >( pElement );
|
|
CDmeTransform *pTransform = ( pTransformControl != NULL ) ? pTransformControl->GetTransform() : NULL;
|
|
|
|
CDmeDag *pDag = ( pTransform != NULL ) ? pTransform->GetDag() : NULL;
|
|
|
|
if ( m_bStateInterface )
|
|
{
|
|
StateIconSetType_t stateIconSetType = STATE_ICON_SET_INVALID;
|
|
|
|
if ( itemType == ANIMTREE_ITEM_COMPONENT )
|
|
{
|
|
if ( nComponentFlags == TRANSFORM_COMPONENT_POSITION )
|
|
{
|
|
stateIconSetType = STATE_ICON_SET_CONTROL_POSITION;
|
|
}
|
|
else if ( nComponentFlags == TRANSFORM_COMPONENT_ROTATION )
|
|
{
|
|
stateIconSetType = STATE_ICON_SET_CONTROL_ROTATION;
|
|
}
|
|
}
|
|
else if ( itemType == ANIMTREE_ITEM_CONTROL )
|
|
{
|
|
stateIconSetType = STATE_ICON_SET_GROUP;
|
|
}
|
|
|
|
if ( pDag && ( stateIconSetType != STATE_ICON_SET_INVALID ) )
|
|
{
|
|
CAnimGroupStateIconSet *pIconSet = new CAnimGroupStateIconSet( this, label, stateIconSetType, pDag, m_Images, m_StateIconIndices );
|
|
kv->SetPtr( "stateIconSet", pIconSet );
|
|
}
|
|
}
|
|
|
|
int idx = AddItem( kv, parentIndex );
|
|
SetItemFgColor( idx, fg );
|
|
SetItemSelectionTextColor( idx, fg );
|
|
|
|
|
|
SetSilentMode( true );
|
|
|
|
if ( selection == SEL_ALL || selection == SEL_SOME )
|
|
{
|
|
Color color = ( selection == SEL_ALL ) ? Color( 128, 128, 128, 128 ) : Color( 128, 128, 64, 64 );
|
|
SetItemSelectionBgColor( idx, color );
|
|
SetItemSelectionUnfocusedBgColor( idx, color );
|
|
AddSelectedItem( idx, false, false, true );
|
|
}
|
|
else
|
|
{
|
|
Color color( 0, 0, 0, 128 );
|
|
SetItemSelectionBgColor( idx, color );
|
|
SetItemSelectionUnfocusedBgColor( idx, color );
|
|
RemoveSelectedItem( idx );
|
|
}
|
|
|
|
|
|
if ( ( itemType == ANIMTREE_ITEM_GROUP ) || ( itemType == ANIMTREE_ITEM_ANIMSET ) )
|
|
{
|
|
SetLabelEditingAllowed( idx, true );
|
|
}
|
|
|
|
SetSilentMode( false );
|
|
|
|
ExpandItem( idx, false );
|
|
|
|
kv->deleteThis();
|
|
|
|
return idx;
|
|
}
|
|
|
|
CDmElement *CAnimGroupTree::GetTreeItemData( int nTreeIndex, AnimTreeItemType_t *pItemType /*= NULL */,
|
|
CDmeAnimationSet **ppParentAnimationSet /*= NULL*/,
|
|
CDmeControlGroup **ppControlGroup /*= NULL*/ ) const
|
|
{
|
|
KeyValues *kv = GetItemData( nTreeIndex );
|
|
if ( !kv )
|
|
return NULL;
|
|
|
|
if ( pItemType )
|
|
{
|
|
*pItemType = static_cast< AnimTreeItemType_t >( kv->GetInt( "itemType" ) );
|
|
}
|
|
|
|
if ( ppParentAnimationSet )
|
|
{
|
|
*ppParentAnimationSet = GetElementKeyValue< CDmeAnimationSet >( kv, "animset" );
|
|
}
|
|
|
|
if ( ppControlGroup )
|
|
{
|
|
*ppControlGroup = GetElementKeyValue< CDmeControlGroup >( kv, "controlgroup" );
|
|
}
|
|
|
|
return GetElementKeyValue< CDmElement >( kv, "handle" );
|
|
}
|
|
|
|
|
|
TransformComponent_t CAnimGroupTree::GetItemComponentFlags( int nTreeIndex ) const
|
|
{
|
|
KeyValues *kv = GetItemData( nTreeIndex );
|
|
return static_cast< TransformComponent_t >( kv->GetInt( "componentFlags" ) );
|
|
}
|
|
|
|
|
|
CDmeControlGroup *CAnimGroupTree::GetControlGroupForTreeItem( int nItemIndex ) const
|
|
{
|
|
CDmElement *pElement = GetTreeItemData( nItemIndex, NULL );
|
|
|
|
CDmeControlGroup *pControlGroup = NULL;
|
|
const CDmeAnimationSet *pAnimationSet = CastElement< CDmeAnimationSet >( pElement );
|
|
|
|
if ( pAnimationSet )
|
|
{
|
|
pControlGroup = pAnimationSet->GetRootControlGroup();
|
|
}
|
|
else
|
|
{
|
|
pControlGroup = CastElement< CDmeControlGroup >( pElement );
|
|
}
|
|
|
|
return pControlGroup;
|
|
}
|
|
|
|
|
|
CAnimGroupStateIconSet *CAnimGroupTree::GetTreeItemStateIconSet( int nTreeIndex )
|
|
{
|
|
KeyValues *kv = GetItemData( nTreeIndex );
|
|
if ( !kv )
|
|
return NULL;
|
|
|
|
return static_cast< CAnimGroupStateIconSet * >( kv->GetPtr( "stateIconSet" ) );
|
|
}
|
|
|
|
|
|
CDmeDag *CAnimGroupTree::GetDagForTreeItem( int nTreeItemIndex ) const
|
|
{
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = GetTreeItemData( nTreeItemIndex, &itemType );
|
|
|
|
if ( !pElement && itemType != ANIMTREE_ITEM_GROUP )
|
|
return NULL;
|
|
|
|
CDmeTransformControl *pTransformControl = CastElement< CDmeTransformControl >( pElement );
|
|
if ( pTransformControl == NULL )
|
|
return NULL;
|
|
|
|
CDmeTransform *pTransform = pTransformControl->GetTransform();
|
|
|
|
if ( !pTransform )
|
|
return NULL;
|
|
|
|
return pTransform->GetDag();
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::CleanupContextMenu()
|
|
{
|
|
if ( m_hContextMenu.Get() )
|
|
{
|
|
delete m_hContextMenu.Get();
|
|
m_hContextMenu = NULL;
|
|
}
|
|
}
|
|
|
|
bool CAnimGroupTree::CanAddDragIntoGroup( const CDmeControlGroup *pTargetGroup, const CDmElement *pTargetElement, const CDmElement *pDragElement, bool bInsertBefore )
|
|
{
|
|
const static CUtlSymbolLarge symControls = g_pDataModel->GetSymbol( "controls" );
|
|
|
|
if ( ( pTargetGroup == NULL ) || ( pDragElement == NULL ) || ( pTargetElement == NULL ) )
|
|
return false;
|
|
|
|
// Cannot drag a group into itself
|
|
if ( pDragElement == pTargetGroup )
|
|
return false;
|
|
|
|
CDmeAnimationSet *pTargetGroupAnimSet = pTargetGroup->FindAnimationSet( true );
|
|
CDmeAnimationSet *pDragGroupAnimSet = NULL;
|
|
|
|
const CDmeControlGroup *pDragGroup = CastElement< CDmeControlGroup >( pDragElement );
|
|
|
|
bool bTargetElenentIsGroup = pTargetElement->IsA( CDmeControlGroup::GetStaticTypeSymbol() );
|
|
|
|
if ( pDragGroup )
|
|
{
|
|
// Cannot drag a group into a group that already exists in its sub-tree
|
|
if ( pDragGroup->IsAncestorOfGroup( pTargetGroup ) )
|
|
return false;
|
|
|
|
// Cannot insert a group before a control
|
|
if ( bInsertBefore && !bTargetElenentIsGroup )
|
|
return false;
|
|
|
|
CDmeControlGroup *pDragGroupParent = pDragGroup->FindParent();
|
|
pDragGroupAnimSet = ( pDragGroupParent != NULL ) ? pDragGroupParent->FindAnimationSet( true ) : NULL;
|
|
}
|
|
else
|
|
{
|
|
// Cannot insert a control before a group
|
|
if ( bInsertBefore && bTargetElenentIsGroup )
|
|
return false;
|
|
|
|
// Find the animation set to which the control belongs
|
|
pDragGroupAnimSet = FindReferringElement< CDmeAnimationSet >( pDragElement, symControls );
|
|
}
|
|
|
|
// If a control group is in the sub-tree of an animation set it must remain in the sub-tree of that animation set,
|
|
// it is not in the sub-tree of an animation set it must not be added to the sub-tree of any other animation set.
|
|
if ( pDragGroupAnimSet != pTargetGroupAnimSet )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CAnimGroupTree::IsItemDroppable( int nItemIndex, bool bInsertBefore, CUtlVector< KeyValues * >& msglist )
|
|
{
|
|
if ( msglist.Count() == 0 )
|
|
return false;
|
|
|
|
CDmeControlGroup *pParentControlGroup = NULL;
|
|
CDmElement *pTargetElement = GetTreeItemData( nItemIndex, NULL, NULL, &pParentControlGroup );
|
|
if ( pTargetElement == NULL )
|
|
return false;
|
|
|
|
CDmeControlGroup *pTargetControlGroup = GetControlGroupForTreeItem( nItemIndex );
|
|
const CDmeControlGroup *pNewParentGroup = bInsertBefore ? pParentControlGroup : pTargetControlGroup;
|
|
|
|
// See if there are any messages in the list that will apply to the control group
|
|
int nMsgCount = msglist.Count();
|
|
for ( int iMsg = 0; iMsg < nMsgCount; ++iMsg )
|
|
{
|
|
KeyValues *pData = msglist[ iMsg ];
|
|
if ( pData == NULL )
|
|
continue;
|
|
|
|
if ( pData->FindKey( "color" ) )
|
|
{
|
|
if ( pTargetControlGroup != NULL )
|
|
return true;
|
|
}
|
|
|
|
const CDmElement *pDragElement = GetElementKeyValue< CDmElement >( pData, "dmeelement" );
|
|
if ( CanAddDragIntoGroup( pNewParentGroup, pTargetElement, pDragElement, bInsertBefore ) )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CAnimGroupTree::OnItemDropped( int nItemIndex, bool bInsertBefore, CUtlVector< KeyValues * >& msglist )
|
|
{
|
|
if ( !IsItemDroppable( nItemIndex, bInsertBefore, msglist ) )
|
|
return;
|
|
|
|
CDmeControlGroup *pParentControlGroup = NULL;
|
|
CDmeAnimationSet *pTargetAnimSet = NULL;
|
|
CDmElement *pTargetElement = GetTreeItemData( nItemIndex, NULL, &pTargetAnimSet, &pParentControlGroup );
|
|
if ( pTargetElement == NULL )
|
|
return;
|
|
|
|
CDmeControlGroup *pTargetControlGroup = GetControlGroupForTreeItem( nItemIndex );
|
|
CDmeControlGroup *pNewParentGroup = bInsertBefore ? pParentControlGroup : pTargetControlGroup;
|
|
|
|
CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Drop onto control group" );
|
|
|
|
int nMsgCount = msglist.Count();
|
|
for ( int iMsg = 0; iMsg < nMsgCount; ++iMsg )
|
|
{
|
|
KeyValues *pData = msglist[ iMsg ];
|
|
if ( pData == NULL )
|
|
continue;
|
|
|
|
if ( pData->FindKey( "color" ) )
|
|
{
|
|
Color clr = pData->GetColor( "color" );
|
|
SetItemFgColor( nItemIndex, clr );
|
|
SetItemSelectionTextColor( nItemIndex, clr );
|
|
pTargetControlGroup->SetGroupColor( clr, false );
|
|
}
|
|
|
|
|
|
CDmElement *pDragElement = GetElementKeyValue< CDmElement >( pData, "dmeelement" );
|
|
if ( CanAddDragIntoGroup( pNewParentGroup, pTargetElement, pDragElement, bInsertBefore ) )
|
|
{
|
|
CDmeControlGroup *pDragGroup = CastElement< CDmeControlGroup >( pDragElement );
|
|
if ( pDragGroup )
|
|
{
|
|
pNewParentGroup->AddChild( pDragGroup, ( bInsertBefore ? pTargetControlGroup : NULL ) );
|
|
}
|
|
else
|
|
{
|
|
pNewParentGroup->AddControl( pDragElement, ( bInsertBefore ? pTargetElement : NULL ) );
|
|
}
|
|
|
|
if ( pTargetAnimSet )
|
|
{
|
|
CDmeControlGroup *pRootControlGroup = pTargetAnimSet->GetRootControlGroup();
|
|
if ( pRootControlGroup )
|
|
{
|
|
pRootControlGroup->DestroyEmptyChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::GetSelectedItemsForDrag( int nPrimaryDragItem, CUtlVector< int >& list )
|
|
{
|
|
// The item actually being dragged will be the first item in the selection list,
|
|
// since ancestors of this primary item may also be in the selection we can't
|
|
// drag the whole selection, but we do want to drag the siblings of the item.
|
|
// So iterate the selection and add any siblings of the primary selected item.
|
|
|
|
CUtlVector< int > selectedItems;
|
|
GetSelectedItems( selectedItems );
|
|
|
|
int nNumSelected = selectedItems.Count();
|
|
if ( nNumSelected <= 0 )
|
|
return;
|
|
|
|
AnimTreeItemType_t itemType;
|
|
CDmeControlGroup *pPrimaryParentGroup = NULL;
|
|
GetTreeItemData( nPrimaryDragItem, &itemType, NULL, &pPrimaryParentGroup );
|
|
|
|
if ( itemType == ANIMTREE_ITEM_COMPONENT )
|
|
return;
|
|
|
|
for ( int i = 0 ; i < nNumSelected; ++i )
|
|
{
|
|
CDmeControlGroup *pParentGroup = NULL;
|
|
GetTreeItemData( selectedItems[ i ], &itemType, NULL, &pParentGroup );
|
|
|
|
if ( ( pPrimaryParentGroup == pParentGroup ) && ( itemType != ANIMTREE_ITEM_COMPONENT ) )
|
|
{
|
|
list.AddToTail( selectedItems[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAnimGroupTree::GenerateDragDataForItem( int nItemIndex, KeyValues *msg )
|
|
{
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = GetTreeItemData( nItemIndex, &itemType );
|
|
|
|
if ( ( pElement ) && ( itemType != ANIMTREE_ITEM_COMPONENT ) )
|
|
{
|
|
msg->SetInt( "dmeelement", pElement->GetHandle() );
|
|
}
|
|
}
|
|
|
|
bool CAnimGroupTree::CanCurrentlyEditLabel( int nItemIndex ) const
|
|
{
|
|
// The item must still be in the selection
|
|
if ( IsItemSelected( nItemIndex ) == false )
|
|
return false;
|
|
|
|
// Parents or children of the item may be selected, but siblings must not be selected.
|
|
int nParentIndex = GetItemParent( nItemIndex );
|
|
|
|
CUtlVector< int > selectedItems;
|
|
GetSelectedItems( selectedItems );
|
|
|
|
int nSelectedItems = selectedItems.Count();
|
|
for ( int iItem = 0; iItem < nSelectedItems; ++iItem )
|
|
{
|
|
int nSelectedItem = selectedItems[ iItem ];
|
|
if ( nItemIndex == nSelectedItem )
|
|
continue;
|
|
|
|
if ( GetItemParent( nSelectedItem) == nParentIndex )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnLabelChanged( int nItemIndex, char const *pOldString, char const *pNewString )
|
|
{
|
|
CUndoScopeGuard undoSg( "Change group label" );
|
|
|
|
CDmElement *pElement = GetTreeItemData( nItemIndex );
|
|
CDmeControlGroup *pControlGroup = CastElement< CDmeControlGroup >( pElement );
|
|
CDmeAnimationSet *pAnimationSet = CastElement< CDmeAnimationSet >( pElement );
|
|
|
|
if ( pControlGroup )
|
|
{
|
|
CDmeControlGroup *pRootGroup = pControlGroup->FindRootControlGroup();
|
|
if ( pRootGroup && pRootGroup->FindChildByName( pNewString, true ) )
|
|
{
|
|
CUtlVector< DmElementHandle_t > childList;
|
|
pRootGroup->GetAllChildren( childList );
|
|
|
|
int nIndex = GenerateUniqueNameIndex( pNewString, childList, 0 );
|
|
CFmtStr newName( "%s%d", pNewString, nIndex );
|
|
pControlGroup->SetName( newName.Access() );
|
|
|
|
// Force the tree display to update to reflect the modified name
|
|
m_pGroupPanel->RebuildTree( true );
|
|
}
|
|
else
|
|
{
|
|
pControlGroup->SetName( pNewString );
|
|
}
|
|
}
|
|
else if ( pAnimationSet )
|
|
{
|
|
KeyValues *pMsgKV = new KeyValues( "SetAnimationSetName", "text", pNewString );
|
|
SetElementKeyValue( pMsgKV, "animset", pAnimationSet );
|
|
PostMessage( m_pGroupPanel->GetEditor(), pMsgKV, 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 )
|
|
{
|
|
PostMessage( GetParent(), new KeyValues( "TreeViewOpenContextMenu", "itemID", itemIndex ), 0.0f );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Override the default right click selection behavior so that the
|
|
// clicked item becomes the first selected item.
|
|
//-----------------------------------------------------------------------------
|
|
void CAnimGroupTree::OnContextMenuSelection( int itemIndex )
|
|
{
|
|
// Select the item, if it was already selected
|
|
// this should make it the first selected item.
|
|
AddSelectedItem( itemIndex, !IsItemSelected( itemIndex ) );
|
|
Assert( GetFirstSelectedItem() == itemIndex );
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnClearWorkCameraParent()
|
|
{
|
|
m_pGroupPanel->m_pController->SetWorkCameraParent( NULL );
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnResetTransformPivot( int viewCenter )
|
|
{
|
|
PostMessage( m_pGroupPanel->GetEditor(), new KeyValues( "ResetTransformPivot", "viewCenter", viewCenter ), 0.0f );
|
|
}
|
|
|
|
void CAnimGroupTree::OnToggleDagLock( KeyValues *pParams )
|
|
{
|
|
PostMessage( m_pGroupPanel->GetEditor(), pParams->MakeCopy(), 0.0f );
|
|
|
|
// Cause perform layout to be run so that the lock icons
|
|
// are updated after the message has been processed.
|
|
InvalidateLayout();
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnSetOverrideParent( KeyValues *pParams )
|
|
{
|
|
PostMessage( m_pGroupPanel->GetEditor(), pParams->MakeCopy(), 0.0f );
|
|
InvalidateLayout();
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnOpenLockContextMenu( KeyValues *pParams )
|
|
{
|
|
PostMessage( m_pGroupPanel->GetEditor(), pParams->MakeCopy(), 0.0f );
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::OnMousePressed( MouseCode code )
|
|
{
|
|
int mx, my;
|
|
input()->GetCursorPos( mx, my );
|
|
ScreenToLocal( mx, my );
|
|
int idx = FindItemUnderMouse( mx, my );
|
|
|
|
// The default tree behavior ignores the width of the item when testing against the mouse. For
|
|
// the animation set editor only the actual are of the item should be considered under the mouse.
|
|
if ( IsItemIDValid( idx ) )
|
|
{
|
|
int xPos, yPos, width, height;
|
|
GetItemBounds( idx, xPos, yPos, width, height );
|
|
|
|
if ( ( mx < xPos ) || ( my < yPos ) || ( mx > ( xPos + width ) ) || ( my > ( yPos + height) ) )
|
|
{
|
|
idx = -1;
|
|
}
|
|
}
|
|
|
|
bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
|
|
if ( !ctrl )
|
|
{
|
|
if ( code == MOUSE_RIGHT )
|
|
{
|
|
PostMessage( GetParent(), new KeyValues( "TreeViewOpenContextMenu", "itemID", idx ), 0.0f );
|
|
}
|
|
else
|
|
{
|
|
BaseClass::OnMousePressed( code );
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( !IsItemIDValid( idx ) || ( mx >= ( 20 + m_nStateColumnWidth ) ) )
|
|
{
|
|
BaseClass::OnMousePressed( code );
|
|
return;
|
|
}
|
|
|
|
|
|
CDmeTransformControl *pTransformControl = CastElement< CDmeTransformControl >( GetTreeItemData( idx ) );
|
|
if ( pTransformControl )
|
|
{
|
|
CDmeDag *pDag = pTransformControl->GetDag();
|
|
m_pGroupPanel->m_pController->SetWorkCameraParent( pDag );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::PaintBackground()
|
|
{
|
|
BaseClass::PaintBackground();
|
|
|
|
if ( m_bStateInterface )
|
|
{
|
|
int nHeight = GetTall();
|
|
vgui::surface()->DrawSetColor( m_StateColumnColor );
|
|
vgui::surface()->DrawFilledRect( 0, 0, m_nStateColumnWidth, nHeight );
|
|
}
|
|
}
|
|
|
|
|
|
void CAnimGroupTree::PerformLayout()
|
|
{
|
|
BaseClass::PerformLayout();
|
|
|
|
for ( int itemID = FirstItem(); itemID != InvalidItemID(); itemID = NextItem( itemID ) )
|
|
{
|
|
CAnimGroupStateIconSet *pIconSet = GetTreeItemStateIconSet( itemID );
|
|
if ( pIconSet == NULL )
|
|
continue;
|
|
|
|
int nPosX, nPosY, nWidth, nHeight;
|
|
if ( GetItemBounds( itemID, nPosX, nPosY, nWidth, nHeight ) )
|
|
{
|
|
pIconSet->UpdateState();
|
|
pIconSet->SetBounds( 0, nPosY, nHeight, nHeight );
|
|
pIconSet->SetVisible( true );
|
|
}
|
|
else
|
|
{
|
|
pIconSet->SetVisible( false );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void CAnimGroupTree::OnTick()
|
|
{
|
|
BaseClass::OnTick();
|
|
|
|
int nWorkCameraParentItem = -1;
|
|
|
|
if ( CDmeDag *pWorkCameraParent = m_pGroupPanel->GetWorkCameraParent() )
|
|
{
|
|
for ( int itemID = FirstItem(); itemID != InvalidItemID(); itemID = NextItem( itemID ) )
|
|
{
|
|
CDmeDag *pDag = GetDagForTreeItem( itemID );
|
|
if ( pDag == pWorkCameraParent )
|
|
{
|
|
nWorkCameraParentItem = itemID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pWorkCameraParentButton->SetVisible( nWorkCameraParentItem != -1 );
|
|
if ( nWorkCameraParentItem != -1 )
|
|
{
|
|
int x = 0, y = 0, w = 0, h = 0;
|
|
GetItemBounds( nWorkCameraParentItem, x, y, w, h );
|
|
m_pWorkCameraParentButton->SetBounds( 1 + m_nStateColumnWidth, y + 1, h - 2, h - 2 );
|
|
m_pWorkCameraParentButton->ClearImages();
|
|
m_pWorkCameraParentButton->AddImage( m_Images.GetImage( m_StateIconIndices[ STATE_ICON_WORK_CAMERA_PARENT_ACTIVE ] ), 0 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CAnimGroupTree::RemoveItem( int itemIndex, bool bPromoteChildren, bool bRecursivelyRemove )
|
|
{
|
|
// The tree view implementation uses negative item indices to indicate
|
|
// recursion, here we don't care, we just want the current item being removed.
|
|
int nActualIndex = ( itemIndex < 0 ) ? -itemIndex : itemIndex;
|
|
|
|
CAnimGroupStateIconSet *pIconSet = GetTreeItemStateIconSet( nActualIndex );
|
|
|
|
if ( pIconSet )
|
|
{
|
|
delete pIconSet;
|
|
}
|
|
|
|
BaseClass::RemoveItem( itemIndex, bPromoteChildren, bRecursivelyRemove );
|
|
}
|
|
|
|
void CAnimGroupTree::RemoveAll()
|
|
{
|
|
for ( int itemID = FirstItem(); itemID != InvalidItemID(); itemID = NextItem( itemID ) )
|
|
{
|
|
CAnimGroupStateIconSet *pIconSet = GetTreeItemStateIconSet( itemID );
|
|
if ( pIconSet )
|
|
{
|
|
delete pIconSet;
|
|
}
|
|
}
|
|
|
|
BaseClass::RemoveAll();
|
|
}
|
|
|
|
|
|
bool CAnimGroupTree::VisibleControlsBelow_R( CDmeControlGroup *pGroup )
|
|
{
|
|
// If the group is not visible itself then it
|
|
// cannot have any visible controls below it.
|
|
if ( !m_pGroupPanel->m_pController->IsControlGroupVisible( pGroup ) )
|
|
return false;
|
|
|
|
// The group is visible and has controls itself then it has
|
|
// visible controls below it, no need to go farther.
|
|
if ( pGroup->Controls().Count() > 0 )
|
|
return true;
|
|
|
|
// If the group did not have any controls itself, check all of its children recursively,
|
|
// if any are visible and have controls then there are visible controls below this group.
|
|
const CDmaElementArray< CDmeControlGroup > &children = pGroup->Children();
|
|
int nNumChildren = children.Count();
|
|
for ( int iChild = 0; iChild < nNumChildren; ++iChild )
|
|
{
|
|
CDmeControlGroup *pChild = children[ iChild ];
|
|
if ( pChild == NULL )
|
|
continue;
|
|
|
|
if ( VisibleControlsBelow_R( pChild ) )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CAnimGroupTree::AddDmeControlGroup( int nParentItemIndex, CDmeAnimationSet *pAnimationSet, CDmeControlGroup *pGroup )
|
|
{
|
|
Assert( pGroup );
|
|
Assert( pAnimationSet );
|
|
|
|
// Add the sub-groups
|
|
const CDmaElementArray< CDmeControlGroup > &subGroups = pGroup->Children();
|
|
int nGroups = subGroups.Count();
|
|
for ( int iGroup = 0; iGroup < nGroups; ++iGroup )
|
|
{
|
|
CDmeControlGroup *pSubGroup = subGroups[ iGroup ];
|
|
if ( pSubGroup == NULL )
|
|
continue;
|
|
|
|
if ( !VisibleControlsBelow_R( pSubGroup ) )
|
|
continue;
|
|
|
|
AddControlGroupToTree( nParentItemIndex, pSubGroup, pGroup, pAnimationSet );
|
|
}
|
|
|
|
// Add the controls
|
|
const CDmaElementArray< CDmElement > &controls = pGroup->Controls();
|
|
int nControls = controls.Count();
|
|
for ( int iControl = 0; iControl < nControls; ++iControl )
|
|
{
|
|
CDmElement *pControl = controls[ iControl ];
|
|
if ( pControl )
|
|
{
|
|
AddControlToTree( nParentItemIndex, pControl, pGroup, pAnimationSet );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAnimGroupTree::GenerateChildrenOfNode(int itemIndex)
|
|
{
|
|
BaseClass::GenerateChildrenOfNode( itemIndex );
|
|
|
|
// Make sure the children are only generated once.
|
|
if ( GetNumChildren( itemIndex ) > 0 )
|
|
return;
|
|
|
|
if ( itemIndex == GetRootItemIndex() )
|
|
{
|
|
CDmeFilmClip *pFilmClip = m_pGroupPanel->m_pController->GetAnimationSetClip();
|
|
CAnimSetGroupAnimSetTraversal traversal( pFilmClip );
|
|
while ( CDmeAnimationSet *pAnimSet = traversal.Next() )
|
|
{
|
|
AddAnimationSetToTree( pAnimSet );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Get type for item
|
|
KeyValues *kv = GetItemData( itemIndex );
|
|
if ( kv )
|
|
{
|
|
AnimTreeItemType_t itemType = static_cast< AnimTreeItemType_t >( kv->GetInt( "itemType" ) );
|
|
|
|
CDmElement *pElement = GetElementKeyValue< CDmElement >( kv, "handle" );
|
|
CDmeAnimationSet *pAnimationSet = CastElement< CDmeAnimationSet >( GetElementKeyValue< CDmElement >( kv, "animset" ) );
|
|
CDmeControlGroup *pControlGroup = CastElement< CDmeControlGroup >( GetElementKeyValue< CDmElement >( kv, "controlgroup" ) );
|
|
TransformComponent_t nComponentFlags = static_cast< TransformComponent_t >( kv->GetInt( "componentFlags" ) );
|
|
|
|
switch ( itemType )
|
|
{
|
|
default:
|
|
break;
|
|
case ANIMTREE_ITEM_ANIMSET:
|
|
// Under anim set we get 1-N groups, expandable if they have children or controls
|
|
{
|
|
Assert( pAnimationSet );
|
|
|
|
CDmeControlGroup *pRootGroup = pAnimationSet->GetRootControlGroup();
|
|
AddDmeControlGroup( itemIndex, pAnimationSet, pRootGroup );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_GROUP:
|
|
// Under group we have subgroups and controls
|
|
{
|
|
Assert( pAnimationSet );
|
|
Assert( pElement );
|
|
CDmeControlGroup *pGroup = CastElement< CDmeControlGroup >( pElement );
|
|
Assert( pGroup );
|
|
AddDmeControlGroup( itemIndex, pAnimationSet, pGroup );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_CONTROL:
|
|
case ANIMTREE_ITEM_COMPONENT:
|
|
// Under transform controls are the position and rotation components
|
|
{
|
|
Assert( pControlGroup );
|
|
Assert( pAnimationSet );
|
|
Assert( pElement );
|
|
CDmeTransformControl *pTranformControl = CastElement< CDmeTransformControl >( pElement );
|
|
if ( pTranformControl )
|
|
{
|
|
AddTransformComponentsToTree( itemIndex, pTranformControl, pControlGroup, pAnimationSet, nComponentFlags );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Find the child of the specified item which has the specified element as its
|
|
// "handle" value
|
|
//-----------------------------------------------------------------------------
|
|
int CAnimGroupTree::FindChildItemForElement( int nParentIndex, const CDmElement *pElement, TransformComponent_t nComponentFlags )
|
|
{
|
|
int nChildren = GetNumChildren( nParentIndex );
|
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|
{
|
|
int nChildIndex = GetChild( nParentIndex, iChild );
|
|
|
|
KeyValues *pItemData = GetItemData( nChildIndex );
|
|
if ( !pItemData )
|
|
continue;
|
|
|
|
CDmElement *pItemElement = GetElementKeyValue< CDmElement >( pItemData, "handle" );
|
|
if ( pItemElement == pElement )
|
|
{
|
|
if ( nComponentFlags == 0 )
|
|
return nChildIndex;
|
|
|
|
TransformComponent_t nItemComponentFlags = static_cast< TransformComponent_t >( pItemData->GetInt( "componentFlags" ) );
|
|
if ( nItemComponentFlags == nComponentFlags )
|
|
return nChildIndex;
|
|
|
|
if ( ( nItemComponentFlags & nComponentFlags ) == nComponentFlags )
|
|
{
|
|
GenerateChildrenOfNode( nChildIndex );
|
|
int nSubChildIndex = FindChildItemForElement( nChildIndex, pElement, nComponentFlags );
|
|
if ( nSubChildIndex >= 0 )
|
|
return nChildIndex;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Find the index of the the tree view item that has the specified element as
|
|
// its "handle" value
|
|
//-----------------------------------------------------------------------------
|
|
int CAnimGroupTree::FindItemForElement( const CDmElement *pElement, TransformComponent_t nComponentFlags )
|
|
{
|
|
int highest = GetHighestItemID();
|
|
for ( int i = 0; i < highest; ++i )
|
|
{
|
|
if ( !IsItemIDValid( i ) )
|
|
continue;
|
|
|
|
KeyValues *pItemData = GetItemData( i );
|
|
if ( !pItemData )
|
|
continue;
|
|
|
|
CDmElement *pItemElement = GetElementKeyValue< CDmElement >( pItemData, "handle" );
|
|
if ( pItemElement == pElement )
|
|
{
|
|
TransformComponent_t nItemComponentFlags = static_cast< TransformComponent_t >( pItemData->GetInt( "componentFlags" ) );
|
|
if ( ( nItemComponentFlags == nComponentFlags ) || ( nComponentFlags == 0 ) )
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Build the tree view items from the root down to the specified animation set
|
|
//-----------------------------------------------------------------------------
|
|
int CAnimGroupTree::BuildTreeToAnimationSet( CDmeAnimationSet *pAnimationSet )
|
|
{
|
|
if ( pAnimationSet == NULL )
|
|
return -1;
|
|
|
|
// Check to see if the animation set is already has an item, if so just return that.
|
|
int nItemIndex = FindItemForElement( pAnimationSet );
|
|
|
|
// If the item was not found find or create the item for the animation set group containing
|
|
// the animation set and then create all its children, including the animation set being looked for.
|
|
if ( nItemIndex < 0 )
|
|
{
|
|
int nParentItemIndex = GetRootItemIndex();
|
|
GenerateChildrenOfNode( nParentItemIndex );
|
|
nItemIndex = FindChildItemForElement( nParentItemIndex, pAnimationSet );
|
|
}
|
|
|
|
return nItemIndex;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Build the tree view items from the root down to the specified control group
|
|
//-----------------------------------------------------------------------------
|
|
int CAnimGroupTree::BuildTreeToGroup( CDmeControlGroup *pGroup, CDmeAnimationSet *pAnimationSet )
|
|
{
|
|
if ( ( pGroup == NULL ) || ( pAnimationSet == NULL ) )
|
|
return -1;
|
|
|
|
// Check to see if the group is already has an item, if so just return that.
|
|
int nItemIndex = FindItemForElement( pGroup );
|
|
|
|
if ( nItemIndex < 0 )
|
|
{
|
|
int nParentItemIndex = -1;
|
|
|
|
if ( pAnimationSet->GetRootControlGroup() == pGroup )
|
|
{
|
|
nParentItemIndex = BuildTreeToAnimationSet( pAnimationSet );
|
|
return nParentItemIndex;
|
|
}
|
|
else
|
|
{
|
|
CDmeControlGroup* pParentGroup = pGroup->FindParent();
|
|
nParentItemIndex = BuildTreeToGroup( pParentGroup, pAnimationSet );
|
|
}
|
|
|
|
if ( nParentItemIndex >= 0 )
|
|
{
|
|
GenerateChildrenOfNode( nParentItemIndex );
|
|
nItemIndex = FindChildItemForElement( nParentItemIndex, pGroup );
|
|
}
|
|
}
|
|
|
|
return nItemIndex;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Build the tree view items from the root down to the specified control
|
|
//-----------------------------------------------------------------------------
|
|
void CAnimGroupTree::BuildTreeToControl( const CDmElement *pControl, TransformComponent_t nComponentFlags )
|
|
{
|
|
if ( pControl == NULL )
|
|
return;
|
|
|
|
// Find the animation set to which the control belongs
|
|
CDmeAnimationSet *pAnimationSet = FindAncestorReferencingElement< CDmeAnimationSet >( pControl );
|
|
if ( pAnimationSet == NULL )
|
|
return;
|
|
|
|
// Check to see if the control is already has an item, if so just return that.
|
|
int nItemIndex = FindItemForElement( pControl, nComponentFlags );
|
|
|
|
// If the item for the control was not found, find the group containing the control
|
|
// and make sure it has an item in the tree and the generate the children for that
|
|
// item which will include the item for the control being looked for.
|
|
if ( nItemIndex < 0 )
|
|
{
|
|
int nParentItemIndex = -1;
|
|
CDmeControlGroup *pGroup = CDmeControlGroup::FindGroupContainingControl( pControl );
|
|
nParentItemIndex = BuildTreeToGroup( pGroup, pAnimationSet );
|
|
if ( nParentItemIndex >= 0 )
|
|
{
|
|
GenerateChildrenOfNode( nParentItemIndex );
|
|
nItemIndex = FindChildItemForElement( nParentItemIndex, pControl, nComponentFlags );
|
|
}
|
|
}
|
|
|
|
if ( nItemIndex >= 0 )
|
|
{
|
|
MakeItemVisible( nItemIndex );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set the selection state on the specified item
|
|
//-----------------------------------------------------------------------------
|
|
void CAnimGroupTree::SetItemSelectionState( int nItemIndex, SelectionState_t selectionState )
|
|
{
|
|
KeyValues *pItemData = GetItemData( nItemIndex );
|
|
|
|
if ( pItemData )
|
|
{
|
|
pItemData->SetInt( "selection", ( int )selectionState );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get the selection state of the specified item
|
|
//-----------------------------------------------------------------------------
|
|
SelectionState_t CAnimGroupTree::GetItemSelectionState( int nItemIndex ) const
|
|
{
|
|
KeyValues *pItemData = GetItemData( nItemIndex );
|
|
if ( pItemData == NULL)
|
|
return SEL_EMPTY;
|
|
|
|
return ( SelectionState_t )( pItemData->GetInt( "selection" ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get a list of the controls which are fully selected and whose parents are
|
|
// not fully selected
|
|
//-----------------------------------------------------------------------------
|
|
void CAnimGroupTree::GetSelectionRootItems( CUtlVector< int > &rootSelectedItems ) const
|
|
{
|
|
CUtlVector< int > selectedItems;
|
|
GetSelectedItems( selectedItems );
|
|
|
|
int nNumSelectedItems = selectedItems.Count();
|
|
rootSelectedItems.EnsureCapacity( nNumSelectedItems );
|
|
|
|
for ( int iItem = 0; iItem < nNumSelectedItems; ++iItem )
|
|
{
|
|
int nItemIndex = selectedItems[ iItem ];
|
|
|
|
// Skip any items which are not fully selected
|
|
if ( GetItemSelectionState( nItemIndex ) != SEL_ALL )
|
|
continue;
|
|
|
|
// Skip any items whose parent is fully selected
|
|
int nParentIndex = GetItemParent( nItemIndex );
|
|
if ( GetItemSelectionState( nParentIndex ) == SEL_ALL )
|
|
continue;
|
|
|
|
rootSelectedItems.AddToTail( nItemIndex );
|
|
}
|
|
}
|
|
|
|
|
|
CBaseAnimSetControlGroupPanel::CBaseAnimSetControlGroupPanel( vgui::Panel *parent, const char *className, CBaseAnimationSetEditor *editor, bool bControlStateInterface ) :
|
|
BaseClass( parent, className ),
|
|
m_pController( NULL )
|
|
{
|
|
m_hEditor = editor;
|
|
m_pController = editor->GetController();
|
|
m_pController->AddControlSelectionChangedListener( this );
|
|
|
|
m_hGroups = SETUP_PANEL( new CAnimGroupTree( this, "AnimSetGroups", this, bControlStateInterface ) );
|
|
m_hGroups->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
|
|
m_hGroups->SetAllowMultipleSelections( true );
|
|
m_hGroups->AddItem( new KeyValues( "root" ), -1 ); // add (invisible) root
|
|
}
|
|
|
|
CBaseAnimSetControlGroupPanel::~CBaseAnimSetControlGroupPanel()
|
|
{
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::ApplySchemeSettings( IScheme *pScheme )
|
|
{
|
|
BaseClass::ApplySchemeSettings( pScheme );
|
|
m_FullSelectionColor = pScheme->GetColor( "AnimSet.FullSelectionColor" , Color( 128, 128, 128, 128 ) );
|
|
m_PartialSelectionColor = pScheme->GetColor( "AnimSet.PartialSelectionColor" , Color( 128, 128, 64, 64 ) );
|
|
m_ContextMenuHighlightColor = pScheme->GetColor( "AnimSet.ContextMenuSelectionColor", Color( 255, 153, 0, 255 ) );
|
|
|
|
// Normally we shouldn't have to call this but ApplySchemeSettings is called directly
|
|
// by the animation set editor, so normal solve traverse isn't performed in that case.
|
|
m_hGroups->ApplySchemeSettings( pScheme );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::SelectAnimTreeItem( int itemIndex, ESelectionMode selectionMode )
|
|
{
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = m_hGroups->GetTreeItemData( itemIndex, &itemType );
|
|
if ( !pElement )
|
|
return;
|
|
|
|
switch ( itemType )
|
|
{
|
|
case ANIMTREE_ITEM_ANIMSET:
|
|
if ( CDmeAnimationSet *pAnimSet = CastElement< CDmeAnimationSet >( pElement ) )
|
|
{
|
|
m_pController->SelectAnimationSet( pAnimSet, selectionMode );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_GROUP:
|
|
if ( CDmeControlGroup *pGroup = CastElement< CDmeControlGroup >( pElement ) )
|
|
{
|
|
m_pController->SelectControlGroup( pGroup, selectionMode );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_CONTROL:
|
|
m_pController->SelectControl( pElement, selectionMode );
|
|
break;
|
|
case ANIMTREE_ITEM_COMPONENT:
|
|
TransformComponent_t nComponentFlags = m_hGroups->GetItemComponentFlags( itemIndex );
|
|
m_pController->SelectControl( pElement, selectionMode, nComponentFlags );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnControlSelectionChanged()
|
|
{
|
|
UpdateSelection();
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::ExpandTreeToControl( const CDmElement *pSelection, TransformComponent_t nComponentFlags )
|
|
{
|
|
m_hGroups->BuildTreeToControl( pSelection, nComponentFlags );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewStartRangeSelection()
|
|
{
|
|
m_pController->SetRangeSelectionState( true );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewFinishRangeSelection()
|
|
{
|
|
m_pController->SetRangeSelectionState( false );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelected( int itemIndex, int replaceSelection )
|
|
{
|
|
SelectAnimTreeItem( itemIndex, replaceSelection ? SELECTION_SET : SELECTION_ADD );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewItemDeselected( int itemIndex )
|
|
{
|
|
SelectAnimTreeItem( itemIndex, SELECTION_REMOVE );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewItemSelectionCleared()
|
|
{
|
|
m_pController->ClearSelection();
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::ChangeAnimationSetClip( CDmeFilmClip *pFilmClip )
|
|
{
|
|
RebuildTree( false );
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::OnControlsAddedOrRemoved()
|
|
{
|
|
RebuildTree( true );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Rebuild the tree view from the current control selection hierarchy
|
|
//-----------------------------------------------------------------------------
|
|
void CBaseAnimSetControlGroupPanel::RebuildTree( bool bRestoreExpansion )
|
|
{
|
|
if ( bRestoreExpansion )
|
|
{
|
|
CUtlVector< ElementExpansion_t > expandedNodes( 0, m_hGroups->GetItemCount() );
|
|
CollectExpandedItems( expandedNodes, m_hGroups->GetRootItemIndex() );
|
|
|
|
m_hGroups->SetSilentMode( true );
|
|
m_hGroups->RemoveAll();
|
|
m_hGroups->SetSilentMode( false );
|
|
m_hGroups->AddItem( new KeyValues( "root" ), -1 ); // add (invisible) root
|
|
m_hGroups->ExpandItem( m_hGroups->GetRootItemIndex(), true );
|
|
|
|
ExpandItems( expandedNodes );
|
|
|
|
UpdateSelection();
|
|
}
|
|
else
|
|
{
|
|
m_hGroups->SetSilentMode( true );
|
|
m_hGroups->RemoveAll();
|
|
m_hGroups->SetSilentMode( false );
|
|
m_hGroups->AddItem( new KeyValues( "root" ), -1 ); // add (invisible) root
|
|
|
|
if ( CDmeFilmClip *pFilmClip = m_pController->GetAnimationSetClip() )
|
|
{
|
|
CAnimSetGroupAnimSetTraversal traversal( pFilmClip );
|
|
while ( CDmeAnimationSet *pAnimSet = traversal.Next() )
|
|
{
|
|
m_hGroups->AddAnimationSetToTree( pAnimSet );
|
|
}
|
|
m_hGroups->ExpandItem( m_hGroups->GetRootItemIndex(), true );
|
|
}
|
|
}
|
|
}
|
|
|
|
// pre-order traversal so that we can ExpandItems linearly
|
|
void CBaseAnimSetControlGroupPanel::CollectExpandedItems( CUtlVector< ElementExpansion_t > &expandedNodes, int nItemIndex )
|
|
{
|
|
if ( nItemIndex == m_hGroups->InvalidItemID() )
|
|
return;
|
|
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = m_hGroups->GetTreeItemData( nItemIndex, &itemType );
|
|
|
|
if ( !m_hGroups->IsItemExpanded( nItemIndex ) )
|
|
return;
|
|
|
|
ElementExpansion_t *pExpansionInfo = NULL;
|
|
if ( pElement )
|
|
{
|
|
int nIndex = expandedNodes.AddToTail();
|
|
pExpansionInfo = &expandedNodes[ nIndex ];
|
|
pExpansionInfo->m_pElement = pElement;
|
|
pExpansionInfo->m_ComponentFlags = TRANSFORM_COMPONENT_NONE;
|
|
}
|
|
|
|
int nChildren = m_hGroups->GetNumChildren( nItemIndex );
|
|
for ( int i = 0; i < nChildren; ++i )
|
|
{
|
|
int nChildIndex = m_hGroups->GetChild( nItemIndex, i );
|
|
|
|
AnimTreeItemType_t childItemType;
|
|
m_hGroups->GetTreeItemData( nChildIndex, &childItemType );
|
|
|
|
if ( childItemType == ANIMTREE_ITEM_COMPONENT )
|
|
{
|
|
if ( m_hGroups->IsItemExpanded( nChildIndex ) && pExpansionInfo )
|
|
{
|
|
pExpansionInfo->m_ComponentFlags |= m_hGroups->GetItemComponentFlags( nChildIndex );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CollectExpandedItems( expandedNodes, nChildIndex );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// assumes expandedNodes have parents before children (ie expandedNodes is a pre-order traversal)
|
|
void CBaseAnimSetControlGroupPanel::ExpandItems( const CUtlVector< ElementExpansion_t > &expandedNodes )
|
|
{
|
|
int nExpandedNodes = expandedNodes.Count();
|
|
for ( int i = 0; i < nExpandedNodes; ++i )
|
|
{
|
|
CDmElement *pElement = expandedNodes[ i ].m_pElement;
|
|
int nItemIndex = m_hGroups->FindItemForElement( pElement );
|
|
if ( nItemIndex != m_hGroups->InvalidItemID() )
|
|
{
|
|
m_hGroups->ExpandItem( nItemIndex, true );
|
|
|
|
TransformComponent_t expandedComponents = expandedNodes[ i ].m_ComponentFlags;
|
|
if ( expandedComponents == TRANSFORM_COMPONENT_NONE )
|
|
continue;
|
|
|
|
int nChildren = m_hGroups->GetNumChildren( nItemIndex );
|
|
for ( int i = 0; i < nChildren; ++i )
|
|
{
|
|
int nChildIndex = m_hGroups->GetChild( nItemIndex, i );
|
|
|
|
AnimTreeItemType_t childItemType;
|
|
m_hGroups->GetTreeItemData( nChildIndex, &childItemType );
|
|
TransformComponent_t childComponents = m_hGroups->GetItemComponentFlags( nChildIndex );
|
|
if ( ( childItemType == ANIMTREE_ITEM_COMPONENT ) && ( childComponents & expandedComponents ) )
|
|
{
|
|
m_hGroups->ExpandItem( nChildIndex, true );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBaseAnimSetControlGroupPanel::UpdateSelection()
|
|
{
|
|
if ( !m_hGroups )
|
|
return;
|
|
|
|
m_hGroups->SetSilentMode( true );
|
|
m_hGroups->ClearSelection();
|
|
m_hGroups->SetSilentMode( false );
|
|
UpdateSelection_R( m_hGroups->GetRootItemIndex() );
|
|
}
|
|
|
|
SelectionState_t CBaseAnimSetControlGroupPanel::UpdateSelection_R( int nParentIndex )
|
|
{
|
|
if ( nParentIndex == m_hGroups->InvalidItemID() )
|
|
return SEL_EMPTY;
|
|
|
|
SelectionState_t selection = SEL_EMPTY;
|
|
|
|
int nChildren = m_hGroups->GetNumChildren( nParentIndex );
|
|
if ( nChildren > 0 )
|
|
{
|
|
for ( int i = 0; i < nChildren; ++i )
|
|
{
|
|
int nChildIndex = m_hGroups->GetChild( nParentIndex, i );
|
|
selection += UpdateSelection_R( nChildIndex );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// check actual controls
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = m_hGroups->GetTreeItemData( nParentIndex, &itemType );
|
|
if ( !pElement )
|
|
return SEL_EMPTY;
|
|
|
|
switch ( itemType )
|
|
{
|
|
case ANIMTREE_ITEM_ANIMSET:
|
|
if ( CDmeAnimationSet *pAnimSet = CastElement< CDmeAnimationSet >( pElement ) )
|
|
{
|
|
selection = m_pController->GetSelectionState( pAnimSet );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_GROUP:
|
|
if ( CDmeControlGroup *pGroup = CastElement< CDmeControlGroup >( pElement ) )
|
|
{
|
|
selection = m_pController->GetSelectionState( pGroup );
|
|
}
|
|
break;
|
|
case ANIMTREE_ITEM_CONTROL:
|
|
selection = m_pController->GetSelectionState( pElement );
|
|
break;
|
|
case ANIMTREE_ITEM_COMPONENT:
|
|
TransformComponent_t nComponentFlags = m_hGroups->GetItemComponentFlags( nParentIndex );
|
|
selection = m_pController->GetSelectionState( pElement, nComponentFlags );
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_hGroups->SetItemSelectionState( nParentIndex, selection );
|
|
|
|
if ( selection == SEL_SOME || selection == SEL_ALL )
|
|
{
|
|
Color color = ( selection == SEL_ALL ) ? m_FullSelectionColor : m_PartialSelectionColor;
|
|
m_hGroups->SetItemSelectionBgColor( nParentIndex, color );
|
|
m_hGroups->SetItemSelectionUnfocusedBgColor( nParentIndex, color );
|
|
|
|
m_hGroups->SetSilentMode( true );
|
|
m_hGroups->AddSelectedItem( nParentIndex, false, false, false );
|
|
m_hGroups->SetSilentMode( false );
|
|
}
|
|
|
|
return selection;
|
|
}
|
|
|
|
|
|
CDmeDag *CBaseAnimSetControlGroupPanel::GetWorkCameraParent()
|
|
{
|
|
return m_pController->GetWorkCameraParent();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Handle the request of the tree view to create a context menu
|
|
//-----------------------------------------------------------------------------
|
|
void CBaseAnimSetControlGroupPanel::OnTreeViewOpenContextMenu( int itemID )
|
|
{
|
|
if ( itemID >= 0 )
|
|
{
|
|
m_hGroups->SetItemSelectionUnfocusedBgColor( itemID, m_ContextMenuHighlightColor );
|
|
}
|
|
|
|
KeyValues *pItemData = m_hGroups->GetItemData( itemID );
|
|
m_hEditor->OpenTreeViewContextMenu( pItemData );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create a new control group containing the selected controls
|
|
//-----------------------------------------------------------------------------
|
|
void CBaseAnimSetControlGroupPanel::CreateGroupFromSelectedControls()
|
|
{
|
|
CUtlVector< int > selectedItems;
|
|
m_hGroups->GetSelectionRootItems( selectedItems );
|
|
|
|
int nNumSelectedItems = selectedItems.Count();
|
|
if ( nNumSelectedItems < 0 )
|
|
return;
|
|
|
|
CDmeControlGroup *pCommonAncestor = NULL;
|
|
|
|
for ( int iItem = 0; iItem < nNumSelectedItems; ++iItem )
|
|
{
|
|
int nItemIndex = selectedItems[ iItem ];
|
|
|
|
AnimTreeItemType_t itemType;
|
|
CDmeControlGroup *pParentControlGroup = NULL;
|
|
m_hGroups->GetTreeItemData( nItemIndex, &itemType, NULL, &pParentControlGroup );
|
|
|
|
// Currently not allowed to group animation sets
|
|
if ( itemType == ANIMTREE_ITEM_ANIMSET )
|
|
return;
|
|
|
|
if ( pCommonAncestor )
|
|
{
|
|
pCommonAncestor = pParentControlGroup->FindCommonAncestor( pCommonAncestor );
|
|
}
|
|
else
|
|
{
|
|
pCommonAncestor = pParentControlGroup;
|
|
}
|
|
|
|
// If any of the selected items do not have a common
|
|
// ancestor, do not allow the group to be created.
|
|
if ( pCommonAncestor == NULL )
|
|
return;
|
|
}
|
|
|
|
// If the selected items did not share a common ancestor a new group cannot be created
|
|
if ( pCommonAncestor == NULL )
|
|
return;
|
|
|
|
// Generate a name for the new group which is unique among the children of the group it will belong to.
|
|
const CDmeControlGroup *pRootGroup = pCommonAncestor->FindRootControlGroup();
|
|
if ( pRootGroup == NULL)
|
|
return;
|
|
|
|
CUtlVector< DmElementHandle_t > childList;
|
|
pRootGroup->GetAllChildren( childList );
|
|
|
|
int nIndex = GenerateUniqueNameIndex( "group", childList, 1 );
|
|
CFmtStr groupName( "group%d", nIndex );
|
|
|
|
// Create the new group and make it a child of the common ancestor
|
|
CDmeControlGroup *pNewGroup = pCommonAncestor->CreateControlGroup( groupName );
|
|
|
|
// Add the selected items to the new group
|
|
if ( pNewGroup )
|
|
{
|
|
for ( int iItem = 0; iItem < nNumSelectedItems; ++iItem )
|
|
{
|
|
int nItemIndex = selectedItems[ iItem ];
|
|
|
|
AnimTreeItemType_t itemType;
|
|
CDmElement *pElement = m_hGroups->GetTreeItemData( nItemIndex, &itemType );
|
|
|
|
if ( itemType == ANIMTREE_ITEM_GROUP )
|
|
{
|
|
pNewGroup->AddChild( CastElement< CDmeControlGroup >( pElement ) );
|
|
}
|
|
else if ( itemType == ANIMTREE_ITEM_CONTROL )
|
|
{
|
|
pNewGroup->AddControl( pElement );
|
|
}
|
|
}
|
|
|
|
// Clean up any empty children which may have been left in the tree.
|
|
pCommonAncestor->DestroyEmptyChildren();
|
|
|
|
// Rebuild the tree so that it includes the new group
|
|
RebuildTree( true );
|
|
|
|
// Find the item corresponding to the new group and set it label editing mode.
|
|
int nNewItemIndex = m_hGroups->FindItemForElement( pNewGroup );
|
|
m_hGroups->MakeItemVisible( nNewItemIndex );
|
|
m_hGroups->StartEditingLabel( nNewItemIndex );
|
|
}
|
|
}
|