void ProcessBezierPathInput(Event e) { // Find which handle mouse is over. Start by looking at previous handle index first, as most likely to still be closest to mouse int previousMouseOverHandleIndex = (mouseOverHandleIndex == -1) ? 0 : mouseOverHandleIndex; mouseOverHandleIndex = -1; for (int i = 0; i < bezierPath.NumPoints; i += 3) { int handleIndex = (previousMouseOverHandleIndex + i) % bezierPath.NumPoints; float handleRadius = GetHandleDiameter(globalDisplaySettings.anchorSize * data.bezierHandleScale, bezierPath[handleIndex]) / 2f; Vector3 pos = MathUtility.TransformPoint(bezierPath[handleIndex], creator.transform, bezierPath.Space); float dst = HandleUtility.DistanceToCircle(pos, handleRadius); if (dst == 0) { mouseOverHandleIndex = handleIndex; break; } } // Shift-left click (when mouse not over a handle) to split or add segment if (mouseOverHandleIndex == -1) { if (e.type == EventType.MouseDown && e.button == 0 && e.shift) { UpdatePathMouseInfo(); // Insert point along selected segment if (selectedSegmentIndex != -1 && selectedSegmentIndex < bezierPath.NumSegments) { Vector3 newPathPoint = pathMouseInfo.closestWorldPointToMouse; newPathPoint = MathUtility.InverseTransformPoint(newPathPoint, creator.transform, bezierPath.Space); Undo.RecordObject(creator, "Split segment"); bezierPath.SplitSegment(newPathPoint, selectedSegmentIndex, pathMouseInfo.timeOnBezierSegment); } // If path is not a closed loop, add new point on to the end of the path else if (!bezierPath.IsClosed) { // insert new point at same dst from scene camera as the point that comes before it (for a 3d path) float dstCamToEndpoint = (Camera.current.transform.position - bezierPath[bezierPath.NumPoints - 1]).magnitude; Vector3 newPathPoint = MouseUtility.GetMouseWorldPosition(bezierPath.Space, dstCamToEndpoint); newPathPoint = MathUtility.InverseTransformPoint(newPathPoint, creator.transform, bezierPath.Space); Undo.RecordObject(creator, "Add segment"); if (e.control || e.command) { bezierPath.AddSegmentToStart(newPathPoint); } else { bezierPath.AddSegmentToEnd(newPathPoint); } } } } // Control click or backspace/delete to remove point if (e.keyCode == KeyCode.Backspace || e.keyCode == KeyCode.Delete || ((e.control || e.command) && e.type == EventType.MouseDown && e.button == 0)) { if (mouseOverHandleIndex != -1) { Undo.RecordObject(creator, "Delete segment"); bezierPath.DeleteSegment(mouseOverHandleIndex); if (mouseOverHandleIndex == handleIndexToDisplayAsTransform) { handleIndexToDisplayAsTransform = -1; } mouseOverHandleIndex = -1; Repaint(); } } // Holding shift and moving mouse (but mouse not over a handle/dragging a handle) if (draggingHandleIndex == -1 && mouseOverHandleIndex == -1) { bool shiftDown = e.shift && !shiftLastFrame; if (shiftDown || ((e.type == EventType.MouseMove || e.type == EventType.MouseDrag) && e.shift)) { UpdatePathMouseInfo(); if (pathMouseInfo.mouseDstToLine < segmentSelectDistanceThreshold) { if (pathMouseInfo.closestSegmentIndex != selectedSegmentIndex) { selectedSegmentIndex = pathMouseInfo.closestSegmentIndex; HandleUtility.Repaint(); } } else { selectedSegmentIndex = -1; HandleUtility.Repaint(); } } } shiftLastFrame = e.shift; }
public static Vector3 DrawHandle(Vector3 position, PathSpace space, bool isInterpickedUp, float handleDiameter, Handles.CapFunction capFunc, HandleColours colours, out HandleInputType inputType, int handleIndex) { int id = GetID(handleIndex); Vector3 screenPosition = Handles.matrix.MultiplyPoint(position); Matrix4x4 cachedMatrix = Handles.matrix; inputType = HandleInputType.None; EventType eventType = Event.current.GetTypeForControl(id); float handleRadius = handleDiameter / 2f; float dstToHandle = HandleUtility.DistanceToCircle(position, handleRadius + extraInputRadius); float dstToMouse = HandleUtility.DistanceToCircle(position, 0); // Handle input events if (isInterpickedUp) { // Repaint if mouse is entering/exiting handle (for highlight colour) if (dstToHandle == 0) { if (!mouseIsOverAHandle) { HandleUtility.Repaint(); mouseIsOverAHandle = true; } } else { if (mouseIsOverAHandle) { HandleUtility.Repaint(); mouseIsOverAHandle = false; } } switch (eventType) { case EventType.MouseDown: if (Event.current.button == 0 && Event.current.modifiers != EventModifiers.Alt) { if (dstToHandle == 0 && dstToMouse < dstMouseToDragPointStart) { dstMouseToDragPointStart = dstToMouse; GUIUtility.hotControl = id; handleDragMouseEnd = handleDragMouseStart = Event.current.mousePosition; handleDragWorldStart = position; selectedHandleID = id; inputType = HandleInputType.LMBPress; } } break; case EventType.MouseUp: dstMouseToDragPointStart = float.MaxValue; if (GUIUtility.hotControl == id && Event.current.button == 0) { GUIUtility.hotControl = 0; selectedHandleID = -1; Event.current.Use(); inputType = HandleInputType.LMBRelease; if (Event.current.mousePosition == handleDragMouseStart) { inputType = HandleInputType.LMBClick; } } break; case EventType.MouseDrag: if (GUIUtility.hotControl == id && Event.current.button == 0) { handleDragMouseEnd += new Vector2(Event.current.delta.x, -Event.current.delta.y); Vector3 position2 = Camera.current.WorldToScreenPoint(Handles.matrix.MultiplyPoint(handleDragWorldStart)) + (Vector3)(handleDragMouseEnd - handleDragMouseStart); inputType = HandleInputType.LMBDrag; // Handle can move freely in 3d space if (space == PathSpace.xyz) { position = Handles.matrix.inverse.MultiplyPoint(Camera.current.ScreenToWorldPoint(position2)); } // Handle is clamped to xy or xz plane else { position = MouseUtility.GetMouseWorldPosition(space); } GUI.changed = true; Event.current.Use(); } break; } } switch (eventType) { case EventType.Repaint: Color originalColour = Handles.color; Handles.color = (isInterpickedUp) ? colours.defaultColour : colours.disabledColour; if (id == GUIUtility.hotControl) { Handles.color = colours.selectedColour; } else if (dstToHandle == 0 && selectedHandleID == -1 && isInterpickedUp) { Handles.color = colours.highlightedColour; } Handles.matrix = Matrix4x4.identity; Vector3 lookForward = Vector3.up; Camera cam = Camera.current; if (cam != null) { if (cam.orthographic) { lookForward = -cam.transform.forward; } else { lookForward = (cam.transform.position - position); } } capFunc(id, screenPosition, Quaternion.LookRotation(lookForward), handleDiameter, EventType.Repaint); Handles.matrix = cachedMatrix; Handles.color = originalColour; break; case EventType.Layout: Handles.matrix = Matrix4x4.identity; HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(screenPosition, handleDiameter / 2f)); Handles.matrix = cachedMatrix; break; } return(position); }