2025-12-01 16:46:28 +08:00
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UIElements;
|
|
|
|
|
|
|
2025-12-09 20:31:44 +08:00
|
|
|
|
namespace AlicizaX.UXTool
|
2025-12-01 16:46:28 +08:00
|
|
|
|
{
|
|
|
|
|
|
public static class ResolutionController
|
|
|
|
|
|
{
|
|
|
|
|
|
private const string EditorPrefsKey = "ResolutionViewInitialized";
|
|
|
|
|
|
|
|
|
|
|
|
private static bool hasInitialized
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return EditorPrefs.GetBool(EditorPrefsKey, false); }
|
|
|
|
|
|
set { EditorPrefs.SetBool(EditorPrefsKey, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// per-SceneView UI instances (避免重复添加同一 VisualElement 到多个父节点)
|
|
|
|
|
|
private static readonly Dictionary<int, VisualElement> roots = new Dictionary<int, VisualElement>();
|
|
|
|
|
|
private static readonly Dictionary<int, IMGUIContainer> containers = new Dictionary<int, IMGUIContainer>();
|
|
|
|
|
|
private static readonly HashSet<int> guiSubscribedIds = new HashSet<int>();
|
|
|
|
|
|
|
|
|
|
|
|
// 反射相关
|
|
|
|
|
|
private static MethodInfo gameViewSizePopupMethod;
|
|
|
|
|
|
private static PropertyInfo selectedSizeIndexProperty;
|
|
|
|
|
|
private static object gameViewInstance;
|
|
|
|
|
|
private static int selectedSizeIndex = -1;
|
|
|
|
|
|
private static object currentSizeGroupTypeObj;
|
|
|
|
|
|
|
|
|
|
|
|
// 事件订阅标志
|
|
|
|
|
|
private static bool subscribedToEditorLoadEvents = false;
|
|
|
|
|
|
private static bool subscribedToUpdate = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 布局参数(需要时可调整)
|
|
|
|
|
|
private const float GuiWidth = 160f;
|
|
|
|
|
|
private const float RootWidth = 180f;
|
|
|
|
|
|
private const float RootHeight = 22f;
|
|
|
|
|
|
private const float OffsetTop = -22f;
|
|
|
|
|
|
private const float OffsetRight = -20f;
|
|
|
|
|
|
|
|
|
|
|
|
[InitializeOnLoadMethod]
|
|
|
|
|
|
public static void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 在初始化时恢复(确保干净状态),并注册自己的事件
|
|
|
|
|
|
RestoreOriginalToolbar();
|
|
|
|
|
|
UXDesinUtil.OnEnterDesignMode += RegisterEvents;
|
|
|
|
|
|
UXDesinUtil.OnExitDesignMode += UnRegisterEvents;
|
|
|
|
|
|
|
|
|
|
|
|
if (UXDesinUtil.InDesign)
|
|
|
|
|
|
{
|
|
|
|
|
|
RegisterEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UnRegisterEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void RegisterEvents()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (subscribedToEditorLoadEvents) return;
|
|
|
|
|
|
EditorApplication.delayCall += OnEditorLoadDelay;
|
|
|
|
|
|
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
|
|
|
|
|
|
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
|
|
|
|
|
|
subscribedToEditorLoadEvents = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void UnRegisterEvents()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!subscribedToEditorLoadEvents) return;
|
|
|
|
|
|
EditorApplication.delayCall -= OnEditorLoadDelay;
|
|
|
|
|
|
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
|
|
|
|
|
|
AssemblyReloadEvents.afterAssemblyReload -= OnAfterAssemblyReload;
|
|
|
|
|
|
subscribedToEditorLoadEvents = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void OnEditorLoadDelay()
|
|
|
|
|
|
{
|
|
|
|
|
|
// EnsureInitialized 是幂等的
|
|
|
|
|
|
if (!hasInitialized)
|
|
|
|
|
|
{
|
|
|
|
|
|
EnsureInitialized();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 仅在设计模式下启动 per-frame 更新
|
|
|
|
|
|
if (UXDesinUtil.InDesign)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateSceneViewUI(); // 立即尝试添加
|
|
|
|
|
|
if (!subscribedToUpdate)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorApplication.update += UpdateSceneViewUI;
|
|
|
|
|
|
subscribedToUpdate = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 不在设计模式则移除所有 UI
|
|
|
|
|
|
Cleanup();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void OnBeforeAssemblyReload()
|
|
|
|
|
|
{
|
|
|
|
|
|
Cleanup();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void OnAfterAssemblyReload()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 延迟调用以等待编辑器恢复
|
|
|
|
|
|
EditorApplication.delayCall += OnEditorLoadDelay;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void EnsureInitialized()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (hasInitialized) return;
|
|
|
|
|
|
|
|
|
|
|
|
bool ok = InitWindowData();
|
|
|
|
|
|
if (!ok)
|
|
|
|
|
|
{
|
|
|
|
|
|
hasInitialized = false;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不再在此创建单一 Root;Root 在 AddRootToSceneView 时为每个 SceneView 创建
|
|
|
|
|
|
hasInitialized = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool InitWindowData()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 尝试通过你项目已有的 Utils 获取主 GameView
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果项目提供了 Utils.GetMainPlayModeView(),保留调用(你原代码中提到)
|
|
|
|
|
|
var utilsType = Type.GetType("Utils");
|
|
|
|
|
|
if (utilsType != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var method = utilsType.GetMethod("GetMainPlayModeView", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
|
|
|
|
|
if (method != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
gameViewInstance = method.Invoke(null, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 忽略 utils 获取失败,继续使用反射查找
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果为空,尝试从类型查找已存在的 GameView 实例
|
|
|
|
|
|
if (gameViewInstance == null)
|
|
|
|
|
|
{
|
2025-12-09 20:31:44 +08:00
|
|
|
|
var gvType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
|
2025-12-01 16:46:28 +08:00
|
|
|
|
if (gvType != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var arr = Resources.FindObjectsOfTypeAll(gvType);
|
|
|
|
|
|
if (arr != null && arr.Length > 0)
|
|
|
|
|
|
gameViewInstance = arr[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (gameViewInstance == null)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
var editorGUILayoutType = Type.GetType("UnityEditor.EditorGUILayout,UnityEditor")
|
2025-12-09 20:31:44 +08:00
|
|
|
|
?? typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.EditorGUILayout");
|
2025-12-01 16:46:28 +08:00
|
|
|
|
if (editorGUILayoutType != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
gameViewSizePopupMethod = editorGUILayoutType.GetMethod("GameViewSizePopup", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-09 20:31:44 +08:00
|
|
|
|
var gameViewType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
|
2025-12-01 16:46:28 +08:00
|
|
|
|
if (gameViewType == null) return false;
|
|
|
|
|
|
|
|
|
|
|
|
selectedSizeIndexProperty = gameViewType.GetProperty("selectedSizeIndex", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
|
|
|
if (selectedSizeIndexProperty == null) return false;
|
|
|
|
|
|
|
|
|
|
|
|
var currentSizeGroupProp = gameViewType.GetProperty("currentSizeGroupType", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
|
|
|
|
|
|
if (currentSizeGroupProp != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var getMethod = currentSizeGroupProp.GetGetMethod(nonPublic: true);
|
|
|
|
|
|
if (getMethod != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (getMethod.IsStatic)
|
|
|
|
|
|
currentSizeGroupTypeObj = currentSizeGroupProp.GetValue(null);
|
|
|
|
|
|
else
|
|
|
|
|
|
currentSizeGroupTypeObj = currentSizeGroupProp.GetValue(gameViewInstance);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始索引读取
|
|
|
|
|
|
selectedSizeIndex = (int)selectedSizeIndexProperty.GetValue(gameViewInstance);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] InitWindowData failed: " + e);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void UpdateSceneViewUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 仅当 UXDesinUtil 在设计模式时显示
|
|
|
|
|
|
if (!UXDesinUtil.InDesign)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (hasInitialized)
|
|
|
|
|
|
RestoreOriginalToolbar();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EnsureInitialized();
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasInitialized)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 为所有可用 SceneView 保证 UI(多 SceneView 情况下,每个 SceneView 一个实例,避免重复添加同一个 VE)
|
|
|
|
|
|
foreach (SceneView sceneView in SceneView.sceneViews)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sceneView == null) continue;
|
|
|
|
|
|
AddRootToSceneView(sceneView);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 触发 repaint
|
|
|
|
|
|
var last = SceneView.lastActiveSceneView;
|
|
|
|
|
|
if (last != null) last.Repaint();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] UpdateSceneViewUI exception: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 为指定的 SceneView 创建并添加 Root + IMGUIContainer(如果尚未添加)。
|
|
|
|
|
|
/// 使用 sceneView.GetInstanceID() 作为 key,避免重复创建/添加。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static void AddRootToSceneView(SceneView sceneView)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sceneView == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
int id = sceneView.GetInstanceID();
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var rootVisual = sceneView.rootVisualElement;
|
|
|
|
|
|
if (rootVisual == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果已经为该 SceneView 创建过 root,则确保它还在该 SceneView 下
|
|
|
|
|
|
if (roots.ContainsKey(id))
|
|
|
|
|
|
{
|
|
|
|
|
|
var existingRoot = roots[id];
|
|
|
|
|
|
if (existingRoot == null || existingRoot.parent == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果被移除则重加
|
|
|
|
|
|
if (existingRoot != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
rootVisual.Add(existingRoot);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果被 GC 或置 null,则删掉记录并重新创建
|
|
|
|
|
|
roots.Remove(id);
|
|
|
|
|
|
if (containers.ContainsKey(id))
|
|
|
|
|
|
containers.Remove(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 若 rootVisual 中已有同名元素(来自旧版本或其他插件残留),不要重复添加
|
|
|
|
|
|
const string rootName = "ResolutionController_Root";
|
|
|
|
|
|
var found = rootVisual.Q(rootName);
|
|
|
|
|
|
if (found != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 已经存在一个元素(可能来自之前的装载),把它当作该 SceneView 的 root
|
|
|
|
|
|
roots[id] = found;
|
|
|
|
|
|
// 如果需要,确保里面有 IMGUIContainer(若无,创建一个)
|
|
|
|
|
|
var gui = found.Q<IMGUIContainer>("IMGUIContainer_ResolutionController");
|
|
|
|
|
|
if (gui == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var newGui = CreateAndAttachIMGUI(found, id);
|
|
|
|
|
|
containers[id] = newGui;
|
|
|
|
|
|
SubscribeGuiHandlerIfNeeded(id, newGui);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的 root + imGUIContainer 实例并加入到 sceneView.rootVisualElement
|
|
|
|
|
|
var newRoot = new VisualElement();
|
|
|
|
|
|
newRoot.name = rootName;
|
|
|
|
|
|
newRoot.style.position = Position.Absolute;
|
|
|
|
|
|
newRoot.style.top = OffsetTop;
|
|
|
|
|
|
newRoot.style.right = OffsetRight;
|
|
|
|
|
|
newRoot.style.width = RootWidth;
|
|
|
|
|
|
newRoot.style.height = RootHeight;
|
|
|
|
|
|
newRoot.style.overflow = Overflow.Visible;
|
|
|
|
|
|
|
|
|
|
|
|
var newGuiContainer = new IMGUIContainer();
|
|
|
|
|
|
newGuiContainer.name = "IMGUIContainer_ResolutionController";
|
|
|
|
|
|
newGuiContainer.style.width = RootWidth;
|
|
|
|
|
|
newGuiContainer.style.height = RootHeight;
|
|
|
|
|
|
|
|
|
|
|
|
newRoot.Add(newGuiContainer);
|
|
|
|
|
|
rootVisual.Add(newRoot);
|
|
|
|
|
|
|
|
|
|
|
|
roots[id] = newRoot;
|
|
|
|
|
|
containers[id] = newGuiContainer;
|
|
|
|
|
|
|
|
|
|
|
|
SubscribeGuiHandlerIfNeeded(id, newGuiContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] AddRootToSceneView failed: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static IMGUIContainer CreateAndAttachIMGUI(VisualElement root, int id)
|
|
|
|
|
|
{
|
|
|
|
|
|
var gui = new IMGUIContainer();
|
|
|
|
|
|
gui.name = "IMGUIContainer_ResolutionController";
|
|
|
|
|
|
gui.style.width = RootWidth;
|
|
|
|
|
|
gui.style.height = RootHeight;
|
|
|
|
|
|
root.Add(gui);
|
|
|
|
|
|
return gui;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void SubscribeGuiHandlerIfNeeded(int id, IMGUIContainer gui)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (gui == null) return;
|
|
|
|
|
|
if (guiSubscribedIds.Contains(id)) return;
|
|
|
|
|
|
gui.onGUIHandler += () => OnGUIHandlerForId(id);
|
|
|
|
|
|
guiSubscribedIds.Add(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void UnsubscribeGuiHandlerIfNeeded(int id)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!guiSubscribedIds.Contains(id)) return;
|
|
|
|
|
|
if (containers.TryGetValue(id, out var gui) && gui != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 无法直接移除匿名 lambda,因此改为移除所有并重新创建时控制(但为保险尝试移除单个引用)
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
gui.onGUIHandler -= () => OnGUIHandlerForId(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
guiSubscribedIds.Remove(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void OnGUIHandlerForId(int id)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
GUILayoutOption[] ops = new GUILayoutOption[] { GUILayout.Width(GuiWidth) };
|
|
|
|
|
|
|
|
|
|
|
|
if (gameViewSizePopupMethod != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 兼容不同签名
|
|
|
|
|
|
gameViewSizePopupMethod.Invoke(null, new object[] { currentSizeGroupTypeObj, selectedSizeIndex, gameViewInstance, EditorStyles.toolbarPopup, ops });
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (TargetParameterCountException)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
gameViewSizePopupMethod.Invoke(null, new object[] { selectedSizeIndex, gameViewInstance, EditorStyles.toolbarPopup, ops });
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 忽略
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 忽略单次调用错误
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OnGUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] OnGUIHandler exception: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void OnGUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (gameViewInstance == null || selectedSizeIndexProperty == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
int nowIndex = (int)selectedSizeIndexProperty.GetValue(gameViewInstance);
|
|
|
|
|
|
if (nowIndex != selectedSizeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
selectedSizeIndex = nowIndex;
|
|
|
|
|
|
// 如果需要可在此触发回调或通知其他系统
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] OnGUI exception: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void RestoreOriginalToolbar()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 取消每个 sceneView 的 gui handler 并移除 roots
|
|
|
|
|
|
foreach (var kv in new List<int>(roots.Keys))
|
|
|
|
|
|
{
|
|
|
|
|
|
int id = kv;
|
|
|
|
|
|
if (containers.TryGetValue(id, out var gui) && gui != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 尝试移除我们的 handler(如果用了 lambda,直接移除可能无效,但我们会移除整个元素)
|
|
|
|
|
|
gui.onGUIHandler = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (roots.TryGetValue(id, out var root) && root != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (root.parent != null)
|
|
|
|
|
|
root.parent.Remove(root);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] RestoreOriginalToolbar failed: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保持状态清理
|
|
|
|
|
|
hasInitialized = false;
|
|
|
|
|
|
guiSubscribedIds.Clear();
|
|
|
|
|
|
containers.Clear();
|
|
|
|
|
|
roots.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void Cleanup()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (subscribedToUpdate)
|
|
|
|
|
|
{
|
|
|
|
|
|
EditorApplication.update -= UpdateSceneViewUI;
|
|
|
|
|
|
subscribedToUpdate = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除所有 gui handlers 并删除 UI
|
|
|
|
|
|
foreach (var id in new List<int>(containers.Keys))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var gui = containers[id];
|
|
|
|
|
|
if (gui != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
gui.onGUIHandler = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var kv in new List<int>(roots.Keys))
|
|
|
|
|
|
{
|
|
|
|
|
|
var root = roots[kv];
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (root != null && root.parent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
root.parent.Remove(root);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
guiSubscribedIds.Clear();
|
|
|
|
|
|
containers.Clear();
|
|
|
|
|
|
roots.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
gameViewSizePopupMethod = null;
|
|
|
|
|
|
selectedSizeIndexProperty = null;
|
|
|
|
|
|
gameViewInstance = null;
|
|
|
|
|
|
currentSizeGroupTypeObj = null;
|
|
|
|
|
|
|
|
|
|
|
|
hasInitialized = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[ResolutionController] Cleanup exception: " + e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|