WuhuIslandTesting/Library/PackageCache/com.unity.splines@1.0.1/Editor/Controls/SplineElementRectSelector.cs

217 lines
8.3 KiB
C#
Raw Normal View History

2025-01-07 02:06:59 +01:00
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Splines
{
class SplineElementRectSelector
{
enum Mode
{
None,
Replace,
Add,
Subtract
}
static class Styles
{
public static readonly GUIStyle selectionRect = GUI.skin.FindStyle("selectionRect");
}
Rect m_Rect;
Vector2 m_StartPos;
Mode m_Mode;
Mode m_InitialMode;
static readonly HashSet<ISplineElement> s_SplineElementsCompareSet = new HashSet<ISplineElement>();
static readonly List<ISplineElement> s_SplineElementsBuffer = new List<ISplineElement>();
static readonly HashSet<ISplineElement> s_PreRectSelectionElements = new HashSet<ISplineElement>();
public void OnGUI(IReadOnlyList<IEditableSpline> paths)
{
int id = GUIUtility.GetControlID(FocusType.Passive);
Event evt = Event.current;
switch (evt.GetTypeForControl(id))
{
case EventType.Layout:
if (!Tools.viewToolActive)
{
HandleUtility.AddDefaultControl(id);
if (m_Mode != Mode.None)
{
// If we've started rect select in Add or Subtract modes, then if we were in a Replace
// mode just before (i.e. the shift or action has been released temporarily),
// we need to bring back the pre rect selection elements into current selection.
if (m_InitialMode != Mode.Replace && RefreshSelectionMode())
{
SplineSelection.Clear();
s_SplineElementsCompareSet.Clear();
if (m_Mode != Mode.Replace)
{
foreach (var element in s_PreRectSelectionElements)
SplineSelection.Add(element);
}
m_Rect = GetRectFromPoints(m_StartPos, evt.mousePosition);
UpdateSelection(m_Rect, paths);
}
}
}
break;
case EventType.Repaint:
if (GUIUtility.hotControl == id && m_Rect.size != Vector2.zero)
{
Handles.BeginGUI();
Styles.selectionRect.Draw(m_Rect, GUIContent.none, false, false, false, false);
Handles.EndGUI();
}
break;
case EventType.MouseDown:
if (HandleUtility.nearestControl == id && evt.button == 0)
{
m_StartPos = evt.mousePosition;
m_Rect = new Rect(Vector3.zero, Vector2.zero);
BeginSelection(paths);
GUIUtility.hotControl = id;
evt.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
{
m_Rect = GetRectFromPoints(m_StartPos, evt.mousePosition);
evt.Use();
UpdateSelection(m_Rect, paths);
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id)
{
GUIUtility.hotControl = 0;
evt.Use();
EndSelection(m_Rect, paths);
}
break;
}
}
protected virtual void BeginSelection(IReadOnlyList<IEditableSpline> paths)
{
RefreshSelectionMode();
m_InitialMode = m_Mode;
s_SplineElementsCompareSet.Clear();
s_SplineElementsBuffer.Clear();
if (m_Mode == Mode.Replace)
{
SplineSelection.Clear();
s_PreRectSelectionElements.Clear();
}
else
SplineSelection.GetSelectedElements(s_PreRectSelectionElements);
}
protected virtual void UpdateSelection(Rect rect, IReadOnlyList<IEditableSpline> paths)
{
//Get all elements in rect
s_SplineElementsBuffer.Clear();
for (int i = 0; i < paths.Count; ++i)
{
IEditableSpline spline = paths[i];
for (int j = 0; j < spline.knotCount; ++j)
GetElementSelection(rect, spline, j, s_SplineElementsBuffer);
}
foreach (var splineElement in s_SplineElementsBuffer)
{
//Compare current frame buffer with last frame's to find new additions/removals
var wasInRectLastFrame = s_SplineElementsCompareSet.Remove(splineElement);
if (m_Mode == Mode.Replace || m_Mode == Mode.Add)
{
var canAdd = m_Mode == Mode.Replace ? true : !s_PreRectSelectionElements.Contains(splineElement);
if (!wasInRectLastFrame && canAdd)
SplineSelection.Add(splineElement);
}
else if (m_Mode == Mode.Subtract && !wasInRectLastFrame)
{
SplineSelection.Remove(splineElement);
}
}
//Remaining spline elements from last frame are removed from selection (or added if mode is subtract)
foreach (var splineElement in s_SplineElementsCompareSet)
{
if (m_Mode == Mode.Replace || m_Mode == Mode.Add)
{
// If we're in Add mode, don't remove elements that were in select prior to rect selection
if (m_Mode == Mode.Add && s_PreRectSelectionElements.Contains(splineElement))
continue;
SplineSelection.Remove(splineElement);
}
else if (m_Mode == Mode.Subtract && s_PreRectSelectionElements.Contains(splineElement))
SplineSelection.Add(splineElement);
}
//Move current elements buffer to hash set for next frame compare
s_SplineElementsCompareSet.Clear();
foreach (var splineElement in s_SplineElementsBuffer)
s_SplineElementsCompareSet.Add(splineElement);
}
bool RefreshSelectionMode()
{
var modeBefore = m_Mode;
if (Event.current.shift)
m_Mode = Mode.Add;
else if (EditorGUI.actionKey)
m_Mode = Mode.Subtract;
else
m_Mode = Mode.Replace;
// Return true if the mode has changed
return m_Mode != modeBefore;
}
void GetElementSelection(Rect rect, IEditableSpline spline, int index, List<ISplineElement> results)
{
var knot = spline.GetKnot(index);
Vector3 screenSpace = HandleUtility.WorldToGUIPointWithDepth(knot.position);
if (screenSpace.z > 0 && rect.Contains(screenSpace))
results.Add(knot);
for(int tangentIndex = 0; tangentIndex < knot.tangentCount; tangentIndex++)
{
var tangent = knot.GetTangent(tangentIndex);
screenSpace = HandleUtility.WorldToGUIPointWithDepth(tangent.position);
if (SplineSelectionUtility.IsSelectable(spline, index, tangent) && screenSpace.z > 0 && rect.Contains(screenSpace))
results.Add(tangent);
}
}
protected virtual void EndSelection(Rect rect, IReadOnlyList<IEditableSpline> paths)
{
m_Mode = m_InitialMode = Mode.None;
}
static Rect GetRectFromPoints(Vector2 a, Vector2 b)
{
Vector2 min = new Vector2(Mathf.Min(a.x, b.x), Mathf.Min(a.y, b.y));
Vector2 max = new Vector2(Mathf.Max(a.x, b.x), Mathf.Max(a.y, b.y));
return new Rect(min, max - min);
}
}
}