Exemple #1
0
 public ObjectPair(Nodes.Node root, NodeTag.DefaultObject obj)
 {
     Root = root;
     Obj = obj;
 }
        /// <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 when a tree node is dragged into the view.
        /// </summary>
        private void BehaviorTreeView_DragEnter(object sender, DragEventArgs e)
        {
            TreeNode sourceNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
            if (sourceNode == null)
                return;

            NodeTag sourceNodeTag = sourceNode.Tag as NodeTag;
            if (sourceNodeTag == null)
                return;

            // store the tree node's defaults
            _dragNodeDefaults = sourceNodeTag.Defaults;
        }
        /// <summary>
        /// Handles when the mouse is moved.
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (_lostFocus)
            {
                _lostFocus = false;

                // update the last ouse position
                _lastMousePosition = e.Location;

                base.OnMouseMove(e);

                return;
            }

            // returns the mouse under the mouse cursor
            NodeViewData nodeFound = _rootNode.IsInside(e.Location);

            // clear previously stored node which can cause problems when dragging to another view
            //_dragTargetNode = null;

            // if a different node is the current one, update it
            if (nodeFound != _currentNode || _currentExpandNode != null)
            {
                if (_dragAttachment == null)
                {
                    _currentNode = nodeFound;
                }

                if (nodeFound == null)
                {
                    this.toolTip.Hide(this);
                }
                else if (Settings.Default.ShowNodeToolTips)
                {
                    if (!string.IsNullOrEmpty(nodeFound.ToolTip))
                        this.toolTipTimer.Start();
                }

                Invalidate();
            }

            // check if we are currently dragging the graph
            if ((e.Button == MouseButtons.Middle || e.Button == MouseButtons.Left && IsPanMode) && _lastMousePosition != e.Location && !this.contextMenu.Visible)
            {
                _isGraphDragged = true;

                // move the graph according to the last mouse position
                _nodeLayoutManager.Offset = new PointF(_nodeLayoutManager.Offset.X - (_lastMousePosition.X - e.X), _nodeLayoutManager.Offset.Y - (_lastMousePosition.Y - e.Y));

                Invalidate();
            }
            // check if we start duplicating an existing node step 1
            else if (e.Button == MouseButtons.Left && KeyCtrlIsDown && _lastMousePosition != e.Location && _dragNodeDefaults == null && _copiedNode == null && _currentNode != null && !(_currentNode.Node is BehaviorNode))
            {
                _movedNode = null;
                _copiedNode = _currentNode.Node;

                // create the layout manager used to draw the graph
                _movedNodeGraph = new NodeLayoutManager(_copiedNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenHighlight, _nodeLayoutManager.EdgePenUpdate, _nodeLayoutManager.EdgePenReadOnly, true);
                _movedNodeGraph.Scale = 0.3f;
                _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;

                // use the existing node as the node defaults
                _dragNodeDefaults = _copiedNode;

                Invalidate();
            }
            // check if we are duplicating an existing node step 2
            else if (e.Button == MouseButtons.Left && KeyCtrlIsDown && _copiedNode != null)
            {
                _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;

                _dragTargetNode = _currentNode;

                Cursor = _currentNode == null ? Cursors.No : Cursors.Default;

                //Point movedGraphGraphPos= new Point(e.Location.X + _movedNodeGraph.Offset.X, e.Location.Y + _movedNodeGraph.Offset.Y /-2);
                //_movedNodeGraph.Location= movedGraphGraphPos;

                Invalidate();
            }
            // check if we start dragging an existing node step 1
            else if (e.Button == MouseButtons.Left && _lastMousePosition != e.Location && !KeyCtrlIsDown && _movedNode == null && _currentNode != null && !(_currentNode.Node is BehaviorNode))
            {
                if (_isNodeDragged) // node
                {
                    if (KeyShiftIsDown || _currentNode.Node.ParentCanAdoptChildren)
                    {
                        _movedNode = _currentNode.Node;

                        // create the layout manager used to draw the graph
                        if (_movedNodeGraph == null)
                            _movedNodeGraph = new NodeLayoutManager(_movedNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenHighlight, _nodeLayoutManager.EdgePenUpdate, _nodeLayoutManager.EdgePenReadOnly, true);
                        _movedNodeGraph.Scale = 0.3f;
                        _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;
                    }
                }
                else // attachment
                {
                    _movedNodeGraph = null;

                    if (_dragAttachment == null)
                    {
                        NodeViewData.SubItem subItem = _currentNode.GetSubItem(_currentNode, _nodeLayoutManager.ViewToGraph(e.Location));
                        _dragAttachment = subItem as NodeViewData.SubItemAttachment;
                    }
                    else
                    {
                        NodeViewData.SubItem subItem = _currentNode.GetSubItem(_currentNode, _nodeLayoutManager.ViewToGraph(e.Location));
                        _dragTargetAttachment = subItem as NodeViewData.SubItemAttachment;

                        Invalidate();
                    }
                }
            }
            // check if we start dragging an existing node step 2
            else if (e.Button == MouseButtons.Left && _movedNode != null && !_clipboardPasteMode)
            {
                // create the layout manager used to draw the graph
                if (_movedNodeGraph == null)
                    _movedNodeGraph = new NodeLayoutManager(_movedNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenHighlight, _nodeLayoutManager.EdgePenUpdate, _nodeLayoutManager.EdgePenReadOnly, true);
                _movedNodeGraph.Scale = 0.3f;
                _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;

                _dragNodeDefaults = _movedNode;
                _dragTargetNode = _currentNode;

                Cursor = _currentNode == null ? Cursors.No : Cursors.Default;

                Invalidate();
            }
            else if (e.Button == MouseButtons.Right && IsPanMode && _panStartMousePosition != e.Location)
            {
                int delta = e.X - (int)_panStartMousePosition.X + (int)_panStartMousePosition.Y - e.Y;
                scaleGraph(delta / 16, false);
            }
            else if (_clipboardPasteMode)
            {
                if (_movedNodeGraph != null)
                    _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;

                _dragTargetNode = _currentNode;

                Cursor = _currentNode == null ? Cursors.No : Cursors.Default;

                Invalidate();
            }
            else if (_currentNode != null && _dragAttachment == null)
            {
                // Highlight the expand/collapse flag
                PointF graphMousePos = _nodeLayoutManager.ViewToGraph(e.Location);
                if (_currentNode.IsInExpandRange(graphMousePos))
                {
                    _currentExpandNode = _currentNode;
                    Invalidate();
                }
                else if (_currentExpandNode != null)
                {
                    _currentExpandNode = null;
                    Invalidate();
                }
            }

            // update the last ouse position
            _lastMousePosition = e.Location;

            base.OnMouseMove(e);
        }
        /// <summary>
        /// Handles when a mouse button is let go of.
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            // check if we were dragging an existing sub item.
            if (e.Button == MouseButtons.Left && _currentNode != null && _dragAttachment != null && _dragTargetAttachment != null &&
                (_dragAttachMode == NodeAttachMode.Top || _dragAttachMode == NodeAttachMode.Bottom))
            {
                NodeViewData.SubItem targetSubItem = _currentNode.GetSubItem(_currentNode, _nodeLayoutManager.ViewToGraph(e.Location));
                if (targetSubItem != null && targetSubItem != _dragAttachment)
                {
                    NodeViewData.SubItemAttachment targetAttachment = targetSubItem as NodeViewData.SubItemAttachment;
                    if (targetAttachment != null && this.MoveSubItem(_currentNode, targetAttachment, _dragAttachment, _dragAttachMode == NodeAttachMode.Top))
                    {
                        _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);

                            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);

                            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);

                            LayoutChanged();
                            break;

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

                            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)
                                    {
                                        bool isParAdded = false;
                                        foreach (ParInfo par in (_clipboardRootNode.Node).Pars)
                                        {
                                            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 ((Node)this.RootNode).Pars)
                                                {
                                                    if (p.Name == par.Name)
                                                    {
                                                        bExist = true;
                                                        break;
                                                    }
                                                }
                                                if (!bExist)
                                                {
                                                    isParAdded = true;
                                                    ((Node)this.RootNode).Pars.Add(par);
                                                }
                                            }
                                        }

                                        if (isParAdded)
                                        {
                                            if (ParSettingsDock.IsVisible())
                                            {
                                                ParSettingsDock.Inspect((Node)_rootNode.RootBehavior);

                                                this.Focus();
                                                this.Parent.Focus();
                                            }
                                        }
                                    }

                                    // reset its properties and methods
                                    sourceNode.ResetMembers(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, sourceBehavior, _dragTargetNode.Node.Behavior);
                    }
                }

                // 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 && !IsPanMode && !KeyAltIsDown && !KeyCtrlIsDown && !KeyShiftIsDown && !_isGraphDragged)
            {
                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 = SelectedTreeCanBeCut();
                copyMenuItem.Enabled = itemEnabled;
                deleteMenuItem.Enabled = SelectedNodeCanBeDeleted();
                deleteTreeMenuItem.Enabled = SelectedTreeCanBeDeleted();

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

                disableMenuItem.Enabled = itemEnabled && SelectedNode.Node.CanBeDisabled();
                disableMenuItem.Text = (SelectedNode != null && 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);
                }

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

            Cursor = Cursors.Default;

            base.OnMouseUp(e);
        }
        /// <summary>
        /// Handles when a key is pressed.
        /// </summary>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                // store when the alt key is pressed
                case (Keys.Menu):
                    IsPanMode = true;
                    break;

                // store when the control key is pressed
                case (Keys.ControlKey):
                    if (_copiedNode == null && _movedNode == null)
                    {
                        Cursor = Cursors.Default;
                    }
                    break;

                // store when the shift key is pressed
                case (Keys.ShiftKey):
                    // update the drawn graph for dragging and duplicating
                    if (_movedNodeGraph != null)
                    {
                        _movedNodeGraph.RenderDepth = int.MaxValue;
                        Invalidate();
                    }
                    break;

                // copy to clipboard
                case (Keys.C):
                    if (KeyCtrlIsDown)
                    {
                        CopySelectedNode();
                    }
                    break;

                // paste from clipboard
                case (Keys.V):
                    if (!_clipboardPasteMode)
                    {
                        _clipboardPasteMode = KeyCtrlIsDown && _clipboardNode != null;

                        if (_clipboardPasteMode)
                        {
                            // create the layout manager used to draw the graph
                            _movedNodeGraph = new NodeLayoutManager(_clipboardNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenHighlight, _nodeLayoutManager.EdgePenUpdate, _nodeLayoutManager.EdgePenReadOnly, true);
                            _movedNodeGraph.Scale = 0.3f;
                            _movedNodeGraph.RenderDepth = KeyShiftIsDown ? int.MaxValue : 0;

                            // use the existing node as the node defaults
                            _dragNodeDefaults = _clipboardNode;

                            Invalidate();
                        }
                    }
                    break;

                // cut to clipboard
                case (Keys.X):
                    if (KeyCtrlIsDown)
                    {
                        CutSelectedNode(KeyShiftIsDown);
                    }
                    break;

                // handle when the delete key is pressed
                case (Keys.Delete):
                    DeleteSelectedNode(KeyShiftIsDown);
                    break;

                case (Keys.E):
                    if (e.Control)
                    {
                        CenterNode(_rootNode);
                    }
                    break;

                case (Keys.K):
                    if (e.Control)
                    {
                        CheckErrors(_rootNode.RootBehavior, false);
                    }
                    break;

                case (Keys.F9):
                    if (SelectedNode != null)
                    {
                        if (e.Shift)
                        {
                            SelectedNode.SetBreakpoint(HighlightBreakPoint.kExit);
                        }
                        else
                        {
                            SelectedNode.SetBreakpoint(HighlightBreakPoint.kEnter);
                        }
                        LayoutChanged();
                    }
                    break;

                default: base.OnKeyDown(e); break;
            }
        }
        /// <summary>
        /// Handles when a key is released.
        /// </summary>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case (Keys.Enter):
                    if (SelectedNode != null)
                    {
                        if (KeyCtrlIsDown)
                            SelectedNode.ExpandAll(!SelectedNode.IsExpanded);
                        else
                            SelectedNode.IsExpanded = !SelectedNode.IsExpanded;

                        LayoutChanged();

                        e.Handled = true;
                    }
                    break;

                // store when the alt key is released
                case (Keys.Menu):
                    IsPanMode = false;
                    break;

                // store when the shift key is released
                case (Keys.ShiftKey):
                    // update the drawn graph for dragging and duplicating
                    if (_movedNodeGraph != null)
                    {
                        _movedNodeGraph.RenderDepth = 0;
                        Invalidate();
                    }
                    break;

                // paste from clipboard
                case (Keys.V):
                    _clipboardPasteMode = false;

                    // reset all the drag data
                    _copiedNode = null;
                    _movedNode = null;
                    _dragTargetNode = null;
                    _dragNodeDefaults = null;
                    _movedNodeGraph = null;

                    // redraw the graph
                    Invalidate();
                    break;

                case (Keys.Left):
                case (Keys.Right):
                case (Keys.Up):
                case (Keys.Down):
                    if (SelectedNode == null)
                    {
                        SelectedNode = this.RootNodeView;
                        if (ClickNode != null)
                            ClickNode(SelectedNode);

                        LayoutChanged();
                        break;
                    }

                    switch (e.KeyCode)
                    {
                        case (Keys.Left):
                            if (SelectedNode != null && SelectedNode.Parent != null)
                            {
                                SelectedNode = SelectedNode.Parent;
                                if (ClickNode != null)
                                    ClickNode(SelectedNode);

                                LayoutChanged();
                            }
                            break;

                        case (Keys.Right):
                            if (SelectedNode != null && SelectedNode.Children.Count > 0)
                            {
                                SelectedNode = SelectedNode.Children[0] as NodeViewData;
                                if (ClickNode != null)
                                    ClickNode(SelectedNode);

                                LayoutChanged();
                            }
                            break;

                        case (Keys.Up):
                            if (SelectedNode != null)
                            {
                                if (!KeyShiftIsDown || !SwitchSelection())
                                {
                                    // Node
                                    if (SelectedNode.SelectedSubItem == null)
                                    {
                                        if (SelectedNode.PreviousNode != null)
                                        {
                                            if (KeyCtrlIsDown) // Move
                                            {
                                                MoveNode(true);
                                            }
                                            else // Select
                                            {
                                                SelectedNode = SelectedNode.PreviousNode as NodeViewData;
                                                if (ClickNode != null)
                                                    ClickNode(SelectedNode);
                                            }
                                        }
                                    }
                                    // Attachment
                                    else
                                    {
                                        NodeViewData.SubItem previousItem = SelectedNode.PreviousSelectedSubItem;
                                        if (previousItem != null)
                                        {
                                            if (KeyCtrlIsDown) // Move
                                            {
                                                NodeViewData.SubItemAttachment sourceItem = SelectedNode.SelectedSubItem as NodeViewData.SubItemAttachment;
                                                NodeViewData.SubItemAttachment targetItem = previousItem as NodeViewData.SubItemAttachment;
                                                MoveSubItem(SelectedNode, sourceItem, targetItem, true);
                                                SelectedNode.SelectedSubItem = sourceItem;
                                            }
                                            else // Select
                                            {
                                                SelectedNode.SelectedSubItem = previousItem;
                                                if (ClickEvent != null)
                                                    ClickEvent(SelectedNode);
                                            }
                                        }
                                    }
                                }

                                LayoutChanged();
                            }
                            break;

                        case (Keys.Down):
                            if (SelectedNode != null)
                            {
                                if (!KeyShiftIsDown || !SwitchSelection())
                                {
                                    // Node
                                    if (SelectedNode.SelectedSubItem == null)
                                    {
                                        if (SelectedNode.NextNode != null)
                                        {
                                            if (KeyCtrlIsDown) // Move
                                            {
                                                MoveNode(false);
                                            }
                                            else // Select
                                            {
                                                SelectedNode = SelectedNode.NextNode as NodeViewData;
                                                if (ClickNode != null)
                                                    ClickNode(SelectedNode);
                                            }
                                        }
                                    }
                                    // Attachment
                                    else
                                    {
                                        NodeViewData.SubItem nextItem = SelectedNode.NextSelectedSubItem;
                                        if (nextItem != null)
                                        {
                                            if (KeyCtrlIsDown) // Move
                                            {
                                                NodeViewData.SubItemAttachment sourceItem = SelectedNode.SelectedSubItem as NodeViewData.SubItemAttachment;
                                                NodeViewData.SubItemAttachment targetItem = nextItem as NodeViewData.SubItemAttachment;
                                                MoveSubItem(SelectedNode, sourceItem, targetItem, false);
                                                SelectedNode.SelectedSubItem = sourceItem;
                                            }
                                            else // Select
                                            {
                                                SelectedNode.SelectedSubItem = nextItem;
                                                if (ClickEvent != null)
                                                    ClickEvent(SelectedNode);
                                            }
                                        }
                                    }
                                }

                                LayoutChanged();
                            }
                            break;
                    }
                    break;

                default:
                    base.OnKeyUp(e);
                    break;
            }
        }
		/// <summary>
		/// Handles when a mouse button is let go of.
		/// </summary>
		protected override void OnMouseUp(MouseEventArgs e)
		{
			// check if we were dragging or copying an existing node
			if(e.Button ==MouseButtons.Right && _movedNode !=null || e.Button ==MouseButtons.Left && _copiedNode !=null || e.Button ==MouseButtons.Left && _clipboardPasteMode)
			{
				// if we have a valid target node continue
				if(_dragTargetNode !=null)
				{
					Node sourcenode= null;

					if(_movedNode !=null)
						sourcenode= _movedNode;
					else if(_copiedNode !=null)
						sourcenode= _keyShiftIsDown ? (Nodes.Node)_copiedNode.CloneBranch() : (Nodes.Node)_copiedNode.Clone();
					else if(_clipboardPasteMode)
						sourcenode= _keyShiftIsDown ? (Nodes.Node)_clipboardNode.CloneBranch() : (Nodes.Node)_clipboardNode.Clone();

					// move the dragged node to the target node, according to the attach mode
					switch(_dragAttachMode)
					{
						// the node will be placed above the traget node
						case(NodeAttachMode.Top):
							if(_movedNode !=null)
							{
								if(_keyShiftIsDown)
								{
									_movedNode.Parent.RemoveChild(_movedNode.ParentConnector, _movedNode);
								}
								else
								{
									if(!_movedNode.ExtractNode())
										throw new Exception(Resources.ExceptionNodeCouldNotBeExtracted);
								}
							}

							int n= _dragTargetNode.Node.ParentConnector.GetChildIndex(_dragTargetNode.Node);
							_dragTargetNode.Node.Parent.AddChild(_dragTargetNode.Node.ParentConnector, sourcenode, n);

							LayoutChanged();
						break;

						// the node will be placed below the target node
						case(NodeAttachMode.Bottom):
							if(_movedNode !=null)
							{
								if(_keyShiftIsDown)
								{
									_movedNode.Parent.RemoveChild(_movedNode.ParentConnector, _movedNode);
								}
								else
								{
									if(!_movedNode.ExtractNode())
										throw new Exception(Resources.ExceptionNodeCouldNotBeExtracted);
								}
							}

							int m= _dragTargetNode.Node.ParentConnector.GetChildIndex(_dragTargetNode.Node);
							_dragTargetNode.Node.Parent.AddChild(_dragTargetNode.Node.ParentConnector, sourcenode, m +1);

							LayoutChanged();
						break;

						// the node will be placed in front of the target node
						case(NodeAttachMode.Left):
							if(_movedNode !=null)
							{
								if(_keyShiftIsDown)
								{
									_movedNode.Parent.RemoveChild(_movedNode.ParentConnector, _movedNode);
								}
								else
								{
									if(!_movedNode.ExtractNode())
										throw new Exception(Resources.ExceptionNodeCouldNotBeExtracted);
								}
							}

							Node parent= _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);

							sourcenode.AddChild(sourcenode.DefaultConnector, _dragTargetNode.Node);
						break;

						// the node will simply attached to the target node
						case(NodeAttachMode.Right):
							if(_movedNode !=null)
							{
								if(_keyShiftIsDown)
								{
									_movedNode.Parent.RemoveChild(_movedNode.ParentConnector, _movedNode);
								}
								else
								{
									if(!_movedNode.ExtractNode())
										throw new Exception(Resources.ExceptionNodeCouldNotBeExtracted);
								}
							}

							_dragTargetNode.Node.AddChild(_dragTargetConnector, sourcenode);

							LayoutChanged();
						break;
					}

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

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

				// redraw the graph
				Invalidate();
			}

			Cursor= Cursors.Hand;

			base.OnMouseUp(e);
		}
		/// <summary>
		/// Handles when the mouse is moved.
		/// </summary>
		protected override void OnMouseMove(MouseEventArgs e)
		{
			if(_lostFocus)
			{
				_lostFocus= false;

				// update the last ouse position
				_lastMousePosition= e.Location;

				base.OnMouseMove(e);

				return;
			}

			// returns the mouse under the mouse cursor
			NodeViewData nodeFound= _rootNode.IsInside(e.Location);

			// clear previously stored node which can cause problems when dragging to another view
			_dragTargetNode= null;

			// if a different node is the current one, update it
			if(nodeFound !=_currentNode)
			{
				_currentNode= nodeFound;

				// if enabled show the tooltip for the node
				if(Settings.Default.ShowNodeToolTips)
				{
					if(_currentNode ==null)
					{
						toolTip.Hide(this);
					}
					else
					{
						if(_currentNode.Node.ToolTip !=string.Empty)
							toolTip.Show(_currentNode.Node.ToolTip, this, new Point( (int)_currentNode.DisplayBoundingBox.X -20, (int)_currentNode.DisplayBoundingBox.Y -30 ));
					}
				}

				Invalidate();
			}

			// check if we are currently dragging the graph
			if(e.Button ==MouseButtons.Left && _lastMousePosition !=e.Location && !_keyControlIsDown && _copiedNode ==null)
			{
				_wasDragged= true;

				// move the graph according to the last mouse position
				_nodeLayoutManager.Offset= new PointF(_nodeLayoutManager.Offset.X - (_lastMousePosition.X - e.X), _nodeLayoutManager.Offset.Y - (_lastMousePosition.Y - e.Y));

				Invalidate();
			}
			// check if we start duplicating an existing node step 1
			else if(e.Button ==MouseButtons.Left && _keyControlIsDown && _lastMousePosition !=e.Location && _copiedNode ==null && _currentNode !=null && !(_currentNode.Node is BehaviorNode))
			{
				_copiedNode= _currentNode.Node;

				// create the layout manager used to draw the graph
				_movedNodeGraph= new NodeLayoutManager(_copiedNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenReadOnly, true);
				_movedNodeGraph.Scale= 0.3f;
				_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

				// use the existing node as the node defaults
				_dragNodeDefaults= _copiedNode;

				Invalidate();
			}
			// check if we are duplicating an existing node step 2
			else if(e.Button ==MouseButtons.Left && _keyControlIsDown && _copiedNode !=null)
			{
				_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

				_dragTargetNode= _currentNode;

				Cursor= _currentNode ==null ? Cursors.No : Cursors.Arrow;

				//Point movedGraphGraphPos= new Point(e.Location.X + _movedNodeGraph.Offset.X, e.Location.Y + _movedNodeGraph.Offset.Y /-2);
				//_movedNodeGraph.Location= movedGraphGraphPos;

				Invalidate();
			}
			// check if we start dragging an existing node step 1
			else if(e.Button ==MouseButtons.Right && _lastMousePosition !=e.Location && _movedNode ==null && _currentNode !=null && !(_currentNode.Node is BehaviorNode) && (_keyShiftIsDown || _currentNode.Node.ParentCanAdoptChildren))
			{
				_movedNode= _currentNode.Node;

				// create the layout manager used to draw the graph
				_movedNodeGraph= new NodeLayoutManager(_movedNode.CloneBranch().CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenReadOnly, true);
				_movedNodeGraph.Scale= 0.3f;
				_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

				// use the existing node as the node defaults
				_dragNodeDefaults= _movedNode;

				Invalidate();
			}
			// check if we are dragging an existing node step 2
			else if(e.Button ==MouseButtons.Right && _movedNode !=null)
			{
				_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

				_dragTargetNode= _currentNode;

				Cursor= _currentNode ==null ? Cursors.No : Cursors.Arrow;

				Invalidate();
			}
			else if(_clipboardPasteMode)
			{
				_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

				_dragTargetNode= _currentNode;

				Cursor= _currentNode ==null ? Cursors.No : Cursors.Arrow;

				Invalidate();
			}

			// update the last ouse position
			_lastMousePosition= e.Location;

			base.OnMouseMove(e);
		}
		/// <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();
		}
		/// <summary>
		/// Handles when a key is pressed.
		/// </summary>
		protected override void OnKeyDown(KeyEventArgs e)
		{
			switch(e.KeyCode)
			{
				// store when the control key is pressed
				case(Keys.ControlKey):
					_keyControlIsDown= true;

					if(_copiedNode ==null && _movedNode ==null)
						Cursor= Cursors.Arrow;
				break;

				// store when the shift key is pressed
				case(Keys.ShiftKey):
					_keyShiftIsDown= true;

					// update the drawn graph for dragging and duplicating
					if(_movedNodeGraph !=null)
					{
						_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;
						Invalidate();
					}
				break;

				// copy to clipboard
				case(Keys.C):
					if(_keyControlIsDown && _selectedNode !=null)
					{
						_clipboardNode= _keyShiftIsDown ? (Node)_selectedNode.Node.CloneBranch() : (Node)_selectedNode.Node.Clone();
					}
				break;

				// paste from clipboard
				case(Keys.V):
					if(!_clipboardPasteMode)
					{
						_clipboardPasteMode= _keyControlIsDown && _clipboardNode !=null;

						if(_clipboardPasteMode)
						{
							// create the layout manager used to draw the graph
							_movedNodeGraph= new NodeLayoutManager(_clipboardNode.CreateNodeViewData(null, _rootNode.RootBehavior), _nodeLayoutManager.EdgePen, _nodeLayoutManager.EdgePenReadOnly, true);
							_movedNodeGraph.Scale= 0.3f;
							_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;

							// use the existing node as the node defaults
							_dragNodeDefaults= _clipboardNode;

							Invalidate();
						}
					}
				break;

				// cut to clipboard
				case(Keys.X):
					if(_keyControlIsDown && _selectedNode !=null)
					{
						_clipboardNode= _keyShiftIsDown ? (Node)_selectedNode.Node.CloneBranch() : (Node)_selectedNode.Node.Clone();

						// store the selected node
						Node node= _selectedNode.Node;

						// clear the selected and current node
						_selectedNode= null;
						_currentNode= null;

						if(_keyShiftIsDown)
						{
							// remove the node
							node.Parent.RemoveChild(node.ParentConnector, node);

							// call the ClickNode event to delselect the node in the editor
							if(ClickNode !=null)
								ClickNode(null);
						}
						else
						{
							if(node.ExtractNode())
							{
								// call the ClickNode event to delselect the node in the editor
								if(ClickNode !=null)
									ClickNode(null);
							}
						}
					}
				break;

				// handle when the delete key is pressed
				case(Keys.Delete):
					// when we have a node selected which is not the root node, continue
					if(_selectedNode !=null && _selectedNode.Node.Parent !=null)
					{
						// check whether we have to delete an event or a node
						if(_selectedNode.Node.SelectedSubItem ==null)
						{
							// store the selected node
							Node node= _selectedNode.Node;

							// clear the selected and current node
							_selectedNode= null;
							_currentNode= null;

							if(_keyShiftIsDown)
							{
								// remove the node
								node.Parent.RemoveChild(node.ParentConnector, node);

								// call the ClickNode event to delselect the node in the editor
								if(ClickNode !=null)
									ClickNode(null);
							}
							else
							{
								if(node.ExtractNode())
								{
									// call the ClickNode event to delselect the node in the editor
									if(ClickNode !=null)
										ClickNode(null);
								}
							}
						}
						else
						{
							// just let the node delete the selected subitem
							if(_selectedNode.Node.RemoveSelectedSubItem())
							{
								_selectedNode.Node.BehaviorWasModified();

								// call the ClickNode event to select the node instead of the deleted subitem
								if(ClickNode !=null)
									ClickNode(_selectedNode);
							}
						}

						// the layout needs to be recalculated
						LayoutChanged();
					}
				break;

				default: base.OnKeyDown(e); break;
			}
		}
		/// <summary>
		/// Handles when a key is released.
		/// </summary>
		protected override void OnKeyUp(KeyEventArgs e)
		{
			switch(e.KeyCode)
			{
				// store when the control key is released
				case(Keys.ControlKey):
					_keyControlIsDown= false;

					if(_copiedNode ==null && _movedNode ==null)
						Cursor= Cursors.Hand;
				break;

				// store when the shift key is released
				case(Keys.ShiftKey):
					_keyShiftIsDown= false;

					// update the drawn graph for dragging and duplicating
					if(_movedNodeGraph !=null)
					{
						_movedNodeGraph.RenderDepth= _keyShiftIsDown ? int.MaxValue : 0;
						Invalidate();
					}
				break;

				// paste from clipboard
				case(Keys.V):
					_clipboardPasteMode= false;

					// reset all the drag data
					_copiedNode= null;
					_movedNode= null;
					_dragTargetNode= null;
					_dragNodeDefaults= null;
					_movedNodeGraph= null;

					// redraw the graph
					Invalidate();
				break;

				default: base.OnKeyUp(e); break;
			}
		}