コード例 #1
0
        public NodeConnection Connect(NodeConnector from, NodeConnector to, string name)
        {
            if (from != null)
            {
                foreach (var other in from.Node.Connections)
                {
                    if (other.From == from &&
                        other.To == to)
                    {
                        return(null);
                    }
                }
            }

            if (to != null)
            {
                foreach (var other in to.Node.Connections)
                {
                    if (other.From == from &&
                        other.To == to)
                    {
                        return(null);
                    }
                }
            }

            var connection = new NodeConnection();

            connection.From = from;
            connection.To   = to;
            connection.Name = name;

            if (from != null)
            {
                from.Node.AddConnection(connection);
            }
            if (to != null)
            {
                to.Node.AddConnection(connection);
            }

            if (ConnectionAdded != null)
            {
                var eventArgs = new AcceptNodeConnectionEventArgs(connection);
                ConnectionAdded(this, eventArgs);
                if (eventArgs.Cancel)
                {
                    Disconnect(connection);
                    return(null);
                }
            }

            UpdateRevisionIndex();
            if (InvalidateViews != null)
            {
                InvalidateViews(this, EventArgs.Empty);
            }

            return(connection);
        }
コード例 #2
0
ファイル: GraphRenderer.cs プロジェクト: trizdreaming/XLE
        private static PointF ConnectorInterfacePoint(NodeConnector connector)
        {
            if (connector == null)
            {
                return(new PointF(0.0f, 0.0f));
            }

            RectangleF bounds;

            if (connector.Node.Collapsed)
            {
                return(new PointF(
                           (connector.bounds.Left + connector.bounds.Right) * 0.5f,
                           (connector.bounds.Top + connector.bounds.Bottom) * 0.5f));
            }
            else
            {
                bounds = connector.bounds;
            }

            float width = bounds.Bottom - bounds.Top - 8;

            if (connector.ElementType == ElementType.InputConnector)
            {
                return(new PointF(bounds.Left + width / 2.0f + 4.0f, (bounds.Top + bounds.Bottom) / 2.0f));
            }
            else
            {
                return(new PointF(bounds.Right - width / 2.0f + 4.0f, (bounds.Top + bounds.Bottom) / 2.0f));
            }
        }
コード例 #3
0
        public bool ConnectionIsAllowed(NodeConnector from, NodeConnector to)
        {
            if (null != CompatibilityStrategy)
            {
                if (CompatibilityStrategy.CanConnect(from, to) == ConnectionType.Incompatible)
                {
                    return(false);
                }
            }

            // If someone has subscribed to the ConnectionAdding event,
            // give them a chance to interrupt this connection attempt.
            if (null != ConnectionAdding)
            {
                // Populate a temporary NodeConnection instance.
                var connection = new NodeConnection();
                connection.From = from;
                connection.To   = to;

                // Fire the event and see if someone cancels it.
                var eventArgs = new AcceptNodeConnectionEventArgs(connection);
                ConnectionAdding(this, eventArgs);
                if (eventArgs.Cancel)
                {
                    return(false);
                }
            }
            return(true);
        }
コード例 #4
0
ファイル: ShaderFragmentNodes.cs プロジェクト: ldh9451/XLE
        public HyperGraph.Compatibility.ConnectionType CanConnect(NodeConnector from, NodeConnector to)
        {
            if (null == from.Item.Tag && null == to.Item.Tag) return HyperGraph.Compatibility.ConnectionType.Compatible;
            if (null == from.Item.Tag || null == to.Item.Tag) return HyperGraph.Compatibility.ConnectionType.Incompatible;

            if (from.Item.Tag is string && to.Item.Tag is string)
            {
                string fromType = (string)from.Item.Tag;
                string toType = (string)to.Item.Tag;
                if (fromType.Equals(toType, StringComparison.CurrentCultureIgnoreCase))
                {
                    return HyperGraph.Compatibility.ConnectionType.Compatible;
                }
                else
                {
                    // Some types have automatic conversion operations
                    if (ShaderPatcherLayer.TypeRules.HasAutomaticConversion(fromType, toType))
                    {
                        return HyperGraph.Compatibility.ConnectionType.Conversion;
                    }
                }
            }

            return HyperGraph.Compatibility.ConnectionType.Incompatible;
        }
