2024-09-03 19:56:21 +08:00

441 lines
10 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public abstract class HierarchyData
{
private static readonly List<HierarchyDataTransform> transformDataPool = new List<HierarchyDataTransform>( 32 );
private static readonly List<List<HierarchyDataTransform>> childrenListPool = new List<List<HierarchyDataTransform>>( 32 );
public abstract string Name { get; }
public abstract bool IsActive { get; }
public abstract int ChildCount { get; }
public abstract Transform BoundTransform { get; }
protected List<HierarchyDataTransform> children;
protected HierarchyData parent;
public HierarchyDataRoot Root
{
get
{
HierarchyData _parent = this;
while( _parent.parent != null )
_parent = _parent.parent;
return (HierarchyDataRoot) _parent;
}
}
protected int m_index;
public int Index { get { return m_index; } }
public int AbsoluteIndex
{
get
{
int result = m_index;
HierarchyData _parent = parent;
while( _parent != null )
{
result += _parent.m_index + 1;
_parent = _parent.parent;
}
return result;
}
}
protected int m_height = 1;
public int Height { get { return m_height; } }
protected int m_depth;
public int Depth { get { return m_depth; } }
public bool CanExpand { get { return ChildCount > 0; } }
public bool IsExpanded
{
get { return children != null; }
set
{
if( IsExpanded == value )
return;
if( value )
{
if( ChildCount == 0 )
return;
PopChildrenList();
}
else
PoolChildrenList();
int prevHeight = m_height;
Refresh();
int deltaHeight = m_height - prevHeight;
if( deltaHeight != 0 )
{
if( parent != null )
{
HierarchyData child = this;
HierarchyData _parent = parent;
while( _parent != null )
{
List<HierarchyDataTransform> children = _parent.children;
for( int i = children.IndexOf( (HierarchyDataTransform) child ) + 1, childCount = children.Count; i < childCount; i++ )
children[i].m_index += deltaHeight;
_parent.m_height += deltaHeight;
child = _parent;
_parent = _parent.parent;
}
}
HierarchyDataRoot root = Root;
if( root != null )
root.Hierarchy.SetListViewDirty();
}
}
}
public virtual bool Refresh()
{
if( m_depth < 0 ) // This object is hidden from Hierarchy
return false;
m_height = 1;
bool hasChanged = false;
int childCount = ChildCount;
if( IsExpanded )
{
if( childCount != children.Count )
hasChanged = true;
//if( childCount == 0 ) // Issue with IsExpanded's Refresh changing iteratedIndex
// PoolChildrenList();
//else
{
RuntimeHierarchy hierarchy = null; // Root's RuntimeHierarchy will be fetched only once when it is needed
for( int i = 0; i < childCount; i++ )
{
Transform child = GetChild( i );
if( children.Count <= i )
{
if( hierarchy == null )
hierarchy = Root.Hierarchy;
GenerateChildItem( child, i, hierarchy );
}
else if( children[i].BoundTransform != child )
{
int childIndex;
for( childIndex = 0; childIndex < children.Count; childIndex++ )
{
if( children[childIndex].BoundTransform == child )
break;
}
if( childIndex == children.Count )
{
if( hierarchy == null )
hierarchy = Root.Hierarchy;
GenerateChildItem( child, i, hierarchy );
}
else
{
HierarchyDataTransform childItem = children[childIndex];
children.RemoveAt( childIndex );
children.Insert( i, childItem );
}
hasChanged = true;
}
hasChanged |= children[i].Refresh();
children[i].m_index = m_height - 1;
m_height += children[i].m_height;
}
for( int i = children.Count - 1; i >= childCount; i-- )
RemoveChildItem( i );
}
}
return hasChanged;
}
public HierarchyData FindDataAtIndex( int index )
{
int upperBound = children.Count - 1;
if( index <= upperBound && children[index].m_index == index )
{
int middle = index;
while( middle < upperBound && index == children[middle + 1].m_index )
middle++;
return children[middle];
}
// Binary search
int min = 0;
int max = upperBound;
while( min <= max )
{
int middle = ( min + max ) / 2;
int childIndex = children[middle].m_index;
if( index == childIndex )
{
// Items hidden from the Hierarchy have same indices with their adjacent items
while( middle < upperBound && index == children[middle + 1].m_index )
middle++;
return children[middle];
}
if( index < childIndex )
max = middle - 1;
else
min = middle + 1;
}
if( max < 0 )
max = 0;
while( max < upperBound && index >= children[max + 1].m_index )
max++;
return children[max].FindDataAtIndex( index - 1 - children[max].m_index );
}
public HierarchyDataTransform FindTransform( Transform target, Transform nextInPath = null )
{
if( m_depth < 0 ) // This object is hidden from Hierarchy
return null;
bool isInitSearch = nextInPath == null;
if( isInitSearch )
{
nextInPath = ( this is HierarchyDataRootSearch ) ? target : target.root;
// In the current implementation, FindTransform is only called from RuntimeHierarchy.Select which
// automatically calls RefreshContent prior to FindTransform
//( (HierarchyDataRoot) this ).RefreshContent();
}
int childIndex = IndexOf( nextInPath );
if( childIndex < 0 )
{
if( isInitSearch && this is HierarchyDataRootPseudoScene )
{
nextInPath = target;
childIndex = IndexOf( nextInPath );
while( childIndex < 0 && nextInPath != null )
{
nextInPath = nextInPath.parent;
childIndex = IndexOf( nextInPath );
}
if( childIndex < 0 )
return null;
}
else
return null;
}
if( !CanExpand )
return null;
bool wasExpanded = IsExpanded;
if( !wasExpanded )
IsExpanded = true;
HierarchyDataTransform childItem = children[childIndex];
if( childItem.BoundTransform == target )
return childItem;
HierarchyDataTransform result = null;
if( childItem.BoundTransform == nextInPath )
{
Transform next = target;
Transform parent = next.parent;
while( parent != null && parent != nextInPath )
{
next = parent;
parent = next.parent;
}
if( parent != null )
result = childItem.FindTransform( target, next );
}
if( result != null && result.m_depth < 0 )
result = null;
if( result == null && !wasExpanded )
IsExpanded = false;
return result;
}
public virtual HierarchyDataTransform FindTransformInVisibleChildren( Transform target, int targetDepth = -1 )
{
for( int i = 0; i < children.Count; i++ )
{
HierarchyDataTransform child = children[i];
if( child.m_depth < 0 )
continue;
if( ReferenceEquals( child.BoundTransform, target ) )
{
if( targetDepth <= 0 || child.m_depth == targetDepth )
return child;
}
else if( ( targetDepth <= 0 || child.m_depth < targetDepth ) && child.IsExpanded && child.BoundTransform && target.IsChildOf( child.BoundTransform ) )
{
child = child.FindTransformInVisibleChildren( target, targetDepth );
if( child != null )
return child;
}
}
return null;
}
public abstract Transform GetChild( int index );
public int IndexOf( Transform transform )
{
for( int i = ChildCount - 1; i >= 0; i-- )
{
if( ReferenceEquals( GetChild( i ), transform ) )
return i;
}
return -1;
}
public void GetSiblingIndexTraversalList( List<int> traversalList )
{
traversalList.Clear();
HierarchyData current = this;
while( current.parent != null )
{
traversalList.Add( current.parent.children.IndexOf( (HierarchyDataTransform) current ) );
current = current.parent;
}
}
public HierarchyData TraverseSiblingIndexList( List<int> traversalList )
{
HierarchyData current = this;
for( int i = traversalList.Count - 1; i >= 0; i-- )
{
int siblingIndex = traversalList[i];
if( current.children == null || siblingIndex >= current.children.Count )
return null;
current = current.children[siblingIndex];
}
return current;
}
private void GenerateChildItem( Transform child, int index, RuntimeHierarchy hierarchy )
{
bool isChildVisible = !RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Contains( child );
if( isChildVisible && hierarchy.GameObjectFilter != null )
isChildVisible = hierarchy.GameObjectFilter( child );
HierarchyDataTransform childData;
int poolIndex = transformDataPool.Count - 1;
if( poolIndex >= 0 )
{
childData = transformDataPool[poolIndex];
transformDataPool.RemoveAt( poolIndex );
}
else
childData = new HierarchyDataTransform();
childData.Initialize( child, this is HierarchyDataRootSearch );
childData.parent = this;
if( isChildVisible )
{
childData.m_depth = m_depth + 1;
childData.m_height = 1;
}
else
{
childData.m_depth = -1;
childData.m_height = 0;
}
children.Insert( index, childData );
}
private void RemoveChildItem( int index )
{
children[index].PoolData();
transformDataPool.Add( children[index] );
children.RemoveAt( index );
}
protected void PoolChildrenList()
{
if( children != null )
{
for( int i = children.Count - 1; i >= 0; i-- )
{
children[i].PoolData();
transformDataPool.Add( children[i] );
}
children.Clear();
childrenListPool.Add( children );
children = null;
}
}
protected void PopChildrenList()
{
int desiredSize = ChildCount;
int bestFittingListIndex = -1;
int bestFittingListDeltaSize = int.MaxValue;
for( int i = childrenListPool.Count - 1; i >= 0; i-- )
{
int deltaSize = childrenListPool[i].Capacity - desiredSize;
if( deltaSize < 0 )
deltaSize = -deltaSize;
if( deltaSize < bestFittingListDeltaSize )
{
bestFittingListDeltaSize = deltaSize;
bestFittingListIndex = i;
}
}
if( bestFittingListIndex >= 0 )
{
children = childrenListPool[bestFittingListIndex];
childrenListPool.RemoveAt( bestFittingListIndex );
}
else
children = new List<HierarchyDataTransform>( ChildCount );
}
public static void ClearPool()
{
childrenListPool.Clear();
transformDataPool.Clear();
if( childrenListPool.Capacity > 128 )
childrenListPool.Capacity = 128;
if( transformDataPool.Capacity > 128 )
transformDataPool.Capacity = 128;
}
}
}