示例#1
0
        /// <summary>
        /// Initializes our own drag and determines whether we are a slave or the master and if there are actual slave handles in that case
        /// </summary>
        public void InitializeDrag(IInputModeContext context)
        {
            coreHandle.InitializeDrag(context);
            if (context.ParentInputMode is MoveInputMode)
            {
                //If we are moved via MoveInputMode (happens when the whole edge is dragged)
                //We only delegate to the core handle
                return;
            }

            //If we are indirectly controlled from the other control point or the bend curve point
            //those implementations put a marker in the lookup
            //If such a marker is present, we DON'T delegate to the other handle and just move ourselves.
            var bcph = context.Lookup <InnerControlPointHandle>();
            var cph  = context.Lookup <OuterControlPointHandle>();

            if (bcph == null && cph == null)
            {
                //We are the master handle and so we control the other one
                var index = bend.GetIndex();

                //Whether this is the first or the last bend in such a control point triple
                var isFirstInTriplet = index % 3 == 1;

                IBend otherBend  = null;
                IBend middleBend = null;
                if (isFirstInTriplet && index < bend.Owner.Bends.Count - 1)
                {
                    //We are the first of the triple and there is a potential slave handle
                    //So get the slave and the middle bend
                    otherBend  = bend.Owner.Bends[index + 2];
                    middleBend = bend.Owner.Bends[index + 1];
                }
                else if (index >= 3)
                {
                    //We are the last of the triple and there is a potential slave handle
                    //So get the slave and the middle bend
                    otherBend  = bend.Owner.Bends[index - 2];
                    middleBend = bend.Owner.Bends[index - 1];
                }
                if (otherBend != null && AreCollinear(bend.Location, middleBend.Location, otherBend.Location))
                {
                    slaveHandle    = otherBend.Lookup <IHandle>();
                    middleLocation = middleBend.Location.ToPointD();
                }

                if (slaveHandle != null)
                {
                    //There not only a bend, but actually a handle to control
                    //notify it that it is the slave
                    //We just put ourselves in the context, so our presence serves as flag to the other handle
                    //And from now on control its actions.
                    var childContext = Contexts.CreateInputModeContext(context.ParentInputMode, context, Lookups.Single(this));
                    slaveHandle.InitializeDrag(childContext);
                    slaveOrigin = slaveHandle.Location.ToPointD();
                }
            }
        }
示例#2
0
        /// <summary>
        /// Initializes the drag.
        /// </summary>
        public void InitializeDrag(IInputModeContext context)
        {
            var imc = context.Lookup <IModelItemCollector>();

            if (imc != null)
            {
                imc.Add(node);
            }
            rotationCenter = node.Layout.GetCenter();
            initialAngle   = GetAngle();

            var graph = context.Lookup <IGraph>();

            if (graph != null)
            {
                compoundEdit = graph.BeginEdit("Change Rotation Angle", "Change Rotation Angle");
            }

            portHandles.Clear();
            var portContext = new DelegatingContext(context);

            foreach (var port in node.Ports)
            {
                var portHandle = new DummyPortLocationModelParameterHandle(port);
                portHandle.InitializeDrag(portContext);
                portHandles.Add(portHandle);
            }
            if (reshapeHandler != null)
            {
                reshapeHandler.InitializeReshape(context);
            }
            // Collect other visible nodes and their angles
            if (SnapToSameAngleDelta > 0)
            {
                var canvas       = context.CanvasControl;
                var rotatedNodes =
                    canvas.GetCanvasObjects()
                    .Select(co => co.UserObject)
                    // only collect nodes
                    .OfType <INode>()
                    // ... that are in the viewport
                    .Where(n => canvas.Viewport.Intersects(n.Layout.ToRectD()))
                    // ... and can be rotated
                    .Where(n => n.Style is RotatableNodeStyleDecorator)
                    // ... and are not *this* node
                    .Where(n => n != node);
                // Group nodes by identical angles
                nodeAngles =
                    rotatedNodes.GroupBy(n => ((RotatableNodeStyleDecorator)n.Style).Angle)
                    .Select(nodes => Tuple.Create(nodes.Key, nodes.ToList().AsEnumerable())).ToList();
            }
        }
