添加debug工具

This commit is contained in:
2024-09-03 19:56:21 +08:00
parent 187407cedb
commit aa4595f290
554 changed files with 59600 additions and 9992 deletions

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: eef0ffa98a129034fbcf9b8ddac213f6
folderAsset: yes
timeCreated: 1510168101
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,464 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class HierarchyDragDropListener : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
private const float POINTER_VALIDATE_INTERVAL = 5f;
#pragma warning disable 0649
[SerializeField]
private float siblingIndexModificationArea = 5f;
[SerializeField]
private float scrollableArea = 75f;
private float _1OverScrollableArea;
[SerializeField]
private float scrollSpeed = 75f;
[Header( "Internal Variables" )]
[SerializeField]
private RuntimeHierarchy hierarchy;
[SerializeField]
private RectTransform content;
[SerializeField]
private Image dragDropTargetVisualization;
#pragma warning restore 0649
private Canvas canvas;
private RectTransform rectTransform;
private float height;
private PointerEventData pointer;
private Camera worldCamera;
private float pointerLastYPos;
private float nextPointerValidation;
private void Start()
{
rectTransform = (RectTransform) transform;
canvas = hierarchy.GetComponentInParent<Canvas>();
_1OverScrollableArea = 1f / scrollableArea;
}
private void OnRectTransformDimensionsChange()
{
height = 0f;
}
private void Update()
{
if( pointer == null )
return;
nextPointerValidation -= Time.unscaledDeltaTime;
if( nextPointerValidation <= 0f )
{
nextPointerValidation = POINTER_VALIDATE_INTERVAL;
if( !pointer.IsPointerValid() )
{
pointer = null;
return;
}
}
Vector2 position;
if( RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, pointer.position, worldCamera, out position ) && position.y != pointerLastYPos )
{
pointerLastYPos = -position.y;
if( height <= 0f )
height = rectTransform.rect.height;
// Scroll the hierarchy when hovering near top or bottom edges
float scrollAmount = 0f;
float viewportYPos = pointerLastYPos;
if( pointerLastYPos < scrollableArea )
scrollAmount = ( scrollableArea - pointerLastYPos ) * _1OverScrollableArea;
else if( pointerLastYPos > height - scrollableArea )
scrollAmount = ( height - scrollableArea - viewportYPos ) * _1OverScrollableArea;
float contentYPos = pointerLastYPos + content.anchoredPosition.y;
if( contentYPos < 0f )
{
if( dragDropTargetVisualization.gameObject.activeSelf )
dragDropTargetVisualization.gameObject.SetActive( false );
hierarchy.AutoScrollSpeed = 0f;
}
else
{
if( contentYPos < hierarchy.ItemCount * hierarchy.Skin.LineHeight )
{
// Show a visual feedback of where the dragged object would be dropped to
if( !dragDropTargetVisualization.gameObject.activeSelf )
{
dragDropTargetVisualization.rectTransform.SetAsLastSibling();
dragDropTargetVisualization.gameObject.SetActive( true );
}
float relativePosition = contentYPos % hierarchy.Skin.LineHeight;
float absolutePosition = -contentYPos + relativePosition;
if( relativePosition < siblingIndexModificationArea )
{
// Dragged object will be dropped above the target
dragDropTargetVisualization.rectTransform.anchoredPosition = new Vector2( 0f, absolutePosition + 2f );
dragDropTargetVisualization.rectTransform.sizeDelta = new Vector2( 20f, 4f ); // 20f: The visualization extends beyond scrollbar
}
else if( relativePosition > hierarchy.Skin.LineHeight - siblingIndexModificationArea )
{
// Dragged object will be dropped below the target
dragDropTargetVisualization.rectTransform.anchoredPosition = new Vector2( 0f, absolutePosition - hierarchy.Skin.LineHeight + 2f );
dragDropTargetVisualization.rectTransform.sizeDelta = new Vector2( 20f, 4f );
}
else
{
// Dragged object will be dropped onto the target
dragDropTargetVisualization.rectTransform.anchoredPosition = new Vector2( 0f, absolutePosition );
dragDropTargetVisualization.rectTransform.sizeDelta = new Vector2( 20f, hierarchy.Skin.LineHeight );
}
}
else if( dragDropTargetVisualization.gameObject.activeSelf )
dragDropTargetVisualization.gameObject.SetActive( false );
hierarchy.AutoScrollSpeed = scrollAmount * scrollSpeed;
}
}
}
void IDropHandler.OnDrop( PointerEventData eventData )
{
( (IPointerExitHandler) this ).OnPointerExit( eventData );
if( !hierarchy.CanReorganizeItems || hierarchy.IsInSearchMode )
return;
Transform[] droppedTransforms = RuntimeInspectorUtils.GetAssignableObjectsFromDraggedReferenceItem<Transform>( eventData );
if( droppedTransforms == null || droppedTransforms.Length == 0 )
return;
// Sorting the selection is necessary to preserve the sibling index order of the dragged Transforms
if( droppedTransforms.Length > 1 )
System.Array.Sort( droppedTransforms, ( transform1, transform2 ) => CompareHierarchySiblingIndices( transform1, transform2 ) );
bool shouldFocusObjectInHierarchy = false;
float contentYPos = pointerLastYPos + content.anchoredPosition.y;
int dataIndex = (int) contentYPos / hierarchy.Skin.LineHeight;
HierarchyData target = hierarchy.GetDataAt( dataIndex );
if( target == null )
{
// Dropped Transform(s) onto the blank space at the bottom of the Hierarchy
for( int i = 0; i < droppedTransforms.Length; i++ )
{
if( droppedTransforms[i].parent != null )
{
droppedTransforms[i].SetParent( null, true );
shouldFocusObjectInHierarchy = true;
}
}
if( !shouldFocusObjectInHierarchy )
return;
}
else
{
int insertDirection;
float relativePosition = contentYPos % hierarchy.Skin.LineHeight;
if( relativePosition < siblingIndexModificationArea )
insertDirection = -1;
else if( relativePosition > hierarchy.Skin.LineHeight - siblingIndexModificationArea )
insertDirection = 1;
else
insertDirection = 0;
// Inserting above/below a scene or pseudo-scene is a special case
if( insertDirection != 0 && !( target is HierarchyDataTransform ) )
{
if( insertDirection < 0 && dataIndex > 0 )
{
// In an hierarchy with consecutive items A and B, insert below A instead of inserting above B because it makes calculations easier
HierarchyData _target = hierarchy.GetDataAt( dataIndex - 1 );
if( _target != null )
{
target = _target;
insertDirection = 1;
}
}
else if( insertDirection > 0 && dataIndex < hierarchy.ItemCount - 1 )
{
// In an hierarchy with consecutive items A and B where B is a Transform, insert above B instead of inserting below A because it makes calculations easier
HierarchyData _target = hierarchy.GetDataAt( dataIndex + 1 );
if( _target != null && _target is HierarchyDataTransform )
{
target = _target;
insertDirection = -1;
}
}
}
HierarchyDataRoot newScene = null;
Transform newParent = null;
int newSiblingIndex = -1;
if( !( target is HierarchyDataTransform ) )
{
// Dropped onto a scene or pseudo-scene
newScene = (HierarchyDataRoot) target;
}
else
{
// Dropped onto a Transform
newParent = ( (HierarchyDataTransform) target ).BoundTransform;
if( !newParent )
return;
if( insertDirection != 0 )
{
if( insertDirection > 0 && target.Height > 1 )
{
// Dropped below an expanded Transform, make dropped object a child of it
newSiblingIndex = 0;
}
else if( target.Depth == 1 && target.Root is HierarchyDataRootPseudoScene )
{
// Dropped above or below a root pseudo-scene object, don't actually change the parent
if( insertDirection < 0 )
newSiblingIndex = ( (HierarchyDataRootPseudoScene) target.Root ).IndexOf( newParent );
else
newSiblingIndex = ( (HierarchyDataRootPseudoScene) target.Root ).IndexOf( newParent ) + 1;
newParent = null;
}
else
{
// Dropped above or below a regular Transform, calculate target sibling index
if( insertDirection < 0 )
newSiblingIndex = newParent.GetSiblingIndex();
else
newSiblingIndex = newParent.GetSiblingIndex() + 1;
// To be able to drop the object at that sibling index, object's parent must also be changed
newParent = newParent.parent;
}
}
if( !newParent )
newScene = target.Root;
}
int successfullyDroppedTransformCount = 0;
for( int i = 0; i < droppedTransforms.Length; i++ )
{
bool _shouldFocusObjectInHierarchy, decrementSiblingIndex;
if( DropTransformOnto( droppedTransforms[i], target, newScene, newParent, ( newSiblingIndex >= 0 ) ? ( newSiblingIndex + successfullyDroppedTransformCount ) : newSiblingIndex, out decrementSiblingIndex, out _shouldFocusObjectInHierarchy ) )
{
successfullyDroppedTransformCount++;
shouldFocusObjectInHierarchy |= _shouldFocusObjectInHierarchy;
if( decrementSiblingIndex )
newSiblingIndex--;
}
}
if( successfullyDroppedTransformCount == 0 )
return;
}
// Don't reveal the selection unless it's necessary (i.e. selection is already fully visible)
if( shouldFocusObjectInHierarchy )
hierarchy.SelectInternal( droppedTransforms, RuntimeHierarchy.SelectOptions.FocusOnSelection | RuntimeHierarchy.SelectOptions.ForceRevealSelection );
else
hierarchy.Refresh();
}
private bool DropTransformOnto( Transform droppedTransform, HierarchyData target, HierarchyDataRoot newScene, Transform newParent, int newSiblingIndex, out bool decrementSiblingIndex, out bool shouldFocusObjectInHierarchy )
{
shouldFocusObjectInHierarchy = false;
decrementSiblingIndex = false;
// If we are only changing the sibling index of the dropped Transform and not its parent, then make sure
// that the target sibling index won't be affected when the dropped Transform is shifted in the Hierarchy
if( droppedTransform.parent == newParent )
{
if( newParent || ( newScene is HierarchyDataRootScene && ( (HierarchyDataRootScene) newScene ).Scene == droppedTransform.gameObject.scene ) )
{
if( newSiblingIndex > droppedTransform.GetSiblingIndex() )
{
newSiblingIndex--;
decrementSiblingIndex = true;
}
}
else if( newScene is HierarchyDataRootPseudoScene )
{
int pseudoSceneSiblingIndex = newScene.IndexOf( droppedTransform );
if( pseudoSceneSiblingIndex >= 0 && newSiblingIndex > pseudoSceneSiblingIndex )
{
newSiblingIndex--;
decrementSiblingIndex = true;
}
}
}
if( newParent ) // Drop inside a Transform
{
if( !hierarchy.CanDropDraggedParentOnChild )
{
// Avoid setting child object as parent of the parent object
if( newParent.IsChildOf( droppedTransform ) )
return false;
}
else
{
Transform curr = newParent;
while( curr.parent != null && curr.parent != droppedTransform )
curr = curr.parent;
// First, set the child object's parent as the dropped object's current parent so that
// the dropped object can then become a child of the former child object
if( curr.parent == droppedTransform )
{
HierarchyDataRootPseudoScene pseudoScene = target.Root as HierarchyDataRootPseudoScene;
int pseudoSceneChildIndex;
if( pseudoScene != null && ( pseudoSceneChildIndex = pseudoScene.IndexOf( droppedTransform ) ) >= 0 )
{
// Dropped object was a root pseudo-scene object, swap the child and parent objects in the pseudo-scene, as well
if( hierarchy.CanDropDraggedObjectsToPseudoScenes )
{
pseudoScene.InsertChild( pseudoSceneChildIndex, curr );
pseudoScene.RemoveChild( droppedTransform );
}
}
int siblingIndex = droppedTransform.GetSiblingIndex();
curr.SetParent( droppedTransform.parent, true );
curr.SetSiblingIndex( siblingIndex );
shouldFocusObjectInHierarchy = true;
}
}
droppedTransform.SetParent( newParent, true );
}
else // Drop at the root of a scene
{
if( newScene is HierarchyDataRootPseudoScene )
{
if( !hierarchy.CanDropDraggedObjectsToPseudoScenes )
return false;
// Add object to pseudo-scene
if( newSiblingIndex < 0 )
( (HierarchyDataRootPseudoScene) newScene ).AddChild( droppedTransform );
else
{
( (HierarchyDataRootPseudoScene) newScene ).InsertChild( newSiblingIndex, droppedTransform );
// Don't try to change the actual sibling index of the Transform
newSiblingIndex = -1;
target = newScene;
}
}
else if( newScene is HierarchyDataRootScene )
{
if( droppedTransform.parent != null )
droppedTransform.SetParent( null, true );
// Change dropped object's scene
Scene scene = ( (HierarchyDataRootScene) newScene ).Scene;
if( droppedTransform.gameObject.scene != scene )
SceneManager.MoveGameObjectToScene( droppedTransform.gameObject, scene );
if( newSiblingIndex < 0 )
{
// If object was dropped onto the scene, add it to the bottom of the scene
newSiblingIndex = scene.rootCount + 1;
shouldFocusObjectInHierarchy = true;
}
}
}
if( newSiblingIndex >= 0 )
droppedTransform.SetSiblingIndex( newSiblingIndex );
shouldFocusObjectInHierarchy |= ( newSiblingIndex < 0 && !target.IsExpanded );
return true;
}
// Returns -1 if t1 is above t2 in Hierarchy, 1 if t1 is below t2 in Hierarchy and 0 if they are the same object
private int CompareHierarchySiblingIndices( Transform t1, Transform t2 )
{
Transform parent1 = t1.parent;
Transform parent2 = t2.parent;
if( parent1 == parent2 )
return t1.GetSiblingIndex() - t2.GetSiblingIndex();
int deltaHierarchyDepth = 0;
for( ; parent1; parent1 = parent1.parent )
deltaHierarchyDepth++;
for( ; parent2; parent2 = parent2.parent )
deltaHierarchyDepth--;
for( ; deltaHierarchyDepth > 0; deltaHierarchyDepth-- )
{
t1 = t1.parent;
if( t1 == t2 )
return 1;
}
for( ; deltaHierarchyDepth < 0; deltaHierarchyDepth++ )
{
t2 = t2.parent;
if( t1 == t2 )
return -1;
}
while( t1.parent != t2.parent )
{
t1 = t1.parent;
t2 = t2.parent;
}
return t1.GetSiblingIndex() - t2.GetSiblingIndex();
}
void IPointerEnterHandler.OnPointerEnter( PointerEventData eventData )
{
if( !hierarchy.CanReorganizeItems || hierarchy.IsInSearchMode )
return;
if( !RuntimeInspectorUtils.GetAssignableObjectFromDraggedReferenceItem<Transform>( eventData ) )
return;
pointer = eventData;
pointerLastYPos = -1f;
nextPointerValidation = POINTER_VALIDATE_INTERVAL;
if( canvas.renderMode == RenderMode.ScreenSpaceOverlay || ( canvas.renderMode == RenderMode.ScreenSpaceCamera && !canvas.worldCamera ) )
worldCamera = null;
else
worldCamera = canvas.worldCamera ? canvas.worldCamera : Camera.main;
Update();
}
void IPointerExitHandler.OnPointerExit( PointerEventData eventData )
{
pointer = null;
worldCamera = null;
if( dragDropTargetVisualization.gameObject.activeSelf )
dragDropTargetVisualization.gameObject.SetActive( false );
hierarchy.AutoScrollSpeed = 0f;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: be531524081657c479afb27aaa9501ac
timeCreated: 1525163086
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,152 @@
using System.Collections.Generic;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class PseudoSceneSourceTransform : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField]
private RuntimeHierarchy m_hierarchy;
public RuntimeHierarchy Hierarchy
{
get { return m_hierarchy; }
set
{
if( m_hierarchy != value )
{
RemoveChildrenFromScene();
m_hierarchy = value;
AddChildrenToScene();
}
}
}
[SerializeField]
private string m_sceneName;
public string SceneName
{
get { return m_sceneName; }
set
{
if( m_sceneName != value )
{
RemoveChildrenFromScene();
m_sceneName = value;
AddChildrenToScene();
}
}
}
[SerializeField]
private bool m_hideOnDisable = false;
public bool HideOnDisable
{
get { return m_hideOnDisable; }
set
{
if( m_hideOnDisable != value )
{
m_hideOnDisable = value;
if( !isEnabled )
{
if( value )
RemoveChildrenFromScene();
else
AddChildrenToScene();
}
}
}
}
#pragma warning restore 0649
private HashSet<Transform> childrenCurrent = new HashSet<Transform>();
private HashSet<Transform> childrenNew = new HashSet<Transform>();
private bool updateChildren = false;
private bool isEnabled = true;
private bool isQuitting = false;
private bool ShouldUpdateChildren { get { return ( isEnabled || !m_hideOnDisable ) && Hierarchy && !string.IsNullOrEmpty( m_sceneName ); } }
private void OnEnable()
{
isEnabled = true;
updateChildren = true;
}
private void OnDisable()
{
if( isQuitting )
return;
isEnabled = false;
if( m_hideOnDisable )
RemoveChildrenFromScene();
}
private void OnApplicationQuit()
{
isQuitting = true;
}
private void OnTransformChildrenChanged()
{
updateChildren = true;
}
private void Update()
{
if( updateChildren )
{
updateChildren = false;
if( !ShouldUpdateChildren )
return;
for( int i = 0; i < transform.childCount; i++ )
{
Transform child = transform.GetChild( i );
childrenNew.Add( child );
if( !childrenCurrent.Remove( child ) )
Hierarchy.AddToPseudoScene( m_sceneName, child );
}
RemoveChildrenFromScene();
HashSet<Transform> temp = childrenCurrent;
childrenCurrent = childrenNew;
childrenNew = temp;
}
}
private void AddChildrenToScene()
{
if( !ShouldUpdateChildren )
return;
for( int i = 0; i < transform.childCount; i++ )
{
Transform child = transform.GetChild( i );
if( childrenCurrent.Add( child ) )
Hierarchy.AddToPseudoScene( m_sceneName, child );
}
}
private void RemoveChildrenFromScene()
{
if( !Hierarchy || string.IsNullOrEmpty( m_sceneName ) )
return;
foreach( Transform removedChild in childrenCurrent )
{
if( removedChild )
Hierarchy.RemoveFromPseudoScene( m_sceneName, removedChild, true );
}
childrenCurrent.Clear();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e1a4ef3d1723234408a97a84690ab8bb
timeCreated: 1510168133
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,441 @@
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;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 328d45f703d254c4aa61dfe88bdc5977
timeCreated: 1582458939
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,52 @@
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public abstract class HierarchyDataRoot : HierarchyData
{
public override Transform BoundTransform { get { return null; } }
public override bool IsActive { get { return true; } }
public RuntimeHierarchy Hierarchy { get; private set; }
protected HierarchyDataRoot( RuntimeHierarchy hierarchy )
{
Hierarchy = hierarchy;
// Root data are expanded by default
PopChildrenList();
}
public abstract Transform GetNearestRootOf( Transform target );
public abstract void RefreshContent();
public override bool Refresh()
{
RefreshContent();
return base.Refresh();
}
public override HierarchyDataTransform FindTransformInVisibleChildren( Transform target, int targetDepth = -1 )
{
return ( m_depth >= 0 && IsExpanded ) ? base.FindTransformInVisibleChildren( target, targetDepth ) : null;
}
public void ResetCachedNames()
{
if( children != null )
{
for( int i = children.Count - 1; i >= 0; i-- )
children[i].ResetCachedName();
}
}
public void RefreshNameOf( Transform target )
{
if( children != null )
{
for( int i = children.Count - 1; i >= 0; i-- )
children[i].RefreshNameOf( target );
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: faafaff4766ca384399d116b1be6de4f
timeCreated: 1508420714
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
using System.Collections.Generic;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class HierarchyDataRootPseudoScene : HierarchyDataRoot
{
private readonly string name;
public override string Name { get { return name; } }
public override int ChildCount { get { return rootObjects.Count; } }
private readonly List<Transform> rootObjects = new List<Transform>();
public HierarchyDataRootPseudoScene( RuntimeHierarchy hierarchy, string name ) : base( hierarchy )
{
this.name = name;
}
public void AddChild( Transform child )
{
if( !rootObjects.Contains( child ) )
rootObjects.Add( child );
}
public void InsertChild( int index, Transform child )
{
index = Mathf.Clamp( index, 0, rootObjects.Count );
rootObjects.Insert( index, child );
// If the object was already in the list, remove the old copy from the list
for( int i = rootObjects.Count - 1; i >= 0; i-- )
{
if( i != index && rootObjects[i] == child )
{
rootObjects.RemoveAt( i );
return;
}
}
}
public void RemoveChild( Transform child )
{
rootObjects.Remove( child );
}
public override void RefreshContent()
{
for( int i = rootObjects.Count - 1; i >= 0; i-- )
{
if( !rootObjects[i] )
rootObjects.RemoveAt( i );
}
}
public override Transform GetChild( int index )
{
return rootObjects[index];
}
public override Transform GetNearestRootOf( Transform target )
{
Transform result = null;
for( int i = rootObjects.Count - 1; i >= 0; i-- )
{
Transform rootObject = rootObjects[i];
if( rootObject && target.IsChildOf( rootObject ) && ( !result || rootObject.IsChildOf( result ) ) )
result = rootObject;
}
return result;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 71d649a158c3ff449a319b49ee730ccb
timeCreated: 1508420714
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace RuntimeInspectorNamespace
{
public class HierarchyDataRootScene : HierarchyDataRoot
{
public override string Name { get { return Scene.name; } }
public override int ChildCount { get { return rootObjects.Count; } }
public Scene Scene { get; private set; }
private readonly List<GameObject> rootObjects = new List<GameObject>();
public HierarchyDataRootScene( RuntimeHierarchy hierarchy, Scene target ) : base( hierarchy )
{
Scene = target;
}
public override void RefreshContent()
{
rootObjects.Clear();
if( Scene.isLoaded )
Scene.GetRootGameObjects( rootObjects );
}
public override Transform GetChild( int index )
{
return rootObjects[index].transform;
}
public override Transform GetNearestRootOf( Transform target )
{
return ( target.gameObject.scene == Scene ) ? target.root : null;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: efbc9d53cb584f74a869dbf48ff4c7bd
timeCreated: 1508420714
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
using System.Collections.Generic;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class HierarchyDataRootSearch : HierarchyDataRoot
{
public override string Name { get { return reference.Name; } }
public override int ChildCount { get { return searchResult.Count; } }
private readonly List<Transform> searchResult = new List<Transform>();
private readonly HierarchyDataRoot reference;
private string searchTerm;
public HierarchyDataRootSearch( RuntimeHierarchy hierarchy, HierarchyDataRoot reference ) : base( hierarchy )
{
this.reference = reference;
}
public override void RefreshContent()
{
if( !Hierarchy.IsInSearchMode )
return;
searchResult.Clear();
searchTerm = Hierarchy.SearchTerm;
int childCount = reference.ChildCount;
for( int i = 0; i < childCount; i++ )
{
Transform obj = reference.GetChild( i );
if( !obj )
continue;
if( RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Contains( obj.transform ) )
continue;
if( obj.name.IndexOf( searchTerm, System.StringComparison.OrdinalIgnoreCase ) >= 0 )
searchResult.Add( obj );
SearchTransformRecursively( obj.transform );
}
}
public override bool Refresh()
{
m_depth = 0;
bool result = base.Refresh();
// Scenes with no matching search results should be hidden in search mode
if( searchResult.Count == 0 )
{
m_height = 0;
m_depth = -1;
}
return result;
}
public override HierarchyDataTransform FindTransformInVisibleChildren( Transform target, int targetDepth = -1 )
{
if( m_depth < 0 || targetDepth > 1 || !IsExpanded )
return null;
for( int i = children.Count - 1; i >= 0; i-- )
{
if( ReferenceEquals( children[i].BoundTransform, target ) )
return children[i];
}
return null;
}
private void SearchTransformRecursively( Transform obj )
{
for( int i = 0; i < obj.childCount; i++ )
{
Transform child = obj.GetChild( i );
if( RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Contains( child ) )
continue;
if( child.name.IndexOf( searchTerm, System.StringComparison.OrdinalIgnoreCase ) >= 0 )
searchResult.Add( child );
SearchTransformRecursively( child );
}
}
public override Transform GetChild( int index )
{
return searchResult[index];
}
public override Transform GetNearestRootOf( Transform target )
{
return searchResult.Contains( target ) ? target : null;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7141026a6a1bd764f9a609622b8a70f1
timeCreated: 1508420714
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,69 @@
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class HierarchyDataTransform : HierarchyData
{
private string cachedName;
public override string Name
{
get
{
if( cachedName == null )
cachedName = transform ? transform.name : "<destroyed>";
return cachedName;
}
}
public override int ChildCount { get { return ( !isSearchEntry && transform ) ? transform.childCount : 0; } }
public override Transform BoundTransform { get { return transform; } }
public override bool IsActive { get { return transform ? transform.gameObject.activeInHierarchy : true; } }
private Transform transform;
private bool isSearchEntry;
public void Initialize( Transform transform, bool isSearchEntry )
{
this.transform = transform;
this.isSearchEntry = isSearchEntry;
}
public override Transform GetChild( int index )
{
return transform.GetChild( index );
}
public void ResetCachedName()
{
cachedName = null;
if( children != null )
{
for( int i = children.Count - 1; i >= 0; i-- )
children[i].ResetCachedName();
}
}
public void RefreshNameOf( Transform target )
{
if( ReferenceEquals( transform, target ) )
cachedName = target.name;
else if( children != null )
{
for( int i = children.Count - 1; i >= 0; i-- )
children[i].RefreshNameOf( target );
}
}
public void PoolData()
{
parent = null;
cachedName = null;
m_depth = 0;
m_height = 0;
PoolChildrenList();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3da479804f0113d4fbde323d386a55f7
timeCreated: 1508420714
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,213 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class HierarchyField : RecycledListItem, ITooltipContent
{
private enum ExpandedState { Collapsed = 0, Expanded = 1, ArrowHidden = 2 };
private const float INACTIVE_ITEM_TEXT_ALPHA = 0.57f;
private const float TEXT_X_OFFSET = 35f;
#pragma warning disable 0649
[SerializeField]
private RectTransform contentTransform;
[SerializeField]
private Text nameText;
[SerializeField]
private PointerEventListener clickListener;
[SerializeField]
private PointerEventListener expandToggle;
[SerializeField]
private Image expandArrow;
[SerializeField]
private Toggle multiSelectionToggle;
[SerializeField]
private Image multiSelectionToggleBackground;
#pragma warning restore 0649
private RectTransform rectTransform;
private Image background;
private int m_skinVersion = 0;
private UISkin m_skin;
public UISkin Skin
{
get { return m_skin; }
set
{
if( m_skin != value || m_skinVersion != m_skin.Version )
{
m_skin = value;
m_skinVersion = m_skin.Version;
rectTransform.sizeDelta = new Vector2( 0f, Skin.LineHeight );
nameText.SetSkinText( Skin );
expandArrow.color = Skin.ExpandArrowColor;
nameText.rectTransform.anchoredPosition = new Vector2( Skin.ExpandArrowSpacing + Skin.LineHeight * 0.75f, 0f );
( (RectTransform) expandToggle.transform ).sizeDelta = new Vector2( Skin.LineHeight, Skin.LineHeight );
( (RectTransform) multiSelectionToggle.transform ).sizeDelta = new Vector2( Skin.LineHeight * 0.8f, Skin.LineHeight * 0.8f );
multiSelectionToggle.graphic.color = Skin.ToggleCheckmarkColor;
multiSelectionToggleBackground.color = Skin.InputFieldNormalBackgroundColor;
}
}
}
private bool m_isSelected;
public bool IsSelected
{
get { return m_isSelected; }
set
{
m_isSelected = value;
Color textColor;
if( m_isSelected )
{
background.color = Skin.SelectedItemBackgroundColor;
textColor = Skin.SelectedItemTextColor;
}
else
{
background.color = Data.Depth == 0 ? Skin.BackgroundColor.Tint( 0.075f ) : Color.clear;
textColor = Skin.TextColor;
}
textColor.a = m_isActive ? 1f : INACTIVE_ITEM_TEXT_ALPHA;
nameText.color = textColor;
multiSelectionToggle.isOn = m_isSelected;
}
}
private bool m_isActive;
private bool IsActive
{
get { return m_isActive; }
set
{
if( m_isActive != value )
{
m_isActive = value;
Color color = nameText.color;
color.a = m_isActive ? 1f : INACTIVE_ITEM_TEXT_ALPHA;
nameText.color = color;
}
}
}
public bool MultiSelectionToggleVisible
{
get { return multiSelectionToggle.gameObject.activeSelf; }
set
{
if( Data == null || Data.Depth <= 0 )
value = false;
if( multiSelectionToggle.gameObject.activeSelf != value )
{
multiSelectionToggle.gameObject.SetActive( value );
contentTransform.anchoredPosition = new Vector2( Skin.IndentAmount * Data.Depth + ( value ? Skin.LineHeight * 0.8f : 0f ), 0f );
}
}
}
private ExpandedState m_isExpanded = ExpandedState.Collapsed;
private ExpandedState IsExpanded
{
get { return m_isExpanded; }
set
{
if( m_isExpanded != value )
{
m_isExpanded = value;
if( m_isExpanded == ExpandedState.ArrowHidden )
expandToggle.gameObject.SetActive( false );
else
{
expandToggle.gameObject.SetActive( true );
expandArrow.rectTransform.localEulerAngles = m_isExpanded == ExpandedState.Expanded ? new Vector3( 0f, 0f, -90f ) : Vector3.zero;
}
}
}
}
bool ITooltipContent.IsActive { get { return this && gameObject.activeSelf; } }
string ITooltipContent.TooltipText { get { return Data.Name; } }
public float PreferredWidth { get; private set; }
public RuntimeHierarchy Hierarchy { get; private set; }
public HierarchyData Data { get; private set; }
public void Initialize( RuntimeHierarchy hierarchy )
{
Hierarchy = hierarchy;
rectTransform = (RectTransform) transform;
background = clickListener.GetComponent<Image>();
if( hierarchy.ShowTooltips )
clickListener.gameObject.AddComponent<TooltipArea>().Initialize( hierarchy.TooltipListener, this );
expandToggle.PointerClick += ( eventData ) => ToggleExpandedState();
clickListener.PointerClick += ( eventData ) => OnClick();
clickListener.PointerDown += OnPointerDown;
clickListener.PointerUp += OnPointerUp;
}
public void SetContent( HierarchyData data )
{
Data = data;
contentTransform.anchoredPosition = new Vector2( Skin.IndentAmount * data.Depth + ( MultiSelectionToggleVisible ? Skin.LineHeight * 0.8f : 0f ), 0f );
background.sprite = data.Depth == 0 ? Hierarchy.SceneDrawerBackground : Hierarchy.TransformDrawerBackground;
RefreshName();
}
private void ToggleExpandedState()
{
Data.IsExpanded = !Data.IsExpanded;
}
public void Refresh()
{
IsActive = Data.IsActive;
IsExpanded = Data.CanExpand ? ( Data.IsExpanded ? ExpandedState.Expanded : ExpandedState.Collapsed ) : ExpandedState.ArrowHidden;
}
public void RefreshName()
{
nameText.text = Data.Name;
if( Hierarchy.ShowHorizontalScrollbar )
{
LayoutRebuilder.ForceRebuildLayoutImmediate( nameText.rectTransform );
PreferredWidth = Data.Depth * m_skin.IndentAmount + TEXT_X_OFFSET + nameText.rectTransform.sizeDelta.x;
}
}
private void OnPointerDown( PointerEventData eventData )
{
Hierarchy.OnDrawerPointerEvent( this, eventData, true );
}
private void OnPointerUp( PointerEventData eventData )
{
Hierarchy.OnDrawerPointerEvent( this, eventData, false );
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3e312fb4db3dfda40b7e02269d07e9ef
timeCreated: 1582458911
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: