Esempio n. 1
0
 // If no current snap action, set it to the action.
 // Otherwise, if set, we're possibly undoing the last snap action (these are always opposite attach/detach actions),
 // if re-attaching or re-detaching from the connection point.
 // Lastly, if attaching to a different connection point, buffer the last snap action (which would always be a detach)
 // and set the current snap action to what will always be the attach to another connection point.
 protected void SetCurrentAction(SnapAction action)
 {
     if (currentSnapAction == null)
     {
         currentSnapAction = action;
     }
     else
     {
         // Connecting to a different shape?
         if (action.TargetShape != currentSnapAction.TargetShape
             // connecting to a different endpoint on the connector?
             || action.GripType != currentSnapAction.GripType
             // connecting to a different connection point on the shape?
             || action.ShapeConnectionPoint != currentSnapAction.ShapeConnectionPoint)
         {
             snapActions.Add(currentSnapAction);
             currentSnapAction = action;
         }
         else
         {
             // User is undoing the last action by re-connecting or disconnecting from the shape to which we just connected / disconnected.
             currentSnapAction = null;
         }
     }
 }
Esempio n. 2
0
 public void Reset()
 {
     snapActions.Clear();
     nearElements.Clear();
     currentlyNear.Clear();
     runningDelta      = Point.Empty;
     currentSnapAction = null;
 }
Esempio n. 3
0
        public bool SnapCheck(GripType gripType, Point delta, Action <Point> update, bool isByKeyPress = false)
        {
            SnapAction action = Snap(gripType, delta, isByKeyPress);

            if (action != null)
            {
                if (action.SnapType == SnapAction.Action.Attach)
                {
                    runningDelta = runningDelta.Add(action.Delta);
                    update(action.Delta);
                    // Controller.DragSelectedElements(action.Delta);
                    // Don't attach at this point, as this will be handled by the mouse-up action.
                    SetCurrentAction(action);
                }
                else if (action.SnapType == SnapAction.Action.Detach)
                {
                    runningDelta = runningDelta.Add(action.Delta);
                    update(action.Delta);
                    // Controller.DragSelectedElements(action.Delta);
                    // Don't detach at this point, as this will be handled by the mouse-up action.
                    SetCurrentAction(action);
                }
                else // Attached
                {
                    // The mouse move had no affect in detaching because it didn't have sufficient velocity.
                    // The problem here is that the mouse moves, affecting the total delta, but the shape doesn't move.
                    // This affects the computation in the MouseUp handler:
                    // Point delta = CurrentMousePosition.Delta(startedDraggingShapesAt);

                    // ===================
                    // We could set the mouse cursor position, which isn't a bad idea, as it keeps the mouse with the shape:

                    //Controller.Canvas.MouseMove -= HandleMouseMoveEvent;
                    //Cursor.Position = Controller.Canvas.PointToScreen(LastMousePosition);
                    //Application.DoEvents();         // sigh - we need the event to trigger, even though it's unwired.
                    //Controller.Canvas.MouseMove += HandleMouseMoveEvent;

                    // The above really doesn't work well because I think we can get multiple move events, and this only handles the first event.
                    // ===================

                    // ===================
                    // Or we could add a "compensation" accumulator for dealing with the deltas that don't move the shape.
                    // This works better, except the attached compensation has to be stored for each detach.
                    // attachedCompensation = attachedCompensation.Add(delta);

                    // That doesn't work either, as the attachedCompensation is treated as a move even though there is no actual movement of the connector!
                    // ===================

                    // Final implementation is to use the runningDelta instead of the CurrentMouseMosition - startDraggingShapesAt difference.

                    // startedDraggingShapesAt = CurrentMousePosition;
                }
            }

            return(action != null);
        }
Esempio n. 4
0
        public SnapAction Clone()
        {
            SnapAction ret = new SnapAction();

            ret.SnapType             = SnapType;
            ret.connector            = connector;
            ret.gripType             = gripType;
            ret.targetShape          = targetShape;
            ret.lineConnectionPoint  = lineConnectionPoint;
            ret.shapeConnectionPoint = shapeConnectionPoint;
            ret.Delta = Delta;

            return(ret);
        }