示例#3
0
        /// <summary>
        /// Creates a new bend at the given location. If this bend is on the first or last segment,
        /// a second bend is created and placed at a location that ensures that the newly create
        /// inner segment is orthogonal.
        /// </summary>
        public int CreateBend(IInputModeContext context, IGraph graph, IEdge edge, PointD location)
        {
            var edgePoints     = GetEdgePoints(edge);
            var closestSegment = DetermineBendSegmentIndex(edgePoints, location);

            int firstSegment = 0;
            int lastSegment  = edge.Bends.Count;

            // if bend wasn't created in first or last segment, call default action
            if (closestSegment != firstSegment && closestSegment != lastSegment)
            {
                return((new DefaultBendCreator()).CreateBend(context, graph, edge, location));
            }

            // add created bend and another one to make the edge stay orthogonal
            if (closestSegment == -1 || context == null || !(context.ParentInputMode is CreateBendInputMode))
            {
                return(-1);
            }
            var editingContext = context.Lookup <OrthogonalEdgeEditingContext>();

            if (editingContext == null)
            {
                return(-1);
            }
            if (closestSegment == firstSegment)
            {
                IPoint nextPoint = edgePoints[1];
                // get orientation of next edge segment to determine second bend location
                SegmentOrientation orientation = editingContext.GetSegmentOrientation(edge, 1);
                graph.AddBend(edge, location, 0);
                if (orientation == SegmentOrientation.Horizontal)
                {
                    graph.AddBend(edge, new PointD(nextPoint.X, location.Y), 1);
                }
                else if (orientation == SegmentOrientation.Vertical)
                {
                    graph.AddBend(edge, new PointD(location.X, nextPoint.Y), 1);
                }
                return(0);
            }
            if (closestSegment == lastSegment)
            {
                IPoint prevPoint = edgePoints[edge.Bends.Count];
                // get orientation of next edge segment to determine second bend location
                SegmentOrientation orientation = editingContext.GetSegmentOrientation(edge, edge.Bends.Count - 1);
                graph.AddBend(edge, location, edge.Bends.Count);
                if (orientation == SegmentOrientation.Horizontal)
                {
                    graph.AddBend(edge, new PointD(prevPoint.X, location.Y), edge.Bends.Count - 1);
                }
                else if (orientation == SegmentOrientation.Vertical)
                {
                    graph.AddBend(edge, new PointD(location.X, prevPoint.Y), edge.Bends.Count - 1);
                }
                return(edge.Bends.Count - 1);
            }
            return(-1);
        }
        /// <summary>
        /// The node is upon to be dragged.
        /// </summary>
        public void InitializeDrag(IInputModeContext context)
        {
            reparentHandler = context.Lookup <IReparentNodeHandler>();
            var graphControl = context.CanvasControl as GraphControl;

            layoutHelper = new LayoutHelper(graphControl, node);
            layoutHelper.InitializeLayout();
            handler.InitializeDrag(context);
        }
