Last active
August 25, 2023 22:15
-
-
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
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 | |
{ | |
#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