添加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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

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:

View File

@ -0,0 +1,655 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class RuntimeInspector : SkinnedWindow, ITooltipManager
{
public enum VariableVisibility { None = 0, SerializableOnly = 1, All = 2 };
public enum HeaderVisibility { Collapsible = 0, AlwaysVisible = 1, Hidden = 2 };
private const string POOL_OBJECT_NAME = "RuntimeInspectorPool";
public delegate object InspectedObjectChangingDelegate( object previousInspectedObject, object newInspectedObject );
public delegate void ComponentFilterDelegate( GameObject gameObject, List<Component> components );
#pragma warning disable 0649
[SerializeField, UnityEngine.Serialization.FormerlySerializedAs( "refreshInterval" )]
private float m_refreshInterval = 0f;
private float nextRefreshTime = -1f;
public float RefreshInterval
{
get { return m_refreshInterval; }
set { m_refreshInterval = value; }
}
[Space]
[SerializeField]
private VariableVisibility m_exposeFields = VariableVisibility.SerializableOnly;
public VariableVisibility ExposeFields
{
get { return m_exposeFields; }
set
{
if( m_exposeFields != value )
{
m_exposeFields = value;
isDirty = true;
}
}
}
[SerializeField]
private VariableVisibility m_exposeProperties = VariableVisibility.SerializableOnly;
public VariableVisibility ExposeProperties
{
get { return m_exposeProperties; }
set
{
if( m_exposeProperties != value )
{
m_exposeProperties = value;
isDirty = true;
}
}
}
[Space]
[SerializeField]
private bool m_arrayIndicesStartAtOne = false;
public bool ArrayIndicesStartAtOne
{
get { return m_arrayIndicesStartAtOne; }
set
{
if( m_arrayIndicesStartAtOne != value )
{
m_arrayIndicesStartAtOne = value;
isDirty = true;
}
}
}
[SerializeField]
private bool m_useTitleCaseNaming = false;
public bool UseTitleCaseNaming
{
get { return m_useTitleCaseNaming; }
set
{
if( m_useTitleCaseNaming != value )
{
m_useTitleCaseNaming = value;
isDirty = true;
}
}
}
[Space]
[SerializeField]
private bool m_showAddComponentButton = true;
public bool ShowAddComponentButton
{
get { return m_showAddComponentButton; }
set
{
if( m_showAddComponentButton != value )
{
m_showAddComponentButton = value;
isDirty = true;
}
}
}
[SerializeField]
private bool m_showRemoveComponentButton = true;
public bool ShowRemoveComponentButton
{
get { return m_showRemoveComponentButton; }
set
{
if( m_showRemoveComponentButton != value )
{
m_showRemoveComponentButton = value;
isDirty = true;
}
}
}
[Space]
[SerializeField]
private bool m_showTooltips;
public bool ShowTooltips { get { return m_showTooltips; } }
[SerializeField]
private float m_tooltipDelay = 0.5f;
public float TooltipDelay
{
get { return m_tooltipDelay; }
set { m_tooltipDelay = value; }
}
internal TooltipListener TooltipListener { get; private set; }
[Space]
[SerializeField]
private int m_nestLimit = 5;
public int NestLimit
{
get { return m_nestLimit; }
set
{
if( m_nestLimit != value )
{
m_nestLimit = value;
isDirty = true;
}
}
}
[SerializeField]
private HeaderVisibility m_inspectedObjectHeaderVisibility = HeaderVisibility.Collapsible;
public HeaderVisibility InspectedObjectHeaderVisibility
{
get { return m_inspectedObjectHeaderVisibility; }
set
{
if( m_inspectedObjectHeaderVisibility != value )
{
m_inspectedObjectHeaderVisibility = value;
if( currentDrawer != null && currentDrawer is ExpandableInspectorField )
( (ExpandableInspectorField) currentDrawer ).HeaderVisibility = m_inspectedObjectHeaderVisibility;
}
}
}
[SerializeField]
private int poolCapacity = 10;
private Transform poolParent;
[SerializeField]
private RuntimeHierarchy m_connectedHierarchy;
public RuntimeHierarchy ConnectedHierarchy
{
get { return m_connectedHierarchy; }
set { m_connectedHierarchy = value; }
}
[SerializeField]
private RuntimeInspectorSettings[] settings;
private bool m_isLocked = false;
public bool IsLocked
{
get { return m_isLocked; }
set { m_isLocked = value; }
}
[Header( "Internal Variables" )]
[SerializeField]
private ScrollRect scrollView;
private RectTransform drawArea;
[SerializeField]
private Image background;
[SerializeField]
private Image scrollbar;
#pragma warning restore 0649
private static int aliveInspectors = 0;
private bool initialized = false;
private readonly Dictionary<Type, InspectorField[]> typeToDrawers = new Dictionary<Type, InspectorField[]>( 89 );
private readonly Dictionary<Type, InspectorField[]> typeToReferenceDrawers = new Dictionary<Type, InspectorField[]>( 89 );
private readonly List<InspectorField> eligibleDrawers = new List<InspectorField>( 4 );
private static readonly Dictionary<Type, List<InspectorField>> drawersPool = new Dictionary<Type, List<InspectorField>>();
private readonly List<VariableSet> hiddenVariables = new List<VariableSet>( 32 );
private readonly List<VariableSet> exposedVariables = new List<VariableSet>( 32 );
private InspectorField currentDrawer = null;
private bool inspectLock = false;
private bool isDirty = false;
private object m_inspectedObject;
public object InspectedObject { get { return m_inspectedObject; } }
public bool IsBound { get { return !m_inspectedObject.IsNull(); } }
private Canvas m_canvas;
public Canvas Canvas { get { return m_canvas; } }
// Used to make sure that the scrolled content always remains within the scroll view's boundaries
private PointerEventData nullPointerEventData;
public InspectedObjectChangingDelegate OnInspectedObjectChanging;
private ComponentFilterDelegate m_componentFilter;
public ComponentFilterDelegate ComponentFilter
{
get { return m_componentFilter; }
set
{
m_componentFilter = value;
Refresh();
}
}
protected override void Awake()
{
base.Awake();
Initialize();
}
private void Initialize()
{
if( initialized )
return;
initialized = true;
drawArea = scrollView.content;
m_canvas = GetComponentInParent<Canvas>();
nullPointerEventData = new PointerEventData( null );
if( m_showTooltips )
{
TooltipListener = gameObject.AddComponent<TooltipListener>();
TooltipListener.Initialize( this );
}
GameObject poolParentGO = GameObject.Find( POOL_OBJECT_NAME );
if( poolParentGO == null )
{
poolParentGO = new GameObject( POOL_OBJECT_NAME );
DontDestroyOnLoad( poolParentGO );
}
poolParent = poolParentGO.transform;
aliveInspectors++;
for( int i = 0; i < settings.Length; i++ )
{
if( !settings[i] )
continue;
VariableSet[] hiddenVariablesForTypes = settings[i].HiddenVariables;
for( int j = 0; j < hiddenVariablesForTypes.Length; j++ )
{
VariableSet hiddenVariablesSet = hiddenVariablesForTypes[j];
if( hiddenVariablesSet.Init() )
hiddenVariables.Add( hiddenVariablesSet );
}
VariableSet[] exposedVariablesForTypes = settings[i].ExposedVariables;
for( int j = 0; j < exposedVariablesForTypes.Length; j++ )
{
VariableSet exposedVariablesSet = exposedVariablesForTypes[j];
if( exposedVariablesSet.Init() )
exposedVariables.Add( exposedVariablesSet );
}
}
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Add( drawArea );
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Add( poolParent );
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
// On new Input System, scroll sensitivity is much higher than legacy Input system
scrollView.scrollSensitivity *= 0.25f;
#endif
}
private void OnDestroy()
{
if( --aliveInspectors == 0 )
{
if( poolParent )
{
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Remove( poolParent );
DestroyImmediate( poolParent.gameObject );
}
ColorPicker.DestroyInstance();
ObjectReferencePicker.DestroyInstance();
drawersPool.Clear();
}
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Remove( drawArea );
}
private void OnTransformParentChanged()
{
m_canvas = GetComponentInParent<Canvas>();
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
if( UnityEditor.EditorApplication.isPlaying )
isDirty = true;
}
#endif
protected override void Update()
{
base.Update();
if( IsBound )
{
float time = Time.realtimeSinceStartup;
if( isDirty )
{
// Rebind to refresh the exposed variables in Inspector
object inspectedObject = m_inspectedObject;
StopInspectInternal();
InspectInternal( inspectedObject );
isDirty = false;
nextRefreshTime = time + m_refreshInterval;
}
else
{
if( time > nextRefreshTime )
{
nextRefreshTime = time + m_refreshInterval;
Refresh();
}
}
}
else if( currentDrawer != null )
StopInspectInternal();
}
public void Refresh()
{
if( IsBound )
{
if( currentDrawer == null )
m_inspectedObject = null;
else
currentDrawer.Refresh();
}
}
// Refreshes the Inspector in the next Update. Called by most of the InspectorDrawers
// when their values have changed. If a drawer is bound to a property whose setter
// may modify the input data (e.g. when input data is 20 but the setter clamps it to 10),
// the drawer's BoundInputFields will still show the unmodified input data (20) until the
// next Refresh. That is because BoundInputFields don't have access to the fields/properties
// they are modifying, there is no way for the BoundInputFields to know whether or not
// the property has modified the input data (changed it from 20 to 10).
//
// Why not refresh only the changed InspectorDrawers? Because changing a property may affect
// multiple fields/properties that are bound to other drawers, we don't know which
// drawers may be affected. The safest way is to refresh all the drawers.
//
// Why not Refresh? That's the hacky part: most drawers call this function in their
// BoundInputFields' OnValueSubmitted event. If Refresh was used, BoundInputField's
// "recentText = str;" line that is called after the OnValueSubmitted event would mess up
// with refreshing the value displayed on the BoundInputField.
public void RefreshDelayed()
{
nextRefreshTime = 0f;
}
// Makes sure that scroll view's contents are within scroll view's bounds
internal void EnsureScrollViewIsWithinBounds()
{
// When scrollbar is snapped to the very bottom of the scroll view, sometimes OnScroll alone doesn't work
if( scrollView.verticalNormalizedPosition <= Mathf.Epsilon )
scrollView.verticalNormalizedPosition = 0.0001f;
scrollView.OnScroll( nullPointerEventData );
}
protected override void RefreshSkin()
{
background.color = Skin.BackgroundColor;
scrollbar.color = Skin.ScrollbarColor;
if( IsBound && !isDirty )
currentDrawer.Skin = Skin;
}
public void Inspect( object obj )
{
if( !m_isLocked )
InspectInternal( obj );
}
internal void InspectInternal( object obj )
{
if( inspectLock )
return;
isDirty = false;
Initialize();
if( OnInspectedObjectChanging != null )
obj = OnInspectedObjectChanging( m_inspectedObject, obj );
if( m_inspectedObject == obj )
return;
StopInspectInternal();
inspectLock = true;
try
{
m_inspectedObject = obj;
if( obj.IsNull() )
return;
#if UNITY_EDITOR || !NETFX_CORE
if( obj.GetType().IsValueType )
#else
if( obj.GetType().GetTypeInfo().IsValueType )
#endif
{
m_inspectedObject = null;
Debug.LogError( "Can't inspect a value type!" );
return;
}
//if( !gameObject.activeSelf )
//{
// m_inspectedObject = null;
// Debug.LogError( "Can't inspect while Inspector is inactive!" );
// return;
//}
InspectorField inspectedObjectDrawer = CreateDrawerForType( obj.GetType(), drawArea, 0, false );
if( inspectedObjectDrawer != null )
{
inspectedObjectDrawer.BindTo( obj.GetType(), string.Empty, () => m_inspectedObject, ( value ) => m_inspectedObject = value );
inspectedObjectDrawer.NameRaw = obj.GetNameWithType();
inspectedObjectDrawer.Refresh();
if( inspectedObjectDrawer is ExpandableInspectorField )
( (ExpandableInspectorField) inspectedObjectDrawer ).IsExpanded = true;
currentDrawer = inspectedObjectDrawer;
if( currentDrawer is ExpandableInspectorField )
( (ExpandableInspectorField) currentDrawer ).HeaderVisibility = m_inspectedObjectHeaderVisibility;
GameObject go = m_inspectedObject as GameObject;
if( !go && m_inspectedObject as Component )
go = ( (Component) m_inspectedObject ).gameObject;
if( ConnectedHierarchy && go && !ConnectedHierarchy.Select( go.transform, RuntimeHierarchy.SelectOptions.FocusOnSelection ) )
ConnectedHierarchy.Deselect();
}
else
m_inspectedObject = null;
}
finally
{
inspectLock = false;
}
}
public void StopInspect()
{
if( !m_isLocked )
StopInspectInternal();
}
internal void StopInspectInternal()
{
if( inspectLock )
return;
if( currentDrawer != null )
{
currentDrawer.Unbind();
currentDrawer = null;
}
m_inspectedObject = null;
scrollView.verticalNormalizedPosition = 1f;
ColorPicker.Instance.Close();
ObjectReferencePicker.Instance.Close();
}
public InspectorField CreateDrawerForType( Type type, Transform drawerParent, int depth, bool drawObjectsAsFields = true, MemberInfo variable = null )
{
InspectorField[] variableDrawers = GetDrawersForType( type, drawObjectsAsFields );
if( variableDrawers != null )
{
for( int i = 0; i < variableDrawers.Length; i++ )
{
if( variableDrawers[i].CanBindTo( type, variable ) )
{
InspectorField drawer = InstantiateDrawer( variableDrawers[i], drawerParent );
drawer.Inspector = this;
drawer.Skin = Skin;
drawer.Depth = depth;
return drawer;
}
}
}
return null;
}
private InspectorField InstantiateDrawer( InspectorField drawer, Transform drawerParent )
{
List<InspectorField> drawerPool;
if( drawersPool.TryGetValue( drawer.GetType(), out drawerPool ) )
{
for( int i = drawerPool.Count - 1; i >= 0; i-- )
{
InspectorField instance = drawerPool[i];
drawerPool.RemoveAt( i );
if( instance )
{
instance.transform.SetParent( drawerParent, false );
instance.gameObject.SetActive( true );
return instance;
}
}
}
InspectorField newDrawer = (InspectorField) Instantiate( drawer, drawerParent, false );
newDrawer.Initialize();
return newDrawer;
}
private InspectorField[] GetDrawersForType( Type type, bool drawObjectsAsFields )
{
bool searchReferenceFields = drawObjectsAsFields && typeof( Object ).IsAssignableFrom( type );
InspectorField[] cachedResult;
if( ( searchReferenceFields && typeToReferenceDrawers.TryGetValue( type, out cachedResult ) ) ||
( !searchReferenceFields && typeToDrawers.TryGetValue( type, out cachedResult ) ) )
return cachedResult;
Dictionary<Type, InspectorField[]> drawersDict = searchReferenceFields ? typeToReferenceDrawers : typeToDrawers;
eligibleDrawers.Clear();
for( int i = settings.Length - 1; i >= 0; i-- )
{
InspectorField[] drawers = searchReferenceFields ? settings[i].ReferenceDrawers : settings[i].StandardDrawers;
for( int j = drawers.Length - 1; j >= 0; j-- )
{
if( drawers[j].SupportsType( type ) )
eligibleDrawers.Add( drawers[j] );
}
}
cachedResult = eligibleDrawers.Count > 0 ? eligibleDrawers.ToArray() : null;
drawersDict[type] = cachedResult;
return cachedResult;
}
internal void PoolDrawer( InspectorField drawer )
{
List<InspectorField> drawerPool;
if( !drawersPool.TryGetValue( drawer.GetType(), out drawerPool ) )
{
drawerPool = new List<InspectorField>( poolCapacity );
drawersPool[drawer.GetType()] = drawerPool;
}
if( drawerPool.Count < poolCapacity )
{
drawer.gameObject.SetActive( false );
drawer.transform.SetParent( poolParent, false );
drawerPool.Add( drawer );
}
else
Destroy( drawer.gameObject );
}
internal ExposedVariablesEnumerator GetExposedVariablesForType( Type type )
{
MemberInfo[] allVariables = type.GetAllVariables();
if( allVariables == null )
return new ExposedVariablesEnumerator( null, null, null, VariableVisibility.None, VariableVisibility.None );
List<VariableSet> hiddenVariablesForType = null;
List<VariableSet> exposedVariablesForType = null;
for( int i = 0; i < hiddenVariables.Count; i++ )
{
if( hiddenVariables[i].type.IsAssignableFrom( type ) )
{
if( hiddenVariablesForType == null )
hiddenVariablesForType = new List<VariableSet>() { hiddenVariables[i] };
else
hiddenVariablesForType.Add( hiddenVariables[i] );
}
}
for( int i = 0; i < exposedVariables.Count; i++ )
{
if( exposedVariables[i].type.IsAssignableFrom( type ) )
{
if( exposedVariablesForType == null )
exposedVariablesForType = new List<VariableSet>() { exposedVariables[i] };
else
exposedVariablesForType.Add( exposedVariables[i] );
}
}
return new ExposedVariablesEnumerator( allVariables, hiddenVariablesForType, exposedVariablesForType, m_exposeFields, m_exposeProperties );
}
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,25 @@
using System;
namespace RuntimeInspectorNamespace
{
public enum ButtonVisibility { None = 0, InitializedObjects = 1, UninitializedObjects = 2 }
[AttributeUsage( AttributeTargets.Method, Inherited = true, AllowMultiple = false )]
public class RuntimeInspectorButtonAttribute : Attribute
{
private readonly string m_label;
private readonly bool m_isInitializer;
private readonly ButtonVisibility m_visibility;
public string Label { get { return m_label; } }
public bool IsInitializer { get { return m_isInitializer; } }
public ButtonVisibility Visibility { get { return m_visibility; } }
public RuntimeInspectorButtonAttribute( string label, bool isInitializer, ButtonVisibility visibility )
{
m_label = label;
m_isInitializer = isInitializer;
m_visibility = visibility;
}
}
}

View File

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

View File

@ -0,0 +1,41 @@
using System;
namespace RuntimeInspectorNamespace
{
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = true )]
public class RuntimeInspectorCustomEditorAttribute : Attribute, IComparable<RuntimeInspectorCustomEditorAttribute>
{
private readonly Type m_inspectedType;
private readonly bool m_editorForChildClasses;
private readonly int m_inspectedTypeDepth;
public Type InspectedType { get { return m_inspectedType; } }
public bool EditorForChildClasses { get { return m_editorForChildClasses; } }
public RuntimeInspectorCustomEditorAttribute( Type inspectedType, bool editorForChildClasses = false )
{
m_inspectedType = inspectedType;
m_editorForChildClasses = editorForChildClasses;
m_inspectedTypeDepth = 0;
while( inspectedType != typeof( object ) )
{
inspectedType = inspectedType.BaseType;
m_inspectedTypeDepth++;
}
}
// While sorting a list of RuntimeInspectorCustomEditor attributes, sort them by their depths in descending order
int IComparable<RuntimeInspectorCustomEditorAttribute>.CompareTo( RuntimeInspectorCustomEditorAttribute other )
{
return other.m_inspectedTypeDepth.CompareTo( m_inspectedTypeDepth );
}
}
public interface IRuntimeInspectorCustomEditor
{
void GenerateElements( ObjectField parent );
void Refresh();
void Cleanup();
}
}

