Skip to content

Instantly share code, notes, and snippets.

@TobiasPott
Last active August 25, 2023 22:15
Show Gist options
  • Save TobiasPott/295fe75879660ff4270857cd7fca7446 to your computer and use it in GitHub Desktop.
Save TobiasPott/295fe75879660ff4270857cd7fca7446 to your computer and use it in GitHub Desktop.
An property drawer to allow selecting from a list of component types on the current selected instance based on type or type inheritance hierarchy
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngineExtensions
{
#if UNITY_EDITOR
// [CustomPropertyDrawer(typeof(CustomMonoBehaviour), true)]
// public class CustomMonoBehaviourSubselectionDrawer : SubselectionDrawer<CustomMonoBehaviour>
// { }
#endif
#if UNITY_EDITOR
public abstract class SubselectionDrawer<T> : PropertyDrawer where T : Component
{
private const float LabelWidthScale = 1.0f;
private const string Tok_Selected = "selected\t";
private const string Tok_FoldoutOff = "sub";
private const string Tok_FoldoutOn = " X ";
private static readonly char[] Tok_TrimChars = new char[] { ' ', '(', ')' };
private bool _foldout = false;
private int _subComps = 0;
// Draw the property inside the given rect
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
float labelWidth = EditorGUIUtility.labelWidth;
SerializedPropertyType pType = property.propertyType;
if (pType == SerializedPropertyType.ExposedReference
|| pType == SerializedPropertyType.ObjectReference)
{
UnityEngine.Object objRef = property.exposedReferenceValue;
if (objRef == null)
objRef = property.objectReferenceValue;
if (objRef != null && objRef is Component)
{
Component compRef = objRef as Component;
Component[] subComps = compRef.GetComponents(typeof(T));
_subComps = subComps.Length;
if (subComps.Length > 1)
{
Rect fldRect = position;
fldRect.xMin = fldRect.xMax - 26;
fldRect.height = EditorGUIUtility.singleLineHeight;
GUIStyle fldStyle = EditorStyles.miniButton;
fldStyle.alignment = TextAnchor.MiddleCenter;
fldStyle.margin = new RectOffset();
fldStyle.padding = new RectOffset();
fldStyle.fontSize = 10;
if (!_foldout && GUI.Button(fldRect, Tok_FoldoutOff, fldStyle)) _foldout = true;
if (_foldout)
{
if (GUI.Button(fldRect, Tok_FoldoutOn, fldStyle))
_foldout = false;
GUIStyle btnStyle = new GUIStyle(EditorStyles.miniButton);
Color clr = btnStyle.normal.textColor;
btnStyle.fontSize = 11;
btnStyle.padding = new RectOffset(5, 5, 2, 2);
btnStyle.alignment = TextAnchor.MiddleLeft;
for (int i = 0; i < subComps.Length; i++)
{
Rect btnPos = position;
btnPos.y += (EditorGUIUtility.singleLineHeight) * (i + 1);
btnPos.height = EditorGUIUtility.singleLineHeight;
Rect lblPos = btnPos;
lblPos.xMax = EditorGUIUtility.labelWidth * LabelWidthScale;
btnPos.xMin += EditorGUIUtility.labelWidth * LabelWidthScale;
GUIStyle lblStyle = new GUIStyle(EditorStyles.miniBoldLabel);
lblStyle.alignment = TextAnchor.MiddleRight;
if (compRef == subComps[i])
{
GUI.color = Color.green;
GUI.Label(lblPos, Tok_Selected, lblStyle);
GUI.color = Color.white;
}
GUI.Label(lblPos, $"{i}#", lblStyle);
string btnLabel = $"{subComps[i]}";
btnLabel = btnLabel.Remove(0, btnLabel.IndexOf('(') + 1).Trim(Tok_TrimChars);
if (btnLabel.Contains('.'))
{
btnLabel = btnLabel.Substring(btnLabel.LastIndexOf('.') + 1);
}
Texture icon = EditorGUIUtility.ObjectContent(subComps[i], subComps[i].GetType()).image;
if (GUI.Button(btnPos, new GUIContent(btnLabel, icon, btnLabel), btnStyle))
{
property.objectReferenceValue = subComps[i];
property.serializedObject.ApplyModifiedProperties();
_foldout = false;
}
}
}
}
}
Rect rawObjRect = position;
if (_subComps > 1)
rawObjRect.xMax -= 28;
EditorGUI.PropertyField(rawObjRect, property, true);
}
else
{
EditorGUI.LabelField(position, $"Type: {property.propertyType} is not supported by {nameof(SubComponentAttribute)}.");
_subComps = 0;
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return base.GetPropertyHeight(property, label) + (_subComps * (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * (_foldout ? 1 : 0));
}
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment