private void SingleNodeAction(object sender, BonsaiInput.NodeContext actionType) { switch (actionType) { case BonsaiInput.NodeContext.SetAsRoot: Canvas.SetRoot(NodeSelection.SingleSelectedNode); break; case BonsaiInput.NodeContext.Duplicate: EditorNodeCreation.DuplicateSingle(Canvas, NodeSelection.SingleSelectedNode); break; case BonsaiInput.NodeContext.FormatTree: BonsaiNode root = NodeSelection.SingleSelectedNode; Formatter.PositionNodesNicely(root, root.Center); break; case BonsaiInput.NodeContext.Delete: RemoveSelectedNodes(); break; case BonsaiInput.NodeContext.AddBreakPoint: SetBreakPoint(NodeSelection.SingleSelectedNode, true); break; case BonsaiInput.NodeContext.DeleteBreakPoint: SetBreakPoint(NodeSelection.SingleSelectedNode, false); break; } UpdateAbortableSelection(); }
public void ToggleSelecion(BonsaiNode node) { if (IsNodeSelected(node)) { selectedNodes.Remove(node); } else { selectedNodes.Add(node); } if (IsSingleSelection) { BonsaiNode selectedNode = SingleSelectedNode; Selection.objects = null; Selection.activeObject = selectedNode.Behaviour; SingleSelected?.Invoke(this, selectedNode); //SelectReferencedNodes(selectedNode); } else if (IsMultiSelection) { Selection.objects = selectedNodes.Select(n => n.Behaviour).ToArray(); } }
/// <summary> /// Formats the tree to look nicely. /// </summary> public static void PositionNodesNicely(BonsaiNode root, Vector2 anchor) { // Sort parent-child connections so formatter uses latest changes. foreach (BonsaiNode node in TreeTraversal.PreOrder(root)) { node.SortChildren(); } var positioning = new FormatPositioning(); foreach (BonsaiNode node in TreeTraversal.PostOrder(root)) { PositionHorizontal(node, positioning); } foreach (BonsaiNode node in TreeTraversal.PreOrder(root)) { PositionVertical(node); } // Move the entire subtree to the anchor. Vector2 offset = EditorSingleDrag.StartDrag(root, root.Center); EditorSingleDrag.SetSubtreePosition(root, anchor, offset); }
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); }
private void StartSingleDrag(BonsaiInputEvent startEvent) { BonsaiNode node = startEvent.node; Vector2 offset = EditorSingleDrag.StartDrag(node, startEvent.canvasMousePostion); MotionAction = (CanvasTransform t) => EditorSingleDrag.Drag(node, BonsaiInput.MousePosition(t), offset); }
private Color NodeStatusColor(BonsaiNode node) { if (!node.Behaviour.IsValid()) { return(Color.red); } if (IsNodeObserving(node)) { return(Preferences.evaluateColor); } else if (IsNodeRunning(node)) { return(Preferences.runningColor); } else if (NodeSelection.IsNodeSelected(node)) { return(Preferences.selectedColor); } //else if (NodeSelection.IsReferenced(node)) //{ // return Preferences.referenceColor; //} else if (abortableSelected.Contains(node)) { return(Preferences.abortColor); } else if (Canvas.Root == node) { return(Preferences.rootSymbolColor); } return(Preferences.defaultNodeBackgroundColor); }
public static void DrawExitStatus(BonsaiNode node) { // Draw the exit status in the top right corner. float statusSize = BonsaiPreferences.Instance.statusIconSize; Rect contentRect = node.ContentRect; var rect = new Rect(contentRect.xMin, contentRect.yMin, statusSize, statusSize); var prefs = BonsaiPreferences.Instance; var status = node.Behaviour.StatusEditorResult; if (status == BTNode.EStatusEditor.Success) { DrawTexture(rect, prefs.successSymbol, prefs.successColor); } else if (status == BTNode.EStatusEditor.Failure) { DrawTexture(rect, prefs.failureSymbol, prefs.failureColor); } else if (status == BTNode.EStatusEditor.Aborted) { DrawTexture(rect, prefs.failureSymbol, prefs.abortedColor); } else if (status == BTNode.EStatusEditor.Interruption) { DrawTexture(rect, prefs.failureSymbol, prefs.interruptedColor); } }
// Creates and adds an editor node to the canvas. private BonsaiNode AddEditorNode(bool hasOutput, Texture icon = null) { var node = BonsaiNode.Create(hasOutput, icon); nodes.Add(node); return(node); }
private BonsaiNode ReconstructEditorNode(BTNode behaviour) { BonsaiNode node = CreateNode(behaviour); node.Behaviour = behaviour; node.Position = behaviour.nodePosition; return(node); }
public void PushToEnd(BonsaiNode node) { bool bRemoved = nodes.Remove(node); if (bRemoved) { nodes.Add(node); } }
public static BonsaiNode DuplicateSingle(BonsaiCanvas canvas, BonsaiNode original) { BonsaiNode duplicate = canvas.CreateNode(original.Behaviour.GetType()); // Duplicate nodes are placed offset from the original. duplicate.Position = original.Position + Vector2.one * 40f; return(duplicate); }
private static void GetCompositeParent(BonsaiNode aborter, out BonsaiNode compositeParent, out BonsaiNode directChild) { directChild = aborter; compositeParent = aborter.Parent; while (compositeParent != null && !compositeParent.Behaviour.IsComposite()) { directChild = compositeParent; compositeParent = compositeParent.Parent; } }
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 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); } }
public void SetSingleSelection(BonsaiNode newSingleSelected) { selectedNodes.Clear(); selectedNodes.Add(newSingleSelected); #if UNITY_2019_1_OR_NEWER Selection.objects = null; #endif Selection.activeObject = newSingleSelected.Behaviour; SingleSelected?.Invoke(this, newSingleSelected); //SelectReferencedNodes(newSingleSelected); }
public void UpdateAbortableSelection(BonsaiNode node) { abortableSelected.Clear(); var aborter = node.Behaviour as BTDecorator; if (aborter) { abortableSelected = new HashSet <BonsaiNode>(Abortables(node, aborter.abortType)); } }
public void UpdateNodeGUI(BTNode behaviour) { BonsaiNode node = Canvas.Nodes.FirstOrDefault(n => n.Behaviour == behaviour); if (node != null) { node.UpdateGui(); node.Center = MathExtensions.SnapPosition(node.Center, SnapStep); } UpdateAbortableSelection(); }
// Render the background color scheme for the node type. public static void DrawNodeTypeBackground(BonsaiNode node) { GUI.DrawTexture( node.ContentRect, BonsaiPreferences.Instance.nodeGradient, ScaleMode.StretchToFill, true, 0f, NodeTypeColor(node), 0f, 4f); }
// Reconstruct editor nodes from the tree. private Dictionary <BTNode, BonsaiNode> ReconstructEditorNodes(IEnumerable <BTNode> behaviours) { var nodeMap = new Dictionary <BTNode, BonsaiNode>(); foreach (BTNode behaviour in behaviours) { BonsaiNode node = ReconstructEditorNode(behaviour); nodeMap.Add(behaviour, node); } return(nodeMap); }
public void SetRoot(BonsaiNode newRoot) { if (newRoot.Parent == null) { Root = newRoot; //Undo.RecordObject(Root, "Set Root"); } else { Debug.LogWarning("Root cannot be a child."); } }
private void SetBreakPoint(BonsaiNode seletedNode, bool breakpoint) { if (seletedNode == null) { return; } if (seletedNode.Behaviour == null) { return; } seletedNode.Behaviour.BreakPoint = breakpoint; }
private void PopulateDecoratorNodes(GenericMenu menu, BonsaiNode node) { var decorators = BonsaiEditor.RegisteredBehaviourNodeTypes.Where(t => t.IsSubclassOf(typeof(BTAuxiliary)) && !t.IsAbstract); foreach (var subclass in decorators) { menu.AddItem(new GUIContent("Decorator/" + subclass.Name), false, () => { CreateNodeRequest?.Invoke("Decorator", subclass); TypeChanged?.Invoke(this, node); }); } }
// A "branch list" is a tree branch where nodes only have a single child. // e.g. Decorator -> Decorator -> Decorator -> Task private static float MaxWidthForBranchList(BonsaiNode leaf) { float maxWidth = leaf.Size.x; var parent = leaf.Parent; while (parent != null && parent.ChildCount() == 1) { maxWidth = Mathf.Max(maxWidth, parent.Size.x); parent = parent.Parent; } return(maxWidth); }
// 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)); } } }
public void Remove(BonsaiNode node) { if (nodes.Remove(node)) { // Clear root since it was removed. if (node == Root) { Root = null; } node.Destroy(); } }
/// <summary> /// Highlights nodes that are being re-evaluated, like abort nodes. /// </summary> /// <param name="node"></param> private bool IsNodeObserving(BonsaiNode node) { BTNode behaviour = node.Behaviour; BehaviorIterator itr = behaviour.Iterator; if (itr != null && itr.IsRunning) { var aborter = behaviour as BTDecorator; return(aborter && aborter.IsObserving); } return(false); }
private void PopulateTypeConversions(GenericMenu menu, BonsaiNode node) { Type coreType = BonsaiEditor.CoreType(node.Behaviour); var behaviourTypes = BonsaiEditor.RegisteredBehaviourNodeTypes; foreach (Type subclass in behaviourTypes.Where(t => t.IsSubclassOf(coreType) && !t.IsAbstract)) { menu.AddItem(new GUIContent("Change Type/" + subclass.Name), false, () => { EditorChangeNodeType.ChangeType(node, subclass); TypeChanged?.Invoke(this, 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); } } }
/// <summary> /// draw breakpoint icon of this node /// </summary> /// <param name="node"></param> private static void DrawBreakpoint(BonsaiNode node) { if (node.Behaviour.BreakPoint) { GUI.DrawTexture( node.BreakpointRect, BonsaiPreferences.Instance.breakPoint, ScaleMode.StretchToFill, true, 0f, Color.red, 0f, 4f); } }
private static void PositionVertical(BonsaiNode node) { BonsaiNode parent = node.Parent; if (parent != null) { float ySeperation = parent.ChildCount() == 1 ? FormatPositioning.yLevelSeparation / 2f : FormatPositioning.yLevelSeparation; float x = node.Position.x; float y = parent.Position.y + parent.Size.y + ySeperation; node.Position = new Vector2(x, y); } }