示例#5
0
        /// <summary>
        /// Finishes the drag and updates the angle of the rotated node.
        /// </summary>
        public void DragFinished(IInputModeContext context, PointD originalLocation, PointD newLocation)
        {
            var vector = (newLocation - rotationCenter).Normalized;

            var angle = CalculateAngle(vector);

            if (ShouldSnap(context))
            {
                angle = SnapAngle(context, angle);
            }
            SetAngle(context, angle);

            // Switch width / height for 'vertical' rotations
            // Note that other parts of the application need support for this feature, too.
            var graph = context.GetGraph();

            if (graph == null)
            {
                return;
            }

            var portContext = new DelegatingContext(context);

            foreach (var portHandle in portHandles)
            {
                portHandle.DragFinished(portContext, originalLocation, newLocation);
            }
            portHandles.Clear();

            // Workaround: if the OrthogonalEdgeEditingContext is used to keep the edges orthogonal, it is not allowed
            // to change that edges manually. Therefore, we explicitly finish the OrthogonalEdgeEditingContext here and
            // then call the edge router.
            var edgeEditingContext = context.Lookup <OrthogonalEdgeEditingContext>();

            if (edgeEditingContext != null && edgeEditingContext.IsInitialized)
            {
                edgeEditingContext.DragFinished();
            }

            if (reshapeHandler != null)
            {
                reshapeHandler.ReshapeFinished(context, node.Layout.ToRectD(), node.Layout.ToRectD());
            }

            if (compoundEdit != null)
            {
                compoundEdit.Commit();
            }

            nodeAngles = null;
            ClearSameAngleHighlights(context);
        }
        protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context)
        {
            var portCandidates = new List <IPortCandidate>();

            // provide existing ports as candidates only if they use EventPortStyle and have no edges attached to them.
            foreach (IPort port in node.Ports)
            {
                if (port.Style is EventPortStyle && context.Lookup <IGraph>().EdgesAt(port).Count == 0)
                {
                    portCandidates.Add(new DefaultPortCandidate(port));
                }
            }

            if (node.Style is ActivityNodeStyle || node.Style is ChoreographyNodeStyle ||
                node.Style is DataObjectNodeStyle || node.Style is AnnotationNodeStyle ||
                node.Style is GroupNodeStyle || node.Style is DataStoreNodeStyle)
            {
                portCandidates.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeTopAnchored));
                portCandidates.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeBottomAnchored));
                portCandidates.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeLeftAnchored));
                portCandidates.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeRightAnchored));
            }
            else if (node.Style is EventNodeStyle || node.Style is GatewayNodeStyle)
            {
                double dmax  = Math.Min(node.Layout.Width / 2, node.Layout.Height / 2);
                var    model = FreeNodePortLocationModel.Instance;
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(0, -dmax))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(dmax, 0))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(0, dmax))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(-dmax, 0))));
            }
            else if (node.Style is ConversationNodeStyle)
            {
                double dx    = 0.5 * Math.Min(node.Layout.Width, node.Layout.Height / BpmnConstants.ConversationWidthHeightRatio);
                double dy    = dx * BpmnConstants.ConversationWidthHeightRatio;
                var    model = FreeNodePortLocationModel.Instance;
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(0, -dy))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(dx, 0))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(0, dy))));
                portCandidates.Add(new DefaultPortCandidate(node, model.CreateParameter(new PointD(0.5, 0.5), new PointD(-dx, 0))));
            }

            var ceim          = context.ParentInputMode as CreateEdgeInputMode;
            var canvasControl = context.CanvasControl;

            if (ceim == null || canvasControl == null || KeyEventRecognizers.ShiftPressed(canvasControl, canvasControl.LastMouse2DEvent))
            {
                // add a dynamic candidate
                portCandidates.Add(new DefaultPortCandidate(node, new FreeNodePortLocationModel()));
            }
            return(portCandidates);
        }
            protected virtual void Clear(IInputModeContext context)
            {
                var snapContext = context.Lookup <GraphSnapContext>();

                if (snapContext != null)
                {
                    snapContext.CollectSnapResults -= CollectSnapResults;
                }
                reshapeSnapResultProviders.Clear();
                originalNodeLayouts.Clear();
                reshapeHandlers.Clear();
                orthogonalEdgeDragHandlers.Clear();
                compoundEdit = null;
            }
            public void Starting(object sender, InputModeEventArgs e)
            {
                IInputModeContext context = e.Context;
                var edgeEditingContext    = context.Lookup <OrthogonalEdgeEditingContext>();

                if (edgeEditingContext != null && !edgeEditingContext.IsInitializing && !edgeEditingContext.IsInitialized)
                {
                    editingContext = edgeEditingContext;
                    editingContext.InitializeDrag(context);
                }
                else
                {
                    editingContext = null;
                }
            }