コード例 #5
0
ファイル: GraphRenderer.cs プロジェクト: taknim/XLE
        public static void RenderInputConnection(Graphics graphics, NodeConnector input, float x, float y, RenderState state)
        {
            if (graphics == null ||
                input == null)
            {
                return;
            }

            RectangleF inputBounds;

            if (input.Node.Collapsed)
            {
                inputBounds = input.Node.inputBounds;
            }
            else
            {
                inputBounds = input.bounds;
            }

            var interfacePoint = ConnectorInterfacePoint(inputBounds, ConnectorType.Input);

            float centerX;
            float centerY;

            using (var path = GetArrowLinePath(x, y, interfacePoint.X, interfacePoint.Y, out centerX, out centerY, true, 0.0f))
            {
                using (var brush = new SolidBrush(GetArrowLineColor(state)))
                {
                    graphics.FillPath(brush, path);
                    graphics.DrawPath(BorderPen, path);
                }
            }
        }
コード例 #6
0
ファイル: GraphControl.cs プロジェクト: coreafive/XLE
        private void EditSimpleConnection(NodeConnector connector)
        {
            using (var dialog = new HyperGraph.TextEditForm())
            {
                var existing = GetSimpleConnection(connector);
                dialog.InputText = (!string.IsNullOrEmpty(existing)) ? existing : "1.0f";

                var result = dialog.ShowDialog();
                if (result == DialogResult.OK)
                {
                    bool foundExisting = false;
                    foreach (var i in connector.Node.Connections)
                        if (i.To == connector && i.From == null)
                        {
                            // empty dialog text means we want to disconnect any existing connections
                            if (dialog.InputText.Length > 0)
                            {
                                i.Name = dialog.InputText;
                            }
                            else
                            {
                                GetGraphModel().Disconnect(i);
                                break;
                            }
                            foundExisting = true;
                        }

                    if (!foundExisting && dialog.InputText.Length > 0)
                        GetGraphModel().Connect(null, connector, dialog.InputText);

                    GetGraphModel().InvokeMiscChange(true);
                }
            }
        }
コード例 #7
0
ファイル: GraphRenderer.cs プロジェクト: trizdreaming/XLE
        public static void RenderOutputConnection(Graphics graphics, NodeConnector output, float x, float y, RenderState state)
        {
            if (graphics == null ||
                output == null)
            {
                return;
            }

            var interfacePoint = ConnectorInterfacePoint(output);

            float centerX;
            float centerY;

            using (var path = GetArrowLinePath(interfacePoint.X, interfacePoint.Y, x, y, out centerX, out centerY, true, 0.0f))
            {
                using (var brush = new SolidBrush(GetArrowLineColor(state)))
                {
                    graphics.FillPath(brush, path);
                    graphics.DrawPath(BorderPen, path);
                }
            }
        }
