Navigation tools upgraded to use the new MainToolbarElement API

This commit is contained in:
Anders Ejlersen 2025-12-06 15:17:30 +01:00
parent 708b99f763
commit 3e1602162c
52 changed files with 837 additions and 66 deletions

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2bb70affaf1b42d9b59779683dbbb62d
timeCreated: 1765023522

View file

@ -0,0 +1,22 @@
#if UNITY_6000_3_OR_NEWER
using System.Linq;
using UnityEditor;
namespace Module.NavigationTool.Editor.Toolbar
{
internal sealed class MainToolbarScenePickerPostProcess : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (HasChange(deletedAssets) || HasChange(movedAssets) || HasChange(importedAssets))
MainToolbarScenePickerElement.Refresh();
}
private static bool HasChange(string[] assets)
{
return assets.Any(s => s.EndsWith(".unity")) ||
assets.Any(s => s.EndsWith("EditorBuildSettings.asset"));
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1a8274c0b09c4ccf99d08c1e6db45331
timeCreated: 1765023528

View file

@ -0,0 +1,64 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
namespace Module.NavigationTool.Editor.Toolbar
{
[InitializeOnLoad]
internal static class MainToolbarScenePickerStateChanged
{
static MainToolbarScenePickerStateChanged()
{
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
EditorSceneManager.newSceneCreated += OnNewSceneCreated;
EditorSceneManager.activeSceneChangedInEditMode += OnActiveSceneChangedInEditMode;
EditorSceneManager.sceneOpened += OnSceneOpened;
EditorSceneManager.sceneClosed += OnSceneClosed;
}
private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnActiveSceneChanged(Scene current, Scene next)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnSceneUnloaded(Scene arg0)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnActiveSceneChangedInEditMode(Scene from, Scene to)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnNewSceneCreated(Scene scene, NewSceneSetup setup, NewSceneMode mode)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnSceneOpened(Scene scene, OpenSceneMode mode)
{
MainToolbarScenePickerElement.Refresh();
}
private static void OnSceneClosed(Scene scene)
{
MainToolbarScenePickerElement.Refresh();
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c9bd16d885949239ac6b9f7ce1825ec
timeCreated: 1765023528

View file

@ -0,0 +1,47 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
namespace Module.NavigationTool.Editor.Toolbar
{
[InitializeOnLoad]
internal static class MainToolbarUIStateChanged
{
static MainToolbarUIStateChanged()
{
EditorSceneManager.sceneSaved += OnSceneSaved;
EditorSceneManager.sceneOpened += OnSceneOpened;
EditorSceneManager.sceneClosed += OnSceneClosed;
PrefabStage.prefabStageOpened += OnPrefabStageOpened;
PrefabStage.prefabStageClosing += OnPrefabStageClosing;
}
private static void OnSceneSaved(Scene scene)
{
MainToolbarUIElement.Refresh();
}
private static void OnSceneOpened(Scene scene, OpenSceneMode mode)
{
MainToolbarUIElement.Refresh();
}
private static void OnSceneClosed(Scene scene)
{
MainToolbarUIElement.Refresh();
}
private static void OnPrefabStageOpened(PrefabStage stage)
{
MainToolbarUIElement.Refresh();
}
private static void OnPrefabStageClosing(PrefabStage stage)
{
MainToolbarUIElement.Refresh();
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 21f843e3d88741ef985041ddb1fa986d
timeCreated: 1765024267

View file

@ -0,0 +1,103 @@
#if UNITY_6000_3_OR_NEWER
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarBuildElement
{
[Preserve]
[MainToolbarElement("Toolbar/Build", ussName = "", defaultDockIndex = 0, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 500)]
public static IEnumerable<MainToolbarElement> Draw()
{
var target = EditorUserBuildSettings.activeBuildTarget;
var group = BuildPipeline.GetBuildTargetGroup(target);
return new List<MainToolbarElement>(2)
{
new MainToolbarDropdown(new MainToolbarContent("Build", "Select build or build & run options"), OnBuildDropdownOpened),
new MainToolbarDropdown(GetButtonContent(group), OnBuildTargetDropdownOpened)
};
}
private static void OnBuildDropdownOpened(Rect rect)
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Build", "Build project with current EditorBuildSettings and target platform"), false, () => Build(false));
menu.AddItem(new GUIContent("Build & Run", "Build & Run project with current EditorBuildSettings and target platform"), false, () => Build(false));
menu.DropDown(rect);
}
private static void OnBuildTargetDropdownOpened(Rect rect)
{
var menu = new GenericMenu();
var type = typeof(BuildTarget);
var values = Enum.GetValues(type);
for (var i = 0; i < values.Length; i++)
{
var target = (BuildTarget)values.GetValue(i);
var group = BuildPipeline.GetBuildTargetGroup(target);
if (target < 0 || !BuildPipeline.IsBuildTargetSupported(group, target))
continue;
if (!IsValid(type, target))
continue;
menu.AddItem(new GUIContent(ObjectNames.NicifyVariableName(target.ToString())), false, () => SetBuildTargetTo(group, target));
}
menu.DropDown(rect);
}
private static void SetBuildTargetTo(BuildTargetGroup group, BuildTarget target)
{
if (EditorUserBuildSettings.SwitchActiveBuildTarget(group, target))
MainToolbar.Refresh("Toolbar/Build Targets");
}
private static bool IsValid(Type type, BuildTarget target)
{
var members = type.GetMember(target.ToString(), BindingFlags.Public | BindingFlags.Static);
if (members.Length == 0)
return false;
for (var j = 0; j < members.Length; j++)
{
if (members[j].GetCustomAttribute<ObsoleteAttribute>() == null)
return true;
}
return false;
}
private static GUIContent GetButtonContent(BuildTargetGroup group)
{
var name = $"BuildSettings.{group}.Small";
if (group == BuildTargetGroup.WSA)
name = "BuildSettings.Metro.Small";
var iconContent = EditorGUIUtility.IconContent(name);
var content = new GUIContent(iconContent.image, "Select target platform for build");
return content;
}
private static void Build(bool withAutorun)
{
var options = BuildPlayerWindow.DefaultBuildMethods.GetBuildPlayerOptions(new BuildPlayerOptions());
if (withAutorun)
options.options |= BuildOptions.AutoRunPlayer;
BuildPlayerWindow.DefaultBuildMethods.BuildPlayer(options);
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c4b306cf95144139c540aa7b6c0a156
timeCreated: 1765022920

View file

@ -0,0 +1,28 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarPlayerPrefsElement
{
[Preserve]
[MainToolbarElement("Toolbar/Player Prefs Delete", ussName = "", defaultDockIndex = 100, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 1500)]
public static MainToolbarElement Draw()
{
var icon = EditorGUIUtility.IconContent("d_CacheServerDisconnected").image as Texture2D;
var content = new MainToolbarContent(icon, "Deletes all PlayerPrefs entries");
return new MainToolbarButton(content, () =>
{
if (!EditorUtility.DisplayDialog("Delete PlayerPrefs", "Are you sure you want to delete all PlayerPrefs data?", "Yes", "No"))
return;
PlayerPrefs.DeleteAll();
PlayerPrefs.Save();
});
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a926471f33c04f7fb75a32f84c6c9d1b
timeCreated: 1765023278

View file

@ -0,0 +1,21 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarProjectSaveElement
{
[Preserve]
[MainToolbarElement("Toolbar/Project/Save", ussName = "", defaultDockIndex = 100, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 1500)]
public static MainToolbarElement Draw()
{
var icon = EditorGUIUtility.IconContent("Project").image as Texture2D;
var content = new MainToolbarContent(icon, "Saves all changed assets");
return new MainToolbarButton(content, AssetDatabase.SaveAssets);
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8383da48c39b4300b74e9c1791c32a8a
timeCreated: 1765024530

View file

@ -0,0 +1,29 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarProjectSettingsElement
{
[Preserve]
[MainToolbarElement("Toolbar/Project/Open Settings", ussName = "", defaultDockIndex = 100, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 1500)]
public static MainToolbarElement Draw()
{
var icon = EditorGUIUtility.IconContent("Settings").image as Texture2D;
var content = new MainToolbarContent(icon, "Opens Preferences/Project Settings");
return new MainToolbarDropdown(content, OnDropdownOpen);
}
private static void OnDropdownOpen(Rect rect)
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Preferences"), false, () => SettingsService.OpenUserPreferences("Module/Toolbar"));
menu.AddItem(new GUIContent("Project Settings"), false, () => SettingsService.OpenProjectSettings("Module/Toolbar"));
menu.DropDown(rect);
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5ebe021aec8e4dc58d5eb863695e3485
timeCreated: 1765024477

View file

@ -0,0 +1,187 @@
#if UNITY_6000_3_OR_NEWER
using System;
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarScenePickerElement
{
private static readonly ScenePickerList SceneList = new();
[Preserve]
[MainToolbarElement("Toolbar/Scene", ussName = "", defaultDockIndex = 100, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 1500)]
public static IEnumerable<MainToolbarElement> Draw()
{
return new List<MainToolbarElement>(3)
{
CreateDropdownSceneList(),
CreateToggleSceneLoad(),
CreateButtonAddNewScene()
};
}
private static MainToolbarDropdown CreateDropdownSceneList()
{
SceneList.Refresh();
var content = new MainToolbarContent(GetSceneLabel());
return new MainToolbarDropdown(content, rect =>
{
var menu = new GenericMenu();
for (var i = 0; i < SceneList.labels.Length; i++)
{
var sceneIndex = i;
menu.AddItem(SceneList.labels[i], SceneList.selected.Contains(i), () => SelectScene(sceneIndex));
}
menu.DropDown(rect);
});
}
private static MainToolbarToggle CreateToggleSceneLoad()
{
var isScenePickerSetAsAdditive = ToolbarScenePickerSettings.IsScenePickerSetAsAdditive;
var content = isScenePickerSetAsAdditive
? new MainToolbarContent("A", "Additive scene loading (toogle to Single)")
: new MainToolbarContent("S", "Single scene loading (toggle to Additive)");
return new MainToolbarToggle(content, isScenePickerSetAsAdditive, result =>
{
ToolbarScenePickerSettings.IsScenePickerSetAsAdditive = result;
MainToolbar.Refresh("Toolbar/Scene");
});
}
private static MainToolbarButton CreateButtonAddNewScene()
{
var icon = EditorGUIUtility.IconContent("d_CreateAddNew").image as Texture2D;
var content = new MainToolbarContent(icon, "Create a new scene");
return new MainToolbarButton(content, () =>
{
try
{
var selection = EditorUtility.DisplayDialogComplex("Create new scene", "How do you want to add the scene?", "Single", "Additive", "Cancel");
if (selection == 2)
return;
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, selection == 0 ? NewSceneMode.Single : NewSceneMode.Additive);
if (EditorUtility.DisplayDialog("Create new scene", "Save scene to disk?", "Yes", "No"))
EditorSceneManager.SaveScene(scene);
}
catch (Exception e)
{
EditorUtility.DisplayDialog("Failed to add scene", e.Message, "Ok");
}
});
}
private static void SelectScene(int index)
{
try
{
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
return;
var scenes = SceneList.scenes[index];
var isScenePickerSetAsAdditive = ToolbarScenePickerSettings.IsScenePickerSetAsAdditive;
for (var i = 0; i < scenes.paths.Count; i++)
{
var path = scenes.paths[i];
var scene = SceneManager.GetSceneByPath(path);
if (scenes.isGroup)
{
if (isScenePickerSetAsAdditive || i != 0)
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
var sceneIndex = SceneList.IndexOfPath(path, false);
if (sceneIndex != -1)
SceneList.selected.Add(sceneIndex);
}
else
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Single);
var sceneIndex = SceneList.IndexOfPath(path, false);
SceneList.selected.Clear();
if (sceneIndex != -1)
SceneList.selected.Add(index);
}
}
else
{
if (scene.isLoaded)
{
if (SceneManager.sceneCount == 1)
return;
EditorSceneManager.CloseScene(scene, true);
SceneList.selected.Remove(index);
}
else if (isScenePickerSetAsAdditive)
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
SceneList.selected.Add(index);
}
else
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Single);
SceneList.selected.Clear();
SceneList.selected.Add(index);
}
}
}
GetSceneLabel();
}
catch (Exception e)
{
Debug.LogException(e);
}
finally
{
MainToolbar.Refresh("Toolbar/Scene");
}
}
private static string GetSceneLabel()
{
var builder = new StringBuilder();
if (SceneList.selected.Count != 0)
{
for (var i = 0; i < SceneList.selected.Count; i++)
{
if (i > 0)
builder.Append(", ");
builder.Append(SceneList.scenes[SceneList.selected[i]].shortname);
}
}
else
{
builder.Append("Unsaved scene(s)");
}
return builder.ToString();
}
public static void Refresh()
{
MainToolbar.Refresh("Toolbar/Scene");
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 279f6b5a4bce42b6b1250f13a31a065c
timeCreated: 1765023392

View file

@ -0,0 +1,30 @@
#if UNITY_6000_3_OR_NEWER
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.Scripting;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarTimeScaleElement
{
[Preserve]
[MainToolbarElement("Toolbar/Time Scale", ussName = "", defaultDockIndex = 0, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 500)]
public static MainToolbarElement Draw()
{
var content = new MainToolbarContent("Time:", "Adjust Time.timeScale from [min;max] and snaps when value is approximately 1.0");
return new MainToolbarSlider(content, Time.timeScale, ToolbarTimeSettings.TimeScaleMinValue, ToolbarTimeSettings.TimeScaleMaxValue, OnTimeScaleValueChanged);
}
private static void OnTimeScaleValueChanged(float value)
{
value = Mathf.Clamp(value, ToolbarTimeSettings.TimeScaleMinValue, ToolbarTimeSettings.TimeScaleMaxValue);
if (Mathf.Abs(value - 1.0f) < 0.02f)
value = 1.0f;
if (!Mathf.Approximately(Time.timeScale, value))
Time.timeScale = value;
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 86d04559b6fc4260b33c97799a0e78e6
timeCreated: 1765023773

View file

@ -0,0 +1,99 @@
#if UNITY_6000_3_OR_NEWER
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditor.Toolbars;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Scripting;
using UTools = UnityEditor.Tools;
namespace Module.NavigationTool.Editor.Toolbar
{
internal static class MainToolbarUIElement
{
[Preserve]
[MainToolbarElement("Toolbar/UI", ussName = "", defaultDockIndex = 0, defaultDockPosition = MainToolbarDockPosition.Middle, menuPriority = 500)]
public static IEnumerable<MainToolbarElement> Draw()
{
var layer = 1 << LayerMask.NameToLayer("UI");
var toggleValue = (UTools.visibleLayers & layer) != 0;
return new List<MainToolbarElement>(2)
{
new MainToolbarToggle(new MainToolbarContent("UI", "Toggles UI visible layer in SceneView"), toggleValue, OnToggleValueChanged),
new MainToolbarDropdown(new MainToolbarContent("Select"), OnDropdownOpen)
};
}
private static void OnToggleValueChanged(bool result)
{
var layer = 1 << LayerMask.NameToLayer("UI");
if (result)
UTools.visibleLayers |= layer;
else
UTools.visibleLayers &= ~layer;
SceneView.RepaintAll();
}
private static void OnDropdownOpen(Rect rect)
{
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
var canvases = prefabStage != null
? prefabStage.prefabContentsRoot.GetComponentsInParent<Canvas>()
: Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID);
var list = new List<Canvas>(canvases.Length);
var menu = new GenericMenu();
for (var i = 0; i < canvases.Length; i++)
{
var root = canvases[i].rootCanvas;
if (list.Contains(root))
continue;
list.Add(root);
menu.AddItem(new GUIContent($"{i}: {root.name}"), false, () => Focus(root.GetInstanceID()));
}
menu.DropDown(rect);
}
private static void Focus(int instanceId)
{
var obj = EditorUtility.EntityIdToObject(instanceId);
var canvas = obj as Canvas;
if (canvas == null)
{
if (obj != null)
Debug.LogWarning("Failed to find Canvas component on object", obj);
return;
}
Selection.activeObject = canvas;
var bounds = InternalEditorUtility.CalculateSelectionBounds(false, true, true);
var point = bounds.center;
var direction = canvas.transform.rotation;
var size = Mathf.Max(bounds.extents.x, bounds.extents.y);
var ortho = canvas.renderMode == RenderMode.ScreenSpaceOverlay;
for (var i = 0; i < SceneView.sceneViews.Count; i++)
{
var view = (SceneView)SceneView.sceneViews[i];
view.in2DMode = false;
view.LookAt(point, direction, size, ortho, false);
}
}
public static void Refresh()
{
MainToolbar.Refresh("Toolbar/UI");
}
}
}
#endif

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c070302f00e44ad6b6a383ae07de6fe2
timeCreated: 1765024213