From a0f5129f3e5434e07201b42d5faccb46f5b21818 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 14 Sep 2024 23:30:11 +0800 Subject: [PATCH] update editors, update EcsPipelineTemplateSO --- .../Editor/AutoEntityCreatorEditor.cs | 15 +- .../Editor/EcsEntityConnectEditor.cs | 49 +- src/DebugUtils/Editor/EntlongDrawer.cs | 9 +- .../Monitors/Editor/EntityMonitorEditor.cs | 8 +- .../Monitors/Editor/PipelineMonitorEditor.cs | 61 ++- .../Editor/PipelineProcessesMonitorEditor.cs | 38 +- .../Monitors/Editor/WorldMonitorEditor.cs | 6 +- .../EcsPipelineTemplateSO.cs | 12 +- .../EcsPipelineTemplateSOEditor.cs | 24 +- .../ReferenceButtonAttribute.cs | 287 +----------- .../Editor/ComponentTemplatePropertyDrawer.cs | 26 +- .../Editor/EntityTemplateEditor.cs | 119 +++-- src/Internal/Editor/EcsGUI.cs | 442 +++++++++++++++--- src/Internal/Editor/ExtendedEditor.cs | 30 +- 14 files changed, 575 insertions(+), 551 deletions(-) diff --git a/src/Connectors/Editor/AutoEntityCreatorEditor.cs b/src/Connectors/Editor/AutoEntityCreatorEditor.cs index 402618d..3b225bf 100644 --- a/src/Connectors/Editor/AutoEntityCreatorEditor.cs +++ b/src/Connectors/Editor/AutoEntityCreatorEditor.cs @@ -7,20 +7,17 @@ namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(AutoEntityCreator))] [CanEditMultipleObjects] - internal class AutoEntityCreatorEditor : Editor + internal class AutoEntityCreatorEditor : ExtendedEditor { - private AutoEntityCreator Target => (AutoEntityCreator)target; - - public override void OnInspectorGUI() + protected override void DrawCustom() { - EditorGUI.BeginChangeCheck(); var iterator = serializedObject.GetIterator(); iterator.NextVisible(true); while (iterator.NextVisible(false)) { EditorGUILayout.PropertyField(iterator, true); } - if (EditorGUI.EndChangeCheck()) + if (EcsGUI.Changed) { serializedObject.ApplyModifiedProperties(); } @@ -33,9 +30,9 @@ namespace DCFApixels.DragonECS.Unity.Editors float height = EcsGUI.EntityBarHeight; Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, height); EditorGUI.DrawRect(rect, new Color(0f, 0f, 0f, 0.1f)); - rect = RectUtility.AddPadding(rect, 2f, 0f); - var (left, autosetCascadeRect) = RectUtility.HorizontalSliceRight(rect, height); - var (_, autosetRect) = RectUtility.HorizontalSliceRight(left, height); + rect = rect.AddPadding(2f, 0f); + var (left, autosetCascadeRect) = rect.HorizontalSliceRight(height); + var (_, autosetRect) = rect.HorizontalSliceRight(height); if (EcsGUI.AutosetCascadeButton(autosetCascadeRect)) { diff --git a/src/Connectors/Editor/EcsEntityConnectEditor.cs b/src/Connectors/Editor/EcsEntityConnectEditor.cs index 2cb3568..9284134 100644 --- a/src/Connectors/Editor/EcsEntityConnectEditor.cs +++ b/src/Connectors/Editor/EcsEntityConnectEditor.cs @@ -7,24 +7,10 @@ namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(EcsEntityConnect))] [CanEditMultipleObjects] - internal class EcsEntityConnectEditor : Editor + internal class EcsEntityConnectEditor : ExtendedEditor { - private bool _isInit = false; - private EcsEntityConnect Target => (EcsEntityConnect)target; - private bool IsMultipleTargets => targets.Length > 1; - - private void Init() + protected override void DrawCustom() { - if (_isInit) - { - return; - } - _isInit = true; - } - - public override void OnInspectorGUI() - { - Init(); EcsEntityConnect[] targets = new EcsEntityConnect[this.targets.Length]; for (int i = 0; i < targets.Length; i++) { @@ -47,16 +33,19 @@ namespace DCFApixels.DragonECS.Unity.Editors private void DrawTemplates() { - EditorGUI.BeginChangeCheck(); - var iterator = serializedObject.GetIterator(); - iterator.NextVisible(true); - while (iterator.NextVisible(false)) + using (EcsGUI.CheckChanged()) { - EditorGUILayout.PropertyField(iterator, true); - } - if (EditorGUI.EndChangeCheck()) - { - serializedObject.ApplyModifiedProperties(); + var iterator = serializedObject.GetIterator(); + iterator.NextVisible(true); + while (iterator.NextVisible(false)) + { + EditorGUILayout.PropertyField(iterator, true); + } + + if (EcsGUI.Changed) + { + serializedObject.ApplyModifiedProperties(); + } } } @@ -65,8 +54,8 @@ namespace DCFApixels.DragonECS.Unity.Editors float height = EcsGUI.EntityBarHeight; Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, height); EditorGUI.DrawRect(rect, new Color(0f, 0f, 0f, 0.1f)); - rect = RectUtility.AddPadding(rect, 2f, 0f); - var (_, buttonRect) = RectUtility.HorizontalSliceRight(rect, height); + rect = rect.AddPadding(2f, 0f); + var (_, buttonRect) = rect.HorizontalSliceRight(height); if (EcsGUI.AutosetCascadeButton(buttonRect)) { foreach (var target in targets) @@ -82,9 +71,9 @@ namespace DCFApixels.DragonECS.Unity.Editors target.Autoset_Editor(); } } - using (new EditorGUI.DisabledScope(!Application.isPlaying)) + using (EcsGUI.SetEnable(Application.isPlaying)) { - buttonRect = RectUtility.Move(buttonRect, -height, 0); + buttonRect = buttonRect.Move(-height, 0); if (EcsGUI.DelEntityButton(buttonRect)) { foreach (var target in targets) @@ -92,7 +81,7 @@ namespace DCFApixels.DragonECS.Unity.Editors target.DeleteEntity_Editor(); } } - buttonRect = RectUtility.Move(buttonRect, -height, 0); + buttonRect = buttonRect.Move(-height, 0); if (EcsGUI.UnlinkButton(buttonRect)) { foreach (var target in targets) diff --git a/src/DebugUtils/Editor/EntlongDrawer.cs b/src/DebugUtils/Editor/EntlongDrawer.cs index b76c59a..2049381 100644 --- a/src/DebugUtils/Editor/EntlongDrawer.cs +++ b/src/DebugUtils/Editor/EntlongDrawer.cs @@ -2,19 +2,18 @@ using DCFApixels.DragonECS.Unity.Internal; using UnityEditor; using UnityEngine; -using static UnityEditor.EditorGUI; namespace DCFApixels.DragonECS.Unity.Editors { [CustomPropertyDrawer(typeof(entlong))] - internal class EntlongDrawer : PropertyDrawer + internal class EntlongDrawer : ExtendedPropertyDrawer { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) { - using (new DisabledScope(false)) + using (EcsGUI.Disable) { EntitySlotInfo slotInfo = new EntitySlotInfo(property.FindPropertyRelative("_full").longValue); - var (labelRect, barRect) = RectUtility.HorizontalSliceLeft(position, EditorGUIUtility.labelWidth * 0.65f); + var (labelRect, barRect) = position.HorizontalSliceLeft(EditorGUIUtility.labelWidth * 0.65f); EditorGUI.LabelField(labelRect, label); bool isAlive = EcsWorld.GetWorld(slotInfo.world).IsAlive(slotInfo.id, slotInfo.gen); diff --git a/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs index 0581d9c..d7a70d2 100644 --- a/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/EntityMonitorEditor.cs @@ -6,14 +6,12 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(EntityMonitor))] - internal class EntityMonitorEditor : Editor + internal class EntityMonitorEditor : ExtendedEditor { - private EntityMonitor Target => (EntityMonitor)target; - - public override void OnInspectorGUI() + protected override void DrawCustom() { bool isAlive = Target.Entity.TryUnpackForUnityEditor(out int id, out short gen, out short worldID, out EcsWorld world); - using (new EditorGUI.DisabledScope(!isAlive)) + using (EcsGUI.SetEnable(isAlive)) { if (GUILayout.Button("Delete Entity", GUILayout.Height(36f))) { diff --git a/src/DebugUtils/Monitors/Editor/PipelineMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/PipelineMonitorEditor.cs index 58b30a0..f42b640 100644 --- a/src/DebugUtils/Monitors/Editor/PipelineMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/PipelineMonitorEditor.cs @@ -9,7 +9,7 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(PipelineMonitor))] - internal class PipelineMonitorEditor : Editor + internal class PipelineMonitorEditor : ExtendedEditor { private GUIStyle _headerStyle; private GUIStyle _interfacesStyle; @@ -17,19 +17,7 @@ namespace DCFApixels.DragonECS.Unity.Editors private GUIStyle systemsListStyle; - private PipelineMonitor Target => (PipelineMonitor)target; - private bool IsShowInterfaces - { - get { return SettingsPrefs.instance.IsShowInterfaces; } - set { SettingsPrefs.instance.IsShowInterfaces = value; } - } - private bool IsShowHidden - { - get { return SettingsPrefs.instance.IsShowHidden; } - set { SettingsPrefs.instance.IsShowHidden = value; } - } - - public override void OnInspectorGUI() + protected override void DrawCustom() { systemsListStyle = new GUIStyle(EditorStyles.miniLabel); systemsListStyle.wordWrap = true; @@ -55,25 +43,27 @@ namespace DCFApixels.DragonECS.Unity.Editors IsShowInterfaces = EditorGUILayout.Toggle("Show Interfaces", IsShowInterfaces); IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden); - GUILayout.BeginVertical(); - foreach (var item in Target.Pipeline.AllSystems) + using (EcsGUI.Layout.BeginVertical()) { - DrawSystem(item); + foreach (var item in Target.Pipeline.AllSystems) + { + DrawSystem(item); + } } - GUILayout.EndVertical(); GUILayout.Label("[Runners]", _headerStyle); - GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); - foreach (var item in Target.Pipeline.AllRunners) + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f))) { - if (item.Key.IsInterface == false) + foreach (var item in Target.Pipeline.AllRunners) { - DrawRunner(item.Value); + if (item.Key.IsInterface == false) + { + DrawRunner(item.Value); + } } } - GUILayout.EndVertical(); } private void DrawSystem(IEcsProcess system) { @@ -82,8 +72,7 @@ namespace DCFApixels.DragonECS.Unity.Editors GUILayout.EndVertical(); GUILayout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)); - GUILayout.BeginHorizontal(); - using (var scope = EcsGUI.SetAlignment(GUI.skin.label)) + using (EcsGUI.Layout.BeginHorizontal()) using (var scope = EcsGUI.SetAlignment(GUI.skin.label)) { scope.Target.alignment = TextAnchor.UpperLeft; @@ -104,7 +93,6 @@ namespace DCFApixels.DragonECS.Unity.Editors scope.Target.alignment = TextAnchor.UpperRight; GUILayout.Label(">", GUILayout.ExpandWidth(true)); } - GUILayout.EndHorizontal(); return; } @@ -119,13 +107,15 @@ namespace DCFApixels.DragonECS.Unity.Editors string name = meta.Name; Color color = meta.Color.ToUnityColor(); - GUILayout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f)); - if (IsShowInterfaces) + + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f))) { - GUILayout.Label(string.Join(", ", type.GetInterfaces().Select(o => o.Name)), _interfacesStyle); + if (IsShowInterfaces) + { + GUILayout.Label(string.Join(", ", type.GetInterfaces().Select(o => o.Name)), _interfacesStyle); + } + GUILayout.Label(name, EditorStyles.boldLabel); } - GUILayout.Label(name, EditorStyles.boldLabel); - GUILayout.EndVertical(); } private void DrawRunner(IEcsRunner runner) { @@ -138,10 +128,11 @@ namespace DCFApixels.DragonECS.Unity.Editors } Color color = meta.Color.ToUnityColor(); - GUILayout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f)); - GUILayout.Label(meta.Name, EditorStyles.boldLabel); - GUILayout.Label(string.Join(", ", runner.ProcessRaw.Cast().Select(o => o.GetType().Name)), systemsListStyle); - GUILayout.EndVertical(); + using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(color, 0.2f))) + { + GUILayout.Label(meta.Name, EditorStyles.boldLabel); + GUILayout.Label(string.Join(", ", runner.ProcessRaw.Cast().Select(o => o.GetType().Name)), systemsListStyle); + } } private bool CheckIsHidden(TypeMeta meta) { diff --git a/src/DebugUtils/Monitors/Editor/PipelineProcessesMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/PipelineProcessesMonitorEditor.cs index df744f3..360142c 100644 --- a/src/DebugUtils/Monitors/Editor/PipelineProcessesMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/PipelineProcessesMonitorEditor.cs @@ -9,34 +9,16 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(PipelineProcessMonitor))] - internal class PipelineProcessesMonitorEditor : Editor + internal class PipelineProcessesMonitorEditor : ExtendedEditor { private static Type SYSTEM_INTERFACE_TYPE = typeof(IEcsProcess); - private bool _isInit = false; private List _processList = new List(); private Dictionary _processeIndexes = new Dictionary(); private SystemData[] _systemsList; - private PipelineProcessMonitor Target => (PipelineProcessMonitor)target; - private bool IsShowInterfaces + protected override void OnInit() { - get { return SettingsPrefs.instance.IsShowInterfaces; } - set { SettingsPrefs.instance.IsShowInterfaces = value; } - } - private bool IsShowHidden - { - get { return SettingsPrefs.instance.IsShowHidden; } - set { SettingsPrefs.instance.IsShowHidden = value; } - } - - private void Init() - { - if (_isInit) - { - return; - } - _processList.Clear(); _processeIndexes.Clear(); IEnumerable fileretSystems = Target.Pipeline.AllSystems; @@ -70,22 +52,24 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } - _isInit = true; } private Vector2 _position; private Vector2 _cellsize = new Vector2(EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight); private Vector2 _nameCellSize = new Vector2(200f, 200f); private (TypeMeta system, TypeMeta process) _selectedPointMeta = default; - public override void OnInspectorGUI() + + protected override void DrawCustom() { - EditorGUI.BeginChangeCheck(); - IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden); - if (EditorGUI.EndChangeCheck()) + using (EcsGUI.CheckChanged()) { - _isInit = false; + IsShowHidden = EditorGUILayout.Toggle("Show Hidden", IsShowHidden); + if (EcsGUI.Changed) + { + Init(); + } } - Init(); + GUILayout.Label("", GUILayout.ExpandWidth(true), GUILayout.Height(400f)); Rect rect = GUILayoutUtility.GetLastRect(); diff --git a/src/DebugUtils/Monitors/Editor/WorldMonitorEditor.cs b/src/DebugUtils/Monitors/Editor/WorldMonitorEditor.cs index 7470fec..ea72a60 100644 --- a/src/DebugUtils/Monitors/Editor/WorldMonitorEditor.cs +++ b/src/DebugUtils/Monitors/Editor/WorldMonitorEditor.cs @@ -5,11 +5,9 @@ using UnityEditor; namespace DCFApixels.DragonECS.Unity.Editors { [CustomEditor(typeof(WorldMonitor))] - internal class WorldMonitorEditor : Editor + internal class WorldMonitorEditor : ExtendedEditor { - private WorldMonitor Target => (WorldMonitor)target; - - public override void OnInspectorGUI() + protected override void DrawCustom() { EcsGUI.Layout.DrawWorldBaseInfo(Target.World); } diff --git a/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs b/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs index e9e5091..7845f21 100644 --- a/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs +++ b/src/EcsPipelineTemplate/EcsPipelineTemplateSO.cs @@ -51,11 +51,11 @@ namespace DCFApixels.DragonECS EcsPipelineTemplate result = new EcsPipelineTemplate(); result.layers = new string[_layers.Length]; Array.Copy(_layers, result.layers, _layers.Length); - result.systems = new EcsPipelineTemplate.AddCommand[_records.Length]; - for (int i = 0; i < result.systems.Length; i++) + result.records = new EcsPipelineTemplate.Record[_records.Length]; + for (int i = 0; i < result.records.Length; i++) { ref var s = ref _records[i]; - result.systems[i] = new EcsPipelineTemplate.AddCommand(s.target, s.parameters); + result.records[i] = new EcsPipelineTemplate.Record(s.target, s.parameters); } return result; } @@ -64,10 +64,10 @@ namespace DCFApixels.DragonECS { _layers = new string[template.layers.Length]; Array.Copy(template.layers, _layers, template.layers.Length); - _records = new Record[template.systems.Length]; + _records = new Record[template.records.Length]; for (int i = 0; i < _records.Length; i++) { - ref var s = ref template.systems[i]; + ref var s = ref template.records[i]; _records[i] = new Record(s.target, s.parameters); } } @@ -136,7 +136,7 @@ namespace DCFApixels.DragonECS public struct Record { [SerializeReference] - [ReferenceButton(typeof(IEcsModule), typeof(IEcsProcess))] + [ReferenceButton(true, typeof(IEcsModule), typeof(IEcsProcess))] public object target; public AddParams parameters; public Record(object target, AddParams parameters) diff --git a/src/EcsPipelineTemplate/EcsPipelineTemplateSOEditor.cs b/src/EcsPipelineTemplate/EcsPipelineTemplateSOEditor.cs index 0fcc518..28b67a9 100644 --- a/src/EcsPipelineTemplate/EcsPipelineTemplateSOEditor.cs +++ b/src/EcsPipelineTemplate/EcsPipelineTemplateSOEditor.cs @@ -8,6 +8,7 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { [CustomPropertyDrawer(typeof(EcsPipelineTemplateSO.Record))] + //[CustomPropertyDrawer(typeof(EcsPipelineTemplate.Record))] internal class EcsPipelineTemplateSORecordDrawer : ExtendedPropertyDrawer { protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) @@ -85,7 +86,6 @@ namespace DCFApixels.DragonECS.Unity.Editors CreateLists(); } - private void CreateLists() { _reorderableLayersList = new ReorderableList(serializedObject, _layersProp, true, false, true, true); @@ -151,15 +151,25 @@ namespace DCFApixels.DragonECS.Unity.Editors using (EcsGUI.CheckChanged()) { var prop = _recordsProp.GetArrayElementAtIndex(index); - var mrProp = prop.FindPropertyRelative(nameof(EcsPipelineTemplateSO.Record.target)); - ITypeMeta meta = mrProp.managedReferenceValue == null ? null : mrProp.managedReferenceValue.GetMeta(); - EcsGUI.DrawTypeMetaBlock(ref rect, prop, meta); + + var targetProp = prop.FindPropertyRelative(nameof(EcsPipelineTemplateSO.Record.target)); + var paramsProp = prop.FindPropertyRelative(nameof(EcsPipelineTemplateSO.Record.parameters)); + + bool isNull = targetProp.managedReferenceValue == null; + ITypeMeta meta = isNull ? null : targetProp.managedReferenceValue.GetMeta(); + + if (EcsGUI.DrawTypeMetaBlock(ref rect, prop, meta)) + { + return; + } EditorGUI.PropertyField(rect, prop, true); } } private float OnReorderableRecordsListElementHeight(int index) { - return EcsGUI.GetTypeMetaBlockHeight(EditorGUI.GetPropertyHeight(_recordsProp.GetArrayElementAtIndex(index))); + float result; + result = EditorGUI.GetPropertyHeight(_recordsProp.GetArrayElementAtIndex(index)); + return EcsGUI.GetTypeMetaBlockHeight(result); } private void OnReorderableRecordsListAdd(ReorderableList list) @@ -202,7 +212,7 @@ namespace DCFApixels.DragonECS.Unity.Editors private void DrawLayoutNameList(SerializedProperty layersProp) { - using (EcsGUI.SetVerticalLayout()) + using (EcsGUI.Layout.BeginVertical()) { GUILayout.Label(UnityEditorUtility.GetLabel(layersProp.displayName), EditorStyles.boldLabel); _reorderableLayersList.DoLayoutList(); @@ -210,7 +220,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } private void DrawRecordList(SerializedProperty recordsProp) { - using (EcsGUI.SetVerticalLayout()) + using (EcsGUI.Layout.BeginVertical()) { GUILayout.Label(UnityEditorUtility.GetLabel(recordsProp.displayName), EditorStyles.boldLabel); _reorderableRecordsList.DoLayoutList(); diff --git a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs index ef35bf7..a8a414a 100644 --- a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs +++ b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs @@ -1,16 +1,18 @@ -using DCFApixels.DragonECS; -using System; +using System; using UnityEngine; namespace DCFApixels.DragonECS.Unity.Internal { internal sealed class ReferenceButtonAttribute : PropertyAttribute { - public readonly Type[] predicateTypes; - public ReferenceButtonAttribute() : this(Array.Empty()) { } - public ReferenceButtonAttribute(params Type[] predicateTypes) + public readonly Type[] PredicateTypes; + public readonly bool IsHideButtonIfNotNull; + public ReferenceButtonAttribute(bool isHideButtonIfNotNull = false) : this(isHideButtonIfNotNull, Array.Empty()) { } + public ReferenceButtonAttribute(params Type[] predicateTypes) : this(false, predicateTypes) { } + public ReferenceButtonAttribute(bool isHideButtonIfNotNull, params Type[] predicateTypes) { - this.predicateTypes = predicateTypes; + IsHideButtonIfNotNull = isHideButtonIfNotNull; + PredicateTypes = predicateTypes; Array.Sort(predicateTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal)); } } @@ -21,237 +23,11 @@ namespace DCFApixels.DragonECS.Unity.Editors { using DCFApixels.DragonECS.Unity.Internal; using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; using UnityEditor; - using UnityEditor.IMGUI.Controls; - using UnityObject = UnityEngine.Object; [CustomPropertyDrawer(typeof(ReferenceButtonAttribute))] - internal sealed class ReferenceButtonAttributeDrawer : PropertyDrawer + internal sealed class ReferenceButtonAttributeDrawer : ExtendedPropertyDrawer { - private static bool _isInit; - - private static Type[] _serializableTypes; - private static Dictionary _predicatTypesMenus = new Dictionary(); - private ReferenceButtonAttribute TargetAttribute => (ReferenceButtonAttribute)attribute; - - #region PredicateTypesKey - private readonly struct PredicateTypesKey : IEquatable - { - public readonly Type[] types; - public PredicateTypesKey(Type[] types) - { - this.types = types; - } - public bool Equals(PredicateTypesKey other) - { - if (types.Length != other.types.Length) { return false; } - for (int i = 0; i < types.Length; i++) - { - if (types[i] != other.types[i]) - { - return false; - } - } - return true; - } - public override bool Equals(object obj) - { - return obj is PredicateTypesKey key && Equals(key); - } - public override int GetHashCode() - { - return HashCode.Combine(types); - } - public static implicit operator PredicateTypesKey(Type[] types) { return new PredicateTypesKey(types); } - public static implicit operator Type[](PredicateTypesKey key) { return key.types; } - } - #endregion - - #region ReferenceDropDown - private class ReferenceDropDown : AdvancedDropdown - { - public readonly Type[] PredicateTypes; - public ReferenceDropDown(Type[] predicateTypes) : base(new AdvancedDropdownState()) - { - PredicateTypes = predicateTypes; - minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30); - } - protected override AdvancedDropdownItem BuildRoot() - { - int increment = 0; - var root = new Item(null, "Select Type", increment++); - root.AddChild(new Item(null, "", increment++)); - - Dictionary dict = new Dictionary(); - - foreach (var type in _serializableTypes) - { - bool isAssignable = false; - foreach (Type predicateTypes in PredicateTypes) - { - if (predicateTypes.IsAssignableFrom(type)) - { - isAssignable = true; - break; - } - } - if (isAssignable) - { - ITypeMeta meta = type.ToMeta(); - string description = meta.Description.Text; - MetaGroup group = meta.Group; - var splitedGroup = group.Splited; - - Item parent = root; - if (splitedGroup.Count > 0) - { - int i = 1; - foreach (var subgroup in splitedGroup) - { - Key key = new Key(group, i); - if (dict.TryGetValue(key, out Item item) == false) - { - item = new Item(null, subgroup, increment++); - parent.AddChild(item); - dict.Add(key, item); - } - parent = item; - i++; - } - } - - var leafItem = new Item(type, meta.Name, increment++); - parent.AddChild(leafItem); - } - } - return root; - } - - protected override void ItemSelected(AdvancedDropdownItem item) - { - base.ItemSelected(item); - OnSelected((Item)item); - } - - public event Action OnSelected = delegate { }; - - public class Item : AdvancedDropdownItem - { - public readonly Type Type; - public Item(Type type, string name, int id) : base(name) - { - Type = type; - this.id = id; - } - } - - #region Key - private readonly struct Key : IEquatable - { - public readonly MetaGroup Group; - public readonly int Length; - public Key(MetaGroup group, int length) - { - Group = group; - Length = length; - } - public bool Equals(Key other) - { - if (Length != other.Length) - { - return false; - } - IEnumerator splitedEnum = Group.Splited.GetEnumerator(); - IEnumerator splitedEnumOther = other.Group.Splited.GetEnumerator(); - for (int i = 0; i < Length; i++) - { - splitedEnum.MoveNext(); - splitedEnumOther.MoveNext(); - if (splitedEnum.Current != splitedEnumOther.Current) - { - return false; - } - } - return true; - } - public override bool Equals(object obj) - { - return obj is Key key && Equals(key); - } - public override int GetHashCode() - { - unchecked - { - int state = Length; - state ^= state << 13; - state ^= state >> 17; - state ^= state << 5; - var x = Group.Splited.GetEnumerator(); - x.MoveNext(); - return x.Current.GetHashCode() ^ state; - }; - } - } - #endregion - } - #endregion - - #region Init - private static void Init() - { - if (_isInit) { return; } - - List types = new List(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - var targetTypes = assembly.GetTypes().Where(type => - (type.IsGenericType || type.IsAbstract || type.IsInterface) == false && - type.IsSubclassOf(typeof(UnityObject)) == false && - type.GetCustomAttribute() != null); - - types.AddRange(targetTypes); - } - _serializableTypes = types.ToArray(); - _isInit = true; - } - - private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes) - { - Init(); - if (_predicatTypesMenus.TryGetValue(predicatTypes, out ReferenceDropDown menu) == false) - { - menu = new ReferenceDropDown(predicatTypes); - menu.OnSelected += SelectComponent; - _predicatTypesMenus.Add(predicatTypes, menu); - } - - return menu; - } - - [ThreadStatic] - private static SerializedProperty currentProperty; - private static void SelectComponent(ReferenceDropDown.Item item) - { - Type type = item.Type; - if (type == null) - { - currentProperty.managedReferenceValue = null; - } - else - { - currentProperty.managedReferenceValue = Activator.CreateInstance(type); - currentProperty.isExpanded = true; - } - - currentProperty.serializedObject.ApplyModifiedProperties(); - - EcsGUI.Changed = true; - } - #endregion - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (property.managedReferenceValue != null) @@ -260,13 +36,14 @@ namespace DCFApixels.DragonECS.Unity.Editors } else { - return EditorGUIUtility.singleLineHeight; + return OneLineHeight; } } - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + + protected override void DrawCustom(Rect position, SerializedProperty property, GUIContent label) { Rect selButtnoRect = position; - selButtnoRect.height = EditorGUIUtility.singleLineHeight; + selButtnoRect.height = OneLineHeight; DrawSelectionPopup(selButtnoRect, property, label); if (property.managedReferenceValue != null) @@ -283,41 +60,9 @@ namespace DCFApixels.DragonECS.Unity.Editors private void DrawSelectionPopup(Rect position, SerializedProperty property, GUIContent label) { - Rect buttonRect = RectUtility.AddPadding(position, EditorGUIUtility.labelWidth, 0f, 0f, 0f); - object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue; - if (GUI.Button(buttonRect, obj == null ? "Select..." : obj.GetMeta().Name, EditorStyles.layerMaskField)) - { - currentProperty = property; - if (TargetAttribute.predicateTypes.Length == 0) - { - GetReferenceDropDown(new Type[1] { fieldInfo.FieldType }).Show(buttonRect); - } - else - { - GetReferenceDropDown(TargetAttribute.predicateTypes).Show(buttonRect); - } - } + Rect buttonRect = position.AddPadding(EditorGUIUtility.labelWidth, 0f, 0f, 0f); + EcsGUI.DrawSelectReferenceButton(buttonRect, property, Attribute.PredicateTypes.Length == 0 ? new Type[1] { fieldInfo.FieldType } : Attribute.PredicateTypes, Attribute.IsHideButtonIfNotNull); } } } -#endif - - -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)] -[System.Serializable] public class TestSystem0 : IEcsProcess { } -[System.Serializable] public class TestSystem1 : IEcsProcess { } -[System.Serializable] public class TestSystem2 : IEcsProcess { } -[System.Serializable] public class TestSystem3 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP)] -[System.Serializable] public class TestSystem4 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP)] -[System.Serializable] public class TestSystem7 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)] -[System.Serializable] public class TestSystem8 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)] -[System.Serializable] public class _TestSystemX : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)] -[System.Serializable] public class TestSystem9 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.AUTHOR)] -[System.Serializable] public class TestSystem5 : IEcsProcess { } -[System.Serializable] public class TestSystem6 : IEcsProcess { } \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs b/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs index 02211c2..6603056 100644 --- a/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -23,30 +23,23 @@ namespace DCFApixels.DragonECS.Unity.Editors } } [CustomPropertyDrawer(typeof(ComponentTemplateReferenceAttribute), true)] - internal class ComponentTemplateReferenceDrawer : PropertyDrawer + internal class ComponentTemplateReferenceDrawer : ExtendedPropertyDrawer { - private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); - - private float Padding => EditorGUIUtility.standardVerticalSpacing; - private float SingleLineWithPadding => EditorGUIUtility.singleLineHeight + Padding * 4f; - private const float DamagedComponentHeight = 18f * 2f; - - private static bool _isInit; + private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); private static ComponentDropDown _componentDropDown; + private float SingleLineWithPadding => OneLineHeight + Padding * 4f; + private float Padding => Spacing; + protected override bool IsInit => _componentDropDown != null; + #region Init - private static void Init() + protected override void OnStaticInit() { - if (_componentDropDown == null) { _isInit = false; } - if (_isInit) { return; } - _componentDropDown = new ComponentDropDown(); - _componentDropDown.OnSelected += SelectComponent; - - _isInit = true; } + [ThreadStatic] private static SerializedProperty currentProperty; private static void SelectComponent(ComponentDropDown.Item item) @@ -93,8 +86,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } - - public override void OnGUI(Rect position, SerializedProperty componentRefProp, GUIContent label) + protected override void DrawCustom(Rect position, SerializedProperty componentRefProp, GUIContent label) { if (componentRefProp.propertyType == SerializedPropertyType.ManagedReference == false) { diff --git a/src/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/EntityTemplate/Editor/EntityTemplateEditor.cs index 4e0f724..16e9e87 100644 --- a/src/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -7,12 +7,11 @@ using UnityEngine; namespace DCFApixels.DragonECS.Unity.Editors { - internal abstract class EntityTemplateEditorBase : Editor + internal abstract class EntityTemplateEditorBase : ExtendedEditor { private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); private ComponentDropDown _componentDropDown; - private bool _isInit = false; private static ComponentColorMode AutoColorMode { @@ -21,16 +20,11 @@ namespace DCFApixels.DragonECS.Unity.Editors } #region Init - private void Init() + protected override bool IsInit => _componentDropDown != null; + protected override void OnInit() { - if (_componentDropDown == null) { _isInit = false; } - if (_isInit) { return; } - _componentDropDown = new ComponentDropDown(); - _componentDropDown.OnSelected += OnAddComponent; - - _isInit = true; } #endregion @@ -167,60 +161,65 @@ namespace DCFApixels.DragonECS.Unity.Editors optionButton.center += Vector2.up * padding * 2f; bool cancelExpanded = EcsGUI.HitTest(optionButton) && Event.current.type == EventType.MouseUp; - EditorGUI.BeginChangeCheck(); - GUILayout.BeginVertical(UnityEditorUtility.GetStyle(alphaPanelColor)); + using (EcsGUI.CheckChanged()) + { + //EditorGUI.BeginChangeCheck(); - #region Draw Component Block - //Close button - optionButton.xMin = optionButton.xMax - HeadIconsRect.width; - if (EcsGUI.CloseButton(optionButton)) - { - OnRemoveComponentAt(index); - return; - } - //Canceling isExpanded - if (cancelExpanded) - { - componentProperty.isExpanded = !componentProperty.isExpanded; - } - //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(componentType, out MonoScript script)) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - EcsGUI.ScriptAssetButton(optionButton, script); - } - //Description icon - if (string.IsNullOrEmpty(description) == false) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - EcsGUI.DescriptionIcon(optionButton, description); - } + GUILayout.BeginVertical(UnityEditorUtility.GetStyle(alphaPanelColor)); - if (propCount <= 0) - { - EcsGUI.Layout.DrawEmptyComponentProperty(componentRefProp, name, isEmpty); - } - else - { - GUIContent label = UnityEditorUtility.GetLabel(name); - if (componentProperty.propertyType == SerializedPropertyType.Generic) + #region Draw Component Block + //Close button + optionButton.xMin = optionButton.xMax - HeadIconsRect.width; + if (EcsGUI.CloseButton(optionButton)) { - EditorGUILayout.PropertyField(componentProperty, label, true); + OnRemoveComponentAt(index); + return; + } + //Canceling isExpanded + if (cancelExpanded) + { + componentProperty.isExpanded = !componentProperty.isExpanded; + } + //Edit script button + if (UnityEditorUtility.TryGetScriptAsset(componentType, out MonoScript script)) + { + optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.ScriptAssetButton(optionButton, script); + } + //Description icon + if (string.IsNullOrEmpty(description) == false) + { + optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + EcsGUI.DescriptionIcon(optionButton, description); + } + + if (propCount <= 0) + { + EcsGUI.Layout.DrawEmptyComponentProperty(componentRefProp, name, isEmpty); } else { - Rect r = RectUtility.AddPadding(GUILayoutUtility.GetRect(label, EditorStyles.objectField), 0, 20f, 0, 0); - EditorGUI.PropertyField(r, componentProperty, label, true); + GUIContent label = UnityEditorUtility.GetLabel(name); + if (componentProperty.propertyType == SerializedPropertyType.Generic) + { + EditorGUILayout.PropertyField(componentProperty, label, true); + } + else + { + Rect r = RectUtility.AddPadding(GUILayoutUtility.GetRect(label, EditorStyles.objectField), 0, 20f, 0, 0); + EditorGUI.PropertyField(r, componentProperty, label, true); + } } - } - #endregion + #endregion - GUILayout.EndVertical(); + GUILayout.EndVertical(); - if (EditorGUI.EndChangeCheck()) - { - componentProperty.serializedObject.ApplyModifiedProperties(); - EditorUtility.SetDirty(componentProperty.serializedObject.targetObject); + //if (EditorGUI.EndChangeCheck()) + if (EcsGUI.Changed) + { + componentProperty.serializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(componentProperty.serializedObject.targetObject); + } } } private void DrawDamagedComponent_Replaced(SerializedProperty componentRefProp, int index) @@ -254,19 +253,19 @@ namespace DCFApixels.DragonECS.Unity.Editors } [CustomEditor(typeof(ScriptableEntityTemplate), true)] - internal class EntityTemplatePresetEditor : EntityTemplateEditorBase + internal class EntityTemplatePresetEditor : EntityTemplateEditorBase { - public override void OnInspectorGUI() + protected override void DrawCustom() { - Draw((ITemplateInternal)target); + Draw(Target); } } [CustomEditor(typeof(MonoEntityTemplate), true)] - internal class EntityTemplateEditor : EntityTemplateEditorBase + internal class EntityTemplateEditor : EntityTemplateEditorBase { - public override void OnInspectorGUI() + protected override void DrawCustom() { - Draw((ITemplateInternal)target); + Draw(Target); } } } diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index a86b560..8c0d30e 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -1,8 +1,11 @@ #if UNITY_EDITOR using DCFApixels.DragonECS.Unity.Internal; using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using UnityEditor; +using UnityEditor.IMGUI.Controls; using UnityEngine; using UnityComponent = UnityEngine.Component; using UnityObject = UnityEngine.Object; @@ -14,6 +17,7 @@ namespace DCFApixels.DragonECS.Unity.Editors #region Scores private static int _changedCounter = 0; private static bool _changed = false; + private static bool _delayedChanged = false; public static int ChangedCounter => _changedCounter; public static bool Changed @@ -21,14 +25,27 @@ namespace DCFApixels.DragonECS.Unity.Editors get { _changed = _changed || GUI.changed; + GUI.changed = _changed; return _changed; } set { - _changed = _changed || GUI.changed || value; + _changed = Changed || value; GUI.changed = _changed; } } + public static bool DelayedChanged + { + get + { + return _delayedChanged; + } + set + { + _delayedChanged = DelayedChanged || value; + Changed = _delayedChanged; + } + } public readonly struct CheckChangedScope : IDisposable { private readonly bool _value; @@ -47,25 +64,33 @@ namespace DCFApixels.DragonECS.Unity.Editors if (_changedCounter <= 0) { _changedCounter = 0; - _changed = false; + _changed = _delayedChanged; + _delayedChanged = false; } } } - - public struct VerticalLayoutScope : IDisposable + public readonly struct CheckChangedScopeWithAutoApply : IDisposable { - public static VerticalLayoutScope New() { GUILayout.BeginVertical(); return new VerticalLayoutScope(); } - public void Dispose() { GUILayout.EndVertical(); } + private readonly CheckChangedScope _scope; + private readonly SerializedObject _serializedObject; + public CheckChangedScopeWithAutoApply(SerializedObject serializedObject) + { + _scope = CheckChangedScope.New(); + _serializedObject = serializedObject; + } + public void Dispose() + { + if (Changed) + { + _serializedObject.ApplyModifiedProperties(); + } + _scope.Dispose(); + } } - public struct HorizontalLayoutScope : IDisposable + public struct ScrollViewScope : IDisposable { - public static HorizontalLayoutScope New() { GUILayout.BeginVertical(); return new HorizontalLayoutScope(); } - public void Dispose() { GUILayout.EndVertical(); } - } - public struct ScrollViewLayoutScope : IDisposable - { - public ScrollViewLayoutScope(ref Vector2 pos) { pos = GUILayout.BeginScrollView(pos); } - public void Dispose() { GUILayout.EndScrollView(); } + public ScrollViewScope(Rect position, ref Vector2 pos, Rect viewRect) { pos = GUI.BeginScrollView(position, pos, viewRect); } + public void Dispose() { GUI.EndScrollView(); } } public readonly struct LabelWidthScope : IDisposable { @@ -172,10 +197,41 @@ namespace DCFApixels.DragonECS.Unity.Editors public void Dispose() { Target.fontStyle = _value; } } + + public static partial class Layout + { + public struct VerticalScope : IDisposable + { + public VerticalScope(GUILayoutOption[] options) { GUILayout.BeginVertical(options); } + public VerticalScope(GUIStyle style, GUILayoutOption[] options) { GUILayout.BeginVertical(style, options); } + public void Dispose() { GUILayout.EndVertical(); } + } + public struct HorizontalScope : IDisposable + { + public HorizontalScope(GUILayoutOption[] options) { GUILayout.BeginHorizontal(options); } + public HorizontalScope(GUIStyle style, GUILayoutOption[] options) { GUILayout.BeginHorizontal(style, options); } + public void Dispose() { GUILayout.EndHorizontal(); } + } + public struct ScrollViewScope : IDisposable + { + public ScrollViewScope(ref Vector2 pos, GUILayoutOption[] options) { pos = GUILayout.BeginScrollView(pos, options); } + public ScrollViewScope(ref Vector2 pos, GUIStyle style, GUILayoutOption[] options) { pos = GUILayout.BeginScrollView(pos, style, options); } + public void Dispose() { GUILayout.EndScrollView(); } + } + + public static ScrollViewScope BeginScrollView(ref Vector2 pos) => new ScrollViewScope(ref pos, Array.Empty()); + public static HorizontalScope BeginHorizontal() => new HorizontalScope(Array.Empty()); + public static VerticalScope BeginVertical() => new VerticalScope(Array.Empty()); + public static ScrollViewScope BeginScrollView(ref Vector2 pos, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, options); + public static HorizontalScope BeginHorizontal(params GUILayoutOption[] options) => new HorizontalScope(options); + public static VerticalScope BeginVertical(params GUILayoutOption[] options) => new VerticalScope(options); + public static ScrollViewScope BeginScrollView(ref Vector2 pos, GUIStyle style, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, style, options); + public static HorizontalScope BeginHorizontal(GUIStyle style, params GUILayoutOption[] options) => new HorizontalScope(style, options); + public static VerticalScope BeginVertical(GUIStyle style, params GUILayoutOption[] options) => new VerticalScope(style, options); + } public static CheckChangedScope CheckChanged() => CheckChangedScope.New(); - public static ScrollViewLayoutScope SetScrollViewLayout(ref Vector2 pos) => new ScrollViewLayoutScope(ref pos); - public static HorizontalLayoutScope SetHorizontalLayout() => HorizontalLayoutScope.New(); - public static VerticalLayoutScope SetVerticalLayout() => VerticalLayoutScope.New(); + public static CheckChangedScopeWithAutoApply CheckChanged(SerializedObject serializedObject) => new CheckChangedScopeWithAutoApply(serializedObject); + public static ScrollViewScope BeginScrollView(Rect position, ref Vector2 pos, Rect viewRect) => new ScrollViewScope(position, ref pos, viewRect); public static FontStyleScope SetFontStyle(GUIStyle target, FontStyle value) => new FontStyleScope(target, value); public static FontStyleScope SetFontStyle(FontStyle value) => new FontStyleScope(GUI.skin.label, value); public static FontStyleScope SetFontStyle(GUIStyle target) => new FontStyleScope(target); @@ -196,6 +252,7 @@ namespace DCFApixels.DragonECS.Unity.Editors public static EditorGUI.DisabledScope Enable => new EditorGUI.DisabledScope(false); public static EditorGUI.DisabledScope Disable => new EditorGUI.DisabledScope(true); public static EditorGUI.DisabledScope SetEnable(bool value) => new EditorGUI.DisabledScope(!value); + public static LabelWidthScope SetLabelWidth(float value) => new LabelWidthScope(value); #endregion private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; @@ -208,6 +265,28 @@ namespace DCFApixels.DragonECS.Unity.Editors public static float EntityBarHeight => EditorGUIUtility.singleLineHeight + 3f; + private static Type[] _serializableTypes; + + + static EcsGUI() + { + InitSerializableTypes(); + } + private static void InitSerializableTypes() + { + List types = new List(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + var targetTypes = assembly.GetTypes().Where(type => + (type.IsGenericType || type.IsAbstract || type.IsInterface) == false && + type.IsSubclassOf(typeof(UnityObject)) == false && + type.GetCustomAttribute() != null); + + types.AddRange(targetTypes); + } + _serializableTypes = types.ToArray(); + } + #region Properties private static ComponentColorMode AutoColorMode { @@ -224,6 +303,14 @@ namespace DCFApixels.DragonECS.Unity.Editors get { return SettingsPrefs.instance.IsShowRuntimeComponents; } set { SettingsPrefs.instance.IsShowRuntimeComponents = value; } } + private static float OneLineHeight + { + get => EditorGUIUtility.singleLineHeight; + } + private static float Spacing + { + get => EditorGUIUtility.standardVerticalSpacing; + } #endregion #region enums @@ -379,7 +466,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } public static void EntityBar(Rect position, bool isPlaceholder, EntityStatus status, int id = 0, short gen = 0, short world = 0) { - using (new LabelWidthScope(0f)) + using (SetLabelWidth(0f)) { var (entityInfoRect, statusRect) = RectUtility.VerticalSliceBottom(position, 3f); @@ -405,7 +492,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } private static void EntityBar_Internal(Rect position, bool isPlaceHolder, int id = 0, short gen = 0, short world = 0) { - using (new LabelWidthScope(0f)) + using (SetLabelWidth(0f)) { Color w = Color.gray; w.a = 0.6f; @@ -451,11 +538,11 @@ namespace DCFApixels.DragonECS.Unity.Editors { return DrawTypeMetaBlockPadding * 2 + contentHeight; } - public static void DrawTypeMetaBlock(ref Rect position, SerializedProperty property, ITypeMeta meta) + public static bool DrawTypeMetaBlock(ref Rect position, SerializedProperty property, ITypeMeta meta) { if (meta == null) { - return; + return false; } GUIContent label = UnityEditorUtility.GetLabel(property.displayName); @@ -483,56 +570,58 @@ namespace DCFApixels.DragonECS.Unity.Editors Color alphaPanelColor = panelColor; alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA; - - EditorGUI.BeginChangeCheck(); - EditorGUI.DrawRect(position, alphaPanelColor); - - Rect paddingPosition = RectUtility.AddPadding(position, DrawTypeMetaBlockPadding * 2f); - - Rect optionButton = position; - optionButton.center -= new Vector2(0, optionButton.height); - optionButton.yMin = optionButton.yMax; - optionButton.yMax += HeadIconsRect.height; - optionButton.xMin = optionButton.xMax - 64; - optionButton.center += Vector2.up * DrawTypeMetaBlockPadding * 1f; - //Canceling isExpanded - if (HitTest(optionButton) && Event.current.type == EventType.MouseUp) + using (CheckChanged()) { - property.isExpanded = !property.isExpanded; - } + EditorGUI.DrawRect(position, alphaPanelColor); - //Close button - optionButton.xMin = optionButton.xMax - HeadIconsRect.width; - if (CloseButton(optionButton)) - { - property.ResetValues(); - return; - } - //Edit script button - if (UnityEditorUtility.TryGetScriptAsset(meta.Type, out MonoScript script)) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - ScriptAssetButton(optionButton, script); - } - //Description icon - if (string.IsNullOrEmpty(description) == false) - { - optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); - DescriptionIcon(optionButton, description); - } + Rect paddingPosition = RectUtility.AddPadding(position, DrawTypeMetaBlockPadding * 2f); - //if (string.IsNullOrEmpty(label.text)) - //{ - // EditorGUI.indentLevel++; - // EditorGUI.PrefixLabel(position.AddPadding(0, 0, 0, position.height - SingleLineWithPadding), UnityEditorUtility.GetLabel(name)); - // EditorGUI.indentLevel--; - //} - //else - //{ - // GUI.Label(position.AddPadding(EditorGUIUtility.labelWidth, 0, 0, position.height - SingleLineWithPadding), name); - //} + Rect optionButton = position; + optionButton.center -= new Vector2(0, optionButton.height); + optionButton.yMin = optionButton.yMax; + optionButton.yMax += HeadIconsRect.height; + optionButton.xMin = optionButton.xMax - 64; + optionButton.center += Vector2.up * DrawTypeMetaBlockPadding * 1f; + //Canceling isExpanded + if (HitTest(optionButton) && Event.current.type == EventType.MouseUp) + { + property.isExpanded = !property.isExpanded; + } - position = paddingPosition; + //Close button + optionButton.xMin = optionButton.xMax - HeadIconsRect.width; + if (CloseButton(optionButton)) + { + property.ResetValues(); + return true; + } + //Edit script button + if (UnityEditorUtility.TryGetScriptAsset(meta.Type, out MonoScript script)) + { + optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + ScriptAssetButton(optionButton, script); + } + //Description icon + if (string.IsNullOrEmpty(description) == false) + { + optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width)); + DescriptionIcon(optionButton, description); + } + + //if (string.IsNullOrEmpty(label.text)) + //{ + // EditorGUI.indentLevel++; + // EditorGUI.PrefixLabel(position.AddPadding(0, 0, 0, position.height - SingleLineWithPadding), UnityEditorUtility.GetLabel(name)); + // EditorGUI.indentLevel--; + //} + //else + //{ + // GUI.Label(position.AddPadding(EditorGUIUtility.labelWidth, 0, 0, position.height - SingleLineWithPadding), name); + //} + + position = paddingPosition; + } + return false; } #endregion @@ -647,7 +736,220 @@ namespace DCFApixels.DragonECS.Unity.Editors } #endregion - #region SerializeReferenceFixer + #region SerializeReference utils + + private static Dictionary _predicatTypesMenus = new Dictionary(); + [ThreadStatic] + private static SerializedProperty _currentProperty; + + #region Init + private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes) + { + if (_predicatTypesMenus.TryGetValue(predicatTypes, out ReferenceDropDown menu) == false) + { + menu = new ReferenceDropDown(predicatTypes); + menu.OnSelected += SelectComponent; + _predicatTypesMenus.Add(predicatTypes, menu); + } + + return menu; + } + private static void SelectComponent(ReferenceDropDown.Item item) + { + Type type = item.Type; + if (type == null) + { + _currentProperty.managedReferenceValue = null; + } + else + { + _currentProperty.managedReferenceValue = Activator.CreateInstance(type); + _currentProperty.isExpanded = true; + } + + _currentProperty.serializedObject.ApplyModifiedProperties(); + DelayedChanged = true; + } + #endregion + + #region PredicateTypesKey + private readonly struct PredicateTypesKey : IEquatable + { + public readonly Type[] types; + public PredicateTypesKey(Type[] types) + { + this.types = types; + } + public bool Equals(PredicateTypesKey other) + { + if (types.Length != other.types.Length) { return false; } + for (int i = 0; i < types.Length; i++) + { + if (types[i] != other.types[i]) + { + return false; + } + } + return true; + } + public override bool Equals(object obj) + { + return obj is PredicateTypesKey key && Equals(key); + } + public override int GetHashCode() + { + return HashCode.Combine(types); + } + public static implicit operator PredicateTypesKey(Type[] types) { return new PredicateTypesKey(types); } + public static implicit operator Type[](PredicateTypesKey key) { return key.types; } + } + #endregion + + #region ReferenceDropDown + private class ReferenceDropDown : AdvancedDropdown + { + public readonly Type[] PredicateTypes; + public ReferenceDropDown(Type[] predicateTypes) : base(new AdvancedDropdownState()) + { + PredicateTypes = predicateTypes; + minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30); + } + protected override AdvancedDropdownItem BuildRoot() + { + int increment = 0; + var root = new Item(null, "Select Type", increment++); + root.AddChild(new Item(null, "", increment++)); + + Dictionary dict = new Dictionary(); + + foreach (var type in _serializableTypes) + { + bool isAssignable = false; + foreach (Type predicateTypes in PredicateTypes) + { + if (predicateTypes.IsAssignableFrom(type)) + { + isAssignable = true; + break; + } + } + if (isAssignable) + { + ITypeMeta meta = type.ToMeta(); + string description = meta.Description.Text; + MetaGroup group = meta.Group; + var splitedGroup = group.Splited; + + Item parent = root; + if (splitedGroup.Count > 0) + { + int i = 1; + foreach (var subgroup in splitedGroup) + { + Key key = new Key(group, i); + if (dict.TryGetValue(key, out Item item) == false) + { + item = new Item(null, subgroup, increment++); + parent.AddChild(item); + dict.Add(key, item); + } + parent = item; + i++; + } + } + + var leafItem = new Item(type, meta.Name, increment++); + parent.AddChild(leafItem); + } + } + return root; + } + + protected override void ItemSelected(AdvancedDropdownItem item) + { + base.ItemSelected(item); + OnSelected((Item)item); + } + + public event Action OnSelected = delegate { }; + + public class Item : AdvancedDropdownItem + { + public readonly Type Type; + public Item(Type type, string name, int id) : base(name) + { + Type = type; + this.id = id; + } + } + + #region Key + private readonly struct Key : IEquatable + { + public readonly MetaGroup Group; + public readonly int Length; + public Key(MetaGroup group, int length) + { + Group = group; + Length = length; + } + public bool Equals(Key other) + { + if (Length != other.Length) + { + return false; + } + IEnumerator splitedEnum = Group.Splited.GetEnumerator(); + IEnumerator splitedEnumOther = other.Group.Splited.GetEnumerator(); + for (int i = 0; i < Length; i++) + { + splitedEnum.MoveNext(); + splitedEnumOther.MoveNext(); + if (splitedEnum.Current != splitedEnumOther.Current) + { + return false; + } + } + return true; + } + public override bool Equals(object obj) + { + return obj is Key key && Equals(key); + } + public override int GetHashCode() + { + unchecked + { + int state = Length; + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + var x = Group.Splited.GetEnumerator(); + x.MoveNext(); + return x.Current.GetHashCode() ^ state; + }; + } + } + #endregion + } + #endregion + + public static void DrawSelectReferenceButton(Rect position, SerializedProperty property, Type[] sortedPredicateTypes, bool isHideButtonIfNotNull) + { + object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue; + if (!isHideButtonIfNotNull || obj == null) + { + if (GUI.Button(position, obj == null ? "Select..." : obj.GetMeta().Name, EditorStyles.layerMaskField)) + { + _currentProperty = property; + GetReferenceDropDown(sortedPredicateTypes).Show(position); + } + } + else + { + GUI.Label(position, obj == null ? "Select..." : obj.GetMeta().Name); + } + } #endregion @@ -656,7 +958,7 @@ namespace DCFApixels.DragonECS.Unity.Editors - public static class Layout + public static partial class Layout { public static void ScriptAssetButton(MonoScript script, params GUILayoutOption[] options) { @@ -934,4 +1236,4 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } -#endif +#endif \ No newline at end of file diff --git a/src/Internal/Editor/ExtendedEditor.cs b/src/Internal/Editor/ExtendedEditor.cs index 1a5e434..3be3c1d 100644 --- a/src/Internal/Editor/ExtendedEditor.cs +++ b/src/Internal/Editor/ExtendedEditor.cs @@ -25,7 +25,7 @@ namespace DCFApixels.DragonECS.Unity.Editors private bool _isStaticInit = false; private bool _isInit = false; - protected float SingleLineHeight + protected float OneLineHeight { get => EditorGUIUtility.singleLineHeight; } @@ -33,6 +33,17 @@ namespace DCFApixels.DragonECS.Unity.Editors { get => EditorGUIUtility.standardVerticalSpacing; } + protected bool IsShowInterfaces + { + get { return SettingsPrefs.instance.IsShowInterfaces; } + set { SettingsPrefs.instance.IsShowInterfaces = value; } + } + protected bool IsShowHidden + { + get { return SettingsPrefs.instance.IsShowHidden; } + set { SettingsPrefs.instance.IsShowHidden = value; } + } + protected bool IsMultipleTargets => targets.Length > 1; protected virtual bool IsStaticInit { get { return _isStaticInit; } } protected virtual bool IsInit { get { return _isInit; } } @@ -53,7 +64,7 @@ namespace DCFApixels.DragonECS.Unity.Editors public sealed override void OnInspectorGUI() { - using (EcsGUI.CheckChanged()) + using (EcsGUI.CheckChanged(serializedObject)) { StaticInit(); Init(); @@ -73,7 +84,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return serializedObject.FindProperty(name); } } - internal abstract class ExtendedEditor : ExtendedEditor where T : UnityObject + internal abstract class ExtendedEditor : ExtendedEditor { public T Target @@ -132,7 +143,16 @@ namespace DCFApixels.DragonECS.Unity.Editors { get => EditorGUIUtility.standardVerticalSpacing; } - + protected bool IsShowInterfaces + { + get { return SettingsPrefs.instance.IsShowInterfaces; } + set { SettingsPrefs.instance.IsShowInterfaces = value; } + } + protected bool IsShowHidden + { + get { return SettingsPrefs.instance.IsShowHidden; } + set { SettingsPrefs.instance.IsShowHidden = value; } + } protected virtual bool IsStaticInit { get { return _isStaticInit; } } protected virtual bool IsInit { get { return _isInit; } } protected void StaticInit() @@ -152,7 +172,7 @@ namespace DCFApixels.DragonECS.Unity.Editors public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - using (EcsGUI.CheckChanged()) + using (EcsGUI.CheckChanged(property.serializedObject)) { StaticInit(); Init();