using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Forms; using static VisualScript.Form1; namespace VisualScript { public partial class Form1 : Form { #region Member private static Panel canvasPanel; private static PropertyGrid propertyGrid; private List<Node> nodes; private static List<Connector> connectors; private Node selectedNode; private Port selectedPort; private Point draggingStartPoint; private Connector selectedConnector; //private static SplitContainer splitContainer; private static MenuStrip menuStrip; #endregion #region Initializer public Form1() { InitializeComponent(); InitializeComponents(); } private void InitializeComponents() { // Menüleiste erstellen menuStrip = new MenuStrip(); ToolStripMenuItem fileMenu = new ToolStripMenuItem("Node"); ToolStripMenuItem menuItemNewVariable = new ToolStripMenuItem("Variable"); menuItemNewVariable.Click += MenuItemNewVariable_Click; ToolStripMenuItem menuItemNewAddNode = new ToolStripMenuItem("AddNode"); menuItemNewAddNode.Click += MenuItemNewAddNode_Click; ToolStripMenuItem menuItemNewSubNode = new ToolStripMenuItem("SubNode"); menuItemNewSubNode.Click += MenuItemNewSubNode_Click; ToolStripMenuItem menuItemNewMulNode = new ToolStripMenuItem("MulNode"); menuItemNewMulNode.Click += MenuItemNewMulNode_Click; ToolStripMenuItem menuItemNewDivNode = new ToolStripMenuItem("DivNode"); menuItemNewDivNode.Click += MenuItemNewDivNode_Click; // Menüpunkte hinzufügen fileMenu.DropDownItems.Add(menuItemNewVariable); fileMenu.DropDownItems.Add(menuItemNewAddNode); fileMenu.DropDownItems.Add(menuItemNewSubNode); fileMenu.DropDownItems.Add(menuItemNewMulNode); fileMenu.DropDownItems.Add(menuItemNewDivNode); // Menü zur Menüleiste hinzufügen menuStrip.Items.Add(fileMenu); this.Controls.Add(menuStrip); // Canvas Panel canvasPanel = new Panel(); canvasPanel.Dock = DockStyle.Fill; canvasPanel.Paint += canvasPanel_Paint; canvasPanel.MouseClick += canvasPanel_MouseClick; // Wenn Maus angeklickt und losgelassen wurde canvasPanel.MouseDown += canvasPanel_MouseDown; // Wenn Maus angeklickt wurde canvasPanel.MouseMove += canvasPanel_MouseMove; canvasPanel.MouseUp += canvasPanel_MouseUp; //this.Controls.Add(canvasPanel); // Property Grid propertyGrid = new PropertyGrid(); propertyGrid.Dock = DockStyle.Fill; //this.Controls.Add(propertyGrid); splitContainer1.Panel1.Controls.Add(canvasPanel); splitContainer1.Panel2.Controls.Add(propertyGrid); //this.Controls.Add(splitContainer); // Liste für Nodes und Connectors initialisieren nodes = new List<Node>(); connectors = new List<Connector>(); } #endregion #region MenuItems Click Events private void MenuItemNewVariable_Click(object sender, EventArgs e) { nodes.Add(new VariableNode()); canvasPanel.Invalidate(); } private void MenuItemNewAddNode_Click(object sender, EventArgs e) { nodes.Add(new AddNode()); canvasPanel.Invalidate(); } private void MenuItemNewSubNode_Click(object sender, EventArgs e) { nodes.Add(new SubNode()); canvasPanel.Invalidate(); } private void MenuItemNewMulNode_Click(object sender, EventArgs e) { nodes.Add(new MulNode()); canvasPanel.Invalidate(); } private void MenuItemNewDivNode_Click(object sender, EventArgs e) { nodes.Add(new DivNode()); canvasPanel.Invalidate(); } #endregion #region Form Event Handler private void canvasPanel_Paint(object sender, PaintEventArgs e) { // Draw Connectors foreach (var connector in connectors) { e.Graphics.DrawLine(Pens.Black, connector.StartPort.Location, connector.EndPort.Location); } // Draw nodes foreach (var node in nodes) node.Paint(sender, e); } private void canvasPanel_MouseClick(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Left) { // Check if a Node is selected foreach (var node in nodes) { if (node.Bounds.Contains(e.Location)) { selectedNode = node; selectedPort = null; propertyGrid.SelectedObject = selectedNode; canvasPanel.Invalidate(); return; } } // Check if a Port is selected foreach (var node in nodes) { var clickedPort = node.InputPorts.Concat<Port>(node.OutputPorts).FirstOrDefault(port => port.Bounds.Contains(e.Location)); if (clickedPort != null) { if (selectedPort == null) { // If no port was selected, select the clicked port selectedPort = clickedPort; propertyGrid.SelectedObject = selectedPort; } else { // If a port was already selected, start the connection ConnectPorts(selectedPort, clickedPort); selectedPort = null; canvasPanel.Invalidate(); } return; } } // Überprüfen, ob auf einen Connector geklickt wurde foreach (var connector in connectors) { //var connectorBounds = GetConnectorBounds(connector); //if (connectorBounds.Contains(e.Location)) if (IsPointOnConnector(e.Location, connector)) { // Connector auswählen selectedConnector = connector; selectedNode = null; selectedPort = null; // Aktualisieren Sie das PropertyGrid für den ausgewählten Connector propertyGrid.SelectedObject = selectedConnector; //selectedConnector = null; canvasPanel.Invalidate(); return; } } } else if (e.Button == MouseButtons.Right) { // Überprüfen, ob auf einen Connector geklickt wurde foreach (var connector in connectors) { if (IsPointOnConnector(e.Location, connector)) { // Connector löschen connectors.Remove(connector); connector.StartPort.Connected = false; connector.EndPort.Connected = false; selectedNode = null; UpdateConnectors(); propertyGrid.Refresh(); canvasPanel.Invalidate(); return; } } List<Node> nodesToRemove = new List<Node>(); foreach (Node n in nodes) { //if (IsPointOnNode(e.Location, n)) if (n.Bounds.Contains(e.Location)) { nodesToRemove.Add(n); break; } } foreach (Node n in nodesToRemove) { nodes.Remove(n); } canvasPanel.Invalidate(); return; } if (e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Control) { var newNode = new VariableNode { X = e.X, Y = e.Y }; nodes.Add(newNode); //selectedNode = newNode; selectedPort = null; propertyGrid.SelectedObject = selectedNode; canvasPanel.Invalidate(); return; } //UpdateConnectors(); // ?? selectedNode = null; //selectedPort = null; propertyGrid.SelectedObject = null; } private void canvasPanel_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { bool test = false; foreach (Node node in nodes) { if (node.Bounds.Contains(e.Location)) { test = true; } } if (!test) { selectedNode = null; //return; } // Prüfen, ob ein existierender Node ausgewählt wurde if (selectedNode != null && selectedNode.Bounds.Contains(e.Location)) { draggingStartPoint = e.Location; return; } // Wenn ein Port ausgewählt wurde, starten Sie die Verbindung if (selectedPort != null && selectedNode != null) { var clickedPort = selectedNode.InputPorts.Concat<Port>(selectedNode.OutputPorts).FirstOrDefault(port => port.Bounds.Contains(e.Location)); if (clickedPort != null && clickedPort != selectedPort) { // Hier wird der Verbindungscode aufgerufen, wenn ein Port ausgewählt ist ConnectPorts(selectedPort, clickedPort); selectedPort = null; canvasPanel.Invalidate(); return; } } // Hier können Sie den Code für das Verschieben eines Nodes implementieren foreach (var node in nodes) { if (node.Bounds.Contains(e.Location)) { selectedNode = node; selectedPort = null; propertyGrid.SelectedObject = selectedNode; draggingStartPoint = e.Location; return; } } } } private void canvasPanel_MouseMove(object sender, MouseEventArgs e) { if (selectedNode != null && e.Button == MouseButtons.Left) { // Bewegen Sie den ausgewählten Node während des Drag-and-Drop selectedNode.X += e.X - draggingStartPoint.X; selectedNode.Y += e.Y - draggingStartPoint.Y; draggingStartPoint = e.Location; canvasPanel.Invalidate(); } } private void canvasPanel_MouseUp(object sender, MouseEventArgs e) { if (selectedNode != null && e.Button == MouseButtons.Left) { // Wenn ein existierender Node verschoben wurde, aktualisieren Sie die Verbindungen UpdateConnectors(); } } #endregion private void ConnectPorts(Port startPort, Port endPort) { connectors.Add(new Connector { StartPort = startPort, EndPort = endPort }); UpdateConnectors(); canvasPanel.Invalidate(); } private void UpdateConnectors() { foreach (var node in nodes) { foreach (var outputPort in node.OutputPorts) { foreach (var inputPort in node.InputPorts) { if (outputPort.Connected && inputPort.Connected) { connectors.Add(new Connector { StartPort = outputPort, EndPort = inputPort }); } } } } foreach(Node n in nodes) { if(n is AddNode || n is SubNode || n is MulNode || n is DivNode) n.UpdateValue(); } canvasPanel.Invalidate(); } #region Nodes public abstract class Node { [Browsable(false)] public int X { get; set; } [Browsable(false)] public int Y { get; set; } [Browsable(true)] public virtual string Name { get; set; } [Browsable(true)] public virtual string Type { get; set; } [Browsable(true)] public virtual string Value { get; set; } = ""; [Browsable(false)] public abstract int Width { get; } [Browsable(false)] public abstract int Height { get; } [Browsable(false)] public Rectangle Bounds => new Rectangle(X, Y, Width, Height); [Browsable(false)] public List<InputPort> InputPorts { get; } = new List<InputPort>(); [Browsable(false)] public List<OutputPort> OutputPorts { get; } = new List<OutputPort>(); public abstract void Paint(object sender, PaintEventArgs e); public abstract void UpdateValue(); } public class VariableNode : Node { public override int Width => 100; public override int Height => 30; public override string Name { get; set; } = "Variable"; public override string Type { get; set; } = ""; public override string Value { get; set; } = ""; public VariableNode() { OutputPorts.Add(new OutputPort(this, "Output 1")); } public override void UpdateValue() { } public override void Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Black, Bounds); e.Graphics.DrawString(Name, DefaultFont, Brushes.Black, Bounds.Location); Rectangle newLocation = Bounds; newLocation.Y += 15; e.Graphics.DrawString(Type.ToString() + ": " + Value, DefaultFont, Brushes.Black, newLocation); // Draw Input Ports foreach (var inputPort in InputPorts) { e.Graphics.FillEllipse(Brushes.Blue, inputPort.Bounds); } // Draw Output Ports foreach (var outputPort in OutputPorts) { e.Graphics.FillEllipse(Brushes.Red, outputPort.Bounds); } } } public class AddNode : Node { public override int Width => 100; public override int Height => 30; public override string Name { get; set; } = "Addition"; public override string Type { get; set; } public override string Value { get; set; } public override void UpdateValue() { int i = 0; int counter = 0; foreach(Connector c in connectors) { // Nicht wenn es ein StartPort ist (Input) /* if(c.StartPort.OwnerNode == this) { if (!string.IsNullOrEmpty(c.EndPort.OwnerNode.Value)) if(counter == 0) i = int.Parse(c.EndPort.OwnerNode.Value); else i += int.Parse(c.EndPort.OwnerNode.Value); } */ if (c.EndPort.OwnerNode == this) { if(!string.IsNullOrEmpty(c.StartPort.OwnerNode.Value)) if(counter == 0) i = int.Parse(c.StartPort.OwnerNode.Value); else i += int.Parse(c.StartPort.OwnerNode.Value); } counter++; } Value = i.ToString(); } public AddNode() { InputPorts.Add(new InputPort(this, "Input 1")); OutputPorts.Add(new OutputPort(this, "Output 1")); } public override void Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Black, Bounds); e.Graphics.DrawString(Name, DefaultFont, Brushes.Black, Bounds.Location); Rectangle newLocation = Bounds; newLocation.Y += 15; e.Graphics.DrawString("Ergebnis: " + Value, DefaultFont, Brushes.Black, newLocation); // Draw Output Ports foreach (var inputPort in InputPorts) { e.Graphics.FillEllipse(Brushes.Red, inputPort.Bounds); } // Draw Output Ports foreach (var outputPort in OutputPorts) { e.Graphics.FillEllipse(Brushes.Red, outputPort.Bounds); } } } public class SubNode : Node { public override int Width => 100; public override int Height => 30; public override string Name { get; set; } = "Subtraction"; public override string Type { get; set; } public override string Value { get; set; } public override void UpdateValue() { int i = 0; int counter = 0; foreach (Connector c in connectors) { if (c.EndPort.OwnerNode == this) { if (!string.IsNullOrEmpty(c.StartPort.OwnerNode.Value)) if (counter == 0) i = int.Parse(c.StartPort.OwnerNode.Value); else i = i - int.Parse(c.StartPort.OwnerNode.Value); counter++; } } Value = i.ToString(); } public SubNode() { InputPorts.Add(new InputPort(this, "Input 1")); OutputPorts.Add(new OutputPort(this, "Output 1")); } public override void Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Black, Bounds); e.Graphics.DrawString(Name, DefaultFont, Brushes.Black, Bounds.Location); Rectangle newLocation = Bounds; newLocation.Y += 15; e.Graphics.DrawString("Ergebnis: " + Value, DefaultFont, Brushes.Black, newLocation); // Draw Output Ports foreach (var inputPort in InputPorts) { e.Graphics.FillEllipse(Brushes.Red, inputPort.Bounds); } // Draw Output Ports foreach (var outputPort in OutputPorts) { e.Graphics.FillEllipse(Brushes.Red, outputPort.Bounds); } } } public class MulNode : Node { public override int Width => 100; public override int Height => 30; public override string Name { get; set; } = "Multiplication"; public override string Type { get; set; } public override string Value { get; set; } public override void UpdateValue() { int i = 0; int counter = 0; foreach (Connector c in connectors) { if (c.EndPort.OwnerNode == this) { if (!string.IsNullOrEmpty(c.StartPort.OwnerNode.Value)) if (counter == 0) i = int.Parse(c.StartPort.OwnerNode.Value); else i *= int.Parse(c.StartPort.OwnerNode.Value); counter++; } } Value = i.ToString(); } public MulNode() { InputPorts.Add(new InputPort(this, "Input 1")); OutputPorts.Add(new OutputPort(this, "Output 1")); } public override void Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Black, Bounds); e.Graphics.DrawString(Name, DefaultFont, Brushes.Black, Bounds.Location); Rectangle newLocation = Bounds; newLocation.Y += 15; e.Graphics.DrawString("Ergebnis: " + Value, DefaultFont, Brushes.Black, newLocation); // Draw Output Ports foreach (var inputPort in InputPorts) { e.Graphics.FillEllipse(Brushes.Red, inputPort.Bounds); } // Draw Output Ports foreach (var outputPort in OutputPorts) { e.Graphics.FillEllipse(Brushes.Red, outputPort.Bounds); } } } public class DivNode : Node { public override int Width => 100; public override int Height => 30; public override string Name { get; set; } = "Division"; public override string Type { get; set; } public override string Value { get; set; } public override void UpdateValue() { int i = 0; int counter = 0; foreach (Connector c in connectors) { if (c.EndPort.OwnerNode == this) { if (!string.IsNullOrEmpty(c.StartPort.OwnerNode.Value)) if (counter == 0) i = int.Parse(c.StartPort.OwnerNode.Value); else i = i / int.Parse(c.StartPort.OwnerNode.Value); counter++; } } Value = i.ToString(); } public DivNode() { InputPorts.Add(new InputPort(this, "Input 1")); OutputPorts.Add(new OutputPort(this, "Output 1")); } public override void Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Black, Bounds); e.Graphics.DrawString(Name, DefaultFont, Brushes.Black, Bounds.Location); Rectangle newLocation = Bounds; newLocation.Y += 15; e.Graphics.DrawString("Ergebnis: " + Value, DefaultFont, Brushes.Black, newLocation); // Draw Output Ports foreach (var inputPort in InputPorts) { e.Graphics.FillEllipse(Brushes.Red, inputPort.Bounds); } // Draw Output Ports foreach (var outputPort in OutputPorts) { e.Graphics.FillEllipse(Brushes.Red, outputPort.Bounds); } } } #endregion #region Ports public abstract class Port { public Node OwnerNode { get; } public string Name { get; set; } public bool Connected { get; set; } protected Port(Node ownerNode, string name) { OwnerNode = ownerNode; Name = name; } public abstract Point Location { get; } public Rectangle Bounds => new Rectangle(Location, new Size(10, 10)); [Browsable(false)] public int portSpacing = 10; } public class InputPort : Port { public InputPort(Node ownerNode, string name) : base(ownerNode, name) { } public override Point Location => new Point( OwnerNode.X - 10, OwnerNode.Y + (OwnerNode.InputPorts.IndexOf(this) ) * portSpacing ); } public class OutputPort : Port { public OutputPort(Node ownerNode, string name) : base(ownerNode, name) { } public override Point Location => new Point( OwnerNode.X + OwnerNode.Width, OwnerNode.Y + (OwnerNode.OutputPorts.IndexOf(this) + 1) * portSpacing ); } #endregion public class Connector { [Browsable(false)] public Port StartPort { get; set; } [Browsable(false)] public Port EndPort { get; set; } [Browsable(true)] [Category("Connector")] public string Test { get { return StartPort.OwnerNode.Type + "::" + StartPort.OwnerNode.Value + " -> " + EndPort.OwnerNode.Type + "::" + EndPort.OwnerNode.Value; } } } #region Helper Functions private Rectangle GetConnectorBounds(Connector connector) { var startPoint = connector.StartPort.Location; var endPoint = connector.EndPort.Location; int x = Math.Min(startPoint.X, endPoint.X); int y = Math.Min(startPoint.Y, endPoint.Y); int width = Math.Abs(startPoint.X - endPoint.X); int height = Math.Abs(startPoint.Y - endPoint.Y); return new Rectangle(x, y, width, height); } private bool IsPointOnConnector(Point clickPoint, Connector connector) { var startPoint = connector.StartPort.Location; var endPoint = connector.EndPort.Location; // Überprüfen, ob der Klickpunkt in der Nähe der Linie liegt float distance = DistancePointToLine(clickPoint, startPoint, endPoint); return distance < 5; // Ändern Sie den Schwellenwert nach Bedarf } private float DistancePointToLine(Point point, Point lineStart, Point lineEnd) { float a = point.X - lineStart.X; float b = point.Y - lineStart.Y; float c = lineEnd.X - lineStart.X; float d = lineEnd.Y - lineStart.Y; float dot = a * c + b * d; float len_sq = c * c + d * d; float param = dot / len_sq; float xx, yy; if (param < 0) { xx = lineStart.X; yy = lineStart.Y; } else if (param > 1) { xx = lineEnd.X; yy = lineEnd.Y; } else { xx = lineStart.X + param * c; yy = lineStart.Y + param * d; } float dx = point.X - xx; float dy = point.Y - yy; return (float)Math.Sqrt(dx * dx + dy * dy); } #endregion } }