diff --git a/Editor/Toolbar/AbstractToolbarDrawer.cs b/Editor/Toolbar/AbstractToolbarDrawer.cs index 4297257..58b9256 100644 --- a/Editor/Toolbar/AbstractToolbarDrawer.cs +++ b/Editor/Toolbar/AbstractToolbarDrawer.cs @@ -1,12 +1,13 @@ -using Module.NavigationTool.Editor.Toolbar; -using UnityEngine; +using UnityEngine; -namespace Module.NavigationTool.Editor +namespace Module.NavigationTool.Editor.Toolbar { public abstract class AbstractToolbarDrawer { + public abstract bool Visible { get; } public abstract bool Enabled { get; } public abstract EToolbarPlacement Placement { get; } + public abstract int Priority { get; } private Rect rect; protected Styles styles; @@ -18,7 +19,6 @@ namespace Module.NavigationTool.Editor public virtual void Update() { - } public void OnGUI() diff --git a/Editor/Toolbar/Enums/EToolbarPlacement.cs b/Editor/Toolbar/Enums/EToolbarPlacement.cs index 8920448..dc4fbb0 100644 --- a/Editor/Toolbar/Enums/EToolbarPlacement.cs +++ b/Editor/Toolbar/Enums/EToolbarPlacement.cs @@ -1,4 +1,4 @@ -namespace Module.NavigationTool.Editor +namespace Module.NavigationTool.Editor.Toolbar { public enum EToolbarPlacement : byte { diff --git a/Editor/Toolbar/Enums/EToolbarPriority.cs b/Editor/Toolbar/Enums/EToolbarPriority.cs new file mode 100644 index 0000000..e1ec294 --- /dev/null +++ b/Editor/Toolbar/Enums/EToolbarPriority.cs @@ -0,0 +1,9 @@ +namespace Module.NavigationTool.Editor.Toolbar +{ + public enum EToolbarPriority + { + Low, + Medium = 1000, + High = 2000 + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Enums/EToolbarPriority.cs.meta b/Editor/Toolbar/Enums/EToolbarPriority.cs.meta new file mode 100644 index 0000000..1097826 --- /dev/null +++ b/Editor/Toolbar/Enums/EToolbarPriority.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5ae525e780674292add7f50aef822261 +timeCreated: 1639929153 \ No newline at end of file diff --git a/Editor/Toolbar/Settings.meta b/Editor/Toolbar/Settings.meta new file mode 100644 index 0000000..396db86 --- /dev/null +++ b/Editor/Toolbar/Settings.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7718853c1abb499a9fd06d686c3624ed +timeCreated: 1639924155 \ No newline at end of file diff --git a/Editor/Toolbar/Settings/ToolbarSettings.cs b/Editor/Toolbar/Settings/ToolbarSettings.cs new file mode 100644 index 0000000..84ed3e9 --- /dev/null +++ b/Editor/Toolbar/Settings/ToolbarSettings.cs @@ -0,0 +1,29 @@ +using UnityEditor; + +namespace Module.NavigationTool.Editor.Toolbar +{ + internal static class ToolbarSettings + { + private const string PREF_IS_UI_ENABLED = "ToolbarSettings_IsUiEnabled"; + private const string PREF_IS_UI_LAYER_ENABLED = "ToolbarSettings_IsUiLayerEnabled"; + private const string PREF_IS_SCENE_ENABLED = "ToolbarSettings_IsSceneEnabled"; + + public static bool IsUiEnabled + { + get => EditorPrefs.GetBool(PREF_IS_UI_ENABLED, true); + set => EditorPrefs.SetBool(PREF_IS_UI_ENABLED, value); + } + + public static bool IsUiLayerEnabled + { + get => EditorPrefs.GetBool(PREF_IS_UI_LAYER_ENABLED, true); + set => EditorPrefs.SetBool(PREF_IS_UI_LAYER_ENABLED, value); + } + + public static bool IsSceneEnabled + { + get => EditorPrefs.GetBool(PREF_IS_SCENE_ENABLED, true); + set => EditorPrefs.SetBool(PREF_IS_SCENE_ENABLED, value); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Settings/ToolbarSettings.cs.meta b/Editor/Toolbar/Settings/ToolbarSettings.cs.meta new file mode 100644 index 0000000..2a2843a --- /dev/null +++ b/Editor/Toolbar/Settings/ToolbarSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ee57c1a04c9448e585e7e524886bdeda +timeCreated: 1639924440 \ No newline at end of file diff --git a/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs b/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs new file mode 100644 index 0000000..4ac3265 --- /dev/null +++ b/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs @@ -0,0 +1,41 @@ +using UnityEditor; +using UnityEngine; + +namespace Module.NavigationTool.Editor.Toolbar +{ + internal static class ToolbarSettingsProvider + { + private static Styles STYLES; + + [SettingsProvider] + public static SettingsProvider GetProvider() + { + return new SettingsProvider("Module/Toolbar", SettingsScope.User) + { + label = "Toolbar", + keywords = new[] { "Scene", "UI", "Toolbar" }, + guiHandler = OnGui + }; + } + + private static void OnGui(string searchContext) + { + if (STYLES == null) + STYLES = new Styles(); + + STYLES.Initialize((GUI.skin)); + + EditorGUILayout.BeginVertical(STYLES.settingsGroup); + { + EditorGUILayout.LabelField("UI", EditorStyles.boldLabel); + ToolbarSettings.IsUiEnabled = EditorGUILayout.Toggle("Enable Canvas picker", ToolbarSettings.IsUiEnabled); + ToolbarSettings.IsUiLayerEnabled = EditorGUILayout.Toggle("Enable Layer toggle", ToolbarSettings.IsUiLayerEnabled); + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Scene", EditorStyles.boldLabel); + ToolbarSettings.IsSceneEnabled = EditorGUILayout.Toggle("Enable Scene picker", ToolbarSettings.IsSceneEnabled); + } + EditorGUILayout.EndVertical(); + } + } +} diff --git a/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs.meta b/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs.meta new file mode 100644 index 0000000..2cd6c21 --- /dev/null +++ b/Editor/Toolbar/Settings/ToolbarSettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7254a01fd35a8c5499c07751fbd7d6fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ToolbarDrawer.cs b/Editor/Toolbar/ToolbarDrawer.cs index 5b67aa0..e319c5e 100644 --- a/Editor/Toolbar/ToolbarDrawer.cs +++ b/Editor/Toolbar/ToolbarDrawer.cs @@ -1,18 +1,22 @@ -using Module.NavigationTool.Editor.Toolbar; -using UnityEditor; +using UnityEditor; using UnityEngine; #if UNITY_2021_1_OR_NEWER +using System.Collections.Generic; using UnityEngine.UIElements; #endif -namespace Module.NavigationTool.Editor +namespace Module.NavigationTool.Editor.Toolbar { [InitializeOnLoad] internal static class ToolbarDrawer { private static bool IS_INITIALIZED; private static AbstractToolbarDrawer[] DRAWERS; + + #if UNITY_2021_1_OR_NEWER + private static readonly Dictionary DICT_MAPPING = new Dictionary(); + #endif static ToolbarDrawer() { @@ -26,40 +30,93 @@ namespace Module.NavigationTool.Editor { DRAWERS = ToolbarUtility.GetAllDrawers(); - #if UNITY_2021_1_OR_NEWER - ToolbarUtility.OnUpdate(OnCreateElements); - #else + #if !UNITY_2021_1_OR_NEWER ToolbarUtility.AddGuiListener(OnGUI); #endif IS_INITIALIZED = true; } + + #if UNITY_2021_1_OR_NEWER + ToolbarUtility.OnUpdate(OnUpdateElements); + #endif for (var i = 0; i < DRAWERS.Length; i++) { - DRAWERS[i].Update(); + if (DRAWERS[i].Visible) + DRAWERS[i].Update(); } } #if UNITY_2021_1_OR_NEWER - private static void OnCreateElements(VisualElement leftAlign, VisualElement rightAlign) + private static void OnUpdateElements(VisualElement leftAlign, VisualElement rightAlign) { const float HEIGHT = 22.0f; + var added = false; for (int i = DRAWERS.Length - 1; i >= 0; i--) { AbstractToolbarDrawer drawer = DRAWERS[i]; - var rect = new Rect(0.0f, 0.0f, drawer.CalculateWidth(), HEIGHT); - drawer.Setup(rect); - - var container = new IMGUIContainer(drawer.OnGUI); - container.style.width = rect.width; + bool valid = CheckValidityOfContainer(drawer, leftAlign, rightAlign); - if (drawer.Placement == EToolbarPlacement.Left) - leftAlign.Add(container); - else - rightAlign.Add(container); + if (drawer.Visible && !valid) + { + var rect = new Rect(0.0f, 0.0f, drawer.CalculateWidth(), HEIGHT); + drawer.Setup(rect); + + var container = new ToolbarIMGUIContainer(drawer.OnGUI, drawer.Priority); + container.style.width = rect.width; + DICT_MAPPING.Add(drawer, container); + added = true; + + if (drawer.Placement == EToolbarPlacement.Left) + leftAlign.Add(container); + else + rightAlign.Add(container); + } + else if (!drawer.Visible && valid) + { + IMGUIContainer container = DICT_MAPPING[drawer]; + DICT_MAPPING.Remove(drawer); + container.RemoveFromHierarchy(); + } } + + if (added) + { + leftAlign.Sort(SortVisualElements); + rightAlign.Sort(SortVisualElements); + } + } + + private static bool CheckValidityOfContainer(AbstractToolbarDrawer drawer, VisualElement leftAlign, VisualElement rightAlign) + { + if (!DICT_MAPPING.TryGetValue(drawer, out IMGUIContainer container)) + return false; + + bool valid = drawer.Placement == EToolbarPlacement.Left + ? leftAlign.Contains(container) + : rightAlign.Contains(container); + + if (!valid) + DICT_MAPPING.Remove(drawer); + + return valid; + } + + private static int SortVisualElements(VisualElement ve0, VisualElement ve1) + { + var c0 = ve0 as ToolbarIMGUIContainer; + var c1 = ve1 as ToolbarIMGUIContainer; + + if (c0 == null && c1 == null) + return 0; + if (c0 == null) + return -1; + if (c1 == null) + return 1; + + return c0.Priority.CompareTo(c1.Priority); } #else private static void OnGUI() @@ -80,6 +137,9 @@ namespace Module.NavigationTool.Editor { AbstractToolbarDrawer drawer = DRAWERS[i]; + if (!drawer.Visible) + continue; + GUI.enabled = drawer.Enabled; float width = drawer.CalculateWidth(); diff --git a/Editor/Toolbar/Tools/ToolScenePicker.cs b/Editor/Toolbar/Tools/ToolScenePicker.cs index ddab564..38bd0f0 100644 --- a/Editor/Toolbar/Tools/ToolScenePicker.cs +++ b/Editor/Toolbar/Tools/ToolScenePicker.cs @@ -6,13 +6,15 @@ using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; -namespace Module.NavigationTool.Editor.Tools +namespace Module.NavigationTool.Editor.Toolbar { [UsedImplicitly] internal sealed class ToolScenePicker : AbstractToolbarDrawer { + public override bool Visible => ToolbarSettings.IsSceneEnabled; public override bool Enabled => !EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode; public override EToolbarPlacement Placement => EToolbarPlacement.Right; + public override int Priority => (int)EToolbarPriority.Medium; private static bool IS_DIRTY = true; private static int SELECTED_INDEX = -1; diff --git a/Editor/Toolbar/Tools/ToolScenePickerEditorStateChanged.cs b/Editor/Toolbar/Tools/ToolScenePickerEditorStateChanged.cs index 0985590..672dc3e 100644 --- a/Editor/Toolbar/Tools/ToolScenePickerEditorStateChanged.cs +++ b/Editor/Toolbar/Tools/ToolScenePickerEditorStateChanged.cs @@ -1,5 +1,4 @@ -using Module.NavigationTool.Editor.Tools; -using UnityEditor; +using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; diff --git a/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs index 1d20529..041319f 100644 --- a/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs +++ b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs @@ -1,5 +1,4 @@ using System.Linq; -using Module.NavigationTool.Editor.Tools; using UnityEditor; namespace Module.NavigationTool.Editor.Toolbar diff --git a/Editor/Toolbar/Tools/ToolUICanvasPicker.cs b/Editor/Toolbar/Tools/ToolUICanvasPicker.cs index e0ecb2b..984ffef 100644 --- a/Editor/Toolbar/Tools/ToolUICanvasPicker.cs +++ b/Editor/Toolbar/Tools/ToolUICanvasPicker.cs @@ -11,13 +11,15 @@ using UnityEditor.SceneManagement; using UnityEditor.Experimental.SceneManagement; #endif -namespace Module.NavigationTool.Editor.Tools +namespace Module.NavigationTool.Editor.Toolbar { [UsedImplicitly] internal sealed class ToolUICanvasPicker : AbstractToolbarDrawer { + public override bool Visible => ToolbarSettings.IsUiEnabled; public override bool Enabled => (UTools.visibleLayers & (1 << LayerMask.NameToLayer("UI"))) != 0; public override EToolbarPlacement Placement => EToolbarPlacement.Left; + public override int Priority => (int)EToolbarPriority.Medium; private static bool IS_DIRTY = true; private static string[] OPTIONS = new string[0]; @@ -62,7 +64,8 @@ namespace Module.NavigationTool.Editor.Tools protected override void Draw(Rect rect) { - // Note: To fix an issue, where instantiated canvases wouldn't be detected, due to no events for canvas additions/removals exist in Unity API (at the moment) + // Note: To fix an issue, where instantiated canvases wouldn't be detected, due to no events for canvas + // additions/removals exist in Unity API (at the moment) if (Event.current.type == EventType.MouseDown) { IS_DIRTY = true; diff --git a/Editor/Toolbar/Tools/ToolUICanvasPickerEditorStateChanged.cs b/Editor/Toolbar/Tools/ToolUICanvasPickerEditorStateChanged.cs index 2061da8..3838c6b 100644 --- a/Editor/Toolbar/Tools/ToolUICanvasPickerEditorStateChanged.cs +++ b/Editor/Toolbar/Tools/ToolUICanvasPickerEditorStateChanged.cs @@ -1,5 +1,4 @@ -using Module.NavigationTool.Editor.Tools; -using UnityEditor; +using UnityEditor; using UnityEditor.Experimental.SceneManagement; using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; diff --git a/Editor/Toolbar/Tools/ToolUILayerToggle.cs b/Editor/Toolbar/Tools/ToolUILayerToggle.cs index 34a0aba..67432f8 100644 --- a/Editor/Toolbar/Tools/ToolUILayerToggle.cs +++ b/Editor/Toolbar/Tools/ToolUILayerToggle.cs @@ -3,13 +3,15 @@ using UnityEditor; using UnityEngine; using UTools = UnityEditor.Tools; -namespace Module.NavigationTool.Editor.Tools +namespace Module.NavigationTool.Editor.Toolbar { [UsedImplicitly] internal sealed class ToolUILayerToggle : AbstractToolbarDrawer { + public override bool Visible => ToolbarSettings.IsUiLayerEnabled; public override bool Enabled => true; public override EToolbarPlacement Placement => EToolbarPlacement.Left; + public override int Priority => (int)EToolbarPriority.Medium - 1; protected override void Draw(Rect rect) { diff --git a/Editor/Toolbar/Utilities/Styles.cs b/Editor/Toolbar/Utilities/Styles.cs index 27d168e..12a9bfd 100644 --- a/Editor/Toolbar/Utilities/Styles.cs +++ b/Editor/Toolbar/Utilities/Styles.cs @@ -9,7 +9,7 @@ namespace Module.NavigationTool.Editor.Toolbar public GUIStyle slider; public GUIStyle label; public GUIStyle labelCenter; - + public GUIStyle settingsGroup; private GUISkin skin; public void Initialize(GUISkin skin) @@ -24,6 +24,10 @@ namespace Module.NavigationTool.Editor.Toolbar label = skin.FindStyle("ToolbarLabel"); labelCenter = skin.FindStyle("ToolbarLabel"); labelCenter.alignment = TextAnchor.MiddleCenter; + settingsGroup = new GUIStyle + { + margin = new RectOffset(8, 0, 8, 0) + }; // Available: ToolbarBoldLabel, ToolbarBottom, ToolbarButtonLeft, ToolbarButtonRight, ToolbarDropDown, // ToolbarLabel, ToolbarTextField, ... diff --git a/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs b/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs new file mode 100644 index 0000000..d4d24ad --- /dev/null +++ b/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs @@ -0,0 +1,16 @@ +using System; +using UnityEngine.UIElements; + +namespace Module.NavigationTool.Editor.Toolbar +{ + internal sealed class ToolbarIMGUIContainer : IMGUIContainer + { + public int Priority { get; } + + public ToolbarIMGUIContainer(Action onGuiHandler, int priority) + : base(onGuiHandler) + { + Priority = priority; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs.meta b/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs.meta new file mode 100644 index 0000000..996aa7b --- /dev/null +++ b/Editor/Toolbar/Utilities/ToolbarIMGUIContainer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 33569aa7bb974bd19b2208063bd64e95 +timeCreated: 1639929711 \ No newline at end of file diff --git a/Editor/Toolbar/Utilities/ToolbarUtility.cs b/Editor/Toolbar/Utilities/ToolbarUtility.cs index 4897ee7..df6b0da 100644 --- a/Editor/Toolbar/Utilities/ToolbarUtility.cs +++ b/Editor/Toolbar/Utilities/ToolbarUtility.cs @@ -41,21 +41,26 @@ namespace Module.NavigationTool.Editor.Toolbar CURRENT_INSTANCE_ID = CURRENT_TOOLBAR.GetInstanceID(); } - if (CURRENT_TOOLBAR == null || CURRENT_PARENT_LEFT != null) + if (CURRENT_TOOLBAR == null) return; - CURRENT_PARENT_LEFT?.RemoveFromHierarchy(); - CURRENT_PARENT_RIGHT?.RemoveFromHierarchy(); + if (CURRENT_PARENT_LEFT == null) + { + CURRENT_PARENT_LEFT?.RemoveFromHierarchy(); + CURRENT_PARENT_RIGHT?.RemoveFromHierarchy(); - FieldInfo root = CURRENT_TOOLBAR.GetType().GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance); - object rawRoot = root?.GetValue(CURRENT_TOOLBAR); - var mRoot = rawRoot as VisualElement; + FieldInfo root = CURRENT_TOOLBAR.GetType().GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance); + object rawRoot = root?.GetValue(CURRENT_TOOLBAR); + var mRoot = rawRoot as VisualElement; - CURRENT_PARENT_LEFT = CreateParent(mRoot, "ToolbarZoneLeftAlign", true); - CURRENT_PARENT_RIGHT = CreateParent(mRoot, "ToolbarZoneRightAlign", false); - callback?.Invoke(CURRENT_PARENT_LEFT, CURRENT_PARENT_RIGHT); + CURRENT_PARENT_LEFT = CreateParent(mRoot, "ToolbarZoneLeftAlign", true); + CURRENT_PARENT_RIGHT = CreateParent(mRoot, "ToolbarZoneRightAlign", false); + } + + if (CURRENT_PARENT_LEFT != null) + callback?.Invoke(CURRENT_PARENT_LEFT, CURRENT_PARENT_RIGHT); } - + private static VisualElement CreateParent(VisualElement root, string query, bool isLeft) { VisualElement parent = root.Q(query); diff --git a/README.md b/README.md new file mode 100644 index 0000000..bde9241 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Description + +This module contains a few helpful editor tools, like favorites, history and some handy toolbar tools. + + +## Favorites + +An editor window, where you can pin folders and assets, so you can easily find the most used assets in your project. + + +## History + +An editor window, where the history of all selected assets are shown. An asset in the window can be selected to easy get back to previous selections. + + +## Toolbar + +Toolbars to the left and right of the play-buttons. Anything can be added, as long as it is supported by IMGUI. + + +### Default tools + +Three tools are available from start: + +* UI Layer: Toggle the UI layer on/off +* UI Canvas: Select and center the camera on any Canvases in the scene +* Scene: Load any scene in the project easily by using the dropdown + + +### Customization + +You can create your own toolbar extensions by extending `AbstractToolbarDrawer`. + +``` +internal sealed class MyCustomTool : AbstractToolbarDrawer +{ + public override bool Visible => true; + public override bool Enabled => true; + public override EToolbarPlacement Placement => EToolbarPlacement.Left; + public override int Priority => (int)EToolbarPriority.Medium; + + protected override void Draw(Rect rect) + { + // Use IMGUI methods for drawing + } + + public override float CalculateWidth() + { + // Default height for toolbar buttons is 30 + return 30.0f; + } +} +``` + +The four properties help define draw and enable state: + +* `Visible`: If it is visible in the toolbar +* `Enabled`: If it is enabled in the toolbar (`GUI.enabled`) +* `Placement`: If it is placed to the left or right of the play-buttons +* `Priority`: Sort order/priority, when drawing the tool \ No newline at end of file diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..1204d10 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ada1af04766a4dcbaba125af58ec4c71 +timeCreated: 1639942319 \ No newline at end of file diff --git a/package.json b/package.json index 7832f05..8f05763 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.module.navigationtool", - "version": "1.0.2", + "version": "1.1.0", "displayName": "Module.NavigationTool", "description": "Support for navigation tools, like favorites, history and toolbars", "unity": "2019.2",