コード例 #8
0
ファイル: GraphRenderer.cs プロジェクト: trizdreaming/XLE
        static void RenderConnector(Graphics graphics, RectangleF bounds, RenderState state, ConnectorType type, NodeConnector connector = null, bool collapsed = false)
        {
            if (collapsed)
            {
                using (var brush = new SolidBrush(GetArrowLineColor(state)))
                    graphics.FillEllipse(brush, bounds);
                return;
            }

            var cornerSize = GraphConstants.ConnectorCornerSize;

            using (var brush = new SolidBrush(GetArrowLineColor(state)))
            {
                using (var path = new GraphicsPath(FillMode.Winding))
                {
                    Rectangle  statusRect;
                    RectangleF clientRect;

                    if (type == ConnectorType.Input)
                    {
                        path.AddLine(bounds.Right, bounds.Top, bounds.Left + cornerSize, bounds.Top);
                        path.AddArc(bounds.Left, bounds.Top, cornerSize, cornerSize, 270, -90);
                        path.AddLine(bounds.Left, bounds.Top + cornerSize, bounds.Left, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Left, bounds.Bottom - cornerSize, cornerSize, cornerSize, 180, -90);
                        path.AddLine(bounds.Left + cornerSize, bounds.Bottom, bounds.Right, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Left + 4), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 8 + width, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }
                    else
                    {
                        path.AddLine(bounds.Left, bounds.Top, bounds.Right - cornerSize, bounds.Top);
                        path.AddArc(bounds.Right - cornerSize, bounds.Top, cornerSize, cornerSize, 270, 90);
                        path.AddLine(bounds.Right, bounds.Top + cornerSize, bounds.Right, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Right - cornerSize, bounds.Bottom - cornerSize, cornerSize, cornerSize, 0, 90);
                        path.AddLine(bounds.Right - cornerSize, bounds.Bottom, bounds.Left, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Right - 4 - width), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 4, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }

                    graphics.FillPath(((state & RenderState.Hover) != 0) ? HoverBrush : NormalBrush, path);
                    graphics.DrawPath(BorderPen, path);
                    graphics.FillEllipse(brush, statusRect);

                    if (connector != null)
                    {
                        connector.Item.RenderConnector(graphics, clientRect);
                    }
                }
            }
        }
コード例 #9
0
 public NodeConnectionEventArgs(NodeConnector from, NodeConnector to, NodeConnection connection)
 {
     Connection = connection; From = from; To = to;
 }
コード例 #10
0
ファイル: GraphControl.cs プロジェクト: coreafive/XLE
 private string GetSimpleConnection(NodeConnector connector)
 {
     //  look for an existing simple connection attached to this connector
     return connector.Node.Connections.Where(x => x.To == connector && x.From == null).Select(x => x.Name).FirstOrDefault();
 }
コード例 #11
0
ファイル: GraphRenderer.cs プロジェクト: ldh9451/XLE
        static void RenderConnector(Graphics graphics, RectangleF bounds, RenderState state, ConnectorType type, NodeConnector connector=null)
        {
            var cornerSize = GraphConstants.ConnectorCornerSize;

            using (var brush = new SolidBrush(GetArrowLineColor(state)))
            {
                using (var path = new GraphicsPath(FillMode.Winding))
                {
                    Rectangle statusRect;
                    RectangleF clientRect;

                    if (type == ConnectorType.Input)
                    {
                        path.AddLine(bounds.Right, bounds.Top, bounds.Left + cornerSize, bounds.Top);
                        path.AddArc(bounds.Left, bounds.Top, cornerSize, cornerSize, 270, -90);
                        path.AddLine(bounds.Left, bounds.Top + cornerSize, bounds.Left, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Left, bounds.Bottom - cornerSize, cornerSize, cornerSize, 180, -90);
                        path.AddLine(bounds.Left + cornerSize, bounds.Bottom, bounds.Right, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Left + 4), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 8 + width, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }
                    else
                    {
                        path.AddLine(bounds.Left, bounds.Top, bounds.Right - cornerSize, bounds.Top);
                        path.AddArc(bounds.Right - cornerSize, bounds.Top, cornerSize, cornerSize, 270, 90);
                        path.AddLine(bounds.Right, bounds.Top + cornerSize, bounds.Right, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Right - cornerSize, bounds.Bottom - cornerSize, cornerSize, cornerSize, 0, 90);
                        path.AddLine(bounds.Right - cornerSize, bounds.Bottom, bounds.Left, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Right - 4 - width), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 4, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }

                    graphics.FillPath(NormalBrush, path);
                    graphics.DrawPath(BorderPen, path);
                    graphics.FillRectangle(brush, statusRect);

                    if ((state & (RenderState.Compatible | RenderState.Conversion | RenderState.Dragging)) == RenderState.Compatible)
                    {
                        graphics.FillRectangle(CompatibleBrush, statusRect);
                        graphics.DrawRectangle(BorderPen, statusRect);
                    }
                    else
                    {
                        graphics.FillRectangle(brush, statusRect);
                    }

                    if (connector!=null)
                    {
                        connector.Item.RenderConnector(graphics, clientRect);
                    }
                }
            }
        }
