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 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) return; 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; 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); 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(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)); } } list.Sort((t0, t1) => t0.Priority.CompareTo(t1.Priority)); } catch (Exception) { // Fail silently } return list.ToArray(); } } }