View File

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

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6d8b0274304d38146ad33297ee67edc2
folderAsset: yes
timeCreated: 1505745266
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,322 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class ArrayField : ExpandableInspectorField, IDropHandler
{
#pragma warning disable 0649
[SerializeField]
private LayoutElement sizeLayoutElement;
[SerializeField]
private Text sizeText;
[SerializeField]
private BoundInputField sizeInput;
#pragma warning restore 0649
private bool isArray;
private Type elementType;
private readonly List<bool> elementsExpandedStates = new List<bool>();
protected override int Length
{
get
{
if( isArray )
{
Array array = (Array) Value;
if( array != null )
return array.Length;
}
else
{
IList list = (IList) Value;
if( list != null )
return list.Count;
}
return 0;
}
}
public override void Initialize()
{
base.Initialize();
sizeInput.Initialize();
sizeInput.OnValueChanged += OnSizeInputBeingChanged;
sizeInput.OnValueSubmitted += OnSizeChanged;
sizeInput.DefaultEmptyValue = "0";
sizeInput.CacheTextOnValueChange = false;
}
public override bool SupportsType( Type type )
{
return ( type.IsArray && type.GetArrayRank() == 1 ) ||
#if UNITY_EDITOR || !NETFX_CORE
( type.IsGenericType && type.GetGenericTypeDefinition() == typeof( List<> ) );
#else
( type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof( List<> ) );
#endif
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
isArray = BoundVariableType.IsArray;
elementType = isArray ? BoundVariableType.GetElementType() : BoundVariableType.GetGenericArguments()[0];
}
protected override void OnUnbound()
{
base.OnUnbound();
sizeInput.Text = "0";
elementsExpandedStates.Clear();
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
sizeInput.Skin = Skin;
sizeLayoutElement.SetHeight( Skin.LineHeight );
sizeText.SetSkinText( Skin );
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) sizeInput.transform ).anchorMin = rightSideAnchorMin;
}
protected override void OnDepthChanged()
{
base.OnDepthChanged();
sizeText.rectTransform.sizeDelta = new Vector2( -Skin.IndentAmount * ( Depth + 1 ), 0f );
}
protected override void ClearElements()
{
elementsExpandedStates.Clear();
for( int i = 0; i < elements.Count; i++ )
elementsExpandedStates.Add( ( elements[i] is ExpandableInspectorField ) ? ( (ExpandableInspectorField) elements[i] ).IsExpanded : false );
base.ClearElements();
}
protected override void GenerateElements()
{
if( Value == null )
return;
if( isArray )
{
Array array = (Array) Value;
for( int i = 0; i < array.Length; i++ )
{
InspectorField elementDrawer = Inspector.CreateDrawerForType( elementType, drawArea, Depth + 1 );
if( elementDrawer == null )
break;
int j = i;
elementDrawer.BindTo( elementType, string.Empty, () => ( (Array) Value ).GetValue( j ), ( value ) =>
{
Array _array = (Array) Value;
_array.SetValue( value, j );
Value = _array;
} );
if( i < elementsExpandedStates.Count && elementsExpandedStates[i] && elementDrawer is ExpandableInspectorField )
( (ExpandableInspectorField) elementDrawer ).IsExpanded = true;
elementDrawer.NameRaw = Inspector.ArrayIndicesStartAtOne ? ( ( i + 1 ) + ":" ) : ( i + ":" );
elements.Add( elementDrawer );
}
}
else
{
IList list = (IList) Value;
for( int i = 0; i < list.Count; i++ )
{
InspectorField elementDrawer = Inspector.CreateDrawerForType( elementType, drawArea, Depth + 1 );
if( elementDrawer == null )
break;
int j = i;
string variableName = Inspector.ArrayIndicesStartAtOne ? ( ( i + 1 ) + ":" ) : ( i + ":" );
elementDrawer.BindTo( elementType, variableName, () => ( (IList) Value )[j], ( value ) =>
{
IList _list = (IList) Value;
_list[j] = value;
Value = _list;
} );
if( i < elementsExpandedStates.Count && elementsExpandedStates[i] && elementDrawer is ExpandableInspectorField )
( (ExpandableInspectorField) elementDrawer ).IsExpanded = true;
elements.Add( elementDrawer );
}
}
sizeInput.Text = Length.ToString( RuntimeInspectorUtils.numberFormat );
elementsExpandedStates.Clear();
}
void IDropHandler.OnDrop( PointerEventData eventData )
{
object[] assignableObjects = RuntimeInspectorUtils.GetAssignableObjectsFromDraggedReferenceItem( eventData, elementType );
if( assignableObjects != null && assignableObjects.Length > 0 )
{
int prevLength = Length;
if( !OnSizeChanged( null, ( prevLength + assignableObjects.Length ).ToString( RuntimeInspectorUtils.numberFormat ) ) )
return;
if( isArray )
{
Array _array = (Array) Value;
for( int i = 0; i < assignableObjects.Length; i++ )
_array.SetValue( assignableObjects[i], prevLength + i );
Value = _array;
}
else
{
IList _list = (IList) Value;
for( int i = 0; i < assignableObjects.Length; i++ )
_list[prevLength + i] = assignableObjects[i];
Value = _list;
}
if( !IsExpanded )
IsExpanded = true;
}
}
private bool OnSizeInputBeingChanged( BoundInputField source, string input )
{
int value;
if( int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) && value >= 0 )
return true;
return false;
}
private bool OnSizeChanged( BoundInputField source, string input )
{
int value;
if( int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) && value >= 0 )
{
int currLength = Length;
if( currLength != value )
{
if( isArray )
{
Array array = (Array) Value;
Array newArray = Array.CreateInstance( BoundVariableType.GetElementType(), value );
if( value > currLength )
{
if( array != null )
Array.ConstrainedCopy( array, 0, newArray, 0, currLength );
for( int i = currLength; i < value; i++ )
{
object template = GetTemplateElement( array );
if( template != null )
newArray.SetValue( template, i );
}
}
else
Array.ConstrainedCopy( array, 0, newArray, 0, value );
Value = newArray;
}
else
{
IList list = (IList) Value;
int deltaLength = value - currLength;
if( deltaLength > 0 )
{
if( list == null )
list = (IList) Activator.CreateInstance( typeof( List<> ).MakeGenericType( BoundVariableType.GetGenericArguments()[0] ) );
for( int i = 0; i < deltaLength; i++ )
list.Add( GetTemplateElement( list ) );
}
else
{
for( int i = 0; i > deltaLength; i-- )
list.RemoveAt( list.Count - 1 );
}
Value = list;
}
Inspector.RefreshDelayed();
}
return true;
}
return false;
}
private object GetTemplateElement( object value )
{
Array array = null;
IList list = null;
if( isArray )
array = (Array) value;
else
list = (IList) value;
object template = null;
Type elementType = isArray ? BoundVariableType.GetElementType() : BoundVariableType.GetGenericArguments()[0];
#if UNITY_EDITOR || !NETFX_CORE
if( elementType.IsValueType )
#else
if( elementType.GetTypeInfo().IsValueType )
#endif
{
if( isArray && array != null && array.Length > 0 )
template = array.GetValue( array.Length - 1 );
else if( !isArray && list != null && list.Count > 0 )
template = list[list.Count - 1];
else
template = Activator.CreateInstance( elementType );
}
else if( typeof( Object ).IsAssignableFrom( elementType ) )
{
if( isArray && array != null && array.Length > 0 )
template = array.GetValue( array.Length - 1 );
else if( !isArray && list != null && list.Count > 0 )
template = list[list.Count - 1];
else
template = null;
}
else if( elementType.IsArray )
template = Array.CreateInstance( elementType, 0 );
#if UNITY_EDITOR || !NETFX_CORE
else if( elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof( List<> ) )
#else
else if( elementType.GetTypeInfo().IsGenericType && elementType.GetGenericTypeDefinition() == typeof( List<> ) )
#endif
template = Activator.CreateInstance( typeof( List<> ).MakeGenericType( elementType ) );
else
template = elementType.Instantiate();
return template;
}
}
}

View File

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

View File

@ -0,0 +1,52 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class BoolField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private Image toggleBackground;
[SerializeField]
private Toggle input;
#pragma warning restore 0649
public override void Initialize()
{
base.Initialize();
input.onValueChanged.AddListener( OnValueChanged );
}
public override bool SupportsType( Type type )
{
return type == typeof( bool );
}
private void OnValueChanged( bool input )
{
Value = input;
Inspector.RefreshDelayed();
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
toggleBackground.color = Skin.InputFieldNormalBackgroundColor;
input.graphic.color = Skin.ToggleCheckmarkColor;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) input.transform ).anchorMin = rightSideAnchorMin;
}
public override void Refresh()
{
base.Refresh();
input.isOn = (bool) Value;
}
}
}

View File

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

View File

@ -0,0 +1,97 @@
using System;
using System.Reflection;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class BoundsField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private Vector3Field inputCenter;
[SerializeField]
private Vector3Field inputExtents;
#pragma warning restore 0649
private MemberInfo centerVariable;
private MemberInfo extentsVariable;
#if UNITY_2017_2_OR_NEWER
private MemberInfo intCenterVariable;
private MemberInfo intSizeVariable;
#endif
protected override float HeightMultiplier { get { return 3f; } }
public override void Initialize()
{
base.Initialize();
centerVariable = typeof( Bounds ).GetProperty( "center" );
extentsVariable = typeof( Bounds ).GetProperty( "extents" );
#if UNITY_2017_2_OR_NEWER
intCenterVariable = typeof( BoundsInt ).GetProperty( "center" );
intSizeVariable = typeof( BoundsInt ).GetProperty( "size" );
#endif
}
public override bool SupportsType( Type type )
{
#if UNITY_2017_2_OR_NEWER
if( type == typeof( BoundsInt ) )
return true;
#endif
return type == typeof( Bounds );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
#if UNITY_2017_2_OR_NEWER
if( BoundVariableType == typeof( BoundsInt ) )
{
inputCenter.BindTo( this, intCenterVariable, "Center:" );
inputExtents.BindTo( this, intSizeVariable, "Size:" );
}
else
#endif
{
inputCenter.BindTo( this, centerVariable, "Center:" );
inputExtents.BindTo( this, extentsVariable, "Extents:" );
}
}
protected override void OnInspectorChanged()
{
base.OnInspectorChanged();
inputCenter.Inspector = Inspector;
inputExtents.Inspector = Inspector;
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
inputCenter.Skin = Skin;
inputExtents.Skin = Skin;
}
protected override void OnDepthChanged()
{
base.OnDepthChanged();
inputCenter.Depth = Depth + 1;
inputExtents.Depth = Depth + 1;
}
public override void Refresh()
{
base.Refresh();
inputCenter.Refresh();
inputExtents.Refresh();
}
}
}

View File

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

View File

@ -0,0 +1,78 @@
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class ColorField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private RectTransform colorPickerArea;
[SerializeField]
private PointerEventListener inputColor;
private Image colorImg;
#pragma warning restore 0649
private bool isColor32;
public override void Initialize()
{
base.Initialize();
colorImg = inputColor.GetComponent<Image>();
inputColor.PointerClick += ShowColorPicker;
}
public override bool SupportsType( Type type )
{
return type == typeof( Color ) || type == typeof( Color32 );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
isColor32 = BoundVariableType == typeof( Color32 );
}
private void ShowColorPicker( PointerEventData eventData )
{
Color value = isColor32 ? (Color) (Color32) Value : (Color) Value;
ColorPicker.Instance.Skin = Inspector.Skin;
ColorPicker.Instance.Show( OnColorChanged, null, value, Inspector.Canvas );
}
private void OnColorChanged( Color32 color )
{
colorImg.color = color;
if( isColor32 )
Value = color;
else
Value = (Color) color;
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
colorPickerArea.anchorMin = rightSideAnchorMin;
}
public override void Refresh()
{
base.Refresh();
if( isColor32 )
colorImg.color = (Color32) Value;
else
colorImg.color = (Color) Value;
}
}
}

