Created
August 25, 2023 21:32
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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