示例#9
0
        private bool IsTargetNodeOccupied(IInputModeContext context, INode node)
        {
            var ceim = context.ParentInputMode as CreateEdgeInputMode;
            var oeec = context.Lookup <OrthogonalEdgeEditingContext>();

            if (oeec != null && oeec.Enabled)
            {
                // check whether there are already edges going in the same direction
                var graph     = ceim.Graph;
                var dummyEdge = ceim.DummyEdge;
                var direction = dummyEdge.TargetPort.GetLocation() - (dummyEdge.Bends.Count > 0
                          ? dummyEdge.Bends.Last().Location.ToPointD()
                          : dummyEdge.SourcePort.GetLocation());
                var foldingView = graph.GetFoldingView();
                if (foldingView != null && foldingView.Manager.MasterGraph.Contains(node))
                {
                    node = foldingView.GetViewItem(node);
                }
                if (node != null && graph.Contains(node))
                {
                    foreach (var edge in graph.EdgesAt(node))
                    {
                        PointD p1, p2;
                        if (edge.SourcePort.Owner == node)
                        {
                            p1 = edge.SourcePort.GetLocation();
                            p2 = edge.Bends.Count > 0 ? edge.Bends.First().Location.ToPointD() : edge.TargetPort.GetLocation();
                        }
                        else
                        {
                            p1 = edge.TargetPort.GetLocation();
                            p2 = edge.Bends.Count > 0 ? edge.Bends.Last().Location.ToPointD() : edge.SourcePort.GetLocation();
                        }

                        var edgeDirection = p2 - p1;
                        // check whether the edge is orthogonal and points into the same direction.
                        if ((edgeDirection.X == 0 || edgeDirection.Y == 0) && edgeDirection.ScalarProduct(direction) < 0)
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
            public virtual void InitializeReshape(IInputModeContext context)
            {
                this.OriginalBounds = rectangle.TightRectangle;

                // register our CollectSnapResults callback
                var snapContext = context.Lookup <GraphSnapContext>();

                if (snapContext != null)
                {
                    snapContext.CollectSnapResults += CollectSnapResults;
                }

                // store original node layouts, reshape handlers and reshape snap result providers
                foreach (var node in ReshapeNodes)
                {
                    originalNodeLayouts.Add(node, node.Layout.ToRectD());

                    // store reshape handler to change the shape of node
                    var reshapeHandler = node.Lookup <IReshapeHandler>();
                    if (reshapeHandler != null)
                    {
                        reshapeHandler.InitializeReshape(context);
                        reshapeHandlers.Add(node, reshapeHandler);
                    }
                    // store reshape snap result provider to collect snap results where node would snap to snaplines etc.
                    var snapResultProvider = node.Lookup <INodeReshapeSnapResultProvider>();
                    if (snapContext != null && snapResultProvider != null)
                    {
                        reshapeSnapResultProviders.Add(node, snapResultProvider);
                    }
                    // store orthogonal edge drag handler that keeps edges at node orthogonal
                    var orthogonalEdgeDragHandler = OrthogonalEdgeEditingContext.CreateOrthogonalEdgeDragHandler(context, node, false);
                    if (orthogonalEdgeDragHandler != null)
                    {
                        orthogonalEdgeDragHandlers[node] = orthogonalEdgeDragHandler;
                    }
                }

                // update the minimum/maximum size of the handle considering all initial node layouts
                Handle.MinimumSize = CalculateMinimumSize();
                Handle.MaximumSize = CalculateMaximumSize();

                // start a compound undo unit
                this.compoundEdit = context.GetGraph().BeginEdit("Undo Group Resize", "Redo Group Resize");
            }
示例#11
0
        /// <summary>
        /// Snaps the angle to the rotation angles of other nodes and the coordinate axes.
        /// </summary>
        /// <remarks>
        /// Angles near such an angle are replaced with this angle.
        /// </remarks>
        private double SnapAngle(IInputModeContext context, double angle)
        {
            // Check for disabled snapping
            var snapContext = context.Lookup <SnapContext>();

            if (snapContext != null && !snapContext.Enabled)
            {
                return(angle);
            }
            // Same angle snapping
            if (SnapToSameAngleDelta > 0 && nodeAngles != null)
            {
                // Find the first angle that is sufficiently similar
                var candidate = nodeAngles.Where(na => CachingOrientedRectangle.NormalizeAngle(Math.Abs(na.Item1 - angle)) < SnapToSameAngleDelta).OrderBy(na => na.Item1).FirstOrDefault();
                if (candidate != null)
                {
                    // Add highlight to every matching node
                    var canvas = (GraphControl)context.CanvasControl;
                    if (sameAngleHighlightedNodes != candidate.Item2)
                    {
                        ClearSameAngleHighlights(context);
                    }
                    foreach (var matchingNode in candidate.Item2)
                    {
                        canvas.HighlightIndicatorManager.AddHighlight(matchingNode);
                    }
                    sameAngleHighlightedNodes = candidate.Item2;
                    return(candidate.Item1);
                }
                ClearSameAngleHighlights(context);
            }
            if (SnapDelta <= 0.0 || SnapStep == 0)
            {
                return(angle);
            }
            var mod = Math.Abs(angle % SnapStep);

            return((mod < SnapDelta || mod > SnapStep - SnapDelta)
        ? SnapStep * Math.Round(angle / SnapStep)
        : angle);
        }
示例#12
0
 /// <summary>
 /// Delegates to the wrapped context's lookup but cancels the snap context.
 /// </summary>
 public object Lookup(Type type)
 {
     return(type == typeof(SnapContext) ? null : context.Lookup(type));
 }
示例#13
0
 /// <summary>
 /// Returns the group node at the given location.
 /// </summary>
 /// <remarks>
 /// If there is no group node, <code>null</code> is returned.
 /// </remarks>
 private INode GetHitGroupNode(IInputModeContext context, PointD location)
 {
     return(context.Lookup <IHitTester <INode> >()
            .EnumerateHits(context, location)
            .FirstOrDefault(n => graphControl.Graph.IsGroupNode(n)));
 }