View File

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

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class EnumField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private Image background;
[SerializeField]
private Image dropdownArrow;
[SerializeField]
private RectTransform templateRoot;
[SerializeField]
private RectTransform templateContentTransform;
[SerializeField]
private RectTransform templateItemTransform;
[SerializeField]
private Image templateBackground;
[SerializeField]
private Image templateCheckmark;
[SerializeField]
private Text templateText;
[SerializeField]
private Dropdown input;
#pragma warning restore 0649
private static readonly Dictionary<Type, List<string>> enumNames = new Dictionary<Type, List<string>>();
private static readonly Dictionary<Type, List<object>> enumValues = new Dictionary<Type, List<object>>();
private List<string> currEnumNames;
private List<object> currEnumValues;
public override void Initialize()
{
base.Initialize();
input.onValueChanged.AddListener( OnValueChanged );
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
// On new Input System, scroll sensitivity is much higher than legacy Input system
templateRoot.GetComponent<ScrollRect>().scrollSensitivity *= 0.25f;
#endif
}
public override bool SupportsType( Type type )
{
#if UNITY_EDITOR || !NETFX_CORE
return type.IsEnum;
#else
return type.GetTypeInfo().IsEnum;
#endif
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
if( !enumNames.TryGetValue( BoundVariableType, out currEnumNames ) || !enumValues.TryGetValue( BoundVariableType, out currEnumValues ) )
{
string[] names = Enum.GetNames( BoundVariableType );
Array values = Enum.GetValues( BoundVariableType );
currEnumNames = new List<string>( names.Length );
currEnumValues = new List<object>( names.Length );
for( int i = 0; i < names.Length; i++ )
{
currEnumNames.Add( names[i] );
currEnumValues.Add( values.GetValue( i ) );
}
enumNames[BoundVariableType] = currEnumNames;
enumValues[BoundVariableType] = currEnumValues;
}
input.ClearOptions();
input.AddOptions( currEnumNames );
}
protected override void OnInspectorChanged()
{
base.OnInspectorChanged();
OnTransformParentChanged();
}
private void OnTransformParentChanged()
{
if( Inspector && Skin )
{
// Dropdown's list should be able to expand as much as possible when necessary
Vector2 templateRootSizeDelta = templateRoot.sizeDelta;
templateRootSizeDelta.y = ( ( (RectTransform) Inspector.Canvas.transform ).rect.height - Skin.LineHeight ) * 0.5f;
templateRoot.sizeDelta = templateRootSizeDelta;
}
}
private void OnValueChanged( int input )
{
Value = currEnumValues[input];
Inspector.RefreshDelayed();
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
OnTransformParentChanged();
Vector2 templateContentSizeDelta = templateContentTransform.sizeDelta;
templateContentSizeDelta.y = Skin.LineHeight + 6f; // Padding at top and bottom edges
templateContentTransform.sizeDelta = templateContentSizeDelta;
Vector2 templateItemSizeDelta = templateItemTransform.sizeDelta;
templateItemSizeDelta.y = Skin.LineHeight;
templateItemTransform.sizeDelta = templateItemSizeDelta;
// Resize the checkmark icon
float templateCheckmarkSize = Skin.LineHeight * 0.66f;
Vector2 templateTextSizeDelta = templateText.rectTransform.sizeDelta;
templateTextSizeDelta.x -= templateCheckmarkSize - templateCheckmark.rectTransform.sizeDelta.x;
templateText.rectTransform.sizeDelta = templateTextSizeDelta;
templateCheckmark.rectTransform.sizeDelta = new Vector2( templateCheckmarkSize, templateCheckmarkSize );
// Resize the dropdown arrow
Vector2 dropdownTextSizeDelta = input.captionText.rectTransform.sizeDelta;
dropdownTextSizeDelta.x -= templateCheckmarkSize - dropdownArrow.rectTransform.sizeDelta.x;
input.captionText.rectTransform.sizeDelta = dropdownTextSizeDelta;
dropdownArrow.rectTransform.sizeDelta = new Vector2( templateCheckmarkSize, templateCheckmarkSize );
background.color = Skin.InputFieldNormalBackgroundColor;
dropdownArrow.color = Skin.TextColor.Tint( 0.1f );
input.captionText.SetSkinInputFieldText( Skin );
templateText.SetSkinInputFieldText( Skin );
templateBackground.color = Skin.InputFieldNormalBackgroundColor.Tint( 0.075f );
templateCheckmark.color = Skin.ToggleCheckmarkColor;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) input.transform ).anchorMin = rightSideAnchorMin;
}
public override void Refresh()
{
base.Refresh();
int valueIndex = currEnumValues.IndexOf( Value );
if( valueIndex != -1 )
input.value = valueIndex;
}
}
}

View File

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

View File

@ -0,0 +1,55 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class ExposedMethodField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private Button invokeButton;
#pragma warning restore 0649
protected ExposedMethod boundMethod;
public override bool SupportsType( Type type )
{
return type == typeof( ExposedMethod );
}
public override void Initialize()
{
base.Initialize();
invokeButton.onClick.AddListener( InvokeMethod );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
invokeButton.SetSkinButton( Skin );
}
protected override void OnDepthChanged()
{
( (RectTransform) invokeButton.transform ).sizeDelta = new Vector2( -Skin.IndentAmount * Depth, 0f );
}
public void SetBoundMethod( ExposedMethod boundMethod )
{
this.boundMethod = boundMethod;
NameRaw = boundMethod.Label;
}
public void InvokeMethod()
{
// Refresh value first
Refresh();
if( boundMethod.IsInitializer )
Value = boundMethod.CallAndReturnValue( Value );
else
boundMethod.Call( Value );
}
}
}

View File

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

View File

@ -0,0 +1,240 @@
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class GameObjectField : ExpandableInspectorField
{
protected override int Length { get { return components.Count + 4; } } // 4: active, name, tag, layer
private string currentTag = null;
private Getter isActiveGetter, nameGetter, tagGetter;
private Setter isActiveSetter, nameSetter, tagSetter;
private PropertyInfo layerProp;
private readonly List<Component> components = new List<Component>( 8 );
private readonly List<bool> componentsExpandedStates = new List<bool>();
private Type[] addComponentTypes;
internal static ExposedMethod addComponentMethod = new ExposedMethod( typeof( GameObjectField ).GetMethod( "AddComponentButtonClicked", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ), new RuntimeInspectorButtonAttribute( "Add Component", false, ButtonVisibility.InitializedObjects ), false );
internal static ExposedMethod removeComponentMethod = new ExposedMethod( typeof( GameObjectField ).GetMethod( "RemoveComponentButtonClicked", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ), new RuntimeInspectorButtonAttribute( "Remove Component", false, ButtonVisibility.InitializedObjects ), true );
public override void Initialize()
{
base.Initialize();
isActiveGetter = () => ( (GameObject) Value ).activeSelf;
isActiveSetter = ( value ) => ( (GameObject) Value ).SetActive( (bool) value );
nameGetter = () => ( (GameObject) Value ).name;
nameSetter = ( value ) =>
{
( (GameObject) Value ).name = (string) value;
NameRaw = Value.GetNameWithType();
RuntimeHierarchy hierarchy = Inspector.ConnectedHierarchy;
if( hierarchy )
hierarchy.RefreshNameOf( ( (GameObject) Value ).transform );
};
tagGetter = () =>
{
GameObject go = (GameObject) Value;
if( !go.CompareTag( currentTag ) )
currentTag = go.tag;
return currentTag;
};
tagSetter = ( value ) => ( (GameObject) Value ).tag = (string) value;
layerProp = typeof( GameObject ).GetProperty( "layer" );
}
public override bool SupportsType( Type type )
{
return type == typeof( GameObject );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
currentTag = ( (GameObject) Value ).tag;
}
protected override void OnUnbound()
{
base.OnUnbound();
components.Clear();
componentsExpandedStates.Clear();
}
protected override void ClearElements()
{
componentsExpandedStates.Clear();
for( int i = 0; i < elements.Count; i++ )
{
// Don't keep track of non-expandable drawers' or destroyed components' expanded states
if( elements[i] is ExpandableInspectorField && ( elements[i].Value as Object ) )
componentsExpandedStates.Add( ( (ExpandableInspectorField) elements[i] ).IsExpanded );
}
base.ClearElements();
}
protected override void GenerateElements()
{
if( components.Count == 0 )
return;
CreateDrawer( typeof( bool ), "Is Active", isActiveGetter, isActiveSetter );
StringField nameField = CreateDrawer( typeof( string ), "Name", nameGetter, nameSetter ) as StringField;
StringField tagField = CreateDrawer( typeof( string ), "Tag", tagGetter, tagSetter ) as StringField;
CreateDrawerForVariable( layerProp, "Layer" );
for( int i = 0, j = 0; i < components.Count; i++ )
{
InspectorField componentDrawer = CreateDrawerForComponent( components[i] );
if( componentDrawer as ExpandableInspectorField && j < componentsExpandedStates.Count && componentsExpandedStates[j++] )
( (ExpandableInspectorField) componentDrawer ).IsExpanded = true;
}
if( nameField )
nameField.SetterMode = StringField.Mode.OnSubmit;
if( tagField )
tagField.SetterMode = StringField.Mode.OnSubmit;
if( Inspector.ShowAddComponentButton )
CreateExposedMethodButton( addComponentMethod, () => this, ( value ) => { } );
componentsExpandedStates.Clear();
}
public override void Refresh()
{
// Refresh components
components.Clear();
GameObject go = Value as GameObject;
if( go )
{
go.GetComponents( components );
for( int i = components.Count - 1; i >= 0; i-- )
{
if( !components[i] )
components.RemoveAt( i );
}
if( Inspector.ComponentFilter != null )
Inspector.ComponentFilter( go, components );
}
// Regenerate components' drawers, if necessary
base.Refresh();
}
[UnityEngine.Scripting.Preserve] // This method is bound to addComponentMethod
private void AddComponentButtonClicked()
{
GameObject target = (GameObject) Value;
if( !target )
return;
if( addComponentTypes == null )
{
List<Type> componentTypes = new List<Type>( 128 );
#if UNITY_EDITOR || !NETFX_CORE
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
#else
// Common Unity assemblies
IEnumerable<Assembly> assemblies = new HashSet<Assembly>
{
typeof( Transform ).Assembly,
typeof( RectTransform ).Assembly,
typeof( Rigidbody ).Assembly,
typeof( Rigidbody2D ).Assembly,
typeof( AudioSource ).Assembly
};
#endif
// Search assemblies for Component types
foreach( Assembly assembly in assemblies )
{
#if( NET_4_6 || NET_STANDARD_2_0 ) && ( UNITY_EDITOR || !NETFX_CORE )
if( assembly.IsDynamic )
continue;
#endif
try
{
foreach( Type type in assembly.GetExportedTypes() )
{
if( !typeof( Component ).IsAssignableFrom( type ) )
continue;
#if UNITY_EDITOR || !NETFX_CORE
if( type.IsGenericType || type.IsAbstract )
#else
if( type.GetTypeInfo().IsGenericType || type.GetTypeInfo().IsAbstract )
#endif
continue;
componentTypes.Add( type );
}
}
catch( NotSupportedException ) { }
catch( System.IO.FileNotFoundException ) { }
catch( Exception e )
{
Debug.LogError( "Couldn't search assembly for Component types: " + assembly.GetName().Name + "\n" + e.ToString() );
}
}
addComponentTypes = componentTypes.ToArray();
}
ObjectReferencePicker.Instance.Skin = Inspector.Skin;
ObjectReferencePicker.Instance.Show(
null, ( type ) =>
{
// Make sure that RuntimeInspector is still inspecting this GameObject
if( type != null && target && Inspector && ( Inspector.InspectedObject as GameObject ) == target )
{
target.AddComponent( (Type) type );
Inspector.Refresh();
}
},
( type ) => ( (Type) type ).FullName,
( type ) => ( (Type) type ).FullName,
addComponentTypes, null, false, "Add Component", Inspector.Canvas );
}
[UnityEngine.Scripting.Preserve] // This method is bound to removeComponentMethod
private static void RemoveComponentButtonClicked( ExpandableInspectorField componentDrawer )
{
if( !componentDrawer || !componentDrawer.Inspector )
return;
Component component = componentDrawer.Value as Component;
if( component && !( component is Transform ) )
componentDrawer.StartCoroutine( RemoveComponentCoroutine( component, componentDrawer.Inspector ) );
}
private static IEnumerator RemoveComponentCoroutine( Component component, RuntimeInspector inspector )
{
Destroy( component );
// Destroy operation doesn't take place immediately, wait for the component to be fully destroyed
yield return null;
inspector.Refresh();
inspector.EnsureScrollViewIsWithinBounds(); // Scroll view's contents can get out of bounds after removing a component
}
}
}

View File

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

View File

