Skip to content

Commit 3043365

Browse files
committed
Merge remote-tracking branch 'origin/master' into develop
2 parents 724d6ee + bc2a486 commit 3043365

File tree

2 files changed

+171
-28
lines changed

2 files changed

+171
-28
lines changed

Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs

Lines changed: 168 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@ namespace Toolbox.Editor.SceneView
77
public class ToolboxEditorSceneViewObjectSelector : EditorWindow
88
{
99
private static readonly Color selectionColor = new Color(0.50f, 0.70f, 1.00f);
10+
private static readonly Color highlightWireColor = Color.yellow;
11+
private const float outlineFillOpacity = 1f;
1012

1113
private const float sizeXPadding = 2f;
1214
private const float sizeYPadding = 2f;
1315
private const float buttonYSpacing = 0.0f;
1416
private const float buttonYSize = 20f;
1517
private const float sizeXOffset = -30f;
18+
private const float indentWidth = 12f;
1619

17-
private List<GameObject> gameObjects;
18-
private List<string> gameObjectPaths;
20+
private List<DisplayEntry> displayEntries;
1921

2022
private GameObject highlightedObject;
23+
private readonly List<Renderer> highlightedRenderers = new List<Renderer>();
2124
private Vector2 size;
2225
private Vector2 buttonSize;
2326

@@ -32,12 +35,23 @@ public static void Show(List<GameObject> gameObjects, Vector2 position)
3235
var window = CreateInstance<ToolboxEditorSceneViewObjectSelector>();
3336
window.wantsMouseMove = true;
3437
window.wantsMouseEnterLeaveWindow = true;
35-
window.gameObjects = gameObjects;
36-
window.InitializeGameObjectPaths();
38+
window.displayEntries = window.BuildDisplayEntries(gameObjects);
3739
window.CalculateSize();
3840
window.ShowAsDropDown(rect, window.size);
3941
}
4042

43+
private void OnEnable()
44+
{
45+
UnityEditor.SceneView.duringSceneGui += OnSceneViewDuringSceneGui;
46+
}
47+
48+
private void OnDisable()
49+
{
50+
UnityEditor.SceneView.duringSceneGui -= OnSceneViewDuringSceneGui;
51+
highlightedRenderers.Clear();
52+
highlightedObject = null;
53+
}
54+
4155
private void OnGUI()
4256
{
4357
if (Event.current.type == EventType.Layout)
@@ -67,18 +81,24 @@ private void OnGuiMouseLeave()
6781
private void OnGuiMouseMove()
6882
{
6983
var rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y);
70-
for (var i = 0; i < gameObjects.Count; i++)
84+
for (var i = 0; i < displayEntries.Count; i++)
7185
{
72-
var gameObject = gameObjects[i];
86+
var entry = displayEntries[i];
87+
var gameObject = entry.GameObject;
7388
if (gameObject == null)
7489
{
7590
//Can happen when something removes the gameobject during the window display.
7691
continue;
7792
}
7893

94+
var indentOffset = entry.Depth * indentWidth;
95+
var drawRect = new Rect(rect);
96+
drawRect.x += indentOffset;
97+
drawRect.width -= indentOffset;
98+
7999
var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject));
80-
GUI.Button(rect, content, Style.buttonStyle);
81-
if (rect.Contains(Event.current.mousePosition))
100+
GUI.Button(drawRect, content, Style.buttonStyle);
101+
if (drawRect.Contains(Event.current.mousePosition))
82102
{
83103
HighlightedObject = gameObject;
84104
}
@@ -90,23 +110,29 @@ private void OnGuiMouseMove()
90110
private void OnGuiNormal()
91111
{
92112
var rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y);
93-
for (var i = 0; i < gameObjects.Count; i++)
113+
for (var i = 0; i < displayEntries.Count; i++)
94114
{
95-
var gameObject = gameObjects[i];
115+
var entry = displayEntries[i];
116+
var gameObject = entry.GameObject;
96117
if (gameObject == null)
97118
{
98119
//Can happen when something removes the gameobject during the window display.
99120
continue;
100121
}
101122

123+
var indentOffset = entry.Depth * indentWidth;
124+
var drawRect = new Rect(rect);
125+
drawRect.x += indentOffset;
126+
drawRect.width -= indentOffset;
127+
102128
var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject));
103129
var objectSelected = Selection.Contains(gameObject);
104130
if (objectSelected)
105131
{
106132
GUI.backgroundColor = selectionColor;
107133
}
108134