コード例 #12
0
ファイル: GraphControl.cs プロジェクト: ldh9451/XLE
        public NodeConnection Connect(NodeConnector from, NodeConnector to)
        {
            if (from      == null || to      == null ||
                from.Node == null || to.Node == null ||
                !from.Enabled ||
                !to.Enabled)
                return null;

            foreach (var other in from.Node.connections)
            {
                if (other.From == from &&
                    other.To == to)
                    return null;
            }

            foreach (var other in to.Node.connections)
            {
                if (other.From == from &&
                    other.To == to)
                    return null;
            }

            var connection = new NodeConnection();
            connection.From = from;
            connection.To = to;

            from.Node.connections.Add(connection);
            to.Node.connections.Add(connection);

            if (ConnectionAdded != null)
            {
                var eventArgs = new AcceptNodeConnectionEventArgs(connection);
                ConnectionAdded(this, eventArgs);
                if (eventArgs.Cancel)
                {
                    Disconnect(connection);
                    return null;
                }
            }

            return connection;
        }
コード例 #13
0
ファイル: GraphControl.cs プロジェクト: ldh9451/XLE
        /// <summary>
        /// Checks whether the connection between two connectors is allowed.
        /// This is achieved through event propagation.
        /// </summary>
        /// <returns></returns>
        private bool ConnectionIsAllowed(NodeConnector from, NodeConnector to)
        {
            if (HighlightCompatible && null != CompatibilityStrategy)
            {
                if (CompatibilityStrategy.CanConnect(from, to) == ConnectionType.Incompatible)
                    return false;
            }

            // If someone has subscribed to the ConnectionAdding event,
            // give them a chance to interrupt this connection attempt.
            if (null != ConnectionAdding)
            {
                // Populate a temporary NodeConnection instance.
                var connection = new NodeConnection();
                connection.From = from;
                connection.To = to;

                // Fire the event and see if someone cancels it.
                var eventArgs = new AcceptNodeConnectionEventArgs(connection);
                ConnectionAdding(this, eventArgs);
                if (eventArgs.Cancel)
                    return false;
            }
            return true;
        }
コード例 #14
0
ファイル: IGraphModel.cs プロジェクト: coreafive/XLE
 public NodeConnectionEventArgs(NodeConnector from, NodeConnector to, NodeConnection connection) { Connection = connection; From = from; To = to; }
コード例 #15
0
ファイル: GraphRenderer.cs プロジェクト: taknim/XLE
        static void RenderConnector(Graphics graphics, RectangleF bounds, RenderState state, ConnectorType type, NodeConnector connector = null)
        {
            var cornerSize = GraphConstants.ConnectorCornerSize;

            using (var brush = new SolidBrush(GetArrowLineColor(state)))
            {
                using (var path = new GraphicsPath(FillMode.Winding))
                {
                    Rectangle  statusRect;
                    RectangleF clientRect;

                    if (type == ConnectorType.Input)
                    {
                        path.AddLine(bounds.Right, bounds.Top, bounds.Left + cornerSize, bounds.Top);
                        path.AddArc(bounds.Left, bounds.Top, cornerSize, cornerSize, 270, -90);
                        path.AddLine(bounds.Left, bounds.Top + cornerSize, bounds.Left, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Left, bounds.Bottom - cornerSize, cornerSize, cornerSize, 180, -90);
                        path.AddLine(bounds.Left + cornerSize, bounds.Bottom, bounds.Right, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Left + 4), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 8 + width, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }
                    else
                    {
                        path.AddLine(bounds.Left, bounds.Top, bounds.Right - cornerSize, bounds.Top);
                        path.AddArc(bounds.Right - cornerSize, bounds.Top, cornerSize, cornerSize, 270, 90);
                        path.AddLine(bounds.Right, bounds.Top + cornerSize, bounds.Right, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Right - cornerSize, bounds.Bottom - cornerSize, cornerSize, cornerSize, 0, 90);
                        path.AddLine(bounds.Right - cornerSize, bounds.Bottom, bounds.Left, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Right - 4 - width), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 4, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }

                    graphics.FillPath(NormalBrush, path);
                    graphics.DrawPath(BorderPen, path);
                    graphics.FillRectangle(brush, statusRect);

                    if ((state & (RenderState.Compatible | RenderState.Conversion | RenderState.Dragging)) == RenderState.Compatible)
                    {
                        graphics.FillRectangle(CompatibleBrush, statusRect);
                        graphics.DrawRectangle(BorderPen, statusRect);
                    }
                    else
                    {
                        graphics.FillRectangle(brush, statusRect);
                    }

                    if (connector != null)
                    {
                        connector.Item.RenderConnector(graphics, clientRect);
                    }
                }
            }
        }
