Skip to content

Instantly share code, notes, and snippets.

@jeffvella
Last active May 2, 2020 23:35
Show Gist options
  • Save jeffvella/ab3d01ff7be94d911b2d082516998fa9 to your computer and use it in GitHub Desktop.
Save jeffvella/ab3d01ff7be94d911b2d082516998fa9 to your computer and use it in GitHub Desktop.
Observe the scene selection rect events without taking over the event with .Use()/HotControl
public static class SelectionHandler<T> where T : IHandleSelectable, IEquatable<T>
{
private static int _selectionHandleHash = nameof(SelectionHandler<T>).GetHashCode();
public static bool IsSelecting { get; private set; }
public static Vector2 StartPosition { get; private set; }
public static Vector2 CurrentPosition{ get; private set; }
public static HashSet<T> Selections { get; } = new HashSet<T>();
public delegate void SelectionEvent();
public static HashSet<T> Scan(IEnumerable<T> selectables)
{
var id = GUIUtility.GetControlID(_selectionHandleHash, FocusType.Passive);
var eventType = Event.current.GetTypeForControl(id);
if (EditorWindow.focusedWindow.GetInstanceID() != SceneView.currentDrawingSceneView.GetInstanceID())
return Selections;
if (eventType == EventType.MouseDown && Event.current.button == 0 && !IsSelecting)
{
StartPosition = Event.current.mousePosition;
CurrentPosition = StartPosition;
IsSelecting = true;
Selections.Clear();
}
if (!IsSelecting)
return Selections;
var isMouseUp = GUIUtility.hotControl == 0;
if (Event.current.isMouse && isMouseUp)
{
IsSelecting = false;
}
else
{
CurrentPosition += new Vector2(Event.current.delta.x, Event.current.delta.y);
var screenDelta = CurrentPosition - StartPosition;
var rect = new Rect(StartPosition, screenDelta);
for (var i = 0; i < SceneView.sceneViews.Count; i++)
{
((SceneView)SceneView.sceneViews[i]).Repaint();
}
if (rect.height < 0)
{
rect.height = -rect.height;
rect.y -= rect.height;
}
if (rect.width < 0)
{
rect.width = -rect.width;
rect.x -= rect.width;
}
Select(selectables, rect);
}
return Selections;
}
private static void Select(IEnumerable<T> selectables, Rect rect)
{
foreach (var item in selectables)
{
var screenPoint = HandleUtility.WorldToGUIPoint(item.WorldPosition);
if (rect.Contains(screenPoint))
{
if (!Selections.Contains(item))
Selections.Add(item);
}
else if (Selections.Contains(item))
{
Selections.Remove(item);
}
}
}
private static void DrawColoredScreenRect(Vector2 screenPoint, Vector2 size, Color color)
{
var rect = new Rect(screenPoint, size);
Handles.BeginGUI();
GUI.color = color;
GUI.Box(rect, GUIContent.none);
GUI.color = Color.white;
Handles.EndGUI();
}
}
// And the normal version
public static class SelectionHandler<T> where T : IHandleSelectable, IEquatable<T>
{
private static int _selectionHandleHash = nameof(SelectionHandler<T>).GetHashCode();
private static Rect _rect;
public static bool IsSelecting { get; private set; }
public static Vector2 StartPosition { get; private set; }
public static Vector2 CurrentPosition{ get; private set; }
public static HashSet<T> Selections { get; } = new HashSet<T>();
public delegate void SelectionEvent();
public static HashSet<T> Scan(GameObject source, IEnumerable<T> selectables)
{
if (Selection.activeGameObject != source)
return Selections;
var id = GUIUtility.GetControlID(_selectionHandleHash, FocusType.Passive);
var eventType = Event.current.GetTypeForControl(id);
switch (eventType)
{
case EventType.MouseDown:
if (!IsSelecting && (Event.current.button == 0))
{
GUIUtility.hotControl = id;
Event.current.Use();
StartPosition = Event.current.mousePosition;
CurrentPosition = StartPosition;
IsSelecting = true;
Selections.Clear();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id && (Event.current.button == 0))
{
GUIUtility.hotControl = 0;
Event.current.Use();
EditorGUIUtility.SetWantsMouseJumping(0);
IsSelecting = false;
_rect = default;
}
break;
case EventType.MouseDrag:
if (IsSelecting)
{
CurrentPosition += new Vector2(Event.current.delta.x, Event.current.delta.y);
var screenDelta = CurrentPosition - StartPosition;
_rect = new Rect(StartPosition, screenDelta);
if (_rect.height < 0)
{
_rect.height = -_rect.height;
_rect.y -= _rect.height;
}
if (_rect.width < 0)
{
_rect.width = -_rect.width;
_rect.x -= _rect.width;
}
Select(selectables, _rect);
RefreshSceneViews();
}
break;
case EventType.Repaint:
if (IsSelecting)
{
Handles.BeginGUI();
var prev = GUI.color;
GUI.color = Color.green;
GUI.Box(_rect, GUIContent.none);
GUI.color = prev;
Handles.EndGUI();
RefreshSceneViews();
}
break;
}
/*
if (eventType == EventType.MouseDown && Event.current.button == 0 && !IsSelecting)
{
GUILayout
StartPosition = Event.current.mousePosition;
CurrentPosition = StartPosition;
IsSelecting = true;
Selections.Clear();
}
if (!IsSelecting)
return Selections;
var isMouseUp = GUIUtility.hotControl == 0;
if (Event.current.isMouse && isMouseUp)
{
IsSelecting = false;
}
else
{
CurrentPosition += new Vector2(Event.current.delta.x, Event.current.delta.y);
var screenDelta = CurrentPosition - StartPosition;
var rect = new Rect(StartPosition, screenDelta);
for (var i = 0; i < SceneView.sceneViews.Count; i++)
{
((SceneView)SceneView.sceneViews[i]).Repaint();
}
if (rect.height < 0)
{
rect.height = -rect.height;
rect.y -= rect.height;
}
if (rect.width < 0)
{
rect.width = -rect.width;
rect.x -= rect.width;
}
Select(selectables, rect);
}*/
return Selections;
}
private static void RefreshSceneViews()
{
//var currentId = EditorWindow.focusedWindow.GetInstanceID();
for (var i = 0; i < SceneView.sceneViews.Count; i++)
{
var thisScene = (SceneView) SceneView.sceneViews[i];
//if (thisScene.GetInstanceID() != currentId)
thisScene.Repaint();
}
}
private static void Select(IEnumerable<T> selectables, Rect rect)
{
foreach (var item in selectables)
{
var screenPoint = HandleUtility.WorldToGUIPoint(item.WorldPosition);
if (rect.Contains(screenPoint))
{
if (!Selections.Contains(item))
Selections.Add(item);
}
else if (Selections.Contains(item))
{
Selections.Remove(item);
}
}
}
private static void DrawColoredScreenRect(Vector2 screenPoint, Vector2 size, Color color)
{
var rect = new Rect(screenPoint, size);
Handles.BeginGUI();
GUI.color = color;
GUI.Box(rect, GUIContent.none);
GUI.color = Color.white;
Handles.EndGUI();
}
private static void DrawColoredScreenRect(Rect rect, Color color)
{
Handles.BeginGUI();
GUI.color = color;
GUI.Box(rect, GUIContent.none);
GUI.color = Color.white;
Handles.EndGUI();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment