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
}
}