using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; using UnityEditor.AnimatedValues; using UnityEngine.Rendering; namespace UnityEditor.Rendering { /// display options added to the Foldout [Flags] public enum FoldoutOption { /// No Option None = 0, /// Foldout will be indented Indent = 1 << 0, /// Foldout will be boxed Boxed = 1 << 2, /// Foldout will be inside another foldout SubFoldout = 1 << 3, /// Remove the space at end of the foldout NoSpaceAtEnd = 1 << 4 } /// display options added to the Group [Flags] public enum GroupOption { /// No Option None = 0, /// Group will be indented Indent = 1 << 0 } /// /// Utility class to draw inspectors /// /// Type of class containing data needed to draw inspector public static class CoreEditorDrawer { /// Abstraction that have the Draw hability public interface IDrawer { /// /// The draw function /// /// The SerializedProperty to draw /// The editor handling this draw call void Draw(TData serializedProperty, Editor owner); } /// Delegate that must say if this is enabled for drawing /// The data used /// The editor rendering /// True if this should be drawn public delegate bool Enabler(TData data, Editor owner); /// Delegate is called when the foldout state is switched /// The data used /// The editor rendering public delegate void SwitchEnabler(TData data, Editor owner); /// Delegate that must be used to select sub object for data for drawing /// The type of the sub object used for data /// The data used /// The editor rendering /// Embeded object that will be used as data source for later draw in this Select public delegate T2Data DataSelect(TData data, Editor owner); /// Delegate type alternative to IDrawer /// The data used /// The editor rendering public delegate void ActionDrawer(TData data, Editor owner); /// Equivalent to EditorGUILayout.Space that can be put in a drawer group public static readonly IDrawer space = Group((data, owner) => EditorGUILayout.Space()); /// Use it when IDrawer required but no operation should be done public static readonly IDrawer noop = Group((data, owner) => { }); /// /// Conditioned drawer that will only be drawn if its enabler function is null or return true /// /// Enable the drawing if null or return true /// The content of the group /// A IDrawer object public static IDrawer Conditional(Enabler enabler, params IDrawer[] contentDrawers) { return new ConditionalDrawerInternal(enabler, contentDrawers.Draw); } /// /// Conditioned drawer that will only be drawn if its enabler function is null or return true /// /// Enable the drawing if null or return true /// The content of the group /// A IDrawer object public static IDrawer Conditional(Enabler enabler, params ActionDrawer[] contentDrawers) { return new ConditionalDrawerInternal(enabler, contentDrawers); } class ConditionalDrawerInternal : IDrawer { ActionDrawer[] actionDrawers { get; set; } Enabler m_Enabler; public ConditionalDrawerInternal(Enabler enabler = null, params ActionDrawer[] actionDrawers) { this.actionDrawers = actionDrawers; m_Enabler = enabler; } void IDrawer.Draw(TData data, Editor owner) { if (m_Enabler != null && !m_Enabler(data, owner)) return; for (var i = 0; i < actionDrawers.Length; i++) actionDrawers[i](data, owner); } } internal static IDrawer ConditionalWithAdditionalProperties(Enabler enabler, AnimFloat animation, params IDrawer[] contentDrawers) { return new ConditionalDrawerWithAdditionalPropertiesInternal(enabler, animation, contentDrawers.Draw); } internal static IDrawer ConditionalWithAdditionalProperties(Enabler enabler, AnimFloat animation, params ActionDrawer[] contentDrawers) { return new ConditionalDrawerWithAdditionalPropertiesInternal(enabler, animation, contentDrawers); } class ConditionalDrawerWithAdditionalPropertiesInternal : IDrawer { ActionDrawer[] m_ActionDrawers { get; set; } Enabler m_Enabler; AnimFloat m_Anim; public ConditionalDrawerWithAdditionalPropertiesInternal(Enabler enabler = null, AnimFloat anim = null, params ActionDrawer[] actionDrawers) { m_ActionDrawers = actionDrawers; m_Enabler = enabler; m_Anim = anim; } void IDrawer.Draw(TData data, Editor owner) { if (m_Enabler != null && !m_Enabler(data, owner)) return; if (m_Anim != null) CoreEditorUtils.BeginAdditionalPropertiesHighlight(m_Anim); for (var i = 0; i < m_ActionDrawers.Length; i++) m_ActionDrawers[i](data, owner); if (m_Anim != null) { CoreEditorUtils.EndAdditionalPropertiesHighlight(); // While the highlight is being changed, force the Repaint of the editor if (m_Anim.value > 0.0f) owner.Repaint(); } } } /// /// Conditioned drawer that will draw something depending of the return of the switch /// /// Chose witch drawing to use /// This will be draw if the is true /// This will be draw if the is false /// A IDrawer object public static IDrawer TernaryConditional(Enabler @switch, IDrawer drawIfTrue, IDrawer drawIfFalse) => new TernaryConditionalDrawerInternal(@switch, drawIfTrue.Draw, drawIfFalse.Draw); /// /// Conditioned drawer that will draw something depending of the return of the switch /// /// Chose witch drawing to use /// This will be draw if the is true /// This will be draw if the is false /// A IDrawer object public static IDrawer TernaryConditional(Enabler @switch, ActionDrawer drawIfTrue, ActionDrawer drawIfFalse) => new TernaryConditionalDrawerInternal(@switch, drawIfTrue, drawIfFalse); class TernaryConditionalDrawerInternal : IDrawer { ActionDrawer drawIfTrue; ActionDrawer drawIfFalse; Enabler m_Switch; public TernaryConditionalDrawerInternal(Enabler @switch, ActionDrawer drawIfTrue, ActionDrawer drawIfFalse) { this.drawIfTrue = drawIfTrue; this.drawIfFalse = drawIfFalse; m_Switch = @switch; } void IDrawer.Draw(TData data, Editor owner) { if (m_Switch != null && !m_Switch(data, owner)) drawIfFalse?.Invoke(data, owner); else drawIfTrue?.Invoke(data, owner); } } /// /// Group of drawing function for inspector. /// They will be drawn one after the other. /// /// The content of the group /// A IDrawer object public static IDrawer Group(params IDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, null, GroupOption.None, contentDrawers.Draw); } /// /// Group of drawing function for inspector. /// They will be drawn one after the other. /// /// The content of the group /// A IDrawer object public static IDrawer Group(params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, null, GroupOption.None, contentDrawers); } /// Group of drawing function for inspector with a set width for labels /// Width used for all labels in the group /// The content of the group /// A IDrawer object public static IDrawer Group(float labelWidth, params IDrawer[] contentDrawers) { return new GroupDrawerInternal(labelWidth, null, GroupOption.None, contentDrawers.Draw); } /// Group of drawing function for inspector with a set width for labels /// Adds a header on top /// The content of the group /// A IDrawer object public static IDrawer Group(GUIContent header, params IDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, header, GroupOption.None, contentDrawers.Draw); } /// Group of drawing function for inspector with a set width for labels /// Width used for all labels in the group /// The content of the group /// A IDrawer object public static IDrawer Group(float labelWidth, params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(labelWidth, null, GroupOption.None, contentDrawers); } /// Group of drawing function for inspector with a set width for labels /// Adds a header on top /// The content of the group /// A IDrawer object public static IDrawer Group(GUIContent header, params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, header, GroupOption.None, contentDrawers); } /// /// Group of drawing function for inspector. /// They will be drawn one after the other. /// /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(GroupOption options, params IDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, null, options, contentDrawers.Draw); } /// /// Group of drawing function for inspector. /// They will be drawn one after the other. /// /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(GroupOption options, params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, null, options, contentDrawers); } /// Group of drawing function for inspector with a set width for labels /// Width used for all labels in the group /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(float labelWidth, GroupOption options, params IDrawer[] contentDrawers) { return new GroupDrawerInternal(labelWidth, null, options, contentDrawers.Draw); } /// Group of drawing function for inspector with a set width for labels /// Adds a header on top /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(GUIContent header, GroupOption options, params IDrawer[] contentDrawers) { return new GroupDrawerInternal(-1f, header, options, contentDrawers.Draw); } /// Group of drawing function for inspector with a set width for labels /// Width used for all labels in the group /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(float labelWidth, GroupOption options, params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(labelWidth, null, options, contentDrawers); } /// Group of drawing function for inspector with a set width for labels /// Adds a header on top /// Allow to add indentation on this group /// The content of the group /// A IDrawer object public static IDrawer Group(GUIContent header, GroupOption options, params ActionDrawer[] contentDrawers) { return new GroupDrawerInternal(-1, header, options, contentDrawers); } class GroupDrawerInternal : IDrawer { ActionDrawer[] actionDrawers { get; set; } GUIContent header { get; } float m_LabelWidth; bool isIndented; public GroupDrawerInternal(float labelWidth = -1f, GUIContent header = null, GroupOption options = GroupOption.None, params ActionDrawer[] actionDrawers) { this.actionDrawers = actionDrawers; this.header = header; m_LabelWidth = labelWidth; isIndented = (options & GroupOption.Indent) != 0; } void IDrawer.Draw(TData data, Editor owner) { if (isIndented) ++EditorGUI.indentLevel; var currentLabelWidth = EditorGUIUtility.labelWidth; if (m_LabelWidth >= 0f) { EditorGUIUtility.labelWidth = m_LabelWidth; } if (header != null) EditorGUILayout.LabelField(header, EditorStyles.boldLabel); for (var i = 0; i < actionDrawers.Length; i++) actionDrawers[i](data, owner); if (m_LabelWidth >= 0f) { EditorGUIUtility.labelWidth = currentLabelWidth; } if (isIndented) --EditorGUI.indentLevel; } } class FoldoutGroupDrawerInternal : IDrawer where TEnum : struct, IConvertible { readonly ActionDrawer[] m_ActionDrawers; readonly bool m_IsBoxed; readonly bool m_IsSubFoldout; readonly bool m_NoSpaceAtEnd; readonly bool m_IsIndented; readonly GUIContent m_Title; readonly string m_HelpUrl; ExpandedState m_State; readonly TEnum m_Mask; readonly Enabler m_Enabler; readonly SwitchEnabler m_SwitchEnabler; public FoldoutGroupDrawerInternal(GUIContent title, TEnum mask, ExpandedState state, Enabler enabler, SwitchEnabler switchEnabler, FoldoutOption options = FoldoutOption.None, params ActionDrawer[] actionDrawers) { m_IsBoxed = (options & FoldoutOption.Boxed) != 0; m_IsIndented = (options & FoldoutOption.Indent) != 0; m_IsSubFoldout = (options & FoldoutOption.SubFoldout) != 0; m_NoSpaceAtEnd = (options & FoldoutOption.NoSpaceAtEnd) != 0; m_ActionDrawers = actionDrawers; m_Title = title; m_State = state; m_Mask = mask; m_HelpUrl = DocumentationUtils.GetHelpURL(mask); m_Enabler = enabler; m_SwitchEnabler = switchEnabler; } void IDrawer.Draw(TData data, Editor owner) { bool expended = m_State[m_Mask]; bool newExpended; if (m_IsSubFoldout) { newExpended = CoreEditorUtils.DrawSubHeaderFoldout(m_Title, expended, m_IsBoxed); } else { CoreEditorUtils.DrawSplitter(m_IsBoxed); newExpended = CoreEditorUtils.DrawHeaderFoldout(m_Title, expended, m_IsBoxed, m_Enabler == null ? (Func)null : () => m_Enabler(data, owner), m_SwitchEnabler == null ? (Action)null : () => m_SwitchEnabler(data, owner), m_HelpUrl); } if (newExpended ^ expended) m_State[m_Mask] = newExpended; if (!newExpended) return; if (m_IsIndented) ++EditorGUI.indentLevel; for (var i = 0; i < m_ActionDrawers.Length; i++) m_ActionDrawers[i](data, owner); if (m_IsIndented) --EditorGUI.indentLevel; if (!m_NoSpaceAtEnd) EditorGUILayout.Space(); } } /// Create an IDrawer based on an other data container /// Type of selected object containing in the given data containing data needed to draw inspector /// The data new source for the inner drawers /// Inner drawers drawed with given data sources /// A IDrawer object public static IDrawer Select( DataSelect dataSelect, params CoreEditorDrawer.IDrawer[] otherDrawers) { return new SelectDrawerInternal(dataSelect, otherDrawers.Draw); } /// Create an IDrawer based on an other data container /// Type of selected object containing in the given data containing data needed to draw inspector /// The data new source for the inner drawers /// Inner drawers drawed with given data sources /// A IDrawer object public static IDrawer Select( DataSelect dataSelect, params CoreEditorDrawer.ActionDrawer[] otherDrawers) { return new SelectDrawerInternal(dataSelect, otherDrawers); } class SelectDrawerInternal : IDrawer { DataSelect m_DataSelect; CoreEditorDrawer.ActionDrawer[] m_SourceDrawers; public SelectDrawerInternal(DataSelect dataSelect, params CoreEditorDrawer.ActionDrawer[] otherDrawers) { m_SourceDrawers = otherDrawers; m_DataSelect = dataSelect; } void IDrawer.Draw(TData data, Editor o) { var p2 = m_DataSelect(data, o); for (var i = 0; i < m_SourceDrawers.Length; i++) m_SourceDrawers[i](p2, o); } } /// /// Create an IDrawer foldout header using an ExpandedState. /// The default option is Indent in this version. /// /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(string title, TEnum mask, ExpandedState state, params IDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, contentDrawers.Draw); } /// /// Create an IDrawer foldout header using an ExpandedState. /// The default option is Indent in this version. /// /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(string title, TEnum mask, ExpandedState state, params ActionDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(EditorGUIUtility.TrTextContent(title), mask, state, contentDrawers); } /// Create an IDrawer foldout header using an ExpandedState /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Drawing options /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(string title, TEnum mask, ExpandedState state, FoldoutOption options, params IDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, options, contentDrawers.Draw); } /// Create an IDrawer foldout header using an ExpandedState /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Drawing options /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(string title, TEnum mask, ExpandedState state, FoldoutOption options, params ActionDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(EditorGUIUtility.TrTextContent(title), mask, state, options, contentDrawers); } /// /// Create an IDrawer foldout header using an ExpandedState. /// The default option is Indent in this version. /// /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(GUIContent title, TEnum mask, ExpandedState state, params IDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, contentDrawers.Draw); } /// /// Create an IDrawer foldout header using an ExpandedState. /// The default option is Indent in this version. /// /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(GUIContent title, TEnum mask, ExpandedState state, params ActionDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, FoldoutOption.Indent, contentDrawers); } /// Create an IDrawer foldout header using an ExpandedState /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Drawing options /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(GUIContent title, TEnum mask, ExpandedState state, FoldoutOption options, params IDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, options, contentDrawers.Draw); } /// Create an IDrawer foldout header using an ExpandedState /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Drawing options /// The content of the foldout header /// A IDrawer object public static IDrawer FoldoutGroup(GUIContent title, TEnum mask, ExpandedState state, FoldoutOption options, params ActionDrawer[] contentDrawers) where TEnum : struct, IConvertible { return FoldoutGroup(title, mask, state, options, null, null, contentDrawers); } // This one is private as we do not want to have unhandled advanced switch. Change it if necessary. static IDrawer FoldoutGroup(GUIContent title, TEnum mask, ExpandedState state, FoldoutOption options, Enabler showAdditionalProperties, SwitchEnabler switchAdditionalProperties, params ActionDrawer[] contentDrawers) where TEnum : struct, IConvertible { return new FoldoutGroupDrawerInternal(title, mask, state, showAdditionalProperties, switchAdditionalProperties, options, contentDrawers); } /// Helper to draw a foldout with an advanced switch on it. /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Delegate allowing to check if advanced mode is active. /// Delegate to know what to do when advance is switched. /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if advanced mode is active and if foldout is expended. /// Drawing options /// A IDrawer object [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")] public static IDrawer AdvancedFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, IDrawer normalContent, IDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible { return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent.Draw, advancedContent.Draw, options); } /// Helper to draw a foldout with an advanced switch on it. /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Delegate allowing to check if advanced mode is active. /// Delegate to know what to do when advance is switched. /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if advanced mode is active and if foldout is expended. /// Drawing options /// A IDrawer object [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")] public static IDrawer AdvancedFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, ActionDrawer normalContent, IDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible { return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent, advancedContent.Draw, options); } /// Helper to draw a foldout with an advanced switch on it. /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Delegate allowing to check if advanced mode is active. /// Delegate to know what to do when advance is switched. /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if advanced mode is active and if foldout is expended. /// Drawing options /// A IDrawer object [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")] public static IDrawer AdvancedFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, IDrawer normalContent, ActionDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible { return AdvancedFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, isAdvanced, switchAdvanced, normalContent.Draw, advancedContent, options); } /// Helper to draw a foldout with an advanced switch on it. /// Type of the mask used /// Type of the persistent state /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Delegate allowing to check if advanced mode is active. /// Delegate to know what to do when advance is switched. /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if advanced mode is active and if foldout is expended. /// Drawing options /// A IDrawer object [Obsolete("Use AdditionalPropertiesFoldoutGroup instead.")] public static IDrawer AdvancedFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, Enabler isAdvanced, SwitchEnabler switchAdvanced, ActionDrawer normalContent, ActionDrawer advancedContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible { return FoldoutGroup(foldoutTitle, foldoutMask, foldoutState, options, isAdvanced, switchAdvanced, normalContent, Conditional((serialized, owner) => isAdvanced(serialized, owner) && foldoutState[foldoutMask], advancedContent).Draw); } /// /// Helper to draw a foldout with additional properties. /// /// Type of the foldout mask used. /// Type of the persistent foldout state. /// Type of the additional properties mask used. /// Type of the persistent additional properties state. /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState /// The AdditionalPropertiesState describing the component /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if additional properties are shown and if foldout is expanded. /// Drawing options /// A IDrawer object public static IDrawer AdditionalPropertiesFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, TAPEnum additionalPropertiesMask, AdditionalPropertiesState additionalPropertiesState, IDrawer normalContent, IDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible where TAPEnum : struct, IConvertible { return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent.Draw, additionalContent.Draw, options); } /// /// Helper to draw a foldout with additional properties. /// /// Type of the foldout mask used. /// Type of the persistent foldout state. /// Type of the additional properties mask used. /// Type of the persistent additional properties state. /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState /// The AdditionalPropertiesState describing the component /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if additional properties are shown and if foldout is expanded. /// Drawing options /// A IDrawer object public static IDrawer AdditionalPropertiesFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, TAPEnum additionalPropertiesMask, AdditionalPropertiesState additionalPropertiesState, ActionDrawer normalContent, IDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible where TAPEnum : struct, IConvertible { return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent, additionalContent.Draw, options); } /// /// Helper to draw a foldout with additional properties. /// /// Type of the foldout mask used. /// Type of the persistent foldout state. /// Type of the additional properties mask used. /// Type of the persistent additional properties state. /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState /// The AdditionalPropertiesState describing the component /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if additional properties are shown and if foldout is expanded. /// Drawing options /// A IDrawer object public static IDrawer AdditionalPropertiesFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, TAPEnum additionalPropertiesMask, AdditionalPropertiesState additionalPropertiesState, IDrawer normalContent, ActionDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible where TAPEnum : struct, IConvertible { return AdditionalPropertiesFoldoutGroup(foldoutTitle, foldoutMask, foldoutState, additionalPropertiesMask, additionalPropertiesState, normalContent.Draw, additionalContent, options); } /// /// Helper to draw a foldout with additional properties. /// /// Type of the foldout mask used. /// Type of the persistent foldout state. /// Type of the additional properties mask used. /// Type of the persistent additional properties state. /// Title wanted for this foldout header /// Bit mask (enum) used to define the boolean saving the state in ExpandedState /// The ExpandedState describing the component /// Bit mask (enum) used to define the boolean saving the state in AdditionalPropertiesState /// The AdditionalPropertiesState describing the component /// The content of the foldout header always visible if expended. /// The content of the foldout header only visible if additional properties are shown and if foldout is expanded. /// Drawing options /// A IDrawer object public static IDrawer AdditionalPropertiesFoldoutGroup(GUIContent foldoutTitle, TEnum foldoutMask, ExpandedState foldoutState, TAPEnum additionalPropertiesMask, AdditionalPropertiesState additionalPropertiesState, ActionDrawer normalContent, ActionDrawer additionalContent, FoldoutOption options = FoldoutOption.Indent) where TEnum : struct, IConvertible where TAPEnum : struct, IConvertible { bool Enabler(TData data, Editor owner) { return additionalPropertiesState[additionalPropertiesMask]; } void SwitchEnabler(TData data, Editor owner) { additionalPropertiesState[additionalPropertiesMask] = !additionalPropertiesState[additionalPropertiesMask]; } return FoldoutGroup(foldoutTitle, foldoutMask, foldoutState, options, Enabler, SwitchEnabler, normalContent, ConditionalWithAdditionalProperties((serialized, owner) => additionalPropertiesState[additionalPropertiesMask] && foldoutState[foldoutMask], additionalPropertiesState.GetAnimation(additionalPropertiesMask), additionalContent).Draw ); } } /// CoreEditorDrawer extensions public static class CoreEditorDrawersExtensions { /// Concatenate a collection of IDrawer as a unique IDrawer /// Type of class containing data needed to draw inspector /// A collection of IDrawers /// The data source for the inner drawers /// The editor drawing public static void Draw(this IEnumerable.IDrawer> drawers, TData data, Editor owner) { EditorGUILayout.BeginVertical(); foreach (var drawer in drawers) drawer.Draw(data, owner); EditorGUILayout.EndVertical(); } } }