@ -0,0 +1,557 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public abstract class InspectorField : MonoBehaviour, ITooltipContent
{
public delegate object Getter();
public delegate void Setter( object value );
#pragma warning disable 0649
[SerializeField]
protected LayoutElement layoutElement;
[SerializeField]
protected Text variableNameText;
[SerializeField]
protected Image variableNameMask;
[SerializeField]
private MaskableGraphic visibleArea;
#pragma warning restore 0649
private RuntimeInspector m_inspector;
public RuntimeInspector Inspector
{
get { return m_inspector; }
set
{
if( m_inspector != value )
{
m_inspector = value;
OnInspectorChanged();
}
}
}
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;
OnSkinChanged();
OnDepthChanged();
}
}
}
private Type m_boundVariableType;
protected Type BoundVariableType { get { return m_boundVariableType; } }
private object m_value;
public object Value
{
get { return m_value; }
protected set
{
try { setter( value ); m_value = value; }
catch { }
}
}
private int m_depth = -1;
public int Depth
{
get { return m_depth; }
set
{
if( m_depth != value )
{
m_depth = value;
OnDepthChanged();
}
}
}
private bool m_isVisible = true;
public bool IsVisible { get { return m_isVisible; } }
public string Name
{
get { if( variableNameText ) return variableNameText.text; return string.Empty; }
set { if( variableNameText ) variableNameText.text = Inspector.UseTitleCaseNaming ? value.ToTitleCase() : value; }
}
public string NameRaw
{
get { if( variableNameText ) return variableNameText.text; return string.Empty; }
set { if( variableNameText ) variableNameText.text = value; }
}
bool ITooltipContent.IsActive { get { return this && gameObject.activeSelf; } }
string ITooltipContent.TooltipText { get { return NameRaw; } }
public virtual bool ShouldRefresh { get { return m_isVisible; } }
protected virtual float HeightMultiplier { get { return 1f; } }
private Getter getter;
private Setter setter;
public virtual void Initialize()
{
if( visibleArea )
visibleArea.onCullStateChanged.AddListener( ( bool isCulled ) => m_isVisible = !isCulled );
}
public abstract bool SupportsType( Type type );
public virtual bool CanBindTo( Type type, MemberInfo variable )
{
return true;
}
public void BindTo( InspectorField parent, MemberInfo variable, string variableName = null )
{
if( variable is FieldInfo )
{
FieldInfo field = (FieldInfo) variable;
if( variableName == null )
variableName = field.Name;
#if UNITY_EDITOR || !NETFX_CORE
if( !parent.BoundVariableType.IsValueType )
#else
if( !parent.BoundVariableType.GetTypeInfo().IsValueType )
#endif
BindTo( field.FieldType, variableName, () => field.GetValue( parent.Value ), ( value ) => field.SetValue( parent.Value, value ), variable );
else
BindTo( field.FieldType, variableName, () => field.GetValue( parent.Value ), ( value ) =>
{
field.SetValue( parent.Value, value );
parent.Value = parent.Value;
}, variable );
}
else if( variable is PropertyInfo )
{
PropertyInfo property = (PropertyInfo) variable;
if( variableName == null )
variableName = property.Name;
#if UNITY_EDITOR || !NETFX_CORE
if( !parent.BoundVariableType.IsValueType )
#else
if( !parent.BoundVariableType.GetTypeInfo().IsValueType )
#endif
BindTo( property.PropertyType, variableName, () => property.GetValue( parent.Value, null ), ( value ) => property.SetValue( parent.Value, value, null ), variable );
else
BindTo( property.PropertyType, variableName, () => property.GetValue( parent.Value, null ), ( value ) =>
{
property.SetValue( parent.Value, value, null );
parent.Value = parent.Value;
}, variable );
}
else
throw new ArgumentException( "Variable can either be a field or a property" );
}
public void BindTo( Type variableType, string variableName, Getter getter, Setter setter, MemberInfo variable = null )
{
m_boundVariableType = variableType;
Name = variableName;
this.getter = getter;
this.setter = setter;
OnBound( variable );
}
public void Unbind()
{
m_boundVariableType = null;
getter = null;
setter = null;
OnUnbound();
Inspector.PoolDrawer( this );
}
protected virtual void OnBound( MemberInfo variable )
{
RefreshValue();
}
protected virtual void OnUnbound()
{
m_value = null;
}
protected virtual void OnInspectorChanged()
{
if( !variableNameText )
return;
if( m_inspector.ShowTooltips )
{
TooltipArea tooltipArea = variableNameText.GetComponent<TooltipArea>();
if( !tooltipArea )
tooltipArea = variableNameText.gameObject.AddComponent<TooltipArea>();
tooltipArea.Initialize( m_inspector.TooltipListener, this );
variableNameText.raycastTarget = true;
}
else
{
TooltipArea tooltipArea = variableNameText.GetComponent<TooltipArea>();
if( tooltipArea )
{
Destroy( tooltipArea );
variableNameText.raycastTarget = false;
}
}
}
protected virtual void OnSkinChanged()
{
if( layoutElement )
layoutElement.SetHeight( Skin.LineHeight * HeightMultiplier );
if( variableNameText )
variableNameText.SetSkinText( Skin );
if( variableNameMask )
variableNameMask.color = Skin.BackgroundColor;
}
protected virtual void OnDepthChanged()
{
if( variableNameText != null )
variableNameText.rectTransform.sizeDelta = new Vector2( -Skin.IndentAmount * Depth, 0f );
}
public virtual void Refresh()
{
RefreshValue();
}
private void RefreshValue()
{
try
{
m_value = getter();
}
catch
{
#if UNITY_EDITOR || !NETFX_CORE
if( BoundVariableType.IsValueType )
#else
if( BoundVariableType.GetTypeInfo().IsValueType )
#endif
m_value = Activator.CreateInstance( BoundVariableType );
else
m_value = null;
}
}
}
public abstract class ExpandableInspectorField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
protected RectTransform drawArea;
[SerializeField]
private PointerEventListener expandToggle;
private RectTransform expandToggleTransform;
[SerializeField]
private LayoutGroup layoutGroup;
[SerializeField]
private Image expandArrow; // Expand Arrow's sprite should look right at 0 rotation
#pragma warning restore 0649
protected readonly List<InspectorField> elements = new List<InspectorField>( 8 );
protected readonly List<ExposedMethodField> exposedMethods = new List<ExposedMethodField>();
protected virtual int Length { get { return elements.Count; } }
public override bool ShouldRefresh { get { return true; } }
private bool m_isExpanded = false;
public bool IsExpanded
{
get { return m_isExpanded; }
set
{
m_isExpanded = value;
drawArea.gameObject.SetActive( m_isExpanded );
if( expandArrow != null )
expandArrow.rectTransform.localEulerAngles = m_isExpanded ? new Vector3( 0f, 0f, -90f ) : Vector3.zero;
if( m_isExpanded )
Refresh();
}
}
private RuntimeInspector.HeaderVisibility m_headerVisibility = RuntimeInspector.HeaderVisibility.Collapsible;
public RuntimeInspector.HeaderVisibility HeaderVisibility
{
get { return m_headerVisibility; }
set
{
if( m_headerVisibility != value )
{
if( m_headerVisibility == RuntimeInspector.HeaderVisibility.Hidden )
{
Depth++;
layoutGroup.padding.top = Skin.LineHeight;
expandToggle.gameObject.SetActive( true );
}
else if( value == RuntimeInspector.HeaderVisibility.Hidden )
{
Depth--;
layoutGroup.padding.top = 0;
expandToggle.gameObject.SetActive( false );
}
m_headerVisibility = value;
if( m_headerVisibility == RuntimeInspector.HeaderVisibility.Collapsible )
{
if( expandArrow != null )
expandArrow.gameObject.SetActive( true );
variableNameText.rectTransform.sizeDelta = new Vector2( -( Skin.ExpandArrowSpacing + Skin.LineHeight * 0.5f ), 0f );
}
else if( m_headerVisibility == RuntimeInspector.HeaderVisibility.AlwaysVisible )
{
if( expandArrow != null )
expandArrow.gameObject.SetActive( false );
variableNameText.rectTransform.sizeDelta = new Vector2( 0f, 0f );
if( !m_isExpanded )
IsExpanded = true;
}
else
{
if( !m_isExpanded )
IsExpanded = true;
}
}
}
}
public override void Initialize()
{
base.Initialize();
expandToggleTransform = (RectTransform) expandToggle.transform;
expandToggle.PointerClick += ( eventData ) =>
{
if( m_headerVisibility == RuntimeInspector.HeaderVisibility.Collapsible )
IsExpanded = !m_isExpanded;
};
IsExpanded = m_isExpanded;
}
protected override void OnUnbound()
{
base.OnUnbound();
IsExpanded = false;
HeaderVisibility = RuntimeInspector.HeaderVisibility.Collapsible;
ClearElements();
}
protected override void OnInspectorChanged()
{
base.OnInspectorChanged();
for( int i = 0; i < elements.Count; i++ )
elements[i].Inspector = Inspector;
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
Vector2 expandToggleSizeDelta = expandToggleTransform.sizeDelta;
expandToggleSizeDelta.y = Skin.LineHeight;
expandToggleTransform.sizeDelta = expandToggleSizeDelta;
if( m_headerVisibility != RuntimeInspector.HeaderVisibility.Hidden )
{
layoutGroup.padding.top = Skin.LineHeight;
if( m_headerVisibility == RuntimeInspector.HeaderVisibility.Collapsible )
variableNameText.rectTransform.sizeDelta = new Vector2( -( Skin.ExpandArrowSpacing + Skin.LineHeight * 0.5f ), 0f );
}
if( expandArrow != null )
{
expandArrow.color = Skin.ExpandArrowColor;
expandArrow.rectTransform.anchoredPosition = new Vector2( Skin.LineHeight * 0.25f, 0f );
expandArrow.rectTransform.sizeDelta = new Vector2( Skin.LineHeight * 0.5f, Skin.LineHeight * 0.5f );
}
for( int i = 0; i < elements.Count; i++ )
elements[i].Skin = Skin;
for( int i = 0; i < exposedMethods.Count; i++ )
exposedMethods[i].Skin = Skin;
}
protected override void OnDepthChanged()
{
Vector2 expandToggleSizeDelta = expandToggleTransform.sizeDelta;
expandToggleSizeDelta.x = -Skin.IndentAmount * Depth;
expandToggleTransform.sizeDelta = expandToggleSizeDelta;
for( int i = 0; i < elements.Count; i++ )
elements[i].Depth = Depth + 1;
}
protected void RegenerateElements()
{
if( elements.Count > 0 || exposedMethods.Count > 0 )
ClearElements();
if( Depth < Inspector.NestLimit )
{
drawArea.gameObject.SetActive( true );
GenerateElements();
GenerateExposedMethodButtons();
drawArea.gameObject.SetActive( m_isExpanded );
}
}
protected abstract void GenerateElements();
private void GenerateExposedMethodButtons()
{
if( Inspector.ShowRemoveComponentButton && typeof( Component ).IsAssignableFrom( BoundVariableType ) && !typeof( Transform ).IsAssignableFrom( BoundVariableType ) )
CreateExposedMethodButton( GameObjectField.removeComponentMethod, () => this, ( value ) => { } );
ExposedMethod[] methods = BoundVariableType.GetExposedMethods();
if( methods != null )
{
bool isInitialized = Value != null && !Value.Equals( null );
for( int i = 0; i < methods.Length; i++ )
{
ExposedMethod method = methods[i];
if( ( isInitialized && method.VisibleWhenInitialized ) || ( !isInitialized && method.VisibleWhenUninitialized ) )
CreateExposedMethodButton( method, () => Value, ( value ) => Value = value );
}
}
}
protected virtual void ClearElements()
{
for( int i = 0; i < elements.Count; i++ )
elements[i].Unbind();
for( int i = 0; i < exposedMethods.Count; i++ )
exposedMethods[i].Unbind();
elements.Clear();
exposedMethods.Clear();
}
public override void Refresh()
{
base.Refresh();
if( m_isExpanded )
{
if( Length != elements.Count )
RegenerateElements();
for( int i = 0; i < elements.Count; i++ )
{
if( elements[i].ShouldRefresh )
elements[i].Refresh();
}
}
}
public InspectorField CreateDrawerForComponent( Component component, string variableName = null )
{
InspectorField variableDrawer = Inspector.CreateDrawerForType( component.GetType(), drawArea, Depth + 1, false );
if( variableDrawer != null )
{
if( variableName == null )
variableName = component.GetType().Name + " component";
variableDrawer.BindTo( component.GetType(), string.Empty, () => component, ( value ) => { } );
variableDrawer.NameRaw = variableName;
elements.Add( variableDrawer );
}
return variableDrawer;
}
public InspectorField CreateDrawerForVariable( MemberInfo variable, string variableName = null )
{
Type variableType = variable is FieldInfo ? ( (FieldInfo) variable ).FieldType : ( (PropertyInfo) variable ).PropertyType;
InspectorField variableDrawer = Inspector.CreateDrawerForType( variableType, drawArea, Depth + 1, true, variable );
if( variableDrawer != null )
{
variableDrawer.BindTo( this, variable, variableName == null ? null : string.Empty );
if( variableName != null )
variableDrawer.NameRaw = variableName;
elements.Add( variableDrawer );
}
return variableDrawer;
}
public InspectorField CreateDrawer( Type variableType, string variableName, Getter getter, Setter setter, bool drawObjectsAsFields = true )
{
InspectorField variableDrawer = Inspector.CreateDrawerForType( variableType, drawArea, Depth + 1, drawObjectsAsFields );
if( variableDrawer != null )
{
variableDrawer.BindTo( variableType, variableName == null ? null : string.Empty, getter, setter );
if( variableName != null )
variableDrawer.NameRaw = variableName;
elements.Add( variableDrawer );
}
return variableDrawer;
}
public ExposedMethodField CreateExposedMethodButton( ExposedMethod method, Getter getter, Setter setter )
{
ExposedMethodField methodDrawer = (ExposedMethodField) Inspector.CreateDrawerForType( typeof( ExposedMethod ), drawArea, Depth + 1, false );
if( methodDrawer != null )
{
methodDrawer.BindTo( typeof( ExposedMethod ), string.Empty, getter, setter );
methodDrawer.SetBoundMethod( method );
exposedMethods.Add( methodDrawer );
}
return methodDrawer;
}
}
}

View File

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

View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class NumberField : InspectorField
{
private static readonly HashSet<Type> supportedTypes = new HashSet<Type>()
{
typeof( int ), typeof( uint ), typeof( long ), typeof( ulong ),
typeof( byte ), typeof( sbyte ), typeof( short ), typeof( ushort ), typeof( char ),
typeof( float ), typeof( double ), typeof( decimal )
};
#pragma warning disable 0649
[SerializeField]
protected BoundInputField input;
#pragma warning restore 0649
protected INumberHandler numberHandler;
public override void Initialize()
{
base.Initialize();
input.Initialize();
input.OnValueChanged += OnValueChanged;
input.OnValueSubmitted += OnValueSubmitted;
input.DefaultEmptyValue = "0";
}
public override bool SupportsType( Type type )
{
return supportedTypes.Contains( type );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
if( BoundVariableType == typeof( float ) || BoundVariableType == typeof( double ) || BoundVariableType == typeof( decimal ) )
input.BackingField.contentType = InputField.ContentType.DecimalNumber;
else
input.BackingField.contentType = InputField.ContentType.IntegerNumber;
numberHandler = NumberHandlers.Get( BoundVariableType );
input.Text = numberHandler.ToString( Value );
}
protected virtual bool OnValueChanged( BoundInputField source, string input )
{
object value;
if( numberHandler.TryParse( input, out value ) )
{
Value = value;
return true;
}
return false;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
Inspector.RefreshDelayed();
return OnValueChanged( source, input );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
input.Skin = Skin;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) input.transform ).anchorMin = rightSideAnchorMin;
}
public override void Refresh()
{
object prevVal = Value;
base.Refresh();
if( !numberHandler.ValuesAreEqual( Value, prevVal ) )
input.Text = numberHandler.ToString( Value );
}
}
}

View File

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

View File

@ -0,0 +1,80 @@
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class NumberRangeField : NumberField
{
#pragma warning disable 0649
[SerializeField]
private BoundSlider slider;
#pragma warning restore 0649
public override void Initialize()
{
base.Initialize();
slider.OnValueChanged += OnSliderValueChanged;
}
public override bool CanBindTo( Type type, MemberInfo variable )
{
return variable != null && variable.HasAttribute<RangeAttribute>();
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
RangeAttribute rangeAttribute = variable.GetAttribute<RangeAttribute>();
slider.SetRange( Mathf.Max( rangeAttribute.min, numberHandler.MinValue ), Mathf.Min( rangeAttribute.max, numberHandler.MaxValue ) );
slider.BackingField.wholeNumbers = BoundVariableType != typeof( float ) && BoundVariableType != typeof( double ) && BoundVariableType != typeof( decimal );
}
protected override bool OnValueChanged( BoundInputField source, string input )
{
object value;
if( numberHandler.TryParse( input, out value ) )
{
float fvalue = numberHandler.ConvertToFloat( value );
if( fvalue >= slider.BackingField.minValue && fvalue <= slider.BackingField.maxValue )
{
Value = value;
return true;
}
}
return false;
}
private void OnSliderValueChanged( BoundSlider source, float value )
{
if( input.BackingField.isFocused )
return;
Value = numberHandler.ConvertFromFloat( value );
input.Text = numberHandler.ToString( Value );
Inspector.RefreshDelayed();
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
slider.Skin = Skin;
float inputFieldWidth = ( 1f - Skin.LabelWidthPercentage ) / 3f;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) slider.transform ).anchorMin = rightSideAnchorMin;
( (RectTransform) slider.transform ).anchorMax = new Vector2( 1f - inputFieldWidth, 1f );
( (RectTransform) input.transform ).anchorMin = new Vector2( 1f - inputFieldWidth, 0f );
}
public override void Refresh()
{
base.Refresh();
slider.Value = numberHandler.ConvertToFloat( Value );
}
}
}

View File

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

View File

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class ObjectField : ExpandableInspectorField
{
#pragma warning disable 0649
[SerializeField]
private Button initializeObjectButton;
#pragma warning restore 0649
private bool elementsInitialized = false;
private IRuntimeInspectorCustomEditor customEditor;
protected override int Length
{
get
{
if( Value.IsNull() )
{
if( !initializeObjectButton.gameObject.activeSelf )
return -1;
return 0;
}
if( initializeObjectButton.gameObject.activeSelf )
return -1;
if( !elementsInitialized )
{
elementsInitialized = true;
return -1;
}
return elements.Count;
}
}
public override void Initialize()
{
base.Initialize();
initializeObjectButton.onClick.AddListener( InitializeObject );
}
public override bool SupportsType( Type type )
{
return true;
}
protected override void OnBound( MemberInfo variable )
{
elementsInitialized = false;
base.OnBound( variable );
}
protected override void GenerateElements()
{
if( Value.IsNull() )
{
initializeObjectButton.gameObject.SetActive( CanInitializeNewObject() );
return;
}
initializeObjectButton.gameObject.SetActive( false );
if( ( customEditor = RuntimeInspectorUtils.GetCustomEditor( Value.GetType() ) ) != null )
customEditor.GenerateElements( this );
else
CreateDrawersForVariables();
}
protected override void ClearElements()
{
base.ClearElements();
if( customEditor != null )
{
customEditor.Cleanup();
customEditor = null;
}
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
initializeObjectButton.SetSkinButton( Skin );
}
public override void Refresh()
{
base.Refresh();
if( customEditor != null )
customEditor.Refresh();
}
public void CreateDrawersForVariables( params string[] variables )
{
if( variables == null || variables.Length == 0 )
{
foreach( MemberInfo variable in Inspector.GetExposedVariablesForType( Value.GetType() ) )
CreateDrawerForVariable( variable );
}
else
{
foreach( MemberInfo variable in Inspector.GetExposedVariablesForType( Value.GetType() ) )
{
if( Array.IndexOf( variables, variable.Name ) >= 0 )
CreateDrawerForVariable( variable );
}
}
}
public void CreateDrawersForVariablesExcluding( params string[] variablesToExclude )
{
if( variablesToExclude == null || variablesToExclude.Length == 0 )
{
foreach( MemberInfo variable in Inspector.GetExposedVariablesForType( Value.GetType() ) )
CreateDrawerForVariable( variable );
}
else
{
foreach( MemberInfo variable in Inspector.GetExposedVariablesForType( Value.GetType() ) )
{
if( Array.IndexOf( variablesToExclude, variable.Name ) < 0 )
CreateDrawerForVariable( variable );
}
}
}
private bool CanInitializeNewObject()
{
#if UNITY_EDITOR || !NETFX_CORE
if( BoundVariableType.IsAbstract || BoundVariableType.IsInterface )
#else
if( BoundVariableType.GetTypeInfo().IsAbstract || BoundVariableType.GetTypeInfo().IsInterface )
#endif
return false;
if( typeof( ScriptableObject ).IsAssignableFrom( BoundVariableType ) )
return true;
if( typeof( UnityEngine.Object ).IsAssignableFrom( BoundVariableType ) )
return false;
if( BoundVariableType.IsArray )
return false;
#if UNITY_EDITOR || !NETFX_CORE
if( BoundVariableType.IsGenericType && BoundVariableType.GetGenericTypeDefinition() == typeof( List<> ) )
#else
if( BoundVariableType.GetTypeInfo().IsGenericType && BoundVariableType.GetGenericTypeDefinition() == typeof( List<> ) )
#endif
return false;
return true;
}
private void InitializeObject()
{
if( CanInitializeNewObject() )
{
Value = BoundVariableType.Instantiate();
RegenerateElements();
IsExpanded = true;
}
}
}
}

View File

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

View File

