示例#1
0
            /// <summary>
            ///   Returns candidates for all ports at orange nodes in the graph, except
            ///   for the current source node to avoid the creation of self-loops.
            /// </summary>
            public IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context)
            {
                List <IPortCandidate> result = new List <IPortCandidate>();

                // add the current one as the default
                result.Add(new DefaultPortCandidate(edge.TargetPort));
                var graph = context.GetGraph();

                if (graph == null)
                {
                    return(result);
                }
                foreach (INode node in graph.Nodes)
                {
                    if (node != edge.SourcePort.Owner && Colors.Orange.Equals(node.Tag))
                    {
                        // If available, use the candidates from the provider. Otherwise, add a default candidate.
                        IPortCandidateProvider provider = node.Lookup <IPortCandidateProvider>();
                        if (provider != null)
                        {
                            result.AddRange(provider.GetTargetPortCandidates(context));
                        }
                        else
                        {
                            result.Add(new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored));
                        }
                    }
                }
                return(result);
            }
            /// <summary>
            /// Returns a list that contains a port candidate for each of the node's
            /// ports. Each candidate has the same location as the port. If a port
            /// already has a connected edge, its port candidate is marked as invalid.
            /// </summary>
            /// <remarks>
            /// Note that the variants of getPortCandidates for target ports are all
            /// implemented by this class. Therefore, this method is only used for
            /// source ports.
            /// </remarks>
            protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context)
            {
                List <IPortCandidate> candidates = new List <IPortCandidate>();
                bool hasValid = false;
                var  graph    = context.GetGraph();

                if (graph != null)
                {
                    // Create a port candidate for each port on the node
                    foreach (IPort port in node.Ports)
                    {
                        DefaultPortCandidate portCandidate = new DefaultPortCandidate(port);
                        bool valid = graph.OutDegree(port) == 0;
                        hasValid |= valid;
                        portCandidate.Validity = valid ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid;
                        candidates.Add(portCandidate);
                    }
                }

                // If no valid candidates have been created so far, use the ShapeGeometryPortCandidateProvider as fallback.
                // This provides a candidate in the middle of each of the four sides of the node.
                if (!hasValid)
                {
                    candidates.AddRange(PortCandidateProviders.FromShapeGeometry(node).GetSourcePortCandidates(context));
                }
                return(candidates);
            }
            /// <summary>
            /// Returns a list that contains a port candidate for each of the node's
            /// ports. Each candidate has the same location as the port. If a port
            /// already has a connected edge, its port candidate is marked as invalid.
            /// </summary>
            /// <remarks>
            /// Note that the various variants of getPortCandidates of
            /// <see cref="PortCandidateProviderBase"/> delegate to this method.
            /// This can be used to provide the same candidates for all use-cases.
            /// </remarks>
            protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context)
            {
                List <IPortCandidate> candidates = new List <IPortCandidate>();
                var graph = context.GetGraph();

                // Create the candidate for each port
                if (graph != null)
                {
                    foreach (IPort port in node.Ports)
                    {
                        DefaultPortCandidate portCandidate = new DefaultPortCandidate(port);
                        portCandidate.Validity = graph.Degree(port) == 0 ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid;
                        candidates.Add(portCandidate);
                    }
                }

                // If no candidates have been created so far, create a single invalid candidate as fallback
                if (candidates.Count == 0)
                {
                    DefaultPortCandidate item = new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored);
                    item.Validity = PortCandidateValidity.Invalid;
                    candidates.Add(item);
                }

                return(candidates);
            }
