From 96571bf45264c317fb4e4f2eb3616d98a1a7f970 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 12 Sep 2024 01:35:37 +0800 Subject: [PATCH] update popup --- .../ReferenceButtonAttribute.cs | 57 +----- .../Editor/ComponentTemplatePropertyDrawer.cs | 34 +--- .../Editor/EntityTemplateEditor.cs | 37 +--- .../Editor/MetaObjectsDropDown.cs | 171 ++++++++++++++++++ .../Editor/MetaObjectsDropDown.cs.meta | 11 ++ src/Internal/Editor/EcsGUI.cs | 26 +-- src/Internal/Editor/UnityEditorUtility.cs | 34 ++-- 7 files changed, 239 insertions(+), 131 deletions(-) create mode 100644 src/EntityTemplate/Editor/MetaObjectsDropDown.cs create mode 100644 src/EntityTemplate/Editor/MetaObjectsDropDown.cs.meta diff --git a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs index d032712..a8822cc 100644 --- a/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs +++ b/src/EcsPipelineTemplate/ReferenceButtonAttribute.cs @@ -70,6 +70,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } #endregion + #region ReferenceDropDown private class ReferenceDropDown : AdvancedDropdown { public readonly Type[] PredicateTypes; @@ -100,7 +101,6 @@ namespace DCFApixels.DragonECS.Unity.Editors if (isAssignable) { ITypeMeta meta = type.ToMeta(); - string name = meta.Name; string description = meta.Description.Text; MetaGroup group = meta.Group; var splitedGroup = group.Splited; @@ -123,7 +123,7 @@ namespace DCFApixels.DragonECS.Unity.Editors } } - var leafItem = new Item(type, name, increment++); + var leafItem = new Item(type, meta.Name, increment++); parent.AddChild(leafItem); } } @@ -165,7 +165,7 @@ namespace DCFApixels.DragonECS.Unity.Editors return false; } IEnumerator splitedEnum = Group.Splited.GetEnumerator(); - IEnumerator splitedEnumOther = Group.Splited.GetEnumerator(); + IEnumerator splitedEnumOther = other.Group.Splited.GetEnumerator(); for (int i = 0; i < Length; i++) { splitedEnum.MoveNext(); @@ -195,50 +195,9 @@ namespace DCFApixels.DragonECS.Unity.Editors }; } } - - //private readonly struct Key : IEquatable - //{ - // public readonly string FullName; - // public readonly int Length; - // public Key(string fullName, int length) - // { - // FullName = fullName; - // Length = length; - // } - // public bool Equals(Key other) - // { - // if (Length != other.Length) - // { - // return false; - // } - // for (int i = 0; i < Length; i++) - // { - // if (FullName[i] != other.FullName[i]) - // { - // 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; - // return FullName.GetHashCode() ^ state; - // }; - // } - //} #endregion - } + #endregion #region Init private static void Init() @@ -344,19 +303,19 @@ namespace DCFApixels.DragonECS.Unity.Editors [MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)] [System.Serializable] public class TestSystem0 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)] [System.Serializable] public class TestSystem1 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)] [System.Serializable] public class TestSystem2 : IEcsProcess { } -[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.SYSTEMS_GROUP)] [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)] +[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 diff --git a/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs b/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs index 9d611fd..02211c2 100644 --- a/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs +++ b/src/EntityTemplate/Editor/ComponentTemplatePropertyDrawer.cs @@ -33,47 +33,29 @@ namespace DCFApixels.DragonECS.Unity.Editors private const float DamagedComponentHeight = 18f * 2f; private static bool _isInit; - private static GenericMenu _genericMenu; + private static ComponentDropDown _componentDropDown; #region Init private static void Init() { - if (_genericMenu == null) { _isInit = false; } + if (_componentDropDown == null) { _isInit = false; } if (_isInit) { return; } - _genericMenu = new GenericMenu(); + _componentDropDown = new ComponentDropDown(); - var componentTemplateDummies = ComponentTemplateTypeCache.Dummies; - foreach (var dummy in componentTemplateDummies) - { - if (dummy.Type.GetCustomAttribute() == null) - { - Debug.LogWarning($"Type {dummy.Type.Name} does not have the [Serializable] attribute"); - continue; - } - ITypeMeta meta = dummy is ITypeMeta metaOverride ? metaOverride : dummy.Type.ToMeta(); - string name = meta.Name; - string description = meta.Description.Text; - MetaGroup group = meta.Group; - - if (group.Name.Length > 0) - { - name = group.Name + name; - } - - _genericMenu.AddItem(new GUIContent(name, description), false, SelectComponent, dummy); - } + _componentDropDown.OnSelected += SelectComponent; _isInit = true; } [ThreadStatic] private static SerializedProperty currentProperty; - private static void SelectComponent(object dummy) + private static void SelectComponent(ComponentDropDown.Item item) { - currentProperty.managedReferenceValue = ((IComponentTemplate)dummy).Clone(); + currentProperty.managedReferenceValue = item.Obj.Clone(); currentProperty.isExpanded = false; currentProperty.serializedObject.ApplyModifiedProperties(); } + #endregion public override float GetPropertyHeight(SerializedProperty property, GUIContent label) @@ -260,7 +242,7 @@ namespace DCFApixels.DragonECS.Unity.Editors if (GUI.Button(buttonRect, "Select")) { currentProperty = componentRefProp; - _genericMenu.ShowAsContext(); + _componentDropDown.Show(buttonRect); } } private void DrawDamagedComponent(Rect position, string message) diff --git a/src/EntityTemplate/Editor/EntityTemplateEditor.cs b/src/EntityTemplate/Editor/EntityTemplateEditor.cs index 661ac20..4e0f724 100644 --- a/src/EntityTemplate/Editor/EntityTemplateEditor.cs +++ b/src/EntityTemplate/Editor/EntityTemplateEditor.cs @@ -11,7 +11,7 @@ namespace DCFApixels.DragonECS.Unity.Editors { private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f); - private GenericMenu _genericMenu; + private ComponentDropDown _componentDropDown; private bool _isInit = false; private static ComponentColorMode AutoColorMode @@ -23,41 +23,22 @@ namespace DCFApixels.DragonECS.Unity.Editors #region Init private void Init() { - if (_genericMenu == null) { _isInit = false; } + if (_componentDropDown == null) { _isInit = false; } if (_isInit) { return; } - _genericMenu = new GenericMenu(); + _componentDropDown = new ComponentDropDown(); - var componentTemplateDummies = ComponentTemplateTypeCache.Dummies; - foreach (var dummy in componentTemplateDummies) - { - if (dummy.Type.GetCustomAttribute() == null) - { - Debug.LogWarning($"Type {dummy.Type.Name} does not have the [Serializable] attribute"); - continue; - } - ITypeMeta meta = dummy is ITypeMeta metaOverride ? metaOverride : dummy.Type.ToMeta(); - string name = meta.Name; - string description = meta.Description.Text; - MetaGroup group = meta.Group; - - if (group.Name.Length > 0) - { - name = group.Name + name; - } - - _genericMenu.AddItem(new GUIContent(name, description), false, OnAddComponent, dummy); - } + _componentDropDown.OnSelected += OnAddComponent; _isInit = true; } #endregion #region Add/Remove - private void OnAddComponent(object obj) + private void OnAddComponent(ComponentDropDown.Item item) { - Type componentType = obj.GetType(); - IComponentTemplate cmptmp = (IComponentTemplate)obj; + Type componentType = item.Obj.GetType(); + IComponentTemplate cmptmp = item.Obj; if (this.target is ITemplateInternal target) { SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName); @@ -112,11 +93,11 @@ namespace DCFApixels.DragonECS.Unity.Editors } private void DrawTop(ITemplateInternal target) { - switch (EcsGUI.Layout.AddClearComponentButtons()) + switch (EcsGUI.Layout.AddClearComponentButtons(out Rect rect)) { case EcsGUI.AddClearComponentButton.AddComponent: Init(); - _genericMenu.ShowAsContext(); + _componentDropDown.Show(rect); break; case EcsGUI.AddClearComponentButton.Clear: Init(); diff --git a/src/EntityTemplate/Editor/MetaObjectsDropDown.cs b/src/EntityTemplate/Editor/MetaObjectsDropDown.cs new file mode 100644 index 0000000..d4f6c8c --- /dev/null +++ b/src/EntityTemplate/Editor/MetaObjectsDropDown.cs @@ -0,0 +1,171 @@ +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.IMGUI.Controls; +using UnityEngine; + +namespace DCFApixels.DragonECS.Unity.Editors +{ + internal class ComponentDropDown : MetaObjectsDropDown + { + public ComponentDropDown() + { + IEnumerable<(IComponentTemplate, ITypeMeta)> itemMetaPairs = ComponentTemplateTypeCache.Dummies.ToArray().Select(dummy => + { + ITypeMeta meta; + if (dummy is IComponentTemplateWithMetaOverride withMetaOverride) + { + meta = withMetaOverride; + } + else + { + meta = dummy.Type.GetMeta(); + } + return (dummy, meta); + }); + Setup(itemMetaPairs); + } + } + internal class RuntimeComponentDropDown : MetaObjectsDropDown + { + public RuntimeComponentDropDown(IEnumerable pools) + { + IEnumerable<(IEcsPool, ITypeMeta)> itemMetaPairs = pools.Select(pool => + { + return (pool, (ITypeMeta)pool.ComponentType.GetMeta()); + }); + Setup(itemMetaPairs); + } + } + internal class MetaObjectsDropDown : AdvancedDropdown + { + private string _name; + private bool _isContainsNull; + private IEnumerable<(T, ITypeMeta)> _itemMetaPairs; + public MetaObjectsDropDown() : base(new AdvancedDropdownState()) + { + minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30); + + } + protected void Setup(IEnumerable<(T, ITypeMeta)> itemMetaPairs, string name = "Select Type", bool isContainsNull = true) + { + _name = name; + _isContainsNull = isContainsNull; + _itemMetaPairs = itemMetaPairs; + } + protected override AdvancedDropdownItem BuildRoot() + { + int increment = 0; + var root = new Item(default, _name, increment++); + + if (_isContainsNull) + { + root.AddChild(new Item(default, "", increment++)); + } + + Dictionary dict = new Dictionary(); + + foreach (var pair in _itemMetaPairs) + { + ITypeMeta meta = pair.Item2; + + 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(default, subgroup, increment++); + parent.AddChild(item); + dict.Add(key, item); + } + parent = item; + i++; + } + } + + var leafItem = new Item(pair.Item1, 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 T Obj; + public Item(T obj, string name, int id) : base(name) + { + Obj = obj; + 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 + } +} +#endif \ No newline at end of file diff --git a/src/EntityTemplate/Editor/MetaObjectsDropDown.cs.meta b/src/EntityTemplate/Editor/MetaObjectsDropDown.cs.meta new file mode 100644 index 0000000..808ba75 --- /dev/null +++ b/src/EntityTemplate/Editor/MetaObjectsDropDown.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be69cae0ab609f14783c21e187dab681 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Internal/Editor/EcsGUI.cs b/src/Internal/Editor/EcsGUI.cs index d106947..8320956 100644 --- a/src/Internal/Editor/EcsGUI.cs +++ b/src/Internal/Editor/EcsGUI.cs @@ -431,16 +431,18 @@ namespace DCFApixels.DragonECS.Unity.Editors } } } - public static bool AddComponentButtons(Rect position) + public static bool AddComponentButton(Rect position, out Rect dropDownRect) { - position = RectUtility.AddPadding(position, 20f, 20f, 12f, 2f); - return GUI.Button(position, "Add Component"); + dropDownRect = RectUtility.AddPadding(position, 20f, 20f, 12f, 2f); + return GUI.Button(dropDownRect, "Add Component"); } - public static AddClearComponentButton AddClearComponentButtons(Rect position) + public static AddClearComponentButton AddClearComponentButtons(Rect position, out Rect dropDownRect) { position = RectUtility.AddPadding(position, 20f, 20f, 12f, 2f); var (left, right) = RectUtility.HorizontalSliceLerp(position, 0.75f); + dropDownRect = left; + if (GUI.Button(left, "Add Component")) { return AddClearComponentButton.AddComponent; @@ -559,13 +561,13 @@ namespace DCFApixels.DragonECS.Unity.Editors } #endregion - public static bool AddComponentButtons() + public static bool AddComponentButtons(out Rect dropDownRect) { - return EcsGUI.AddComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f)); + return EcsGUI.AddComponentButton(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f), out dropDownRect); } - public static AddClearComponentButton AddClearComponentButtons() + public static AddClearComponentButton AddClearComponentButtons(out Rect dropDownRect) { - return EcsGUI.AddClearComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f)); + return EcsGUI.AddClearComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 36f), out dropDownRect); } public static void DrawRuntimeComponents(entlong entity, bool isWithFoldout = true) { @@ -587,11 +589,11 @@ namespace DCFApixels.DragonECS.Unity.Editors } if (isWithFoldout == false || IsShowRuntimeComponents) { - if (AddComponentButtons()) + if (AddComponentButtons(out Rect dropDownRect)) { - GenericMenu genericMenu = RuntimeComponentsUtility.GetAddComponentGenericMenu(world); + RuntimeComponentDropDown genericMenu = RuntimeComponentsUtility.GetAddComponentGenericMenu(world); RuntimeComponentsUtility.CurrentEntityID = entityID; - genericMenu.ShowAsContext(); + genericMenu.Show(dropDownRect); } GUILayout.Box("", UnityEditorUtility.GetStyle(GUI.color, 0.16f), GUILayout.ExpandWidth(true)); @@ -600,7 +602,7 @@ namespace DCFApixels.DragonECS.Unity.Editors int i = 0; foreach (var componentTypeID in componentTypeIDs) { - var pool = world.GetPoolInstance(componentTypeID); + var pool = world.FindPoolInstance(componentTypeID); { DrawRuntimeComponent(componentTypeIDs.Length, i++, entityID, pool); } diff --git a/src/Internal/Editor/UnityEditorUtility.cs b/src/Internal/Editor/UnityEditorUtility.cs index ded6920..d4f916b 100644 --- a/src/Internal/Editor/UnityEditorUtility.cs +++ b/src/Internal/Editor/UnityEditorUtility.cs @@ -1,6 +1,7 @@ using DCFApixels.DragonECS.Unity.Internal; using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; using System.Text; using UnityEditor; @@ -272,9 +273,9 @@ namespace DCFApixels.DragonECS.Unity.Editors { public struct WorldData { - public GenericMenu addComponentGenericMenu; + public RuntimeComponentDropDown addComponentGenericMenu; public int poolsCount; - public WorldData(GenericMenu addComponentGenericMenu, int poolsCount) + public WorldData(RuntimeComponentDropDown addComponentGenericMenu, int poolsCount) { this.addComponentGenericMenu = addComponentGenericMenu; this.poolsCount = poolsCount; @@ -283,7 +284,7 @@ namespace DCFApixels.DragonECS.Unity.Editors //world id private static Dictionary _worldDatas = new Dictionary(); - public static GenericMenu GetAddComponentGenericMenu(EcsWorld world) + public static RuntimeComponentDropDown GetAddComponentGenericMenu(EcsWorld world) { if (_worldDatas.TryGetValue(world, out WorldData data)) { @@ -305,20 +306,21 @@ namespace DCFApixels.DragonECS.Unity.Editors private static WorldData CreateWorldData(EcsWorld world) { - GenericMenu genericMenu = new GenericMenu(); + IEnumerable pools = world.AllPools.ToArray().Where(o => o.IsNullOrDummy() == false); + RuntimeComponentDropDown genericMenu = new RuntimeComponentDropDown(pools); - var pools = world.AllPools; - for (int i = 0; i < pools.Length; i++) - { - var pool = pools[i]; - if (pool.IsNullOrDummy()) - { - continue; - } - var meta = pool.ComponentType.ToMeta(); - string name = meta.Group.Name + meta.Name; - genericMenu.AddItem(new GUIContent(name, meta.Description.Text), false, OnAddComponent, pool); - } + //var pools = world.AllPools; + //for (int i = 0; i < pools.Length; i++) + //{ + // var pool = pools[i]; + // if (pool.IsNullOrDummy()) + // { + // continue; + // } + // var meta = pool.ComponentType.ToMeta(); + // string name = meta.Group.Name + meta.Name; + // genericMenu.AddItem(new GUIContent(name, meta.Description.Text), false, OnAddComponent, pool); + //} return new WorldData(genericMenu, world.PoolsCount); }