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);
}