コード例 #16
0
ファイル: GraphRenderer.cs プロジェクト: ldh9451/XLE
        public static void RenderOutputConnection(Graphics graphics, NodeConnector output, float x, float y, RenderState state)
        {
            if (graphics == null ||
                output == null)
                return;

            RectangleF outputBounds;
            if (output.Node.Collapsed)	outputBounds = output.Node.outputBounds;
            else						outputBounds = output.bounds;

            var interfacePoint = ConnectorInterfacePoint(outputBounds, ConnectorType.Output);

            float centerX;
            float centerY;
            using (var path = GetArrowLinePath(interfacePoint.X, interfacePoint.Y, x, y, out centerX, out centerY, true, 0.0f))
            {
                using (var brush = new SolidBrush(GetArrowLineColor(state)))
                {
                    graphics.FillPath(brush, path);
                    graphics.DrawPath(BorderPen, path);
                }
            }
        }
コード例 #17
0
ファイル: GraphRenderer.cs プロジェクト: coreafive/XLE
		static void RenderConnector(Graphics graphics, RectangleF bounds, RenderState state, ConnectorType type, NodeConnector connector=null, bool collapsed=false)
		{
            if (collapsed)
            {
                using (var brush = new SolidBrush(GetArrowLineColor(state)))
                    graphics.FillEllipse(brush, bounds);
                return;
            }

            var cornerSize = GraphConstants.ConnectorCornerSize;

			using (var brush = new SolidBrush(GetArrowLineColor(state)))
			{
                using (var path = new GraphicsPath(FillMode.Winding))
                {
                    Rectangle statusRect;
                    RectangleF clientRect;

                    if (type == ConnectorType.Input)
                    {
                        path.AddLine(bounds.Right, bounds.Top, bounds.Left + cornerSize, bounds.Top);
                        path.AddArc(bounds.Left, bounds.Top, cornerSize, cornerSize, 270, -90);
                        path.AddLine(bounds.Left, bounds.Top + cornerSize, bounds.Left, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Left, bounds.Bottom - cornerSize, cornerSize, cornerSize, 180, -90);
                        path.AddLine(bounds.Left + cornerSize, bounds.Bottom, bounds.Right, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Left + 4), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 8 + width, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }
                    else
                    {
                        path.AddLine(bounds.Left, bounds.Top, bounds.Right - cornerSize, bounds.Top);
                        path.AddArc(bounds.Right - cornerSize, bounds.Top, cornerSize, cornerSize, 270, 90);
                        path.AddLine(bounds.Right, bounds.Top + cornerSize, bounds.Right, bounds.Bottom - cornerSize);
                        path.AddArc(bounds.Right - cornerSize, bounds.Bottom - cornerSize, cornerSize, cornerSize, 0, 90);
                        path.AddLine(bounds.Right - cornerSize, bounds.Bottom, bounds.Left, bounds.Bottom);

                        int width = (int)(bounds.Bottom - bounds.Top - 8);
                        statusRect = new Rectangle((int)(bounds.Right - 4 - width), (int)(bounds.Top + 4), width, (int)(bounds.Height - 8));
                        clientRect = new RectangleF(bounds.Left + 4, bounds.Top + 4, bounds.Width - 12 - width, bounds.Height - 8);
                    }

                    graphics.FillPath(((state & RenderState.Hover)!=0) ? HoverBrush : NormalBrush , path);
                    graphics.DrawPath(BorderPen, path);
                    graphics.FillEllipse(brush, statusRect);

                    if (connector!=null)
                    {
                        connector.Item.RenderConnector(graphics, clientRect);
                    }
                }
			}
		}