@ -0,0 +1,132 @@
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class ObjectReferenceField : InspectorField, IDropHandler
{
#pragma warning disable 0649
[SerializeField]
private RectTransform referencePickerArea;
[SerializeField]
private PointerEventListener input;
[SerializeField]
private PointerEventListener inspectReferenceButton;
private Image inspectReferenceImage;
[SerializeField]
protected Image background;
[SerializeField]
protected Text referenceNameText;
#pragma warning restore 0649
public override void Initialize()
{
base.Initialize();
input.PointerClick += ShowReferencePicker;
if( inspectReferenceButton != null )
{
inspectReferenceButton.PointerClick += InspectReference;
inspectReferenceImage = inspectReferenceButton.GetComponent<Image>();
}
}
public override bool SupportsType( Type type )
{
return typeof( Object ).IsAssignableFrom( type );
}
private void ShowReferencePicker( PointerEventData eventData )
{
Object[] allReferences = Resources.FindObjectsOfTypeAll( BoundVariableType );
ObjectReferencePicker.Instance.Skin = Inspector.Skin;
ObjectReferencePicker.Instance.Show(
( reference ) => OnReferenceChanged( (Object) reference ), null,
( reference ) => (Object) reference ? ( (Object) reference ).name : "None",
( reference ) => reference.GetNameWithType(),
allReferences, (Object) Value, true, "Select " + BoundVariableType.Name, Inspector.Canvas );
}
private void InspectReference( PointerEventData eventData )
{
if( Value != null && !Value.Equals( null ) )
{
if( Value is Component )
Inspector.InspectInternal( ( (Component) Value ).gameObject );
else
Inspector.InspectInternal( Value );
}
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
OnReferenceChanged( (Object) Value );
}
protected virtual void OnReferenceChanged( Object reference )
{
if( (Object) Value != reference )
Value = reference;
if( referenceNameText != null )
referenceNameText.text = reference.GetNameWithType( BoundVariableType );
if( inspectReferenceButton != null )
inspectReferenceButton.gameObject.SetActive( Value != null && !Value.Equals( null ) );
Inspector.RefreshDelayed();
}
public void OnDrop( PointerEventData eventData )
{
Object assignableObject = (Object) RuntimeInspectorUtils.GetAssignableObjectFromDraggedReferenceItem( eventData, BoundVariableType );
if( assignableObject )
OnReferenceChanged( assignableObject );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
background.color = Skin.InputFieldNormalBackgroundColor.Tint( 0.075f );
referenceNameText.SetSkinInputFieldText( Skin );
referenceNameText.resizeTextMinSize = Mathf.Max( 2, Skin.FontSize - 2 );
referenceNameText.resizeTextMaxSize = Skin.FontSize;
if( inspectReferenceImage )
{
inspectReferenceImage.color = Skin.TextColor.Tint( 0.1f );
inspectReferenceImage.GetComponent<LayoutElement>().SetWidth( Mathf.Max( Skin.LineHeight - 8, 6 ) );
}
if( referencePickerArea )
{
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
referencePickerArea.anchorMin = rightSideAnchorMin;
}
}
public override void Refresh()
{
object lastValue = Value;
base.Refresh();
if( lastValue != Value )
OnReferenceChanged( (Object) Value );
}
}
}

View File

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

View File

@ -0,0 +1,217 @@
using System;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class RectField : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private BoundInputField inputX;
[SerializeField]
private BoundInputField inputY;
[SerializeField]
private BoundInputField inputW;
[SerializeField]
private BoundInputField inputH;
[SerializeField]
private Text labelX;
[SerializeField]
private Text labelY;
[SerializeField]
private Text labelW;
[SerializeField]
private Text labelH;
#pragma warning restore 0649
#if UNITY_2017_2_OR_NEWER
private bool isRectInt;
#endif
protected override float HeightMultiplier { get { return 2f; } }
public override void Initialize()
{
base.Initialize();
inputX.Initialize();
inputY.Initialize();
inputW.Initialize();
inputH.Initialize();
inputX.OnValueChanged += OnValueChanged;
inputY.OnValueChanged += OnValueChanged;
inputW.OnValueChanged += OnValueChanged;
inputH.OnValueChanged += OnValueChanged;
inputX.OnValueSubmitted += OnValueSubmitted;
inputY.OnValueSubmitted += OnValueSubmitted;
inputW.OnValueSubmitted += OnValueSubmitted;
inputH.OnValueSubmitted += OnValueSubmitted;
inputX.DefaultEmptyValue = "0";
inputY.DefaultEmptyValue = "0";
inputW.DefaultEmptyValue = "0";
inputH.DefaultEmptyValue = "0";
}
public override bool SupportsType( Type type )
{
#if UNITY_2017_2_OR_NEWER
if( type == typeof( RectInt ) )
return true;
#endif
return type == typeof( Rect );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
#if UNITY_2017_2_OR_NEWER
isRectInt = BoundVariableType == typeof( RectInt );
if( isRectInt )
{
RectInt val = (RectInt) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputW.Text = val.width.ToString( RuntimeInspectorUtils.numberFormat );
inputH.Text = val.height.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Rect val = (Rect) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputW.Text = val.width.ToString( RuntimeInspectorUtils.numberFormat );
inputH.Text = val.height.ToString( RuntimeInspectorUtils.numberFormat );
}
}
private bool OnValueChanged( BoundInputField source, string input )
{
#if UNITY_2017_2_OR_NEWER
if( isRectInt )
{
int value;
if( int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) )
{
RectInt val = (RectInt) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else if( source == inputW )
val.width = value;
else
val.height = value;
Value = val;
return true;
}
}
else
#endif
{
float value;
if( float.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out value ) )
{
Rect val = (Rect) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else if( source == inputW )
val.width = value;
else
val.height = value;
Value = val;
return true;
}
}
return false;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
Inspector.RefreshDelayed();
return OnValueChanged( source, input );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
labelX.SetSkinText( Skin );
labelY.SetSkinText( Skin );
labelW.SetSkinText( Skin );
labelH.SetSkinText( Skin );
inputX.Skin = Skin;
inputY.Skin = Skin;
inputW.Skin = Skin;
inputH.Skin = Skin;
float inputFieldWidth = ( 1f - Skin.LabelWidthPercentage ) / 3f;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage + inputFieldWidth, 0f );
Vector2 rightSideAnchorMax = new Vector2( Skin.LabelWidthPercentage + 2f * inputFieldWidth, 1f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) inputX.transform ).SetAnchorMinMaxInputField( labelX.rectTransform, new Vector2( rightSideAnchorMin.x, 0.5f ), rightSideAnchorMax );
( (RectTransform) inputW.transform ).SetAnchorMinMaxInputField( labelW.rectTransform, rightSideAnchorMin, new Vector2( rightSideAnchorMax.x, 0.5f ) );
rightSideAnchorMin.x += inputFieldWidth;
rightSideAnchorMax.x = 1f;
( (RectTransform) inputY.transform ).SetAnchorMinMaxInputField( labelY.rectTransform, new Vector2( rightSideAnchorMin.x, 0.5f ), rightSideAnchorMax );
( (RectTransform) inputH.transform ).SetAnchorMinMaxInputField( labelH.rectTransform, rightSideAnchorMin, new Vector2( rightSideAnchorMax.x, 0.5f ) );
}
public override void Refresh()
{
#if UNITY_2017_2_OR_NEWER
if( isRectInt )
{
RectInt prevVal = (RectInt) Value;
base.Refresh();
RectInt val = (RectInt) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.width != prevVal.width )
inputW.Text = val.width.ToString( RuntimeInspectorUtils.numberFormat );
if( val.height != prevVal.height )
inputH.Text = val.height.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Rect prevVal = (Rect) Value;
base.Refresh();
Rect val = (Rect) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.width != prevVal.width )
inputW.Text = val.width.ToString( RuntimeInspectorUtils.numberFormat );
if( val.height != prevVal.height )
inputH.Text = val.height.ToString( RuntimeInspectorUtils.numberFormat );
}
}
}
}

View File

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

View File

@ -0,0 +1,116 @@
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class StringField : InspectorField
{
public enum Mode { OnValueChange = 0, OnSubmit = 1 };
#pragma warning disable 0649
[SerializeField]
private BoundInputField input;
#pragma warning restore 0649
private Mode m_setterMode = Mode.OnValueChange;
public Mode SetterMode
{
get { return m_setterMode; }
set
{
m_setterMode = value;
input.CacheTextOnValueChange = m_setterMode == Mode.OnValueChange;
}
}
private int lineCount = 1;
protected override float HeightMultiplier { get { return lineCount; } }
public override void Initialize()
{
base.Initialize();
input.Initialize();
input.OnValueChanged += OnValueChanged;
input.OnValueSubmitted += OnValueSubmitted;
input.DefaultEmptyValue = string.Empty;
}
public override bool SupportsType( Type type )
{
return type == typeof( string );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
int prevLineCount = lineCount;
if( variable == null )
lineCount = 1;
else
{
MultilineAttribute multilineAttribute = variable.GetAttribute<MultilineAttribute>();
if( multilineAttribute != null )
lineCount = Mathf.Max( 1, multilineAttribute.lines );
else if( variable.HasAttribute<TextAreaAttribute>() )
lineCount = 3;
else
lineCount = 1;
}
if( prevLineCount != lineCount )
{
input.BackingField.lineType = lineCount > 1 ? InputField.LineType.MultiLineNewline : InputField.LineType.SingleLine;
input.BackingField.textComponent.alignment = lineCount > 1 ? TextAnchor.UpperLeft : TextAnchor.MiddleLeft;
OnSkinChanged();
}
}
protected override void OnUnbound()
{
base.OnUnbound();
SetterMode = Mode.OnValueChange;
}
private bool OnValueChanged( BoundInputField source, string input )
{
if( m_setterMode == Mode.OnValueChange )
Value = input;
return true;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
if( m_setterMode == Mode.OnSubmit )
Value = input;
Inspector.RefreshDelayed();
return true;
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
input.Skin = Skin;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) input.transform ).anchorMin = rightSideAnchorMin;
}
public override void Refresh()
{
base.Refresh();
if( Value == null )
input.Text = string.Empty;
else
input.Text = (string) Value;
}
}
}

View File

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

View File

@ -0,0 +1,36 @@
using System;
#if !UNITY_EDITOR && NETFX_CORE
using System.Reflection;
#endif
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class TextureReferenceField : ObjectReferenceField
{
#pragma warning disable 0649
[SerializeField]
private RawImage referencePreview;
#pragma warning restore 0649
protected override float HeightMultiplier { get { return 2f; } }
public override bool SupportsType( Type type )
{
return typeof( Texture ).IsAssignableFrom( type ) || typeof( Sprite ).IsAssignableFrom( type );
}
protected override void OnReferenceChanged( Object reference )
{
base.OnReferenceChanged( reference );
referenceNameText.gameObject.SetActive( !reference );
Texture tex = reference.GetTexture();
referencePreview.enabled = tex != null;
referencePreview.texture = tex;
}
}
}

View File

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

View File

@ -0,0 +1,34 @@
using System;
using System.Reflection;
using UnityEngine;
namespace RuntimeInspectorNamespace
{
public class TransformField : ExpandableInspectorField
{
protected override int Length { get { return 3; } } // localPosition, localEulerAngles, localScale
private PropertyInfo positionProp, rotationProp, scaleProp;
public override void Initialize()
{
base.Initialize();
positionProp = typeof( Transform ).GetProperty( "localPosition" );
rotationProp = typeof( Transform ).GetProperty( "localEulerAngles" );
scaleProp = typeof( Transform ).GetProperty( "localScale" );
}
public override bool SupportsType( Type type )
{
return type == typeof( Transform );
}
protected override void GenerateElements()
{
CreateDrawerForVariable( positionProp, "Position" );
CreateDrawerForVariable( rotationProp, "Rotation" );
CreateDrawerForVariable( scaleProp, "Scale" );
}
}
}

View File

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

View File

@ -0,0 +1,169 @@
using System;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class Vector2Field : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private BoundInputField inputX;
[SerializeField]
private BoundInputField inputY;
[SerializeField]
private Text labelX;
[SerializeField]
private Text labelY;
#pragma warning restore 0649
#if UNITY_2017_2_OR_NEWER
private bool isVector2Int;
#endif
public override void Initialize()
{
base.Initialize();
inputX.Initialize();
inputY.Initialize();
inputX.OnValueChanged += OnValueChanged;
inputY.OnValueChanged += OnValueChanged;
inputX.OnValueSubmitted += OnValueSubmitted;
inputY.OnValueSubmitted += OnValueSubmitted;
inputX.DefaultEmptyValue = "0";
inputY.DefaultEmptyValue = "0";
}
public override bool SupportsType( Type type )
{
#if UNITY_2017_2_OR_NEWER
if( type == typeof( Vector2Int ) )
return true;
#endif
return type == typeof( Vector2 );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
#if UNITY_2017_2_OR_NEWER
isVector2Int = BoundVariableType == typeof( Vector2Int );
if( isVector2Int )
{
Vector2Int val = (Vector2Int) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Vector2 val = (Vector2) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
}
}
private bool OnValueChanged( BoundInputField source, string input )
{
#if UNITY_2017_2_OR_NEWER
if( isVector2Int )
{
int value;
if( int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) )
{
Vector2Int val = (Vector2Int) Value;
if( source == inputX )
val.x = value;
else
val.y = value;
Value = val;
return true;
}
}
else
#endif
{
float value;
if( float.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out value ) )
{
Vector2 val = (Vector2) Value;
if( source == inputX )
val.x = value;
else
val.y = value;
Value = val;
return true;
}
}
return false;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
Inspector.RefreshDelayed();
return OnValueChanged( source, input );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
labelX.SetSkinText( Skin );
labelY.SetSkinText( Skin );
inputX.Skin = Skin;
inputY.Skin = Skin;
float inputFieldWidth = ( 1f - Skin.LabelWidthPercentage ) / 3f;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage + inputFieldWidth, 0f );
Vector2 rightSideAnchorMax = new Vector2( Skin.LabelWidthPercentage + 2f * inputFieldWidth, 1f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) inputX.transform ).SetAnchorMinMaxInputField( labelX.rectTransform, rightSideAnchorMin, rightSideAnchorMax );
rightSideAnchorMin.x += inputFieldWidth;
rightSideAnchorMax.x = 1f;
( (RectTransform) inputY.transform ).SetAnchorMinMaxInputField( labelY.rectTransform, rightSideAnchorMin, rightSideAnchorMax );
}
public override void Refresh()
{
#if UNITY_2017_2_OR_NEWER
if( isVector2Int )
{
Vector2Int prevVal = (Vector2Int) Value;
base.Refresh();
Vector2Int val = (Vector2Int) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Vector2 prevVal = (Vector2) Value;
base.Refresh();
Vector2 val = (Vector2) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
}
}
}
}

View File

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

View File

@ -0,0 +1,195 @@
using System;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class Vector3Field : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private BoundInputField inputX;
[SerializeField]
private BoundInputField inputY;
[SerializeField]
private BoundInputField inputZ;
[SerializeField]
private Text labelX;
[SerializeField]
private Text labelY;
[SerializeField]
private Text labelZ;
#pragma warning restore 0649
#if UNITY_2017_2_OR_NEWER
private bool isVector3Int;
#endif
public override void Initialize()
{
base.Initialize();
inputX.Initialize();
inputY.Initialize();
inputZ.Initialize();
inputX.OnValueChanged += OnValueChanged;
inputY.OnValueChanged += OnValueChanged;
inputZ.OnValueChanged += OnValueChanged;
inputX.OnValueSubmitted += OnValueSubmitted;
inputY.OnValueSubmitted += OnValueSubmitted;
inputZ.OnValueSubmitted += OnValueSubmitted;
inputX.DefaultEmptyValue = "0";
inputY.DefaultEmptyValue = "0";
inputZ.DefaultEmptyValue = "0";
}
public override bool SupportsType( Type type )
{
#if UNITY_2017_2_OR_NEWER
if( type == typeof( Vector3Int ) )
return true;
#endif
return type == typeof( Vector3 );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
#if UNITY_2017_2_OR_NEWER
isVector3Int = BoundVariableType == typeof( Vector3Int );
if( isVector3Int )
{
Vector3Int val = (Vector3Int) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Vector3 val = (Vector3) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
}
}
private bool OnValueChanged( BoundInputField source, string input )
{
#if UNITY_2017_2_OR_NEWER
if( isVector3Int )
{
int value;
if( int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) )
{
Vector3Int val = (Vector3Int) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else
val.z = value;
Value = val;
return true;
}
}
else
#endif
{
float value;
if( float.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out value ) )
{
Vector3 val = (Vector3) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else
val.z = value;
Value = val;
return true;
}
}
return false;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
Inspector.RefreshDelayed();
return OnValueChanged( source, input );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
labelX.SetSkinText( Skin );
labelY.SetSkinText( Skin );
labelZ.SetSkinText( Skin );
inputX.Skin = Skin;
inputY.Skin = Skin;
inputZ.Skin = Skin;
float inputFieldWidth = ( 1f - Skin.LabelWidthPercentage ) / 3f;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage, 0f );
Vector2 rightSideAnchorMax = new Vector2( Skin.LabelWidthPercentage + inputFieldWidth, 1f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) inputX.transform ).SetAnchorMinMaxInputField( labelX.rectTransform, rightSideAnchorMin, rightSideAnchorMax );
rightSideAnchorMin.x += inputFieldWidth;
rightSideAnchorMax.x += inputFieldWidth;
( (RectTransform) inputY.transform ).SetAnchorMinMaxInputField( labelY.rectTransform, rightSideAnchorMin, rightSideAnchorMax );
rightSideAnchorMin.x += inputFieldWidth;
rightSideAnchorMax.x = 1f;
( (RectTransform) inputZ.transform ).SetAnchorMinMaxInputField( labelZ.rectTransform, rightSideAnchorMin, rightSideAnchorMax );
}
public override void Refresh()
{
#if UNITY_2017_2_OR_NEWER
if( isVector3Int )
{
Vector3Int prevVal = (Vector3Int) Value;
base.Refresh();
Vector3Int val = (Vector3Int) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.z != prevVal.z )
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
}
else
#endif
{
Vector3 prevVal = (Vector3) Value;
base.Refresh();
Vector3 val = (Vector3) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.z != prevVal.z )
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
}
}
}
}

