private void OnGUI() { if (!editor) { editor = this; } SelectDB(); skin = Resources.Load <GUISkin>("Node Editor Skin"); GUI.skin = skin; float eWidth = editor.position.width; float eHeight = editor.position.height; if (!db) { EditorGUILayout.HelpBox("Select an object with a QD_NodeDB script.", MessageType.Info); } else { Event e = Event.current; mouse = e.mousePosition; int nodeCount = db.Nodes.Count; // Mouse click events, taken from https://forum.unity.com/threads/simple-node-editor.189230/ if (e.type == EventType.MouseDown && e.button == 1 && !connectingNodes) { bool clicked = false; int selectedIndex = -1; bool knobClicked = false; int knobSelectedIndex = -1; for (int i = 0; i < nodeCount; ++i) { QD_Node node = db.Nodes[i]; if (node.Window.Contains(mouse + scroll)) { selectedIndex = i; clicked = true; break; } else { int inputCount = node.Inputs.Count; for (int j = 0; j < inputCount; ++j) { if (node.InputKnob(j).Contains(mouse + scroll)) { selectedIndex = i; clicked = true; knobSelectedIndex = j; knobClicked = true; knobType = QD_KnobType.Input; selectedKnob = j; break; } } if (knobClicked) { break; } int outputCount = node.Outputs.Count; for (int j = 0; j < outputCount; ++j) { if (node.OutputKnob(j).Contains(mouse + scroll)) { selectedIndex = i; clicked = true; knobSelectedIndex = j; knobClicked = true; knobType = QD_KnobType.Output; selectedKnob = j; break; } } if (knobClicked) { break; } } } if (!clicked) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Add Conversation"), false, ContextCallback, "Add Conversation"); menu.AddItem(new GUIContent("Add Speaker"), false, ContextCallback, "Add Speaker"); menu.AddItem(new GUIContent("Add Message"), false, ContextCallback, "Add Message"); menu.AddItem(new GUIContent("Add Choice"), false, ContextCallback, "Add Choice"); menu.ShowAsContext(); e.Use(); } else { GenericMenu menu = new GenericMenu(); if (!knobClicked) { menu.AddItem(new GUIContent("Detach All Connected Nodes"), false, ContextCallback, "Detach All Connected Nodes"); menu.AddItem(new GUIContent("Delete Node"), false, ContextCallback, "Delete Node"); } else { menu.AddItem(new GUIContent("Attach to Node"), false, ContextCallback, "Attach to Node"); menu.AddItem(new GUIContent("Detach Connected Nodes"), false, ContextCallback, "Detach Connected Nodes"); } menu.ShowAsContext(); e.Use(); selectedNode = db.Nodes[selectedIndex]; } } else if (e.type == EventType.MouseDown && e.button == 0 && connectingNodes) { bool clicked = false; int selectedIndex = -1; bool knobClicked = false; int knobSelectedIndex = -1; QD_KnobType clickedKnobType = QD_KnobType.Input; for (int i = 0; i < nodeCount; ++i) { QD_Node node = db.Nodes[i]; int inputCount = node.Inputs.Count; for (int j = 0; j < inputCount; ++j) { if (node.InputKnob(j).Contains(mouse + scroll)) { selectedIndex = i; clicked = true; knobSelectedIndex = j; knobClicked = true; clickedKnobType = QD_KnobType.Input; break; } } if (knobClicked) { break; } int outputCount = node.Outputs.Count; for (int j = 0; j < outputCount; ++j) { if (node.OutputKnob(j).Contains(mouse + scroll)) { selectedIndex = i; clicked = true; knobSelectedIndex = j; knobClicked = true; clickedKnobType = QD_KnobType.Output; break; } } if (knobClicked) { break; } } if (clicked) { EditorUtility.SetDirty(db); if (knobType == QD_KnobType.Input && clickedKnobType == QD_KnobType.Output) { QD_Node outputNode = db.Nodes[selectedIndex]; QD_Knob input = selectedNode.Inputs[selectedKnob]; QD_Knob output = outputNode.Outputs[knobSelectedIndex]; if (selectedNode.ID != outputNode.ID && (!output.Connections.ContainsKey(selectedNode.ID) || !output.Connections.Get(selectedNode.ID).Contains(selectedKnob)) && (!input.Connections.ContainsKey(outputNode.ID) || !input.Connections.Get(outputNode.ID).Contains(knobSelectedIndex)) && (output.AllowMultipleConnections || output.Connections.Count == 0) && (input.AllowMultipleConnections || input.Connections.Count == 0) && selectedNode.CanConnect(knobType, selectedKnob, outputNode.Type, QD_KnobType.Output, knobSelectedIndex) ) { selectedNode.ConnectNode(outputNode.ID, knobSelectedIndex, selectedKnob, QD_KnobType.Input); outputNode.ConnectNode(selectedNode.ID, selectedKnob, knobSelectedIndex, QD_KnobType.Output); } } else if (knobType == QD_KnobType.Output && clickedKnobType == QD_KnobType.Input) { QD_Node inputNode = db.Nodes[selectedIndex]; QD_Knob input = inputNode.Inputs[knobSelectedIndex]; QD_Knob output = selectedNode.Outputs[selectedKnob]; if (selectedNode.ID != inputNode.ID && (!output.Connections.ContainsKey(inputNode.ID) || !output.Connections.Get(inputNode.ID).Contains(knobSelectedIndex)) && (!input.Connections.ContainsKey(selectedNode.ID) || !input.Connections.Get(selectedNode.ID).Contains(selectedKnob)) && (output.AllowMultipleConnections || output.Connections.Count == 0) && (input.AllowMultipleConnections || input.Connections.Count == 0) && selectedNode.CanConnect(knobType, selectedKnob, inputNode.Type, QD_KnobType.Input, knobSelectedIndex) ) { selectedNode.ConnectNode(inputNode.ID, knobSelectedIndex, selectedKnob, QD_KnobType.Output); inputNode.ConnectNode(selectedNode.ID, selectedKnob, knobSelectedIndex, QD_KnobType.Input); } } } connectingNodes = false; selectedNode = null; knobClicked = false; selectedKnob = -1; e.Use(); } if (connectingNodes && selectedNode != null) { Rect mouseRect = new Rect(e.mousePosition.x, e.mousePosition.y, 10, 10); Rect knobRect = knobType == QD_KnobType.Input ? selectedNode.InputKnob(selectedKnob) : selectedNode.OutputKnob(selectedKnob); knobRect.position += new Vector2(knobRect.width / 2, knobRect.height / 2) - scroll; DrawNodeCurve(knobType == QD_KnobType.Output ? knobRect : mouseRect, knobType == QD_KnobType.Output ? mouseRect : knobRect, false); Repaint(); } GUILayout.BeginArea(new Rect(-scroll, new Vector2(5000, 5000))); for (int i = 0; i < nodeCount; ++i) { QD_Node node = db.Nodes[i]; int outputCount = node.Outputs.Count; for (int j = 0; j < outputCount; ++j) { QD_Knob output = node.Outputs[j]; if (output.Connections.Count > 0) { foreach (KeyValuePair <int, List <int> > connection in output.Connections.dictionary) { int connectionCount = connection.Value.Count; for (int k = 0; k < connectionCount; ++k) { DrawNodeCurve(node.OutputKnob(j), db.GetNode(connection.Key).InputKnob(connection.Value[k]), true); } } } } } BeginWindows(); for (int i = 0; i < nodeCount; ++i) { QD_Node node = db.Nodes[i]; if (node.Type == QD_NodeType.Speaker) { QD_SpeakerNode realNode = db.GetSpeakerNode(node.ID); node.Window = GUI.Window(node.ID, node.Window, realNode.DrawWindow, realNode.WindowTitle); } else if (node.Type == QD_NodeType.Message) { QD_MessageNode realNode = db.GetMessageNode(node.ID); node.Window = GUI.Window(node.ID, node.Window, realNode.DrawWindow, realNode.WindowTitle); } else if (node.Type == QD_NodeType.Conversation) { QD_ConversationNode realNode = db.GetConversationNode(node.ID); node.Window = GUI.Window(node.ID, node.Window, realNode.DrawWindow, realNode.WindowTitle); } else if (node.Type == QD_NodeType.Choice) { QD_ChoiceNode realNode = db.GetChoiceNode(node.ID); node.Window = GUI.Window(node.ID, node.Window, realNode.DrawWindow, realNode.WindowTitle); } node.DrawKnobs(); } EndWindows(); GUILayout.EndArea(); scroll = new Vector2( GUI.HorizontalScrollbar(new Rect(0, eHeight - 15, eWidth - 15, eHeight - 5), scroll.x, eHeight, 0, 5000), GUI.VerticalScrollbar(new Rect(eWidth - 15, 0, eWidth - 5, eHeight - 15), scroll.y, eHeight, 0, 5000) ); } }
/// <summary> /// Creates a new node of the given type at the given position. /// </summary> /// <param name="type"></param> /// <param name="position"></param> public void CreateNode(QD_NodeType type, Vector2 position) { int id = NextID++; var node = new QD_Node(id, type, position.x, position.y); if (type == QD_NodeType.Speaker) { var speakerNode = new QD_SpeakerNode(id, type, position.x, position.y); node.Window.width = speakerNode.Window.width; node.Window.height = speakerNode.Window.height; node.Inputs = speakerNode.CloneKnobs(QD_KnobType.Input); node.Outputs = speakerNode.CloneKnobs(QD_KnobType.Output); node.AllowedInputs = speakerNode.AllowedInputs; node.AllowedOutputs = speakerNode.AllowedOutputs; var speakerData = new QD_Speaker(id); DataDB.Speakers.Add(speakerData); speakerNode.Data = speakerData; SpeakerNodes.Add(speakerNode); } else if (type == QD_NodeType.Message) { var messageNode = new QD_MessageNode(id, type, position.x, position.y); node.Window.width = messageNode.Window.width; node.Window.height = messageNode.Window.height; node.Inputs = messageNode.CloneKnobs(QD_KnobType.Input); node.Outputs = messageNode.CloneKnobs(QD_KnobType.Output); node.AllowedInputs = messageNode.AllowedInputs; node.AllowedOutputs = messageNode.AllowedOutputs; var messageData = new QD_Message(id); DataDB.Messages.Add(messageData); messageNode.Data = messageData; MessageNodes.Add(messageNode); } else if (type == QD_NodeType.Conversation) { var conversationNode = new QD_ConversationNode(id, type, position.x, position.y); node.Window.width = conversationNode.Window.width; node.Window.height = conversationNode.Window.height; node.Inputs = conversationNode.CloneKnobs(QD_KnobType.Input); node.Outputs = conversationNode.CloneKnobs(QD_KnobType.Output); node.AllowedInputs = conversationNode.AllowedInputs; node.AllowedOutputs = conversationNode.AllowedOutputs; var conversationData = new QD_Conversation(id); DataDB.Conversations.Add(conversationData); conversationNode.Data = conversationData; ConversationNodes.Add(conversationNode); } else if (type == QD_NodeType.Choice) { var choiceNode = new QD_ChoiceNode(id, type, position.x, position.y); node.Window.width = choiceNode.Window.width; node.Window.height = choiceNode.Window.height; node.Inputs = choiceNode.CloneKnobs(QD_KnobType.Input); node.Outputs = choiceNode.CloneKnobs(QD_KnobType.Output); node.AllowedInputs = choiceNode.AllowedInputs; node.AllowedOutputs = choiceNode.AllowedOutputs; var choiceData = new QD_Choice(id); DataDB.Choices.Add(choiceData); choiceNode.Data = choiceData; ChoiceNodes.Add(choiceNode); } Nodes.Add(node); }