Skip to content

Instantly share code, notes, and snippets.

@TobiasPott
Created August 25, 2023 21:32
Show Gist options
  • Save TobiasPott/ea7b9f6e057db1b68b9a116bb7da67b8 to your computer and use it in GitHub Desktop.
Save TobiasPott/ea7b9f6e057db1b68b9a116bb7da67b8 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
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngineExtensions
{
public class SubComponentAttribute : PropertyAttribute
{
public Type type;
public SubComponentAttribute(Type type)
{
this.type = type;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SubComponentAttribute))]
public class SubComponentAttributeDrawer : PropertyDrawer
{
private const float LabelWidthScale = 1.0f;
private const string Tok_Selected = "selected ";
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)
{
// First get the attribute since it contains the range for the slider
SubComponentAttribute att = attribute as SubComponentAttribute;
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(att.type);
_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;
if (compRef == subComps[i])
{
GUIStyle lblStyle = new GUIStyle(EditorStyles.miniBoldLabel);
lblStyle.alignment = TextAnchor.MiddleRight;
GUI.color = Color.green;
GUI.Label(lblPos, Tok_Selected, lblStyle);
GUI.color = Color.white;
}
string btnLabel = $"{subComps[i].ToString().Replace(compRef.name, string.Empty).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