using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace Obi{ [System.AttributeUsage(System.AttributeTargets.Field)] public abstract class MultiPropertyAttribute : PropertyAttribute { #if UNITY_EDITOR public IOrderedEnumerable stored = null; public virtual void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.PropertyField(position,property,label,true); } internal virtual void OnPreGUI(Rect position, SerializedProperty property){} internal virtual void OnPostGUI(Rect position, SerializedProperty property){} internal virtual bool IsVisible(SerializedProperty property){return true;} internal virtual float? GetPropertyHeight( SerializedProperty property, GUIContent label){return null;} #endif } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(MultiPropertyAttribute),true)] public class MultiPropertyDrawer : PropertyDrawer { private MultiPropertyAttribute RetrieveAttributes() { MultiPropertyAttribute mAttribute = attribute as MultiPropertyAttribute; // Get the attribute list, sorted by "order". if (mAttribute.stored == null) { mAttribute.stored = fieldInfo.GetCustomAttributes(typeof(MultiPropertyAttribute), false).OrderBy(s => ((PropertyAttribute)s).order); } return mAttribute; } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { MultiPropertyAttribute mAttribute = RetrieveAttributes(); // If the attribute is invisible, regain the standard vertical spacing. foreach (MultiPropertyAttribute attr in mAttribute.stored) if (!attr.IsVisible(property)) return -EditorGUIUtility.standardVerticalSpacing; // In case no attribute returns a modified height, return the property's default one: float height = EditorGUI.GetPropertyHeight(property, label, true); //base.GetPropertyHeight(property, label); // Check if any of the attributes wants to modify height: foreach (object atr in mAttribute.stored) { if (atr as MultiPropertyAttribute != null) { var tempheight = ((MultiPropertyAttribute)atr).GetPropertyHeight(property, label); if (tempheight.HasValue) { height = tempheight.Value; break; } } } return height; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { MultiPropertyAttribute mAttribute = RetrieveAttributes(); // Calls to IsVisible. If it returns false for any attribute, the property will not be rendered. foreach (MultiPropertyAttribute attr in mAttribute.stored) if (!attr.IsVisible(property)) return; // Calls to OnPreRender before the last attribute draws the UI. foreach (MultiPropertyAttribute attr in mAttribute.stored) attr.OnPreGUI(position,property); // The last attribute is in charge of actually drawing something: ((MultiPropertyAttribute)mAttribute.stored.Last()).OnGUI(position,property,label); // Calls to OnPostRender after the last attribute draws the UI. These are called in inverse order. foreach (MultiPropertyAttribute attr in mAttribute.stored.Reverse()) attr.OnPostGUI(position,property); } } #endif }