using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.RMGUI; namespace RMGUI.GraphView { public class RectangleSelector : Manipulator, IDecorator { private Vector2 m_Start = Vector2.zero; private Vector2 m_End = Vector2.zero; public MouseButton activateButton { get; set; } public RectangleSelector() { activateButton = MouseButton.LeftMouse; } // get the AA aligned bound public Rect ComputeAAAlignedBound(Rect position, Matrix4x4 transform) { var min = transform.MultiplyPoint3x4(position.min); var max = transform.MultiplyPoint3x4(position.max); return Rect.MinMaxRect(Math.Min(min.x, max.x), Math.Min(min.y, max.y), Math.Max(min.x, max.x), Math.Max(min.y, max.y)); } public override EventPropagation HandleEvent(Event evt, VisualElement finalTarget) { if (finalTarget != target && !this.HasCapture()) return EventPropagation.Continue; var graphView = target as GraphView; if (graphView == null) { throw new InvalidOperationException("Manipulator can only be added to a GraphView"); } switch (evt.type) { case EventType.MouseDown: if (evt.button == (int)activateButton) { if (!evt.control) { graphView.ClearSelection(); } this.TakeCapture(); target.AddDecorator(this); m_Start = evt.mousePosition; m_End = m_Start; return EventPropagation.Stop; } break; case EventType.MouseUp: if (this.HasCapture() && evt.button == (int)activateButton) { this.ReleaseCapture(); target.RemoveDecorator(this); m_End = evt.mousePosition; Rect selectionRect = new Rect(); selectionRect.min = new Vector2(Math.Min(m_Start.x, m_End.x), Math.Min(m_Start.y, m_End.y)); selectionRect.max = new Vector2(Math.Max(m_Start.x, m_End.x), Math.Max(m_Start.y, m_End.y)); selectionRect = ComputeAAAlignedBound(selectionRect, graphView.contentViewContainer.transform.inverse); selectionRect.width = Mathf.Max(selectionRect.width, 5.0f); selectionRect.height = Mathf.Max(selectionRect.height, 5.0f); List selection = graphView.selection; var children = graphView.contentViewContainer.GetChildren(); while (children.MoveNext()) { var child = children.Current; if (child == null) continue; var selectable = child as ISelectable; var selectableTransform = child.transform.inverse; var localSelRect = new Rect(selectableTransform.MultiplyPoint3x4(selectionRect.position), selectableTransform.MultiplyPoint3x4(selectionRect.size)); if (selectable != null && selectable.IsSelectable() && selectable.Overlaps(localSelRect)) { if (selection.Contains(selectable)) graphView.RemoveFromSelection(selectable); else graphView.AddToSelection(selectable); } } return EventPropagation.Stop; } break; case EventType.MouseDrag: if (this.HasCapture()) { m_End = evt.mousePosition; return EventPropagation.Stop; } break; } return EventPropagation.Continue; } public override void OnLostCapture() { target.RemoveDecorator(this); } public void PrePaint(VisualElement t, PaintContext pc) { } // todo shanti move paint dotted border to StylePainter // todo move text render to style painter public void PostPaint(VisualElement t, PaintContext pc) { var screenStart = m_Start; var screenEnd = m_End; // Avoid drawing useless information if (m_Start == m_End) return; // Apply offset screenStart += t.position.position; screenEnd += t.position.position; var r = new Rect { min = new Vector2(Math.Min(screenStart.x, screenEnd.x), Math.Min(screenStart.y, screenEnd.y)), max = new Vector2(Math.Max(screenStart.x, screenEnd.x), Math.Max(screenStart.y, screenEnd.y)) }; var lineColor = new Color(1.0f, 0.6f, 0.0f, 1.0f); var segmentSize = 5f; Vector3[] points = { new Vector3(r.xMin, r.yMin, 0.0f), new Vector3(r.xMax, r.yMin, 0.0f), new Vector3(r.xMax, r.yMax, 0.0f), new Vector3(r.xMin, r.yMax, 0.0f) }; DrawDottedLine(points[0], points[1], segmentSize, lineColor); DrawDottedLine(points[1], points[2], segmentSize, lineColor); DrawDottedLine(points[2], points[3], segmentSize, lineColor); DrawDottedLine(points[3], points[0], segmentSize, lineColor); var str = "(" + String.Format("{0:0}", m_Start.x) + ", " + String.Format("{0:0}", m_Start.y) + ")"; GUI.skin.label.Draw(new Rect(screenStart.x, screenStart.y - 18.0f, 200.0f, 20.0f), new GUIContent(str), 0); str = "(" + String.Format("{0:0}", m_End.x) + ", " + String.Format("{0:0}", m_End.y) + ")"; GUI.skin.label.Draw(new Rect(screenEnd.x - 80.0f, screenEnd.y + 5.0f, 200.0f, 20.0f), new GUIContent(str), 0); } private void DrawDottedLine(Vector3 p1, Vector3 p2, float segmentsLength, Color col) { UIHelpers.ApplyWireMaterial(); GL.Begin(GL.LINES); GL.Color(col); float length = Vector3.Distance(p1, p2); // ignore z component int count = Mathf.CeilToInt(length/segmentsLength); for (int i = 0; i < count; i += 2) { GL.Vertex((Vector3.Lerp(p1, p2, i*segmentsLength/length))); GL.Vertex((Vector3.Lerp(p1, p2, (i + 1)*segmentsLength/length))); } GL.End(); } } }