public DeltaHistogram() { base.GetItemValue = (di) => di.BytesDelta; base.GetItemText = (di) => di.Traceback.Frames.Array[di.Traceback.Frames.Offset].Function; base.GetItemTooltip = (di) => { var sf = CustomTooltip.GetDefaultStringFormat(); var content = new DeltaInfoTooltipContent( di, new DeltaInfo.RenderParams { BackgroundBrush = new SolidBrush(SystemColors.Info), BackgroundColor = SystemColors.Info, TextBrush = new SolidBrush(SystemColors.InfoText), IsExpanded = true, IsSelected = false, FunctionHighlightBrush = new SolidBrush(SystemColors.Highlight), FunctionHighlightTextBrush = new SolidBrush(SystemColors.HighlightText), FunctionFilter = FunctionFilter, ShadeBrush = new SolidBrush(Color.FromArgb(31, 0, 0, 0)), StringFormat = sf } ); return(content); }; }
protected void ShowTooltip(int itemIndex, Point location) { if (Tooltip == null) { Tooltip = new CustomTooltip(this); } var item = Items[itemIndex]; using (var g = CreateGraphics()) { var content = GetItemTooltip(item); content.Font = Font; content.Location = PointToScreen(location); CustomTooltip.FitContentOnScreen( g, content, ref content.Font, ref content.Location, ref content.Size ); Tooltip.SetContent(content); } if (_HoverIndex != itemIndex) { var oldIndex = _HoverIndex; _HoverIndex = itemIndex; InvalidateItem(oldIndex); InvalidateItem(_HoverIndex); } }
protected IEnumerator <object> FinishShowingTooltip( Point mouseLocation, HeapSnapshot.Heap heap, HeapSnapshot.Allocation allocation, HeapSnapshot.Traceback rawTraceback ) { var uniqueRawFrames = rawTraceback.Frames.AsEnumerable().Distinct(); var fSymbols = Instance.Database.SymbolCache.Select(uniqueRawFrames); using (fSymbols) yield return(fSymbols); var symbolDict = SequenceUtils.ToDictionary( uniqueRawFrames, fSymbols.Result ); var tracebackInfo = HeapRecording.ConstructTracebackInfo( rawTraceback.ID, rawTraceback.Frames, symbolDict ); var renderParams = new DeltaInfo.RenderParams { BackgroundBrush = new SolidBrush(SystemColors.Info), BackgroundColor = SystemColors.Info, TextBrush = new SolidBrush(SystemColors.InfoText), IsExpanded = true, IsSelected = false, Font = Font, ShadeBrush = new SolidBrush(Color.FromArgb(31, 0, 0, 0)), StringFormat = CustomTooltip.GetDefaultStringFormat() }; var content = new HeapSnapshot.AllocationTooltipContent( ref allocation, ref tracebackInfo, ref renderParams ) { Location = mouseLocation, Font = Font }; using (var g = CreateGraphics()) CustomTooltip.FitContentOnScreen( g, content, ref content.RenderParams.Font, ref content.Location, ref content.Size ); Tooltip.SetContent(content); }
public GraphHistogram() { base.GetItemValue = (sgn) => sgn.BytesRequested; base.GetItemText = (sgn) => sgn.Key.ToString(); base.GetItemTooltip = (sgn) => { var sf = CustomTooltip.GetDefaultStringFormat(); TooltipContentBase content = new StackGraphTooltipContent( sgn, sf ); return(content); }; }
protected void ShowTooltip(int itemIndex, Point location) { if (Tooltip == null) { Tooltip = new CustomTooltip(this); } var item = Items[itemIndex]; var sf = CustomTooltip.GetDefaultStringFormat(); using (var g = CreateGraphics()) { var content = new DeltaInfoTooltipContent( item, new DeltaInfo.RenderParams { BackgroundBrush = new SolidBrush(SystemColors.Info), BackgroundColor = SystemColors.Info, TextBrush = new SolidBrush(SystemColors.InfoText), IsExpanded = true, IsSelected = false, FunctionHighlightBrush = new SolidBrush(SystemColors.Highlight), FunctionHighlightTextBrush = new SolidBrush(SystemColors.HighlightText), FunctionFilter = FunctionFilter, Font = Font, ShadeBrush = new SolidBrush(Color.FromArgb(31, 0, 0, 0)), StringFormat = sf } ) { Location = this.PointToScreen(location) }; CustomTooltip.FitContentOnScreen( g, content, ref content.RenderParams.Font, ref content.Location, ref content.Size ); Tooltip.SetContent(content); } if (_HoverIndex != itemIndex) { var oldIndex = _HoverIndex; _HoverIndex = itemIndex; InvalidateItem(oldIndex); InvalidateItem(_HoverIndex); } }
protected void ShowTooltip(LayoutItem item, Point location) { if (Tooltip == null) { Tooltip = new CustomTooltip(this); } using (var g = CreateGraphics()) { var content = GetItemTooltip(item.Item); content.Font = Font; content.Location = PointToScreen(new Point( (int)item.Rectangle.Left, (int)item.Rectangle.Bottom + 2 )); CustomTooltip.FitContentOnScreen( g, content, ref content.Font, ref content.Location, ref content.Size ); Tooltip.SetContent(content); } if (_HoverItem != item) { var oldItem = _HoverItem; _HoverItem = item; if (oldItem != null) { Invalidate(oldItem.Rectangle); } Invalidate(item.Rectangle); } }
protected override void OnMouseMove(MouseEventArgs e) { HeapSnapshot.Heap heap; int allocationIndex; if (AllocationFromPoint(e.Location, out heap, out allocationIndex)) { if ((heap != TooltipHeap) || (allocationIndex != TooltipAllocationIndex)) { TooltipAllocationIndex = allocationIndex; TooltipHeap = heap; if (Tooltip == null) { Tooltip = new CustomTooltip(this); } Instance.Scheduler.Start( FinishShowingTooltip( PointToScreen(e.Location), heap, heap.Allocations[allocationIndex], Snapshot.Tracebacks[heap.Allocations[allocationIndex].TracebackID] ), TaskExecutionPolicy.RunAsBackgroundTask ); Invalidate(); } } else { HideTooltip(); base.OnMouseMove(e); } }
protected override void OnMouseMove(MouseEventArgs e) { HeapSnapshot.Heap heap; int allocationIndex; if (AllocationFromPoint(e.Location, out heap, out allocationIndex)) { if ((heap != TooltipHeap) || (allocationIndex != TooltipAllocationIndex)) { TooltipAllocationIndex = allocationIndex; TooltipHeap = heap; if (Tooltip == null) Tooltip = new CustomTooltip(this); Instance.Scheduler.Start( FinishShowingTooltip( PointToScreen(e.Location), heap, heap.Allocations[allocationIndex], Snapshot.Tracebacks[heap.Allocations[allocationIndex].TracebackID] ), TaskExecutionPolicy.RunAsBackgroundTask ); Invalidate(); } } else { HideTooltip(); base.OnMouseMove(e); } }
protected override void OnPaint(PaintEventArgs e) { bool retrying = false, selectedItemVisible = false; int minVisibleIndex = int.MaxValue, maxVisibleIndex = -int.MaxValue; int width = ClientSize.Width - ScrollBar.Width; float centerX = width / 2.0f; float max = GraphLog(Maximum); retryFromHere: if (_SelectedIndex >= Items.Count) { _SelectedIndex = Items.Count - 1; } if (_SelectedIndex < 0) { _SelectedIndex = 0; } if (_ScrollOffset >= Items.Count) { _ScrollOffset = Items.Count - 1; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } VisibleItems.Clear(); ItemData data; HashSet <string> textToFlush = new HashSet <string>(TextCache.Keys); using (var sf = CustomTooltip.GetDefaultStringFormat()) using (var gridLineFont = new Font(Font.FontFamily, Font.Size * 0.85f, Font.Style)) using (var outlinePen = new Pen(Color.Black)) using (var activeOutlinePen = new Pen(SystemColors.HighlightText)) using (var gridPen = new Pen(Color.FromArgb(96, 0, 0, 0))) using (var backgroundBrush = new SolidBrush(BackColor)) using (var whiteOutlinePen = new Pen(Color.White, 2.5f)) using (var blackOutlinePen = new Pen(Color.Black, 2.5f)) using (var textBrush = new SolidBrush(ForeColor)) using (var highlightBrush = new SolidBrush(SystemColors.Highlight)) { blackOutlinePen.LineJoin = whiteOutlinePen.LineJoin = LineJoin.Round; int marginHeight = 0; for (int i = Maximum; i >= Math.Min(Maximum, 16); i /= 4) { marginHeight = Math.Max(marginHeight, (int)Math.Ceiling(e.Graphics.MeasureString( "+" + FormatSize(i), gridLineFont, ClientSize.Height, sf ).Width) + 1 ); } var rgn = new Rectangle(0, 0, width, marginHeight); if (rgn.IntersectsWith(e.ClipRectangle)) { using (var scratch = Scratch.Get(e.Graphics, rgn)) { var g = scratch.Graphics; g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, centerX, 0, centerX, marginHeight); for (int i = Maximum; i >= Math.Min(Maximum, 16); i /= 4) { float x = (GraphLog(i) / max) * (width / 2.0f); var formatted = FormatSize(i); g.DrawLine(gridPen, centerX + x, 0, centerX + x, marginHeight); var text = String.Format("+{0}", formatted); textToFlush.Remove(text); var bitmap = TextCache.Get(g, text, gridLineFont, RotateFlipType.Rotate90FlipNone, ForeColor, BackColor, sf, new SizeF(marginHeight, 999)); g.DrawImageUnscaled(bitmap, (int)(centerX + x), 0); g.DrawLine(gridPen, centerX - x, 0, centerX - x, marginHeight); text = String.Format("-{0}", formatted); textToFlush.Remove(text); bitmap = TextCache.Get(g, text, gridLineFont, RotateFlipType.Rotate90FlipNone, ForeColor, BackColor, sf, new SizeF(marginHeight, 999)); g.DrawImageUnscaled(bitmap, (int)(centerX - x - bitmap.Width), 0); } } } int y = marginHeight; rgn = new Rectangle(0, y, width, ItemHeight); if ((TotalDelta.GetValueOrDefault(0) != 0) && rgn.IntersectsWith(e.ClipRectangle)) { using (var scratch = Scratch.Get(e.Graphics, rgn)) { var barRectangle = ComputeBarRectangle( TotalDelta.Value, centerX, rgn.Y, width, max ); var g = scratch.Graphics; g.ResetClip(); g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, centerX, rgn.Y, centerX, rgn.Bottom); g.DrawRectangle( outlinePen, barRectangle.X, barRectangle.Y, barRectangle.Width, barRectangle.Height ); var oldRenderingHint = g.TextRenderingHint; try { g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.DrawString("Delta bytes", Font, textBrush, barRectangle.X, barRectangle.Y, sf); } finally { g.TextRenderingHint = oldRenderingHint; } } } if ((TotalDelta.GetValueOrDefault(0) != 0)) { y += ItemHeight; } for (int i = _ScrollOffset; (i < Items.Count) && (y < ClientSize.Height); i++) { var selected = (i == SelectedIndex); var item = Items[i]; GetItemData(i, out data); rgn = new Rectangle(0, y, width, ItemHeight); var bytesDelta = GetItemValue(item); var barRectangle = ComputeBarRectangle( bytesDelta, centerX, rgn.Y, width, max ); var itemColor = SelectItemColor(item); if (rgn.IntersectsWith(e.ClipRectangle)) { using (var itemBrush = new SolidBrush(itemColor)) using (var scratch = Scratch.Get(e.Graphics, rgn)) { var g = scratch.Graphics; g.ResetClip(); g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, centerX, rgn.Y, centerX, rgn.Bottom); g.FillRectangle( (_HoverIndex == i) ? highlightBrush : itemBrush, barRectangle ); g.DrawRectangle( (_HoverIndex == i) ? activeOutlinePen : outlinePen, barRectangle.X - 0.5f, barRectangle.Y - 0.5f, barRectangle.Width + 1f, barRectangle.Height + 1f ); string itemText = null; if ((GetItemText != null) && (itemText = GetItemText(item)) != null) { bool white = (itemColor.GetBrightness() <= 0.25f); textToFlush.Remove(itemText); var bitmap = TextCache.Get( g, itemText, Font, RotateFlipType.RotateNoneFlipNone, white ? Color.White : Color.Black, white ? Color.Black : Color.LightGray, sf, new SizeF(barRectangle.Width, barRectangle.Height) ); g.DrawImageUnscaled( bitmap, (int)Math.Floor(barRectangle.X), (int)Math.Floor(barRectangle.Y) ); } } } VisibleItems.Add(new VisibleItem { Rectangle = new Rectangle( (int)Math.Floor(barRectangle.X), (int)Math.Floor(barRectangle.Y), (int)Math.Ceiling(barRectangle.Width), (int)Math.Ceiling(barRectangle.Height) ), Index = i }); y += ItemHeight; if ((rgn.X >= 0) && (rgn.Right < ClientSize.Width)) { minVisibleIndex = Math.Min(minVisibleIndex, i); maxVisibleIndex = Math.Max(maxVisibleIndex, i); selectedItemVisible |= selected; } } if (y < ClientSize.Height) { e.Graphics.FillRectangle(backgroundBrush, new Rectangle(0, y, ClientSize.Width, ClientSize.Height - y)); e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; e.Graphics.DrawLine(gridPen, centerX, y, centerX, ClientSize.Height); } } if (!selectedItemVisible && !retrying && ShouldAutoscroll) { if (_SelectedIndex > maxVisibleIndex) { _ScrollOffset += _SelectedIndex - maxVisibleIndex; } else if (_SelectedIndex < minVisibleIndex) { _ScrollOffset -= minVisibleIndex - _SelectedIndex; } if (_ScrollOffset >= Items.Count) { _ScrollOffset = Items.Count - 1; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } retrying = true; goto retryFromHere; } int largeChange = Math.Max(4, ClientSize.Width / ItemHeight); if (ScrollBar.LargeChange != largeChange) { ScrollBar.LargeChange = largeChange; } int scrollMax = Math.Max(1, Items.Count - 1) + largeChange - 1; if (ScrollBar.Maximum != scrollMax) { ScrollBar.Maximum = scrollMax; } if (ScrollBar.Value != ScrollOffset) { ScrollBar.Value = ScrollOffset; } TextCache.Flush(textToFlush); ShouldAutoscroll = false; base.OnPaint(e); }
protected override void OnPaint(PaintEventArgs e) { bool retrying = false, selectedItemVisible = false; int minVisibleIndex = int.MaxValue, maxVisibleIndex = -int.MaxValue; int height = ClientSize.Height - ScrollBar.Height; float centerY = height / 2.0f; float max = GraphLog(Maximum); retryFromHere: if (_SelectedIndex >= Items.Count) { _SelectedIndex = Items.Count - 1; } if (_SelectedIndex < 0) { _SelectedIndex = 0; } if (_ScrollOffset >= Items.Count) { _ScrollOffset = Items.Count - 1; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } VisibleItems.Clear(); ItemData data; using (var sf = CustomTooltip.GetDefaultStringFormat()) using (var gridLineFont = new Font(Font.FontFamily, Font.Size * 0.85f, Font.Style)) using (var outlinePen = new Pen(Color.Black)) using (var activeOutlinePen = new Pen(SystemColors.HighlightText)) using (var gridPen = new Pen(Color.FromArgb(96, 0, 0, 0))) using (var backgroundBrush = new SolidBrush(BackColor)) using (var textBrush = new SolidBrush(ForeColor)) using (var highlightBrush = new SolidBrush(SystemColors.Highlight)) { int marginWidth = 0; for (int i = Maximum; i >= Math.Min(Maximum, 16); i /= 4) { marginWidth = Math.Max(marginWidth, (int)Math.Ceiling(e.Graphics.MeasureString( "+" + FormatSize(i), gridLineFont, ClientSize.Width, sf ).Width) + 1 ); } var rgn = new Rectangle(0, 0, marginWidth, height); if (rgn.IntersectsWith(e.ClipRectangle)) { using (var scratch = Scratch.Get(e.Graphics, rgn)) { var g = scratch.Graphics; g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, 0, centerY, marginWidth, centerY); for (int i = Maximum; i >= Math.Min(Maximum, 16); i /= 4) { float y = (GraphLog(i) / max) * (height / 2.0f); var formatted = FormatSize(i); g.DrawLine(gridPen, 0, centerY - y, marginWidth, centerY - y); var text = String.Format("+{0}", formatted); g.DrawString(text, gridLineFont, textBrush, new PointF(0, centerY - y)); g.DrawLine(gridPen, 0, centerY + y, marginWidth, centerY + y); text = String.Format("-{0}", formatted); var sz = g.MeasureString(text, gridLineFont, marginWidth, sf); g.DrawString(text, gridLineFont, textBrush, new PointF(0, centerY + y - sz.Height)); } } } int x = marginWidth; rgn = new Rectangle(x, 0, ItemWidth, height); if ((TotalDelta.GetValueOrDefault(0) != 0) && rgn.IntersectsWith(e.ClipRectangle)) { using (var scratch = Scratch.Get(e.Graphics, rgn)) { var barRectangle = ComputeBarRectangle( TotalDelta.Value, rgn.X, centerY, height, max ); var g = scratch.Graphics; g.ResetClip(); g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, rgn.X, centerY, rgn.Right, centerY); g.DrawRectangle( outlinePen, barRectangle.X, barRectangle.Y, barRectangle.Width, barRectangle.Height ); var oldTransform = g.Transform; var oldAlignment = sf.LineAlignment; var oldRenderingHint = g.TextRenderingHint; try { g.ResetTransform(); g.RotateTransform(90); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; sf.LineAlignment = StringAlignment.Far; g.DrawString("Delta bytes", Font, textBrush, Math.Min(barRectangle.Y, barRectangle.Bottom), 0f, sf); } finally { sf.LineAlignment = oldAlignment; g.Transform = oldTransform; g.TextRenderingHint = oldRenderingHint; } } } if ((TotalDelta.GetValueOrDefault(0) != 0)) { x += ItemWidth; } for (int i = _ScrollOffset; (i < Items.Count) && (x < ClientSize.Width); i++) { var selected = (i == SelectedIndex); var item = Items[i]; GetItemData(i, out data); rgn = new Rectangle(x, 0, ItemWidth, height); var barRectangle = ComputeBarRectangle( item.BytesDelta * (item.Added ? 1 : -1), rgn.X, centerY, height, max ); if (rgn.IntersectsWith(e.ClipRectangle)) { using (var itemBrush = new SolidBrush(SelectItemColor(ref item))) using (var scratch = Scratch.Get(e.Graphics, rgn)) { var g = scratch.Graphics; g.ResetClip(); g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawLine(gridPen, rgn.X, centerY, rgn.Right, centerY); g.FillRectangle( (_HoverIndex == i) ? highlightBrush : itemBrush, barRectangle ); g.DrawRectangle( (_HoverIndex == i) ? activeOutlinePen : outlinePen, barRectangle.X - 0.5f, barRectangle.Y - 0.5f, barRectangle.Width + 1f, barRectangle.Height + 1f ); } } VisibleItems.Add(new VisibleItem { Rectangle = new Rectangle( (int)Math.Floor(barRectangle.X), (int)Math.Floor(barRectangle.Y), (int)Math.Ceiling(barRectangle.Width), (int)Math.Ceiling(barRectangle.Height) ), Index = i }); x += ItemWidth; if ((rgn.X >= 0) && (rgn.Right < ClientSize.Width)) { minVisibleIndex = Math.Min(minVisibleIndex, i); maxVisibleIndex = Math.Max(maxVisibleIndex, i); selectedItemVisible |= selected; } } if (x < ClientSize.Width) { e.Graphics.FillRectangle(backgroundBrush, new Rectangle(x, 0, ClientSize.Width - x, ClientSize.Height)); e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; e.Graphics.DrawLine(gridPen, x, centerY, ClientSize.Width, centerY); } } if (!selectedItemVisible && !retrying && ShouldAutoscroll) { if (_SelectedIndex > maxVisibleIndex) { _ScrollOffset += _SelectedIndex - maxVisibleIndex; } else if (_SelectedIndex < minVisibleIndex) { _ScrollOffset -= minVisibleIndex - _SelectedIndex; } if (_ScrollOffset >= Items.Count) { _ScrollOffset = Items.Count - 1; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } retrying = true; goto retryFromHere; } int largeChange = Math.Max(4, ClientSize.Width / ItemWidth); if (ScrollBar.LargeChange != largeChange) { ScrollBar.LargeChange = largeChange; } int scrollMax = Math.Max(1, Items.Count - 1) + largeChange - 1; if (ScrollBar.Maximum != scrollMax) { ScrollBar.Maximum = scrollMax; } if (ScrollBar.Value != ScrollOffset) { ScrollBar.Value = ScrollOffset; } ShouldAutoscroll = false; base.OnPaint(e); }