Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

855 lines
28 KiB

//====== Copyright © 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;
}