Files
ichni_Creator_Studio/Assets/Editor/QuickSelector.CS

231 lines
9.0 KiB
C#

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
[InitializeOnLoad]
public class QuickSelectorHud
{
public static GameObject HoveredObject;
static QuickSelectorHud()
{
SceneView.duringSceneGui += OnSceneGUI;
}
private static void OnSceneGUI(SceneView sceneView)
{
if (HoveredObject != null)
{
DrawHighlight(HoveredObject);
sceneView.Repaint();
}
Event e = Event.current;
if (e.type == EventType.MouseDown && e.button == 1 && e.shift)
{
var entries = CollectData(sceneView, e.mousePosition);
QuickSelectorPopup popup = new QuickSelectorPopup(entries);
PopupWindow.Show(new Rect(e.mousePosition.x, e.mousePosition.y, 0, 0), popup);
e.Use();
}
}
private static void DrawHighlight(GameObject go)
{
Handles.color = new Color(0f, 0.7f, 1f, 1f); // 亮蓝色
RectTransform rt = go.GetComponent<RectTransform>();
if (rt != null)
{
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
Handles.DrawPolyLine(corners[0], corners[1], corners[2], corners[3], corners[0]);
Handles.color = new Color(0f, 0.7f, 1f, 0.1f);
Handles.DrawAAConvexPolygon(corners);
}
else
{
Renderer r = go.GetComponent<Renderer>();
if (r != null) Handles.DrawWireCube(r.bounds.center, r.bounds.size);
}
}
private static List<SelectionEntry> CollectData(SceneView sceneView, Vector2 mousePos)
{
bool enableUI = EditorPrefs.GetBool("QS_UI", true);
bool enable3D = EditorPrefs.GetBool("QS_3D", true);
Vector2 guiPos = mousePos;
guiPos.y = sceneView.camera.pixelHeight - guiPos.y;
Ray ray = HandleUtility.GUIPointToWorldRay(mousePos);
HashSet<GameObject> processed = new HashSet<GameObject>();
List<SelectionEntry> list = new List<SelectionEntry>();
GameObject smart = HandleUtility.PickGameObject(mousePos, false);
if (smart != null) AddEntry(list, processed, smart, "PICK");
if (enableUI)
{
var rects = GameObject.FindObjectsByType<RectTransform>(FindObjectsSortMode.None);
foreach (var rect in rects)
{
if (rect.gameObject.activeInHierarchy && RectTransformUtility.RectangleContainsScreenPoint(rect, guiPos, sceneView.camera))
AddEntry(list, processed, rect.gameObject, "UI");
}
}
if (enable3D)
{
RaycastHit[] hits = Physics.RaycastAll(ray, float.MaxValue);
foreach (var hit in hits) AddEntry(list, processed, hit.collider.gameObject, "3D");
foreach (var r in GameObject.FindObjectsByType<Renderer>(FindObjectsSortMode.None))
if (!processed.Contains(r.gameObject) && r.bounds.IntersectRay(ray, out _))
AddEntry(list, processed, r.gameObject, "Mesh");
}
return list;
}
private static void AddEntry(List<SelectionEntry> list, HashSet<GameObject> set, GameObject go, string src)
{
if (go == null || !set.Add(go)) return;
string maj = (go.GetComponent<RectTransform>() != null) ? "UI" : (go.GetComponent<Collider>() != null ? "3D" : "Mesh");
string min = (maj == "UI") ? GetUIType(go) : (go.GetComponent<Renderer>()?.GetType().Name ?? "Object");
list.Add(new SelectionEntry { go = go, root = GetRoot(go.transform), depth = GetDepth(go.transform), sibling = go.transform.GetSiblingIndex(), major = maj, minor = min });
}
private static string GetUIType(GameObject go)
{
if (go.GetComponent("TextMeshProUGUI")) return "TMPro";
if (go.GetComponent<Text>()) return "Text";
if (go.GetComponent<Image>()) return "Image";
return "Rect";
}
private static GameObject GetRoot(Transform t) { while (t.parent != null) t = t.parent; return t.gameObject; }
private static int GetDepth(Transform t) { int d = 0; while (t.parent != null) { d++; t = t.parent; } return d; }
}
public class SelectionEntry { public GameObject go, root; public int depth, sibling; public string major, minor; }
public class QuickSelectorPopup : PopupWindowContent
{
private List<SelectionEntry> _entries;
private List<DisplayItem> _displayItems;
private Vector2 _scroll;
private GUIStyle _hoverStyle;
private GUIStyle _richLabelStyle; // 修正点:手动创建支持富文本的 Style
public QuickSelectorPopup(List<SelectionEntry> entries)
{
_entries = entries;
RefreshList();
}
public override Vector2 GetWindowSize() => new Vector2(280, Mathf.Min((_displayItems.Count * 22) + 30, 450));
public override void OnGUI(Rect rect)
{
// 样式初始化
if (_hoverStyle == null)
{
_hoverStyle = new GUIStyle(EditorStyles.label);
_hoverStyle.normal.background = MakeTex(2, 2, new Color(0.2f, 0.5f, 1f, 0.4f));
}
if (_richLabelStyle == null)
{
_richLabelStyle = new GUIStyle(EditorStyles.label);
_richLabelStyle.richText = true; // 关键修正:开启富文本支持
}
_scroll = EditorGUILayout.BeginScrollView(_scroll);
Event e = Event.current;
foreach (var item in _displayItems)
{
if (item.isSep) { EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); continue; }
Rect r = EditorGUILayout.GetControlRect(false, 20);
bool isHover = r.Contains(e.mousePosition);
if (isHover)
{
GUI.Box(r, "", _hoverStyle);
if (QuickSelectorHud.HoveredObject != item.ent.go)
{
QuickSelectorHud.HoveredObject = item.ent.go;
EditorGUIUtility.PingObject(item.ent.go);
SceneView.RepaintAll();
}
if (e.type == EventType.MouseDown && e.button == 0)
{
Selection.activeGameObject = item.ent.go;
this.editorWindow.Close();
}
}
// 使用修正后的富文本样式绘制
GUI.Label(r, item.label, _richLabelStyle);
}
EditorGUILayout.EndScrollView();
DrawToolbar();
if (e.type == EventType.MouseMove && !rect.Contains(e.mousePosition))
{
QuickSelectorHud.HoveredObject = null;
}
}
private void DrawToolbar()
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
if (GUILayout.Toggle(EditorPrefs.GetBool("QS_UI", true), "UI", EditorStyles.toolbarButton) != EditorPrefs.GetBool("QS_UI", true))
{
EditorPrefs.SetBool("QS_UI", !EditorPrefs.GetBool("QS_UI")); RefreshList();
}
if (GUILayout.Toggle(EditorPrefs.GetBool("QS_3D", true), "3D", EditorStyles.toolbarButton) != EditorPrefs.GetBool("QS_3D", true))
{
EditorPrefs.SetBool("QS_3D", !EditorPrefs.GetBool("QS_3D")); RefreshList();
}
GUILayout.FlexibleSpace();
if (GUILayout.Toggle(EditorPrefs.GetBool("QS_REV", false), "Reverse", EditorStyles.toolbarButton) != EditorPrefs.GetBool("QS_REV", false))
{
EditorPrefs.SetBool("QS_REV", !EditorPrefs.GetBool("QS_REV")); RefreshList();
}
GUILayout.EndHorizontal();
}
public override void OnClose() { QuickSelectorHud.HoveredObject = null; SceneView.RepaintAll(); }
private void RefreshList()
{
_displayItems = new List<DisplayItem>();
bool rev = EditorPrefs.GetBool("QS_REV", false);
var groups = _entries.GroupBy(x => x.root).OrderByDescending(g => g.Any(e => e.major == "UI")).ThenBy(g => g.Key.name);
bool first = true;
foreach (var g in groups)
{
if (!first) _displayItems.Add(new DisplayItem { isSep = true });
first = false;
var sorted = rev ? g.OrderByDescending(x => x.depth).ThenByDescending(x => x.sibling) : g.OrderBy(x => x.depth).ThenBy(x => x.sibling);
int minD = g.Min(x => x.depth);
int maxD = g.Max(x => x.depth);
foreach (var ent in sorted)
{
int ind = rev ? (maxD - ent.depth) : (ent.depth - minD);
string color = (ent.major == "UI" ? "#00E6FF" : "#AAAAAA"); // 调整 UI 标签为更亮的青色
string label = $"{new string(' ', ind * 4)}<color={color}>[{ent.major}|{ent.minor}]</color> {ent.go.name}";
_displayItems.Add(new DisplayItem { ent = ent, label = label });
}
}
if (editorWindow != null) editorWindow.Repaint();
}
private Texture2D MakeTex(int w, int h, Color col)
{
Color[] pix = new Color[w * h]; for (int i = 0; i < pix.Length; i++) pix[i] = col;
Texture2D t = new Texture2D(w, h); t.SetPixels(pix); t.Apply(); return t;
}
private class DisplayItem { public bool isSep; public SelectionEntry ent; public string label; }
}