Esempio n. 5
0
        protected void DoUndoSnapAction(UndoStack undoStack, SnapAction action)
        {
            SnapAction closureAction = action.Clone();

            // Do/undo/redo as part of of the move group.
            if (closureAction.SnapType == SnapAction.Action.Attach)
            {
                undoStack.UndoRedo("Attach",
                                   () => closureAction.Attach(),
                                   () => closureAction.Detach(),
                                   false);
            }
            else
            {
                undoStack.UndoRedo("Detach",
                                   () => closureAction.Detach(),
                                   () => closureAction.Attach(),
                                   false);
            }
        }
Esempio n. 6
0
        protected SnapAction Snap(GripType type, Point delta, bool isByKeyPress)
        {
            SnapAction action = null;

            // Snapping permitted only when one and only one element is selected.
            if (controller.SelectedElements.Count != 1)
            {
                return(null);
            }
            if (controller.IsSnapToBeIgnored)
            {
                return(null);
            }

            // bool snapped = false;
            GraphicElement selectedElement = controller.SelectedElements[0];

            // Look for connection points on nearby elements.
            // If a connection point is nearby, and the delta is moving toward that connection point, then snap to that connection point.

            // So, it seems odd that we're using the connection points of the line, rather than the anchors.
            // However, this is actually simpler, and a line's connection points should at least include the endpoint anchors.
            IEnumerable <ConnectionPoint> connectionPoints = selectedElement.GetConnectionPoints().Where(p => type == GripType.None || p.Type == type);

            nearElements = GetNearbyElements(connectionPoints);
            ShowConnectionPoints(nearElements.Select(e => e.NearElement), true);
            ShowConnectionPoints(currentlyNear.Where(e => !nearElements.Any(e2 => e.NearElement == e2.NearElement)).Select(e => e.NearElement), false);
            currentlyNear = nearElements;

            // Issue #6
            // TODO: Again, sort of kludgy.
            UpdateWithNearElementConnectionPoints(nearElements);
            nearElements = nearElements.OrderBy(si => si.AbsDx + si.AbsDy).ToList();    // abs(dx) + abs(dy) as a fast "distance" sorter, no need for sqrt(dx^2 + dy^2)

            foreach (SnapInfo si in nearElements)
            {
                ConnectionPoint nearConnectionPoint = si.NearElement.GetConnectionPoints().FirstOrDefault(cp => cp.Point.IsNear(si.LineConnectionPoint.Point, SNAP_CONNECTION_POINT_RANGE));

                if (nearConnectionPoint != null)
                {
                    Point sourceConnectionPoint = si.LineConnectionPoint.Point;
                    int   neardx     = nearConnectionPoint.Point.X - sourceConnectionPoint.X; // calculate to match possible delta sign
                    int   neardy     = nearConnectionPoint.Point.Y - sourceConnectionPoint.Y;
                    int   neardxsign = neardx.Sign();
                    int   neardysign = neardy.Sign();
                    int   deltaxsign = delta.X.Sign();
                    int   deltaysign = delta.Y.Sign();

                    // Are we attached already or moving toward the shape's connection point?
                    if ((neardxsign == 0 || deltaxsign == 0 || neardxsign == deltaxsign) &&
                        (neardysign == 0 || deltaysign == 0 || neardysign == deltaysign))
                    {
                        // If attached, are we moving away from the connection point to detach it?
                        // Keyboard overrides the velocity check so we immediately detach if moving away.
                        if (neardxsign == 0 && neardxsign == 0 && ((delta.X.Abs() >= SNAP_DETACH_VELOCITY || delta.Y.Abs() >= SNAP_DETACH_VELOCITY) ||
                                                                   (isByKeyPress && (neardxsign != deltaxsign || neardysign != deltaysign))))
                        {
                            // Detach:
                            action = new SnapAction(SnapAction.Action.Detach, selectedElement, type, si.NearElement, si.LineConnectionPoint, nearConnectionPoint, delta);
                            break;
                        }
                        else
                        {
                            // Not already connected?
                            if (neardxsign != 0 || neardysign != 0)
                            {
                                // Attach:
                                action = new SnapAction(SnapAction.Action.Attach, selectedElement, type, si.NearElement, si.LineConnectionPoint, nearConnectionPoint, new Point(neardx, neardy));
                            }
                            else
                            {
                                action = new SnapAction();
                                break;
                            }

                            // delta = new Point(neardx, neardy);
                            // snapped = true;
                            break;
                        }
                    }
                }
            }

            return(action);
        }