/// <summary> /// Creates a new instance of a referenced behaviour node for a sub-reference graph. /// </summary> /// <param name="impulse">The original non-sub-reference graph referenced behaviour node.</param> public ReferencedBehavior(ReferencedBehavior referencedBehavior) : base(null, _theBackgroundBrush, _theDraggedBackgroundBrush, referencedBehavior.BaseLabel, false, referencedBehavior.Description) { _genericChildrenLocal= new ConnectorMultiple(_children, string.Empty, "GenericChildren", 1, int.MaxValue); _genericChildren= _genericChildrenLocal; // when this node is saved, the children won't as they belong to another behaviour _saveChildren= false; _referencedBehavior= null; referencedBehavior.CloneProperties(this); OnPropertyValueChanged(false); CopyEventHandlers(referencedBehavior); #if DEBUG _debugIsSubreferencedGraphNode= true; #endif }
/// <summary> /// Adds nodes to the referenced behaviour which represent sub-referenced behaviours. /// </summary> /// <param name="rootBehavior">The behaviour this node belongs to. NOT the referenced one.</param> /// <param name="parent">The node the sub-referenced behaviours will be added to.</param> /// <param name="node">The current node we are checking.</param> protected void GenerateReferencedBehaviorsTree(BehaviorNode rootBehavior, Node parent, Node node) { // check if this is a referenced behaviour if(node is ReferencedBehavior) { ReferencedBehavior rbnode= (ReferencedBehavior)node; // create the dummy node and add it without marking the behaviour as being modified as these are no REAL nodes. ReferencedBehavior rb= new ReferencedBehavior(rbnode); parent.AddChildNotModified(parent.DefaultConnector, rb); // we have a circular reference here. Skip the children if(rbnode._referencedBehavior ==rootBehavior) { rb._genericChildren.IsReadOnly= true; return; } // do the same for all the children foreach(Node child in node.Children) GenerateReferencedBehaviorsTree(rootBehavior, rb, child); rb._genericChildren.IsReadOnly= true; } else if(node is Impulse) { // create the dummy node and add it without marking the behaviour as being modified as these are no REAL nodes. Impulse ip= new Impulse( (Impulse)node ); // do the same for all the children foreach(Node child in node.Children) GenerateReferencedBehaviorsTree(rootBehavior, ip, child); if(ip.Children.Count >0) { parent.AddChildNotModified(parent.DefaultConnector, ip); ip.GenericChildren.IsReadOnly= true; } } else { // do the same for all the children foreach(Node child in node.Children) GenerateReferencedBehaviorsTree(rootBehavior, parent, child); } }
/// <summary> /// Attaches a dragged node from the node explorer to an existing node. /// </summary> /// <param name="nvd">The node the new node will be attached to.</param> /// <param name="mode">The way the new node will be attached.</param> /// <param name="nodetag">The tag of the you want to create.</param> /// <param name="label">The label of the new node.</param> private void InsertNewNode(NodeViewData nvd, NodeAttachMode mode, NodeTag nodetag) { // check if the attach mode is valid if(mode ==NodeAttachMode.Event || mode ==NodeAttachMode.None) throw new Exception("A node cannot be created with the given attach mode"); if(nodetag.Type !=NodeTagType.Behavior && nodetag.Type !=NodeTagType.Node) throw new Exception("Only behaviours and nodes can be attached to a behaviour tree"); Node node= nvd.Node; Node newnode; // when we attach a behaviour we must create a special referenced behaviour node if(nodetag.Type ==NodeTagType.Behavior) { // reset any previously loaded behaviour FileManagers.FileManager.ResetLoadedBehavior(); // get the behaviour we want to reference BehaviorNode behavior= _behaviorTreeList.LoadBehavior(nodetag.Filename); // a behaviour may not reference itself if(behavior ==_rootNode.RootBehavior) return; // create the referenced behaviour node for the behaviour ReferencedBehavior refnode= new ReferencedBehavior(_rootNode.RootBehavior, behavior); // register the view so it gets updated when the referenced behaviour gets updated. refnode.ReferencedBehaviorWasModified+= new ReferencedBehavior.ReferencedBehaviorWasModifiedEventDelegate(refnode_ReferencedBehaviorWasModified); newnode= refnode; } else { // simply create the node which is supposed to be created. newnode= Node.Create(nodetag.NodeType); } // update label newnode.OnPropertyValueChanged(false); // attach the new node with the correct mode switch(mode) { // the new node is inserted in front of the target node case(NodeAttachMode.Left): Node parent= node.Parent; int k= parent.Children.IndexOf(node); Node.Connector conn= node.ParentConnector; Debug.Check(conn !=null); parent.RemoveChild(conn, node); parent.AddChild(conn, newnode, k); Node.Connector newconn= newnode.GetConnector(conn.Identifier); Debug.Check(newconn !=null); newnode.AddChild(newconn, node); // automatically select the new node _selectedNodePending= newnode; _selectedNodePendingParent= nvd.Parent; break; // the new node is simply added to the target node's children case(NodeAttachMode.Right): node.AddChild(_dragTargetConnector, newnode); // automatically select the new node _selectedNodePending= newnode; _selectedNodePendingParent= nvd; break; // the new node is placed above the target node case(NodeAttachMode.Top): int n= _dragTargetNode.Node.ParentConnector.GetChildIndex(node); node.Parent.AddChild(_dragTargetNode.Node.ParentConnector, newnode, n); // automatically select the new node _selectedNodePending= newnode; _selectedNodePendingParent= nvd.Parent; break; // the new node is placed below the target node case(NodeAttachMode.Bottom): int m= _dragTargetNode.Node.ParentConnector.GetChildIndex(node); node.Parent.AddChild(_dragTargetNode.Node.ParentConnector, newnode, m +1); // automatically select the new node _selectedNodePending= newnode; _selectedNodePendingParent= nvd.Parent; break; } // the layout needs to be recalculated LayoutChanged(); }