/// <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>
        /// Configures custom port handling with the help of <see cref="ILookup"/>.
        /// </summary>
        /// <remarks>
        /// When a user interacts with edges and their endpoints,
        /// node.Lookup(IPortCandidateProvider) is called for the nodes in that graph,
        /// and the framework returns the implementation of IPortCandidateProvider which
        /// supplies the list of available ports.
        ///
        /// Instead of the default, we'll register a custom lookup for type IPortCandidateProvider.
        ///
        /// Note: we'll update this method in a future tutorial step to work with folding.
        /// </remarks>
        private void CustomizePortHandling()
        {
            // Sets auto cleanup to false, since we don't want to remove unoccupied ports.
            Graph.NodeDefaults.Ports.AutoCleanUp = false;

            // First we create a GraphDecorator from the IGraph.
            // GraphDecorator is a utility class that aids in decorating model items from a graph instance.

            // Here, we call NodeDecorator.PortCandidateProviderDecorator
            // to access the lookup decorator for ports - the thing we want to change.

            // One way to decorate the graph is to use the factory design pattern.
            // We set the factory to a lambda expression which
            // returns instances that implement the IPortCandidateProvider interface.

            // Here we can create a CompositePortCandidateProvider that combines various port candidate providers.
            // The ExistingPortsCandidateProvider provides port candidates at the locations of the already existing ports.
            // The NodeCenterPortCandidateProvider provides a single port candidate at the center of the node.
            // The ShapeGeometryPortCandidateProvider provides several port candidates based on the shape of the node.
            Graph.GetDecorator().NodeDecorator.PortCandidateProviderDecorator.SetFactory(
                node => PortCandidateProviders.Combine(
                    PortCandidateProviders.FromExistingPorts(node),
                    PortCandidateProviders.FromNodeCenter(node),
                    PortCandidateProviders.FromShapeGeometry(node)));

            // To modify the existing lookup for a graph element, typically we decorate it with the help
            // of one of graph's Get...Decorator() extension methods,
            // which allows to dynamically insert custom implementations for the specified types.
            // Doing this can be seen as dynamically subclassing
            // the class in question (the INode implementation in this case), but only
            // for the node instances that live in the graph in question and then
            // overriding just their Lookup(Type) method. The only difference to traditional
            // subclassing is that you get the "this" passed in as a parameter.
            // Doing this more than once is like subclassing more and more, so the order matters.
        }
Example #3
0
 internal CustomPortCandidateProvider(INode node)
 {
     this.node = node;
     geometryPortCandidateProvider =
         PortCandidateProviders.Combine(
             PortCandidateProviders.FromNodeCenter(node),
             PortCandidateProviders.FromShapeGeometry(node));
 }
Example #4
0
        /// <summary>
        /// Called upon loading of the form.
        /// This method initializes the graph and the input mode.
        /// </summary>
        /// <seealso cref="InitializeInputModes"/>
        /// <seealso cref="InitializeGraph"/>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            description.LoadFile(new MemoryStream(Resources.description), RichTextBoxStreamType.RichText);

            //Keep shared instances of copied node styles
            graphControl.Clipboard.FromClipboardCopier.Clone = graphControl.Clipboard.FromClipboardCopier.Clone & ~GraphCopier.CloneTypes.NodeStyle;
            graphControl.Clipboard.ToClipboardCopier.Clone   = graphControl.Clipboard.ToClipboardCopier.Clone & ~GraphCopier.CloneTypes.NodeStyle;

            // write symbolic style name in graphml to make the nodes use the default style when imported, not the specific style instance
            // otherwise, 'change color' wouldn't work on imported nodes
            graphControl.GraphMLIOHandler.QueryReferenceId += delegate(object sender, QueryReferenceIdEventArgs args) { if (args.Value == defaultStyle)
                                                                                                                        {
                                                                                                                            args.ReferenceId = "defaultStyle";
                                                                                                                        }
            };

            // if node style is string "defaultStyle" in graphml, assign defaultStyle
            graphControl.GraphMLIOHandler.ResolveReference += delegate(object sender, ResolveReferenceEventArgs args) { if (args.ReferenceId == "defaultStyle")
                                                                                                                        {
                                                                                                                            args.Value = defaultStyle;
                                                                                                                        }
            };

            graphControl.Graph.SetUndoEngineEnabled(true);
            UndoEngine engine = graphControl.Graph.GetUndoEngine();

            if (engine != null)
            {
                engine.AutoMergeTime    = TimeSpan.FromMilliseconds(100);
                engine.PropertyChanged += delegate {
                    UpdateUndoState();
                };
            }
            UpdateUndoState();

            // Add some more interesting port candidates.
            GraphDecorator decorator = graphControl.Graph.GetDecorator();

            decorator.NodeDecorator.PortCandidateProviderDecorator.SetFactory(
                node => PortCandidateProviders.FromShapeGeometry(node));

            // add callbacks to the business objects at the nodes in the graph
            graphControl.Graph.NodeCreated += OnNodeCreated;
            graphControl.Graph.NodeRemoved += OnNodeRemoved;

            // initialize the graph
            InitializeGraph();

            // reset the Undo queue so the initial graph creation cannot be undone
            graphControl.Graph.GetUndoEngine().Clear();

            // initialize the input mode
            InitializeInputModes();
        }
 /// <summary>
 /// Returns a central port candidate if the owner node of the source
 /// candidate is green, and an empty list otherwise.
 /// </summary>
 public override IEnumerable <IPortCandidate> GetTargetPortCandidates(IInputModeContext context, IPortCandidate source)
 {
     // Check if the source node is green
     if (Color.Green.Equals(source.Owner.Tag))
     {
         return(PortCandidateProviders.FromNodeCenter(node).GetTargetPortCandidates(context, source));
     }
     else
     {
         return(new IPortCandidate[0]);
     }
 }
