856 lines
28 KiB
C++
856 lines
28 KiB
C++
|
//====== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. =======
|
|||
|
//
|
|||
|
// Purpose: Implementation of the CDmeControlGroup class. The CDmeControlGroup
|
|||
|
// class provides hierarchical grouping of animation controls and used for
|
|||
|
// selection of the animation set controls.
|
|||
|
//
|
|||
|
//=============================================================================
|
|||
|
#include "movieobjects/dmecontrolgroup.h"
|
|||
|
#include "movieobjects/dmetransform.h"
|
|||
|
#include "movieobjects/dmetransformcontrol.h"
|
|||
|
#include "movieobjects/dmeanimationset.h"
|
|||
|
#include "datamodel/dmelementfactoryhelper.h"
|
|||
|
|
|||
|
// memdbgon must be the last include file in a .cpp file!!!
|
|||
|
#include "tier0/memdbgon.h"
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Expose this class to the scene database
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
IMPLEMENT_ELEMENT_FACTORY( DmeControlGroup, CDmeControlGroup );
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Provide post construction processing.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::OnConstruction()
|
|||
|
{
|
|||
|
m_Children.Init( this, "children" );
|
|||
|
m_Controls.Init( this, "controls" );
|
|||
|
m_GroupColor.InitAndSet( this, "groupColor", Color( 200, 200, 200, 255 ) );
|
|||
|
m_ControlColor.InitAndSet( this, "controlColor", Color( 200, 200, 200, 255 ) );
|
|||
|
m_Visible.InitAndSet( this, "visible", true );
|
|||
|
m_Selectable.InitAndSet( this, "selectable", true );
|
|||
|
m_Snappable.InitAndSet( this, "snappable", true );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Provide processing and cleanup before shutdown
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::OnDestruction()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Add a the provided control to the group, if the control is currently in another group
|
|||
|
// it will be removed from the other group first.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::AddControl( CDmElement *pControl, const CDmElement *pInsertBeforeControl )
|
|||
|
{
|
|||
|
if ( pControl == NULL )
|
|||
|
return;
|
|||
|
|
|||
|
// Remove the control from any group it is currently in.
|
|||
|
CDmeControlGroup *pCurrentGroup = FindGroupContainingControl( pControl );
|
|||
|
if ( pCurrentGroup )
|
|||
|
{
|
|||
|
pCurrentGroup->RemoveControl( pControl );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// If a insert location control was specified find it in the list of controls
|
|||
|
int nInsertLocation = m_Controls.InvalidIndex();
|
|||
|
if ( pInsertBeforeControl )
|
|||
|
{
|
|||
|
nInsertLocation = m_Controls.Find( pInsertBeforeControl );
|
|||
|
}
|
|||
|
|
|||
|
// Add the control to the group
|
|||
|
if ( nInsertLocation != m_Controls.InvalidIndex() )
|
|||
|
{
|
|||
|
m_Controls.InsertBefore( nInsertLocation, pControl );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
m_Controls.AddToTail( pControl );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Remove a control from the group. This will only search the immediate group for the
|
|||
|
// specified control and remove it. It will not remove the control if it is in a child of this
|
|||
|
// group. Returns false if the control was not found.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::RemoveControl( const CDmElement *pControl )
|
|||
|
{
|
|||
|
if ( pControl == NULL )
|
|||
|
return false;
|
|||
|
|
|||
|
int nControls = m_Controls.Count();
|
|||
|
for ( int iControl = 0; iControl < nControls; ++iControl )
|
|||
|
{
|
|||
|
if ( pControl == m_Controls[ iControl ] )
|
|||
|
{
|
|||
|
m_Controls.Remove( iControl );
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Get a flat list of all of the controls in the group. If the recursive flag is true
|
|||
|
// a flat list of all of the controls in the entire sub-tree of the group will be returned. If
|
|||
|
// the recursive flag is false on
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::GetControlsInGroup( CUtlVector< CDmElement* > &controlList, bool recursive ) const
|
|||
|
{
|
|||
|
// If the recursive flag is set add all of the controls
|
|||
|
// of the entire tree of each child group within the group.
|
|||
|
if ( recursive )
|
|||
|
{
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
pChild->GetControlsInGroup( controlList, true );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Add the controls from this group.
|
|||
|
int nControls = m_Controls.Count();
|
|||
|
for ( int iControl = 0; iControl < nControls; ++iControl )
|
|||
|
{
|
|||
|
CDmElement *pControl = m_Controls[ iControl ];
|
|||
|
if ( pControl )
|
|||
|
{
|
|||
|
controlList.AddToTail( pControl );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Find a control with the specified name within the group. If the recursive flag is true
|
|||
|
// the entire sub-tree of the group will be searched, otherwise only the immediate control will
|
|||
|
// be searched for the group. If the parent group pointer is provided it will be returned with the
|
|||
|
// group to which the control belongs directly.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
CDmElement *CDmeControlGroup::FindControlByName( const char *pchName, bool recursive, CDmeControlGroup **pParentGroup )
|
|||
|
{
|
|||
|
// Search the controls contained directly by the group for one with the specified name.
|
|||
|
int nControls = m_Controls.Count();
|
|||
|
for ( int iControl = 0; iControl < nControls; ++iControl )
|
|||
|
{
|
|||
|
CDmElement *pControl = m_Controls[ iControl ];
|
|||
|
if ( pControl )
|
|||
|
{
|
|||
|
if ( V_stricmp( pControl->GetName(), pchName ) == 0 )
|
|||
|
{
|
|||
|
if ( pParentGroup )
|
|||
|
{
|
|||
|
*pParentGroup = this;
|
|||
|
}
|
|||
|
|
|||
|
return pControl;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If the control was not found in the controls contained directly by the group
|
|||
|
// search the children and their sub-trees if the recursive flag is true.
|
|||
|
if ( recursive )
|
|||
|
{
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
CDmElement *pControl = pChild->FindControlByName( pchName, true, pParentGroup );
|
|||
|
if ( pControl )
|
|||
|
return pControl;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Find the group to which the specified control belongs, if any. This function searches
|
|||
|
// for any control groups which reference the specified control. It simply returns the first one
|
|||
|
// it finds, as a control should only every belong to a single control group.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::FindGroupContainingControl( const CDmElement* pControl )
|
|||
|
{
|
|||
|
return FindReferringElement< CDmeControlGroup >( pControl, "controls" );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Make the specified group a child of this group. The group will be removed from the
|
|||
|
// child list of any other group to which it may currently belong.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::AddChild( CDmeControlGroup *pGroup, const CDmeControlGroup *pInsertBeforeGroup )
|
|||
|
{
|
|||
|
// Can't make a group its own child
|
|||
|
Assert( pGroup != this );
|
|||
|
if ( pGroup == this )
|
|||
|
return;
|
|||
|
|
|||
|
// Remove the group from its current control group if it belongs one.
|
|||
|
CDmeControlGroup *pParentGroup = pGroup->FindParent();
|
|||
|
if ( pParentGroup )
|
|||
|
{
|
|||
|
pParentGroup->RemoveChild( pGroup );
|
|||
|
}
|
|||
|
|
|||
|
// If a insert location group was specified find it in the list of children
|
|||
|
int nInsertLocation = m_Children.InvalidIndex();
|
|||
|
if ( pInsertBeforeGroup )
|
|||
|
{
|
|||
|
nInsertLocation = m_Children.Find( pInsertBeforeGroup );
|
|||
|
}
|
|||
|
|
|||
|
// Add the specified group as child of this group.
|
|||
|
if ( nInsertLocation != m_Children.InvalidIndex() )
|
|||
|
{
|
|||
|
m_Children.InsertBefore( nInsertLocation, pGroup );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
m_Children.AddToTail( pGroup );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Remove the specified child group. Searches the immediate children of the node for the
|
|||
|
// specified group and removes it from the child list if the group is found. Returns true if the
|
|||
|
// group is found, false if the group is not found.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::RemoveChild( const CDmeControlGroup *pGroup )
|
|||
|
{
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
if ( m_Children[ iChild ] == pGroup )
|
|||
|
{
|
|||
|
m_Children.Remove( iChild );
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Move the specified child group to the top of the list
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::MoveChildToTop( const CDmeControlGroup *pGroup )
|
|||
|
{
|
|||
|
// Make sure the group is actually a child, and move it
|
|||
|
// to the top of the list if it is not already there.
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 1; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
if ( m_Children[ iChild ] == pGroup )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
m_Children.Remove( iChild );
|
|||
|
m_Children.InsertBefore( 0, pChild );
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Move the specified child group to the bottom of the list
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::MoveChildToBottom( const CDmeControlGroup *pGroup )
|
|||
|
{
|
|||
|
// Make sure the group is actually a child, and move it
|
|||
|
// to the bottom of the list if it is not already there.
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < (nChildren - 1); ++iChild )
|
|||
|
{
|
|||
|
if ( m_Children[ iChild ] == pGroup )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
m_Children.Remove( iChild );
|
|||
|
m_Children.AddToTail( pChild );
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Compare the two groups by name for an ascending sort
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
int CDmeControlGroup::CompareByNameAscending( CDmeControlGroup * const *pGroupA, CDmeControlGroup * const *pGroupB )
|
|||
|
{
|
|||
|
return V_stricmp( (*pGroupA)->GetName(), (*pGroupB)->GetName() );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Compare the two groups by name for a descending sort
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
int CDmeControlGroup::CompareByNameDecending( CDmeControlGroup * const *pGroupA, CDmeControlGroup * const *pGroupB )
|
|||
|
{
|
|||
|
return V_stricmp( (*pGroupB)->GetName(), (*pGroupA)->GetName() );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Sore the children by name
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SortChildrenByName( bool bAscending )
|
|||
|
{
|
|||
|
// Copy the children into a temporary array to be sorted.
|
|||
|
int nNumChildren = m_Children.Count();
|
|||
|
CUtlVector< CDmeControlGroup * > sortedList( 0, nNumChildren );
|
|||
|
|
|||
|
for ( int iChild = 0; iChild < nNumChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pGroup = m_Children[ iChild ];
|
|||
|
if ( pGroup )
|
|||
|
{
|
|||
|
sortedList.AddToTail( pGroup );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Sort the temporary array in ascending or descending order
|
|||
|
if ( bAscending )
|
|||
|
{
|
|||
|
sortedList.Sort( CompareByNameAscending );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sortedList.Sort( CompareByNameDecending );
|
|||
|
}
|
|||
|
|
|||
|
// Remove all of the children from the original list and then add them back in sorted order
|
|||
|
m_Children.RemoveAll();
|
|||
|
int nNumSorted = sortedList.Count();
|
|||
|
for ( int iChild = 0; iChild < nNumSorted; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pGroup = sortedList[ iChild ];
|
|||
|
if ( pGroup )
|
|||
|
{
|
|||
|
m_Children.AddToTail( pGroup );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Determine if the group has child of the specified name
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::HasChildGroup( const char *pchName, bool recursive )
|
|||
|
{
|
|||
|
if ( FindChildByName( pchName, recursive ) == NULL )
|
|||
|
return false;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Find the child group with the specified name. If the recursive flag is true the entire
|
|||
|
// sub-tree of the group will be searched, otherwise only the immediate children of the group will
|
|||
|
// be searched for the specified child. If a parent group pointer is provided it will be returned
|
|||
|
// with the immediate parent in which the child was located.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::FindChildByName( const char *pchName, bool recursive, CDmeControlGroup **pParentGroup )
|
|||
|
{
|
|||
|
// Search the immediate children for a group with the specified name.
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
if ( V_stricmp( pChild->GetName(), pchName ) == 0 )
|
|||
|
{
|
|||
|
if ( pParentGroup )
|
|||
|
{
|
|||
|
*pParentGroup = this;
|
|||
|
}
|
|||
|
return pChild;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If the group was not found in the immediate children of the current group and the recursive
|
|||
|
// flag is set, search the sub-trees of all the children for the specified group.
|
|||
|
if ( recursive )
|
|||
|
{
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pGroup = pChild->FindChildByName( pchName, true, pParentGroup );
|
|||
|
if ( pGroup )
|
|||
|
return pGroup;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Find the parent of the group. Searches for groups which reference this group as a
|
|||
|
// child. Each group is allowed to be the child of only one group, so the first group found is
|
|||
|
// returned.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::FindParent() const
|
|||
|
{
|
|||
|
const static CUtlSymbolLarge symChildren = g_pDataModel->GetSymbol( "children" );
|
|||
|
CDmeControlGroup *pParent = FindReferringElement< CDmeControlGroup >( this, symChildren );
|
|||
|
return pParent;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Determine if this group is an ancestor of the specified group
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::IsAncestorOfGroup( const CDmeControlGroup *pGroup ) const
|
|||
|
{
|
|||
|
if ( pGroup == NULL )
|
|||
|
return false;
|
|||
|
|
|||
|
const CDmeControlGroup *pCurrentGroup = pGroup;
|
|||
|
const CDmeControlGroup *pParent = pGroup->FindParent();
|
|||
|
|
|||
|
while ( pParent )
|
|||
|
{
|
|||
|
if ( pParent == this )
|
|||
|
return true;
|
|||
|
|
|||
|
pCurrentGroup = pParent;
|
|||
|
pParent = pParent->FindParent();
|
|||
|
Assert( pCurrentGroup != pParent );
|
|||
|
if ( pCurrentGroup == pParent )
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Create a control group with the provided name and add it to the specified parent. If a child of
|
|||
|
// the specified name already exists it will be returned and no new group will be created.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::CreateControlGroup( const char *pchName )
|
|||
|
{
|
|||
|
CDmeControlGroup *pExistingGroup = FindChildByName( pchName, false );
|
|||
|
if ( pExistingGroup )
|
|||
|
return pExistingGroup;
|
|||
|
|
|||
|
// Create the new control group with the specified name
|
|||
|
CDmeControlGroup *pNewGroup = CreateElement< CDmeControlGroup >( pchName, GetFileId() );
|
|||
|
|
|||
|
// Add the group to as a child of this group
|
|||
|
AddChild( pNewGroup );
|
|||
|
|
|||
|
return pNewGroup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Get a flat list of all of the groups in sub-tree of the group
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::GetAllChildren( CUtlVector< DmElementHandle_t > &childGroupList ) const
|
|||
|
{
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
childGroupList.AddToTail( pChild->GetHandle() );
|
|||
|
pChild->GetAllChildren( childGroupList );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Recursively destroy the children of the specified group which have no controls or sub groups
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::DestroyEmptyChildren_R( CDmeControlGroup *pGroup )
|
|||
|
{
|
|||
|
int nNumChildren = pGroup->m_Children.Count();
|
|||
|
|
|||
|
// Build a list of the children which are empty and should be destroyed. This
|
|||
|
// process will recursively remove empty children of the children so that if
|
|||
|
// a child has only empty sub-children then it will still be removed.
|
|||
|
CUtlVector< CDmeControlGroup * > childrenToDestroy( 0, nNumChildren );
|
|||
|
for ( int iChild = 0; iChild < nNumChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = pGroup->m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
if ( DestroyEmptyChildren_R( pChild ) )
|
|||
|
{
|
|||
|
childrenToDestroy.AddToTail( pChild );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Destroy the empty children
|
|||
|
int nNumToDestroy = childrenToDestroy.Count();
|
|||
|
for ( int iChild = 0; iChild < nNumToDestroy; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = childrenToDestroy[ iChild ];
|
|||
|
pGroup->RemoveChild( pChild );
|
|||
|
}
|
|||
|
|
|||
|
// If this node is now empty return true indicating that it may be destroyed
|
|||
|
return ( ( pGroup->m_Children.Count() == 0 ) && ( pGroup->m_Controls.Count() == 0 ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Destroy all of the empty children of the group, will not destroy this group even it is empty.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::DestroyEmptyChildren()
|
|||
|
{
|
|||
|
DestroyEmptyChildren_R( this );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Destroy the control group, moving all of its children and controls into this node
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::DestroyGroup( CDmeControlGroup *pGroup, CDmeControlGroup *pRecipient, bool recursive )
|
|||
|
{
|
|||
|
if ( pGroup == NULL )
|
|||
|
return;
|
|||
|
|
|||
|
// Remove the group from its parent
|
|||
|
CDmeControlGroup *pParent = pGroup->FindParent();
|
|||
|
if ( pParent )
|
|||
|
{
|
|||
|
pParent->RemoveChild( pGroup );
|
|||
|
if ( pRecipient == NULL )
|
|||
|
{
|
|||
|
pRecipient = pParent;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Destroy the group and all of its children if specified
|
|||
|
DestroyGroup_R( pGroup, pRecipient, recursive );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Recursively destroy the child groups of the specified group and and the controls to the
|
|||
|
// specified recipient group
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::DestroyGroup_R( CDmeControlGroup *pGroup, CDmeControlGroup *pRecipient, bool recursive )
|
|||
|
{
|
|||
|
if ( pGroup == NULL )
|
|||
|
return;
|
|||
|
|
|||
|
// If the group is not empty there must be a recipient to receive its controls and groups
|
|||
|
if ( pRecipient == NULL && !pGroup->IsEmpty() )
|
|||
|
{
|
|||
|
Assert( pGroup->IsEmpty() || pRecipient );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Iterate through the children, if recursive destroy the
|
|||
|
// children otherwise copy the children to the recipient.
|
|||
|
int nChildren = pGroup->m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
CDmeControlGroup *pChild = pGroup->m_Children[ iChild ];
|
|||
|
if ( pChild )
|
|||
|
{
|
|||
|
if ( recursive )
|
|||
|
{
|
|||
|
DestroyGroup_R( pChild, pRecipient, true );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pRecipient->m_Children.AddToTail( pChild );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Copy all the controls of the node into the recipient
|
|||
|
int nControls = pGroup->m_Controls.Count();
|
|||
|
for ( int iControl = 0; iControl < nControls; ++iControl )
|
|||
|
{
|
|||
|
CDmElement *pControl = pGroup->m_Controls[ iControl ];
|
|||
|
pRecipient->m_Controls.AddToTail( pControl );
|
|||
|
}
|
|||
|
|
|||
|
// Destroy the group
|
|||
|
DestroyElement( pGroup );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Remove all of the children and controls from the group
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::RemoveAllChildrenAndControls()
|
|||
|
{
|
|||
|
m_Children.RemoveAll();
|
|||
|
m_Controls.RemoveAll();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Set the color of the group, this is the color that is used when displaying the group in
|
|||
|
// the user interface.
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SetGroupColor( const Color &groupColor, bool bRecursive )
|
|||
|
{
|
|||
|
m_GroupColor = groupColor;
|
|||
|
|
|||
|
if ( !bRecursive )
|
|||
|
return;
|
|||
|
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
if ( m_Children[ iChild ] )
|
|||
|
{
|
|||
|
m_Children[ iChild ]->SetGroupColor( groupColor, true );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
// Purpose: Set the color to be used on the controls of the group
|
|||
|
//-------------------------------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SetControlColor( const Color &controlColor, bool bRecursive )
|
|||
|
{
|
|||
|
m_ControlColor = controlColor;
|
|||
|
|
|||
|
if ( !bRecursive )
|
|||
|
return;
|
|||
|
|
|||
|
int nChildren = m_Children.Count();
|
|||
|
for ( int iChild = 0; iChild < nChildren; ++iChild )
|
|||
|
{
|
|||
|
if ( m_Children[ iChild ] )
|
|||
|
{
|
|||
|
m_Children[ iChild ]->SetControlColor( controlColor, true );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Set the visible state of the group
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SetVisible( bool bVisible )
|
|||
|
{
|
|||
|
m_Visible = bVisible;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Enable or disable selection of the controls
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SetSelectable( bool bSelectable )
|
|||
|
{
|
|||
|
m_Selectable = bSelectable;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Enable or disable control snapping
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::SetSnappable( bool bSnappable )
|
|||
|
{
|
|||
|
m_Snappable = bSnappable;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Purpose: Determine if there are any controls or children in the group
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::IsEmpty() const
|
|||
|
{
|
|||
|
if ( m_Controls.Count() > 0 ) return false;
|
|||
|
if ( m_Children.Count() > 0 ) return false;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Is the group visible
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::IsVisible() const
|
|||
|
{
|
|||
|
CDmeControlGroup *pParent = FindParent();
|
|||
|
if ( pParent && !pParent->IsVisible() )
|
|||
|
return false;
|
|||
|
|
|||
|
return m_Visible;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Can controls in the group be selected in the viewport
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::IsSelectable() const
|
|||
|
{
|
|||
|
CDmeControlGroup *pParent = FindParent();
|
|||
|
if ( pParent && !pParent->IsSelectable() )
|
|||
|
return false;
|
|||
|
|
|||
|
return m_Selectable;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Can controls in the group be snapped to in the viewport
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
bool CDmeControlGroup::IsSnappable() const
|
|||
|
{
|
|||
|
CDmeControlGroup *pParent = FindParent();
|
|||
|
if ( pParent && !pParent->IsSnappable() )
|
|||
|
return false;
|
|||
|
|
|||
|
return m_Snappable;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Find the shared ancestor between this control group and the specified control
|
|||
|
// group. Will return NULL if groups are not in the same tree and do not share a
|
|||
|
// common ancestor. If one group is an ancestor of the other group then that
|
|||
|
// group will be returned, so result may be one of the nodes which is not
|
|||
|
// technically an ancestor of that node.
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::FindCommonAncestor( CDmeControlGroup *pControlGroupB )
|
|||
|
{
|
|||
|
CDmeControlGroup *pControlGroupA = this;
|
|||
|
|
|||
|
// If the specified group is this group then
|
|||
|
// the common ancestor is the group itself.
|
|||
|
if ( pControlGroupA == pControlGroupB )
|
|||
|
return pControlGroupA;
|
|||
|
|
|||
|
// Build the path from each group to the root
|
|||
|
CUtlVector< CDmeControlGroup * > pathToGroupA;
|
|||
|
CUtlVector< CDmeControlGroup * > pathToGroupB;
|
|||
|
pControlGroupA->BuildPathFromRoot( pathToGroupA );
|
|||
|
pControlGroupB->BuildPathFromRoot( pathToGroupB );
|
|||
|
|
|||
|
// Now walk each of the the paths until they diverge
|
|||
|
CDmeControlGroup *pCommonGroup = NULL;
|
|||
|
int nNumSteps = MIN( pathToGroupA.Count(), pathToGroupB.Count() );
|
|||
|
|
|||
|
int iStep = 0;
|
|||
|
while ( iStep < nNumSteps )
|
|||
|
{
|
|||
|
if ( pathToGroupA[ iStep ] != pathToGroupB[ iStep ] )
|
|||
|
break;
|
|||
|
|
|||
|
pCommonGroup = pathToGroupA[ iStep ];
|
|||
|
++iStep;
|
|||
|
}
|
|||
|
|
|||
|
return pCommonGroup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Find the root control group which this control group is in the sub tree of.
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
CDmeControlGroup *CDmeControlGroup::FindRootControlGroup()
|
|||
|
{
|
|||
|
CDmeControlGroup *pCurrent = this;
|
|||
|
CDmeControlGroup *pParent = pCurrent->FindParent();
|
|||
|
|
|||
|
while ( pParent )
|
|||
|
{
|
|||
|
pCurrent = pParent;
|
|||
|
pParent = pParent->FindParent();
|
|||
|
}
|
|||
|
|
|||
|
return pCurrent;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Build a list of the control group that form the path to the root of the tree
|
|||
|
// to which the control group belongs
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
void CDmeControlGroup::BuildPathFromRoot( CUtlVector< CDmeControlGroup * > &pathToGroup )
|
|||
|
{
|
|||
|
CUtlVector< CDmeControlGroup * > pathToRoot( 0, 16 );
|
|||
|
|
|||
|
CDmeControlGroup *pCurrent = this;
|
|||
|
|
|||
|
while ( pCurrent )
|
|||
|
{
|
|||
|
pathToRoot.AddToTail( pCurrent );
|
|||
|
pCurrent = pCurrent->FindParent();
|
|||
|
}
|
|||
|
|
|||
|
int nNumGroups = pathToRoot.Count();
|
|||
|
pathToGroup.SetCount( nNumGroups );
|
|||
|
|
|||
|
for ( int iGroup = 0; iGroup < nNumGroups; ++iGroup )
|
|||
|
{
|
|||
|
pathToGroup[ iGroup ] = pathToRoot[ nNumGroups - 1 - iGroup ];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Find the animation set associated with the control group
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
CDmeAnimationSet *CDmeControlGroup::FindAnimationSet( bool bSearchAncestors ) const
|
|||
|
{
|
|||
|
const static CUtlSymbolLarge symRootControlGroup = g_pDataModel->GetSymbol( "rootControlGroup" );
|
|||
|
const CDmeControlGroup *pCurrent = this;
|
|||
|
|
|||
|
while ( pCurrent )
|
|||
|
{
|
|||
|
CDmeAnimationSet *pAnimationSet = FindReferringElement< CDmeAnimationSet >( pCurrent, symRootControlGroup );
|
|||
|
if ( pAnimationSet != NULL )
|
|||
|
return pAnimationSet;
|
|||
|
|
|||
|
if ( bSearchAncestors == false )
|
|||
|
break;
|
|||
|
|
|||
|
const CDmeControlGroup *pParent = pCurrent->FindParent();
|
|||
|
if ( pCurrent == pParent )
|
|||
|
break;
|
|||
|
|
|||
|
pCurrent = pParent;
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|