public void DrawTheadline() { if (DoRevalue) { RecalcCover(InternalRoot); RecalcCover(ExternalRoot); DoRevalue = false; RevalueCount++; DoResize = true; } // set what nodes are allowed in the threadline based on the current root if (CurrentThreadlineZoom != CurrentRoot) { CenterMap.Clear(); CenterMap.Add(CurrentRoot.ID); Utilities.RecurseTree <NodeModel>( tree: CurrentRoot.Nodes, evaluate: n => CenterMap.Add(n.ID), recurse: n => n.Nodes); CurrentThreadlineZoom = CurrentRoot; } long currentTick = XRay.Watch.ElapsedTicks; if (!Paused) { CalcThreadline(currentTick); } LayoutThreadlines(currentTick); }
public void DrawCallGraph() { if (DoRevalue || XRay.CallChange || (ShowLayout != ShowNodes.All && XRay.CoverChange) || (ShowLayout == ShowNodes.Instances && XRay.InstanceChange)) { RecalcCover(InternalRoot); RecalcCover(ExternalRoot); PositionMap.Clear(); CenterMap.Clear(); var root = CurrentRoot; //causes method graph with ShowExternal on to show nothing //if (root == InternalRoot && ShowExternal) // root = TopRoot; TopGraph = new GraphSet(this, root); // combine position and center maps for graph tree Utilities.RecurseTree( TopGraph, s => { foreach (var kvp in s.PositionMap) { PositionMap[kvp.Key] = kvp.Value; } foreach (var id in s.CenterMap) { CenterMap.Add(id); } }, s => s.Subsets.Values ); XRay.CallChange = false; XRay.CoverChange = false; XRay.InstanceChange = false; DoRevalue = false; RevalueCount++; DoResize = true; } // graph created in relative coords so it doesnt need to be re-computed each resize, only on recalc if (DoResize) { Utilities.RecurseTree( TopGraph, s => { foreach (var graph in s.Graphs) { if (s.GraphContainer == null) { ScaleGraph(graph, new RectangleF(ScreenOffset, ScreenSize)); } else if (s.GraphContainer.XNode.External) { // this is assuming the external node is a triangle var area = s.GraphContainer.AreaF; var inside = new RectangleF(area.X + area.Width / 4f, area.Y + area.Height / 2f, area.Width / 2f, area.Height / 2f); ScaleGraph(graph, inside); } else { ScaleGraph(graph, s.GraphContainer.AreaF); } } }, s => s.Subsets.Values ); DoResize = false; ResizeCount++; } }
private void SizeNode(IRenderer Renderer, NodeModel root, NodeModel exclude, bool center) { if (!root.Show) { return; } RectangleF insideArea = root.AreaF; if (ShowLabels) { // check if enough room in root box for label var labelSpace = root.AreaF; labelSpace.Width -= LabelPadding * 2.0f; labelSpace.Height -= LabelPadding * 2.0f; var labelSize = new RectangleF(root.AreaF.Location, Renderer.MeasureString(root.Name, TextFont)); float minHeight = (root.Nodes.Count > 0) ? labelSize.Height * 2.0f : labelSize.Height; if (minHeight < labelSpace.Height && labelSize.Width / 3f < labelSpace.Width) { labelSize.X += LabelPadding; labelSize.Y += LabelPadding; if (labelSpace.Width < labelSize.Width) { root.LabelClipped = true; labelSize.Width = labelSpace.Width; } insideArea.Y += labelSize.Height; insideArea.Height -= labelSize.Height; root.RoomForLabel = true; root.LabelRect = labelSize; } } List <Sector> sectors = new TreeMap(root, exclude, insideArea.Size).Results; foreach (Sector sector in sectors) { var node = sector.OriginalValue; sector.Rect = RectangleExtensions.Contract(sector.Rect, NodeBorderWidth); if (sector.Rect.X < NodeBorderWidth) { sector.Rect.X = NodeBorderWidth; } if (sector.Rect.Y < NodeBorderWidth) { sector.Rect.Y = NodeBorderWidth; } if (sector.Rect.X > insideArea.Width - NodeBorderWidth) { sector.Rect.X = insideArea.Width - NodeBorderWidth; } if (sector.Rect.Y > insideArea.Height - NodeBorderWidth) { sector.Rect.Y = insideArea.Height - NodeBorderWidth; } sector.Rect.X += insideArea.X; sector.Rect.Y += insideArea.Y; node.SetArea(sector.Rect); PositionMap[node.ID] = node; node.RoomForLabel = false; // cant do above without graphic artifacts node.LabelClipped = false; if (center) { CenterMap.Add(node.ID); } if (sector.Rect.Width > 1.0f && sector.Rect.Height > 1.0f) { SizeNode(Renderer, node, exclude, center); } } }