Skip to content

Commit b3a1893

Browse files
authored
Merge pull request #79 from Grizmu/develop
Added scene view extension flow with a scene object picker
2 parents a32a602 + 4b1e6af commit b3a1893

12 files changed

Lines changed: 999 additions & 6 deletions

Assets/Editor Toolbox/Editor/SceneView.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
using System.Collections.Generic;
2+
using UnityEditor;
3+
using UnityEngine;
4+
5+
namespace Toolbox.Editor.SceneView
6+
{
7+
public class ToolboxEditorSceneViewObjectSelector : EditorWindow
8+
{
9+
private List<GameObject> gameObjects;
10+
private List<string> gameObjectPaths;
11+
12+
private const float sizeXPadding = 2f;
13+
private const float sizeYPadding = 2f;
14+
private const float buttonYSpacing = 0.0f;
15+
private const float buttonYSize = 20f;
16+
private const float sizeXOffset = -30f;
17+
18+
private GameObject highlightedObject;
19+
private Vector2 size;
20+
private Vector2 buttonSize;
21+
private static readonly Color selectionColor = new Color(0.50f, 0.70f, 1.00f);
22+
23+
private int shiftMinSelectionId = -1;
24+
private int shiftMaxSelectionId = -1;
25+
private int shiftLastId = -1;
26+
27+
public static void Show(List<GameObject> gameObjects, Vector2 position)
28+
{
29+
var rect = new Rect(position, Vector2.one);
30+
31+
var window = CreateInstance<ToolboxEditorSceneViewObjectSelector>();
32+
window.wantsMouseMove = true;
33+
window.wantsMouseEnterLeaveWindow = true;
34+
window.gameObjects = gameObjects;
35+
window.InitializeGameObjectPaths();
36+
window.CalculateSize();
37+
window.ShowAsDropDown(rect, window.size);
38+
}
39+
40+
private Vector2 CalculateSize()
41+
{
42+
size = Vector2.zero;
43+
44+
foreach (var go in gameObjects)
45+
{
46+
GUIContent content = EditorGUIUtility.ObjectContent(go, typeof(GameObject));
47+
Vector2 currentSize = Style.buttonStyle.CalcSize(content);
48+
if (currentSize.x > size.x)
49+
{
50+
size.x = currentSize.x;
51+
}
52+
}
53+
54+
//This is needed because CalcSize calculates content drawing with icon at full size.
55+
size.x += sizeXOffset;
56+
57+
buttonSize.x = size.x;
58+
buttonSize.y = buttonYSize;
59+
60+
size.y = gameObjects.Count * buttonYSize + sizeYPadding * 2.0f + buttonYSpacing * gameObjects.Count - 1;
61+
size.x += sizeXPadding * 2.0f;
62+
63+
return size;
64+
}
65+
66+
private void InitializeGameObjectPaths()
67+
{
68+
gameObjectPaths = new List<string>();
69+
var pathStack = new Stack<string>();
70+
71+
for (int i = 0; i < gameObjects.Count; i++)
72+
{
73+
pathStack.Clear();
74+
Transform transform = gameObjects[i].transform;
75+
pathStack.Push(transform.gameObject.name);
76+
77+
while (transform.parent != null)
78+
{
79+
transform = transform.parent;
80+
pathStack.Push(transform.gameObject.name);
81+
}
82+
83+
string path = string.Join("/", pathStack.ToArray());
84+
gameObjectPaths.Add(path);
85+
}
86+
}
87+
88+
private void OnGUI()
89+
{
90+
if (Event.current.type == EventType.Layout)
91+
{
92+
return;
93+
}
94+
95+
switch (Event.current.type)
96+
{
97+
case EventType.MouseMove:
98+
{
99+
OnGUIMouseMove();
100+
break;
101+
}
102+
case EventType.MouseLeaveWindow:
103+
{
104+
OnGUIMouseLeave();
105+
break;
106+
}
107+
default:
108+
{
109+
OnGUINormal();
110+
break;
111+
}
112+
}
113+
}
114+
115+
private void OnGUINormal()
116+
{
117+
Rect rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y);
118+
119+
for (int i = 0; i < gameObjects.Count; i++)
120+
{
121+
var gameObject = gameObjects[i];
122+
123+
if(gameObject == null)
124+
{
125+
//Can happen when something removes the gameobject during the window display.
126+
continue;
127+
}
128+
129+
var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject));
130+
131+
bool objectSelected = Selection.Contains(gameObject);
132+
133+
if (objectSelected)
134+
{
135+
GUI.backgroundColor = selectionColor;
136+
}
137+
138+
if (GUI.Button(rect, content, Style.buttonStyle))
139+
{
140+
GameObjectButtonPress(i);
141+
}
142+
143+
GUI.backgroundColor = Color.white;
144+
145+
rect.y += buttonYSize + buttonYSpacing;
146+
}
147+
}
148+
149+
private void OnGUIMouseMove()
150+
{
151+
var rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y);
152+
153+
for (int i = 0; i < gameObjects.Count; i++)
154+
{
155+
var gameObject = gameObjects[i];
156+
157+
if (gameObject == null)
158+
{
159+
//Can happen when something removes the gameobject during the window display.
160+
continue;
161+
}
162+
163+
var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject));
164+
165+
GUI.Button(rect, content, Style.buttonStyle);
166+
167+
if (rect.Contains(Event.current.mousePosition))
168+
{
169+
HighlightedObject = gameObject;
170+
}
171+
172+
rect.y += buttonYSize + buttonYSpacing;
173+
}
174+
}
175+
176+
private void GameObjectButtonPress(int id)
177+
{
178+
SelectObject(id, Event.current.control, Event.current.shift);
179+
180+
if (Event.current.control || Event.current.shift)
181+
{
182+
return;
183+
}
184+
185+
Close();
186+
}
187+
188+
private void UpdateShiftSelectionIDs(int id)
189+
{
190+
if(shiftLastId == -1)
191+
{
192+
shiftLastId = id;
193+
}
194+
195+
if(shiftMinSelectionId == -1)
196+
{
197+
shiftMinSelectionId = id;
198+
}
199+
200+
if (shiftMaxSelectionId == -1)
201+
{
202+
shiftMaxSelectionId = id;
203+
}
204+
205+
if(id < shiftMinSelectionId)
206+
{
207+
shiftMinSelectionId = id;
208+
}
209+
else if(id >= shiftMaxSelectionId)
210+
{
211+
shiftMaxSelectionId = id;
212+
}
213+
else if(id > shiftMinSelectionId)
214+
{
215+
//ID is between min and max.
216+
if(shiftLastId < id)
217+
{
218+
shiftMaxSelectionId = id;
219+
}
220+
else
221+
{
222+
shiftMinSelectionId = id;
223+
}
224+
}
225+
226+
shiftLastId = id;
227+
}
228+
229+
private void SelectObject(int id, bool control, bool shift)
230+
{
231+
var gameObject = gameObjects[id];
232+
233+
if (shift)
234+
{
235+
UpdateShiftSelectionIDs(id);
236+
SelectObjects(shiftMinSelectionId, shiftMaxSelectionId);
237+
}
238+
else if (control)
239+
{
240+
UpdateShiftSelectionIDs(id);
241+
242+
if (Selection.Contains(gameObject))
243+
{
244+
//Deselect
245+
RemoveObjectFromSelection(gameObject);
246+
}
247+
else
248+
{
249+
//Select
250+
AddObjectToSelection(gameObject);
251+
}
252+
}
253+
else
254+
{
255+
Selection.objects = new Object[] { gameObject };
256+
}
257+
}
258+
259+
private void SelectObjects(int minID, int maxID)
260+
{
261+
var size = maxID - minID + 1;
262+
var newSelection = new Object[size];
263+
264+
int index = 0;
265+
266+
for (int i = minID; i <= maxID; i++)
267+
{
268+
newSelection[index] = gameObjects[i];
269+
index++;
270+
}
271+
272+
Selection.objects = newSelection;
273+
}
274+
275+
private void AddObjectToSelection(GameObject gameObject)
276+
{
277+
var currentSelection = Selection.objects;
278+
var newSelection = new Object[currentSelection.Length + 1];
279+
280+
currentSelection.CopyTo(newSelection, 0);
281+
newSelection[newSelection.Length - 1] = gameObject;
282+
283+
Selection.objects = newSelection;
284+
}
285+
286+
private void RemoveObjectFromSelection(GameObject gameObject)
287+
{
288+
var currentSelection = Selection.objects;
289+
var newSelection = new Object[currentSelection.Length - 1];
290+
291+
var index = 0;
292+
293+
for (int i = 0; i < currentSelection.Length; i++)
294+
{
295+
if (currentSelection[i] == gameObject)
296+
{
297+
continue;
298+
}
299+
300+
newSelection[index] = currentSelection[i];
301+
index++;
302+
}
303+
304+
Selection.objects = newSelection;
305+
}
306+
307+
private void OnGUIMouseLeave()
308+
{
309+
HighlightedObject = null;
310+
}
311+
312+
private GameObject HighlightedObject
313+
{
314+
set
315+
{
316+
if (highlightedObject == value)
317+
{
318+
return;
319+
}
320+
321+
highlightedObject = value;
322+
UnityEditor.SceneView.RepaintAll();
323+
324+
if (highlightedObject != null)
325+
{
326+
EditorGUIUtility.PingObject(highlightedObject);
327+
}
328+
}
329+
}
330+
331+
private static class Style
332+
{
333+
internal static readonly GUIStyle buttonStyle;
334+
335+
static Style()
336+
{
337+
buttonStyle = new GUIStyle(GUI.skin.button);
338+
buttonStyle.alignment = TextAnchor.MiddleLeft;
339+
}
340+
}
341+
}
342+
}

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

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)