0.5.0: Added toolbar with scene picker

This commit is contained in:
Anders Ejlersen 2021-03-11 12:27:50 +01:00
parent d35a79faf1
commit 27d7ecb2dd
19 changed files with 365 additions and 3 deletions

8
Editor/Toolbar.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 797b16e835d4ed542bf7636d218e8323
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7539098b999c4b1fa6f8d0f8874ea7db
timeCreated: 1615452342

View file

@ -0,0 +1,8 @@
namespace Game.NavigationTool.Editor
{
public enum EToolbarPlacement : byte
{
Left,
Right
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c1fe5a408a5b4d579b63db87d4da61b8
timeCreated: 1615452354

View file

@ -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();
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c46344ec11b41baacc411eda7b4535a
timeCreated: 1615451575

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 573d9d105c364ee1851d16ebea1a8322
timeCreated: 1615452234

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1a4664fec0474f6fab58c6f66fc531f1
timeCreated: 1615451704

View file

@ -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<string>(scenes.Length);
var listPaths = new List<string>(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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 172702143ca2476994af66dff7f0c0f9
timeCreated: 1615451718

View file

@ -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"));
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: aba187d5f2434c93b4104a1136897484
timeCreated: 1615458676

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e5c179f2fa4b14648a720e0b3b2b435d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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, ...
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 179c3a6025164e1f94a944b7b903dd23
timeCreated: 1615459188

View file

@ -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<IToolbarDrawer>(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();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a557eb0c4731f0e4b93d7d9381f003c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,8 +1,8 @@
{ {
"name": "com.module.navigationtool", "name": "com.module.navigationtool",
"version": "0.4.0", "version": "0.5.0",
"displayName": "Module.NavigationTool", "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", "unity": "2019.2",
"unityRelease": "17f1", "unityRelease": "17f1",
"dependencies": { "dependencies": {
@ -10,7 +10,8 @@
"keywords": [ "keywords": [
"navigation", "navigation",
"favorites", "favorites",
"history" "history",
"toolbar"
], ],
"author": { "author": {
"name": "Anders Ejlersen", "name": "Anders Ejlersen",