Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Typed Dropdown boiler plate #368

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#if UNITY_2021_3_OR_NEWER
using UnityEngine;
using System;

namespace NaughtyAttributes
{
/// <summary>
/// Draws a dropdown with all types derived from the given base type
/// </summary>
public class TypeDropdownAttribute : PropertyAttribute
{
public readonly Type baseType;
public readonly Type defaultType;
public TypeDropdownAttribute(Type baseType) : this(baseType, baseType)
{

}

public TypeDropdownAttribute(Type baseType, Type defaultType)
{
this.baseType = baseType;
this.defaultType = defaultType;
}
}
}
#endif

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
@@ -0,0 +1,152 @@
#if UNITY_2021_3_OR_NEWER
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEditor;

namespace NaughtyAttributes
{
public abstract class SerializedReferencePropertyDrawerBase : PropertyDrawer
{
static float lineHeight => EditorGUIUtility.singleLineHeight;
static float verticalSpacing => EditorGUIUtility.standardVerticalSpacing;
protected abstract System.Type DefaultType { get; }
protected abstract System.Type BaseType { get; }

System.Collections.Generic.List<Type> m_Types = new List<Type>();

bool m_Initialized = false;

/// <summary>
/// If you override OnGUI or GetPropertyHeight, you should call this method first
/// </summary>
protected void Init()
{
if (m_Initialized)
return;

CollectTypes(m_Types);
Initialize();

m_Initialized = true;
}

/// <summary>
/// Called after types are collected. Can be used to initialze custom fields
/// </summary>
protected virtual void Initialize()
{

}

/// <summary>
/// Called during initialization to collect types. Can be overriden to provide custom types
/// </summary>
/// <param name="list"></param>
protected virtual void CollectTypes(List<Type> list)
{
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
foreach (var type in assembly.GetTypes())
{
if (BaseType.IsAssignableFrom(type) && !type.IsGenericType && !type.IsAbstract && type.AssemblyQualifiedName != DefaultType.AssemblyQualifiedName)
{
m_Types.Add(type);
}
}
}
}


public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Init();

EditorGUI.BeginProperty(position, label, property);

var dropDownRect = position;
dropDownRect.height = lineHeight;
dropDownRect.x += EditorGUIUtility.labelWidth + verticalSpacing;
dropDownRect.width -= EditorGUIUtility.labelWidth + verticalSpacing;

DrawDropdpownContent(dropDownRect, property);

EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}


public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
Init();
return EditorGUI.GetPropertyHeight(property);
}

public void DrawDropdpownContent(Rect position, SerializedProperty property)
{
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isPaused);

var oCol = GUI.contentColor;
if (property.managedReferenceValue == null)
{
FillProperty(property, DefaultType);
}

var currentObject = property.managedReferenceValue;
var currentSelectorType = currentObject.GetType();
var currentContent = GetGUIContentForType(currentSelectorType);

var rect = position;

if (EditorGUI.DropdownButton(rect, currentContent, FocusType.Keyboard))
{
GenericMenu menu = new GenericMenu();
for (var i = 0; i < m_Types.Count; i++)
{
var type = m_Types[i];
var content = GetGUIContentForType(type);
bool isOn = currentContent.text == content.text;
menu.AddItem(content, currentContent.text == content.text, () =>
{
if (!isOn)
{
FillProperty(property, type);
}
});
}

menu.AddSeparator(null);

var defaultContent = GetGUIContentForType(DefaultType);
bool defaultIsOn = defaultContent.text == currentContent.text;
menu.AddItem(GetGUIContentForType(DefaultType), defaultIsOn, () =>
{
if (!defaultIsOn)
{
FillProperty(property, DefaultType);
}
});
menu.DropDown(rect);
}

GUI.contentColor = oCol;

GUIContent GetGUIContentForType(System.Type type)
{
if (type.AssemblyQualifiedName == DefaultType.AssemblyQualifiedName)
return new GUIContent($"{type.Name} (Default)");
return new GUIContent($"{type.Name}");
}
EditorGUI.EndDisabledGroup();
}

private static void FillProperty(SerializedProperty property, System.Type type)
{
var newAsset = Activator.CreateInstance(type);
property.managedReferenceValue = newAsset;
property.serializedObject.ApplyModifiedProperties();
}
}
}
#endif

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
@@ -0,0 +1,15 @@
#if UNITY_2021_3_OR_NEWER
using System;
using UnityEditor;

namespace NaughtyAttributes
{

[CustomPropertyDrawer(typeof(TypeDropdownAttribute))]
public class TypeDropdownAttributePropertyDrawer : SerializedReferencePropertyDrawerBase
{
protected override Type DefaultType => (attribute as TypeDropdownAttribute).defaultType;
protected override Type BaseType => (attribute as TypeDropdownAttribute).baseType;
}
}
#endif

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

30 changes: 30 additions & 0 deletions Assets/NaughtyAttributes/Scripts/Test/TypedDropdownTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#if UNITY_2021_3_OR_NEWER
using NaughtyAttributes;
using UnityEngine;

namespace NaughtyAttributes.Test
{
public class TypedDropdownTest : MonoBehaviour
{
[SerializeReference]
[TypeDropdown(typeof(Animal))]
public Animal MyPet;
}

[System.Serializable]
public class Animal
{
public string nickname = "Silly Billy";
}

public class Dog : Animal
{
public string Breed = "Golden Retriever";
}

public class Cat : Animal
{
public int lives = 9;
}
}
#endif
11 changes: 11 additions & 0 deletions Assets/NaughtyAttributes/Scripts/Test/TypedDropdownTest.cs.meta

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