109-
if (GUI.Button(rect, content, Style.buttonStyle))
135+
if (GUI.Button(drawRect, content, Style.buttonStyle))
110136
{
111137
GameObjectButtonPress(i);
112138
}
@@ -120,47 +146,107 @@ private Vector2 CalculateSize()
120146
{
121147
size = Vector2.zero;
122148

123-
foreach (var go in gameObjects)
149+
var maxIndent = 0f;
150+
foreach (var entry in displayEntries)
124151
{
125-
var content = EditorGUIUtility.ObjectContent(go, typeof(GameObject));
152+
var content = EditorGUIUtility.ObjectContent(entry.GameObject, typeof(GameObject));
126153
var currentSize = Style.buttonStyle.CalcSize(content);
127154
if (currentSize.x > size.x)
128155
{
129156
size.x = currentSize.x;
130157
}
158+
159+
var currentIndent = entry.Depth * indentWidth;
160+
if (currentIndent > maxIndent)
161+
{
162+
maxIndent = currentIndent;
163+
}
131164
}
132165

166+
size.x += maxIndent;
133167
//This is needed because CalcSize calculates content drawing with icon at full size.
134168
size.x += sizeXOffset;
135169

136170
buttonSize.x = size.x;
137171
buttonSize.y = buttonYSize;
138172

139-
size.y = gameObjects.Count * buttonYSize + sizeYPadding * 2.0f + buttonYSpacing * gameObjects.Count - 1;
173+
size.y = displayEntries.Count * buttonYSize + sizeYPadding * 2.0f + buttonYSpacing * displayEntries.Count - 1;
140174
size.x += sizeXPadding * 2.0f;
141175

142176
return size;
143177
}
144178

145-
private void InitializeGameObjectPaths()
179+
private List<DisplayEntry> BuildDisplayEntries(List<GameObject> objectsUnderCursor)
146180
{
147-
gameObjectPaths = new List<string>();
148-
var pathStack = new Stack<string>();
181+
var entries = new List<DisplayEntry>();
182+
183+
if (objectsUnderCursor == null || objectsUnderCursor.Count == 0)
184+
{
185+
return entries;
186+
}
187+
188+
var underCursorSet = new HashSet<Transform>();
189+
foreach (var gameObject in objectsUnderCursor)
190+
{
191+
if (gameObject == null)
192+
{
193+
continue;
194+
}
195+
196+
underCursorSet.Add(gameObject.transform);
197+
}
198+
199+
var relevantTransforms = new HashSet<Transform>();
200+
foreach (var transform in underCursorSet)
201+
{
202+
var current = transform;
203+
while (current != null && relevantTransforms.Add(current))
204+
{
205+
current = current.parent;
206+
}
207+
}
208+
209+
var orderedRoots = new List<Transform>();
210+
foreach (var gameObject in objectsUnderCursor)
211+
{
212+
if (gameObject == null)
213+
{
214+
continue;
215+
}
216+
217+
var top = gameObject.transform;
218+
while (top.parent != null && relevantTransforms.Contains(top.parent))
219+
{
220+
top = top.parent;
221+
}
222+
223+
if (!orderedRoots.Contains(top))
224+
{
225+
orderedRoots.Add(top);
226+
}
227+
}
149228

150-
for (var i = 0; i < gameObjects.Count; i++)
229+
foreach (var root in orderedRoots)
151230
{
152-
pathStack.Clear();
153-
var transform = gameObjects[i].transform;
154-
pathStack.Push(transform.gameObject.name);
231+
AppendHierarchy(root, 0, relevantTransforms, entries);
232+
}
233+
234+
return entries;
235+
}
236+
237+
private void AppendHierarchy(Transform current, int depth, HashSet<Transform> relevantTransforms, List<DisplayEntry> entries)
238+
{
239+
entries.Add(new DisplayEntry(current.gameObject, depth));
155240

156-
while (transform.parent != null)
241+
for (var i = 0; i < current.childCount; i++)
242+
{
243+
var child = current.GetChild(i);
244+
if (!relevantTransforms.Contains(child))
157245
{
158-
transform = transform.parent;
159-
pathStack.Push(transform.gameObject.name);
246+
continue;
160247
}
161248

162-
var path = string.Join("/", pathStack.ToArray());
163-
gameObjectPaths.Add(path);
249+
AppendHierarchy(child, depth + 1, relevantTransforms, entries);
164250
}
165251
}
166252

