GameDev.CoreSystems/Architecture/ScriptableObjects/Editor/Drawers/BaseReferenceDrawer.cs

187 lines
7.0 KiB
C#

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Type = System.Type;
namespace ScriptableObjectArchitecture.Editor
{
[CustomPropertyDrawer(typeof(BaseReference), true)]
public sealed class BaseReferenceDrawer : PropertyDrawer
{
/// <summary>
/// Options to display in the popup to select constant or variable.
/// </summary>
private static readonly string[] popupOptions =
{
"Use Constant",
"Use Variable"
};
private const float MultilineThreshold = 20;
// Property Names
private const string VARIABLE_PROPERTY_NAME = "_variable";
private const string CONSTANT_VALUE_PROPERTY_NAME = "_constantValue";
private const string USE_CONSTANT_VALUE_PROPERTY_NAME = "_useConstant";
// Warnings
private const string COULD_NOT_FIND_VALUE_FIELD_WARNING_FORMAT =
"Could not find FieldInfo for [{0}] specific property drawer on type [{1}].";
private Type ValueType { get { return BaseReferenceHelper.GetValueType(fieldInfo); } }
private bool SupportsMultiLine { get { return SOArchitecture_EditorUtility.SupportsMultiLine(ValueType); } }
private SerializedProperty property;
private SerializedProperty useConstant;
private SerializedProperty constantValue;
private SerializedProperty variable;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Get properties
this.property = property;
useConstant = property.FindPropertyRelative("_useConstant");
constantValue = property.FindPropertyRelative("_constantValue");
variable = property.FindPropertyRelative("_variable");
int oldIndent = ResetIndent();
Rect fieldRect = DrawLabel(position, property, label);
Rect valueRect = DrawField(position, fieldRect);
DrawValue(position, valueRect);
EndIndent(oldIndent);
property.serializedObject.ApplyModifiedProperties();
}
private bool IsConstantValueMultiline(SerializedProperty property)
{
return GenericPropertyDrawer.GetHeight(property, ValueType) > MultilineThreshold;
}
private Rect DrawLabel(Rect position, SerializedProperty property, GUIContent label)
{
return EditorGUI.PrefixLabel(position, label);
}
private Rect DrawField(Rect position, Rect fieldRect)
{
Rect buttonRect = GetPopupButtonRect(fieldRect);
Rect valueRect = GetValueRect(fieldRect, buttonRect);
int result = DrawPopupButton(buttonRect, useConstant.boolValue ? 0 : 1);
useConstant.boolValue = result == 0;
return valueRect;
}
private void DrawValue(Rect position, Rect valueRect)
{
if (useConstant.boolValue)
{
DrawGenericPropertyField(position, valueRect);
}
else
{
EditorGUI.PropertyField(valueRect, variable, GUIContent.none);
}
}
private void DrawGenericPropertyField(Rect position, Rect valueRect)
{
if (IsConstantValueMultiline(constantValue))
{
using (new EditorGUI.IndentLevelScope())
{
position.y += EditorGUIUtility.singleLineHeight;
position.height = GenericPropertyDrawer.GetHeight(constantValue, ValueType);
GenericPropertyDrawer.DrawPropertyDrawer(position, constantValue, ValueType);
}
}
else
{
GenericPropertyDrawer.DrawPropertyDrawer(valueRect, constantValue, ValueType, false);
}
}
private Rect GetConstantMultilineRect(Rect position, Rect valueRect)
{
return new Rect(position.x, valueRect.y + EditorGUIUtility.singleLineHeight, position.width, GenericPropertyDrawer.GetHeight(constantValue, ValueType));
}
private Rect GetMultiLineFieldRect(Rect position)
{
return EditorGUI.IndentedRect(new Rect
{
position = new Vector2(position.x, position.y + EditorGUIUtility.singleLineHeight),
size = new Vector2(position.width, EditorGUI.GetPropertyHeight(constantValue) + EditorGUIUtility.singleLineHeight)
});
}
private bool ShouldDrawMultiLineField()
{
return useConstant.boolValue && SupportsMultiLine && EditorGUI.GetPropertyHeight(constantValue) > EditorGUIUtility.singleLineHeight;
}
private int ResetIndent()
{
// Store old indent level and set it to 0, the PrefixLabel takes care of it
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
return indent;
}
private void EndIndent(int indent)
{
EditorGUI.indentLevel = indent;
}
private int DrawPopupButton(Rect rect, int value)
{
return EditorGUI.Popup(rect, value, popupOptions, Styles.PopupStyle);
}
private Rect GetValueRect(Rect fieldRect, Rect buttonRect)
{
Rect valueRect = new Rect(fieldRect);
valueRect.x += buttonRect.width;
valueRect.width -= buttonRect.width;
return valueRect;
}
private Rect GetPopupButtonRect(Rect fieldrect)
{
Rect buttonRect = new Rect(fieldrect);
buttonRect.yMin += Styles.PopupStyle.margin.top;
buttonRect.width = Styles.PopupStyle.fixedWidth + Styles.PopupStyle.margin.right;
buttonRect.height = Styles.PopupStyle.fixedHeight + Styles.PopupStyle.margin.top;
return buttonRect;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty useConstant = property.FindPropertyRelative(USE_CONSTANT_VALUE_PROPERTY_NAME);
SerializedProperty constantValue = property.FindPropertyRelative(CONSTANT_VALUE_PROPERTY_NAME);
if (useConstant.boolValue)
{
if (IsConstantValueMultiline(constantValue))
{
return GenericPropertyDrawer.GetHeight(constantValue, ValueType) + EditorGUIUtility.singleLineHeight;
}
else
{
return EditorGUIUtility.singleLineHeight;
}
}
return EditorGUIUtility.singleLineHeight;
}
static class Styles
{
static Styles()
{
PopupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions"))
{
imagePosition = ImagePosition.ImageOnly,
};
}
public static GUIStyle PopupStyle { get; set; }
}
}
}