mirror of
https://github.com/maxartz15/ScriptableData.git
synced 2024-11-23 23:05:32 +01:00
Instance indicator colors
Added instance colors to better indicate what is being displayed. Code refactor.
This commit is contained in:
parent
91648de3d9
commit
22fee290ce
@ -1,6 +1,8 @@
|
|||||||
# Change Log:
|
# Change Log:
|
||||||
## 1.0.0
|
## 1.1.1
|
||||||
- Base project.
|
- Instance indicator colors.
|
||||||
|
- Code refactor.
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
- ExstendableScriptableObjectDrawer.
|
- ExstendableScriptableObjectDrawer.
|
||||||
|
## 1.0.0
|
||||||
|
- Base project.
|
@ -1,56 +1,59 @@
|
|||||||
// References:
|
// References:
|
||||||
// https://gist.github.com/tomkail/ba4136e6aa990f4dc94e0d39ec6a058c
|
// https://gist.github.com/tomkail/ba4136e6aa990f4dc94e0d39ec6a058c
|
||||||
// Developed by Tom Kail at Inkle
|
// Developed by Tom Kail at Inkle
|
||||||
// Released under the MIT Licence as held at https://opensource.org/licenses/MIT
|
// Released under the MIT Licence as held at https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace ScriptableData.Editor
|
namespace ScriptableData.Editor
|
||||||
{
|
{
|
||||||
[CustomPropertyDrawer(typeof(ScriptableObject), true)]
|
[CustomPropertyDrawer(typeof(ScriptableObject), true)]
|
||||||
public class ExtendedScriptableObjectDrawer : PropertyDrawer
|
public class ExtendedScriptableObjectDrawer : PropertyDrawer
|
||||||
{
|
{
|
||||||
private static readonly string[] ignoreClassFullNames = new string[] { "TMPro.TMP_FontAsset" };
|
// Permamently exclude classes from being affected by the drawer.
|
||||||
|
private static readonly string[] ignoredFullClassNames = new string[] { "TMPro.TMP_FontAsset" };
|
||||||
private const int buttonWidth = 20;
|
private const int buttonWidth = 20;
|
||||||
|
|
||||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||||
{
|
{
|
||||||
float totalHeight = EditorGUIUtility.singleLineHeight;
|
float totalHeight = EditorGUIUtility.singleLineHeight;
|
||||||
if (property.objectReferenceValue == null || !HasVisableSubProperties(property) || fieldInfo.HasAttribute<NonExtendableAttribute>())
|
|
||||||
|
SerializedObject serializedObject = null;
|
||||||
|
if (property.objectReferenceValue is ScriptableObject scriptableObject)
|
||||||
|
{
|
||||||
|
serializedObject = new SerializedObject(scriptableObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializedObject == null || !serializedObject.HasVisableSubProperties() || fieldInfo.HasAttribute<NonExtendableAttribute>())
|
||||||
{
|
{
|
||||||
return totalHeight;
|
return totalHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.isExpanded)
|
if (property.isExpanded)
|
||||||
{
|
{
|
||||||
ScriptableObject data = property.objectReferenceValue as ScriptableObject;
|
// Iterate over all the values and draw them.
|
||||||
|
SerializedProperty p = serializedObject.GetIterator();
|
||||||
|
|
||||||
if (data == null)
|
if (p.NextVisible(true))
|
||||||
{
|
|
||||||
return EditorGUIUtility.singleLineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedObject serializedObject = new SerializedObject(data);
|
|
||||||
SerializedProperty prop = serializedObject.GetIterator();
|
|
||||||
if (prop.NextVisible(true))
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (prop.name == "m_Script")
|
// Skip drawing the class file.
|
||||||
|
if (EditorUtils.IsIgnoredProperty(p))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializedProperty subProp = serializedObject.FindProperty(prop.name);
|
float height = EditorGUI.GetPropertyHeight(p, null, true) + EditorGUIUtility.standardVerticalSpacing;
|
||||||
float height = EditorGUI.GetPropertyHeight(subProp, null, true) + EditorGUIUtility.standardVerticalSpacing;
|
|
||||||
totalHeight += height;
|
totalHeight += height;
|
||||||
}
|
}
|
||||||
while (prop.NextVisible(false));
|
while (p.NextVisible(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a tiny bit of height if open for the background
|
// Add a tiny bit of height if open for the background
|
||||||
totalHeight += EditorGUIUtility.standardVerticalSpacing;
|
totalHeight += EditorGUIUtility.standardVerticalSpacing;
|
||||||
}
|
}
|
||||||
@ -64,6 +67,7 @@ namespace ScriptableData.Editor
|
|||||||
|
|
||||||
Type fieldType = EditorUtils.GetFieldType(fieldInfo);
|
Type fieldType = EditorUtils.GetFieldType(fieldInfo);
|
||||||
|
|
||||||
|
// Draw with default drawer.
|
||||||
if (fieldType == null || HasIgnoredClassName(fieldType) || fieldInfo.HasAttribute<NonExtendableAttribute>())
|
if (fieldType == null || HasIgnoredClassName(fieldType) || fieldInfo.HasAttribute<NonExtendableAttribute>())
|
||||||
{
|
{
|
||||||
EditorGUI.PropertyField(position, property, label);
|
EditorGUI.PropertyField(position, property, label);
|
||||||
@ -71,148 +75,80 @@ namespace ScriptableData.Editor
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptableObject propertySO = null;
|
|
||||||
if (!property.hasMultipleDifferentValues && property.serializedObject.targetObject != null && property.serializedObject.targetObject is ScriptableObject)
|
|
||||||
{
|
|
||||||
propertySO = property.serializedObject.targetObject as ScriptableObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUIContent guiContent = new GUIContent(property.displayName);
|
|
||||||
Rect foldoutRect = new Rect(position.x, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight);
|
Rect foldoutRect = new Rect(position.x, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight);
|
||||||
if (property.objectReferenceValue != null && HasVisableSubProperties(property))
|
|
||||||
{
|
|
||||||
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, guiContent, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foldoutRect.x += 10;
|
|
||||||
EditorGUI.Foldout(foldoutRect, property.isExpanded, guiContent, true, EditorStyles.label);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect indentedPosition = EditorGUI.IndentedRect(position);
|
Rect indentedPosition = EditorGUI.IndentedRect(position);
|
||||||
float indentOffset = indentedPosition.x - position.x;
|
float indentOffset = indentedPosition.x - position.x;
|
||||||
Rect propertyRect = new Rect(position.x + (EditorGUIUtility.labelWidth - indentOffset + 2), position.y, position.width - (EditorGUIUtility.labelWidth - indentOffset + 2), EditorGUIUtility.singleLineHeight);
|
Rect propertyRect = new Rect(position.x + (EditorGUIUtility.labelWidth - indentOffset + 2), position.y, position.width - (EditorGUIUtility.labelWidth - indentOffset + 2), EditorGUIUtility.singleLineHeight);
|
||||||
|
|
||||||
if (propertySO != null || property.objectReferenceValue == null)
|
SerializedObject serializedObject = null;
|
||||||
|
if(property.objectReferenceValue is ScriptableObject scriptableObject)
|
||||||
{
|
{
|
||||||
propertyRect.width -= buttonWidth;
|
serializedObject = new SerializedObject(scriptableObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUI.BeginChangeCheck();
|
// Check for sub properties and if the property can be expanded.
|
||||||
|
if (serializedObject != null && serializedObject.HasVisableSubProperties())
|
||||||
Object assignedObject = EditorGUI.ObjectField(propertyRect, GUIContent.none, property.objectReferenceValue, fieldType, false);
|
|
||||||
|
|
||||||
if (EditorGUI.EndChangeCheck())
|
|
||||||
{
|
{
|
||||||
property.objectReferenceValue = assignedObject;
|
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, new GUIContent(property.displayName), true);
|
||||||
property.serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect buttonRect = new Rect(position.x + position.width - buttonWidth, position.y, buttonWidth, EditorGUIUtility.singleLineHeight);
|
|
||||||
|
|
||||||
if (property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue != null)
|
|
||||||
{
|
|
||||||
if (property.isExpanded)
|
if (property.isExpanded)
|
||||||
{
|
{
|
||||||
DrawScriptableObjectChildFields(position, property);
|
// Draw sub properties.
|
||||||
|
serializedObject.Draw(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
EditorGUI.LabelField(foldoutRect, new GUIContent(property.displayName));
|
||||||
|
|
||||||
|
if (property.objectReferenceValue == null)
|
||||||
|
{
|
||||||
|
propertyRect.width -= buttonWidth;
|
||||||
|
|
||||||
|
// Draw create button.
|
||||||
|
Rect buttonRect = new Rect(position.x + position.width - buttonWidth, position.y, buttonWidth, EditorGUIUtility.singleLineHeight);
|
||||||
DrawScriptableObjectCreateButton(buttonRect, property, fieldType);
|
DrawScriptableObjectCreateButton(buttonRect, property, fieldType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
// Draw object field.
|
||||||
|
EditorGUI.PropertyField(propertyRect, property, GUIContent.none, false);
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
property.serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
property.serializedObject.ApplyModifiedProperties();
|
property.serializedObject.ApplyModifiedProperties();
|
||||||
EditorGUI.EndProperty();
|
EditorGUI.EndProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawScriptableObjectChildFields(Rect position, SerializedProperty property)
|
private static void DrawScriptableObjectCreateButton(Rect position, SerializedProperty property, Type type)
|
||||||
{
|
|
||||||
ScriptableObject scriptableObject = (ScriptableObject)property.objectReferenceValue;
|
|
||||||
|
|
||||||
if (scriptableObject == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw a background that shows us clearly which fields are part of the ScriptableObject
|
|
||||||
GUI.Box(new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing - 1, position.width, position.height - EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing), "");
|
|
||||||
|
|
||||||
EditorGUI.indentLevel++;
|
|
||||||
SerializedObject serializedObject = new SerializedObject(scriptableObject);
|
|
||||||
|
|
||||||
// Iterate over all the values and draw them
|
|
||||||
SerializedProperty prop = serializedObject.GetIterator();
|
|
||||||
float y = position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
|
||||||
|
|
||||||
EditorGUI.BeginChangeCheck();
|
|
||||||
|
|
||||||
if (prop.NextVisible(true))
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Don't bother drawing the class file
|
|
||||||
if (prop.name == "m_Script") continue;
|
|
||||||
float height = EditorGUI.GetPropertyHeight(prop, new GUIContent(prop.displayName), true);
|
|
||||||
EditorGUI.PropertyField(new Rect(position.x, y, position.width /*- buttonWidth*/, height), prop, true);
|
|
||||||
y += height + EditorGUIUtility.standardVerticalSpacing;
|
|
||||||
}
|
|
||||||
while (prop.NextVisible(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EditorGUI.EndChangeCheck())
|
|
||||||
{
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUI.indentLevel--;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawScriptableObjectCreateButton(Rect position, SerializedProperty property, Type type)
|
|
||||||
{
|
{
|
||||||
if (GUI.Button(position, "+"))
|
if (GUI.Button(position, "+"))
|
||||||
{
|
|
||||||
if (type.IsAbstract)
|
|
||||||
{
|
{
|
||||||
GenericMenu typeChooser = new GenericMenu();
|
GenericMenu typeChooser = new GenericMenu();
|
||||||
foreach (var elem in type.Assembly.GetTypes().Where(t => type.IsAssignableFrom(t)))
|
IEnumerable<Type> types = type.Assembly.GetTypes().Where(t => type.IsAssignableFrom(t));
|
||||||
|
foreach (Type t in types)
|
||||||
{
|
{
|
||||||
if (elem.IsAbstract) continue;
|
if (t.IsAbstract)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
typeChooser.AddItem(new GUIContent(elem.Name), false, (elem) => {
|
typeChooser.AddItem(new GUIContent(t.Name), false, (o) => {
|
||||||
property.objectReferenceValue = EditorUtils.CreateAssetWithSavePrompt(elem as Type, EditorUtils.GetSelectedAssetPath(property));
|
property.objectReferenceValue = EditorUtils.CreateAssetWithSavePrompt(o as Type, EditorUtils.GetSelectedAssetPath(property));
|
||||||
property.serializedObject.ApplyModifiedProperties();
|
property.serializedObject.ApplyModifiedProperties();
|
||||||
}, elem);
|
}, t);
|
||||||
}
|
}
|
||||||
typeChooser.ShowAsContext();
|
typeChooser.ShowAsContext();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
property.objectReferenceValue = EditorUtils.CreateAssetWithSavePrompt(type, EditorUtils.GetSelectedAssetPath(property));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HasIgnoredClassName(Type type)
|
private static bool HasIgnoredClassName(Type type)
|
||||||
{
|
{
|
||||||
return ignoreClassFullNames.Contains(type.FullName);
|
return ignoredFullClassNames.Contains(type.FullName);
|
||||||
}
|
|
||||||
|
|
||||||
private bool HasVisableSubProperties(SerializedProperty property)
|
|
||||||
{
|
|
||||||
ScriptableObject scriptableObject = (ScriptableObject)property.objectReferenceValue;
|
|
||||||
|
|
||||||
if (scriptableObject != null)
|
|
||||||
{
|
|
||||||
SerializedObject serializedObject = new SerializedObject(scriptableObject);
|
|
||||||
SerializedProperty prop = serializedObject.GetIterator();
|
|
||||||
while (prop.NextVisible(true))
|
|
||||||
{
|
|
||||||
if (prop.name == "m_Script") continue;
|
|
||||||
return true; //if theres any visible property other than m_script
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ using System.Reflection;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
namespace ScriptableData.Editor
|
namespace ScriptableData.Editor
|
||||||
{
|
{
|
||||||
@ -66,5 +67,85 @@ namespace ScriptableData.Editor
|
|||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Draw(this SerializedObject serializedObject, Rect position)
|
||||||
|
{
|
||||||
|
// Get position with indentation.
|
||||||
|
Rect indentedPosition = EditorGUI.IndentedRect(position);
|
||||||
|
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
// Draw a background that shows us clearly which fields are part of the ScriptableObject.
|
||||||
|
GUI.Box(new Rect(indentedPosition.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing - 1, position.width, position.height - EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing), "");
|
||||||
|
// Draw color coded side to indicate the scriptable object instance.
|
||||||
|
if (serializedObject.targetObject != null)
|
||||||
|
{
|
||||||
|
Random.InitState(serializedObject.targetObject.GetInstanceID());
|
||||||
|
EditorGUI.DrawRect(new Rect(indentedPosition.x - EditorGUIUtility.standardVerticalSpacing, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing - 1, EditorGUIUtility.standardVerticalSpacing, position.height - EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing), Random.ColorHSV(0f, 1f, 1f, 1f, 0.75f, 0.75f));
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect pRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, position.width, 0);
|
||||||
|
|
||||||
|
// Iterate over all the values and draw them.
|
||||||
|
SerializedProperty p = serializedObject.GetIterator();
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
if (p.NextVisible(true))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (IsIgnoredProperty(p))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRect.height = EditorGUI.GetPropertyHeight(p, new GUIContent(p.displayName), true);
|
||||||
|
// Draw property.
|
||||||
|
EditorGUI.PropertyField(pRect, p, true);
|
||||||
|
|
||||||
|
pRect.y += pRect.height + EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
}
|
||||||
|
while (p.NextVisible(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasVisableSubProperties(this SerializedObject serializedObject)
|
||||||
|
{
|
||||||
|
SerializedProperty p = serializedObject.GetIterator();
|
||||||
|
|
||||||
|
if (p.NextVisible(true))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (IsIgnoredProperty(p))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
while (p.NextVisible(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsIgnoredProperty(SerializedProperty property)
|
||||||
|
{
|
||||||
|
// Skip drawing the class file.
|
||||||
|
if (property.name == "m_Script")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "com.vertexcolor.scriptabledata",
|
"name": "com.vertexcolor.scriptabledata",
|
||||||
"displayName": "ScriptableData",
|
"displayName": "ScriptableData",
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"unity": "2019.1",
|
"unity": "2019.1",
|
||||||
"description": "ScriptableData code base for ScriptableObject workflow.",
|
"description": "ScriptableData code base for ScriptableObject workflow.",
|
||||||
"category": "Tool",
|
"category": "Tool",
|
||||||
|
Loading…
Reference in New Issue
Block a user