@@ -218,7 +304,7 @@ private void UpdateShiftSelectionIDs(int id)
218304

219305
private void SelectObject(int id, bool control, bool shift)
220306
{
221-
var gameObject = gameObjects[id];
307+
var gameObject = displayEntries[id].GameObject;
222308

223309
if (shift)
224310
{
@@ -252,7 +338,7 @@ private void SelectObjects(int minId, int maxId)
252338

253339
for (var i = minId; i <= maxId; i++)
254340
{
255-
newSelection[index] = gameObjects[i];
341+
newSelection[index] = displayEntries[i].GameObject;
256342
index++;
257343
}
258344

@@ -307,9 +393,63 @@ private GameObject HighlightedObject
307393
{
308394
EditorGUIUtility.PingObject(highlightedObject);
309395
}
396+
397+
UpdateHighlightedRenderers();
310398
}
311399
}
312400

401+
private void UpdateHighlightedRenderers()
402+
{
403+
highlightedRenderers.Clear();
404+
405+
if (highlightedObject == null)
406+
{
407+
return;
408+
}
409+
410+
highlightedRenderers.AddRange(highlightedObject.GetComponentsInChildren<Renderer>(true));
411+
}
412+
413+
private void OnSceneViewDuringSceneGui(UnityEditor.SceneView sceneView)
414+
{
415+
if (highlightedRenderers.Count == 0 ||
416+
Event.current.type != EventType.Repaint)
417+
{
418+
return;
419+
}
420+
421+
// Unity 6.1+ provides Handles.DrawOutline which also highlights children in one call.
422+
#if UNITY_6000_1_OR_NEWER
423+
Handles.DrawOutline(highlightedRenderers.ToArray(), highlightWireColor, highlightWireColor, outlineFillOpacity);
424+
#else
425+
using (new Handles.DrawingScope(highlightWireColor))
426+
{
427+
foreach (var renderer in highlightedRenderers)
428+
{
429+
if (renderer == null)
430+
{
431+
continue;
432+
}
433+
434+
var bounds = renderer.bounds;
435+
Handles.DrawWireCube(bounds.center, bounds.size);
436+
}
437+
}
438+
#endif
439+
}
440+
441+
private readonly struct DisplayEntry
442+
{
443+
internal DisplayEntry(GameObject gameObject, int depth)
444+
{
445+
GameObject = gameObject;
446+
Depth = depth;
447+
}
448+
449+
internal GameObject GameObject { get; }
450+
internal int Depth { get; }
451+
}
452+
313453
private static class Style
314454
{
315455
internal static readonly GUIStyle buttonStyle;

Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ public static void OverrideLabelByValue(GUIContent label, SerializedProperty pro
428428
case SerializedPropertyType.ObjectReference:
429429
label.text = property.objectReferenceValue ? property.objectReferenceValue.ToString() : "null";
430430
break;
431+
case SerializedPropertyType.ManagedReference:
432+
label.text = property.managedReferenceValue?.ToString() ?? "null";
433+
break;
431434
case SerializedPropertyType.LayerMask:
432435
switch (property.intValue)
433436
{

0 commit comments

Comments
 (0)