/// <summary> /// Creates a new NodeLayoutManager. /// </summary> /// <param name="edgePen">The pen which is used to draw the edges connecting the nodes.</param> /// <param name="edgePenSubReferenced">The pen which is used to draw the edges connecting sub-referenced nodes.</param> /// <param name="skipLabels">Defines if labels are drawn or not.</param> /// <param name="rootNode">The root of the nodes shown in the view.</param> internal NodeLayoutManager(NodeViewData rootNode, Pen edgePen, Pen edgePenSubReferenced, bool skipLabels) { _rootNodeLayout = rootNode; _edgePen = edgePen; _edgePenReadOnly = edgePenSubReferenced; _skipLabels = skipLabels; }
/// <summary> /// Draws the graph. /// </summary> /// <param name="graphics">The graphics object we want to draw to.</param> /// <param name="currentNode">The node the mouse is currently hovering over.</param> /// <param name="selectedNode">The node which is currently selected.</param> /// <param name="graphMousePos">The mouse's position in the graph.</param> internal void DrawGraph(Graphics graphics, NodeViewData currentNode, NodeViewData selectedNode, PointF graphMousePos) { // setup drawing graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.Transform = new System.Drawing.Drawing2D.Matrix(_scale, 0.0f, 0.0f, _scale, _offset.X, _offset.Y); // update display bounding boxes _rootNodeLayout.UpdateDisplay(_offset.X, _offset.Y, _scale); // draw comment backgrounds if (!_skipLabels) { _rootNodeLayout.DrawCommentBackground(graphics, _renderDepth, _padding); } // draw the edges if (_edgePen != null && _renderDepth > 0) { _rootNodeLayout.DrawEdges(graphics, _edgePen, _edgePenReadOnly, _renderDepth - 1); } // draw the nodes _rootNodeLayout.Draw(graphics, currentNode, selectedNode, _skipLabels, graphMousePos, _renderDepth); // draw comment text if (!_skipLabels) { _rootNodeLayout.DrawCommentText(graphics, _renderDepth); } // draw last mouse pos //e.Graphics.DrawRectangle(Pens.Red, graphMousePos.X -1.0f, graphMousePos.Y -1.0f, 2.0f, 2.0f); }
/// <summary> /// Draws the node's shape as the background. /// </summary> /// <param name="graphics">The graphics object used for drawing.</param> /// <param name="nvd">The node view data of the node the subitem belongs to.</param> /// <param name="brush">The brush to draw the node's shape.</param> protected void DrawBackground(Graphics graphics, NodeViewData nvd, Brush brush) { if (brush != null) { nvd.DrawShapeBackground(graphics, nvd.BoundingBox, brush); } }
public override void Draw(Graphics graphics, NodeViewData nvd, RectangleF boundingBox) { // render background DrawBackground(graphics, nvd, _selected ? _backgroundSelected : _backgroundNormal); // render the label PointF center = new PointF(boundingBox.Left + boundingBox.Width * 0.5f, boundingBox.Top + boundingBox.Height * 0.5f); SizeF labelSize = MeasureDisplayStringWidth(graphics, Label, _labelFont); // draw text switch (_alignment) { case (Alignment.Left): graphics.DrawString(Label, _labelFont, _labelBrush, boundingBox.Left + 6.0f, center.Y - labelSize.Height * 0.5f); break; case (Alignment.Center): graphics.DrawString(Label, _labelFont, _labelBrush, center.X - labelSize.Width * 0.5f, center.Y - labelSize.Height * 0.5f); break; case (Alignment.Right): graphics.DrawString(Label, _labelFont, _labelBrush, boundingBox.Right - labelSize.Width - 6.0f, center.Y - labelSize.Height * 0.5f); break; } //graphics.DrawRectangle(Pens.Red, boundingBox.X, boundingBox.Y, boundingBox.Width, boundingBox.Height); }
/// <summary> /// Draws the node's shape as the background. /// </summary> /// <param name="dc">The graphics object used for drawing.</param> /// <param name="nvd">The node view data of the node the subitem belongs to.</param> /// <param name="brush">The brush to draw the node's shape.</param> protected void DrawBackground(DrawingContext dc, NodeViewData nvd, Brush brush) { if (brush != null) { nvd.DrawShape(dc, nvd.BoundingBox, brush, null); } }
public override void Update(NodeViewData node, DrawingContext dc) { // calculate the extent used by the label FormattedText formattedText = _labelFont.FormatText(Label, Brushes.White); _width = formattedText.Width; }
public override void Draw(DrawingContext dc, NodeViewData nvd, Rect boundingBox) { // render background DrawBackground(dc, nvd, _selected ? _backgroundSelected : _backgroundNormal); // render the label Point center = new Point(boundingBox.Left + boundingBox.Width * 0.5f, boundingBox.Top + boundingBox.Height * 0.5f); FormattedText formattedText = _labelFont.FormatText(Label, _labelBrush); // draw text switch (_alignment) { case (Alignment.Left): dc.DrawText(formattedText, new Point(boundingBox.Left + 6.0, center.Y - formattedText.Height * 0.5)); break; case (Alignment.Center): dc.DrawText(formattedText, new Point(center.X - formattedText.Width * 0.5, center.Y - formattedText.Height * 0.5)); break; case (Alignment.Right): dc.DrawText(formattedText, new Point(boundingBox.Right - formattedText.Width - 6.0, center.Y - formattedText.Height * 0.5)); break; } //graphics.DrawRectangle(Pens.Red, boundingBox.X, boundingBox.Y, boundingBox.Width, boundingBox.Height); }
/// <summary> /// Draws the graph. /// </summary> /// <param name="dc">The graphics object we want to draw to.</param> /// <param name="currentNode">The node the mouse is currently hovering over.</param> /// <param name="selectedNode">The node which is currently selected.</param> /// <param name="graphMousePos">The mouse's position in the graph.</param> internal void DrawGraph(DrawingContext dc, NodeViewData currentNode, NodeViewData selectedNode, Point graphMousePos) { // setup drawing dc.PushTransform(new MatrixTransform(_scale, 0.0, 0.0, _scale, _offset.X, _offset.Y)); // update display bounding boxes _rootNodeLayout.UpdateDisplay(_offset.X, _offset.Y, _scale); // draw comment backgrounds if (!_skipLabels) { _rootNodeLayout.DrawCommentBackground(dc, _renderDepth, _padding); } // draw the edges if (_edgePen != null && _renderDepth > 0) { _rootNodeLayout.DrawEdges(dc, _edgePen, _edgePenReadOnly, _renderDepth - 1); } // draw the nodes _rootNodeLayout.Draw(dc, currentNode, selectedNode, _skipLabels, graphMousePos, _renderDepth); // draw comment text if (!_skipLabels) { _rootNodeLayout.DrawCommentText(dc, _renderDepth); } // draw last mouse pos //e.Graphics.DrawRectangle(Pens.Red, graphMousePos.X -1.0f, graphMousePos.Y -1.0f, 2.0f, 2.0f); dc.Pop(); }
/// <summary> /// This function adapts the children of the view that they represent the children of the node this view is for. /// Children are added and removed. /// </summary> /// <param name="processedBehaviors">A list of previously processed behaviours to deal with circular references.</param> public virtual void SynchronizeWithNode(IList <BehaviorNode> processedBehaviors) { // allow the node to add some final children or remove some _node.PreLayoutUpdate(this); // if the counts do not fit we must rebuild bool rebuild = _node.Children.Count != _children.Count; // check if all children are associated to the correct children of the node if (!rebuild) { for (int i = 0; i < _node.Children.Count; ++i) { // this view is associated to another node than the child of the node if (_children[i].Node != _node.Children[i]) { rebuild = true; break; } } } // check if we must rebuild the child list if (rebuild) { // store the old children List <NodeViewData> oldChildren = _children; // create a new list _children = new List <NodeViewData>(); // update the children foreach (Node child in _node.Children) { // check if our old child list already contains a view for this node. If so copy it. NodeViewData nvd = child.FindNodeViewData(oldChildren); if (nvd != null) { Debug.Check(_rootBehavior == nvd.RootBehavior); _children.Add(nvd); } // otherwise create a new view else { _children.Add(child.CreateNodeViewData(this, _rootBehavior)); } } } // synchronise the children as well foreach (NodeViewData child in _children) { Debug.Check(child.RootBehavior == _rootBehavior); child.SynchronizeWithNode(processedBehaviors); } }
/// <summary> /// Is called when the node was double-clicked. Used for referenced behaviours. /// </summary> /// <param name="nvd">The view data of the node in the current view.</param> /// <param name="layoutChanged">Does the layout need to be recalculated?</param> /// <returns>Returns if the node handled the double click or not.</returns> public override bool OnDoubleClick(NodeViewData nvd, out bool layoutChanged) { NodeViewDataReferencedBehavior nvdrb = (NodeViewDataReferencedBehavior)nvd; nvdrb.IsExpanded = !nvdrb.IsExpanded; layoutChanged = true; return(true); }
public override void Draw(DrawingContext dc, NodeViewData nvd, Rect boundingBox) { Event evnt = (Event)_attachment; // use a different brush depending on if the event is reacted to or blocked. _labelBrush = evnt.BlockEvent ? Brushes.Orange : Brushes.White; base.Draw(dc, nvd, boundingBox); }
public NodeViewDataStyled(NodeViewData parent, BehaviorNode rootBehavior, Node node, Pen borderPen, Brush backgroundBrush, Brush draggedBackgroundBrush, string label, string description) : base(parent, rootBehavior, node, NodeShape.RoundedRectangle, new Style(backgroundBrush, null, Brushes.White), new Style(null, __defaultCurrentBorderPen, null), new Style(null, __defaultSelectedBorderPen, null), new Style(draggedBackgroundBrush, null, null), label, __defaultLabelFont, 120, 35, description) { }
/// <summary> /// Handles when an event of a node is selected. /// </summary> /// <param name="node">The node whose event is selected.</param> private void control_ClickEvent(NodeViewData node) { // if there is no subitem selected, use the properties of the node if (node.SelectedSubItem == null || node.SelectedSubItem.SelectableObject == null) { PropertiesDock.InspectObject(node.Node); } // publish the properties of the subitem's selection object else { PropertiesDock.InspectObject(node.SelectedSubItem.SelectableObject); } }
/// <summary> /// Draws the node to the graph. /// </summary> /// <param name="graphics">The graphics object we render to.</param> /// <param name="currentNode">The current node under the mouse cursor.</param> /// <param name="selectedNode">The currently selected node.</param> /// <param name="isDragged">Determines if the node is currently being dragged.</param> /// <param name="graphMousePos">The mouse position in the untransformed graph.</param> /// <param name="renderDepth">The depth which is still rendered.</param> public virtual void Draw(Graphics graphics, NodeViewData currentNode, NodeViewData selectedNode, bool isDragged, PointF graphMousePos, int renderDepth) { _node.Draw(graphics, this, currentNode == null ? false : this.Node == currentNode.Node, selectedNode == null ? false : this.Node == selectedNode.Node, isDragged, graphMousePos); // draw children if (renderDepth > 0) { foreach (NodeViewData child in _children) { child.Draw(graphics, currentNode, selectedNode, isDragged, graphMousePos, renderDepth - 1); } } }
/// <summary> /// Creates a new view for a given node. /// </summary> /// <param name="parent">The parent of the new NodeViewData.</param> /// <param name="rootBehavior">The behaviour which is the root of the graph the given node is shown in.</param> /// <param name="node">The node the view is created for.</param> public NodeViewData(NodeViewData parent, BehaviorNode rootBehavior, Node node) { Debug.Check(rootBehavior != null); _parent = parent; _rootBehavior = rootBehavior; _node = node; if (parent != null) { WasModified = parent.WasModified; } _node.WasModified += new Node.WasModifiedEventDelegate(node_WasModified); }
/// <summary> /// Returns the node a given location is in. /// </summary> /// <param name="location">The location you want to check.</param> /// <returns>Returns null if the position is not inside any node.</returns> public NodeViewData IsInside(PointF location) { if (_displayBoundingBox.Contains(location)) { return(this); } foreach (NodeViewData node in _children) { NodeViewData insidenode = node.IsInside(location); if (insidenode != null) { return(insidenode); } } return(null); }
/// <summary> /// Returns the first NodeViewData which is associated with the given node. Notice that there might be other NodeViewDatas which are ignored. /// </summary> /// <param name="node">The node you want to get the NodeViewData for.</param> /// <returns>Returns the first NodeViewData found.</returns> public virtual NodeViewData FindNodeViewData(Node node) { // check if this is a fitting view if (_node == node) { return(this); } // search the children foreach (NodeViewData child in _children) { NodeViewData result = child.FindNodeViewData(node); if (result != null) { return(result); } } return(null); }
private void listView_DoubleClick(object sender, EventArgs e) { // check if there is an item selected if (listView.SelectedItems.Count < 1) { return; } // check if this item has a node connected to it. The no-errors message doesn't Nodes.BehaviorNode node = (Nodes.BehaviorNode)listView.SelectedItems[0].Tag; if (node == null) { return; } // show the behaviour and select the node. NodeViewData nvd = _behaviorTreeList.ShowNode((Nodes.Node)node); _behaviorTreeView.SelectedNode = nvd; }
/// <summary> /// Handles when a node is clicked. /// </summary> /// <param name="node">The node that was clicked.</param> private void control_ClickNode(NodeViewData node) { PropertiesDock.InspectObject(node == null ? null : node.Node); }
/// <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); }
public NodeViewDataReferencedBehavior(NodeViewData parent, Nodes.BehaviorNode rootBehavior, Nodes.ReferencedBehaviorNode node) : base(parent, rootBehavior, (Node)node) { }
/// <summary> /// Handles when a node is clicked. /// </summary> /// <param name="node">The node that was clicked.</param> private void control_ClickNode(NodeViewData node) { PropertiesDock.InspectObject(node ==null ? null : node.Node); }
/// <summary> /// Handles when the user doucle-clicks. /// </summary> protected override void OnMouseDoubleClick(MouseEventArgs e) { // when the user double-clicked a node and the graph was not dragged and it was the left mouse button, continue if(_currentNode !=null && DoubleClickNode !=null && !_wasDragged && e.Button ==MouseButtons.Left) { // call double-clicked on the node bool layoutChanged; if(_currentNode.Node.OnDoubleClick(_currentNode, out layoutChanged)) { // check if the node requires the layout to be updated, for example when expanding or collapsing referenced behaviours if(layoutChanged) { // keep the position of the current node _maintainNodePosition= _currentNode; _graphOrigin= _maintainNodePosition.DisplayBoundingBox.Location; LayoutChanged(); } } else { // if the node did not handle the double-click the developer may if(DoubleClickNode !=null) DoubleClickNode(_currentNode); } } else base.OnMouseDoubleClick(e); }
/// <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 the root node changes. /// </summary> /// <param name="node">The node which was changed, in our case always the root node.</param> void nodeViewData_WasModified(NodeViewData node) { LayoutChanged(); }
/// <summary> /// Centres the given node in the view. /// </summary> /// <param name="node">The node which will be centred.</param> internal void CenterNode(NodeViewData node) { // we use the existing maintain position stuff for that RectangleF bbox= node.BoundingBox; _maintainNodePosition= node; // if the node was not yet shown there is no bounding box so we simply use the min height for that float height= bbox.Height <=0.0f ? node.Node.MinHeight : bbox.Height; _graphOrigin= new PointF(20.0f, ClientSize.Height *0.5f - height *0.5f); Invalidate(); }
public override void Update(NodeViewData node, Graphics graphics) { // calculate the extent used by the label _width = MeasureDisplayStringWidth(graphics, Label, _labelFont).Width; }
public NodeViewDataReferencedBehavior(NodeViewData parent, Nodes.BehaviorNode rootBehavior, Nodes.ReferencedBehaviorNode node, Pen borderPen, Brush backgroundBrush, string label, string description) : base(parent, rootBehavior, (Node)node, borderPen, backgroundBrush, label, description) { }
/// <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> /// Adds nodes to the referenced behaviour which represent sub-referenced behaviours. /// </summary> /// <param name="processedBehaviors">A list of processed behaviours to handle circular references.</param> /// <param name="parent">The node the sub-referenced behaviours will be added to.</param> /// <param name="node">The current node we are checking.</param> protected void GenerateReferencedBehaviorsTree(ProcessedBehaviors processedBehaviors, NodeViewData parent, Node node) { if (!processedBehaviors.MayProcess(node)) { return; } // check if this is a referenced behaviour if (node is ReferencedBehaviorNode) { // create the dummy node and add it without marking the behaviour as being modified as these are no REAL nodes. NodeViewData rb = node.CreateNodeViewData(parent, _rootBehavior); #if DEBUG rb.IsSubreferencedGraphNode(); #endif rb.DoSynchronizeWithNode(processedBehaviors); Connector conn = parent.GetConnector("GenericChildren"); Debug.Check(conn != null); Connector rbconn = parent.GetConnector("GenericChildren"); Debug.Check(rbconn != null); bool parentReadOnly = conn.IsReadOnly; conn.IsReadOnly = false; parent.AddChildNotModified(conn, rb); conn.IsReadOnly = parentReadOnly; // we have a circular reference here. Skip the children if (((ReferencedBehaviorNode)node).Reference == _rootBehavior) { rbconn.IsReadOnly = true; return; } // do the same for all the children foreach (Node child in node.Children) { GenerateReferencedBehaviorsTree(processedBehaviors.Branch(child), rb, child); } rbconn.IsReadOnly = true; } else if (node is Impulse) { // create the dummy node and add it without marking the behaviour as being modified as these are no REAL nodes. NodeViewData ip = node.CreateNodeViewData(parent, _rootBehavior); ip.DoSynchronizeWithNode(processedBehaviors); // do the same for all the children foreach (Node child in node.Children) { GenerateReferencedBehaviorsTree(processedBehaviors.Branch(child), ip, child); } if (ip.Children.Count > 0) { Connector conn = parent.GetConnector("GenericChildren"); Debug.Check(conn != null); Connector ipconn = ip.GetConnector("GenericChildren"); Debug.Check(ipconn != null); parent.AddChildNotModified(conn, ip); ipconn.IsReadOnly = true; } } else { // do the same for all the children foreach (Node child in node.Children) { GenerateReferencedBehaviorsTree(processedBehaviors.Branch(child), parent, child); } } }
/// <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> /// Called when the node is drawn. /// </summary> /// <param name="dc">The graphics object used to draw the subitem.</param> /// <param name="nvd">The node view data of the node the subitem belongs to.</param> /// <param name="boundingBox">The bounding box of the subitem. Drawing is clipped to this.</param> public abstract void Draw(DrawingContext dc, NodeViewData nvd, Rect boundingBox);
/// <summary> /// Draws the node to the graph. /// </summary> /// <param name="graphics">The graphics object we render to.</param> /// <param name="currentNode">The current node under the mouse cursor.</param> /// <param name="selectedNode">The currently selected node.</param> /// <param name="isDragged">Determines if the node is currently being dragged.</param> /// <param name="graphMousePos">The mouse position in the untransformed graph.</param> /// <param name="renderDepth">The depth which is still rendered.</param> public virtual void Draw(Graphics graphics, NodeViewData currentNode, NodeViewData selectedNode, bool isDragged, PointF graphMousePos, int renderDepth) { _node.Draw(graphics, this, currentNode ==null ? false : this.Node ==currentNode.Node, selectedNode ==null ? false : this.Node ==selectedNode.Node, isDragged, graphMousePos); // draw children if(renderDepth >0) { foreach(NodeViewData child in _children) child.Draw(graphics, currentNode, selectedNode, isDragged, graphMousePos, renderDepth -1); } }
/// <summary> /// Called when the node gets updated. /// </summary> /// <param name="node">The node the subitem belongs to.</param> /// <param name="dc">The graphics object used for the update, NOT for drawing!</param> public abstract void Update(NodeViewData node, DrawingContext dc);
/// <summary> /// Called when the node is drawn. /// </summary> /// <param name="graphics">The graphics object used to draw the subitem.</param> /// <param name="nvd">The node view data of the node the subitem belongs to.</param> /// <param name="boundingBox">The bounding box of the subitem. Drawing is clipped to this.</param> public abstract void Draw(Graphics graphics, NodeViewData nvd, RectangleF boundingBox);
/// <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; } }
/// <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 an event of a node is selected. /// </summary> /// <param name="node">The node whose event is selected.</param> private void control_ClickEvent(NodeViewData node) { // if there is no subitem selected, use the properties of the node if(node.Node.SelectedSubItem ==null || node.Node.SelectedSubItem.SelectableObject ==null) { PropertiesDock.InspectObject(node.Node); } // publish the properties of the subitem's selection object else { PropertiesDock.InspectObject(node.Node.SelectedSubItem.SelectableObject); } }
/// <summary> /// Called when the node gets updated. /// </summary> /// <param name="node">The node the subitem belongs to.</param> /// <param name="graphics">The graphics object used for the update, NOT for drawing!</param> public abstract void Update(NodeViewData node, Graphics graphics);
/// <summary> /// Handles when a node is double-clicked. /// </summary> /// <param name="node">The node that was double-clicked.</param> private void control_DoubleClickNode(NodeViewData node) { }
/// <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.Event) _dragAttachMode= NodeAttachMode.None; else if(_dragNodeDefaults is Events.Event && _dragAttachMode !=NodeAttachMode.Event) _dragAttachMode= NodeAttachMode.Event; } // 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 event to a node else if(_dragTargetNode !=null && (e.KeyState & 1/*left mouse button*/) >0 && _dragNodeDefaults is Events.Event && _dragTargetNode.Node.AcceptsEvents) { e.Effect= DragDropEffects.Move; } // update last know mouse position _lastMousePosition= new PointF(pt.X, pt.Y); }
/// <summary> /// Creates a new NodeLayoutManager. /// </summary> /// <param name="edgePen">The pen which is used to draw the edges connecting the nodes.</param> /// <param name="edgePenSubReferenced">The pen which is used to draw the edges connecting sub-referenced nodes.</param> /// <param name="skipLabels">Defines if labels are drawn or not.</param> /// <param name="rootNode">The root of the nodes shown in the view.</param> internal NodeLayoutManager(NodeViewData rootNode, Pen edgePen, Pen edgePenSubReferenced, bool skipLabels) { _rootNodeLayout= rootNode; _edgePen= edgePen; _edgePenReadOnly= edgePenSubReferenced; _skipLabels= skipLabels; }
/// <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> /// Creates a new view for a given node. /// </summary> /// <param name="parent">The parent of the new NodeViewData.</param> /// <param name="rootBehavior">The behaviour which is the root of the graph the given node is shown in.</param> /// <param name="node">The node the view is created for.</param> public NodeViewData(NodeViewData parent, BehaviorNode rootBehavior, Node node) { Debug.Check(rootBehavior !=null); _parent= parent; _rootBehavior= rootBehavior; _node= node; if(parent !=null) WasModified= parent.WasModified; _node.WasModified+= new Node.WasModifiedEventDelegate(node_WasModified); }
/// <summary> /// Draws the graph. /// </summary> /// <param name="graphics">The graphics object we want to draw to.</param> /// <param name="currentNode">The node the mouse is currently hovering over.</param> /// <param name="selectedNode">The node which is currently selected.</param> /// <param name="graphMousePos">The mouse's position in the graph.</param> internal void DrawGraph(Graphics graphics, NodeViewData currentNode, NodeViewData selectedNode, PointF graphMousePos) { // setup drawing graphics.InterpolationMode= System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; graphics.SmoothingMode= System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.Transform= new System.Drawing.Drawing2D.Matrix(_scale, 0.0f, 0.0f, _scale, _offset.X, _offset.Y); // update display bounding boxes _rootNodeLayout.UpdateDisplay(_offset.X, _offset.Y, _scale); // draw comment backgrounds if(!_skipLabels) _rootNodeLayout.DrawCommentBackground(graphics, _renderDepth, _padding); // draw the edges if(_edgePen !=null && _renderDepth >0) _rootNodeLayout.DrawEdges(graphics, _edgePen, _edgePenReadOnly, _renderDepth -1); // draw the nodes _rootNodeLayout.Draw(graphics, currentNode, selectedNode, _skipLabels, graphMousePos, _renderDepth); // draw comment text if(!_skipLabels) _rootNodeLayout.DrawCommentText(graphics, _renderDepth); // draw last mouse pos //e.Graphics.DrawRectangle(Pens.Red, graphMousePos.X -1.0f, graphMousePos.Y -1.0f, 2.0f, 2.0f); }