View File

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

View File

@ -0,0 +1,201 @@
using System;
using System.Globalization;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class Vector4Field : InspectorField
{
#pragma warning disable 0649
[SerializeField]
private BoundInputField inputX;
[SerializeField]
private BoundInputField inputY;
[SerializeField]
private BoundInputField inputZ;
[SerializeField]
private BoundInputField inputW;
[SerializeField]
private Text labelX;
[SerializeField]
private Text labelY;
[SerializeField]
private Text labelZ;
[SerializeField]
private Text labelW;
#pragma warning restore 0649
private bool isQuaternion;
protected override float HeightMultiplier { get { return 2f; } }
public override void Initialize()
{
base.Initialize();
inputX.Initialize();
inputY.Initialize();
inputZ.Initialize();
inputW.Initialize();
inputX.OnValueChanged += OnValueChanged;
inputY.OnValueChanged += OnValueChanged;
inputZ.OnValueChanged += OnValueChanged;
inputW.OnValueChanged += OnValueChanged;
inputX.OnValueSubmitted += OnValueSubmitted;
inputY.OnValueSubmitted += OnValueSubmitted;
inputZ.OnValueSubmitted += OnValueSubmitted;
inputW.OnValueSubmitted += OnValueSubmitted;
inputX.DefaultEmptyValue = "0";
inputY.DefaultEmptyValue = "0";
inputZ.DefaultEmptyValue = "0";
inputW.DefaultEmptyValue = "0";
}
public override bool SupportsType( Type type )
{
return type == typeof( Vector4 ) || type == typeof( Quaternion );
}
protected override void OnBound( MemberInfo variable )
{
base.OnBound( variable );
isQuaternion = BoundVariableType == typeof( Quaternion );
if( isQuaternion )
{
Quaternion val = (Quaternion) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
inputW.Text = val.w.ToString( RuntimeInspectorUtils.numberFormat );
}
else
{
Vector4 val = (Vector4) Value;
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
inputW.Text = val.w.ToString( RuntimeInspectorUtils.numberFormat );
}
}
private bool OnValueChanged( BoundInputField source, string input )
{
float value;
if( float.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out value ) )
{
if( isQuaternion )
{
Quaternion val = (Quaternion) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else if( source == inputZ )
val.z = value;
else
val.w = value;
Value = val;
}
else
{
Vector4 val = (Vector4) Value;
if( source == inputX )
val.x = value;
else if( source == inputY )
val.y = value;
else if( source == inputZ )
val.z = value;
else
val.w = value;
Value = val;
}
return true;
}
return false;
}
private bool OnValueSubmitted( BoundInputField source, string input )
{
Inspector.RefreshDelayed();
return OnValueChanged( source, input );
}
protected override void OnSkinChanged()
{
base.OnSkinChanged();
labelX.SetSkinText( Skin );
labelY.SetSkinText( Skin );
labelZ.SetSkinText( Skin );
labelW.SetSkinText( Skin );
inputX.Skin = Skin;
inputY.Skin = Skin;
inputZ.Skin = Skin;
inputW.Skin = Skin;
float inputFieldWidth = ( 1f - Skin.LabelWidthPercentage ) / 3f;
Vector2 rightSideAnchorMin = new Vector2( Skin.LabelWidthPercentage + inputFieldWidth, 0f );
Vector2 rightSideAnchorMax = new Vector2( Skin.LabelWidthPercentage + 2f * inputFieldWidth, 1f );
variableNameMask.rectTransform.anchorMin = rightSideAnchorMin;
( (RectTransform) inputX.transform ).SetAnchorMinMaxInputField( labelX.rectTransform, new Vector2( rightSideAnchorMin.x, 0.5f ), rightSideAnchorMax );
( (RectTransform) inputZ.transform ).SetAnchorMinMaxInputField( labelZ.rectTransform, rightSideAnchorMin, new Vector2( rightSideAnchorMax.x, 0.5f ) );
rightSideAnchorMin.x += inputFieldWidth;
rightSideAnchorMax.x = 1f;
( (RectTransform) inputY.transform ).SetAnchorMinMaxInputField( labelY.rectTransform, new Vector2( rightSideAnchorMin.x, 0.5f ), rightSideAnchorMax );
( (RectTransform) inputW.transform ).SetAnchorMinMaxInputField( labelW.rectTransform, rightSideAnchorMin, new Vector2( rightSideAnchorMax.x, 0.5f ) );
}
public override void Refresh()
{
if( isQuaternion )
{
Quaternion prevVal = (Quaternion) Value;
base.Refresh();
Quaternion val = (Quaternion) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.z != prevVal.z )
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
if( val.w != prevVal.w )
inputW.Text = val.w.ToString( RuntimeInspectorUtils.numberFormat );
}
else
{
Vector4 prevVal = (Vector4) Value;
base.Refresh();
Vector4 val = (Vector4) Value;
if( val.x != prevVal.x )
inputX.Text = val.x.ToString( RuntimeInspectorUtils.numberFormat );
if( val.y != prevVal.y )
inputY.Text = val.y.ToString( RuntimeInspectorUtils.numberFormat );
if( val.z != prevVal.z )
inputZ.Text = val.z.ToString( RuntimeInspectorUtils.numberFormat );
if( val.w != prevVal.w )
inputW.Text = val.w.ToString( RuntimeInspectorUtils.numberFormat );
}
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 812f29dac95cacd4cb67b33c8e79cd42
folderAsset: yes
timeCreated: 1505745284
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,142 @@
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class BoundInputField : MonoBehaviour
{
public delegate bool OnValueChangedDelegate( BoundInputField source, string input );
private bool initialized = false;
private bool inputValid = true;
private bool inputAltered = false;
private InputField inputField;
private Image inputFieldBackground;
public InputField BackingField { get { return inputField; } }
[System.NonSerialized]
public string DefaultEmptyValue = string.Empty;
[System.NonSerialized]
public bool CacheTextOnValueChange = true;
private string recentText = string.Empty;
public string Text
{
get { return inputField.text; }
set
{
recentText = value;
if( !inputField.isFocused )
{
inputValid = true;
inputField.text = value;
inputFieldBackground.color = Skin.InputFieldNormalBackgroundColor;
}
}
}
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 )
{
Initialize();
m_skin = value;
m_skinVersion = m_skin.Version;
inputField.textComponent.SetSkinInputFieldText( m_skin );
inputFieldBackground.color = m_skin.InputFieldNormalBackgroundColor;
Text placeholder = inputField.placeholder as Text;
if( placeholder != null )
{
float placeholderAlpha = placeholder.color.a;
placeholder.SetSkinInputFieldText( m_skin );
Color placeholderColor = placeholder.color;
placeholderColor.a = placeholderAlpha;
placeholder.color = placeholderColor;
}
}
}
}
public OnValueChangedDelegate OnValueChanged;
public OnValueChangedDelegate OnValueSubmitted;
private void Awake()
{
Initialize();
}
public void Initialize()
{
if( initialized )
return;
inputField = GetComponent<InputField>();
inputFieldBackground = GetComponent<Image>();
inputField.onValueChanged.AddListener( InputFieldValueChanged );
inputField.onEndEdit.AddListener( InputFieldValueSubmitted );
initialized = true;
}
private void InputFieldValueChanged( string str )
{
if( !inputField.isFocused )
return;
inputAltered = true;
if( str == null || str.Length == 0 )
str = DefaultEmptyValue;
if( OnValueChanged != null )
{
inputValid = OnValueChanged( this, str );
if( inputValid && CacheTextOnValueChange )
recentText = str;
inputFieldBackground.color = inputValid ? Skin.InputFieldNormalBackgroundColor : Skin.InputFieldInvalidBackgroundColor;
}
}
private void InputFieldValueSubmitted( string str )
{
inputFieldBackground.color = Skin.InputFieldNormalBackgroundColor;
if( !inputAltered )
{
inputField.text = recentText;
return;
}
inputAltered = false;
if( str == null || str.Length == 0 )
str = DefaultEmptyValue;
if( OnValueSubmitted != null )
{
if( OnValueSubmitted( this, str ) )
recentText = str;
}
else if( inputValid )
recentText = str;
inputField.text = recentText;
inputValid = true;
}
}
}

View File

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

View File

@ -0,0 +1,89 @@
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class BoundSlider : MonoBehaviour
{
public delegate void OnValueChangedDelegate( BoundSlider source, float value );
#pragma warning disable 0649
[SerializeField]
private Slider slider;
public Slider BackingField { get { return slider; } }
[SerializeField]
private Image sliderBackground;
[SerializeField]
private Image thumb;
#pragma warning restore 0649
private bool sliderFocused = false;
public bool IsFocused { get { return sliderFocused; } }
public float Value
{
get { return slider.value; }
set { slider.value = value; }
}
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;
sliderBackground.color = m_skin.SliderBackgroundColor;
thumb.color = m_skin.SliderThumbColor;
}
}
}
public OnValueChangedDelegate OnValueChanged;
private void Awake()
{
PointerEventListener sliderPointerListener = slider.gameObject.AddComponent<PointerEventListener>();
sliderPointerListener.PointerDown += ( ev ) => sliderFocused = true;
sliderPointerListener.PointerUp += ( ev ) => sliderFocused = false;
slider.onValueChanged.AddListener( SliderValueChanged );
}
private void OnDisable()
{
sliderFocused = false;
}
public void SetRange( float min, float max )
{
sliderFocused = false;
if( min > max )
{
float temp = min;
min = max;
max = temp;
}
slider.minValue = min;
slider.maxValue = max;
}
private void SliderValueChanged( float value )
{
if( !sliderFocused )
return;
if( OnValueChanged != null )
OnValueChanged( this, value );
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 951b3609b11944b4d9a7bd33c2cea2b6
folderAsset: yes
timeCreated: 1506496159
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,260 @@
using System;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class ColorPicker : SkinnedWindow
{
private static ColorPicker m_instance;
public static ColorPicker Instance
{
get
{
if( !m_instance )
{
m_instance = Instantiate( Resources.Load<ColorPicker>( "RuntimeInspector/ColorPicker" ) );
m_instance.gameObject.SetActive( false );
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Add( m_instance.transform );
}
return m_instance;
}
}
#pragma warning disable 0649
[SerializeField]
private Image panel;
[SerializeField]
private ColorWheelControl colorWheel;
[SerializeField]
private ColorPickerAlphaSlider alphaSlider;
[SerializeField]
private Text rgbaText;
[SerializeField]
private BoundInputField rInput;
[SerializeField]
private BoundInputField gInput;
[SerializeField]
private BoundInputField bInput;
[SerializeField]
private BoundInputField aInput;
[SerializeField]
private LayoutElement rgbaLayoutElement;
[SerializeField]
private LayoutElement buttonsLayoutElement;
[SerializeField]
private Button cancelButton;
[SerializeField]
private Button okButton;
#pragma warning restore 0649
private Canvas referenceCanvas;
private Color initialValue;
private ColorWheelControl.OnColorChangedDelegate onColorChanged, onColorConfirmed;
protected override void Awake()
{
base.Awake();
rInput.Initialize();
gInput.Initialize();
bInput.Initialize();
aInput.Initialize();
cancelButton.onClick.AddListener( Cancel );
okButton.onClick.AddListener( () =>
{
try
{
if( onColorConfirmed != null )
onColorConfirmed( colorWheel.Color );
}
catch( Exception e )
{
Debug.LogException( e );
}
Close();
} );
}
private void Start()
{
colorWheel.OnColorChanged += OnSelectedColorChanged;
alphaSlider.OnValueChanged += OnAlphaChanged;
rInput.DefaultEmptyValue = "0";
gInput.DefaultEmptyValue = "0";
bInput.DefaultEmptyValue = "0";
aInput.DefaultEmptyValue = "0";
rInput.Skin = Skin;
gInput.Skin = Skin;
bInput.Skin = Skin;
aInput.Skin = Skin;
rInput.OnValueChanged += OnRGBAChanged;
gInput.OnValueChanged += OnRGBAChanged;
bInput.OnValueChanged += OnRGBAChanged;
aInput.OnValueChanged += OnRGBAChanged;
OnSelectedColorChanged( colorWheel.Color );
}
public void Show( ColorWheelControl.OnColorChangedDelegate onColorChanged, ColorWheelControl.OnColorChangedDelegate onColorConfirmed, Color initialColor, Canvas referenceCanvas )
{
initialValue = initialColor;
this.onColorChanged = null;
colorWheel.PickColor( initialColor );
alphaSlider.Color = initialColor;
alphaSlider.Value = initialColor.a;
this.onColorChanged = onColorChanged;
this.onColorConfirmed = onColorConfirmed;
if( referenceCanvas && this.referenceCanvas != referenceCanvas )
{
this.referenceCanvas = referenceCanvas;
Canvas canvas = GetComponent<Canvas>();
canvas.CopyValuesFrom( referenceCanvas );
canvas.sortingOrder = Mathf.Max( 1000, referenceCanvas.sortingOrder + 100 );
}
( (RectTransform) panel.transform ).anchoredPosition = Vector2.zero;
gameObject.SetActive( true );
}
public void Cancel()
{
try
{
if( colorWheel.Color != initialValue && onColorChanged != null )
onColorChanged( initialValue );
}
catch( Exception e )
{
Debug.LogException( e );
}
Close();
}
public void Close()
{
onColorChanged = null;
onColorConfirmed = null;
gameObject.SetActive( false );
}
protected override void RefreshSkin()
{
panel.color = Skin.WindowColor;
rgbaLayoutElement.SetHeight( Skin.LineHeight );
buttonsLayoutElement.SetHeight( Mathf.Min( 45f, Skin.LineHeight * 1.5f ) );
rgbaText.SetSkinText( Skin );
rInput.Skin = Skin;
gInput.Skin = Skin;
bInput.Skin = Skin;
aInput.Skin = Skin;
cancelButton.SetSkinButton( Skin );
okButton.SetSkinButton( Skin );
}
private void OnSelectedColorChanged( Color32 color )
{
rInput.Text = color.r.ToString( RuntimeInspectorUtils.numberFormat );
gInput.Text = color.g.ToString( RuntimeInspectorUtils.numberFormat );
bInput.Text = color.b.ToString( RuntimeInspectorUtils.numberFormat );
aInput.Text = color.a.ToString( RuntimeInspectorUtils.numberFormat );
alphaSlider.Color = color;
try
{
if( onColorChanged != null )
onColorChanged( color );
}
catch( Exception e )
{
Debug.LogException( e );
}
}
private void OnAlphaChanged( float alpha )
{
aInput.Text = ( (int) ( alpha * 255 ) ).ToString( RuntimeInspectorUtils.numberFormat );
colorWheel.Alpha = alpha;
Color color = colorWheel.Color;
color.a = alpha;
try
{
if( onColorChanged != null )
onColorChanged( color );
}
catch( Exception e )
{
Debug.LogException( e );
}
}
private bool OnRGBAChanged( BoundInputField source, string input )
{
byte value;
if( byte.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out value ) )
{
Color32 color = colorWheel.Color;
if( source == rInput )
color.r = value;
else if( source == gInput )
color.g = value;
else if( source == bInput )
color.b = value;
else
{
color.a = value;
alphaSlider.Value = value / 255f;
}
alphaSlider.Color = color;
colorWheel.PickColor( color );
return true;
}
return false;
}
public static void DestroyInstance()
{
if( m_instance )
{
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Remove( m_instance.transform );
Destroy( m_instance );
m_instance = null;
}
}
}
}

