using Invector; using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using UnityEditor; using UnityEngine; namespace Beyond { public class bEditorHelper : Editor { /// /// Get PropertyName /// /// /// You must pass a lambda of the form: '() => Class.Property' or '() => object.Property' /// public static string GetPropertyName(Expression> propertyLambda) { var me = propertyLambda.Body as MemberExpression; if (me == null) { throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'"); } return me.Member.Name; } /// /// Check if type is a /// /// /// public static bool IsUnityEventyType(Type type) { if (type.Equals(typeof(UnityEngine.Events.UnityEvent))) return true; if (type.BaseType.Equals(typeof(UnityEngine.Events.UnityEvent))) return true; if (type.Name.Contains("UnityEvent") || type.BaseType.Name.Contains("UnityEvent")) return true; return false; } } [CanEditMultipleObjects] [CustomEditor(typeof(vMonoBehaviour), true)] public class vEditorBase : Editor { #region Variables public string[] ignoreEvents; public string[] notEventProperties; public string[] ignore_vMono = new string[] { "openCloseWindow", "openCloseEvents", "selectedToolbar" }; public vClassHeaderAttribute headerAttribute; public GUISkin skin; public Texture2D m_Logo; public List toolbars; #endregion public class vToolBar { public string title; public bool useIcon; public string iconName; public List variables; public int order; public vToolBar() { title = string.Empty; variables = new List(); } } protected virtual void OnEnable() { var targetObject = serializedObject.targetObject; var hasAttributeHeader = targetObject.GetType().IsDefined(typeof(vClassHeaderAttribute), true); if (hasAttributeHeader) { var attributes = Attribute.GetCustomAttributes(targetObject.GetType(), typeof(vClassHeaderAttribute), true); if (attributes.Length > 0) headerAttribute = (vClassHeaderAttribute)attributes[0]; } skin = Resources.Load("vSkin") as GUISkin; m_Logo = Resources.Load("icon_v2") as Texture2D; var prop = serializedObject.GetIterator(); if (((vMonoBehaviour)target) != null) { const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; List events = new List(); toolbars = new List(); var toolbar = new vToolBar(); toolbar.title = "Default"; toolbars.Add(toolbar); var index = 0; bool needReorder = false; int oldOrder = 0; while (prop.NextVisible(true)) { var fieldInfo = targetObject.GetType().GetField(prop.name, flags); if (fieldInfo != null) { var toolBarAttributes = fieldInfo.GetCustomAttributes(typeof(vEditorToolbarAttribute), true); if (toolBarAttributes.Length > 0) { var attribute = toolBarAttributes[0] as vEditorToolbarAttribute; var _toolbar = toolbars.Find(tool => tool != null && tool.title == attribute.title); if (_toolbar == null) { toolbar = new vToolBar(); toolbar.title = attribute.title; toolbar.useIcon = attribute.useIcon; toolbar.iconName = attribute.icon; toolbars.Add(toolbar); toolbar.order = attribute.order; if (oldOrder < attribute.order) needReorder = true; index = toolbars.Count - 1; } else { index = toolbars.IndexOf(_toolbar); if (index < toolbars.Count) { if (attribute.overrideChildOrder) { if (oldOrder < attribute.order) needReorder = true; toolbars[index].order = attribute.order; } if (attribute.overrideIcon) { toolbars[index].useIcon = true; toolbars[index].iconName = attribute.icon; } } } } if (index < toolbars.Count) { toolbars[index].variables.Add(prop.name); } if ((bEditorHelper.IsUnityEventyType(fieldInfo.FieldType) && !events.Contains(fieldInfo.Name))) { events.Add(fieldInfo.Name); } } } if (needReorder) toolbars.Sort((a, b) => a.order.CompareTo(b.order)); var nullToolBar = toolbars.FindAll(tool => tool != null && (tool.variables == null || tool.variables.Count == 0)); for (int i = 0; i < nullToolBar.Count; i++) { if (toolbars.Contains(nullToolBar[i])) toolbars.Remove(nullToolBar[i]); } ignoreEvents = events.vToArray(); if (headerAttribute != null) m_Logo = Resources.Load(headerAttribute.iconName) as Texture2D; //else headerAttribute = new vClassHeaderAttribute(target.GetType().Name); } } protected bool openCloseWindow { get { return serializedObject.FindProperty("openCloseWindow").boolValue; } set { var _openClose = serializedObject.FindProperty("openCloseWindow"); if (_openClose != null && value != _openClose.boolValue) { _openClose.boolValue = value; serializedObject.ApplyModifiedProperties(); } } } protected bool openCloseEvents { get { var _openCloseEvents = serializedObject.FindProperty("openCloseEvents"); return _openCloseEvents != null ? _openCloseEvents.boolValue : false; } set { var _openCloseEvents = serializedObject.FindProperty("openCloseEvents"); if (_openCloseEvents != null && value != _openCloseEvents.boolValue) { _openCloseEvents.boolValue = value; serializedObject.ApplyModifiedProperties(); } } } protected int selectedToolBar { get { var _selectedToolBar = serializedObject.FindProperty("selectedToolbar"); return _selectedToolBar != null ? _selectedToolBar.intValue : 0; } set { var _selectedToolBar = serializedObject.FindProperty("selectedToolbar"); if (_selectedToolBar != null && value != _selectedToolBar.intValue) { _selectedToolBar.intValue = value; serializedObject.ApplyModifiedProperties(); } } } public override bool UseDefaultMargins() { return false; } public override void OnInspectorGUI() { serializedObject.Update(); if (toolbars != null && toolbars.Count > 1) { GUILayout.BeginVertical(headerAttribute != null ? headerAttribute.header : target.GetType().Name, skin.window); GUILayout.Label(m_Logo, skin.label, GUILayout.MaxHeight(25)); if (headerAttribute.openClose) { openCloseWindow = GUILayout.Toggle(openCloseWindow, openCloseWindow ? "Close Properties" : "Open Properties", EditorStyles.toolbarButton); } if (!headerAttribute.openClose || openCloseWindow) { var titles = getToobarTitles(); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script")); var customToolbar = skin.GetStyle("customToolbar"); if (headerAttribute.useHelpBox) { EditorStyles.helpBox.richText = true; EditorGUILayout.HelpBox(headerAttribute.helpBoxText, MessageType.Info); } GUILayout.Space(10); selectedToolBar = GUILayout.SelectionGrid(selectedToolBar, titles, titles.Length > 2 ? 3 : titles.Length, customToolbar, GUILayout.MinWidth(250)); if (!(selectedToolBar < toolbars.Count)) selectedToolBar = 0; GUILayout.Space(10); //GUILayout.Box(toolbars[selectedToolBar].title, skin.box, GUILayout.ExpandWidth(true)); var ignore = getIgnoreProperties(toolbars[selectedToolBar]); var ignoreProperties = ignore.Append(ignore_vMono); DrawPropertiesExcluding(serializedObject, ignoreProperties); AdditionalGUI(); } GUILayout.EndVertical(); } else { if (headerAttribute == null) { if (((vMonoBehaviour)target) != null) DrawPropertiesExcluding(serializedObject, ignore_vMono); else base.OnInspectorGUI(); AdditionalGUI(); } else { GUILayout.BeginVertical(headerAttribute.header, skin.window); GUILayout.Label(m_Logo, skin.label, GUILayout.MaxHeight(25)); if (headerAttribute.openClose) { openCloseWindow = GUILayout.Toggle(openCloseWindow, openCloseWindow ? "Close Properties" : "Open Properties", EditorStyles.toolbarButton); } if (!headerAttribute.openClose || openCloseWindow) { if (headerAttribute.useHelpBox) { EditorStyles.helpBox.richText = true; EditorGUILayout.HelpBox(headerAttribute.helpBoxText, MessageType.Info); } if (ignoreEvents != null && ignoreEvents.Length > 0) { var ignoreProperties = ignoreEvents.Append(ignore_vMono); DrawPropertiesExcluding(serializedObject, ignoreProperties); openCloseEvents = GUILayout.Toggle(openCloseEvents, (openCloseEvents ? "Close " : "Open ") + "Events ", skin.button); if (openCloseEvents) { foreach (string propName in ignoreEvents) { var prop = serializedObject.FindProperty(propName); if (prop != null) EditorGUILayout.PropertyField(prop); } } } else { var ignoreProperties = ignoreEvents.Append(ignore_vMono); DrawPropertiesExcluding(serializedObject, ignoreProperties); } } AdditionalGUI(); EditorGUILayout.EndVertical(); } } if (GUI.changed) { serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); } } public GUIContent[] getToobarTitles() { List props = new List(); for (int i = 0; i < toolbars.Count; i++) { if (toolbars[i] != null) { Texture icon = null; var _icon = Resources.Load(toolbars[i].iconName); if (_icon) icon = _icon as Texture; GUIContent content = new GUIContent(toolbars[i].useIcon ? "" : toolbars[i].title, icon, ""); props.Add(content); } } return props.vToArray(); } public string[] getIgnoreProperties(vToolBar toolbar) { List props = new List(); for (int i = 0; i < toolbars.Count; i++) { if (toolbars[i] != null && toolbar != null && toolbar.variables != null) { for (int a = 0; a < toolbars[i].variables.Count; a++) { if (!props.Contains(toolbars[i].variables[a]) && !toolbar.variables.Contains(toolbars[i].variables[a])) { props.Add(toolbars[i].variables[a]); } } } } props.Add("m_Script"); return props.vToArray(); } protected virtual void AdditionalGUI() { } } }