protected override void OnPaint(PaintEventArgs e) { int height = ClientSize.Height; int pixelsPerHour = (PixelsPerHour * (_Scrollable ? ZoomRatio : 128)) / 128; long maxValue = MaximumThreshold; long minTicks = 0, maxTicks = 0; int contentWidth; const long hourInTicks = Squared.Util.Time.SecondInTicks * 60 * 60; if (Items.Count > 0) { maxValue = Math.Max(MaximumThreshold, (from s in Items select _ItemValueGetter(s)).Max()); minTicks = (from s in Items select s.Timestamp.Ticks).Min(); maxTicks = (from s in Items select s.Timestamp.Ticks).Max(); bool rescaled = false; rescale: _ContentWidth = contentWidth = (int)( (maxTicks - minTicks) * pixelsPerHour / hourInTicks ) + MarginWidth; if (!_Scrollable && !rescaled) { var ratio = (ClientSize.Width / (double)(contentWidth + 1)) * 128.0; _ZoomRatio = (int)Math.Floor(ratio); if (_ZoomRatio < 1) { _ZoomRatio = 1; } pixelsPerHour = (PixelsPerHour * _ZoomRatio) / 128; if (pixelsPerHour < 1) { pixelsPerHour = 1; } rescaled = true; goto rescale; } } else { _ContentWidth = contentWidth = MarginWidth; } if (_Scrollable) { height -= ScrollBar.Height; if (_ScrollOffset > contentWidth - ClientSize.Width) { _ScrollOffset = contentWidth - ClientSize.Width; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } int scrollMax = contentWidth - ClientSize.Width + ScrollBar.LargeChange - 1; bool enabled = (scrollMax > 0); if (scrollMax < 0) { scrollMax = 0; } // WinForms' scrollbar control is terrible if (ScrollBar.Maximum != scrollMax) { ScrollBar.Maximum = scrollMax; } if (ScrollBar.Value != _ScrollOffset) { ScrollBar.Value = _ScrollOffset; } if (ScrollBar.Enabled != enabled) { ScrollBar.Enabled = enabled; } if (!ScrollBar.Visible) { ScrollBar.Visible = true; } if (!ZoomInButton.Visible) { ZoomInButton.Visible = true; } if (!ZoomOutButton.Visible) { ZoomOutButton.Visible = true; } } else { if (ScrollBar.Visible) { ScrollBar.Visible = false; } if (ZoomInButton.Visible) { ZoomInButton.Visible = false; } if (ZoomOutButton.Visible) { ZoomOutButton.Visible = false; } _ScrollOffset = 0; } using (var outlinePen = new Pen(Color.Black)) using (var gridPen = new Pen(Color.FromArgb(96, 0, 0, 0))) using (var scratch = Scratch.Get(e.Graphics, ClientRectangle)) { var g = scratch.Graphics; g.Clear(BackColor); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; float y = 0; using (var textBrush = new SolidBrush(ForeColor)) { g.DrawLine(gridPen, 0, height - VerticalMargin, ClientSize.Width, height - VerticalMargin); g.DrawLine(gridPen, 0, VerticalMargin, Width, VerticalMargin); var lineHeight = g.MeasureString("AaBbYyZz", Font).Height; var numLines = (int)Math.Min( Math.Max(2, Math.Floor((height / lineHeight) * GridLineRatio)), MaxGridLines ); for (int i = 0; i <= numLines; i++) { var value = (maxValue * i / numLines); var text = _ItemValueFormatter(value); y = (float)(height - VerticalMargin - ((value / (double)maxValue) * (height - VerticalMargin * 2))); g.DrawLine(gridPen, 0, y, ClientSize.Width, y); g.DrawString(text, Font, textBrush, new PointF(4, y)); } } var itemXCoordinates = (from item in Items select (int)((item.Timestamp.Ticks - minTicks) * pixelsPerHour / hourInTicks ) - _ScrollOffset).ToArray(); var itemYCoordinates = (from item in Items select (float)(height - VerticalMargin - ( (_ItemValueGetter(item) / (double)maxValue) * (height - VerticalMargin * 2) ))); var valueSeriesYCoordinates = ( from series in DataSeries.Values select( from value in series select (float)(height - VerticalMargin - ( (value / (double)maxValue) * (height - VerticalMargin * 2) )) ) ); var firstIndex = Math.Max(0, IndexFromPoint(new Point(0, 0), -1)); using (var brush = new SolidBrush(Color.FromArgb(127, ForeColor))) DrawValueSeries( g, itemXCoordinates.Skip(firstIndex), itemYCoordinates.Skip(firstIndex), ClientSize.Width, height, brush, outlinePen ); int seriesIndex = 0; foreach (var series in valueSeriesYCoordinates) { int hue = (HSV.HueMax * seriesIndex) / DataSeries.Count; var seriesColor = HSV.ColorFromHSV( (UInt16)hue, HSV.SaturationMax, HSV.ValueMax ); using (var brush = new SolidBrush(Color.FromArgb(15, seriesColor))) using (var pen = new Pen(Color.FromArgb(160, seriesColor))) DrawValueSeries( g, itemXCoordinates.Skip(firstIndex), series.Skip(firstIndex), ClientSize.Width, height, brush, pen ); seriesIndex += 1; } firstIndex = Selection.First; var takeCount = Selection.Second - Selection.First + 1; using (var brush = new SolidBrush(SystemColors.Highlight)) using (var pen = new Pen(SystemColors.HighlightText) { Width = 2.0f }) DrawValueSeries( g, itemXCoordinates.Skip(firstIndex).Take(takeCount), itemYCoordinates.Skip(firstIndex).Take(takeCount), ClientSize.Width, height, brush, pen ); var cursorPos = PointToClient(Cursor.Position); DateTime mouseTime; if (ClientRectangle.Contains(cursorPos) && TimeFromPoint(_MouseMoveLocation, out mouseTime)) { using (var pen = new Pen(Color.FromArgb(127, SystemColors.HighlightText))) { pen.Width = 2.0f; g.DrawLine(pen, _MouseMoveLocation.X, 0, _MouseMoveLocation.X, height); } var mouseIndex = IndexFromTime(mouseTime, -1); if (!_MouseDownLocation.HasValue) { using (var pen = new Pen(SystemColors.HighlightText)) { pen.Width = 2.0f; var item = Items[mouseIndex]; var x = (int)((item.Timestamp.Ticks - minTicks) * pixelsPerHour / hourInTicks) - _ScrollOffset; g.DrawLine( pen, x, 0, x, height ); } } } } }
protected override void OnPaint(PaintEventArgs e) { bool retrying = false, selectedItemVisible = false; int minVisibleIndex = int.MaxValue, maxVisibleIndex = int.MinValue; var width = ClientSize.Width - ScrollBar.Width; 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 = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Near, FormatFlags = StringFormatFlags.FitBlackBox | StringFormatFlags.NoWrap | StringFormatFlags.DisplayFormatControl | StringFormatFlags.MeasureTrailingSpaces, HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None, Trimming = StringTrimming.None }) using (var shadeBrush = new SolidBrush(Color.FromArgb(31, 0, 0, 0))) using (var elideBackgroundBrush = new SolidBrush(Color.FromArgb(192, SystemColors.Window))) using (var elideTextBrush = new SolidBrush(Color.FromArgb(220, SystemColors.WindowText))) using (var backgroundBrush = new SolidBrush(BackColor)) using (var textBrush = new SolidBrush(ForeColor)) using (var highlightBrush = new SolidBrush(SystemColors.Highlight)) using (var highlightTextBrush = new SolidBrush(SystemColors.HighlightText)) { var lineHeight = e.Graphics.MeasureString("AaBbYyZz", Font, width, sf).Height; CollapsedSize = (int)Math.Ceiling(lineHeight * 3); var renderParams = new DeltaInfo.RenderParams { Font = Font, FunctionFilter = FunctionFilter, FunctionHighlightBrush = highlightBrush, FunctionHighlightTextBrush = highlightTextBrush, ElideBackgroundBrush = elideBackgroundBrush, ElideTextBrush = elideTextBrush, ShadeBrush = shadeBrush, StringFormat = sf, }; int y = 0; for (int i = _ScrollOffset; (i < Items.Count) && (y < ClientSize.Height); i++) { var y1 = y; var selected = (i == SelectedIndex); var item = Items[i]; GetItemData(i, out data); var rgn = new Rectangle( 0, y, width, data.Expanded ? (int)Math.Ceiling(lineHeight * (item.Traceback.Frames.Count + 1)) : CollapsedSize ); using (var scratch = Scratch.Get(e.Graphics, rgn)) { var g = scratch.Graphics; g.ResetClip(); g.Clear(selected ? highlightBrush.Color : backgroundBrush.Color); renderParams.BackgroundColor = selected ? highlightBrush.Color : backgroundBrush.Color; renderParams.BackgroundBrush = selected ? highlightBrush : backgroundBrush; renderParams.TextBrush = selected ? highlightTextBrush : textBrush; renderParams.ContentRegion = rgn; renderParams.IsExpanded = data.Expanded; renderParams.IsSelected = selected; y += (int)Math.Ceiling(item.Render(g, ref renderParams)); } VisibleItems.Add(new VisibleItem { Y1 = y1, Y2 = y, Index = i }); if ((y1 >= 0) && (y < ClientSize.Height) || ((y - y1) >= ClientSize.Height)) { 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)); } } 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.Height / CollapsedSize); 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); }
protected override void OnPaint(PaintEventArgs e) { if (Snapshot == null) { e.Graphics.Clear(BackColor); return; } var width = ClientSize.Width - ScrollBar.Width; var bytesPerRow = BytesPerRow; var contentHeight = ContentHeight; if (_ScrollOffset >= contentHeight) { _ScrollOffset = contentHeight - 1; } if (_ScrollOffset < 0) { _ScrollOffset = 0; } using (var shadeBrush = new SolidBrush(SystemColors.ControlLight)) using (var backgroundBrush = new SolidBrush(BackColor)) { foreach (var vh in WalkHeaps(Snapshot, _ScrollOffset, bytesPerRow, width)) { var rgn = new Rectangle(0, vh.FirstRow * RowHeight, width, vh.HeightInRows * RowHeight); if (rgn.Y > ClientSize.Height) { break; } if (rgn.Bottom < 0) { continue; } var clippedRgn = rgn; clippedRgn.Intersect(e.ClipRectangle); if (rgn.IntersectsWith(e.ClipRectangle)) { using (var scratch = Scratch.Get(e.Graphics, clippedRgn)) { var g = scratch.Graphics; g.SmoothingMode = SmoothingMode.None; g.ResetClip(); g.Clear(shadeBrush.Color); foreach (var vha in WalkHeapAllocations(vh.Heap, bytesPerRow, vh.FirstRow, width)) { if (vha.Rectangle.Y < 0) { continue; } if (vha.Rectangle.Bottom > ClientSize.Height) { break; } bool isSelected = (vha.Index == TooltipAllocationIndex) && (vha.Heap == TooltipHeap); Color itemColor; if (isSelected) { itemColor = SystemColors.Highlight; } else { itemColor = SelectItemColor(vha.Allocation); } using (var brush = new SolidBrush(itemColor)) g.FillRectangle(brush, vha.Rectangle); } } } } var lastContentY = (contentHeight - _ScrollOffset) * RowHeight; if (lastContentY < ClientSize.Height) { e.Graphics.FillRectangle( backgroundBrush, new Rectangle( 0, lastContentY, ClientSize.Width, ClientSize.Height - lastContentY ) ); } } var largeChange = ClientSize.Height / RowHeight; if (ScrollBar.LargeChange != largeChange) { ScrollBar.LargeChange = largeChange; } int scrollMax = Math.Max(1, contentHeight) + largeChange - 1; if (ScrollBar.Maximum != scrollMax) { ScrollBar.Maximum = scrollMax; } if (ScrollBar.Value != ScrollOffset) { ScrollBar.Value = ScrollOffset; } base.OnPaint(e); }
protected override void OnPaint(PaintEventArgs e) { var clipRectF = (RectangleF)e.ClipRectangle; if (Layout.Count == 0) { e.Graphics.Clear(BackColor); } var stringFormat = new StringFormat { Alignment = StringAlignment.Near, FormatFlags = StringFormatFlags.FitBlackBox | StringFormatFlags.NoFontFallback | StringFormatFlags.NoWrap, Trimming = StringTrimming.EllipsisPath, HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show }; var textToFlush = new HashSet <string>(TextCache.Keys); int textSuppressLimit = 2; foreach (var group in Layout) { if (!group.Rectangle.IntersectsWith(clipRectF)) { foreach (var item in group.Items) { textToFlush.Remove(GetItemText(item.Item)); } continue; } using (var scratch = Scratch.Get(e.Graphics, group.Rectangle)) { var g = scratch.Graphics; if (scratch.IsCancelled) { continue; } g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Clear(BackColor); foreach (var item in group.Items) { var opacity = 255; Color itemColor; Color outlineColor; if ((item.NestingDepth > 0) && (item != _HoverItem)) { opacity = (int)(opacity * Math.Pow(0.7, item.NestingDepth)); } if (item == _HoverItem) { itemColor = SystemColors.Highlight; outlineColor = SystemColors.HighlightText; } else { itemColor = SelectItemColor(item.Item); outlineColor = Color.FromArgb(opacity / 2, 0, 0, 0); } bool white = (itemColor.GetBrightness() <= 0.25f); using (var brush = new SolidBrush( Color.FromArgb(opacity, itemColor.R, itemColor.G, itemColor.B) )) g.FillRectangle(brush, item.Rectangle); using (var outlinePen = new Pen(outlineColor, BlockOutlineThickness)) g.DrawRectangle( outlinePen, item.Rectangle.X, item.Rectangle.Y, item.Rectangle.Width, item.Rectangle.Height ); if ((item.NestingDepth >= textSuppressLimit) && (item != _HoverItem)) { continue; } if ((item.Rectangle.Width > MinimumTextWidth) && (item.Rectangle.Height > MinimumTextHeight)) { var itemText = GetItemText(item.Item); textToFlush.Remove(itemText); var bitmap = TextCache.Get( g, itemText, Font, RotateFlipType.RotateNoneFlipNone, white ? Color.White : Color.Black, white ? Color.Black : Color.LightGray, stringFormat, new SizeF(item.Rectangle.Width, item.Rectangle.Height) ); var w = (int)Math.Min(item.Rectangle.Width, bitmap.Width); var h = (int)Math.Min(item.Rectangle.Height, bitmap.Height); g.DrawImageUnscaledAndClipped( bitmap, new Rectangle( (int)item.Rectangle.Right - w, (int)item.Rectangle.Bottom - h, w, h ) ); } } } } TextCache.Flush(textToFlush); }
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); }