Example #6
0
        /// <summary>
        ///  Callback used by the decorator in <see cref="CreateEditorMode"/>
        /// </summary>
        private IPortCandidateProvider GetPortCandidateProvider(INode forNode)
        {
            var model = new MyNodePortLocationModel {
                Inset = 10
            };

            return(PortCandidateProviders.FromCandidates(
                       new DefaultPortCandidate(forNode, model.CreateParameter(PortLocation.Center)),
                       new DefaultPortCandidate(forNode, model.CreateParameter(PortLocation.North)),
                       new DefaultPortCandidate(forNode, model.CreateParameter(PortLocation.East)),
                       new DefaultPortCandidate(forNode, model.CreateParameter(PortLocation.South)),
                       new DefaultPortCandidate(forNode, model.CreateParameter(PortLocation.West))));
        }
        private void CreateSampleGraph()
        {
            IGraph graph = graphControl.Graph;

            CreateNode(graph, 100, 100, 80, 30, Colors.Firebrick, "No Edge");
            CreateNode(graph, 350, 100, 80, 30, Colors.Green, "Green Only");
            CreateNode(graph, 100, 200, 80, 30, Colors.Green, "Green Only");
            CreateNode(graph, 350, 200, 80, 30, Colors.Firebrick, "No Edge");

            // The blue nodes have predefined ports
            var portStyle = new ColorPortStyle();

            var blue1 = CreateNode(graph, 100, 300, 80, 30, Colors.RoyalBlue, "One   Port");

            graph.AddPort(blue1, blue1.Layout.GetCenter(), portStyle).Tag = Colors.Black;

            var blue2 = CreateNode(graph, 350, 300, 100, 100, Colors.RoyalBlue, "Many Ports");
            var portCandidateProvider = PortCandidateProviders.FromShapeGeometry(blue2, 0, 0.25, 0.5,
                                                                                 0.75);

            portCandidateProvider.Style = portStyle;
            portCandidateProvider.Tag   = Colors.Black;
            var candidates = portCandidateProvider.GetSourcePortCandidates(graphControl.InputModeContext);

            foreach (IPortCandidate portCandidate in candidates)
            {
                if (portCandidate.Validity != PortCandidateValidity.Dynamic)
                {
                    portCandidate.CreatePort(graphControl.InputModeContext);
                }
            }

            // The orange node
            CreateNode(graph, 100, 400, 100, 100, Colors.Orange, "Dynamic Ports");

            INode n = CreateNode(graph, 100, 540, 100, 100, Colors.Purple, "Individual\nPort Constraints");

            AddIndividualPorts(graph, n);

            n = CreateNode(graph, 350, 540, 100, 100, Colors.Purple, "Individual\nPort Constraints");
            AddIndividualPorts(graph, n);
        }
