Files
Cielonos/Assets/OtherPlugins/CoInspector/Editor/Windows/HierarchyPopup.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

475 lines
16 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace CoInspector
{
internal class HierarchyPopup : EditorWindow
{
private GameObject selectedGameObject;
static private GUIStyle labelStyle;
static private GUIStyle foldoutStyle;
static Vector2 lastPosition = Vector2.zero;
private Vector2 scrollPosition;
private Vector2 startPosition;
private float maxX = 0;
private float countUntilTarget = 0;
private int indentSize = 13;
private int hoveredIndent = -1;
private bool reachedTarget = false;
private bool resizedOnStart = false;
private bool firstScroll = false;
private bool hoveringIndent = false;
private CoInspectorWindow owner;
private Dictionary<GameObject, bool> expandedObjects = new Dictionary<GameObject, bool>();
private Dictionary<GameObject, int> pendingLines = new Dictionary<GameObject, int>();
private Color colorSelected = new Color(0.58f, 0.58f, 0.90f, 0.30f);
private Color lineColor;
bool colorGrid = false;
private float maxWidth = 0;
private float maxHeight = 0;
GameObject root;
internal static void ShowWindow(GameObject gameObject, CoInspectorWindow _owner, Vector2 mousePosition)
{
PopUpTip.Hide();
if (gameObject == null)
{
return;
}
InitializeStyles();
HierarchyPopup window = GetWindow<HierarchyPopup>(true, "Local Hierarchy");
window.InitializeHierarchy(gameObject, _owner, mousePosition);
}
internal static void InitializeStyles()
{
labelStyle = new GUIStyle(CustomGUIStyles.RichLabel);
labelStyle.stretchWidth = false;
labelStyle.margin = new RectOffset(0, 0, 0, 0);
labelStyle.padding = new RectOffset(0, 0, 0, 0);
labelStyle.fixedHeight = 16;
labelStyle.contentOffset = new Vector2(2, 2);
foldoutStyle = new GUIStyle(EditorStyles.foldout);
foldoutStyle.margin.top = 0;
foldoutStyle.margin.left = 4;
foldoutStyle.fixedHeight = 16;
foldoutStyle.fixedWidth = 1;
}
internal void InitializeHierarchy(GameObject gameObject, CoInspectorWindow _owner, Vector2 mousePosition)
{
lineColor = CustomColors.SimpleShadow;
if (EditorGUIUtility.isProSkin)
{
lineColor = new Color(0.4f, 0.4f, 0.4f, 1f);
}
startPosition = new Vector2(_owner.position.x, _owner.position.y);
startPosition.x += mousePosition.x;
startPosition.y += mousePosition.y + 80;
if (lastPosition != Vector2.zero)
{
startPosition = lastPosition;
}
maxX = _owner.position.xMax;
selectedGameObject = gameObject;
owner = _owner;
root = FindContextualRoot(gameObject);
titleContent = new GUIContent("Local Hierarchy of '" + gameObject.name + "'");
if (gameObject.transform.parent == null)
{
float width = CustomGUIStyles.WrapLabelStyle.CalcSize(new GUIContent("<i>Root-level siblings are not shown!</i>")).x + 40;
minSize = new Vector2(width, 100);
}
Focus();
ExpandPath(gameObject);
}
GameObject FindContextualRoot(GameObject gameObject)
{
Transform current = gameObject.transform;
while (current.parent != null)
{
current = current.parent;
}
return current.gameObject;
}
float ScrollToPosition(float _height, float targetY)
{
targetY -= 18;
float centeredPosition = targetY - (_height / 2);
return centeredPosition;
}
void OnGUI()
{
GUI.backgroundColor *= 0.97f;
if (selectedGameObject == null || root == null)
{
EditorGUILayout.LabelField("<i>No GameObject selected!</i>");
return;
}
pendingLines.Clear();
pendingLines.Add(root, 0);
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
EditorGUILayout.BeginHorizontal();
GUILayout.Space(3);
EditorGUILayout.BeginVertical();
GUILayout.Space(3);
bool changed = false;
if (Event.current.type == EventType.Repaint)
{
hoveringIndent = false;
}
EditorGUI.BeginChangeCheck();
DrawGameObject(root, 0);
if (EditorGUI.EndChangeCheck())
{
changed = true;
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
if (expandedObjects != null && expandedObjects.ContainsKey(root) && (expandedObjects.Count == 1 || expandedObjects[root] == false))
{
CustomGUIStyles.InfoLabel("<i>Root-level siblings are not shown!</i>");
}
EditorGUILayout.EndScrollView();
if (!resizedOnStart)
{
Resize();
}
if (changed)
{
ResetSize();
}
if (!hoveringIndent)
{
hoveredIndent = -1;
}
}
private void ResetSize()
{
resizedOnStart = false;
maxHeight = 0;
maxWidth = 0;
Repaint();
}
private void Resize()
{
if (reachedTarget)
{
float height = 500;
if (maxHeight < height)
{
height = maxHeight;
}
if (height > maxHeight)
{
height = maxHeight;
}
Rect newRect;
if (firstScroll)
{
newRect = new Rect(position.x, position.y, maxWidth, height + 40);
}
else
{
newRect = new Rect(startPosition.x, startPosition.y, maxWidth, height + 40);
if (lastPosition == Vector2.zero)
{
newRect.x -= maxWidth / 2;
}
}
if (newRect.xMax > maxX)
{
newRect.x = maxX - newRect.width;
}
if (newRect.x < 0)
{
newRect.x = 0;
}
if (!firstScroll && newRect.height > 400)
{
newRect.height = 400;
}
if (newRect.width < 200)
{
newRect.width = 200;
}
if (!firstScroll && lastPosition == Vector2.zero)
{
newRect.x -= 60;
}
newRect.width += 25;
newRect.height -= 30;
newRect.x = position.x;
newRect.y = position.y;
position = newRect;
resizedOnStart = true;
if (!firstScroll)
{
firstScroll = true;
scrollPosition.y = ScrollToPosition(newRect.height, countUntilTarget);
}
Repaint();
}
}
private void OnDestroy()
{
lastPosition = position.position;
}
private void ShowContextMenu(GameObject obj)
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Open in current Tab"), false, () =>
{
owner.SetTargetGameObject(obj);
Close();
});
menu.AddItem(new GUIContent("Open in new Tab"), false, () =>
{
owner.AddTabNext();
owner.SetTargetGameObject(obj);
Close();
});
menu.AddSeparator("");
menu.AddItem(new GUIContent("Select in Hierarchy"), false, () =>
{
owner.ignoreNextSelection = true;
Selection.activeGameObject = obj;
Close();
}
);
menu.AddSeparator("");
menu.AddItem(new GUIContent("Ping in Hierarchy"), false, () => EditorGUIUtility.PingObject(obj));
menu.AddItem(new GUIContent("Frame on Scene View"), false, () => EditorUtils.FocusOnSceneView(obj));
menu.ShowAsContext();
}
private void OnLostFocus()
{
Close();
}
void DrawGameObject(GameObject obj, int indentLevel, int childIndex = 0)
{
if ((obj.hideFlags & HideFlags.HideInHierarchy) != 0)
{
return;
}
bool hasChildren = obj.transform.childCount > 0;
if (!resizedOnStart)
{
maxHeight += 18;
}
if (!reachedTarget)
{
countUntilTarget += 18;
}
GUILayout.BeginHorizontal(CustomGUIStyles.InspectorButtonStyle, GUILayout.Height(18));
GUILayout.Space(indentLevel * indentSize);
Texture2D icon = EditorUtils.GetBestFittingIconForGameObject(obj);
string _name = obj.name;
if (obj == selectedGameObject)
{
_name = "<b>" + _name + "</b>";
}
GUIContent content = new GUIContent(" " + _name, icon);
bool isExpanded = expandedObjects.ContainsKey(obj) && expandedObjects[obj];
bool drawFoldout = hasChildren;
GUIStyle _labelStyle = labelStyle;
GUIStyle _foldoutStyle = foldoutStyle;
if (drawFoldout)
{
drawFoldout = false;
foreach (Transform child in obj.transform)
{
if ((child.gameObject.hideFlags & HideFlags.HideInHierarchy) == 0)
{
drawFoldout = true;
break;
}
}
}
if (drawFoldout)
{
isExpanded = EditorGUILayout.Foldout(isExpanded, "", false, _foldoutStyle);
expandedObjects[obj] = isExpanded;
}
GUILayout.EndHorizontal();
Rect rect = GUILayoutUtility.GetLastRect();
Rect savedRect = new Rect(rect);
if (obj == selectedGameObject)
{
Rect rect1 = new Rect(rect);
rect1.height = 20;
//rect1.y += 2;
EditorGUI.DrawRect(rect1, colorSelected);
}
if (selectedGameObject == obj)
{
reachedTarget = true;
}
else if (selectedGameObject.transform.parent == null)
{
reachedTarget = true;
}
Rect clickRect = new Rect(rect);
bool hovered = false;
bool partiallyHovered = false;
if (clickRect.Contains(Event.current.mousePosition))
{
partiallyHovered = true;
if (Event.current.mousePosition.x > indentLevel * indentSize + 16)
{
hovered = true;
if (Event.current.type == EventType.MouseDown)
{
Event.current.Use();
if (Event.current.button == 0)
{
owner.SetTargetGameObject(obj);
owner.SetScrollPosition();
Close();
}
else if (Event.current.button == 1)
{
ShowContextMenu(obj);
}
else if (Event.current.button == 2)
{
owner.AddTabNext();
owner.SetTargetGameObject(obj);
Close();
}
}
}
}
if (hovered || obj == selectedGameObject)
{
_labelStyle.normal.textColor = Color.white;
}
else
{
_labelStyle.normal.textColor = GUI.skin.label.normal.textColor;
}
GUIContent content1 = new GUIContent(obj.name);
_labelStyle.padding.left = 14 + (indentLevel * indentSize);
_labelStyle.hover.textColor = _labelStyle.normal.textColor;
float width = _labelStyle.CalcSize(content1).x + 25;
if (width > maxWidth)
{
maxWidth = width;
}
rect.width = width;
rect.x += 2;
rect.y -= 2;
GUILayoutUtility.GetRect(width, 0);
GUI.Label(rect, content.image, _labelStyle);
rect.x += 15;
GUI.Label(rect, content.text, _labelStyle);
colorGrid = !colorGrid;
DrawTreeLines(savedRect, obj, indentLevel, hasChildren, partiallyHovered);
int childCount = obj.transform.childCount;
if (isExpanded)
{
int lastIndex = obj.transform.childCount - 1;
if (hasChildren)
{
pendingLines.Add(obj.transform.GetChild(lastIndex).gameObject, indentLevel + 1);
}
for (int i = 0; i < obj.transform.childCount; i++)
{
Transform child = obj.transform.GetChild(i);
DrawGameObject(child.gameObject, indentLevel + 1, lastIndex - i);
}
}
}
void DrawTreeLines(Rect originalRect, GameObject obj, int indentLevel, bool hasChildren, bool partiallyHovered)
{
if (indentLevel > 0)
{
Rect rect = new Rect(originalRect);
rect.height = 1;
rect.width = 7;
rect.y += 7;
rect.x = indentLevel * indentSize + 1;
Color _lineColor = lineColor;
if (partiallyHovered || obj == selectedGameObject)
{
_lineColor = Color.white * 0.65f;
}
EditorUtils.DrawLineUnderRect(rect, _lineColor);
if (!hasChildren)
{
rect.x += 9;
rect.width = 7;
EditorUtils.DrawLineUnderRect(rect, _lineColor);
}
foreach (var item in pendingLines)
{
rect = new Rect(originalRect);
rect.x = item.Value * indentSize;
rect.width = 1;
if (item.Key == obj)
{
rect.height = 8;
}
else
{
// rect.y += 3;
rect.height = 18;
}
Rect rect2 = new Rect(rect);
rect.width = 7;
rect.x -= 2;
EditorGUIUtility.AddCursorRect(rect, MouseCursor.Link);
{
if (rect.Contains(Event.current.mousePosition))
{
hoveredIndent = item.Value;
hoveringIndent = true;
if (Event.current.type == EventType.MouseDown)
{
expandedObjects[item.Key.transform.parent.gameObject] = false;
GUI.changed = true;
}
}
}
EditorGUI.DrawRect(rect2, _lineColor);
}
if (pendingLines.ContainsKey(obj))
{
pendingLines.Remove(obj);
}
}
}
void ExpandPath(GameObject gameObject)
{
Transform current = gameObject.transform;
while (current != null)
{
expandedObjects[current.gameObject] = true;
current = current.parent;
}
}
}
}