private void DeleteButton_Click(object sender, RoutedEventArgs e) { GraphEditorViewModel graph = (GraphEditorViewModel)VisualEditor.DataContext; graph.VisualNodes.Clear(); graph.Connections.Clear(); }
private void VisualNode_MouseDown(object sender, MouseButtonEventArgs e) { UserControl controlSender = (UserControl)sender; VisualGraphComponentViewModel node = (VisualGraphComponentViewModel)controlSender.DataContext; GraphEditorViewModel graphViewModel = (GraphEditorViewModel)DataContext; node.ZIndex = graphViewModel.FindMaxZIndex() + 10; }
private void Editor_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // If we are creating a connection... if (IsCreatingConnection) { ConnectionBuilderViewModel connectionBuilder = (ConnectionBuilderViewModel)NewConnectionLine.DataContext; NodePinViewModel connectionRootPin = (NodePinViewModel)connectionBuilder.OutputPin.DataContext; // Check if we are clicking from an input pin // If we are, try to automatically place a constant node connecting to the input pin if (connectionRootPin.IsOutputPin == false && connectionRootPin.IsExecutionPin == false) { GraphEditorViewModel viewModel = (GraphEditorViewModel)this.DataContext; VisualConstantNodeViewModel autoConstantNode = new VisualConstantNodeViewModel(connectionRootPin.DataType) { X = viewModel.MousePoint.X, Y = viewModel.MousePoint.Y }; viewModel.VisualNodes.Add(autoConstantNode); // Generates the view for the NodePin in the constant node before we add it Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null); viewModel.Connections.Add(new ConnectionViewModel(autoConstantNode.OutputPin.Pin, connectionRootPin.Pin)); } IsCreatingConnection = false; return; } // If we aren't creating a connection just deselect any nodes foreach (VisualGraphComponentViewModel node in ((GraphEditorViewModel)DataContext).VisualNodes) { node.IsSelected = false; } }
public static NodeGraphManager BuildGraph(GraphEditorViewModel graph) { List <VisualNodeViewModel> visualExecutionNodes = new List <VisualNodeViewModel>(); foreach (var graphComponent in graph.VisualNodes) { VisualNodeViewModel visualNode = graphComponent as VisualNodeViewModel; if (visualNode != null && visualNode.ExecutionInputs.Count > 0) { visualExecutionNodes.Add(visualNode); } } // Begin to build our graph NodeGraphManager graphManager = new NodeGraphManager(); Dictionary <VisualNodeViewModel, GraphNode> functionNodes = new Dictionary <VisualNodeViewModel, GraphNode>(); List <VisualConstantNodeViewModel> constantNodes = new List <VisualConstantNodeViewModel>(); foreach (dynamic visualNode in graph.VisualNodes) { if (visualNode is VisualNodeViewModel) { functionNodes.Add(visualNode, new GraphNode(visualNode.NodeType, graphManager)); } else if (visualNode is VisualConstantNodeViewModel) { constantNodes.Add(visualNode as VisualConstantNodeViewModel); } } // Wire up constant nodes foreach (var constantNode in constantNodes) { List <ConnectionViewModel> connections = GetPinConnections(constantNode.OutputPin, graph); // Lookup each input pin that the constant node is connecting to and add it in our graph manager foreach (var connection in connections) { foreach (var functionNode in functionNodes) { if (functionNode.Key.Inputs.Contains(connection.InputPin)) { // Get pin index int pindex = ((NodePinViewModel)connection.InputPin).Index; IDataTypeContainer valueToSet; // Get value to set if (constantNode.OutputPin.DataType == typeof(DataTypes.Numeric)) { valueToSet = new DataTypes.Numeric(Double.Parse(constantNode.Value)); } else if (constantNode.OutputPin.DataType == typeof(DataTypes.Boolean)) { valueToSet = new DataTypes.Boolean(Boolean.Parse(constantNode.Value)); } else if (constantNode.OutputPin.DataType == typeof(DataTypes.String)) { valueToSet = new DataTypes.String(constantNode.Value); } else { throw new Exception("Data type could not be determined."); } OutputPin pinConnection = new OutputPin( ((NodePinViewModel)connection.InputPin).DataType, null) { OutputValue = valueToSet, OutputRealised = true }; graphManager.AddConnection(pinConnection, functionNode.Value.NodeInputs[pindex]); } } } } // Wire up functional nodes foreach (var functionNode in functionNodes) { int outputPindex = 0; // Check each output pin on the node foreach (var output in functionNode.Key.Outputs) { List <ConnectionViewModel> connections = GetPinConnections(output, graph); foreach (var connection in connections) { // Wire up non-execution pins foreach (var targetFunctionNode in functionNodes) { if (targetFunctionNode.Key.Inputs.Contains(connection.InputPin)) { int pindex = ((NodePinViewModel)connection.InputPin).Index; graphManager.AddConnection( functionNodes[functionNode.Key].NodeOutputs[outputPindex], targetFunctionNode.Value.NodeInputs[pindex]); } } } } // Wire up execution pins foreach (var executionOutput in functionNode.Key.ExecutionOutputs) { List <ConnectionViewModel> connections = GetPinConnections(executionOutput, graph); if (connections.Count == 0) { graphManager.AddNode(functionNode.Value); } foreach (var connection in connections) { foreach (var targetFunctionNode in functionNodes) { if (targetFunctionNode.Key.ExecutionInputs.Contains(connection.InputPin)) { int pindex = ((NodePinViewModel)connection.OutputPin).Index; graphManager.AddConnection(functionNode.Value, pindex, targetFunctionNode.Value); } } } } } graphManager.RealiseNodeOutputs(); return(graphManager); }
public static List <ConnectionViewModel> GetPinConnections(NodePinViewModel pin, GraphEditorViewModel graph) { List <ConnectionViewModel> pinConnections = new List <ConnectionViewModel>(); foreach (var connection in graph.Connections) { NodePinViewModel inputPin = connection.InputPin; NodePinViewModel outputPin = connection.OutputPin; if (pin == inputPin || pin == outputPin) { pinConnections.Add(connection); } } return(pinConnections); }
public async static Task <NodeGraphManager> BuildGraphAsync(GraphEditorViewModel graph) { return(await Task.Run(() => BuildGraph(graph))); }
private void NodePin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { DependencyObject parentObject = VisualTreeHelper.GetParent(this); // Find the visual editor while (!(parentObject is VisualEditor)) { parentObject = VisualTreeHelper.GetParent(parentObject); if (parentObject == null) { return; } } VisualEditor visualEditor = parentObject as VisualEditor; // Determine how to handle the click if (visualEditor.IsCreatingConnection) { // If we are creating a new connection then we have to validate and add a new one GraphEditorViewModel graph = ((GraphEditorViewModel)visualEditor.DataContext); ConnectionBuilderViewModel connectionBuilder = ((ConnectionBuilderViewModel)visualEditor.NewConnectionLine.DataContext); NodePinViewModel rootPin = (NodePinViewModel)connectionBuilder.OutputPin.DataContext; NodePinViewModel targetPin = (NodePinViewModel)this.DataContext; // Validate the output and input pins // Reverse them if needed // TODO: More extensive validation. ie. Check for output -> output or input -> input connections. // Ensure datatypes are the same between pins if (rootPin.DataType != targetPin.DataType) { // If the data types do not match try and add in an auto-conversion foreach (var rule in graph.ConversionRules) { if (rule.Item1 == rootPin.DataType && rule.Item2 == targetPin.DataType) { // Conversion rule found! // Add the conversion node at the midpoint between pins Point rootPoint = rootPin.Pin.Centre; Point targetPoint = targetPin.Pin.Centre; Point midPoint = new Point( ((rootPoint.X + targetPoint.X) / 2), (rootPoint.Y + targetPoint.Y) / 2); VisualNodeViewModel conversionNode = new VisualNodeViewModel(rule.Item3) { X = midPoint.X, Y = midPoint.Y }; graph.VisualNodes.Add(conversionNode); // Generate the conversion node's view so we can access its pins Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null); // Add the new connections, but ensure it is an OutputPin -> InputPin connection // Otherwise, we need to correct for that here if (((NodePinViewModel)connectionBuilder.OutputPin.DataContext).IsOutputPin == false) { // Connections need flipping graph.Connections.Add(new ConnectionViewModel(targetPin.Pin, conversionNode.Inputs[0].Pin)); graph.Connections.Add(new ConnectionViewModel(conversionNode.Outputs[0].Pin, rootPin.Pin)); } else { // Connection is correct graph.Connections.Add(new ConnectionViewModel(rootPin.Pin, conversionNode.Inputs[0].Pin)); graph.Connections.Add(new ConnectionViewModel(conversionNode.Outputs[0].Pin, targetPin.Pin)); } } } } // If datatypes are the same, we can just create a connection between the pins // Make sure the connection is added in an OutputPin -> InputPin order else { if (((NodePinViewModel)connectionBuilder.OutputPin.DataContext).IsOutputPin == false) { graph.Connections.Add(new ConnectionViewModel(this, connectionBuilder.OutputPin)); } else { graph.Connections.Add(new ConnectionViewModel(connectionBuilder.OutputPin, this)); } } visualEditor.IsCreatingConnection = false; } else { // We need to initialise the 'create a connection' mode visualEditor.IsCreatingConnection = true; // And set the root pin ConnectionBuilderViewModel newConnection = ((ConnectionBuilderViewModel)visualEditor.NewConnectionLine.DataContext); newConnection.OutputPin = this; } }