Example #8
0
        /// <summary>
        ///   Creates the sample graph of this demo.
        /// </summary>
        private void CreateSampleGraph(GraphControl graphControl)
        {
            var graph          = graphControl.Graph;
            var blackPortStyle =
                new NodeStylePortStyleAdapter(new ShapeNodeStyle
            {
                Shape = ShapeNodeShape.Ellipse,
                Brush = Brushes.Black,
                Pen   = null
            })
            {
                RenderSize = new SizeD(3, 3)
            };

            graph.SetUndoEngineEnabled(true);

            CreateSubgraph(graph, Colors.Firebrick, 0);
            CreateSubgraph(graph, Colors.Orange, 200);
            CreateSubgraph(graph, Colors.Green, 600);

            // the blue nodes have some additional ports besides the ones used by the edge
            var nodes = CreateSubgraph(graph, Colors.RoyalBlue, 400);

            graph.AddPort(nodes[0], FreeNodePortLocationModel.Instance.CreateParameter(new PointD(1, 0.2)), blackPortStyle);
            graph.AddPort(nodes[0], FreeNodePortLocationModel.Instance.CreateParameter(new PointD(1, 0.8)), blackPortStyle);

            var candidateProvider = PortCandidateProviders.FromShapeGeometry(nodes[2], 0, 0.25, 0.5, 0.75);

            candidateProvider.Style = blackPortStyle;
            IEnumerable <IPortCandidate> candidates = candidateProvider.GetSourcePortCandidates(graphControl.InputModeContext);

            foreach (IPortCandidate portCandidate in candidates)
            {
                if (portCandidate.Validity != PortCandidateValidity.Dynamic)
                {
                    portCandidate.CreatePort(graphControl.InputModeContext);
                }
            }
            graph.GetUndoEngine().Clear();
        }
Example #9
0
        /// <summary>
        /// Creates an <see cref="IPortCandidateProvider"/> that considers the node's shape and rotation.
        /// </summary>
        private static IPortCandidateProvider CreatePortCandidateProvider(INode node)
        {
            var rotatedPortModel = RotatablePortLocationModelDecorator.Instance;
            var freeModel        = FreeNodePortLocationModel.Instance;

            var rnsd    = (RotatableNodeStyleDecorator)node.Style;
            var wrapped = rnsd.Wrapped;
            var sns     = wrapped as ShapeNodeStyle;

            if (wrapped is ShinyPlateNodeStyle || wrapped is BevelNodeStyle ||
                sns != null && sns.Shape == ShapeNodeShape.RoundRectangle)
            {
                return(PortCandidateProviders.Combine(
                           //Take all existing ports - these are assumed to have the correct port location model
                           PortCandidateProviders.FromUnoccupiedPorts(node),
                           //Provide explicit candidates - these are all backed by a rotatable port location model
                           PortCandidateProviders.FromCandidates(
                               //Port candidates at the corners that are slightly inset
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(freeModel.CreateParameter(new PointD(0, 0), new PointD(5, 5)))),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(freeModel.CreateParameter(new PointD(0, 1), new PointD(5, -5)))),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(freeModel.CreateParameter(new PointD(1, 0), new PointD(-5, 5)))),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(freeModel.CreateParameter(new PointD(1, 1), new PointD(-5, -5)))),
                               //Port candidates at the sides and the center
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeLeftAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeBottomAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeCenterAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeTopAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeRightAnchored))
                               )));
            }
            if (sns != null && sns.Shape == ShapeNodeShape.Rectangle)
            {
                return(PortCandidateProviders.Combine(
                           PortCandidateProviders.FromUnoccupiedPorts(node),
                           PortCandidateProviders.FromCandidates(
                               //Port candidates at the corners
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeTopLeftAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeTopRightAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeBottomLeftAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeBottomRightAnchored)),
                               //Port candidates at the sides and the center
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeLeftAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeBottomAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeCenterAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeTopAnchored)),
                               new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(FreeNodePortLocationModel.NodeRightAnchored))
                               )));
            }
            if (sns != null)
            {
                // Can be an arbitrary shape. First create a dummy node that is not rotated
                var dummyNode = new SimpleNode
                {
                    Style  = sns,
                    Layout = node.Layout
                };
                var shapeProvider      = PortCandidateProviders.FromShapeGeometry(dummyNode, 0);
                var shapeCandidates    = shapeProvider.GetTargetPortCandidates(null);
                var rotatingCandidates =
                    shapeCandidates.Select(c => new DefaultPortCandidate(node, rotatedPortModel.CreateWrappingParameter(c.LocationParameter)));
                return(PortCandidateProviders.Combine(
                           PortCandidateProviders.FromUnoccupiedPorts(node),
                           PortCandidateProviders.FromCandidates(rotatingCandidates)));
            }
            return(null);
        }