示例#4
0
            // a button has been hit: perform the action
            public void OnClicked(IInputModeContext context, PointD location)
            {
                var hitInfo   = GetHitInfo(location);
                var classInfo = (ClassInfo)node.Tag;
                var graph     = context.GetGraph();

                switch (hitInfo)
                {
                case HitInfo.None:
                    break;

                case HitInfo.ToggleAllDetails:
                    classInfo.ShowDetails = !classInfo.ShowDetails;
                    if (graph != null)
                    {
                        graph.AddUndoUnit("Toggle Details", "Toggle Details", () => classInfo.ShowDetails = !classInfo.ShowDetails,
                                          () => classInfo.ShowDetails = !classInfo.ShowDetails);
                    }
                    AdjustNodeBoundsCommand.Execute(node, context.CanvasControl);
                    break;

                case HitInfo.TogglePropertyDetails:
                    classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden;
                    if (graph != null)
                    {
                        graph.AddUndoUnit("Toggle Property Details", "Toggle Property Details",
                                          () => classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden,
                                          () => classInfo.Properties.DetailsHidden = !classInfo.Properties.DetailsHidden);
                    }
                    AdjustNodeBoundsCommand.Execute(node, context.CanvasControl);
                    break;

                case HitInfo.ToggleMethodDetails:
                    classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden;
                    if (graph != null)
                    {
                        graph.AddUndoUnit("Toggle Method Details", "Toggle Method Details",
                                          () => classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden,
                                          () => classInfo.Methods.DetailsHidden = !classInfo.Methods.DetailsHidden);
                    }
                    AdjustNodeBoundsCommand.Execute(node, context.CanvasControl);
                    break;

                case HitInfo.ToggleFieldDetails:
                    classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden;
                    if (graph != null)
                    {
                        graph.AddUndoUnit("Toggle Field Details", "Toggle Field Details",
                                          () => classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden,
                                          () => classInfo.Fields.DetailsHidden = !classInfo.Fields.DetailsHidden);
                    }
                    AdjustNodeBoundsCommand.Execute(node, context.CanvasControl);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
示例#5
0
        /// <summary>
        /// The subtree is upon to be dragged.
        /// </summary>
        public void InitializeDrag(IInputModeContext context)
        {
            subtree      = new Subtree(context.GetGraph(), node);
            layoutHelper = new RelocateSubtreeLayoutHelper((GraphControl)context.CanvasControl, subtree);
            layoutHelper.InitializeLayout();

            compositeHandler = CreateCompositeHandler(subtree);
            compositeHandler.InitializeDrag(context);
        }
示例#6
0
        public void DragFinished([NotNull] IInputModeContext context, PointD originalLocation, PointD newLocation)
        {
            CancelDrag(context, originalLocation);
            var graph = context.GetGraph();

            if (graph != null)
            {
                // assign the new size
                graph.SetLabelPreferredSize(label, dummyPreferredSize);
            }
        }
        public override void InitializeDrag(IInputModeContext context)
        {
            var graph = context.GetGraph();

            ZOrderSupport = graph.Lookup <ZOrderSupport>();

            // store initial parent of the node...
            this.initialParent = graph.GetParent(node);
            this.currentParent = initialParent;
            this.dragging      = true;
            base.InitializeDrag(context);
        }
示例#8
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);
        }
示例#9
0
        /// <summary>
        /// Sets the angle to the node style if the style supports this.
        /// </summary>
        private void SetAngle(IInputModeContext context, double angle)
        {
            var wrapper = node.Style as RotatableNodeStyleDecorator;

            if (wrapper != null)
            {
                var oldAngle = wrapper.Angle;
                context.GetGraph().AddUndoUnit("Change Angle", "Change Angle",
                                               () => wrapper.Angle = oldAngle,
                                               () => wrapper.Angle = angle);
                wrapper.Angle = angle;
            }
        }
            public override void HandleReshape(IInputModeContext context, RectD originalBounds, RectD newBounds)
            {
                base.HandleReshape(context, originalBounds, newBounds);
                // some reshaped nodes might got moved outside their parents bounds so enlarge the group node bounds if necessary
                var graph = context.GetGraph();

                foreach (var node in ReshapeNodes)
                {
                    if (graph.IsGroupNode(node))
                    {
                        graph.GetGroupingSupport().EnlargeGroupNode(context, node, true);
                    }
                }
            }
示例#11
0
            /// <summary>
            ///   Returns port candidates for all existing ports at all nodes in the graph as alternatives.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <returns>A sequence of all possible port candidates in <paramref name="context" />'s graph.</returns>
            private IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context)
            {
                var graph = context.GetGraph();

                if (graph == null)
                {
                    return(Enumerable.Empty <IPortCandidate>());
                }

                return
                    (from node in graph.Nodes
                     from port in node.Ports
                     select CreatePortCandidate(node, port));
            }
示例#12
0
                public void DragFinished(IInputModeContext inputModeContext, PointD originalLocation, PointD newLocation)
                {
                    // the value is already set.
                    // we create an Undo unit, though, to make the edit undoable
                    var clipboardBusinessObject = node.Tag as ClipboardBusinessObject;

                    if (clipboardBusinessObject != null && clipboardBusinessObject.Value != originalValue)
                    {
                        var undoEngine = inputModeContext.GetGraph().GetUndoEngine();
                        if (undoEngine != null)
                        {
                            undoEngine.AddUnit(new BusinessValueUndoUnit(clipboardBusinessObject, originalValue));
                        }
                    }
                }