View File

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

View File

@ -0,0 +1,62 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
public class ColorPickerAlphaSlider : MonoBehaviour, IPointerDownHandler, IDragHandler
{
public delegate void OnValueChangedDelegate( float alpha );
private RectTransform rectTransform;
#pragma warning disable 0649
[SerializeField]
private Image alphaImage;
[SerializeField]
private RectTransform selector;
#pragma warning restore 0649
private float m_value;
public float Value
{
get { return m_value; }
set
{
m_value = value;
selector.anchorMin = new Vector2( m_value, 0.5f );
selector.anchorMax = new Vector2( m_value, 0.5f );
}
}
public Color Color
{
get { return alphaImage.color; }
set { value.a = 1f; alphaImage.color = value; }
}
public OnValueChangedDelegate OnValueChanged;
private void Awake()
{
rectTransform = (RectTransform) transform;
}
public void OnPointerDown( PointerEventData eventData )
{
OnDrag( eventData );
}
public void OnDrag( PointerEventData eventData )
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, eventData.position, eventData.pressEventCamera, out localPoint );
Value = Mathf.Clamp01( localPoint.x / rectTransform.sizeDelta.x );
if( OnValueChanged != null )
OnValueChanged( m_value );
}
}
}

View File

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

View File

@ -0,0 +1,104 @@
using UnityEngine;
using UnityEngine.EventSystems;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace RuntimeInspectorNamespace
{
public class DraggedReferenceItem : PopupBase, IDragHandler, IEndDragHandler
{
private object[] m_references;
public object[] References { get { return m_references; } }
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
// In new Input System, it is just not possible to change a PointerEventData's pointerDrag and dragging variables inside Update/LateUpdate,
// EventSystemUIInputModule will reverse these changes immediately. So we'll allow only a single DraggedReferenceItem
// with the new Input System and track its PointerEventData manually using Pointer.current
internal static DraggedReferenceItem InstanceItem { get; private set; }
private readonly System.Collections.Generic.List<RaycastResult> hoveredUIElements = new System.Collections.Generic.List<RaycastResult>( 4 );
#endif
public void SetContent( object[] references, PointerEventData draggingPointer )
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( InstanceItem )
InstanceItem.DestroySelf();
InstanceItem = this;
draggingPointer = new PointerEventData( EventSystem.current )
{
pressPosition = draggingPointer.pressPosition,
position = draggingPointer.position,
delta = draggingPointer.delta
};
#endif
m_references = references;
label.text = ( references.Length == 1 ) ? references[0].GetNameWithType() : string.Concat( references[0].GetNameWithType(), " (and ", ( references.Length - 1 ).ToString( RuntimeInspectorUtils.numberFormat ), " more)" );
draggingPointer.pointerDrag = gameObject;
draggingPointer.dragging = true;
SetPointer( draggingPointer );
}
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
private void LateUpdate()
{
if( Pointer.current == null || !Pointer.current.press.isPressed )
{
// We must execute OnDrop manually
if( EventSystem.current )
{
hoveredUIElements.Clear();
EventSystem.current.RaycastAll( pointer, hoveredUIElements );
int i = 0;
while( i < hoveredUIElements.Count && !ExecuteEvents.ExecuteHierarchy( hoveredUIElements[i].gameObject, pointer, ExecuteEvents.dropHandler ) )
i++;
}
OnEndDrag( pointer );
}
else
{
Vector2 pointerPos = Pointer.current.position.ReadValue();
Vector2 pointerDelta = pointerPos - pointer.position;
if( pointerDelta.x != 0f || pointerDelta.y != 0f )
{
pointer.position = pointerPos;
pointer.delta = pointerDelta;
OnDrag( pointer );
}
}
}
#endif
protected override void DestroySelf()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( InstanceItem == this )
InstanceItem = null;
#endif
RuntimeInspectorUtils.PoolDraggedReferenceItem( this );
}
public void OnDrag( PointerEventData eventData )
{
if( eventData.pointerId != pointer.pointerId )
return;
RepositionSelf();
}
public void OnEndDrag( PointerEventData eventData )
{
DestroySelf();
}
}
}

View File

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

View File

@ -0,0 +1,167 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace RuntimeInspectorNamespace
{
[RequireComponent( typeof( Camera ) )]
public class DraggedReferenceSourceCamera : MonoBehaviour
{
public delegate Object RaycastHitProcesserDelegate( RaycastHit hit );
private Camera _camera;
#pragma warning disable 0649
[SerializeField]
private UISkin draggedReferenceSkin;
[SerializeField]
private Canvas draggedReferenceCanvas;
[SerializeField]
private float holdTime = 0.4f;
[SerializeField]
private LayerMask interactableObjectsMask = ~0;
[SerializeField]
private float raycastRange = float.MaxValue;
#pragma warning restore 0649
private bool pointerDown = false;
private float pointerDownTime;
private Vector2 pointerDownPos;
private Object hitObject;
private DraggedReferenceItem draggedReference;
private PointerEventData draggingPointer;
#if !ENABLE_INPUT_SYSTEM || ENABLE_LEGACY_INPUT_MANAGER
private readonly List<RaycastResult> hoveredUIElements = new List<RaycastResult>( 4 );
#endif
public RaycastHitProcesserDelegate ProcessRaycastHit;
private void Awake()
{
_camera = GetComponent<Camera>();
}
private void Update()
{
#if !ENABLE_INPUT_SYSTEM || ENABLE_LEGACY_INPUT_MANAGER
// On new Input System, DraggedReferenceItem's PointerEventData is tracked by DraggedReferenceItem itself, not this component
if( draggingPointer != null )
{
if( !draggedReference || !draggedReference.gameObject.activeSelf )
draggingPointer = null;
else if( IsPointerHeld() )
{
draggingPointer.position = GetPointerPosition();
ExecuteEvents.Execute( draggedReference.gameObject, draggingPointer, ExecuteEvents.dragHandler );
}
else
{
ExecuteEvents.Execute( draggedReference.gameObject, draggingPointer, ExecuteEvents.endDragHandler );
if( EventSystem.current != null )
{
hoveredUIElements.Clear();
EventSystem.current.RaycastAll( draggingPointer, hoveredUIElements );
int i = 0;
while( i < hoveredUIElements.Count && !ExecuteEvents.ExecuteHierarchy( hoveredUIElements[i].gameObject, draggingPointer, ExecuteEvents.dropHandler ) )
i++;
}
draggingPointer = null;
}
}
else
#endif
{
if( !pointerDown )
{
if( IsPointerDown() && EventSystem.current && !EventSystem.current.IsPointerOverGameObject() )
{
RaycastHit hit;
if( Physics.Raycast( _camera.ScreenPointToRay( GetPointerPosition() ), out hit, raycastRange, interactableObjectsMask ) )
{
hitObject = ( ProcessRaycastHit != null ) ? ProcessRaycastHit( hit ) : hit.collider.gameObject;
if( hitObject )
{
pointerDown = true;
pointerDownTime = Time.realtimeSinceStartup;
pointerDownPos = GetPointerPosition();
}
}
}
}
else
{
if( IsPointerHeld() )
{
if( ( GetPointerPosition() - pointerDownPos ).sqrMagnitude >= 100f )
pointerDown = false;
else if( Time.realtimeSinceStartup - pointerDownTime >= holdTime )
{
pointerDown = false;
if( hitObject && EventSystem.current )
{
draggingPointer = new PointerEventData( EventSystem.current )
{
#if !ENABLE_INPUT_SYSTEM || ENABLE_LEGACY_INPUT_MANAGER
pointerId = Input.touchCount > 0 ? Input.GetTouch( 0 ).fingerId : -1,
#endif
pressPosition = GetPointerPosition(),
position = GetPointerPosition(),
button = PointerEventData.InputButton.Left
};
draggedReference = RuntimeInspectorUtils.CreateDraggedReferenceItem( hitObject, draggingPointer, draggedReferenceSkin, draggedReferenceCanvas );
if( !draggedReference )
{
pointerDown = false;
draggingPointer = null;
}
}
}
}
else
pointerDown = false;
}
}
}
private bool IsPointerDown()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
return Pointer.current != null && Pointer.current.press.wasPressedThisFrame;
#else
return Input.GetMouseButtonDown( 0 );
#endif
}
private bool IsPointerHeld()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
return Pointer.current != null && Pointer.current.press.isPressed;
#else
return Input.GetMouseButton( 0 );
#endif
}
private Vector2 GetPointerPosition()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
return Pointer.current != null ? Pointer.current.position.ReadValue() : Vector2.zero;
#else
return Input.mousePosition;
#endif
}
}
}

View File

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

View File

@ -0,0 +1,68 @@
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
namespace RuntimeInspectorNamespace
{
public class DraggedReferenceSourceUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IBeginDragHandler
{
#pragma warning disable 0649
[SerializeField]
private Object[] m_references;
public Object[] References
{
get { return m_references; }
set { m_references = value; }
}
[SerializeField]
private UISkin draggedReferenceSkin;
[SerializeField]
private float holdTime = 0.4f;
#pragma warning restore 0649
private IEnumerator pointerHeldCoroutine = null;
public void OnPointerDown( PointerEventData eventData )
{
if( pointerHeldCoroutine != null )
return;
if( m_references.IsEmpty() )
return;
pointerHeldCoroutine = CreateReferenceItemCoroutine( eventData );
StartCoroutine( pointerHeldCoroutine );
}
public void OnPointerUp( PointerEventData eventData )
{
if( pointerHeldCoroutine != null )
{
StopCoroutine( pointerHeldCoroutine );
pointerHeldCoroutine = null;
}
}
public void OnBeginDrag( PointerEventData eventData )
{
if( pointerHeldCoroutine != null )
{
StopCoroutine( pointerHeldCoroutine );
pointerHeldCoroutine = null;
}
}
private IEnumerator CreateReferenceItemCoroutine( PointerEventData eventData )
{
Vector2 pressPosition = eventData.pressPosition;
float dragThreshold = EventSystem.current.pixelDragThreshold;
yield return new WaitForSecondsRealtime( holdTime );
if( !m_references.IsEmpty() && ( eventData.position - pressPosition ).sqrMagnitude < dragThreshold * dragThreshold )
RuntimeInspectorUtils.CreateDraggedReferenceItem( m_references, eventData, draggedReferenceSkin, GetComponentInParent<Canvas>() );
}
}
}

View File

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

View File

@ -0,0 +1,64 @@
using System;
using System.Reflection;
namespace RuntimeInspectorNamespace
{
public struct ExposedMethod
{
private readonly MethodInfo method;
private readonly RuntimeInspectorButtonAttribute properties;
private readonly bool isExtensionMethod;
public string Label { get { return properties.Label; } }
public bool IsInitializer { get { return properties.IsInitializer; } }
public bool VisibleWhenInitialized { get { return ( properties.Visibility & ButtonVisibility.InitializedObjects ) == ButtonVisibility.InitializedObjects; } }
public bool VisibleWhenUninitialized { get { return ( properties.Visibility & ButtonVisibility.UninitializedObjects ) == ButtonVisibility.UninitializedObjects; } }
public ExposedMethod( MethodInfo method, RuntimeInspectorButtonAttribute properties, bool isExtensionMethod )
{
this.method = method;
this.properties = properties;
this.isExtensionMethod = isExtensionMethod;
}
public void Call( object source )
{
if( isExtensionMethod )
method.Invoke( null, new object[] { source } );
else if( method.IsStatic )
method.Invoke( null, null );
else if( source != null )
method.Invoke( source, null );
}
public object CallAndReturnValue( object source )
{
if( isExtensionMethod )
return method.Invoke( null, new object[] { source } );
if( method.IsStatic )
return method.Invoke( null, null );
if( source != null )
return method.Invoke( source, null );
return null;
}
}
public struct ExposedExtensionMethodHolder
{
public readonly Type extendedType;
public readonly MethodInfo method;
public readonly RuntimeInspectorButtonAttribute properties;
public ExposedExtensionMethodHolder( Type extendedType, MethodInfo method, RuntimeInspectorButtonAttribute properties )
{
this.extendedType = extendedType;
this.method = method;
this.properties = properties;
}
}
}

View File

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

View File

@ -0,0 +1,112 @@
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using Visibility = RuntimeInspectorNamespace.RuntimeInspector.VariableVisibility;
namespace RuntimeInspectorNamespace
{
public class ExposedVariablesEnumerator : IEnumerator<MemberInfo>, IEnumerable<MemberInfo>
{
public MemberInfo Current { get { return variables[index]; } }
object IEnumerator.Current { get { return variables[index]; } }
private int index;
private readonly MemberInfo[] variables;
private readonly List<VariableSet> hiddenVariables, exposedVariables;
private readonly Visibility fieldVisibility, propertyVisibility;
public ExposedVariablesEnumerator( MemberInfo[] variables, List<VariableSet> hiddenVariables, List<VariableSet> exposedVariables, Visibility fieldVisibility, Visibility propertyVisibility )
{
index = -1;
this.variables = variables;
this.hiddenVariables = hiddenVariables;
this.exposedVariables = exposedVariables;
this.fieldVisibility = fieldVisibility;
this.propertyVisibility = propertyVisibility;
}
public void Dispose() { }
public IEnumerator<MemberInfo> GetEnumerator()
{
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this;
}
public bool MoveNext()
{
if( variables == null )
return false;
while( ++index < variables.Length )
{
if( ShouldExposeVariable( variables[index] ) )
return true;
}
return false;
}
public void Reset()
{
index = -1;
}
private bool ShouldExposeVariable( MemberInfo variable )
{
string variableName = variable.Name;
if( exposedVariables != null )
{
for( int i = 0; i < exposedVariables.Count; i++ )
{
if( exposedVariables[i].variables.Contains( variableName ) )
return true;
}
}
if( hiddenVariables != null )
{
for( int i = 0; i < hiddenVariables.Count; i++ )
{
if( hiddenVariables[i].variables.Contains( variableName ) )
return false;
}
}
if( variable is FieldInfo )
{
switch( fieldVisibility )
{
case Visibility.None: return false;
case Visibility.All: return true;
case Visibility.SerializableOnly:
FieldInfo field = (FieldInfo) variable;
return field.IsPublic || field.HasAttribute<SerializeField>();
}
}
else
{
switch( propertyVisibility )
{
case Visibility.None: return false;
case Visibility.All: return true;
case Visibility.SerializableOnly:
PropertyInfo property = (PropertyInfo) variable;
return property.GetGetMethod( true ).IsPublic || property.HasAttribute<SerializeField>();
}
}
return true;
}
}
}

View File

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

View File

@ -0,0 +1,19 @@
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
// Credit: http://answers.unity.com/answers/1157876/view.html
[RequireComponent( typeof( CanvasRenderer ) )]
public class NonDrawingGraphic : Graphic
{
public override void SetMaterialDirty() { return; }
public override void SetVerticesDirty() { return; }
protected override void OnPopulateMesh( VertexHelper vh )
{
vh.Clear();
return;
}
}
}

View File

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

View File

@ -0,0 +1,19 @@
using UnityEngine;
using UnityEngine.UI;
namespace RuntimeInspectorNamespace
{
// Credit: http://answers.unity.com/answers/1157876/view.html
[RequireComponent( typeof( CanvasRenderer ) )]
public class NonDrawingMaskableGraphic : MaskableGraphic
{
public override void SetMaterialDirty() { return; }
public override void SetVerticesDirty() { return; }
protected override void OnPopulateMesh( VertexHelper vh )
{
vh.Clear();
return;
}
}
}

View File

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

View File

