添加debug工具
This commit is contained in:
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eef0ffa98a129034fbcf9b8ddac213f6
|
||||
folderAsset: yes
|
||||
timeCreated: 1510168101
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be531524081657c479afb27aaa9501ac
|
||||
timeCreated: 1525163086
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1a4ef3d1723234408a97a84690ab8bb
|
||||
timeCreated: 1510168133
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 328d45f703d254c4aa61dfe88bdc5977
|
||||
timeCreated: 1582458939
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: faafaff4766ca384399d116b1be6de4f
|
||||
timeCreated: 1508420714
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71d649a158c3ff449a319b49ee730ccb
|
||||
timeCreated: 1508420714
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efbc9d53cb584f74a869dbf48ff4c7bd
|
||||
timeCreated: 1508420714
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7141026a6a1bd764f9a609622b8a70f1
|
||||
timeCreated: 1508420714
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3da479804f0113d4fbde323d386a55f7
|
||||
timeCreated: 1508420714
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e312fb4db3dfda40b7e02269d07e9ef
|
||||
timeCreated: 1582458911
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user