#if UNITY_2018_3_OR_NEWER
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace UnityAtoms.Editor
{
///
/// The base Unity Atoms property drawer. Makes it possible to create and add a new Atom via Unity's inspector. Only availble in `UNITY_2018_3_OR_NEWER`.
///
/// The type of Atom the property drawer should apply to.
public abstract class AtomDrawer : PropertyDrawer where T : ScriptableObject
{
class DrawerData
{
public bool UserClickedToCreateAtom = false;
public string NameOfNewAtom = "";
public string WarningText = "";
}
private const string NAMING_FIELD_CONTROL_NAME = "Naming Field";
private Dictionary _perPropertyViewData = new Dictionary();
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property.serializedObject.isEditingMultipleObjects)
{
return EditorGUI.GetPropertyHeight(property);
}
DrawerData drawerData = GetDrawerData(property.propertyPath);
var isCreatingSO = drawerData.UserClickedToCreateAtom && property.objectReferenceValue == null;
if (!isCreatingSO || drawerData.WarningText.Length <= 0) return base.GetPropertyHeight(property, label);
return base.GetPropertyHeight(property, label) * 2 + 4f;
}
private DrawerData GetDrawerData(string propertyPath)
{
DrawerData drawerData;
if (!_perPropertyViewData.TryGetValue(propertyPath, out drawerData))
{
drawerData = new DrawerData();
_perPropertyViewData[propertyPath] = drawerData;
}
return drawerData;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.serializedObject.isEditingMultipleObjects)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
EditorGUI.BeginProperty(position, label, property);
DrawerData drawerData = GetDrawerData(property.propertyPath);
var isCreatingSO = drawerData.UserClickedToCreateAtom && property.objectReferenceValue == null;
var restWidth = drawerData.UserClickedToCreateAtom ? 50 : 58;
var gutter = drawerData.UserClickedToCreateAtom ? 2f : 6f;
Rect restRect = new Rect();
Rect warningRect = new Rect();
Rect nestRect = new Rect();
if (drawerData.WarningText.Length > 0)
{
position = IMGUIUtils.SnipRectV(position, EditorGUIUtility.singleLineHeight, out warningRect, 2f);
}
if (property.objectReferenceValue == null)
{
position = IMGUIUtils.SnipRectH(position, position.width - restWidth, out restRect, gutter);
}
else if(property.GetParent() is BaseAtom ab && AtomFuser.IsValidFuse(ab))
{
position = IMGUIUtils.SnipRectH(position, position.width - restWidth, out nestRect, gutter);
}
var defaultGUIColor = GUI.color;
GUI.color = isCreatingSO ? Color.yellow : defaultGUIColor;
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), isCreatingSO && label != GUIContent.none ? new GUIContent("Name of New Atom") : label);
GUI.color = defaultGUIColor;
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
GUI.SetNextControlName(NAMING_FIELD_CONTROL_NAME);
drawerData.NameOfNewAtom = EditorGUI.TextField(isCreatingSO ? position : Rect.zero, drawerData.NameOfNewAtom);
if (!isCreatingSO)
{
EditorGUI.BeginChangeCheck();
var obj = EditorGUI.ObjectField(position, property.objectReferenceValue, typeof(T), false);
if (EditorGUI.EndChangeCheck())
{
if (property.GetParent() is BaseAtom ab)
{
if (obj == null && AtomFuser.IsFused(property, ab))
{
AtomFuser.DiffuseAtom(property, ab);
}
else if (property.objectReferenceValue != null && AtomFuser.IsFused(property, ab))
{
if (property.objectReferenceValue.name != obj.name)
{
AtomFuser.DiffuseAtom(property, ab);
property.objectReferenceValue = obj;
AtomFuser.FuseAtom(property, ab);
}
}
}
property.objectReferenceValue = obj;
}
}
if (property.objectReferenceValue == null)
{
if (isCreatingSO)
{
var buttonWidth = 24;
Rect secondButtonRect;
Rect firstButtonRect = IMGUIUtils.SnipRectH(restRect, restRect.width - buttonWidth, out secondButtonRect, gutter);
if (GUI.Button(firstButtonRect, "✓")
|| (Event.current.keyCode == KeyCode.Return
&& GUI.GetNameOfFocusedControl() == NAMING_FIELD_CONTROL_NAME))
{
if (drawerData.NameOfNewAtom.Length > 0)
{
try
{
string path = AssetDatabase.GetAssetPath(property.serializedObject.targetObject);
path = path == "" ? "Assets/" : Path.GetDirectoryName(path) + "/";
T so = ScriptableObject.CreateInstance();
if (property.GetParent() is BaseAtom ab)
{
so.name = drawerData.NameOfNewAtom;
AssetDatabase.AddObjectToAsset(so, ab);
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(ab));
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(so));
property.objectReferenceValue = so;
}
else
{
AssetDatabase.CreateAsset(so, path + drawerData.NameOfNewAtom + ".asset");
AssetDatabase.SaveAssets();
property.objectReferenceValue = so;
}
}
catch
{
Debug.LogError("Not able to create Atom");
}
drawerData.UserClickedToCreateAtom = false;
drawerData.WarningText = "";
}
else
{
drawerData.WarningText = "Name of new Atom must be specified!";
EditorGUI.FocusTextInControl(NAMING_FIELD_CONTROL_NAME);
}
}
if (GUI.Button(secondButtonRect, "✗")
|| (Event.current.keyCode == KeyCode.Escape
&& GUI.GetNameOfFocusedControl() == NAMING_FIELD_CONTROL_NAME))
{
drawerData.UserClickedToCreateAtom = false;
drawerData.WarningText = "";
}
if (drawerData.WarningText.Length > 0)
{
EditorGUI.HelpBox(warningRect, drawerData.WarningText, MessageType.Warning);
}
}
else
{
if (GUI.Button(restRect, "Create"))
{
drawerData.UserClickedToCreateAtom = true;
EditorGUI.FocusTextInControl(NAMING_FIELD_CONTROL_NAME);
var baseAtomName = AtomNameUtils.CleanPropertyName(property.name) + typeof(T).Name;
var atomName = property.GetParent() is BaseAtom parentAtom ? parentAtom.name + baseAtomName : baseAtomName;
drawerData.NameOfNewAtom = AtomNameUtils.CreateUniqueName(atomName);
}
}
}
else
{
if (property.GetParent() is BaseAtom ab)
{
var subAsset = AtomFuser.FindSubAsset(ab, property.objectReferenceValue);
if (subAsset == null)
{
if (GUI.Button(nestRect, "Fuse"))
{
AtomFuser.FuseAtom(property, ab);
}
}
else if(AtomFuser.IsValidFuse(ab))
{
if (GUI.Button(nestRect, "Diffuse"))
{
AtomFuser.DiffuseAtom(property, ab);
}
}
}
}
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
}
#endif