コード例 #18
0
ファイル: GraphControl.cs プロジェクト: coreafive/XLE
 private void DisconnectAll(NodeConnector connector)
 {
     var connectionsDupe = connector.Node.Connections.ToArray();
     foreach (var i in connectionsDupe)
         if (i.To == connector || i.From == connector)
             GetGraphModel().Disconnect(i);
 }
コード例 #19
0
ファイル: GraphRenderer.cs プロジェクト: coreafive/XLE
        private static PointF ConnectorInterfacePoint(NodeConnector connector)
        {
            if (connector == null) return new PointF(0.0f, 0.0f);

            RectangleF bounds;
            if (connector.Node.Collapsed)
            {
                return new PointF(
                    (connector.bounds.Left + connector.bounds.Right) * 0.5f,
                    (connector.bounds.Top + connector.bounds.Bottom) * 0.5f);
            } else
                bounds = connector.bounds;

            float width = bounds.Bottom - bounds.Top - 8;
            if (connector.ElementType == ElementType.InputConnector) {
                return new PointF(bounds.Left + width / 2.0f + 4.0f, (bounds.Top + bounds.Bottom) / 2.0f);
            } else {
                return new PointF(bounds.Right - width / 2.0f + 4.0f, (bounds.Top + bounds.Bottom) / 2.0f);
            }
        }
コード例 #20
0
ファイル: GraphRenderer.cs プロジェクト: coreafive/XLE
		public static void RenderInputConnection(Graphics graphics, NodeConnector input, float x, float y, RenderState state)
		{
			if (graphics == null || 
				input == null)
				return;
			
            var interfacePoint = ConnectorInterfacePoint(input);

			float centerX;
			float centerY;
            using (var path = GetArrowLinePath(x, y, interfacePoint.X, interfacePoint.Y, out centerX, out centerY, true, 0.0f))
			{
				using (var brush = new SolidBrush(GetArrowLineColor(state)))
				{
					graphics.FillPath(brush, path);
                    graphics.DrawPath(BorderPen, path);
				}
			}
		}
コード例 #21
0
ファイル: GraphModel.cs プロジェクト: coreafive/XLE
        public NodeConnection Connect(NodeConnector from, NodeConnector to, string name)
        {
            if (from != null)
            {
                foreach (var other in from.Node.Connections)
                {
                    if (other.From == from &&
                        other.To == to)
                        return null;
                }
            }

            if (to != null)
            {
                foreach (var other in to.Node.Connections)
                {
                    if (other.From == from &&
                        other.To == to)
                        return null;
                }
            }

            var connection = new NodeConnection();
            connection.From = from;
            connection.To = to;
            connection.Name = name;

            if (from != null)
                from.Node.AddConnection(connection);
            if (to != null)
                to.Node.AddConnection(connection);

            if (ConnectionAdded != null)
            {
                var eventArgs = new AcceptNodeConnectionEventArgs(connection);
                ConnectionAdded(this, eventArgs);
                if (eventArgs.Cancel)
                {
                    Disconnect(connection);
                    return null;
                }
            }

            UpdateRevisionIndex();
            if (InvalidateViews != null) 
                InvalidateViews(this, EventArgs.Empty);

            return connection;
        }