module-navigation-tool/Editor/Toolbar/Utilities/ToolbarUtility.cs

187 lines
6.4 KiB
C#

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 Module.NavigationTool.Editor.Toolbar
{
internal static class ToolbarUtility
{
private static readonly Assembly ASSEMBLY = typeof(UnityEditor.Editor).Assembly;
#if UNITY_2021_1_OR_NEWER
private static ScriptableObject CURRENT_TOOLBAR;
private static VisualElement CURRENT_PARENT_LEFT;
private static VisualElement CURRENT_PARENT_RIGHT;
private static int CURRENT_INSTANCE_ID = -1;
#endif
#if UNITY_2021_1_OR_NEWER
public static void OnUpdate(Action<VisualElement, VisualElement> callback)
{
if (CURRENT_TOOLBAR == null)
CURRENT_TOOLBAR = GetToolbarObject();
if (CURRENT_TOOLBAR != null && CURRENT_PARENT_LEFT != null && CURRENT_TOOLBAR.GetInstanceID() != CURRENT_INSTANCE_ID)
{
CURRENT_PARENT_LEFT.RemoveFromHierarchy();
CURRENT_PARENT_LEFT = null;
CURRENT_PARENT_RIGHT.RemoveFromHierarchy();
CURRENT_PARENT_RIGHT = null;
CURRENT_INSTANCE_ID = CURRENT_TOOLBAR.GetInstanceID();
}
if (CURRENT_TOOLBAR == null || CURRENT_PARENT_LEFT != null)
return;
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;
CURRENT_PARENT_LEFT = CreateParent(mRoot, "ToolbarZoneLeftAlign", true);
CURRENT_PARENT_RIGHT = CreateParent(mRoot, "ToolbarZoneRightAlign", false);
callback?.Invoke(CURRENT_PARENT_LEFT, CURRENT_PARENT_RIGHT);
}
private static VisualElement CreateParent(VisualElement root, string query, bool isLeft)
{
VisualElement parent = root.Q(query);
VisualElement result;
if (isLeft)
{
result = new VisualElement
{
style = {
flexGrow = 1,
flexDirection = FlexDirection.Row
}
};
result.Add(new VisualElement
{
style = {
flexGrow = 1
}
});
}
else
{
result = new VisualElement
{
style = {
flexGrow = 1,
flexDirection = FlexDirection.RowReverse
}
};
result.Add(new VisualElement
{
style =
{
flexGrow = 1
}
});
}
parent.Add(result);
return result;
}
#else
public static void AddGuiListener(Action action)
{
ScriptableObject so = GetToolbarObject();
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);
if (piWindowBackend == null)
return;
#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
object 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);
}
#endif
private static ScriptableObject GetToolbarObject()
{
Type typeToolbar = ASSEMBLY.GetType("UnityEditor.Toolbar");
Object[] toolbars = Resources.FindObjectsOfTypeAll(typeToolbar);
return toolbars.Length > 0 ? (ScriptableObject)toolbars[0] : null;
}
public static AbstractToolbarDrawer[] GetAllDrawers()
{
var list = new List<AbstractToolbarDrawer>(8);
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
Type iType = typeof(AbstractToolbarDrawer);
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((AbstractToolbarDrawer)FormatterServices.GetUninitializedObject(type));
}
}
}
catch (Exception)
{
// Fail silently
}
return list.ToArray();
}
}
}