/// <summary> /// Creates a graph link between the two specified pins /// </summary> /// <typeparam name="T">The type of the link. Should be GraphLink or one of its subclass</typeparam> /// <param name="output">The output pin from where the link originates</param> /// <param name="input">The input pin, where the link points to</param> /// <returns></returns> public static T CreateLink <T>(Graph graph, GraphPin output, GraphPin input) where T : GraphLink { // Make sure the pin types are correct if (output.PinType != GraphPinType.Output || input.PinType != GraphPinType.Input) { throw new System.ApplicationException("Invalid pin types while creating a link"); } if (!GraphSchema.CanCreateLink(output, input)) { return(null); } // Make sure a link doesn't already exists foreach (T link in graph.Links) { if (link.Input == input && link.Output == output) { return(link); } } { Undo.RecordObject(graph, "Create Link"); T link = CreateLink <T>(graph); link.Input = input; link.Output = output; Undo.RegisterCreatedObjectUndo(link, "Create Link"); return(link); } }
public void Destroy() { UnityEngine.Object.DestroyImmediate(mousePin); UnityEngine.Object.DestroyImmediate(link); mousePin = null; link = null; }
/// <summary> /// Shows the context menu in the theme graph editor /// </summary> /// <param name="graph">The graph shown in the graph editor</param> /// <param name="sourcePin">The source pin, if the user dragged a link out of a pin. null otherwise</param> /// <param name="mouseWorld">The position of the mouse. The context menu would be shown from here</param> public void Show(Graph graph, GraphPin sourcePin, Vector2 mouseWorld) { showItemMeshNode = false; showItemMarkerNode = false; showItemMarkerEmitterNode = false; this.sourcePin = sourcePin; this.mouseWorldPosition = mouseWorld; if (sourcePin.Node is MarkerNode) { showItemMeshNode = true; } else if (sourcePin.Node is VisualNode) { if (sourcePin.PinType == GraphPinType.Input) { // We can only create marker nodes from here showItemMarkerNode = true; } else { // We can only create marker emitter nodes from here showItemMarkerEmitterNode = true; } } else if (sourcePin.Node is MarkerEmitterNode) { // we can only create mesh nodes from the input pin of this node showItemMeshNode = true; } ShowMenu(graph); }
public void Draw(GraphRendererContext rendererContext, GraphCamera camera) { if (!active) { return; } var mouseWorld = camera.ScreenToWorld(mouseScreenPosition); mousePin.Position = mouseWorld; GraphLinkRenderer.DrawGraphLink(rendererContext, link, camera); // Check the pin that comes under the mouse pin var targetPin = graphEditor.GetPinUnderPosition(mouseWorld); if (targetPin != null) { var sourcePin = attachedPin; var pins = new GraphPin[] { sourcePin, targetPin }; Array.Sort(pins, new GraphPinHierarchyComparer()); string errorMessage; if (!GraphSchema.CanCreateLink(pins[0], pins[1], out errorMessage)) { GraphTooltip.message = errorMessage; } } }
void CreateLinkBetweenPins(GraphPin outputPin, GraphPin inputPin) { if (outputPin.PinType != GraphPinType.Output && inputPin.PinType != GraphPinType.Input) { Debug.LogError("Pin type mismatch"); return; } // Make sure they are not from the same node if (outputPin.Node == inputPin.Node) { Debug.LogError("Linking pins from the same node"); return; } // Create a link var link = GraphOperations.CreateLink <GraphLink>(graph, outputPin, inputPin); if (link != null) { DungeonEditorHelper.AddToAsset(graph, link); graph.NotifyStateChanged(); } else { Debug.Log("GraphSchema: Link not allowed"); } }
// Breaks all the links attached to the pin private static void BreakLinks(GraphPin pin) { GraphLink[] links = pin.GetConntectedLinks(); foreach (var link in links) { DestroyLink(link); } }
// Called when the mouse is released after dragging a link out of an existing pin void HandleMouseDraggedLinkReleased(Vector2 mousePositionScreen) { var mouseWorld = camera.ScreenToWorld(mousePositionScreen); var sourcePin = cursorDragLink.AttachedPin; // Check if the mouse was released over a pin GraphPin targetPin = null; GraphNode[] sortedNodes = graph.Nodes.ToArray(); System.Array.Sort(sortedNodes, new NodeReversedZIndexComparer()); foreach (var node in sortedNodes) { if (node.Bounds.Contains(mouseWorld)) { // Check if we are above a pin in this node var pins = new List <GraphPin>(); pins.AddRange(node.InputPins); pins.AddRange(node.OutputPins); foreach (var pin in pins) { if (pin.ContainsPoint(mouseWorld)) { targetPin = pin; break; } } break; } } if (targetPin != null) { if (sourcePin.PinType != targetPin.PinType) { GraphPin source, target; if (sourcePin.PinType == GraphPinType.Output) { source = sourcePin; target = targetPin; } else { source = targetPin; target = sourcePin; } if (source.Node != target.Node) { CreateLinkBetweenPins(source, target); } } } else { // We stopped drag on an empty space. Show a context menu to allow user to create nodes from this position contextMenu.Show(graph, sourcePin, mouseWorld); } }
/// <summary> /// Show the context menu /// </summary> /// <param name="graph">The owning graph</param> public void Show(Graph graph) { showItemMeshNode = true; showItemMarkerNode = true; showItemMarkerEmitterNode = true; sourcePin = null; mouseWorldPosition = Vector2.zero; ShowMenu(graph); }
public void Activate(GraphPin fromPin) { active = true; attachedPin = fromPin; mousePin.PinType = (attachedPin.PinType == GraphPinType.Input) ? GraphPinType.Output : GraphPinType.Input; mousePin.Tangent = -attachedPin.Tangent; mousePin.TangentStrength = attachedPin.TangentStrength; AttachPinToLink(mousePin); AttachPinToLink(attachedPin); }
void AttachPinToLink(GraphPin pin) { if (pin.PinType == GraphPinType.Input) { link.Input = pin; } else { link.Output = pin; } }
/// <summary> /// Destroys all links connected to this pin /// </summary> private static void DestroyPinLinks(GraphPin pin) { var pinLinks = pin.GetConntectedLinks(); foreach (var link in pinLinks) { GraphOperations.DestroyLink(link); } pin.NotifyPinLinksDestroyed(); }
/// <summary> /// Handles the mouse input and returns true if handled /// </summary> public static bool HandlePinInput(GraphPin pin, Event e, GraphEditor graphEditor) { var camera = graphEditor.Camera; var mousePosition = e.mousePosition; var mousePositionWorld = camera.ScreenToWorld(mousePosition); int buttonIdDrag = 0; int buttonIdDestroyLinks = 1; if (pin.ContainsPoint(mousePositionWorld)) { if (e.type == EventType.MouseDown && e.button == buttonIdDrag) { pin.ClickState = GraphPinMouseState.Clicked; return(true); } if (e.button == buttonIdDestroyLinks) { if (e.type == EventType.MouseDown) { pin.RequestLinkDeletionInitiated = true; } else if (e.type == EventType.MouseDrag) { pin.RequestLinkDeletionInitiated = false; } else if (e.type == EventType.MouseUp) { if (pin.RequestLinkDeletionInitiated) { DestroyPinLinks(pin); if (pin.Node != null && pin.Node.Graph != null) { graphEditor.HandleGraphStateChanged(); } } } return(true); } if (pin.ClickState != GraphPinMouseState.Clicked) { pin.ClickState = GraphPinMouseState.Hover; } } else { pin.ClickState = GraphPinMouseState.None; } return(false); }
public CursorDragLink(GraphEditor graphEditor) { this.graphEditor = graphEditor; mousePin = ScriptableObject.CreateInstance <GraphPin>(); mousePin.PinType = GraphPinType.Input; mousePin.name = "Cursor_DragPin"; link = ScriptableObject.CreateInstance <GraphLink>(); link.name = "Cursor_DragLink"; mousePin.hideFlags = HideFlags.HideAndDontSave; link.hideFlags = HideFlags.HideAndDontSave; }
static Color GetPinColor(GraphPin pin) { Color color; if (pin.ClickState == GraphPinMouseState.Clicked) { color = GraphEditorConstants.PIN_COLOR_CLICK; } else if (pin.ClickState == GraphPinMouseState.Hover) { color = GraphEditorConstants.PIN_COLOR_HOVER; } else { color = GraphEditorConstants.PIN_COLOR; } return(color); }
public static void Draw(GraphRendererContext rendererContext, GraphPin pin, GraphCamera camera) { var pinBounds = new Rect(pin.GetBounds()); var positionWorld = pin.Node.Position + pinBounds.position; var positionScreen = camera.WorldToScreen(positionWorld); pinBounds.position = positionScreen; pinBounds.size /= camera.ZoomLevel; var originalColor = GUI.backgroundColor; GUI.backgroundColor = GetPinColor(pin); GUI.Box(pinBounds, ""); GUI.backgroundColor = originalColor; // Draw the pin texture var pinTexture = rendererContext.Resources.GetResource <Texture2D>(DungeonEditorResources.TEXTURE_PIN_GLOW); if (pinTexture != null) { GUI.DrawTexture(pinBounds, pinTexture); } }
protected bool BuildChoices(GraphPin inputPin, List <DialogueFragment> fragments) { DialoguePin pin = inputPin as DialoguePin; if (pin == null) { return(false); } BaseDialogueObject obj = pin.Node as BaseDialogueObject; if (obj == null) { return(false); } if (pin.Type == GraphPin.PinType.Output && obj is Dialogue) { return(true); // connection to a dialogue output is reached so it's the end of the dialogue } bool processObject = true; if (pin.Script != null) { dynamic result = pin.Script.Run(this); if (pin.Type == GraphPin.PinType.Input) { if (!(result is Boolean)) { GameDebugger.Log(LogLevel.Warning, "One of input pins script on dialogue object '0x{0:X16}' exits with a non boolean result ({1})", obj.Id, result.GetType().Name); return(true); // end the dialogue due to error } if (!result) // input pin is a condition. if it returns false, then object is not processed { processObject = false; } } } if (processObject && !(obj is Dialogue) && pin.Type == GraphPin.PinType.Input) { if (BuildChoices(obj, fragments)) { return(true); } } foreach (GraphConnection conn in pin.Connections) { if (conn.Target == pin) { continue; // ignore incoming connections } if (BuildChoices(conn.Target, fragments)) // recursion through connections { return(true); } } return(false); }
void OnMenuItemClicked(GraphMenuAction action, GraphContextMenuEvent e) { var mouseScreen = lastMousePosition; GraphNode node = null; if (action == GraphMenuAction.AddGameObjectNode) { node = CreateNode <GameObjectNode>(mouseScreen); SelectNode(node); } else if (action == GraphMenuAction.AddSpriteNode) { node = CreateNode <SpriteNode>(mouseScreen); SelectNode(node); } else if (action == GraphMenuAction.AddMarkerNode) { node = CreateNode <MarkerNode>(mouseScreen); SelectNode(node); } else if (action == GraphMenuAction.AddMarkerEmitterNode) { if (e.userdata != null) { var markerName = e.userdata as String; node = CreateMarkerEmitterNode(mouseScreen, markerName); if (node != null) { SelectNode(node); } } } if (node != null) { // Check if the menu was created by dragging out a link if (e.sourcePin != null) { GraphPin targetPin = e.sourcePin.PinType == GraphPinType.Input ? node.OutputPins[0] : node.InputPins[0]; // Align the target pin with the mouse position where the link was dragged and released node.Position = e.mouseWorldPosition - targetPin.Position; GraphPin inputPin, outputPin; if (e.sourcePin.PinType == GraphPinType.Input) { inputPin = e.sourcePin; outputPin = targetPin; } else { inputPin = targetPin; outputPin = e.sourcePin; } CreateLinkBetweenPins(outputPin, inputPin); } } }
void HandleDragPin(GraphPin pin) { cursorDragLink.Activate(pin); }
void HandleDrag(Event e) { int dragButton = 0; if (draggingNodes) { if (e.type == EventType.MouseUp && e.button == dragButton) { draggingNodes = false; } else if (e.type == EventType.MouseDrag && e.button == dragButton) { // Drag all the selected nodes foreach (var node in graph.Nodes) { if (node.Selected) { Undo.RecordObject(node, "Move Node"); node.DragNode(e.delta); } } } } else { // Check if we have started to drag if (e.type == EventType.MouseDown && e.button == dragButton) { // Find the node that was clicked below the mouse var mousePosition = e.mousePosition; var mousePositionWorld = camera.ScreenToWorld(mousePosition); // sort the nodes front to back GraphNode[] sortedNodes = graph.Nodes.ToArray(); System.Array.Sort(sortedNodes, new NodeReversedZIndexComparer()); GraphNode mouseOverNode = null; foreach (var node in sortedNodes) { var mouseOver = node.Bounds.Contains(mousePositionWorld); if (mouseOver) { mouseOverNode = node; break; } } if (mouseOverNode != null && mouseOverNode.Selected) { // Make sure we are not over a pin var pins = new List <GraphPin>(); pins.AddRange(mouseOverNode.InputPins); pins.AddRange(mouseOverNode.OutputPins); bool isOverPin = false; GraphPin overlappingPin = null; foreach (var pin in pins) { if (pin.ContainsPoint(mousePositionWorld)) { isOverPin = true; overlappingPin = pin; break; } } if (!isOverPin) { draggingNodes = true; } else { HandleDragPin(overlappingPin); } } } } }
public override void Show(GraphEditor graphEditor, GraphPin sourcePin, Vector2 mouseWorld) { }
/// <summary> /// Shows the context menu in the theme graph editor /// </summary> /// <param name="graph">The graph shown in the graph editor</param> /// <param name="sourcePin">The source pin, if the user dragged a link out of a pin. null otherwise</param> /// <param name="mouseWorld">The position of the mouse. The context menu would be shown from here</param> public abstract void Show(GraphEditor graphEditor, GraphPin sourcePin, Vector2 mouseWorld);