@ -0,0 +1,233 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace RuntimeInspectorNamespace
{
public interface INumberHandler
{
float MinValue { get; }
float MaxValue { get; }
bool TryParse( string input, out object value );
bool ValuesAreEqual( object value1, object value2 );
object ConvertFromFloat( float value );
float ConvertToFloat( object value );
string ToString( object value );
}
public class NumberHandlers
{
#region Implementations
private class IntHandler : INumberHandler
{
public float MinValue { get { return int.MinValue; } }
public float MaxValue { get { return int.MaxValue; } }
public bool TryParse( string input, out object value ) { int parsedVal; bool result = int.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (int) value1 == (int) value2; }
public object ConvertFromFloat( float value ) { return (int) value; }
public float ConvertToFloat( object value ) { return (int) value; }
public string ToString( object value ) { return ( (int) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class UIntHandler : INumberHandler
{
public float MinValue { get { return uint.MinValue; } }
public float MaxValue { get { return uint.MaxValue; } }
public bool TryParse( string input, out object value ) { uint parsedVal; bool result = uint.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (uint) value1 == (uint) value2; }
public object ConvertFromFloat( float value ) { return (uint) value; }
public float ConvertToFloat( object value ) { return (uint) value; }
public string ToString( object value ) { return ( (uint) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class LongHandler : INumberHandler
{
public float MinValue { get { return long.MinValue; } }
public float MaxValue { get { return long.MaxValue; } }
public bool TryParse( string input, out object value ) { long parsedVal; bool result = long.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (long) value1 == (long) value2; }
public object ConvertFromFloat( float value ) { return (long) value; }
public float ConvertToFloat( object value ) { return (long) value; }
public string ToString( object value ) { return ( (long) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class ULongHandler : INumberHandler
{
public float MinValue { get { return ulong.MinValue; } }
public float MaxValue { get { return ulong.MaxValue; } }
public bool TryParse( string input, out object value ) { ulong parsedVal; bool result = ulong.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (ulong) value1 == (ulong) value2; }
public object ConvertFromFloat( float value ) { return (ulong) value; }
public float ConvertToFloat( object value ) { return (ulong) value; }
public string ToString( object value ) { return ( (ulong) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class ByteHandler : INumberHandler
{
public float MinValue { get { return byte.MinValue; } }
public float MaxValue { get { return byte.MaxValue; } }
public bool TryParse( string input, out object value ) { byte parsedVal; bool result = byte.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (byte) value1 == (byte) value2; }
public object ConvertFromFloat( float value ) { return (byte) value; }
public float ConvertToFloat( object value ) { return (byte) value; }
public string ToString( object value ) { return ( (byte) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class SByteHandler : INumberHandler
{
public float MinValue { get { return sbyte.MinValue; } }
public float MaxValue { get { return sbyte.MaxValue; } }
public bool TryParse( string input, out object value ) { sbyte parsedVal; bool result = sbyte.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (sbyte) value1 == (sbyte) value2; }
public object ConvertFromFloat( float value ) { return (sbyte) value; }
public float ConvertToFloat( object value ) { return (sbyte) value; }
public string ToString( object value ) { return ( (sbyte) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class ShortHandler : INumberHandler
{
public float MinValue { get { return short.MinValue; } }
public float MaxValue { get { return short.MaxValue; } }
public bool TryParse( string input, out object value ) { short parsedVal; bool result = short.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (short) value1 == (short) value2; }
public object ConvertFromFloat( float value ) { return (short) value; }
public float ConvertToFloat( object value ) { return (short) value; }
public string ToString( object value ) { return ( (short) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class UShortHandler : INumberHandler
{
public float MinValue { get { return ushort.MinValue; } }
public float MaxValue { get { return ushort.MaxValue; } }
public bool TryParse( string input, out object value ) { ushort parsedVal; bool result = ushort.TryParse( input, NumberStyles.Integer, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (ushort) value1 == (ushort) value2; }
public object ConvertFromFloat( float value ) { return (ushort) value; }
public float ConvertToFloat( object value ) { return (ushort) value; }
public string ToString( object value ) { return ( (ushort) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class CharHandler : INumberHandler
{
public float MinValue { get { return char.MinValue; } }
public float MaxValue { get { return char.MaxValue; } }
public bool TryParse( string input, out object value ) { char parsedVal; bool result = char.TryParse( input, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (char) value1 == (char) value2; }
public object ConvertFromFloat( float value ) { return (char) value; }
public float ConvertToFloat( object value ) { return (char) value; }
public string ToString( object value ) { return ( (char) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class FloatHandler : INumberHandler
{
public float MinValue { get { return float.MinValue; } }
public float MaxValue { get { return float.MaxValue; } }
public bool TryParse( string input, out object value ) { float parsedVal; bool result = float.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (float) value1 == (float) value2; }
public object ConvertFromFloat( float value ) { return value; }
public float ConvertToFloat( object value ) { return (float) value; }
public string ToString( object value ) { return ( (float) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class DoubleHandler : INumberHandler
{
public float MinValue { get { return float.MinValue; } }
public float MaxValue { get { return float.MaxValue; } }
public bool TryParse( string input, out object value ) { double parsedVal; bool result = double.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (double) value1 == (double) value2; }
public object ConvertFromFloat( float value ) { return (double) value; }
public float ConvertToFloat( object value ) { return (float) (double) value; }
public string ToString( object value ) { return ( (double) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
private class DecimalHandler : INumberHandler
{
public float MinValue { get { return float.MinValue; } }
public float MaxValue { get { return float.MaxValue; } }
public bool TryParse( string input, out object value ) { decimal parsedVal; bool result = decimal.TryParse( input, NumberStyles.Float, RuntimeInspectorUtils.numberFormat, out parsedVal ); value = parsedVal; return result; }
public bool ValuesAreEqual( object value1, object value2 ) { return (decimal) value1 == (decimal) value2; }
public object ConvertFromFloat( float value ) { return (decimal) value; }
public float ConvertToFloat( object value ) { return (float) (decimal) value; }
public string ToString( object value ) { return ( (decimal) value ).ToString( RuntimeInspectorUtils.numberFormat ); }
}
#endregion
private static readonly Dictionary<Type, INumberHandler> handlers = new Dictionary<Type, INumberHandler>( 16 );
public static INumberHandler Get( Type type )
{
INumberHandler result;
if( !handlers.TryGetValue( type, out result ) )
{
if( type == typeof( int ) )
result = new IntHandler();
else if( type == typeof( float ) )
result = new FloatHandler();
else if( type == typeof( long ) )
result = new LongHandler();
else if( type == typeof( double ) )
result = new DoubleHandler();
else if( type == typeof( byte ) )
result = new ByteHandler();
else if( type == typeof( char ) )
result = new CharHandler();
else if( type == typeof( short ) )
result = new ShortHandler();
else if( type == typeof( uint ) )
result = new UIntHandler();
else if( type == typeof( ulong ) )
result = new ULongHandler();
else if( type == typeof( sbyte ) )
result = new SByteHandler();
else if( type == typeof( ushort ) )
result = new UShortHandler();
else if( type == typeof( decimal ) )
result = new DecimalHandler();
else
result = null;
handlers[type] = result;
}
return result;
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b311827a1381d0c439e3ff4be4fd4d6e
folderAsset: yes
timeCreated: 1506496576
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,308 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;
using UnityEngine.UI;
using System.Collections.Generic;
namespace RuntimeInspectorNamespace
{
public class ObjectReferencePicker : SkinnedWindow, IListViewAdapter
{
private const string SPRITE_ATLAS_PREFIX = "SpriteAtlasTexture-";
private static ObjectReferencePicker m_instance;
public static ObjectReferencePicker Instance
{
get
{
if( !m_instance )
{
m_instance = Instantiate( Resources.Load<ObjectReferencePicker>( "RuntimeInspector/ObjectReferencePicker" ) );
m_instance.gameObject.SetActive( false );
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Add( m_instance.transform );
}
return m_instance;
}
}
public delegate void ReferenceCallback( object reference );
private ReferenceCallback onReferenceChanged, onSelectionConfirmed;
public delegate string NameGetter( object reference );
private NameGetter referenceNameGetter, referenceDisplayNameGetter;
#pragma warning disable 0649
[SerializeField]
private Image panel;
[SerializeField]
private Image scrollbar;
[SerializeField]
private InputField searchBar;
[SerializeField]
private Image searchIcon;
[SerializeField]
private Image searchBarBackground;
[SerializeField]
private Text selectPromptText;
[SerializeField]
private LayoutElement searchBarLayoutElement;
[SerializeField]
private LayoutElement buttonsLayoutElement;
[SerializeField]
private Button cancelButton;
[SerializeField]
private Button okButton;
[SerializeField]
private RecycledListView listView;
[SerializeField]
private Image listViewBackground;
[SerializeField]
private ObjectReferencePickerItem referenceItemPrefab;
#pragma warning restore 0649
private Canvas referenceCanvas;
private readonly List<object> references = new List<object>( 64 );
private readonly List<object> filteredReferences = new List<object>( 64 );
private object initialValue;
private object currentlySelectedObject;
private ObjectReferencePickerItem currentlySelectedItem;
int IListViewAdapter.Count { get { return filteredReferences.Count; } }
float IListViewAdapter.ItemHeight { get { return Skin.LineHeight; } }
protected override void Awake()
{
base.Awake();
listView.SetAdapter( this );
searchBar.onValueChanged.AddListener( OnSearchTextChanged );
cancelButton.onClick.AddListener( Cancel );
okButton.onClick.AddListener( () =>
{
try
{
if( onSelectionConfirmed != null )
onSelectionConfirmed( currentlySelectedObject );
}
catch( Exception e )
{
Debug.LogException( e );
}
Close();
} );
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
// On new Input System, scroll sensitivity is much higher than legacy Input system
listView.GetComponent<ScrollRect>().scrollSensitivity *= 0.25f;
#endif
}
public void Show( ReferenceCallback onReferenceChanged, ReferenceCallback onSelectionConfirmed, NameGetter referenceNameGetter, NameGetter referenceDisplayNameGetter, object[] references, object initialReference, bool includeNullReference, string title, Canvas referenceCanvas )
{
initialValue = initialReference;
this.onReferenceChanged = onReferenceChanged;
this.onSelectionConfirmed = onSelectionConfirmed;
this.referenceNameGetter = referenceNameGetter ?? ( ( reference ) => reference.GetNameWithType() );
this.referenceDisplayNameGetter = referenceDisplayNameGetter ?? ( ( reference ) => reference.GetNameWithType() );
if( referenceCanvas && this.referenceCanvas != referenceCanvas )
{
this.referenceCanvas = referenceCanvas;
Canvas canvas = GetComponent<Canvas>();
canvas.CopyValuesFrom( referenceCanvas );
canvas.sortingOrder = Mathf.Max( 1000, referenceCanvas.sortingOrder + 100 );
}
panel.rectTransform.anchoredPosition = Vector2.zero;
gameObject.SetActive( true );
selectPromptText.text = title;
currentlySelectedObject = initialReference;
GenerateReferenceItems( references, includeNullReference );
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
// On desktop platforms, automatically focus on search field
// We don't do the same on mobile because immediately showing the on-screen keyboard after presenting the window wouldn't be nice
searchBar.ActivateInputField();
#endif
}
public void Cancel()
{
try
{
if( currentlySelectedObject != initialValue && onReferenceChanged != null )
onReferenceChanged( initialValue );
}
catch( Exception e )
{
Debug.LogException( e );
}
Close();
}
public void Close()
{
onReferenceChanged = null;
onSelectionConfirmed = null;
referenceNameGetter = null;
referenceDisplayNameGetter = null;
initialValue = null;
currentlySelectedObject = null;
currentlySelectedItem = null;
references.Clear();
filteredReferences.Clear();
gameObject.SetActive( false );
}
protected override void RefreshSkin()
{
panel.color = Skin.WindowColor;
listViewBackground.color = Skin.BackgroundColor;
scrollbar.color = Skin.ScrollbarColor;
selectPromptText.SetSkinText( Skin );
searchBar.textComponent.SetSkinButtonText( Skin );
searchBarBackground.color = Skin.ButtonBackgroundColor;
searchIcon.color = Skin.ButtonTextColor;
searchBarLayoutElement.SetHeight( Skin.LineHeight );
buttonsLayoutElement.SetHeight( Mathf.Min( 45f, Skin.LineHeight * 1.5f ) );
cancelButton.SetSkinButton( Skin );
okButton.SetSkinButton( Skin );
listView.ResetList();
}
private void GenerateReferenceItems( object[] references, bool includeNullReference )
{
this.references.Clear();
filteredReferences.Clear();
searchBar.text = string.Empty;
if( includeNullReference )
this.references.Add( null );
Array.Sort( references, ( ref1, ref2 ) => referenceNameGetter( ref1 ).CompareTo( referenceNameGetter( ref2 ) ) );
for( int i = 0; i < references.Length; i++ )
{
Object unityReference = references[i] as Object;
if( unityReference )
{
if( unityReference.hideFlags != HideFlags.None && unityReference.hideFlags != HideFlags.NotEditable &&
unityReference.hideFlags != HideFlags.HideInHierarchy && unityReference.hideFlags != HideFlags.HideInInspector )
continue;
if( ( unityReference is Texture || unityReference is Sprite ) && unityReference.name.StartsWith( SPRITE_ATLAS_PREFIX ) )
continue;
this.references.Add( unityReference );
}
else if( references[i] != null )
this.references.Add( references[i] );
}
OnSearchTextChanged( string.Empty );
listView.UpdateList();
}
RecycledListItem IListViewAdapter.CreateItem( Transform parent )
{
ObjectReferencePickerItem item = (ObjectReferencePickerItem) Instantiate( referenceItemPrefab, parent, false );
item.Skin = Skin;
return item;
}
private void OnSearchTextChanged( string value )
{
filteredReferences.Clear();
value = value.ToLowerInvariant();
for( int i = 0; i < references.Count; i++ )
{
if( referenceNameGetter( references[i] ).ToLowerInvariant().Contains( value ) )
filteredReferences.Add( references[i] );
}
listView.UpdateList();
}
void IListViewAdapter.SetItemContent( RecycledListItem item )
{
ObjectReferencePickerItem it = (ObjectReferencePickerItem) item;
it.SetContent( filteredReferences[it.Position], referenceDisplayNameGetter( filteredReferences[it.Position] ) );
if( it.Reference == currentlySelectedObject )
{
it.IsSelected = true;
currentlySelectedItem = it;
}
else
it.IsSelected = false;
it.Skin = Skin;
}
void IListViewAdapter.OnItemClicked( RecycledListItem item )
{
if( currentlySelectedItem != null )
currentlySelectedItem.IsSelected = false;
currentlySelectedItem = (ObjectReferencePickerItem) item;
currentlySelectedObject = currentlySelectedItem.Reference;
currentlySelectedItem.IsSelected = true;
try
{
if( onReferenceChanged != null )
onReferenceChanged( currentlySelectedObject );
}
catch( Exception e )
{
Debug.LogException( e );
}
}
public static void DestroyInstance()
{
if( m_instance )
{
RuntimeInspectorUtils.IgnoredTransformsInHierarchy.Remove( m_instance.transform );
Destroy( m_instance );
m_instance = null;
}
}
}
}

View File

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

View File

@ -0,0 +1,89 @@
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;
namespace RuntimeInspectorNamespace
{
public class ObjectReferencePickerItem : RecycledListItem
{
#pragma warning disable 0649
[SerializeField]
private Image background;
[SerializeField]
private RawImage texturePreview;
private LayoutElement texturePreviewLayoutElement;
[SerializeField]
private Text referenceNameText;
#pragma warning restore 0649
public object Reference { get; private set; }
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;
( (RectTransform) transform ).sizeDelta = new Vector2( 0f, Skin.LineHeight );
int previewDimensions = Mathf.Max( 5, Skin.LineHeight - 7 );
texturePreviewLayoutElement.SetWidth( previewDimensions );
texturePreviewLayoutElement.SetHeight( previewDimensions );
referenceNameText.SetSkinText( m_skin );
IsSelected = m_isSelected;
}
}
}
private bool m_isSelected = false;
public bool IsSelected
{
get { return m_isSelected; }
set
{
m_isSelected = value;
if( m_isSelected )
{
background.color = Skin.SelectedItemBackgroundColor;
referenceNameText.color = Skin.SelectedItemTextColor;
}
else
{
background.color = Color.clear;
referenceNameText.color = Skin.TextColor;
}
}
}
private void Awake()
{
texturePreviewLayoutElement = texturePreview.GetComponent<LayoutElement>();
GetComponent<PointerEventListener>().PointerClick += ( eventData ) => OnClick();
}
public void SetContent( object reference, string displayName )
{
Reference = reference;
referenceNameText.text = displayName;
Texture previewTex = ( reference as Object ).GetTexture();
if( previewTex != null )
{
texturePreview.gameObject.SetActive( true );
texturePreview.texture = previewTex;
}
else
texturePreview.gameObject.SetActive( false );
}
}
}

View File

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

Some files were not shown because too many files have changed in this diff Show More