Terminal.Gui/Views/CharMap/CharMap.Refactoring.md
CharMap currently has a workaround where it sets ViewportSettings |= ViewportSettingsFlags.AllowLocationPlusSizeGreaterThanContentSize because it implements fixed row/column headers using custom drawing logic within OnDrawingContent. This fights against the default viewport clamping behavior.
The proper solution is to move the headers into the Padding adornment, which is the idiomatic Terminal.Gui pattern for fixed UI elements that surround scrollable content.
┌─────────────────────────────────────────────┐
│ Viewport (custom drawing) │
│ ┌─────────┬─────────────────────────────────┤
│ │ │ 0 1 2 3 4 5 ... F (header)
│ ├─────────┼─────────────────────────────────┤
│ │U+02500_ │ ─ ━ │ ┃ ┄ ... (glyphs) │
│ │U+02510_ │ ┐ ┑ ┒ ┓ └ ... │
│ │ ... │ ... │
│ └─────────┴─────────────────────────────────┤
└─────────────────────────────────────────────┘
Issues with current approach:
U+XXXXX_) are drawn in OnDrawingContent but don't scroll0 1 2 ... F) are drawn in OnDrawingContent but don't scrollRowLabelWidth calculations throughout the codeHorizontalScrollBar.X = RowLabelWidth to offset scrollbarHorizontalScrollBar.ScrollableContentSize = GetContentSize().Width - RowLabelWidthAllowLocationPlusSizeGreaterThanContentSize flag to work properlyGetCursor(), UpdateCursor(), ScrollToMakeCursorVisible()┌─────────────────────────────────────────────┐
│ Padding.Top (column headers) │
│ 0 1 2 3 4 5 6 7 8 9 A B C D │
├─────────┬───────────────────────────────────┤
│ Padding │ Viewport (glyphs only) │
│ .Left │ ─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ │
│U+02500_ │ ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ │
│U+02510_ │ ... │
│ ... │ │
├─────────┴───────────────────────────────────┤
│ Padding.Bottom (horizontal scrollbar) │
└─────────────────────────────────────────────┘
Benefits:
16 * COLUMN_WIDTH × visibleRows * rowHeightAllowLocationPlusSizeGreaterThanContentSize flagConfigure Padding thickness
Padding.Thickness = new Thickness(RowLabelWidth, HEADER_HEIGHT, 0, 0);
Create header drawing in Padding
Padding.DrawingContent eventCharMapPadding class that overrides OnDrawingContentUpdate SetContentSize() calls
RowLabelWidth from width calculationHEADER_HEIGHT from height calculationSetContentSize(new Size(16 * COLUMN_WIDTH, visibleRows * rowHeight))Simplify OnDrawingContent()
x = col * COLUMN_WIDTH, y = visibleRow * rowHeightRemove custom scrollbar positioning
HorizontalScrollBar.X = RowLabelWidthScrollableContentSize adjustmentsRemove ViewportSettings workaround
ViewportSettings |= ViewportSettingsFlags.AllowLocationPlusSizeGreaterThanContentSizeUpdate GetCursor()
RowLabelWidth offset from X calculationHEADER_HEIGHT offset from Y calculationx = (codePoint % 16) * COLUMN_WIDTH - Viewport.Xy = visibleRowIndex * rowHeight - Viewport.YUpdate UpdateCursor()
Update ScrollToMakeCursorVisible()
The row labels need to scroll vertically (but not horizontally) with the content. The column headers need to scroll horizontally (but not vertically) with the content.
Option A: Redraw on ViewportChanged
ViewportChangedPadding.SetNeedsDraw() to redraw headers with current scroll positionViewport.X to column header drawingViewport.Y to row label drawingOption B: Use SubViews in Padding
PaddingPaddingTerminal.Gui/Views/CharMap/CharMap.cs - Main refactoringTests/UnitTestsParallelizable/Views/CharMapTests.cs - If exists, update testsVisualRole.Focus/Active for highlightingView.Padding - The adornment where headers should liveScrollBar positioning in Padding - Example of content in PaddingBorder.Title drawing - Example of custom drawing in adornmentsAdornment.OnDrawingContent - How to customize adornment drawing