void OnGUI() { if (Tree == null) { Viewer.DrawStaticGrid(position.size); Viewer.DrawMode(); Editor.EditorMode = BonsaiEditor.Mode.Edit; } else { // Make sure to build a canvas for an active tree. if (Editor.Canvas == null) { BuildCanvas(); } CanvasTransform t = Transform; Editor.PollInput(Event.current, t, CanvasInputRect); Viewer.Draw(t); } DrawToolbar(); UpdateWindowTitle(); }
public void PollInput(Event e, CanvasTransform t, Rect inputRect) { if (lastCreatedNodeToPosition != null) { lastCreatedNodeToPosition.Center = BonsaiInput.MousePosition(t); lastCreatedNodeToPosition = null; } if (e.type == EventType.MouseDrag) { if (MotionAction != null) { MotionAction(t); OnCanvasChanged(); } } if (BonsaiInput.IsPanAction(e)) { Pan(e.delta); OnCanvasChanged(); } if (BonsaiInput.IsZoomAction(e)) { Zoom(e.delta.y); OnCanvasChanged(); } Input.HandleMouseEvents(e, t, Canvas.Nodes, inputRect); }
public void HandleMouseEvents( Event e, CanvasTransform transform, IReadOnlyList <BonsaiNode> nodes, Rect inputRect) { // Mouse must be inside the editor canvas. if (!inputRect.Contains(e.mousePosition)) { CanvasLostFocus(this, EventArgs.Empty); return; } HandleClickActions(transform, nodes, e); if (EditInputEnabled) { HandleEditorShortcuts(e); if (e.type == EventType.ContextClick) { HandleContextInput(transform, nodes); e.Use(); } } }
public static void DrawLineCanvasSpace(CanvasTransform t, Vector2 start, Vector2 end, Color color, float width) { start = t.CanvasToScreenSpace(start); end = t.CanvasToScreenSpace(end); if (t.IsScreenAxisLineInView(start, end)) { DrawLineScreenSpace(start, end, color, width); } }
public void Draw(CanvasTransform t) { if (Event.current.type == EventType.Repaint) { DrawGrid(t); DrawMode(); } DrawCanvasContents(t); }
public static void DrawPorts(CanvasTransform t, BonsaiNode node) { // There is always an input port. DrawPort(t, node.InputRect); if (node.HasOutput) { DrawPort(t, node.OutputRect); } }
private void DrawNodes(CanvasTransform t) { if (editorMode == BonsaiEditor.Mode.Edit) { DrawNodesInEditMode(t); } else { DrawNodesInViewMode(t); } }
private void HandleContextInput(CanvasTransform t, IReadOnlyList <BonsaiNode> nodes) { if (selection.IsMultiSelection) { HandleMultiContext(); } else { HandleSingleContext(t, nodes); } }
private void DrawNodesInEditMode(CanvasTransform t) { var nodes = Canvas.Nodes; for (int i = 0; i < nodes.Count; i++) { BonsaiNode node = nodes[i]; Drawer.DrawNode(t, node, NodeStatusColor(node)); Drawer.DrawPorts(t, node); } }
// Does not render ports in view mode since nodes cannot be changed. private void DrawNodesInViewMode(CanvasTransform t) { var nodes = Canvas.Nodes; for (int i = 0; i < nodes.Count; i++) { BonsaiNode node = nodes[i]; if (t.InView(node.RectPositon)) { Drawer.DrawNode(t, node, NodeStatusColor(node)); } } }
private void DrawConnections(CanvasTransform t) { var nodes = Canvas.Nodes; for (int i = 0; i < nodes.Count; i++) { BonsaiNode node = nodes[i]; if (node.HasOutput) { Drawer.DrawNodeConnections(t, node); } } }
private void DrawCanvasContents(CanvasTransform t) { var canvasRect = new Rect(Vector2.zero, t.size); ScaleUtility.BeginScale(canvasRect, ZoomScale, BonsaiWindow.toolbarHeight); CustomDraw?.Invoke(t); DrawConnections(t); DrawNodes(t); ScaleUtility.EndScale(canvasRect, ZoomScale, BonsaiWindow.toolbarHeight); // Overlays and independent of zoom. CustomOverlayDraw?.Invoke(); }
/// <summary> /// Get the first node detected under the mouse. Ports are counted as port of the check. /// </summary> /// <returns></returns> private static BonsaiNode NodeUnderMouse(CanvasTransform transform, IReadOnlyList <BonsaiNode> nodes) { // Iterate in reverse so the last drawn node (top) receives input first. for (int i = nodes.Count - 1; i >= 0; i--) { BonsaiNode node = nodes[i]; if (IsUnderMouse(transform, node.ContentRectClick) || IsUnderMouse(transform, node.InputRect) || IsUnderMouse(transform, node.OutputRect)) { return(node); } } return(null); }
private void HandleSingleContext(CanvasTransform t, IReadOnlyList <BonsaiNode> nodes) { BonsaiNode node = NodeUnderMouse(t, nodes); if (node != null) { NodeContextClick?.Invoke(this, node); CreateSingleSelectionContextMenu(node).ShowAsContext(); } else { CanvasContextClick?.Invoke(this, EventArgs.Empty); ShowCreateNodeMenu(); } }
private void HandleClickActions(CanvasTransform t, IReadOnlyList <BonsaiNode> nodes, Event e) { if (IsClickAction(e)) { if (quickClicksCount == 0) { doubleClickTimer.Start(); } clickTimer.Start(); MouseDown?.Invoke(this, CreateInputEvent(t, nodes)); } else if (IsUnlickAction(e)) { BonsaiInputEvent inputEvent = CreateInputEvent(t, nodes); // A node click is registered if below a time threshold. if (clickTimer.Enabled) { Click?.Invoke(this, inputEvent); } // Collect quick, consecutive clicks. if (doubleClickTimer.Enabled) { quickClicksCount++; } // Double click event occured. if (quickClicksCount >= 2) { DoubleClick?.Invoke(this, inputEvent); doubleClickTimer.Stop(); quickClicksCount = 0; } clickTimer.Stop(); MouseUp?.Invoke(this, inputEvent); } }
private static BonsaiInputEvent CreateInputEvent(CanvasTransform transform, IReadOnlyList <BonsaiNode> nodes) { bool isInputFocused = false; bool isOutputFocused = false; BonsaiNode node = NodeUnderMouse(transform, nodes); if (node != null) { isInputFocused = IsInputUnderMouse(transform, node); isOutputFocused = IsOutputUnderMouse(transform, node); } return(new BonsaiInputEvent { transform = transform, canvasMousePostion = MousePosition(transform), node = node, isInputFocused = isInputFocused, isOutputFocused = isOutputFocused }); }
public static void DrawNode( CanvasTransform t, BonsaiNode node, Color statusColor) { // Convert the node rect from canvas to screen space. Rect screenRect = node.RectPositon; screenRect.position = t.CanvasToScreenSpace(screenRect.position); // Remember the original color that way it is reset when the function exits. Color originalColor = GUI.color; DrawNodeBackground(screenRect, statusColor); // The node contents are grouped together within the node body. GUI.BeginGroup(screenRect); // Make the body of node local to the group coordinate space. Rect localRect = node.RectPositon; localRect.position = Vector2.zero; // Draw the contents inside the node body, automatically laid out. GUILayout.BeginArea(localRect, GUIStyle.none); DrawNodeTypeBackground(node); DrawExitStatus(node); DrawNodeContent(node); DrawBreakpoint(node); DrawPreOrderIndex(node); GUILayout.EndArea(); GUI.EndGroup(); GUI.color = originalColor; }
private void DrawGrid(CanvasTransform t) { var canvasRect = new Rect(Vector2.zero, t.size); Drawer.DrawGrid(canvasRect, Preferences.gridTexture, ZoomScale, panOffset); }
public static void DrawNodeConnections(CanvasTransform t, BonsaiNode node) { if (node.ChildCount() == 0) { return; } var prefs = BonsaiPreferences.Instance; Color connectionColor = prefs.defaultConnectionColor; float connectionWidth = prefs.defaultConnectionWidth; if (node.Behaviour.StatusEditorResult == BTNode.EStatusEditor.Running) { connectionColor = prefs.runningStatusColor; connectionWidth = prefs.runningConnectionWidth; } // Start the Y anchor coord at the tip of the Output port. float yoffset = node.RectPositon.yMax; // Calculate the anchor position. float anchorX = node.RectPositon.center.x; float anchorY = (yoffset + node.GetNearestInputY()) / 2f; // Anchor line, between the first and last child. // Find the min and max X coords between the children and the parent. node.GetBoundsX(out float anchorLineStartX, out float anchorLineEndX); // Get start and end positions of the anchor line (The common line where the parent and children connect). var anchorLineStart = new Vector2(anchorLineStartX, anchorY); var anchorLineEnd = new Vector2(anchorLineEndX, anchorY); // The tip where the parent starts its line to connect to the anchor line. var parentAnchorTip = new Vector2(anchorX, yoffset); // The point where the parent connects to the anchor line. var parentAnchorLineConnection = new Vector2(anchorX, anchorY); // Draw the lines from the calculated positions. DrawLineCanvasSpace( t, parentAnchorTip, parentAnchorLineConnection, connectionColor, connectionWidth); DrawLineCanvasSpace( t, anchorLineStart, anchorLineEnd, prefs.defaultConnectionColor, prefs.defaultConnectionWidth); foreach (BonsaiNode child in node.Children) { // Get the positions to draw a line between the node and the anchor line. Vector2 center = child.InputRect.center; var anchorLineConnection = new Vector2(center.x, anchorY); // The node is running, hightlight the connection. if (child.Behaviour.StatusEditorResult == BTNode.EStatusEditor.Running) { DrawLineCanvasSpace( t, center, anchorLineConnection, prefs.runningStatusColor, prefs.runningConnectionWidth); // Hightlight the portion of the anchorline between the running child and parent node. DrawLineCanvasSpace( t, anchorLineConnection, parentAnchorLineConnection, prefs.runningStatusColor, prefs.runningConnectionWidth); } else { // The node is not running, draw a default connection. DrawLineCanvasSpace( t, anchorLineConnection, center, prefs.defaultConnectionColor, prefs.defaultConnectionWidth); } } }
public static void DrawLineCanvasSpace(CanvasTransform t, Vector2 start, Vector2 end, Color color) { start = t.CanvasToScreenSpace(start); end = t.CanvasToScreenSpace(end); DrawLineScreenSpace(start, end, color); }
/// <summary> /// Returns the mouse position in canvas space. /// </summary> /// <returns></returns> public static Vector2 MousePosition(CanvasTransform transform) { return(transform.ScreenToCanvasSpace(Event.current.mousePosition)); }
/// <summary> /// Tests if the rect is under the mouse. /// </summary> /// <param name="r"></param> /// <returns></returns> public static bool IsUnderMouse(CanvasTransform transform, Rect r) { return(r.Contains(MousePosition(transform))); }
/// <summary> /// Get the ouput for the node if under the mouse. /// </summary> /// <param name="node"></param> /// <returns></returns> private static bool IsOutputUnderMouse(CanvasTransform t, BonsaiNode node) { return(node.HasOutput && IsUnderMouse(t, node.OutputRect)); }
/// <summary> /// Get the input for the node if under the mouse. /// </summary> /// <param name="node"></param> /// <returns></returns> private static bool IsInputUnderMouse(CanvasTransform t, BonsaiNode node) { return(IsUnderMouse(t, node.InputRect)); }
public static void DrawPort(CanvasTransform t, Rect portRect) { // Convert the body rect from canvas to screen space. portRect.position = t.CanvasToScreenSpace(portRect.position); GUI.DrawTexture(portRect, BonsaiPreferences.Instance.portTexture, ScaleMode.StretchToFill); }