Fix #5518: Padding adornment fills with stale attribute when parent skips ClearViewport (#5358)#5519
Conversation
…dding column A raster ImageView placed at Pos.Right of a view that has a right Padding column overwrites that padding column (the cell one to the LEFT of the ImageView's frame) when it redraws. The full first draw repaints the neighbour so it looks correct; a partial redraw (a focus round-trip) leaves the overwrite behind. Surfaced in winprint as the page-preview pane bleeding its canvas colour into the settings panel's seam (on both Sixel and Kitty). Not actually raster-specific — a plain View at Pos.Right reproduces it too — so the fix likely belongs in the View draw/clip path. Test currently FAILS (reproduces #5518). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dec1d4af2b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Root cause: regression bisected to #5358 (
|
Thickness.Draw fills the adornment via the driver's CurrentAttribute and never sets one itself, relying on the caller having set it. The parent's ClearViewport (SetAttributeForRole) used to do that right before adornments drew. Since #5358 the parent skips its ClearViewport on a child-only redraw, so the Padding adornment inherited a stale CurrentAttribute — e.g. Color.None left by a sibling raster ImageView's transparent-marking — and filled the padding column with foreign content (the seam-overdraw winprint reported, on both Sixel and Kitty). Set the view's Normal attribute before the no-subview Padding.Thickness.Draw so the fill is deterministic regardless of prior draw state. Does not touch the #5358 clear optimization. Full parallelizable (17449) + non-parallelizable (74) suites stay green; the #5518 repro test now passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes a redraw regression where a view’s right Padding thickness could be filled using a stale Driver.CurrentAttribute when the parent skips ClearViewport during child-only redraws (#5358), causing background “bleed” into the padding seam (#5518).
Changes:
- Set
VisualRole.Normalbefore callingPadding.Thickness.Draw (...)whenPadding.Viewis not present, ensuring deterministic padding fill regardless of prior draw state. - Add a regression test reproducing the seam overwrite via focus-driven partial redraws with an
ImageViewadjacent to a padded neighbour.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Terminal.Gui/ViewBase/View.Drawing.Adornments.cs | Forces a known attribute before padding thickness fill to avoid inheriting stale CurrentAttribute on partial redraws. |
| Tests/UnitTestsParallelizable/Views/ImageViewNeighbourPaddingTests.cs | New regression test covering the seam/padding overwrite scenario from #5518. |
Fixes #5518.
Symptom
A view with a right
Paddingnext to a rasterImageView(winprint's settings panel ↔ page preview) shows the image pane's background bleeding into the padding "seam" column after a partial (focus) redraw — on both Sixel and Kitty, so not encoder-specific. In fact it isn't ImageView-specific at all: a plainViewreproduces it.Root cause
Thickness.Drawfills an adornment viadriver.CurrentAttributeand never sets an attribute itself — it relies on the caller having set one. The parent'sClearViewport→SetAttributeForRoleused to setCurrentAttributeto the parent's background right before adornments drew.Since #5358 (
584c02526) the parent skipsClearViewporton a child-only redraw (the intended fan-out optimization). So on a partial redraw thePaddingadornment inherits a staleCurrentAttribute—Color.Noneleft behind by a sibling rasterImageView's transparent-marking (or the sibling's background for a plainView) — and fills the padding column with it. Driver-level tracing pinned the writer exactly:(Bisect: passes at
584c02526^, fails from584c02526on.)Fix
Set the view's
Normalattribute before the no-subviewPadding.Thickness.Draw, so the fill is deterministic regardless of prior draw state. It does not touch the #5358 clear optimization, so the fan-out tests keep passing.The same latent pattern exists for
Margin/BorderThickness.Draw(they also fill with the ambient attribute); I scoped this PR to the demonstratedPaddingcase and left those, since their "correct" attribute differs (border scheme, transparent margin) and no repro exercises them.Validation
ImageViewNeighbourPaddingTests(fails before, passes after).SubViewOnlyRedrawTests,TabsFanOutDiagnosticTests,ViewDrawingClippingTests,BorderArrangementTests) all stay green.🤖 Generated with Claude Code