Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Editor/Drawers.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using UnityEditor;
using UnityEngine;

namespace TNRD
namespace TNRD.Drawers
{
internal sealed partial class SerializableInterfacePropertyDrawer
public partial class CustomObjectDrawer
{
private static class Styles
{
Expand Down
3 changes: 3 additions & 0 deletions Editor/Drawers/CustomObjectDrawer.Styles.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

114 changes: 114 additions & 0 deletions Editor/Drawers/CustomObjectDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using UnityEditor;
using UnityEngine;

namespace TNRD.Drawers
{
public partial class CustomObjectDrawer
{
public delegate void ButtonClickedDelegate(Rect position);

public delegate void ClickedDelegate();

public delegate void DeletePressedDelegate();

public delegate void PropertiesClickedDelegate();

private bool isSelected;

private Event Event => Event.current;

public event ButtonClickedDelegate ButtonClicked;
public event ClickedDelegate Clicked;
public event DeletePressedDelegate DeletePressed;
public event PropertiesClickedDelegate PropertiesClicked;

public void OnGUI(Rect position, GUIContent label, GUIContent content)
{
Rect positionWithoutThumb = new Rect(position);
positionWithoutThumb.xMax -= 20;

position = DrawPrefixLabel(position, label);
DrawObjectField(position, content);
DrawButton(position);

HandleMouseDown(position, positionWithoutThumb);
HandleKeyDown();
}

private Rect DrawPrefixLabel(Rect position, GUIContent label)
{
GUIStyle labelStyle = isSelected ? Styles.SelectedLabelStyle : Styles.RegularLabelStyle;
Rect result = EditorGUI.PrefixLabel(position, label, labelStyle);
return result;
}

private void DrawObjectField(Rect position, GUIContent objectFieldContent)
{
Rect positionWithoutThumb = new Rect(position);
positionWithoutThumb.xMax -= 20;

if (Event.type == EventType.Repaint)
{
EditorStyles.objectField.Draw(position,
objectFieldContent,
position.Contains(Event.mousePosition),
false,
false,
isSelected);
}
}

private void ForceRepaintEditors()
{
foreach (Editor activeEditor in ActiveEditorTracker.sharedTracker.activeEditors)
{
activeEditor.Repaint();
}
}

private void DrawButton(Rect position)
{
Rect buttonRect = new Rect(position);
buttonRect.yMin += 1;
buttonRect.yMax -= 1;
buttonRect.xMin = buttonRect.xMax - 20;
buttonRect.xMax -= 1;

if (GUI.Button(buttonRect, string.Empty, "objectFieldButton"))
{
ButtonClicked?.Invoke(position);
}
}

private void HandleMouseDown(Rect position, Rect positionWithoutThumb)
{
if (Event.type != EventType.MouseDown)
return;

if (Event.button == 0)
{
isSelected = positionWithoutThumb.Contains(Event.mousePosition);
ForceRepaintEditors();
Clicked?.Invoke();
}
else if (Event.button == 1 && positionWithoutThumb.Contains(Event.mousePosition))
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Properties..."), false, () => { PropertiesClicked?.Invoke(); });
menu.DropDown(position);
Event.Use();
}
}

private void HandleKeyDown()
{
if (!isSelected)
return;

if (Event.type == EventType.KeyDown && Event.keyCode == KeyCode.Delete)
{
DeletePressed?.Invoke();
}
}
}
}
3 changes: 3 additions & 0 deletions Editor/Drawers/CustomObjectDrawer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Editor/Drawers/IReferenceDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using UnityEngine;

namespace TNRD.Drawers
{
internal interface IReferenceDrawer
{
float GetHeight();
void OnGUI(Rect position);
}
}
3 changes: 3 additions & 0 deletions Editor/Drawers/IReferenceDrawer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions Editor/Drawers/RawReferenceDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace TNRD.Drawers
{
internal class RawReferenceDrawer : ReferenceDrawer, IReferenceDrawer
{
private readonly GUIContent label;
private readonly FieldInfo fieldInfo;

private object RawReferenceValue
{
get
{
#if UNITY_2021_1_OR_NEWER
return RawReferenceProperty.managedReferenceValue;
#else
ISerializableInterface instance =
(ISerializableInterface)fieldInfo.GetValue(Property.serializedObject.targetObject);
return instance.GetRawReference();
#endif
}
}

/// <inheritdoc />
public RawReferenceDrawer(SerializedProperty property, GUIContent label, Type genericType, FieldInfo fieldInfo)
: base(property, genericType)
{
this.label = label;
this.fieldInfo = fieldInfo;
}

/// <inheritdoc />
public float GetHeight()
{
if (RawReferenceValue == null)
return EditorGUIUtility.singleLineHeight;

return EditorGUIUtility.singleLineHeight +
EditorGUIUtility.standardVerticalSpacing +
EditorGUI.GetPropertyHeight(RawReferenceProperty, true);
}

/// <inheritdoc />
public void OnGUI(Rect position)
{
Rect objectFieldRect = new Rect(position)
{
height = EditorGUIUtility.singleLineHeight
};

object rawReferenceValue = RawReferenceValue;

GUIContent content = rawReferenceValue == null
? EditorGUIUtility.ObjectContent((MonoScript)null, typeof(MonoScript))
: new GUIContent(rawReferenceValue.GetType().Name, IconUtility.ScriptIcon);

CustomObjectDrawer.OnGUI(objectFieldRect, label, content);
if (rawReferenceValue == null)
return;

Rect objectDrawerRect = new Rect(position);
objectDrawerRect.yMin += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;

EditorGUI.PropertyField(objectDrawerRect,
RawReferenceProperty,
new GUIContent(rawReferenceValue.GetType().Name),
true);
}

/// <inheritdoc />
protected override void OnPropertiesClicked()
{
Type type = RawReferenceValue.GetType();
string typeName = type.Name;

string[] guids = AssetDatabase.FindAssets($"t:Script {typeName}");
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
MonoScript monoScript = AssetDatabase.LoadAssetAtPath<MonoScript>(assetPath);
if (monoScript.GetClass() == type)
{
PropertyEditorUtility.Show(monoScript);
return;
}
}
}
}
}
3 changes: 3 additions & 0 deletions Editor/Drawers/RawReferenceDrawer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 98 additions & 0 deletions Editor/Drawers/ReferenceDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;

namespace TNRD.Drawers
{
internal abstract class ReferenceDrawer
{
protected readonly SerializedProperty Property;
protected readonly Type GenericType;
protected readonly CustomObjectDrawer CustomObjectDrawer;

protected SerializedProperty ReferenceModeProperty => Property.FindPropertyRelative("mode");
protected SerializedProperty RawReferenceProperty => Property.FindPropertyRelative("rawReference");
protected SerializedProperty UnityReferenceProperty => Property.FindPropertyRelative("unityReference");

protected ReferenceDrawer(SerializedProperty property, Type genericType)
{
Property = property;
GenericType = genericType;

CustomObjectDrawer = new CustomObjectDrawer();
CustomObjectDrawer.ButtonClicked += OnButtonClicked;
CustomObjectDrawer.Clicked += OnClicked;
CustomObjectDrawer.DeletePressed += OnDeletePressed;
CustomObjectDrawer.PropertiesClicked += OnPropertiesClicked;
}

private void OnButtonClicked(Rect position)
{
AdvancedDropdownState state = new AdvancedDropdownState();
SerializableInterfaceAdvancedDropdown dropdown =
new SerializableInterfaceAdvancedDropdown(state, GenericType, GetRelevantScene());
dropdown.ItemSelectedEvent += OnItemSelected;
dropdown.Show(position);
}

private Scene? GetRelevantScene()
{
Object target = Property.serializedObject.targetObject;

if (target is ScriptableObject)
return null;
if (target is Component component)
return component.gameObject.scene;
if (target is GameObject gameObject)
return gameObject.scene;

return null;
}

private void OnClicked()
{
switch ((ReferenceMode)ReferenceModeProperty.enumValueIndex)
{
case ReferenceMode.Raw:
// No support for pinging raw objects for now (I guess this would ping the MonoScript?)
break;
case ReferenceMode.Unity:
EditorGUIUtility.PingObject(UnityReferenceProperty.objectReferenceValue);
break;
default:
throw new ArgumentOutOfRangeException();
}
}

private void OnDeletePressed()
{
RawReferenceProperty.managedReferenceValue = null;
UnityReferenceProperty.objectReferenceValue = null;
Property.serializedObject.ApplyModifiedProperties();
}

private void OnItemSelected(ReferenceMode mode, object reference)
{
ReferenceModeProperty.enumValueIndex = (int)mode;

switch (mode)
{
case ReferenceMode.Raw:
RawReferenceProperty.managedReferenceValue = reference;
break;
case ReferenceMode.Unity:
UnityReferenceProperty.objectReferenceValue = (Object)reference;
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
}

Property.serializedObject.ApplyModifiedProperties();
}

protected abstract void OnPropertiesClicked();
}
}
3 changes: 3 additions & 0 deletions Editor/Drawers/ReferenceDrawer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading