Пример #1
0
        // Returns the distance the new position has moved along slideDir1 and slideDir2
        private static Vector2 CalcDeltaAlongDirections(
            int id,
            Vector3 handlePos,
            Vector3 offset,
            Vector3 handleDir,
            Vector3 slideDir1,
            Vector3 slideDir2,
            float handleSize,
            Handles.CapFunction capFunction,
            Vector2 snap,
            bool drawHelper)
        {
            Vector3    position = handlePos + offset;
            Quaternion rotation = Quaternion.LookRotation(handleDir, slideDir1);
            Vector2    deltaDistanceAlongDirections = new Vector2(0, 0);

            Event evt = Event.current;

            switch (evt.GetTypeForControl(id))
            {
            case EventType.Layout:
            case EventType.MouseMove:
                if (capFunction != null)
                {
                    capFunction(id, position, rotation, handleSize, EventType.Layout);
                }
                else
                {
                    HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(handlePos + offset, handleSize * .5f));
                }
                break;

            case EventType.MouseDown:
                // am I closest to the thingy?
                if (HandleUtility.nearestControl == id && evt.button == 0 && GUIUtility.hotControl == 0 && !evt.alt)
                {
                    s_CurrentMousePosition = evt.mousePosition;
                    bool    success         = true;
                    Vector3 localMousePoint = Handles.inverseMatrix.MultiplyPoint(GetMousePosition(handleDir, handlePos, ref success));
                    if (success)
                    {
                        GUIUtility.hotControl = id;     // Grab mouse focus
                        s_StartPosition       = handlePos;

                        Vector3 clickOffset = localMousePoint - handlePos;
                        s_StartPlaneOffset.x = Vector3.Dot(clickOffset, slideDir1);
                        s_StartPlaneOffset.y = Vector3.Dot(clickOffset, slideDir2);

                        evt.Use();
                        EditorGUIUtility.SetWantsMouseJumping(1);
                    }
                }
                break;

            case EventType.MouseDrag:

                capFunction?.Invoke(id, position, rotation, handleSize, EventType.Layout);

                if (GUIUtility.hotControl == id)
                {
                    Vector2 mouseDelta = evt.mousePosition - s_CurrentMousePosition;
                    s_CurrentMousePosition += mouseDelta;
                    bool    success         = true;
                    Vector3 localMousePoint = Handles.inverseMatrix.MultiplyPoint(GetMousePosition(handleDir, handlePos, ref success));
                    if (success)
                    {
                        // Determine hitpos projection onto slideDirs
                        deltaDistanceAlongDirections.x = HandleUtility.PointOnLineParameter(localMousePoint, s_StartPosition, slideDir1);
                        deltaDistanceAlongDirections.y = HandleUtility.PointOnLineParameter(localMousePoint, s_StartPosition, slideDir2);
                        deltaDistanceAlongDirections  -= s_StartPlaneOffset;
                        deltaDistanceAlongDirections.x = Handles.SnapValue(deltaDistanceAlongDirections.x, snap.x);
                        deltaDistanceAlongDirections.y = Handles.SnapValue(deltaDistanceAlongDirections.y, snap.y);

                        GUI.changed = true;
                    }
                    evt.Use();
                }
                break;

            case EventType.MouseUp:
                if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
                {
                    GUIUtility.hotControl = 0;
                    evt.Use();
                    EditorGUIUtility.SetWantsMouseJumping(0);
                }
                break;

            case EventType.Repaint:
            {
                if (capFunction == null)
                {
                    break;
                }

                Handles.SetupHandleColor(id, evt, out var prevColor, out var thickness);
                capFunction(id, position, rotation, handleSize, EventType.Repaint);
                Handles.color = prevColor;

                // Draw a helper rectangle to show what plane we are dragging in
                if (drawHelper && GUIUtility.hotControl == id)
                {
                    Vector3[] verts      = new Vector3[4];
                    float     helperSize = handleSize * 10.0f;
                    verts[0]      = position + (slideDir1 * helperSize + slideDir2 * helperSize);
                    verts[1]      = verts[0] - slideDir1 * helperSize * 2.0f;
                    verts[2]      = verts[1] - slideDir2 * helperSize * 2.0f;
                    verts[3]      = verts[2] + slideDir1 * helperSize * 2.0f;
                    Handles.color = Color.white;
                    float outline = 0.6f;
                    Handles.DrawSolidRectangleWithOutline(verts, new Color(1, 1, 1, 0.05f), new Color(outline, outline, outline, 0.4f));
                    Handles.color = prevColor;
                }
            }

            break;
            }

            return(deltaDistanceAlongDirections);
        }
Пример #2
0
        internal static Vector3 Do(int id, Vector3 position, Vector3 offset, Vector3 handleDirection, Vector3 slideDirection, float size, Handles.CapFunction capFunction, float snap)
        {
            Event evt       = Event.current;
            var   eventType = evt.GetTypeForControl(id);

            switch (eventType)
            {
            case EventType.Layout:
            case EventType.MouseMove:
                if (capFunction != null)
                {
                    capFunction(id, position + offset, ToQuaternion(handleDirection), size, EventType.Layout);
                }
                else
                {
                    HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position + offset, size * .2f));
                }
                break;

            case EventType.MouseDown:
                // am I closest to the thingy?
                if (HandleUtility.nearestControl == id && evt.button == 0 && GUIUtility.hotControl == 0 && !evt.alt)
                {
                    GUIUtility.hotControl = id;        // Grab mouse focus
                    s_StartMousePosition  = evt.mousePosition;
                    s_ConstraintOrigin    = Handles.matrix.MultiplyPoint3x4(position);
                    s_StartPosition       = position;
                    s_ConstraintDirection = Handles.matrix.MultiplyVector(slideDirection);
                    s_HandleOffset        = HandleUtility.CalcPositionOnConstraint(Camera.current, evt.mousePosition, s_ConstraintOrigin, s_ConstraintDirection, out Vector3 point)
                            ? s_ConstraintOrigin - point
                            : Vector3.zero;
                    evt.Use();
                    s_StartHandleSize          = HandleUtility.GetHandleSize(point);
                    s_StartInverseHandleMatrix = Handles.inverseMatrix;
                }

                break;

            case EventType.MouseDrag:

                capFunction?.Invoke(id, position + offset, ToQuaternion(handleDirection), size, EventType.Layout);

                if (GUIUtility.hotControl == id)
                {
                    // First try to calculate the translation by casting a mouse ray against a world position plane
                    // oriented towards the camera. This gives more accurate results than doing the line translation
                    // in 2D space, but is more prone towards skewing extreme values when the ray is near parallel
                    // to the plane. To address this, CalcPositionOnConstraint will fail if the mouse ray is close
                    // to parallel (see HandleUtility.k_MinRayConstraintDot) and fall back to 2D based movement.
                    if (HandleUtility.CalcPositionOnConstraint(Camera.current, evt.mousePosition, s_ConstraintOrigin, s_ConstraintDirection, out Vector3 worldPosition))
                    {
                        var handleOffset = s_HandleOffset * (HandleUtility.GetHandleSize(worldPosition) / s_StartHandleSize);
                        worldPosition += handleOffset;

                        if (EditorSnapSettings.incrementalSnapActive)
                        {
                            Vector3 dir  = worldPosition - s_ConstraintOrigin;
                            float   dist = Handles.SnapValue(dir.magnitude, snap) * Mathf.Sign(Vector3.Dot(s_ConstraintDirection, dir));
                            worldPosition = s_ConstraintOrigin + s_ConstraintDirection.normalized * dist;
                        }
                        else if (EditorSnapSettings.gridSnapActive)
                        {
                            worldPosition = Snapping.Snap(worldPosition, GridSettings.size, (SnapAxis) new SnapAxisFilter(s_ConstraintDirection));
                        }

                        position = s_StartInverseHandleMatrix.MultiplyPoint(worldPosition);

                        s_StartPosition      = position;
                        s_StartMousePosition = evt.mousePosition;
                    }
                    else
                    {
                        // Unlike HandleUtility.CalcPositionOnConstraint, CalcLineTranslation _does_ multiply constraint
                        // origin and direction by Handles.matrix, so make sure to pass in unmodified vectors here
                        float dist = HandleUtility.CalcLineTranslation(s_StartMousePosition, evt.mousePosition, s_StartPosition, slideDirection);
                        dist          = Handles.SnapValue(dist, snap);
                        worldPosition = Handles.matrix.MultiplyPoint(s_StartPosition) + s_ConstraintDirection * dist;
                        if (EditorSnapSettings.gridSnapActive)
                        {
                            worldPosition = Snapping.Snap(worldPosition, GridSettings.size, (SnapAxis) new SnapAxisFilter(s_ConstraintDirection));
                        }
                        position = Handles.inverseMatrix.MultiplyPoint(worldPosition);
                    }

                    GUI.changed = true;
                    evt.Use();
                }
                break;

            case EventType.MouseUp:
                if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
                {
                    GUIUtility.hotControl = 0;
                    evt.Use();
                }
                break;

            case EventType.Repaint:
                Handles.SetupHandleColor(id, evt, out var prevColor, out var thickness);
                capFunction(id, position + offset, ToQuaternion(handleDirection), size, EventType.Repaint);
                Handles.color = prevColor;
                break;
            }
            return(position);
        }