From 27d7ecb2dd379047949576b830c00285bc14f3fc Mon Sep 17 00:00:00 2001 From: Anders Ejlersen Date: Thu, 11 Mar 2021 12:27:50 +0100 Subject: [PATCH] 0.5.0: Added toolbar with scene picker --- Editor/Toolbar.meta | 8 ++ Editor/Toolbar/Enums.meta | 3 + Editor/Toolbar/Enums/EToolbarPlacement.cs | 8 ++ .../Toolbar/Enums/EToolbarPlacement.cs.meta | 3 + Editor/Toolbar/IToolbarDrawer.cs | 16 ++++ Editor/Toolbar/IToolbarDrawer.cs.meta | 3 + Editor/Toolbar/ToolbarDrawer.cs | 78 +++++++++++++++++ Editor/Toolbar/ToolbarDrawer.cs.meta | 3 + Editor/Toolbar/Tools.meta | 3 + Editor/Toolbar/Tools/ToolScenePicker.cs | 77 +++++++++++++++++ Editor/Toolbar/Tools/ToolScenePicker.cs.meta | 3 + .../Tools/ToolScenePickerPostProcess.cs | 20 +++++ .../Tools/ToolScenePickerPostProcess.cs.meta | 3 + Editor/Toolbar/Utilities.meta | 8 ++ Editor/Toolbar/Utilities/Styles.cs | 27 ++++++ Editor/Toolbar/Utilities/Styles.cs.meta | 3 + Editor/Toolbar/Utilities/ToolbarUtility.cs | 84 +++++++++++++++++++ .../Toolbar/Utilities/ToolbarUtility.cs.meta | 11 +++ package.json | 7 +- 19 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 Editor/Toolbar.meta create mode 100644 Editor/Toolbar/Enums.meta create mode 100644 Editor/Toolbar/Enums/EToolbarPlacement.cs create mode 100644 Editor/Toolbar/Enums/EToolbarPlacement.cs.meta create mode 100644 Editor/Toolbar/IToolbarDrawer.cs create mode 100644 Editor/Toolbar/IToolbarDrawer.cs.meta create mode 100644 Editor/Toolbar/ToolbarDrawer.cs create mode 100644 Editor/Toolbar/ToolbarDrawer.cs.meta create mode 100644 Editor/Toolbar/Tools.meta create mode 100644 Editor/Toolbar/Tools/ToolScenePicker.cs create mode 100644 Editor/Toolbar/Tools/ToolScenePicker.cs.meta create mode 100644 Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs create mode 100644 Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs.meta create mode 100644 Editor/Toolbar/Utilities.meta create mode 100644 Editor/Toolbar/Utilities/Styles.cs create mode 100644 Editor/Toolbar/Utilities/Styles.cs.meta create mode 100644 Editor/Toolbar/Utilities/ToolbarUtility.cs create mode 100644 Editor/Toolbar/Utilities/ToolbarUtility.cs.meta diff --git a/Editor/Toolbar.meta b/Editor/Toolbar.meta new file mode 100644 index 0000000..5255caa --- /dev/null +++ b/Editor/Toolbar.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 797b16e835d4ed542bf7636d218e8323 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Enums.meta b/Editor/Toolbar/Enums.meta new file mode 100644 index 0000000..3c22871 --- /dev/null +++ b/Editor/Toolbar/Enums.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7539098b999c4b1fa6f8d0f8874ea7db +timeCreated: 1615452342 \ No newline at end of file diff --git a/Editor/Toolbar/Enums/EToolbarPlacement.cs b/Editor/Toolbar/Enums/EToolbarPlacement.cs new file mode 100644 index 0000000..01dfd96 --- /dev/null +++ b/Editor/Toolbar/Enums/EToolbarPlacement.cs @@ -0,0 +1,8 @@ +namespace Game.NavigationTool.Editor +{ + public enum EToolbarPlacement : byte + { + Left, + Right + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Enums/EToolbarPlacement.cs.meta b/Editor/Toolbar/Enums/EToolbarPlacement.cs.meta new file mode 100644 index 0000000..eb30cb8 --- /dev/null +++ b/Editor/Toolbar/Enums/EToolbarPlacement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c1fe5a408a5b4d579b63db87d4da61b8 +timeCreated: 1615452354 \ No newline at end of file diff --git a/Editor/Toolbar/IToolbarDrawer.cs b/Editor/Toolbar/IToolbarDrawer.cs new file mode 100644 index 0000000..2d6f5a5 --- /dev/null +++ b/Editor/Toolbar/IToolbarDrawer.cs @@ -0,0 +1,16 @@ +using Game.NavigationTool.Editor.Toolbar; +using UnityEngine; + +namespace Game.NavigationTool.Editor +{ + public interface IToolbarDrawer + { + bool Visible { get; } + bool Enabled { get; } + EToolbarPlacement Placement { get; } + + void Update(); + void Draw(Rect rect, Styles styles); + float CalculateWidth(); + } +} \ No newline at end of file diff --git a/Editor/Toolbar/IToolbarDrawer.cs.meta b/Editor/Toolbar/IToolbarDrawer.cs.meta new file mode 100644 index 0000000..45a4ae0 --- /dev/null +++ b/Editor/Toolbar/IToolbarDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c46344ec11b41baacc411eda7b4535a +timeCreated: 1615451575 \ No newline at end of file diff --git a/Editor/Toolbar/ToolbarDrawer.cs b/Editor/Toolbar/ToolbarDrawer.cs new file mode 100644 index 0000000..ce61303 --- /dev/null +++ b/Editor/Toolbar/ToolbarDrawer.cs @@ -0,0 +1,78 @@ +using Game.NavigationTool.Editor.Toolbar; +using UnityEditor; +using UnityEngine; + +namespace Game.NavigationTool.Editor +{ + [InitializeOnLoad] + internal static class ToolbarDrawer + { + private static bool IS_INITIALIZED; + private static IToolbarDrawer[] DRAWERS; + private static Styles styles; + + static ToolbarDrawer() + { + EditorApplication.update -= OnEditorUpdate; + EditorApplication.update += OnEditorUpdate; + } + + private static void OnEditorUpdate() + { + if (!IS_INITIALIZED) + { + styles = new Styles(); + DRAWERS = ToolbarUtility.GetAllDrawers(); + ToolbarUtility.AddGuiListener(OnGUI); + IS_INITIALIZED = true; + } + + for (var i = 0; i < DRAWERS.Length; i++) + { + DRAWERS[i].Update(); + } + } + + private static void OnGUI() + { + const float Y = 5.0f; + const float SPACING = 8.0f; + const float HEIGHT = 22.0f; + const float PLAY_BUTTON_EXTENT = 48.0f; + + if (DRAWERS == null) + return; + + styles.Initialize(GUI.skin); + float xLeft = EditorGUIUtility.currentViewWidth * 0.5f - PLAY_BUTTON_EXTENT; + float xRight = EditorGUIUtility.currentViewWidth * 0.5f + PLAY_BUTTON_EXTENT; + + for (var i = 0; i < DRAWERS.Length; i++) + { + IToolbarDrawer drawer = DRAWERS[i]; + + if (!drawer.Visible) + continue; + + GUI.enabled = drawer.Enabled; + float width = drawer.CalculateWidth(); + Rect rect; + + if (drawer.Placement == EToolbarPlacement.Left) + { + rect = new Rect(xLeft - width, Y, width, HEIGHT); + xLeft -= width + SPACING; + } + else + { + rect = new Rect(xRight, Y, width, HEIGHT); + xRight += width + SPACING; + } + + drawer.Draw(rect, styles); + } + + GUI.enabled = true; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ToolbarDrawer.cs.meta b/Editor/Toolbar/ToolbarDrawer.cs.meta new file mode 100644 index 0000000..5d904c3 --- /dev/null +++ b/Editor/Toolbar/ToolbarDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 573d9d105c364ee1851d16ebea1a8322 +timeCreated: 1615452234 \ No newline at end of file diff --git a/Editor/Toolbar/Tools.meta b/Editor/Toolbar/Tools.meta new file mode 100644 index 0000000..ceb0764 --- /dev/null +++ b/Editor/Toolbar/Tools.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1a4664fec0474f6fab58c6f66fc531f1 +timeCreated: 1615451704 \ No newline at end of file diff --git a/Editor/Toolbar/Tools/ToolScenePicker.cs b/Editor/Toolbar/Tools/ToolScenePicker.cs new file mode 100644 index 0000000..023477c --- /dev/null +++ b/Editor/Toolbar/Tools/ToolScenePicker.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.IO; +using Game.NavigationTool.Editor.Toolbar; +using JetBrains.Annotations; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Game.NavigationTool.Editor.Tools +{ + [UsedImplicitly] + internal sealed class ToolScenePicker : IToolbarDrawer + { + public bool Visible => true; + public bool Enabled => !EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode; + public EToolbarPlacement Placement => EToolbarPlacement.Right; + + private static bool IS_DIRTY = true; + private static int SELECTED_INDEX = -1; + private static string[] OPTIONS = new string[0]; + private static string[] PATHS = new string[0]; + + private void Initialize() + { + if (!IS_DIRTY) + return; + + EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes; + var listNames = new List(scenes.Length); + var listPaths = new List(scenes.Length); + + for (var i = 0; i < scenes.Length; i++) + { + if (string.IsNullOrEmpty(scenes[i].path)) + continue; + + listNames.Add(Path.GetFileNameWithoutExtension(scenes[i].path)); + listPaths.Add(scenes[i].path); + } + + OPTIONS = listNames.ToArray(); + PATHS = listPaths.ToArray(); + + Scene activeScene = SceneManager.GetActiveScene(); + SELECTED_INDEX = listPaths.IndexOf(activeScene.path); + IS_DIRTY = false; + } + + public void Update() + { + Initialize(); + } + + public void Draw(Rect rect, Styles styles) + { + Initialize(); + int temp = EditorGUI.Popup(rect, SELECTED_INDEX, OPTIONS, styles.popup); + + if (temp != -1 && temp != SELECTED_INDEX && OPTIONS.Length != 0) + { + SELECTED_INDEX = temp; + EditorSceneManager.OpenScene(PATHS[SELECTED_INDEX], OpenSceneMode.Single); + } + } + + public float CalculateWidth() + { + return 100.0f; + } + + public static void SetAsDirty() + { + IS_DIRTY = true; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Tools/ToolScenePicker.cs.meta b/Editor/Toolbar/Tools/ToolScenePicker.cs.meta new file mode 100644 index 0000000..730d6a4 --- /dev/null +++ b/Editor/Toolbar/Tools/ToolScenePicker.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 172702143ca2476994af66dff7f0c0f9 +timeCreated: 1615451718 \ No newline at end of file diff --git a/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs new file mode 100644 index 0000000..ba6434c --- /dev/null +++ b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs @@ -0,0 +1,20 @@ +using System.Linq; +using Game.NavigationTool.Editor.Tools; +using UnityEditor; + +namespace Game.NavigationTool.Editor.Toolbar +{ + internal sealed class ToolbarPostProcess : AssetPostprocessor + { + private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + if (HasChange(deletedAssets) || HasChange(movedAssets) || HasChange(importedAssets)) + ToolScenePicker.SetAsDirty(); + } + + private static bool HasChange(string[] assets) + { + return assets.Any(s => s.EndsWith(".unity")); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs.meta b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs.meta new file mode 100644 index 0000000..721a713 --- /dev/null +++ b/Editor/Toolbar/Tools/ToolScenePickerPostProcess.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aba187d5f2434c93b4104a1136897484 +timeCreated: 1615458676 \ No newline at end of file diff --git a/Editor/Toolbar/Utilities.meta b/Editor/Toolbar/Utilities.meta new file mode 100644 index 0000000..0834d0b --- /dev/null +++ b/Editor/Toolbar/Utilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5c179f2fa4b14648a720e0b3b2b435d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Utilities/Styles.cs b/Editor/Toolbar/Utilities/Styles.cs new file mode 100644 index 0000000..c191ba9 --- /dev/null +++ b/Editor/Toolbar/Utilities/Styles.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace Game.NavigationTool.Editor.Toolbar +{ + public sealed class Styles + { + public GUIStyle popup; + public GUIStyle button; + public GUIStyle slider; + + private GUISkin skin; + + public void Initialize(GUISkin skin) + { + if (this.skin == skin) + return; + + this.skin = skin; + popup = skin.FindStyle("ToolbarPopup"); + button = skin.FindStyle("ToolbarButtonFlat"); + slider = skin.FindStyle("ToolbarSlider"); + + // Available: ToolbarBoldLabel, ToolbarBottom, ToolbarButtonLeft, ToolbarButtonRight, ToolbarDropDown, + // ToolbarLabel, ToolbarTextField, ... + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Utilities/Styles.cs.meta b/Editor/Toolbar/Utilities/Styles.cs.meta new file mode 100644 index 0000000..09a55f1 --- /dev/null +++ b/Editor/Toolbar/Utilities/Styles.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 179c3a6025164e1f94a944b7b903dd23 +timeCreated: 1615459188 \ No newline at end of file diff --git a/Editor/Toolbar/Utilities/ToolbarUtility.cs b/Editor/Toolbar/Utilities/ToolbarUtility.cs new file mode 100644 index 0000000..abea4f0 --- /dev/null +++ b/Editor/Toolbar/Utilities/ToolbarUtility.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using System.Reflection; +using System.Runtime.Serialization; +using Object = UnityEngine.Object; + +#if UNITY_2019_1_OR_NEWER +using UnityEngine.UIElements; +#else +using UnityEngine.Experimental.UIElements; +#endif + +namespace Game.NavigationTool.Editor.Toolbar +{ + internal static class ToolbarUtility + { + public static void AddGuiListener(Action action) + { + Assembly assembly = typeof(UnityEditor.Editor).Assembly; + Type typeToolbar = assembly.GetType("UnityEditor.Toolbar"); + Object[] toolbars = Resources.FindObjectsOfTypeAll(typeToolbar); + ScriptableObject so = toolbars.Length > 0 ? (ScriptableObject)toolbars[0] : null; + + if (so == null) + return; + + Type typeGuiView = assembly.GetType("UnityEditor.GUIView"); + + #if UNITY_2020_1_OR_NEWER + Type typeWindowBackend = assembly.GetType("UnityEditor.IWindowBackend"); + PropertyInfo piWindowBackend = typeGuiView.GetProperty("windowBackend", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + PropertyInfo piVisualTree = typeWindowBackend.GetProperty("visualTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + #else + PropertyInfo piVisualTree = typeGuiView.GetProperty("visualTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + #endif + + if (piVisualTree == null) + return; + + FieldInfo fiImguiContainer = typeof(IMGUIContainer).GetField("m_OnGUIHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (fiImguiContainer == null) + return; + + #if UNITY_2020_1_OR_NEWER + var windowBackend = piWindowBackend.GetValue(so); + var visualTree = (VisualElement)piVisualTree.GetValue(windowBackend, null); + #else + var visualTree = (VisualElement)piVisualTree.GetValue(so, null); + #endif + + var container = (IMGUIContainer)visualTree[0]; + var handler = (Action)fiImguiContainer.GetValue(container); + handler -= action; + handler += action; + fiImguiContainer.SetValue(container, handler); + } + + public static IToolbarDrawer[] GetAllDrawers() + { + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + Type iType = typeof(IToolbarDrawer); + + var list = new List(8); + + for (var i = 0; i < assemblies.Length; i++) + { + Assembly assembly = assemblies[i]; + Type[] types = assembly.GetTypes(); + + for (var j = 0; j < types.Length; j++) + { + Type type = types[j]; + + if (!type.IsAbstract && iType.IsAssignableFrom(type)) + list.Add((IToolbarDrawer)FormatterServices.GetUninitializedObject(type)); + } + } + + return list.ToArray(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Utilities/ToolbarUtility.cs.meta b/Editor/Toolbar/Utilities/ToolbarUtility.cs.meta new file mode 100644 index 0000000..a98b591 --- /dev/null +++ b/Editor/Toolbar/Utilities/ToolbarUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a557eb0c4731f0e4b93d7d9381f003c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json index 3bdfadf..68f8989 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "com.module.navigationtool", - "version": "0.4.0", + "version": "0.5.0", "displayName": "Module.NavigationTool", - "description": "Support for navigation tools, like favorites and history", + "description": "Support for navigation tools, like favorites, history and toolbars", "unity": "2019.2", "unityRelease": "17f1", "dependencies": { @@ -10,7 +10,8 @@ "keywords": [ "navigation", "favorites", - "history" + "history", + "toolbar" ], "author": { "name": "Anders Ejlersen",