Example #1
0
        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 VertexPath is not a closed loop, add new point on to the end of the VertexPath
                    else if (!BezierPath.IsClosed)
                    {
                        // If control/command are held down, the point gets pre-pended, so we want to check distance
                        // to the endpoint we are adding to
                        var pointIdx = e.control || e.command ? 0 : BezierPath.NumPoints - 1;
                        // insert new point at same dst from scene camera as the point that comes before it (for a 3d VertexPath)
                        var endPointLocal  = BezierPath[pointIdx];
                        var endPointGlobal =
                            MathUtility.TransformPoint(endPointLocal, creator.transform, BezierPath.Space);
                        var distanceCameraToEndpoint = (Camera.current.transform.position - endPointGlobal).magnitude;
                        var newPointGlobal           =
                            MouseUtility.GetMouseWorldPosition(BezierPath.Space, distanceCameraToEndpoint);
                        var newPointLocal =
                            MathUtility.InverseTransformPoint(newPointGlobal, creator.transform, BezierPath.Space);

                        Undo.RecordObject(creator, "Add segment");
                        if (e.control || e.command)
                        {
                            BezierPath.AddSegmentToStart(newPointLocal);
                        }
                        else
                        {
                            BezierPath.AddSegmentToEnd(newPointLocal);
                        }
                    }
                }
            }

            // 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;
        }
Example #2
0
        public static Vector3 DrawHandle(Vector3 position, CoreScript.PathSpace space, bool isInteractive, 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 * .5f;
            float     dstToHandle  = HandleUtility.DistanceToCircle(position, handleRadius + extraInputRadius);
            float     dstToMouse   = HandleUtility.DistanceToCircle(position, 0);

            // Handle input events
            if (isInteractive)
            {
                // 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 = (isInteractive) ? colours.defaultColour : colours.disabledColour;

                if (id == GUIUtility.hotControl)
                {
                    Handles.color = colours.selectedColour;
                }
                else if (dstToHandle == 0 && selectedHandleID == -1 && isInteractive)
                {
                    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 * .5f));
                Handles.matrix = cachedMatrix;
                break;
            }

            return(position);
        }