Beispiel #1
0
        /// <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, PointF mousePos) {
            if (nodetag.Type != NodeTagType.Behavior && nodetag.Type != NodeTagType.Prefab && nodetag.Type != NodeTagType.Node) {
                throw new Exception("Only behaviours, prefabs and nodes can be attached to a behaviour tree");
            }

            Node newnode = null;
            bool isPrefabInstance = false;

            // when we attach a behaviour we must create a special referenced behaviour node
            if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab) {
                if (!File.Exists(nodetag.Filename)) {
                    if (!SaveBehavior(nodetag.Filename)) {
                        return;
                    }
                }

                // get the behavior we want to reference
                BehaviorNode behavior = _behaviorTreeList.LoadBehavior(nodetag.Filename);

                // a behaviour reference itself
                if (nvd != null && nvd.IsBehaviorReferenced(behavior)) {
                    if (DialogResult.Cancel == MessageBox.Show(Resources.CircularReferencedInfo, Resources.Warning, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning)) {
                        return;
                    }
                }

                if (nodetag.Type == NodeTagType.Prefab) {
                    behavior = (BehaviorNode)behavior.Clone();
                }

                Behavior rootB = _rootNodeView.RootBehavior as Behavior;
                Behavior b = behavior as Behavior;

                if (rootB.AgentType == null) {
                    rootB.AgentType = b.AgentType;

                } else if (!IsCompatibleAgentType(rootB, b)) {
                    return;
                }

                // behavior
                if (nodetag.Type == NodeTagType.Behavior) {
                    // create the referenced behaviour node for the behaviour
                    ReferencedBehavior refnode = Node.CreateReferencedBehaviorNode(_rootNodeView.RootBehavior, behavior, mode == NodeAttachMode.None || ((Node)this.RootNode).IsFSM);

                    newnode = (Node)refnode;
                    //the comment seems too long to overlap the node
                    //newnode.CommentText = Resources.ThisIsReferenceTree;
                    newnode.CommentBackground = Node.CommentColor.Gray;
                }

                // prefab
                else {
                    // Copy all Pars from the prefab file into the current behavior node.
                    List<ParInfo> pars = new List<ParInfo>();
                    foreach(ParInfo par in b.LocalVars) {
                        bool found = false;
                        foreach(ParInfo rootPar in rootB.LocalVars) {
                            if (par.Name == rootPar.Name) {
                                if (par.Type != rootPar.Type) {
                                    string errorMsg = string.Format(Resources.ParErrorInfo, par.Name, b.Label, rootB.Label);
                                    MessageBox.Show(errorMsg, Resources.LoadError, MessageBoxButtons.OK);
                                    return;
                                }

                                found = true;
                                break;
                            }
                        }

                        if (!found) {
                            pars.Add(par);
                        }
                    }

                    rootB.LocalVars.AddRange(pars);

                    // The first child should be the root node of the prefab tree.
                    Node behaviorNode = (Node)behavior;

                    if (behaviorNode.Children.Count > 0) {
                        newnode = (Node)behaviorNode.Children[0];

                        string prefab = Path.GetFileNameWithoutExtension(behavior.Filename);
                        newnode.CommentText = string.Format("Prefab[{0}]", prefab);

                        isPrefabInstance = true;
                        string prefabName = FileManagers.FileManager.GetRelativePath(behavior.Filename);
                        newnode.SetPrefab(prefabName);
                    }
                }

            } else {
                // simply create the node which is supposed to be created.
                newnode = Node.Create(nodetag.NodeType);

                if (newnode != null)
                    newnode.PostCreatedByEditor();
            }

            if (newnode == null) {
                return;
            }

            // update label
            newnode.OnPropertyValueChanged(false);

            Node node = (nvd != null) ? nvd.Node : null;

            if (node == null) {
                mode = NodeAttachMode.None;
            }

            Attachments.Attachment startCondition = null;

            // attach the new node with the correct mode
            switch (mode) {
                    // the new node is inserted in front of the target node
                case NodeAttachMode.Left:
                    if (node != null) {
                        Node parent = (Node)node.Parent;

                        int k = node.ParentConnector.GetChildIndex(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:
                    if (newnode != null && newnode.IsFSM) {
                        startCondition = this.addFSMNode(newnode, mousePos);

                        newnode.ScreenLocation = new PointF(_rootNodeView.BoundingBox.Left + _rootNodeView.BoundingBox.Width * 1.5f, _rootNodeView.BoundingBox.Top);

                    } else if (node != null) {
                        node.AddChild(_dragTargetConnector, newnode);

                        _dragTargetConnector.IsExpanded = true;

                        // automatically select the new node
                        _selectedNodePending = newnode;
                        _selectedNodePendingParent = nvd;
                    }

                    break;

                    // the new node is placed above the target node
                case NodeAttachMode.Top:
                    if (node != null) {
                        int n = _dragTargetNode.Node.ParentConnector.GetChildIndex(node);
                        ((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:
                    if (node != null) {
                        int m = _dragTargetNode.Node.ParentConnector.GetChildIndex(node);
                        ((Node)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, m + 1);

                        // automatically select the new node
                        _selectedNodePending = newnode;
                        _selectedNodePendingParent = nvd.Parent;
                    }

                    break;

                    // the node will replace the target node
                case NodeAttachMode.Center:
                    if (node != null && replaceNode(node, newnode)) {
                        // automatically select the new node
                        _selectedNodePending = newnode;
                        _selectedNodePendingParent = nvd.Parent;

                        this.Redraw();
                    }

                    break;

                case NodeAttachMode.None:
                    if (newnode != null && newnode.IsFSM) {
                        startCondition = this.addFSMNode(newnode, mousePos);

                        // automatically select the new node
                        _selectedNodePending = newnode;
                        _selectedNodePendingParent = this.RootNodeView;
                    }

                    break;
            }

            // After being created, its Id should be reset.
            if (newnode != null) {
                newnode.ResetId(true);

                // set the prefab dirty for the current parent
                if (newnode.Parent != null) {
                    Node parent = (Node)newnode.Parent;

                    if (!string.IsNullOrEmpty(parent.PrefabName)) {
                        parent.HasOwnPrefabData = true;

                        if (!isPrefabInstance) {
                            newnode.SetPrefab(parent.PrefabName);
                            newnode.HasOwnPrefabData = true;
                        }
                    }
                }

                if (startCondition != null) {
                    startCondition.TargetFSMNodeId = newnode.Id;
                }

                UndoManager.Save(this.RootNode);
            }

            // the layout needs to be recalculated
            LayoutChanged();
        }
Beispiel #2
0
        /// <summary>
        /// Handles the drawing and updating of the graph.
        /// </summary>
        protected override void OnPaint(PaintEventArgs e) {
            base.OnPaint(e);

            // calculate the mouse position in the graph
            PointF graphMousePos = _nodeLayoutManager.ViewToGraph(_lastMousePosition);

            // when the layout was changed it needs to be recalculated
            bool layoutChanged = _nodeLayoutManager.LayoutChanged;

            if (layoutChanged) {
                _nodeLayoutManager.UpdateLayout(e.Graphics, _forceChangeLayout);
                _forceChangeLayout = false;
            }

            // center the root behaviour if requested
            if (_pendingCenterBehavior) {
                _pendingCenterBehavior = false;
                CenterNode(_rootNodeView);
            }

            // select the pending node
            if (_selectedNodePending != null) {
                if (_selectedNodePendingParent != null) {
                    if (_selectedNodePendingParent.CanBeExpanded() && !_selectedNodePendingParent.IsExpanded) {
                        _selectedNodePendingParent.IsExpanded = true;
                        LayoutChanged();
                    }

                    SelectedNode = _selectedNodePendingParent.GetChild(_selectedNodePending);

                } else {
                    SelectedNode = RootNodeView.FindNodeViewData(_selectedNodePending);
                }

                if (SelectedNode != null) {
                    if (SelectedNode.CanBeExpanded() && !SelectedNode.IsExpanded) {
                        SelectedNode.IsExpanded = true;
                        LayoutChanged();
                    }

                    SelectedNode.SelectedSubItem = SelectedNode.GetSubItem(_selectedAttachmentPending);
                    ShowNode(SelectedNode);
                }

                _selectedNodePending = null;
                _selectedNodePendingParent = null;
                _selectedAttachmentPending = null;

                if (ClickEvent != null) {
                    ClickEvent(SelectedNode);
                }
            }

            // check if we must keep the original position of the mouse
            if (_maintainMousePosition) {
                _maintainMousePosition = false;

                // move the graph so that _graphOrigin is at the same position in the view as it was before
                float mouseX = (graphMousePos.X - _graphOrigin.X) * _nodeLayoutManager.Scale + _nodeLayoutManager.Offset.X;
                float mouseY = (graphMousePos.Y - _graphOrigin.Y) * _nodeLayoutManager.Scale + _nodeLayoutManager.Offset.Y;

                _nodeLayoutManager.Offset = new PointF(mouseX, mouseY);
            }

            // check if we must keep the original position of _maintainNodePosition
            else if (_maintainNodePosition != null) {
                // move the graph so that _graphOrigin is at the same position in the view as it was before
                RectangleF bbox = _maintainNodePosition.IsFSM ? _maintainNodePosition.GetTotalBoundingBox() : _maintainNodePosition.BoundingBox;
                PointF viewpos = new PointF(bbox.X * _nodeLayoutManager.Scale, bbox.Y * _nodeLayoutManager.Scale);

                _nodeLayoutManager.Offset = new PointF(_graphOrigin.X - viewpos.X, _graphOrigin.Y - viewpos.Y);
            }

            // reset the node whose position we want to keep
            _maintainNodePosition = null;

            // draw the graph to the view
            _nodeLayoutManager.DrawGraph(e.Graphics, graphMousePos, _currentNode, SelectedNode, _highlightedNodeIds, _updatedNodeIds, _highlightedTransitionIds, _highlightBreakPoint, _profileInfos);

            // check if we are currently dragging a node and we must draw additional data
            if (_dragTargetNode != null && _dragAttachment == null && (KeyCtrlIsDown && _movedNode != null || _dragTargetNode.Node != _movedNode)) {
                if (_dragAttachMode == NodeAttachMode.Attachment) {
                    // we could draw some stuff for attachements here
                } else {
                    // draw the arrows for the attach modes

                    // get the bounding box of the node
                    RectangleF bbox = _dragTargetNode.BoundingBox;

                    // get the bounding box of the connector
                    _dragTargetConnector = null;

                    // the depth of the area for the mouse
                    const float offset = 12.0f;

                    // the distance of the arrow from the border and its height
                    const float innerOffset = 2.0f;

                    // the horizintal middle of the node
                    float centerX = bbox.Left + bbox.Width * 0.5f;
                    float centerY = bbox.Top + bbox.Height * 0.5f;
                    float centerBoxX = bbox.X + bbox.Width * 0.4f;
                    float centerBoxWidth = bbox.Width * 0.2f;

                    // the half width of the arrow depending of the node's height
                    float arrowHalfWidth = (bbox.Height - innerOffset - innerOffset) * 0.5f;

                    // calculate the mouse areas for the different attach modes
                    RectangleF top    = new RectangleF(centerBoxX, bbox.Top, centerBoxWidth, offset);
                    RectangleF bottom = new RectangleF(centerBoxX, bbox.Bottom - offset, centerBoxWidth, offset);
                    RectangleF center = new RectangleF(centerBoxX, centerY - offset * 0.5f, centerBoxWidth, offset);
                    RectangleF left   = new RectangleF(bbox.X, bbox.Y, offset, bbox.Height);

                    // update for dragging in a new node
                    BehaviorNode behavior = _dragNodeDefaults as BehaviorNode;

                    if (behavior != null && behavior.FileManager == null) {
                        behavior = null;
                    }

                    // the node that is currently dragged
                    Node draggedNode = (_movedNode != null) ? _movedNode : (_dragNodeDefaults as Node);

                    if (draggedNode == null) {
                        return;
                    }

                    Node.Connector parentConnector = _dragTargetNode.Node.ParentConnector;
                    bool canBeAdoptedByParent = parentConnector != null && (!parentConnector.IsAsChild || AdoptNodeByAncestor(_dragTargetNode.Node.Parent, draggedNode));
                    //bool targetCanBeAdoptedByParent = (_movedNode == null) || (_movedNode.ParentConnector != null) && _movedNode.ParentConnector.AcceptsChild(_dragTargetNode.Node);
                    bool hasParentBehavior = _dragTargetNode.HasParentBehavior(behavior);
                    bool parentHasParentBehavior = (_dragTargetNode.Parent == null);

                    bool isFSM = _rootNodeView.IsFSM || (_rootNodeView.Children.Count == 0);

                    bool mayTop = !isFSM && canBeAdoptedByParent /*&& targetCanBeAdoptedByParent*/ && !parentHasParentBehavior &&
                                  parentConnector != null && parentConnector.AcceptsChild(draggedNode);

                    bool mayBottom = mayTop;

                    bool mayCenter = !parentHasParentBehavior && (_rootNodeView.IsFSM && draggedNode.IsFSM || canBeAdoptedByParent && 
                                     draggedNode.GetType() != _dragTargetNode.Node.GetType() &&
                                     parentConnector != null && !parentConnector.IsReadOnly && parentConnector.AcceptsChild(draggedNode, true) &&
                                     draggedNode.CanAdoptChildren(_dragTargetNode.Node));

                    bool mayLeft = !isFSM && (_dragTargetNode.Node.Parent != _movedNode) &&
                                   canBeAdoptedByParent && !parentHasParentBehavior && !hasParentBehavior &&
                                   parentConnector != null && !parentConnector.IsReadOnly && parentConnector.AcceptsChild(draggedNode, true) &&
                                   !(draggedNode is BehaviorNode) && draggedNode.CanAdoptNode(_dragTargetNode.Node);

                    // update for moving an existing node
                    bool dragTargetHasParentMovedNode = false;

                    if (_movedNode != null) {
                        mayCenter = false;
                        dragTargetHasParentMovedNode = KeyShiftIsDown && _dragTargetNode.Node.HasParent(_movedNode);

                        // a node may not dragged on itself and may not dragged on one of its own children
                        if (_dragTargetNode.Node == _movedNode || dragTargetHasParentMovedNode) {
                            //mayTop = KeyCtrlIsDown;
                            mayTop &= KeyCtrlIsDown && (_dragTargetNode.Node.ParentConnector != null) && _dragTargetNode.Node.ParentConnector.AcceptsChild(_movedNode);
                            mayBottom = mayTop;
                            mayLeft = false;

                        } else {
                            // a dragged node cannot be placed in the same position again
                            mayTop &= (KeyCtrlIsDown || _dragTargetNode.Node.PreviousNode != _movedNode);
                            mayBottom &= (KeyCtrlIsDown || _dragTargetNode.Node.NextNode != _movedNode);
                            mayLeft &= _movedNode.CanAdoptChildren(_dragTargetNode.Node) && (!KeyShiftIsDown || _movedNode.Children.Count == 0);
                        }
                    }

                    if (_copiedNode != null) {
                        mayCenter = false;
                        mayLeft &= _copiedNode.CanAdoptChildren(_dragTargetNode.Node) && (!KeyShiftIsDown || _copiedNode.Children.Count == 0);
                        mayTop &= (_dragTargetNode.Node.ParentConnector != null) && _dragTargetNode.Node.ParentConnector.AcceptsChild(_copiedNode);
                        mayBottom = mayTop;

                    } else if (_clipboardPasteMode) {
                        mayCenter = false;
                        mayLeft &= !KeyShiftIsDown;
                    }

                    // reset the attach mode
                    _dragAttachMode = NodeAttachMode.None;

                    // the vertices needed to draw the arrows
                    PointF[] vertices = new PointF[3];

                    // draw the top arrow if this action is allowed
                    if (mayTop) {
                        vertices[0] = new PointF(centerX - arrowHalfWidth, top.Bottom - innerOffset);
                        vertices[1] = new PointF(centerX, top.Top + innerOffset);
                        vertices[2] = new PointF(centerX + arrowHalfWidth, top.Bottom - innerOffset);

                        if (top.Contains(graphMousePos)) {
                            _dragAttachMode = NodeAttachMode.Top;
                            e.Graphics.FillPolygon(Brushes.White, vertices);

                        } else {
                            e.Graphics.FillPolygon(Brushes.Black, vertices);
                        }
                    }

                    // draw the bottom arrow if this action is allowed
                    if (mayBottom) {
                        vertices[0] = new PointF(centerX - arrowHalfWidth, bottom.Top + innerOffset);
                        vertices[1] = new PointF(centerX + arrowHalfWidth, bottom.Top + innerOffset);
                        vertices[2] = new PointF(centerX, bottom.Bottom - innerOffset);

                        if (_dragAttachMode == NodeAttachMode.None && bottom.Contains(graphMousePos)) {
                            _dragAttachMode = NodeAttachMode.Bottom;
                            e.Graphics.FillPolygon(Brushes.White, vertices);

                        } else {
                            e.Graphics.FillPolygon(Brushes.Black, vertices);
                        }
                    }

                    // draw the center rectangle if this action is allowed
                    if (mayCenter) {
                        if (center.Contains(graphMousePos)) {
                            _dragAttachMode = NodeAttachMode.Center;
                            e.Graphics.FillRectangle(Brushes.White, centerX - arrowHalfWidth * 0.5f, centerY - innerOffset * 2.0f, arrowHalfWidth, innerOffset * 4.0f);

                        } else {
                            e.Graphics.FillRectangle(Brushes.Black, centerX - arrowHalfWidth * 0.5f, centerY - innerOffset * 2.0f, arrowHalfWidth, innerOffset * 4.0f);
                        }
                    }

                    // draw the left arrow if this action is allowed
                    if (mayLeft) {
                        vertices[0] = new PointF(left.Right - innerOffset, left.Top + innerOffset);
                        vertices[1] = new PointF(left.Right - innerOffset, left.Bottom - innerOffset);
                        vertices[2] = new PointF(left.Left + innerOffset, left.Top + left.Height * 0.5f);

                        if (_dragAttachMode == NodeAttachMode.None && left.Contains(graphMousePos)) {
                            _dragAttachMode = NodeAttachMode.Left;
                            e.Graphics.FillPolygon(Brushes.White, vertices);

                        } else {
                            e.Graphics.FillPolygon(Brushes.Black, vertices);
                        }
                    }

                    // draw the right arrow if this action is allowed
                    foreach(Node.Connector connector in _dragTargetNode.Connectors) {
                        RectangleF bboxConnector = _dragTargetNode.GetConnectorBoundingBox(bbox, connector);
                        RectangleF right = new RectangleF(bboxConnector.Right - offset, bboxConnector.Y, offset, bboxConnector.Height);

                        bool mayRight = !_rootNodeView.IsFSM && !dragTargetHasParentMovedNode &&
                                        !hasParentBehavior &&
                                        !connector.IsReadOnly &&
                                        connector.AcceptsChild(draggedNode) &&
                                        (!connector.IsAsChild || AdoptNodeByAncestor(_dragTargetNode.Node, draggedNode));

                        if (mayRight && draggedNode != null && connector == draggedNode.ParentConnector) {
                            mayRight = false;
                        }

                        if (mayRight) {
                            float inOffset = bboxConnector.Height > innerOffset * 4.0f ? innerOffset : 3.0f;

                            vertices[0] = new PointF(right.Left + inOffset, right.Top + inOffset);
                            vertices[1] = new PointF(right.Right - inOffset, right.Top + right.Height * 0.5f);
                            vertices[2] = new PointF(right.Left + inOffset, right.Bottom - inOffset);

                            if (_dragAttachMode == NodeAttachMode.None && right.Contains(graphMousePos)) {
                                _dragTargetConnector = _dragTargetNode.Node.GetConnector(connector.Identifier);
                                _dragAttachMode = NodeAttachMode.Right;
                                e.Graphics.FillPolygon(Brushes.White, vertices);

                            } else {
                                e.Graphics.FillPolygon(Brushes.Black, vertices);
                            }
                        }
                    }
                }
            }

            // draw last mouse pos
            //e.Graphics.DrawRectangle(Pens.Red, graphMousePos.X -1.0f, graphMousePos.Y -1.0f, 2.0f, 2.0f);

            //when we are dragging an existing node we draw a small graph representing it
            if (_movedNodeGraph != null) {
                // update the layout for the graph. This happens only once inside the function.
                _movedNodeGraph.UpdateLayout(e.Graphics);

                // offset the graph to the mouse position
                _movedNodeGraph.Offset = new PointF(_nodeLayoutManager.Offset.X + graphMousePos.X * _nodeLayoutManager.Scale,
                                                    _nodeLayoutManager.Offset.Y + graphMousePos.Y * _nodeLayoutManager.Scale - _movedNodeGraph.RootNodeLayout.LayoutRectangle.Height * 0.5f * _movedNodeGraph.Scale);

                // draw the graph
                _movedNodeGraph.DrawGraph(e.Graphics, graphMousePos);
            }

            // attachment
            if (_currentNode != null && _dragTargetNode != null &&
                _dragAttachment != null && _dragTargetAttachment != null && _dragAttachment != _dragTargetAttachment &&
                _dragTargetNode.Node.AcceptsAttachment(_dragAttachment.Attachment)) {
                _dragAttachMode = NodeAttachMode.None;

                Attachments.Attachment sourceAttach = _dragAttachment.SelectableObject as Attachments.Attachment;
                Attachments.Attachment targetAttach = _dragTargetAttachment.SelectableObject as Attachments.Attachment;

                if (sourceAttach != null && targetAttach != null &&
                    sourceAttach.IsPrecondition == targetAttach.IsPrecondition &&
                    sourceAttach.IsTransition == targetAttach.IsTransition &&
                    sourceAttach.IsEffector == targetAttach.IsEffector)
                {
                    SubItemRegin regin = _dragTargetNode.GetSubItemRegin(graphMousePos);
                    int itemIndex = _currentNode.GetSubItemIndex(_dragAttachment);
                    int targetItemIndex = _dragTargetNode.GetSubItemIndex(_dragTargetAttachment);

                    if (regin != SubItemRegin.Out && itemIndex >= 0 && targetItemIndex >= 0) {
                        RectangleF bbox = _dragTargetNode.GetSubItemBoundingBox(graphMousePos);

                        const float offset = 8.0f;
                        const float innerOffset = 2.0f;

                        float centerX = bbox.Left + bbox.Width * 0.5f;
                        float centerY = bbox.Top + bbox.Height * 0.5f;
                        float centerBoxX = bbox.X + bbox.Width * 0.4f;
                        float arrowHalfWidth = bbox.Width * 0.12f;

                        RectangleF top = new RectangleF(centerX - arrowHalfWidth, bbox.Top, arrowHalfWidth * 2.0f, offset);
                        RectangleF bottom = new RectangleF(centerX - arrowHalfWidth, bbox.Bottom - offset, arrowHalfWidth * 2.0f, offset);

                        PointF[] vertices = new PointF[3];

                        switch (regin) {
                            case SubItemRegin.Top:
                                if (KeyCtrlIsDown || _currentNode != _dragTargetNode || itemIndex != targetItemIndex - 1) {
                                    vertices[0] = new PointF(centerX - arrowHalfWidth, top.Bottom - innerOffset);
                                    vertices[1] = new PointF(centerX, top.Top + innerOffset);
                                    vertices[2] = new PointF(centerX + arrowHalfWidth, top.Bottom - innerOffset);

                                    if (top.Contains(graphMousePos)) {
                                        _dragAttachMode = NodeAttachMode.Top;
                                        e.Graphics.FillPolygon(Brushes.White, vertices);

                                    } else {
                                        e.Graphics.FillPolygon(Brushes.Black, vertices);
                                    }
                                }

                                break;

                            case SubItemRegin.Bottom:
                                if (KeyCtrlIsDown || _currentNode != _dragTargetNode || itemIndex != targetItemIndex + 1) {
                                    vertices[0] = new PointF(centerX - arrowHalfWidth, bottom.Top + innerOffset);
                                    vertices[1] = new PointF(centerX + arrowHalfWidth, bottom.Top + innerOffset);
                                    vertices[2] = new PointF(centerX, bottom.Bottom - innerOffset);

                                    if (bottom.Contains(graphMousePos)) {
                                        _dragAttachMode = NodeAttachMode.Bottom;
                                        e.Graphics.FillPolygon(Brushes.White, vertices);

                                    } else {
                                        e.Graphics.FillPolygon(Brushes.Black, vertices);
                                    }
                                }

                                break;
                        }
                    }
                }
            }

            if (_movedSubItem != null) {
                NodeViewData.SubItemText subitem = _movedSubItem as NodeViewData.SubItemText;

                if (subitem != null) {
                    RectangleF boundingBox = new RectangleF(graphMousePos, new SizeF(50, 12));
                    e.Graphics.FillRectangle(subitem.BackgroundBrush, boundingBox);
                }
            }

            // draw FSM related
            DrawFSMArrow(e, graphMousePos);
            DrawFSMDragCurve(e, graphMousePos);

            //the first time of paint, to collapse plan failed branch by default
            Behavior b = this.RootNode as Behavior;

            if (b.PlanIsCollapseFailedBranch > 0) {
                if (b.PlanIsCollapseFailedBranch == Behavior.kPlanIsCollapseFailedBranch) {
                    NodeViewData root = (NodeViewData)this.RootNodeView.Children[0];
                    CollapseFailedBrach(root);
                }

                b.PlanIsCollapseFailedBranch--;

                this.CenterNode(this._rootNodeView);
                this.LayoutChanged();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Handles when a tree node is dragged on the view.
        /// </summary>
        private void BehaviorTreeView_DragOver(object sender, DragEventArgs e) {
            // get the node we are dragging over
            Point pt = PointToClient(new Point(e.X, e.Y));
            NodeViewData nodeFound = _rootNodeView.GetInsideNode(new PointF(pt.X, pt.Y));

            // update last know mouse position
            _lastMousePosition = new PointF(pt.X, pt.Y);

            // update the current node
            if (nodeFound != _currentNode) {
                _currentNode = nodeFound;
                Invalidate();
            }

            // when we are moving on a node we must keep drawing as the ttach ode might change but not the node
            else if (nodeFound != null) {
                Invalidate();
            }

            // store the target node
            _dragTargetNode = _currentNode;

            // deny drop by default
            e.Effect = DragDropEffects.None;

            // process dragging the property and method string value from the Meta Browser
            string dragItem = (string)e.Data.GetData(DataFormats.Text);

            if (!string.IsNullOrEmpty(dragItem) &&
                _dragTargetNode != null && _dragTargetNode.Node != null &&
                _dragTargetNode.Node.AcceptDefaultPropertyByDragAndDrop()) {
                e.Effect = DragDropEffects.Move;

                _dragAttachMode = NodeAttachMode.None;

                return;
            }

            // make sure the correct drag attach mode is set
            if (_dragTargetNode != null) {
                if (_dragNodeDefaults is Nodes.Node && _dragAttachMode == NodeAttachMode.Attachment) {
                    _dragAttachMode = NodeAttachMode.None;

                } else if (_dragNodeDefaults is Attachments.Attachment && _dragAttachMode != NodeAttachMode.Attachment) {
                    _dragAttachMode = NodeAttachMode.Attachment;
                }
            }

            // check if we are trying to drop a node on another one
            if (_dragTargetNode != null && (e.KeyState & 1/*left mouse button*/) > 0) {
                if (_dragNodeDefaults != null &&
                    (_dragNodeDefaults is Nodes.Node && (_dragAttachMode != NodeAttachMode.None || !(_dragNodeDefaults is Nodes.BehaviorNode) || !(_dragTargetNode.Node is Nodes.BehaviorNode)) ||
                     _dragNodeDefaults is Attachments.Attachment && _dragTargetNode.Node.AcceptsAttachment(_dragNodeDefaults))) {
                    e.Effect = DragDropEffects.Move;
                }
            }

            // If this is an empty node, no effect for it.
            if (_dragTargetNode == null || _dragTargetNode.Node == null || _dragNodeDefaults == null ||
                _dragAttachMode == NodeAttachMode.None && !_dragTargetNode.Node.AcceptsAttachment(_dragNodeDefaults))
            {
                e.Effect = DragDropEffects.None;
            }

            if (_rootNodeView.IsFSM || _rootNodeView.Children.Count == 0) { // fsm or empty behavior
                if (_dragNodeDefaults != null) {
                    if (_dragNodeDefaults is Node) {
                        Node dragNode = _dragNodeDefaults as Node;

                        if (dragNode.IsFSM || dragNode is Behavior) {
                            if (_dragTargetNode == null) {
                                e.Effect = DragDropEffects.Move;
                            }
                            //else if (_dragNodeDefaults is Nodes.BehaviorNode) {
                            //    e.Effect = DragDropEffects.None;
                            //}
                        }

                    } else if (_dragNodeDefaults is Attachments.Attachment) {
                        Attachments.Attachment dragAttachment = _dragNodeDefaults as Attachments.Attachment;

                        if (dragAttachment.IsFSM) {
                            if (_dragTargetNode != null && !(_dragTargetNode.Node is Nodes.BehaviorNode) &&
                                _dragTargetNode.Node.AcceptsAttachment(dragAttachment)) {
                                e.Effect = DragDropEffects.Move;
                            }

                            else {
                                e.Effect = DragDropEffects.None;
                            }
                        }
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Handles when dropping a tree node on the view.
        /// </summary>
        private void BehaviorTreeView_DragDrop(object sender, DragEventArgs e) {
            // make sure the view is focused
            Focus();

            // drag the property or method into the node
            string dragItem = (string)e.Data.GetData(DataFormats.Text);

            if (!string.IsNullOrEmpty(dragItem) && _dragTargetNode != null && _dragTargetNode.Node != null) {
                if (_dragTargetNode.Node.SetDefaultPropertyByDragAndDrop(dragItem)) {
                    if (ClickNode != null) {
                        ClickNode(_dragTargetNode);
                    }

                    UndoManager.Save(this.RootNode);

                    LayoutChanged();
                }

                return;
            }

            // get source node
            TreeNode sourceNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");

            if (sourceNode == null) {
                return;
            }

            NodeTag sourceNodeTag = (NodeTag)sourceNode.Tag;

            // keep the current node position
            //KeepNodePosition(_dragTargetNode);

            bool bDragBTOverNode = !((Node)this.RootNode).IsFSM && sourceNodeTag.Type == NodeTagType.Behavior && _dragTargetNode is Behaviac.Design.NodeViewData;

            // check if we are dropping an attach
            // or if we are dropping a bt to a node and the indicator is not left/right/up/bottom/center
            if (_dragAttachMode == NodeAttachMode.Attachment ||
                (bDragBTOverNode && (_dragAttachMode == NodeAttachMode.None || _dragAttachMode == NodeAttachMode.Attachment))) {
                Attachments.Attachment attach = null;

                // when we attach a behaviour we must create a special referenced behaviour node
                if (bDragBTOverNode) {
                    //drag an event(a bt) to a node
                    if (!File.Exists(sourceNodeTag.Filename))
                    {
                        MainWindow.Instance.SaveBehavior(sourceNodeTag.Defaults as Nodes.BehaviorNode, false);
                    }

                    if (File.Exists(sourceNodeTag.Filename)) {
                        // get the behavior we want to reference
                        BehaviorNode behavior = _behaviorTreeList.LoadBehavior(sourceNodeTag.Filename);
                        Behavior rootB = _rootNodeView.RootBehavior as Behavior;
                        Behavior b = behavior as Behavior;

                        if (!b.CanBeAttached || !IsCompatibleAgentType(rootB, b))
                            return;

                        attach = Behaviac.Design.Attachments.Attachment.Create(typeof(Behaviac.Design.Attachments.Event), _dragTargetNode.Node);
                        Behaviac.Design.Attachments.Event evt = (Behaviac.Design.Attachments.Event)attach;
                        evt.ReferencedBehavior = behavior;
                    }

                } else if (_dragTargetNode != null) {
                    Debug.Check(_dragAttachMode == NodeAttachMode.Attachment);

                    // add the attach to the target node
                    attach = Behaviac.Design.Attachments.Attachment.Create(sourceNodeTag.NodeType, _dragTargetNode.Node);
                }

                if (_dragTargetNode != null && attach != null && _dragTargetNode.Node.AcceptsAttachment(attach))
                {
                    attach.OnPropertyValueChanged(false);

                    attach.ResetId();
                    _dragTargetNode.Node.AddAttachment(attach);

                    NodeViewData.SubItemAttachment sub = attach.CreateSubItem();
                    _dragTargetNode.AddSubItem(sub);

                    SelectedNode = _dragTargetNode;
                    SelectedNode.SelectedSubItem = sub;

                    // call the ClickEvent event handler
                    if (ClickEvent != null) {
                        ClickEvent(SelectedNode);
                    }

                    UndoManager.Save(this.RootNode);

                    LayoutChanged();
                }
            }

            //else if (_dragAttachMode != NodeAttachMode.None)
            else {
                // attach a new node to the target node
                InsertNewNode(_dragTargetNode, _dragAttachMode, sourceNodeTag, this.PointToClient(new Point(e.X, e.Y)));
            }

            // reset drag stuff
            _dragTargetNode = null;
            _dragNodeDefaults = null;
            _dragAttachMode = NodeAttachMode.None;

            Invalidate();
        }
Beispiel #5
0
        /// <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.Attachment || mode == NodeAttachMode.None)
                throw new Exception("A node cannot be created with the given attach mode");

            if (nodetag.Type != NodeTagType.Behavior && nodetag.Type != NodeTagType.Prefab && nodetag.Type != NodeTagType.Node)
                throw new Exception("Only behaviours, prefabs and nodes can be attached to a behaviour tree");

            Node node = nvd.Node;
            Node newnode = null;
            bool isPrefabInstance = false;

            // when we attach a behaviour we must create a special referenced behaviour node
            if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab)
            {
                if (!File.Exists(nodetag.Filename))
                {
                    if (!SaveBehavior(nodetag.Filename))
                        return;
                }

                // get the behavior we want to reference
                BehaviorNode behavior = _behaviorTreeList.LoadBehavior(nodetag.Filename);

                // a behaviour reference itself
                if (nvd.IsBehaviorReferenced(behavior))
                {
                    if (DialogResult.Cancel == MessageBox.Show(Resources.CircularReferencedInfo, Resources.Warning, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning))
                        return;
                }

                if (nodetag.Type == NodeTagType.Prefab)
                {
                    behavior = (BehaviorNode)behavior.Clone();
                }

                Behavior rootB = _rootNode.RootBehavior as Behavior;
                Behavior b = behavior as Behavior;

                if (rootB.AgentType == null)
                {
                    rootB.AgentType = b.AgentType;
                }
                else if (!IsCompatibleAgentType(rootB, b))
                {
                    return;
                }

                // behavior
                if (nodetag.Type == NodeTagType.Behavior)
                {
                    // create the referenced behaviour node for the behaviour
                    ReferencedBehaviorNode refnode = Node.CreateReferencedBehaviorNode(_rootNode.RootBehavior, behavior);

                    // register the view so it gets updated when the referenced behaviour gets updated.
                    refnode.ReferencedBehaviorWasModified += new ReferencedBehavior.ReferencedBehaviorWasModifiedEventDelegate(refnode_ReferencedBehaviorWasModified);

                    newnode = (Node)refnode;
                    newnode.CommentText = Resources.ThisIsReferenceTree;
                    newnode.CommentBackground = Node.CommentColor.Gray;
                }
                // prefab
                else
                {
                    // Copy all Pars from the prefab file into the current behavior node.
                    List<ParInfo> pars = new List<ParInfo>();
                    foreach (ParInfo par in b.Pars)
                    {
                        bool found = false;
                        foreach (ParInfo rootPar in rootB.Pars)
                        {
                            if (par.Name == rootPar.Name)
                            {
                                if (par.Type != rootPar.Type)
                                {
                                    string errorMsg = string.Format(Resources.ParErrorInfo, par.Name, b.Label, rootB.Label);
                                    MessageBox.Show(errorMsg, Resources.LoadError, MessageBoxButtons.OK);
                                    return;
                                }

                                found = true;
                                break;
                            }
                        }

                        if (!found)
                            pars.Add(par);
                    }

                    rootB.Pars.AddRange(pars);
                    if (ParSettingsDock.IsVisible())
                        ParSettingsDock.Inspect((Node)_rootNode.RootBehavior);

                    // The first child should be the root node of the prefab tree.
                    Node behaviorNode = (Node)behavior;
                    if (behaviorNode.Children.Count > 0)
                    {
                        newnode = (Node)behaviorNode.Children[0];

                        string prefab = Path.GetFileNameWithoutExtension(behavior.Filename);
                        newnode.CommentText = string.Format("Prefab[{0}]", prefab);

                        isPrefabInstance = true;
                        string prefabName = FileManagers.FileManager.GetRelativePath(behavior.Filename);
                        newnode.SetPrefab(prefabName);
                    }
                }
            }
            else
            {
                // simply create the node which is supposed to be created.
                newnode = Node.Create(nodetag.NodeType);
            }

            if (newnode == null)
                return;

            // 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)node.Parent;

                    int k = node.ParentConnector.GetChildIndex(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)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)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, m + 1);

                    // automatically select the new node
                    _selectedNodePending = newnode;
                    _selectedNodePendingParent = nvd.Parent;
                    break;

                // the node will replace the target node
                case (NodeAttachMode.Center):
                    if (replaceNode(node, newnode))
                    {
                        // automatically select the new node
                        _selectedNodePending = newnode;
                        _selectedNodePendingParent = nvd.Parent;
                    }
                    break;
            }

            // After being created, its Id should be reset.
            if (newnode != null)
            {
                newnode.ResetId(isPrefabInstance);

                // set the prefab dirty for the current parent
                if (newnode.Parent != null)
                {
                    Node parent = (Node)newnode.Parent;
                    if (!string.IsNullOrEmpty(parent.PrefabName))
                    {
                        parent.HasOwnPrefabData = true;
                        if (!isPrefabInstance)
                        {
                            newnode.SetPrefab(parent.PrefabName);
                            newnode.HasOwnPrefabData = true;
                        }
                    }
                }

                if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab)
                    ExpandedNodePool.SetExpandedNode(newnode.Behavior.RelativePath, newnode.Id.ToString(), false);

                UndoManager.Save(this.RootNode, newnode.Behavior);
            }

            // the layout needs to be recalculated
            LayoutChanged();
        }
Beispiel #6
0
        /// <summary>
        /// Handles when a mouse button is let go of.
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            _movedSubItem = null;

            // check if we were dragging a transition for the FSM.
            if (e.Button == MouseButtons.Left && _currentNode != null && ((_objectDragType == ObjectDragTypes.kNode) && _currentNode.IsFSM || _fsmSubItem != null && _fsmDragMode != FSMDragModes.kNone)) {
                if (Plugin.EditMode == EditModes.Design && _startMousePosition != e.Location) {
                    // drag and move the fsm node
                    if ((_objectDragType == ObjectDragTypes.kNode) && _currentNode.IsFSM) {
                        UndoManager.Save(this.RootNode);

                        LayoutChanged();
                    }

                    // drag and connector the target node
                    else {
                        NodeViewData targetNvd = _rootNodeView.GetInsideNode(e.Location);

                        if (targetNvd != null && targetNvd.IsFSM && (targetNvd.Parent != null) && _fsmSubItem is NodeViewData.SubItemAttachment) {
                            NodeViewData.SubItemAttachment subItemAttachment = _fsmSubItem as NodeViewData.SubItemAttachment;

                            if (subItemAttachment.Attachment != null && subItemAttachment.Attachment.TargetFSMNodeId != targetNvd.Node.Id) {
                                subItemAttachment.Attachment.TargetFSMNodeId = targetNvd.Node.Id;

                                UndoManager.Save(this.RootNode);

                                LayoutChanged();
                            }
                        }
                    }
                }
            }

            // check if we were dragging an existing sub item.
            else if (e.Button == MouseButtons.Left && _currentNode != null && _dragTargetNode != null && _dragAttachment != null) {
                NodeViewData.SubItem targetSubItem = _dragTargetNode.GetSubItem(_dragTargetNode, _nodeLayoutManager.ViewToGraph(e.Location));

                if (KeyCtrlIsDown || targetSubItem != _dragAttachment) {
                    NodeViewData.SubItemAttachment targetAttachment = targetSubItem as NodeViewData.SubItemAttachment;

                    if ((_currentNode != _dragTargetNode || targetAttachment != null) &&
                        this.MoveSubItem(_currentNode, _dragTargetNode, _dragAttachment, targetAttachment, _dragAttachMode == NodeAttachMode.Top, KeyCtrlIsDown)) {
                        _currentNode.ClickEvent(_currentNode, _nodeLayoutManager.ViewToGraph(e.Location));

                        LayoutChanged();
                    }
                }

                _dragAttachment = null;
                _dragTargetAttachment = null;
                _dragAttachMode = NodeAttachMode.None;
            }

            // check if we were dragging or copying an existing node.
            else if (e.Button == MouseButtons.Left && (_movedNode != null || _copiedNode != null || _clipboardPasteMode)) {
                // if we have a valid target node continue
                if (_dragTargetNode != null) {
                    Node sourceNode = null;

                    if (_copiedNode != null) {
                        bool cloneBranch = !(_copiedNode is ReferencedBehavior);
                        sourceNode = (KeyShiftIsDown && cloneBranch) ? (Nodes.Node)_copiedNode.CloneBranch() : (Nodes.Node)_copiedNode.Clone();

                    } else if (_clipboardPasteMode) {
                        bool cloneBranch = !(_clipboardNode is ReferencedBehavior);
                        sourceNode = (/*KeyShiftIsDown && */cloneBranch) ? (Nodes.Node)_clipboardNode.CloneBranch() : (Nodes.Node)_clipboardNode.Clone();

                    } else if (_movedNode != null) {
                        sourceNode = _movedNode;
                    }

                    Debug.Check(sourceNode != null);
                    Node sourceParent = (Node)sourceNode.Parent;
                    BehaviorNode sourceBehavior = sourceNode.Behavior;

                    if (_dragTargetNode.Node == sourceNode) {
                        _dragAttachMode = NodeAttachMode.None;
                    }

                    if (_dragAttachMode == NodeAttachMode.Top ||
                        _dragAttachMode == NodeAttachMode.Bottom ||
                        _dragAttachMode == NodeAttachMode.Left ||
                        _dragAttachMode == NodeAttachMode.Right ||
                        _dragAttachMode == NodeAttachMode.Center) {
                        // set the prefab dirty for its previous parent
                        if (sourceParent != null && !string.IsNullOrEmpty(sourceParent.PrefabName)) {
                            sourceParent.HasOwnPrefabData = true;
                        }

                        if (KeyShiftIsDown) {
                            if (sourceParent != null) {
                                sourceParent.RemoveChild(sourceNode.ParentConnector, sourceNode);
                            }

                        } else {
                            sourceNode.ExtractNode();
                        }
                    }

                    // move the dragged node to the target node, according to the attach mode
                    switch (_dragAttachMode) {
                            // the node will be placed above the target node
                        case (NodeAttachMode.Top):
                            int n = _dragTargetNode.Node.ParentConnector.GetChildIndex(_dragTargetNode.Node);
                            ((Node)_dragTargetNode.Node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, sourceNode, n);

                            _selectedNodePending = sourceNode;
                            _selectedNodePendingParent = _dragTargetNode.Parent;

                            LayoutChanged();
                            break;

                            // the node will be placed below the target node
                        case (NodeAttachMode.Bottom):
                            int m = _dragTargetNode.Node.ParentConnector.GetChildIndex(_dragTargetNode.Node);
                            ((Node)_dragTargetNode.Node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, sourceNode, m + 1);

                            _selectedNodePending = sourceNode;
                            _selectedNodePendingParent = _dragTargetNode.Parent;

                            LayoutChanged();
                            break;

                            // the node will be placed in front of the target node
                        case (NodeAttachMode.Left):
                            Node parent = (Node)_dragTargetNode.Node.Parent;
                            Node.Connector conn = _dragTargetNode.Node.ParentConnector;

                            int o = conn.GetChildIndex(_dragTargetNode.Node);

                            parent.RemoveChild(conn, _dragTargetNode.Node);
                            parent.AddChild(conn, sourceNode, o);

                            BaseNode.Connector sourceConn = sourceNode.GetConnector(conn.Identifier);
                            Debug.Check(sourceConn != null);

                            sourceNode.AddChild(sourceConn, _dragTargetNode.Node);

                            _selectedNodePending = sourceNode;
                            _selectedNodePendingParent = _dragTargetNode.Parent;

                            LayoutChanged();
                            break;

                            // the node will simply attached to the target node
                        case (NodeAttachMode.Right):
                            _dragTargetNode.Node.AddChild(_dragTargetConnector, sourceNode);

                            _selectedNodePending = sourceNode;
                            _selectedNodePendingParent = _dragTargetNode;

                            LayoutChanged();
                            break;

                            // the node will replace the target node
                        case (NodeAttachMode.Center):
                            if (replaceNode(_dragTargetNode.Node, sourceNode)) {
                                LayoutChanged();
                            }

                            break;
                    }

                    if (_dragAttachMode != NodeAttachMode.None) {
                        // If cloning a node, its Id should be reset.
                        if (_copiedNode != null || _clipboardPasteMode) {
                            // Cross two different behavior files
                            if (_clipboardPasteMode && _clipboardRootNode != this.RootNodeView) {
                                try {
                                    // Copy the used Pars from the current behavior to the new one.
                                    if (_clipboardNode != null && _clipboardRootNode != null && _clipboardRootNode.Node is Behavior) {
                                        foreach(ParInfo par in((Behavior)(_clipboardRootNode.Node)).LocalVars) {
                                            List<Node.ErrorCheck> result = new List<Node.ErrorCheck>();
                                            Plugin.CheckPar(_clipboardNode, par, ref result);

                                            if (result.Count > 0) {
                                                bool bExist = false;
                                                foreach(ParInfo p in((Behavior)this.RootNode).LocalVars) {
                                                    if (p.Name == par.Name) {
                                                        bExist = true;
                                                        break;
                                                    }
                                                }

                                                if (!bExist) {
                                                    ((Behavior)this.RootNode).LocalVars.Add(par);
                                                }
                                            }
                                        }
                                    }

                                    // reset its properties and methods
                                    sourceNode.ResetMembers(false, this.RootNode.AgentType, true);

                                } catch {
                                }
                            }

                            // reset its Id
                            sourceNode.ResetId(true);
                        }

                        // update the node's label
                        sourceNode.OnPropertyValueChanged(false);

                        // set the prefab dirty for its current parent
                        if (sourceNode.Parent != null) {
                            Node parent = (Node)sourceNode.Parent;

                            if (!string.IsNullOrEmpty(parent.PrefabName)) {
                                parent.HasOwnPrefabData = true;
                                sourceNode.SetPrefab(parent.PrefabName, true);
                            }
                        }

                        UndoManager.Save(this.RootNode);
                    }
                }

                // reset all the drag data
                if (!_clipboardPasteMode) {
                    _copiedNode = null;
                    _movedNode = null;
                    _dragTargetNode = null;
                    _dragNodeDefaults = null;
                    _movedNodeGraph = null;
                }

                // redraw the graph
                Invalidate();
            }

            // popup the menu for the current hit node
            else if (e.Button == MouseButtons.Right && !KeyAltIsDown && !KeyCtrlIsDown && !KeyShiftIsDown) {
                bool itemEnabled = (SelectedNode != null && SelectedNode.Node.Parent != null);
                itemEnabled &= (Plugin.EditMode == EditModes.Design);

                deleteMenuItem.ShortcutKeys = Keys.Delete;
                deleteTreeMenuItem.ShortcutKeys = Keys.Shift | Keys.Delete;

                cutMenuItem.Enabled = SelectedNodeCanBeCut();
                cutTreeMenuItem.Enabled = (SelectedNode != null) && !SelectedNode.IsFSM && SelectedTreeCanBeCut();
                copyMenuItem.Enabled = itemEnabled;
                copySubtreeMenuItem.Enabled = (SelectedNode != null) && !SelectedNode.IsFSM;
                pasteMenuItem.Enabled = SelectedNodeCanBePasted();
                deleteMenuItem.Enabled = SelectedNodeCanBeDeleted();
                deleteTreeMenuItem.Enabled = (SelectedNode != null) && !SelectedNode.IsFSM && SelectedTreeCanBeDeleted();

                bool isReferencedBehavior = SelectedNode != null && SelectedNode.Node is ReferencedBehavior;
                bool isEvent = SelectedNode != null && SelectedNode.SelectedSubItem != null && SelectedNode.SelectedSubItem.SelectableObject is Attachments.Event;
                referenceMenuItem.Enabled = itemEnabled || isReferencedBehavior || isEvent;
                referenceMenuItem.Text = (isReferencedBehavior || isEvent) ? Resources.OpenReference : Resources.SaveReference;

                disableMenuItem.Enabled = false;
                if (itemEnabled)
                {
                    if (SelectedNode.SelectedSubItem != null && SelectedNode.SelectedSubItem.SelectableObject is Attachments.Attachment)
                    {
                        Attachments.Attachment attach = SelectedNode.SelectedSubItem.SelectableObject as Attachments.Attachment;
                        disableMenuItem.Enabled = attach.CanBeDisabled();
                        disableMenuItem.Text = attach.Enable ? Resources.DisableNode : Resources.EnableNode;
                    }
                    else
                    {
                        disableMenuItem.Enabled = SelectedNode.Node.CanBeDisabled();
                        disableMenuItem.Text = SelectedNode.Node.Enable ? Resources.DisableNode : Resources.EnableNode;
                    }
                }

                expandMenuItem.Enabled = (SelectedNode != null && SelectedNode.CanBeExpanded());
                collapseMenuItem.Enabled = expandMenuItem.Enabled;
                expandAllMenuItem.Enabled = expandMenuItem.Enabled;
                collapseAllMenuItem.Enabled = expandMenuItem.Enabled;

                bool isPrefabInstance = SelectedNode != null && !string.IsNullOrEmpty(SelectedNode.Node.PrefabName);
                breakPrefabMenuItem.Enabled = itemEnabled && isPrefabInstance;

                if (isPrefabInstance) {
                    string fullpath = FileManagers.FileManager.GetFullPath(SelectedNode.Node.PrefabName);
                    isPrefabInstance = File.Exists(fullpath);
                }

                savePrefabMenuItem.Enabled = itemEnabled;
                savePrefabMenuItem.Text = isPrefabInstance ? Resources.OpenPrefab : Resources.SavePrefab;

                if (SelectedNode != null) {
                    Node prefabRoot = SelectedNode.Node.GetPrefabRoot();
                    string relativeFilename = FileManagers.FileManager.GetRelativePath(this.RootNode.Filename);
                    applyMenuItem.Enabled = itemEnabled && isPrefabInstance && SelectedNode.Node.PrefabName != relativeFilename && prefabRoot.IsPrefabDataDirty();
                }

                breakpointMenuItem.Enabled = SelectedNode != null && SelectedNode.Parent != null;

                if (SelectedNode != null) {
                    enterBreakpointMenuItem.Text = SelectedNode.GetBreakpointOperation(HighlightBreakPoint.kEnter);
                    exitBreakpointMenuItem.Text = SelectedNode.GetBreakpointOperation(HighlightBreakPoint.kExit);

                    this.beakpointPlanning.Visible = false;

                    if (SelectedNode.Node is Task) {
                        this.beakpointPlanning.Visible = true;
                        beakpointPlanning.Text = SelectedNode.GetBreakpointOperation(HighlightBreakPoint.kPlanning);
                    }
                }

                contextMenu.Show(this, new Point(e.X, e.Y));
            }

            Cursor = Cursors.Default;
            _fsmDragMode = FSMDragModes.kNone;

            // redraw the graph
            Invalidate();

            base.OnMouseUp(e);
        }
Beispiel #7
0
        /// <summary>
        /// Handles when a tree node is dragged on the view.
        /// </summary>
        private void BehaviorTreeView_DragOver(object sender, DragEventArgs e)
        {
            // get the node we are dragging over
            Point pt = PointToClient(new Point(e.X, e.Y));
            NodeViewData nodeFound = _rootNode.IsInside(new PointF(pt.X, pt.Y));

            // update the current node
            if (nodeFound != _currentNode)
            {
                _currentNode = nodeFound;
                Invalidate();
            }
            // when we are moving on a node we must keep drawing as the ttach ode might change but not the node
            else if (nodeFound != null)
            {
                Invalidate();
            }

            // store the target node
            _dragTargetNode = _currentNode;

            // deny drop by default
            e.Effect = DragDropEffects.None;

            // make sure the correct drag attach mode is set
            if (_dragTargetNode != null)
            {
                if (_dragNodeDefaults is Nodes.Node && _dragAttachMode == NodeAttachMode.Attachment)
                {
                    _dragAttachMode = NodeAttachMode.None;
                }
                else if (_dragNodeDefaults is Attachments.Attachment && _dragAttachMode != NodeAttachMode.Attachment)
                {
                    _dragAttachMode = NodeAttachMode.Attachment;
                }
            }

            // check if we are trying to drop a node on another one
            if (_dragTargetNode != null && (e.KeyState & 1/*left mouse button*/) > 0 && _dragNodeDefaults is Nodes.Node)
            {
                e.Effect = DragDropEffects.Move;
            }
            // check if we are trying attach an attachement to a node
            else if (_dragTargetNode != null && (e.KeyState & 1/*left mouse button*/) > 0 && _dragNodeDefaults is Attachments.Attachment && _dragTargetNode.Node.AcceptsAttachment(_dragNodeDefaults.GetType()))
            {
                e.Effect = DragDropEffects.Move;
            }

            // If this is an empty node, no effect for it.
            if (_dragTargetNode == null || _dragTargetNode.Node == null)
                e.Effect = DragDropEffects.None;

            // update last know mouse position
            _lastMousePosition = new PointF(pt.X, pt.Y);
        }
Beispiel #8
0
        /// <summary>
        /// Handles when dropping a tree node on the view.
        /// </summary>
        private void BehaviorTreeView_DragDrop(object sender, DragEventArgs e)
        {
            //make sure the view is focused
            Focus();

            // get source node
            TreeNode sourceNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
            NodeTag sourceNodeTag = (NodeTag)sourceNode.Tag;

            // keep the current node position
            KeepNodePosition(_dragTargetNode);

            bool bDragBTOverNode = sourceNodeTag.Type == NodeTagType.Behavior && _dragTargetNode is Behaviac.Design.NodeViewData;

            // check if we are dropping an attach
            // or if we are dropping a bt to a node and the indicator is not left/right/up/bottom/center
            if (_dragAttachMode == NodeAttachMode.Attachment ||
                (bDragBTOverNode && (_dragAttachMode == NodeAttachMode.None || _dragAttachMode == NodeAttachMode.Attachment)))
            {
                Attachments.Attachment attach = null;

                // when we attach a behaviour we must create a special referenced behaviour node
                if (bDragBTOverNode)
                {
                    //drag an event(a bt) to a node
                    if (File.Exists(sourceNodeTag.Filename))
                    {
                        // get the behavior we want to reference
                        BehaviorNode behavior = _behaviorTreeList.LoadBehavior(sourceNodeTag.Filename);
                        Behavior rootB = _rootNode.RootBehavior as Behavior;
                        Behavior b = behavior as Behavior;

                        if (!IsCompatibleAgentType(rootB, b))
                        {
                            return;
                        }

                        attach = Behaviac.Design.Attachments.Attachment.Create(typeof(Behaviac.Design.Attachments.Event), _dragTargetNode.Node);
                        Behaviac.Design.Attachments.Event evt = (Behaviac.Design.Attachments.Event)attach;
                        evt.ReferencedBehavior = behavior;
                    }
                }
                else
                {
                    Debug.Check(_dragAttachMode == NodeAttachMode.Attachment);

                    // add the attach to the target node
                    attach = Behaviac.Design.Attachments.Attachment.Create(sourceNodeTag.NodeType, _dragTargetNode.Node);
                }

                attach.OnPropertyValueChanged(false);

                _dragTargetNode.Node.AddAttachment(attach);

                NodeViewData.SubItemAttachment sub = attach.CreateSubItem();

                _dragTargetNode.AddSubItem(sub);
                _dragTargetNode.Node.BehaviorWasModified();

                SelectedNode = _dragTargetNode;
                SelectedNode.SelectedSubItem = sub;

                // call the ClickEvent event handler
                if (ClickEvent != null)
                    ClickEvent(SelectedNode);

                // After being created, its Id should be reset.
                attach.ResetId();

                UndoManager.Save(this.RootNode, _dragTargetNode.Node.Behavior);

                LayoutChanged();
            }
            else if (_dragAttachMode != NodeAttachMode.None)
            {
                // attach a new node to the target node
                InsertNewNode(_dragTargetNode, _dragAttachMode, sourceNodeTag);
            }

            // reset drag stuff
            _dragTargetNode = null;
            _dragNodeDefaults = null;
            _dragAttachMode = NodeAttachMode.None;

            Invalidate();
        }
		/// <summary>
		/// Handles the drawing and updating of the graph.
		/// </summary>
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);

			// calculate the mouse position in the graph
			PointF graphMousePos= _nodeLayoutManager.ViewToGraph(_lastMousePosition);

			// when the layout was changed it needs to be recalculated
			bool layoutChanged= _nodeLayoutManager.LayoutChanged;
			if(layoutChanged)
				_nodeLayoutManager.UpdateLayout(e.Graphics);

			// centre the root behaviour if requested
			if(_pendingCentreBehavior)
			{
				_pendingCentreBehavior= false;

				CenterNode(_rootNode);
			}

			// select the pending node
			if(_selectedNodePending !=null)
			{
				SelectedNode= _selectedNodePendingParent.GetChild(_selectedNodePending);

				_selectedNodePending= null;
				_selectedNodePendingParent= null;

				if(ClickNode !=null)
					ClickNode(_selectedNode);
			}

			// check if we must keep the original position of the mouse
			if(_maintainMousePosition)
			{
				_maintainMousePosition= false;

				// move the graph so that _graphOrigin is at the same position in the view as it was before
				float mouseX= (graphMousePos.X - _graphOrigin.X) * _nodeLayoutManager.Scale + _nodeLayoutManager.Offset.X;
				float mouseY= (graphMousePos.Y - _graphOrigin.Y) * _nodeLayoutManager.Scale + _nodeLayoutManager.Offset.Y;
				_nodeLayoutManager.Offset= new PointF(mouseX, mouseY);
			}
			// check if we must keep the original position of _maintainNodePosition
			else if(_maintainNodePosition !=null)
			{
				// move the graph so that _graphOrigin is at the same position in the view as it was before
				RectangleF bbox= _maintainNodePosition.BoundingBox;

				PointF viewpos= new PointF(bbox.Location.X * _nodeLayoutManager.Scale, bbox.Location.Y * _nodeLayoutManager.Scale);

				_nodeLayoutManager.Offset= new PointF(_graphOrigin.X - viewpos.X, _graphOrigin.Y - viewpos.Y);
			}

			// reset the node whose position we want to keep
			_maintainNodePosition= null;

			// draw the graph to the view
			_nodeLayoutManager.DrawGraph(e.Graphics, _currentNode, _selectedNode, graphMousePos);

			// check if we are currently dragging a node and we must draw additional data
			if(_dragTargetNode !=null && _dragTargetNode.Node !=_movedNode)
			{
				if(_dragAttachMode == NodeAttachMode.Event)
				{
					// we could draw some stuff for events here
				}
				else
				{
					// draw the arrows for the attach modes

					// get the bounding box of the node
					RectangleF bbox= _dragTargetNode.BoundingBox;

					// get the bounding box of the connector
					_dragTargetConnector= null;

					// the depth of the area for the mouse
					const float offset= 20.0f;

					// the distance of the arrow from the border and its height
					const float innerOffset= 6.0f;

					// the horizintal middle of the node
					float centerX= bbox.Left + bbox.Width *0.5f;

					// the half width of the arrow depending of the node's height
					float arrowHalfWidth= (bbox.Height - innerOffset - innerOffset) *0.5f;

					// calculate the mouse areas for the different attach modes
					RectangleF top= new RectangleF(bbox.X + offset, bbox.Top, bbox.Width - offset - offset, offset);
					RectangleF bottom= new RectangleF(bbox.X + offset, bbox.Bottom - offset, bbox.Width - offset - offset, offset);
					RectangleF left= new RectangleF(bbox.X, bbox.Y, offset, bbox.Height);

					// update for dragging in a new node
					BehaviorNode behavior= _dragNodeDefaults as BehaviorNode;
					if(behavior !=null && behavior.FileManager ==null)
						behavior= null;

					bool hasParentBehavior= _dragTargetNode.HasParentBehavior(behavior);
					bool parentHasParentBehavior= _dragTargetNode.Parent !=null && _dragTargetNode.Parent.HasParentBehavior(behavior);

					bool mayTop= _dragTargetNode.Node.Parent !=null && !parentHasParentBehavior && _dragTargetNode.Node.ParentConnector.AcceptsChildren(1);

					bool mayBottom= _dragTargetNode.Node.Parent !=null && !parentHasParentBehavior && _dragTargetNode.Node.ParentConnector.AcceptsChildren(1);

					bool mayLeft= _dragTargetNode.Parent !=null && !parentHasParentBehavior && !hasParentBehavior &&
									!_dragTargetNode.Node.ParentConnector.IsReadOnly &&
									_dragNodeDefaults is Node &&
									((Node)_dragNodeDefaults).CanAdoptNode(_dragTargetNode.Node) &&
									!(_dragNodeDefaults.GetType() is BehaviorNode);

					// update for moving an existing node
					bool dragTargetHasParentMovedNode= false;
					if(_movedNode !=null)
					{
						dragTargetHasParentMovedNode= _keyShiftIsDown && _dragTargetNode.HasParent(_movedNode);

						// a node may not dragged on itself and may not dragged on one of its own children
						if(_dragTargetNode.Node ==_movedNode || dragTargetHasParentMovedNode)
						{
							mayTop= false;
							mayBottom= false;
							mayLeft= false;
						}
						else
						{
							// a dragged node cannot be placed in the same position again
							mayTop= mayTop && _dragTargetNode.Node.PreviousNode !=_movedNode;
							mayBottom= mayBottom && _dragTargetNode.Node.NextNode !=_movedNode;
							mayLeft= mayLeft && _movedNode.CanAdoptChildren(_dragTargetNode.Node) && (!_keyShiftIsDown || _movedNode.Children.Count ==0);
						}
					}
					else if(_copiedNode !=null)
					{
						mayLeft= mayLeft && _copiedNode.CanAdoptChildren(_dragTargetNode.Node) && (!_keyShiftIsDown || _copiedNode.Children.Count ==0);
					}

					// reset the attach mode
					_dragAttachMode= NodeAttachMode.None;

					// the vertices needed to draw the arrows
					PointF[] vertices= new PointF[3];

					// draw the top arrow if this action is allowed
					if(mayTop)
					{
						vertices[0]= new PointF(centerX - arrowHalfWidth, top.Bottom - innerOffset);
						vertices[1]= new PointF(centerX, top.Top + innerOffset);
						vertices[2]= new PointF(centerX + arrowHalfWidth, top.Bottom - innerOffset);
						if(top.Contains(graphMousePos))
						{
							_dragAttachMode= NodeAttachMode.Top;
							e.Graphics.FillPolygon(Brushes.White, vertices);
						}
						else e.Graphics.FillPolygon(Brushes.Black, vertices);
					}

					// draw the bottom arrow if this action is allowed
					if(mayBottom)
					{
						vertices[0]= new PointF(centerX - arrowHalfWidth, bottom.Top + innerOffset);
						vertices[1]= new PointF(centerX + arrowHalfWidth, bottom.Top + innerOffset);
						vertices[2]= new PointF(centerX, bottom.Bottom - innerOffset);
						if(_dragAttachMode ==NodeAttachMode.None && bottom.Contains(graphMousePos))
						{
							_dragAttachMode= NodeAttachMode.Bottom;
							e.Graphics.FillPolygon(Brushes.White, vertices);
						}
						else e.Graphics.FillPolygon(Brushes.Black, vertices);
					}

					// draw the left arrow if this action is allowed
					if(mayLeft)
					{
						vertices[0]= new PointF(left.Right - innerOffset, left.Top + innerOffset);
						vertices[1]= new PointF(left.Right - innerOffset, left.Bottom - innerOffset);
						vertices[2]= new PointF(left.Left + innerOffset, left.Top + left.Height *0.5f);
						if(_dragAttachMode ==NodeAttachMode.None && left.Contains(graphMousePos))
						{
							_dragAttachMode= NodeAttachMode.Left;
							e.Graphics.FillPolygon(Brushes.White, vertices);
						}
						else e.Graphics.FillPolygon(Brushes.Black, vertices);
					}

					// draw the right arrow if this action is allowed
					foreach(Node.Connector connector in _dragTargetNode.Node.Connectors)
					{
						RectangleF bboxConnector= _dragTargetNode.Node.GetConnectorBoundingBox(bbox, connector);

						//e.Graphics.DrawRectangle(Pens.Red, bboxConnector.X, bboxConnector.Y, bboxConnector.Width, bboxConnector.Height);

						RectangleF right= new RectangleF(bboxConnector.Right - offset, bboxConnector.Y, offset, bboxConnector.Height);

						bool mayRight= !dragTargetHasParentMovedNode && !hasParentBehavior && connector.AcceptsChildren(1);

						if(mayRight && _movedNode !=null && connector ==_movedNode.ParentConnector)
							mayRight= false;

						if(mayRight)
						{
							float inOffset= bboxConnector.Height >innerOffset *4.0f ? innerOffset : 3.0f;

							vertices[0]= new PointF(right.Left + inOffset, right.Top + inOffset);
							vertices[1]= new PointF(right.Right - inOffset, right.Top + right.Height *0.5f);
							vertices[2]= new PointF(right.Left + inOffset, right.Bottom - inOffset);
							if(_dragAttachMode ==NodeAttachMode.None && right.Contains(graphMousePos))
							{
								_dragTargetConnector= connector;
								_dragAttachMode= NodeAttachMode.Right;
								e.Graphics.FillPolygon(Brushes.White, vertices);
							}
							else e.Graphics.FillPolygon(Brushes.Black, vertices);
						}
					}
				}
			}

			// draw last mouse pos
			//e.Graphics.DrawRectangle(Pens.Red, graphMousePos.X -1.0f, graphMousePos.Y -1.0f, 2.0f, 2.0f);

			//when we are dragging an existing node we draw a small graph representing it
			if(_movedNodeGraph !=null)
			{
				// update the layout for the graph. This happens only once inside the function.
				_movedNodeGraph.UpdateLayout(e.Graphics);

				// offset the graph to the mouse position
				_movedNodeGraph.Offset= new PointF(_nodeLayoutManager.Offset.X + graphMousePos.X * _nodeLayoutManager.Scale,
										_nodeLayoutManager.Offset.Y + graphMousePos.Y * _nodeLayoutManager.Scale - _movedNodeGraph.RootNodeLayout.LayoutRectangle.Height *0.5f * _movedNodeGraph.Scale);

				// draw the graph
				_movedNodeGraph.DrawGraph(e.Graphics, null, null, graphMousePos);
			}

			//if(_currentNode !=null && _currentNode.SubItems.Count >0)
			//	Invalidate();
		}
		/// <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();
		}
		/// <summary>
		/// Handles when dropping a tree node on the view.
		/// </summary>
		private void BehaviorTreeView_DragDrop(object sender, DragEventArgs e)
		{
			//make sure the view is focused
			Focus();

			// get source node
			TreeNode sourceNode= (TreeNode) e.Data.GetData("System.Windows.Forms.TreeNode");
			NodeTag sourceNodeTag= (NodeTag)sourceNode.Tag;

			// keep the current node position
			_maintainNodePosition= _dragTargetNode;
			_graphOrigin= _maintainNodePosition.DisplayBoundingBox.Location;

			// check if we are dropping an event
			if(_dragAttachMode ==NodeAttachMode.Event)
			{
				// add the event to the target node
				Events.Event evnt= Brainiac.Design.Events.Event.Create(sourceNodeTag.NodeType, _dragTargetNode.Node);
				evnt.OnPropertyValueChanged(false);
				Nodes.Node.SubItemEvent sub= new Nodes.Node.SubItemEvent(evnt);
				_dragTargetNode.Node.AddSubItem(sub);
				_dragTargetNode.Node.BehaviorWasModified();

				SelectedNode= _dragTargetNode;
				_selectedNode.Node.SelectedSubItem= sub;

				// call the ClickEvent event handler
				if(ClickEvent !=null)
					ClickEvent(_selectedNode);

				LayoutChanged();
			}
			else if(_dragAttachMode !=NodeAttachMode.None)
			{
				// attach a new node to the target node
				InsertNewNode(_dragTargetNode, _dragAttachMode, sourceNodeTag);
			}

			// reset drag stuff
			_dragTargetNode= null;
			_dragNodeDefaults= null;
			_dragAttachMode= NodeAttachMode.None;

			Invalidate();
		}