/// <summary> /// Show the behavior tree view with highlights. /// </summary> /// <param name="agentFullname">The fullname of an agent instance, as the format of "agnetType::instanceName".</param> /// <param name="frame">The current frame when connecting or playing.</param> public static BehaviorNode ShowBehaviorTree(string agentFullname, int frame, List<string> highlightNodeIds, List<string> updatedNodeIds, HighlightBreakPoint highlightBreakPoint, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos) { string behaviorFilename = (highlightBreakPoint != null) ? highlightBreakPoint.BehaviorFilename : FrameStatePool.GetBehaviorFilename(agentFullname, frame); if (!string.IsNullOrEmpty(behaviorFilename)) { BehaviorTreeView behaviorTreeView = ShowBehaviorTree(behaviorFilename); if (behaviorTreeView != null) { if (!Settings.Default.ShowProfilingInfo) profileInfos = null; behaviorTreeView.SetHighlights(highlightNodeIds, updatedNodeIds, highlightBreakPoint, profileInfos); //behaviorTreeView.Focus(); return behaviorTreeView.RootNode; } } return null; }
public void SetHighlights(List<string> highlightedTransitionIds, List<string> highlightedNodeIds, List<string> updatedNodeIds, HighlightBreakPoint highlightBreakPoint, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos) { bool shouldRefresh = (_highlightBreakPoint != highlightBreakPoint); if (shouldRefresh && highlightBreakPoint != null) { SelectedNode = RootNodeView.FindNodeViewData(highlightBreakPoint.NodeId); if (ClickNode != null) { ClickNode(SelectedNode); } } if (!shouldRefresh) { shouldRefresh = !compareTwoLists(_highlightedTransitionIds, highlightedTransitionIds); } if (!shouldRefresh) { shouldRefresh = !compareTwoLists(_updatedNodeIds, updatedNodeIds); } if (!shouldRefresh) { shouldRefresh = !compareTwoLists(_highlightedNodeIds, highlightedNodeIds); } if (!shouldRefresh) { shouldRefresh = !compareTwoDicts(_profileInfos, profileInfos); } _highlightedTransitionIds = highlightedTransitionIds; _highlightBreakPoint = highlightBreakPoint; _highlightedNodeIds = highlightedNodeIds; _updatedNodeIds = updatedNodeIds; _profileInfos = profileInfos; if (shouldRefresh) { List<string> allExpandedIds = new List<string>(); if (_highlightedNodeIds != null) { allExpandedIds.AddRange(_highlightedNodeIds); } if (_updatedNodeIds != null) { foreach(string id in _updatedNodeIds) { if (!allExpandedIds.Contains(id)) { allExpandedIds.Add(id); } } } bool layoutChanged = false; foreach(string id in allExpandedIds) { NodeViewData nvd = RootNodeView.FindNodeViewData(id); if (nvd != null && !nvd.CheckAllParentsExpanded()) { nvd.SetAllParentsExpanded(); this._pendingCenterBehavior = true; layoutChanged = true; } } if (layoutChanged) { LayoutChanged(); } Refresh(); } }
public void ClearHighlightBreakPoint() { _highlightBreakPoint = null; Invalidate(); }
public void ClearHighlights() { _highlightBreakPoint = null; _highlightedNodeIds = null; _updatedNodeIds = null; _highlightedTransitionIds = null; _profileInfos = null; Invalidate(); }
private void updateHighlights(string agentFullname, int frame, List<string> highlightedTransitionIds, List<string> highlightNodeIds, List<string> updatedNodeIds, HighlightBreakPoint breakPoint, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos) { if (agentFullname == Plugin.DebugAgentInstance || breakPoint != null) { BehaviorNode behavior = UIUtilities.ShowBehaviorTree(agentFullname, frame, highlightedTransitionIds, highlightNodeIds, updatedNodeIds, breakPoint, profileInfos); } }
/// <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, PointF graphMousePos, NodeViewData currentNode = null, NodeViewData selectedNode = null, List<string> highlightedNodeIds = null, List<string> updatedNodeIds = null, HighlightBreakPoint highlightBreakPoint = null, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos = null) { // draw the node count of the root node if (_rootNodeLayout.RootBehavior == _rootNodeLayout.Node) _rootNodeLayout.DrawCount(graphics); // 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, highlightedNodeIds, updatedNodeIds, _edgePen, _edgePenHighLight, _edgePenUpdate, _edgePenReadOnly, _renderDepth - 1); // draw the nodes _rootNodeLayout.Draw(graphics, _skipLabels, graphMousePos, _renderDepth, currentNode, selectedNode, highlightedNodeIds, updatedNodeIds, highlightBreakPoint, profileInfos); // 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 to the graph. /// </summary> /// <param name="graphics">The graphics object we render to.</param> /// <param name="nvd">The view data of this node for drawing.</param> /// <param name="isCurrent">Determines if the node is currently hovered over.</param> /// <param name="isSelected">Determines if the node is selected.</param> /// <param name="isDragged">Determines if the node is currently being dragged.</param> /// <param name="graphMousePos">The mouse position in the untransformed graph.</param> public void Draw(Graphics graphics, NodeViewData nvd, PointF graphMousePos, bool isCurrent, bool isSelected, bool isDragged, bool isHighlighted, bool isUpdated, HighlightBreakPoint highlightBreakPoint, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos) { #if DEBUG //ensure consistency DebugCheckIntegrity(); #endif RectangleF boundingBox = nvd.BoundingBox; // assemble the correct style Style style = _defaultStyle; Behavior b = this.Node.Behavior as Behavior; if (b != null && b.PlanningProcess != null) { FrameStatePool.PlanningState nodeState = b.PlanningProcess.GetNode(this.FullId); if (nodeState != null) { if (nodeState._bOk) { style += _planSucceededStyle; } else { style += _planFailedStyle; } } } if (isDragged) { style += _draggedStyle; } else if (isSelected) { style += _selectedStyle; } else if (isCurrent) { style += _currentStyle; } else if (isHighlighted) { style += _highlightedStyle; } else if (isUpdated) { style += _updatedStyle; } if (style.Background != null) { DrawShapeBackground(graphics, boundingBox, style.Background); } // if the node is dragged, do not render the events if (!isDragged) { // if this node is not selected, deselect the event if (!isSelected && _selectedSubItem != null) { _selectedSubItem.IsSelected = false; _selectedSubItem = null; } if (_subItems.Count > 0) { Region prevreg = graphics.Clip; // draw non parallel subitems first for (int i = 0; i < _subItems.Count; ++i) { if (!_subItems[i].ShowParallelToLabel) { // get the bounding box of the event RectangleF newclip = GetSubItemBoundingBox(boundingBox, i); graphics.Clip = new Region(newclip); _subItems[i].Draw(graphics, nvd, newclip); } } // draw parallel subitems second for (int i = 0; i < _subItems.Count; ++i) { if (_subItems[i].ShowParallelToLabel) { // get the bounding box of the event RectangleF newclip = GetSubItemBoundingBox(boundingBox, i); graphics.Clip = new Region(newclip); _subItems[i].Draw(graphics, nvd, newclip); } } // restore rendering area graphics.Clip = prevreg; } // draw the label of the node if (style.Label != null) { // calculate the height of all non-parallel subitems so we can correctly center the label float subItemsHeight = 0.0f; foreach(SubItem sub in _subItems) { if (!sub.ShowParallelToLabel) { subItemsHeight += sub.Height; } } float x = boundingBox.Left + (boundingBox.Width - _subItemParallelWidth) * 0.5f - _realLabelSize.Width * 0.5f; float y = boundingBox.Top + boundingBox.Height * 0.5f - subItemsHeight * 0.5f - _realLabelSize.Height * 0.5f; y += getTopAttachmentsHeight(); graphics.DrawString(this.DisplayLabel, _font, style.Label, x, y); //graphics.DrawRectangle(Pens.Red, boundingBox.X, boundingBox.Y, boundingBox.Width, boundingBox.Height); //graphics.DrawRectangle(Pens.Red, x, y, _realLabelSize.Width, _realLabelSize.Height); //graphics.DrawRectangle(Pens.Green, x, y, _labelSize.Width, _labelSize.Height); } } // draw the prefab border if (!string.IsNullOrEmpty(nvd.Node.PrefabName)) { _prefabStyle.Border.DashStyle = nvd.Node.IsPrefabDataDirty() ? System.Drawing.Drawing2D.DashStyle.Dash : System.Drawing.Drawing2D.DashStyle.Solid; DrawShapeBorder(graphics, boundingBox, _prefabStyle.Border); _prefabStyle.Border.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; } // draw the nodes border if (style.Border != null) { if (isHighlighted && (isCurrent || isSelected)) { //highlight border DrawShapeBorder(graphics, boundingBox, _highlightedStyle.Border); //shrink it to draw the selected/current border RectangleF rect = boundingBox; rect.Inflate(-_highlightedStyle.Border.Width, -_highlightedStyle.Border.Width); DrawShapeBorder(graphics, rect, style.Border); } else { DrawShapeBorder(graphics, boundingBox, style.Border); } } // draw the profile info if (profileInfos != null && profileInfos.Count > 0) { string fullId = nvd.FullId; if (profileInfos.ContainsKey(fullId)) { FrameStatePool.NodeProfileInfos.ProfileInfo profileInfo = profileInfos[fullId]; string timeStr = string.Format("{0:F3}", Math.Abs(profileInfo.Time)); string avgTimeStr = (profileInfo.Count <= 0) ? "0" : string.Format("{0:F3}", profileInfo.TotalTime / profileInfo.Count); string info = string.Format("{0} {1} {2}", timeStr, avgTimeStr, profileInfo.Count); SizeF txtSize = MeasureDisplayStringWidth(graphics, info, _profileFont); float x = boundingBox.Left; float y = boundingBox.Top - txtSize.Height - 2; graphics.DrawString(info, (profileInfo.Time >= 0) ? _profileBoldFont : _profileFont, Brushes.Black, x, y); } } // draw the attached condition foreach(Node.Connector connector in nvd.Connectors) { if (!connector.IsAsChild) { PointF[] vertices = getConnectorTriangle(nvd, connector); Brush brush = isCurrent && nvd.IsInExpandConnectorRange(graphMousePos) ? Brushes.Yellow : Brushes.Blue; graphics.FillPolygon(Brushes.LightGray, vertices); if (this.IsExpanded && connector.ChildCount > 0) { graphics.FillRectangle(brush, vertices[0].X + 0.5f, vertices[0].Y + 3.5f, 5.5f, 1.5f); if (!connector.IsExpanded) { graphics.FillRectangle(brush, vertices[0].X + 2.5f, vertices[0].Y + 1.5f, 1.5f, 5.5f); } } } } // draw the breakpoints bool isBreakpointHighlighted = false; const float width = 18.0f; BreakPointStates enterState = getBreakPointState(highlightBreakPoint, HighlightBreakPoint.kEnter); if (HighlightBreakPoint.ShowBreakPoint && (enterState == BreakPointStates.Normal || enterState == BreakPointStates.Disable) || enterState == BreakPointStates.Highlight) { isBreakpointHighlighted |= (enterState == BreakPointStates.Highlight); float x = boundingBox.X + width * 0.1f; float y = boundingBox.Y + (boundingBox.Height - width) * 0.5f; graphics.FillEllipse(getBrush(enterState), x, y, width, width); } BreakPointStates exitState = getBreakPointState(highlightBreakPoint, HighlightBreakPoint.kExit); if (HighlightBreakPoint.ShowBreakPoint && (exitState == BreakPointStates.Normal || exitState == BreakPointStates.Disable) || exitState == BreakPointStates.Highlight) { isBreakpointHighlighted |= (exitState == BreakPointStates.Highlight); float x = boundingBox.X + (boundingBox.Width - width) - width * 0.1f; float y = boundingBox.Y + (boundingBox.Height - width) * 0.5f; graphics.FillEllipse(getBrush(exitState), x, y, width, width); } BreakPointStates planState = getBreakPointState(highlightBreakPoint, HighlightBreakPoint.kPlanning); if (HighlightBreakPoint.ShowBreakPoint && (planState == BreakPointStates.Normal || planState == BreakPointStates.Disable) || planState == BreakPointStates.Highlight) { isBreakpointHighlighted |= (planState == BreakPointStates.Highlight); float x = boundingBox.X + (boundingBox.Width * 0.5f) - width * 0.5f; float y = boundingBox.Y + (boundingBox.Height - width) * 0.5f; graphics.FillEllipse(getBrush(planState), x, y, width, width); } // draw the expand or collapse symbol if (nvd.CanBeExpanded()) { Brush brush = isCurrent && nvd.IsInExpandRange(graphMousePos) ? Brushes.Yellow : Brushes.LightGray; graphics.FillRectangle(brush, boundingBox.X + 5.0f, boundingBox.Y + 5.0f, 12.0f, 2.0f); if (!nvd.IsExpanded) { graphics.FillRectangle(brush, boundingBox.X + 10.0f, boundingBox.Y, 2.0f, 12.0f); } } // draw node id if (ShowNodeId) { graphics.DrawString(nvd.FullId, _profileFont, isBreakpointHighlighted ? Brushes.Yellow : Brushes.White, boundingBox.X, boundingBox.Y + boundingBox.Height); } //graphics.DrawRectangle(Pens.Red, nvd.LayoutRectangle.X, nvd.LayoutRectangle.Y, nvd.LayoutRectangle.Width, nvd.LayoutRectangle.Height); }
private BreakPointStates getBreakPointState(HighlightBreakPoint highlightBreakPoint, string actionName) { Behavior behavior = RootBehavior as Behavior; if (behavior != null && !string.IsNullOrEmpty(behavior.Filename)) { string behaviorName = behavior.MakeRelative(behavior.Filename); string fullId = FullId; DebugDataPool.BreakPoint breakPoint = DebugDataPool.FindBreakPoint(behaviorName, fullId, actionName); if (breakPoint != null) { if (breakPoint.IsEnable(actionName)) { if (highlightBreakPoint != null && highlightBreakPoint.NodeId == fullId && highlightBreakPoint.ActionName == actionName) { return BreakPointStates.Highlight; } return BreakPointStates.Normal; } return BreakPointStates.Disable; } } return BreakPointStates.None; }
/// <summary> /// Draws the node to the graph. /// </summary> /// <param name="graphics">The graphics object we render to.</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> /// <param name="currentNode">The current node under the mouse cursor.</param> /// <param name="selectedNode">The currently selected node.</param> public void Draw(Graphics graphics, bool isDragged, PointF graphMousePos, int renderDepth, NodeViewData currentNode, NodeViewData selectedNode, List<string> highlightedNodeIds, List<string> updatedNodeIds, HighlightBreakPoint highlightBreakPoint, Dictionary<string, FrameStatePool.NodeProfileInfos.ProfileInfo> profileInfos) { bool isHighlighted = (highlightedNodeIds != null) && highlightedNodeIds.Contains(FullId); bool isUpdated = (updatedNodeIds != null) && updatedNodeIds.Contains(FullId); Draw(graphics, this, graphMousePos, (currentNode == null) ? false : (Node == currentNode.Node), (selectedNode == null) ? false : (Node == selectedNode.Node), isDragged, isHighlighted, isUpdated, highlightBreakPoint, profileInfos); // draw children if (IsExpanded && renderDepth > 0) { foreach(NodeViewData child in _children) { if (child.ParentConnector != null && (child.ParentConnector.IsAsChild || child.ParentConnector.IsExpanded)) { child.Draw(graphics, isDragged, graphMousePos, renderDepth - 1, currentNode, selectedNode, highlightedNodeIds, updatedNodeIds, highlightBreakPoint, profileInfos); } } } // draw FSM nodes foreach(NodeViewData child in this.FSMNodes) { child.Draw(graphics, isDragged, graphMousePos, renderDepth - 1, currentNode, selectedNode, highlightedNodeIds, updatedNodeIds, highlightBreakPoint, profileInfos); } }