/// <summary> /// Formats the tree to look nicely. /// </summary> public void PositionNodesNicely() { var bt = window.tree; // Assumption for Nicify: // There must be a root set. if (bt.Root == null) { return; } // This is for the node editor to use to place the nodes. var positions = new Dictionary <BehaviourNode, Vector2>(); var levels = calculateLevels(); var posParams = new PositioningParameters(); Action <BehaviourNode> positionInPlace = (node) => { positionNode(node, positions, levels, posParams); }; TreeIterator <BehaviourNode> .Traverse(bt.Root, positionInPlace, Traversal.PostOrder); foreach (var editorNode in canvas.Nodes) { var behaviour = editorNode.behaviour; if (positions.ContainsKey(behaviour)) { Vector2 pos = positions[behaviour]; editorNode.bodyRect.position = pos; } } }
/// <summary> /// Adds and removes children types based on current types selected. /// </summary> public void UpdateParentChildren() { _parentsToSetChildren.Clear(); _parentsToClearChildren.Clear(); TreeIterator <TypeSelectionNode> .Traverse(_root, markAdditionsAndRemovals); setParentChildren(); clearParentChildren(); }
/// <summary> /// Sets the position of the subtree at an offset. /// </summary> /// <param name="pos">The position of the subtree. </param> /// <param name="offset">Additional offset.</param> /// <param name="root">The subtree root.</param> public void SetSubtreePosition(Vector2 pos, Vector2 offset, BonsaiNode root) { float min = float.MinValue; if (root.Input.outputConnection != null) { float nodeTop = root.Input.bodyRect.yMin; float parentBottom = root.Input.outputConnection.bodyRect.yMax; // The root cannot be above its parent. if (nodeTop < parentBottom) { min = parentBottom; } } // Record the old position so we can know by how much the root moved // so all children can be shifted by the pan delta. Vector2 oldPos = root.bodyRect.position; // Clamp the position so it does not go above the parent. Vector2 diff = pos - offset; diff.y = Mathf.Clamp(diff.y, min, float.MaxValue); Vector2 rounded = SnapPosition(diff); root.bodyRect.position = rounded; // Calculate the change of position of the root. Vector2 pan = root.bodyRect.position - oldPos; // Move the entire subtree of the root. Action <BonsaiNode> subtreeDrag = (node) => { // For all children, pan by the same amount that the parent changed by. if (node != root) { node.bodyRect.position += SnapPosition(pan); } }; TreeIterator <BonsaiNode> .Traverse(root, subtreeDrag); }
// To do this, we do a regular DFS and just check the current // path length at a given node to determine its level. private Dictionary <BehaviourNode, int> calculateLevels() { var bt = window.tree; if (bt.Root == null) { return(null); } var levels = new Dictionary <BehaviourNode, int>(); Action <BehaviourNode, TreeIterator <BehaviourNode> > setLevel = (node, itr) => { levels.Add(node, itr.CurrentLevel); }; TreeIterator <BehaviourNode> .Traverse(bt.Root, setLevel, Traversal.LevelOrder); return(levels); }
/// <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. TreeIterator <BonsaiNode> .Traverse( root, node => node.SortChildren()); var positioning = new FormatPositioning(); TreeIterator <BonsaiNode> .Traverse( root, node => PositionHorizontal(node, positioning), Traversal.PostOrder); TreeIterator <BonsaiNode> .Traverse( root, node => PositionVertical(node)); // Move the entire subtree to the anchor. Vector2 offset = EditorSingleDrag.StartDrag(root, root.Center); EditorSingleDrag.SetSubtreePosition(root, anchor, offset); }