示例#13
0
            /// <summary>
            ///   Returns for each green node a candidate with a dynamic <see cref="FreeNodePortLocationModel"/>.
            ///   When the Shift key is pressed, a port can be placed
            ///   anywhere inside that node.
            /// </summary>
            public IEnumerable <IPortCandidate> GetSourcePortCandidates(IInputModeContext context)
            {
                var graph = context.GetGraph();

                if (graph == null)
                {
                    return(Enumerable.Empty <IPortCandidate>());
                }
                else
                {
                    return
                        (from node in graph.Nodes
                         where Equals(node.Tag, Colors.Green)
                         select(IPortCandidate) new DefaultPortCandidate(node, FreeNodePortLocationModel.Instance));
                }
            }
        public void DragFinished(IInputModeContext context, PointD originalLocation, PointD newLocation)
        {
            var graph = context.GetGraph();

            if (graph != null)
            {
                var model  = label.LayoutParameter.Model;
                var finder = model.Lookup <ILabelModelParameterFinder>();
                if (finder != null)
                {
                    var param = finder.FindBestParameter(label, model, GetCurrentLabelLayout());
                    graph.SetLabelLayoutParameter(label, param);
                }
            }
            CancelDrag(context, originalLocation);
        }
示例#15
0
        /// <summary>
        /// Sets the original node bounds according to the given anchor location and size.
        /// </summary>
        private RectD SetNodeLocationAndSize(IInputModeContext inputModeContext, PointD anchor, SizeD size)
        {
            var graph = inputModeContext.GetGraph();

            if (graph == null)
            {
                return(RectD.Empty);
            }
            var orientedRectangle = new OrientedRectangle(anchor.X, anchor.Y, size.Width, size.Height,
                                                          initialLayout.UpX, initialLayout.UpY);
            var center = orientedRectangle.GetCenter();

            var layout = RectD.FromCenter(center, size);

            graph.SetNodeLayout(node, layout);
            return(layout);
        }
            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");
            }
            /// <summary>
            /// Returns all port candidates that apply for the provided opposite port candidate.
            /// </summary>
            /// <remarks>
            /// In this implementation only source ports with the same color and source ports of nodes
            /// with the same color as the target port are accepted.
            /// </remarks>
            public override IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context, IPortCandidate source)
            {
                List <IPortCandidate> candidates = new List <IPortCandidate>();
                var graph = context.GetGraph();

                if (graph != null)
                {
                    foreach (IPort port in node.Ports)
                    {
                        DefaultPortCandidate portCandidate = new DefaultPortCandidate(port);
                        var  sourcePort = source.CreatePort(context);
                        bool valid      = port.Tag.Equals(source.Owner.Tag) || sourcePort != null && port.Tag.Equals(sourcePort.Tag);
                        portCandidate.Validity = valid ? PortCandidateValidity.Valid : PortCandidateValidity.Invalid;
                        candidates.Add(portCandidate);
                    }
                }

                return(candidates);
            }
        /// <summary>
        /// Returns the suitable candidates based on the specified <see cref="EdgeDirection"/>.
        /// </summary>
        private IEnumerable <IPortCandidate> GetCandidatesForDirection(EdgeDirection direction, IInputModeContext context)
        {
            // If EdgeDirectionPolicy.DetermineFromPortCandidates is used, CreateEdgeInputMode queries GetSourcePortCandidates
            // as well as GetTargetPortCandidates to collect possible port candidates to start the edge creation.
            // In this case this method is called twice (with EdgeDirection.In and EdgeDirection.Out) so for each call we
            // should only return the *valid* port candidates of a port as otherwise for each port a valid as well as an invalid
            // candidate is returned.
            var provideAllCandidates = true;
            var ceim = context.ParentInputMode as CreateEdgeInputMode;

            if (ceim != null)
            {
                // check the edge direction policy as well as whether candidates are collected for starting or ending the edge creation
                provideAllCandidates = ceim.EdgeDirectionPolicy != EdgeDirectionPolicy.DetermineFromPortCandidates ||
                                       ceim.IsCreationInProgress;
            }

            var candidates = new List <IPortCandidate>();

            // iterate over all available ports
            foreach (var port in context.GetGraph().Ports)
            {
                // create a port candidate, invalidate it (so it is visible but not usable)
                var candidate = new DefaultPortCandidate(port)
                {
                    Validity = PortCandidateValidity.Invalid
                };
                // get the port descriptor
                var portDescriptor = port.Tag as PortDescriptor;
                // make the candidate valid if the direction is the same as the one supplied
                if (portDescriptor != null && portDescriptor.EdgeDirection == direction)
                {
                    candidate.Validity = PortCandidateValidity.Valid;
                }
                // add the candidate to the list
                if (provideAllCandidates || candidate.Validity == PortCandidateValidity.Valid)
                {
                    candidates.Add(candidate);
                }
            }
            // and return the list
            return(candidates);
        }
        public void Uninstall(IInputModeContext context)
        {
            context.GetGraph().NodeLayoutChanged -= NodeLayoutChanged;
            var geim = context.ParentInputMode as GraphEditorInputMode;

            geim.MultiSelectionStarted  -= MultiSelectionStarted;
            geim.MultiSelectionFinished -= MultiSelectionFinished;
            ((GraphControl)context.CanvasControl).Selection.ItemSelectionChanged -= ItemSelectionChanged;

            handleInputMode.DragStarted  -= RegisterReshapedNodes;
            handleInputMode.DragStarting -= moveHandleOrthogonalHelper.Starting;
            handleInputMode.DragFinished -= moveHandleOrthogonalHelper.Finished;
            handleInputMode.DragCanceled -= moveHandleOrthogonalHelper.Canceled;
            handleInputMode.DragStarted  -= moveHandleOrthogonalHelper.Started;

            RemoveRectangleVisualization();
            handleInputMode.Uninstall(context);
            handleInputMode  = null;
            InputModeContext = null;
        }
            /// <summary>
            /// Creates an enumeration of possible port candidates, in this
            /// case one port candidate for each of the node's
            /// ports in the same location as the port.
            /// </summary>
            /// <remarks>
            /// This method is used to provide the same candidates for all
            /// use-cases. It is used as a fallback if methods <c>GetSourcePortCandidates()</c>
            /// and <c>GetTargetPortCandidates()</c> aren't implemented.
            /// </remarks>
            protected override IEnumerable <IPortCandidate> GetPortCandidates(IInputModeContext context)
            {
                List <IPortCandidate> candidates = new List <IPortCandidate>();
                var graph = context.GetGraph();

                if (graph != null)
                {
                    foreach (IPort port in node.Ports)
                    {
                        DefaultPortCandidate portCandidate = new DefaultPortCandidate(port);
                        candidates.Add(portCandidate);
                    }
                }
                if (candidates.Count == 0)
                {
                    DefaultPortCandidate item = new DefaultPortCandidate(node, FreeNodePortLocationModel.NodeCenterAnchored);
                    item.Validity = PortCandidateValidity.Invalid;
                    candidates.Add(item);
                }

                return(candidates);
            }
        public void Install(IInputModeContext context, ConcurrencyController controller)
        {
            InputModeContext = context;
            var geim = context.ParentInputMode as GraphEditorInputMode;

            if (geim == null)
            {
                throw new InvalidOperationException("NodeGroupResizingInputMode must be installed as child mode of GraphEditorInputMode");
            }

            // create own HandleInputMode for the handles
            handleInputMode = new HandleInputMode {
                Priority = 1
            };

            // notify the GraphSnapContext which nodes are resized and shouldn't provide SnapLines
            handleInputMode.DragStarted += RegisterReshapedNodes;

            // forward events to OrthogonalEdgeEditingContext so it can handle keeping edges at reshaped nodes orthogonal
            handleInputMode.DragStarting += moveHandleOrthogonalHelper.Starting;
            handleInputMode.DragStarted  += moveHandleOrthogonalHelper.Started;
            handleInputMode.DragFinished += moveHandleOrthogonalHelper.Finished;
            handleInputMode.DragCanceled += moveHandleOrthogonalHelper.Canceled;

            handleInputMode.Install(context, controller);
            handleInputMode.Enabled = false;

            // update handles depending on the changed node selection
            geim.MultiSelectionStarted  += MultiSelectionStarted;
            geim.MultiSelectionFinished += MultiSelectionFinished;
            ((GraphControl)context.CanvasControl).Selection.ItemSelectionChanged += ItemSelectionChanged;

            // add a NodeLayoutChanged listener so the reshape rect is updated when the nodes are moved (e.g. through
            // layout animations or MoveInputMode).
            context.GetGraph().NodeLayoutChanged += NodeLayoutChanged;
        }