@@ -9,13 +9,21 @@ public class ToolboxEditorSceneViewObjectSelector : EditorWindow
99 private List < GameObject > gameObjects ;
1010 private List < string > gameObjectPaths ;
1111
12- private const float sizeXPadding = 8f ;
13- private const float sizeYPadding = 4f ;
14- private const float sizeYspacing = 2.0f ;
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 ;
1517
1618 private GameObject highlightedObject ;
1719 private Vector2 size ;
20+ private Vector2 buttonSize ;
1821 private GUIStyle buttonStyle ;
22+ private Color selectionColor = new Color ( 0.50f , 0.70f , 1.00f ) ;
23+
24+ private int shiftMinSelectionID = - 1 ;
25+ private int shiftMaxSelectionID = - 1 ;
26+ private int shiftLastID = - 1 ;
1927
2028 private GameObject HighlightedObject
2129 {
@@ -27,8 +35,12 @@ private GameObject HighlightedObject
2735 }
2836
2937 highlightedObject = value ;
30- Selection . activeGameObject = value ;
3138 UnityEditor . SceneView . RepaintAll ( ) ;
39+
40+ if ( highlightedObject != null )
41+ {
42+ EditorGUIUtility . PingObject ( highlightedObject ) ;
43+ }
3244 }
3345 }
3446
@@ -58,24 +70,26 @@ private Vector2 CalculateSize()
5870 InitializeStyle ( ) ;
5971 }
6072
61- GUIContent content = new GUIContent ( ) ;
62-
6373 size = Vector2 . zero ;
6474
65- foreach ( string path in gameObjectPaths )
75+ foreach ( GameObject go in gameObjects )
6676 {
67- content . text = path ;
77+ GUIContent content = EditorGUIUtility . ObjectContent ( go , typeof ( GameObject ) ) ;
6878 Vector2 currentSize = buttonStyle . CalcSize ( content ) ;
6979 if ( currentSize . x > size . x )
7080 {
7181 size . x = currentSize . x ;
7282 }
73-
74- size . y += currentSize . y + sizeYspacing ;
7583 }
7684
77- size . x += sizeXPadding ;
78- size . y += sizeYPadding ;
85+ //This is needed because CalcSize calculates content drawing with icon at full size.
86+ size . x += sizeXOffset ;
87+
88+ buttonSize . x = size . x ;
89+ buttonSize . y = buttonYSize ;
90+
91+ size . y = gameObjects . Count * buttonYSize + sizeYPadding * 2.0f + buttonYSpacing * gameObjects . Count - 1 ;
92+ size . x += sizeXPadding * 2.0f ;
7993
8094 return size ;
8195 }
@@ -109,6 +123,11 @@ private void OnGUI()
109123 InitializeStyle ( ) ;
110124 }
111125
126+ if ( Event . current . type == EventType . Layout )
127+ {
128+ return ;
129+ }
130+
112131 //Debug.Log($"Event : {Event.current.type}");
113132
114133 if ( Event . current . type == EventType . MouseMove )
@@ -127,37 +146,194 @@ private void OnGUI()
127146
128147 private void OnGUI_Normal ( )
129148 {
149+ Rect rect = new Rect ( sizeXPadding , sizeYPadding , buttonSize . x , buttonSize . y ) ;
150+
130151 for ( int i = 0 ; i < gameObjects . Count ; i ++ )
131152 {
132153 GameObject gameObject = gameObjects [ i ] ;
133- if ( GUILayout . Button ( gameObjectPaths [ i ] , buttonStyle ) )
154+
155+ if ( gameObject == null )
134156 {
135- Selection . activeGameObject = gameObject ;
136- Event . current . Use ( ) ;
137- Close ( ) ;
157+ //Can happen when something removes the gameobject during the window display.
158+ continue ;
138159 }
160+
161+ GUIContent content = EditorGUIUtility . ObjectContent ( gameObject , typeof ( GameObject ) ) ;
162+
163+ bool objectSelected = Selection . Contains ( gameObject ) ;
164+
165+ if ( objectSelected )
166+ {
167+ GUI . backgroundColor = selectionColor ;
168+ }
169+
170+ if ( GUI . Button ( rect , content , buttonStyle ) )
171+ {
172+ GameObjectButtonPress ( i ) ;
173+ }
174+
175+ GUI . backgroundColor = Color . white ;
176+
177+ rect . y += buttonYSize + buttonYSpacing ;
139178 }
140179 }
141180
142181 private void OnGUI_MouseMove ( )
143182 {
183+ Rect rect = new Rect ( sizeXPadding , sizeYPadding , buttonSize . x , buttonSize . y ) ;
184+
144185 for ( int i = 0 ; i < gameObjects . Count ; i ++ )
145186 {
146187 GameObject gameObject = gameObjects [ i ] ;
147- if ( GUILayout . Button ( gameObjectPaths [ i ] , buttonStyle ) )
188+
189+ if ( gameObject == null )
148190 {
149- Selection . activeGameObject = gameObject ;
150- Event . current . Use ( ) ;
151- Close ( ) ;
191+ //Can happen when something removes the gameobject during the window display.
192+ continue ;
152193 }
153194
154- Rect lastRect = GUILayoutUtility . GetLastRect ( ) ;
195+ GUIContent content = EditorGUIUtility . ObjectContent ( gameObject , typeof ( GameObject ) ) ;
155196
156- if ( lastRect . Contains ( Event . current . mousePosition ) )
197+ GUI . Button ( rect , content , buttonStyle ) ;
198+
199+ if ( rect . Contains ( Event . current . mousePosition ) )
157200 {
158201 HighlightedObject = gameObject ;
159202 }
203+
204+ rect . y += buttonYSize + buttonYSpacing ;
205+ }
206+ }
207+
208+ private void GameObjectButtonPress ( int id )
209+ {
210+ SelectObject ( id , Event . current . control , Event . current . shift ) ;
211+
212+ if ( Event . current . control || Event . current . shift )
213+ {
214+ return ;
215+ }
216+
217+ Close ( ) ;
218+ }
219+
220+ private void UpdateShiftSelectionIDs ( int id )
221+ {
222+ if ( shiftLastID == - 1 )
223+ {
224+ shiftLastID = id ;
225+ }
226+
227+ if ( shiftMinSelectionID == - 1 )
228+ {
229+ shiftMinSelectionID = id ;
230+ }
231+
232+ if ( shiftMaxSelectionID == - 1 )
233+ {
234+ shiftMaxSelectionID = id ;
235+ }
236+
237+ if ( id < shiftMinSelectionID )
238+ {
239+ shiftMinSelectionID = id ;
160240 }
241+ else if ( id >= shiftMaxSelectionID )
242+ {
243+ shiftMaxSelectionID = id ;
244+ }
245+ else if ( id > shiftMinSelectionID )
246+ {
247+ //ID is between min and max.
248+ if ( shiftLastID < id )
249+ {
250+ shiftMaxSelectionID = id ;
251+ }
252+ else
253+ {
254+ shiftMinSelectionID = id ;
255+ }
256+ }
257+
258+ shiftLastID = id ;
259+ }
260+
261+ private void SelectObject ( int id , bool control , bool shift )
262+ {
263+ GameObject gameObject = gameObjects [ id ] ;
264+
265+ if ( shift )
266+ {
267+ UpdateShiftSelectionIDs ( id ) ;
268+ SelectObjects ( shiftMinSelectionID , shiftMaxSelectionID ) ;
269+ }
270+ else if ( control )
271+ {
272+ UpdateShiftSelectionIDs ( id ) ;
273+
274+ if ( Selection . Contains ( gameObject ) )
275+ {
276+ //Deselect
277+ RemoveObjectFromSelection ( gameObject ) ;
278+ }
279+ else
280+ {
281+ //Select
282+ AddObjectToSelection ( gameObject ) ;
283+ }
284+ }
285+ else
286+ {
287+ Selection . objects = new Object [ ] { gameObject } ;
288+ }
289+ }
290+
291+ private void SelectObjects ( int minID , int maxID )
292+ {
293+ int size = maxID - minID + 1 ;
294+ Object [ ] newSelection = new Object [ size ] ;
295+
296+ int index = 0 ;
297+
298+ for ( int i = minID ; i <= maxID ; i ++ )
299+ {
300+ newSelection [ index ] = gameObjects [ i ] ;
301+ index ++ ;
302+ }
303+
304+ Selection . objects = newSelection ;
305+ }
306+
307+ private void AddObjectToSelection ( GameObject gameObject )
308+ {
309+ Object [ ] currentSelection = Selection . objects ;
310+ Object [ ] newSelection = new Object [ currentSelection . Length + 1 ] ;
311+
312+ currentSelection . CopyTo ( newSelection , 0 ) ;
313+ newSelection [ newSelection . Length - 1 ] = gameObject ;
314+
315+ Selection . objects = newSelection ;
316+ }
317+
318+ private void RemoveObjectFromSelection ( GameObject gameObject )
319+ {
320+ Object [ ] currentSelection = Selection . objects ;
321+ Object [ ] newSelection = new Object [ currentSelection . Length - 1 ] ;
322+
323+ int index = 0 ;
324+
325+ for ( int i = 0 ; i < currentSelection . Length ; i ++ )
326+ {
327+ if ( currentSelection [ i ] == gameObject )
328+ {
329+ continue ;
330+ }
331+
332+ newSelection [ index ] = currentSelection [ i ] ;
333+ index ++ ;
334+ }
335+
336+ Selection . objects = newSelection ;
161337 }
162338
163339 private void OnGUI_MouseLeave ( )
0 commit comments