Skip to content

StrokeRect and StrokeRoundRect: paint the width they were given - #17

Merged
tannevaled merged 1 commit into
mainfrom
feat/stroke-width
Aug 15, 2026
Merged

StrokeRect and StrokeRoundRect: paint the width they were given#17
tannevaled merged 1 commit into
mainfrom
feat/stroke-width

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Both take a lineW and discard it. The pixel back-end always painted a one-pixel outline:

func (p *PixelPainter) StrokeRect(r Rect, c RGBA, lineW int) {
	...                      // one outline, always
}
func (p *PixelPainter) StrokeRoundRect(r Rect, radius int, c RGBA, lineW int) {
	_ = lineW // 1-px hint; matches StrokeRect

So a caller asking for a thicker border got a hairline, and no error, for as long as the interface has existed.

The interface documents lineW as "a hint; back-ends that can't do variable strokes ignore it" — which is right for a cell grid, where a terminal cell is atomic, and is asserted as still true here. It is not a description of a pixel surface, which can do exactly this and simply never did.

What it does now

lineW concentric outlines drawn inward from the rect's edge, so the border stays inside the bounds it frames — what a widget laying out to its own bounds needs. The rings stop when they meet in the middle rather than walking outside the rect. The rounded form loses one radius per ring, so the corners stay concentric instead of fanning out. A width below one is one: a border of no pixels is not a border.

Tested on the thickness where it is visible — how far in from the edge the border still paints — for square and rounded, at 0, negative, 1, 2, 3, 4, 5 and thicker-than-the-rect. The package stays at 100%.

Where this came from

go-widgets/toolkit has a documented HiDPI knob (SetMetricScale) that every widget's pixel metric is supposed to route through, so a host on a 2× screen sets it once and the chrome scales. Borders could not scale: the toolkit asked for a two-pixel stroke and the painter gave it one. This is the bottom of that stack; the toolkit half follows.

🤖 Generated with Claude Code

Both took a lineW and discarded it. The pixel back-end always painted a
one-pixel outline, so a caller asking for a thicker border got a hairline and no
error -- for as long as the interface has existed.

The interface documents lineW as "a hint; back-ends that can't do variable
strokes ignore it", which is right for a cell grid, where a terminal cell is
atomic. It is not a description of a pixel surface, which can do exactly this
and simply never did.

lineW is now concentric outlines drawn INWARD from the rect's edge, so the
border stays inside the bounds it frames -- what a widget laying out to its own
bounds needs -- and the rings stop when they meet in the middle rather than
walking outside. The rounded form loses one radius per ring so the corners stay
concentric. A width below one is one: a border of no pixels is not a border.

Found from above: go-widgets/toolkit cannot thicken its chrome for a HiDPI
screen, because the request had nowhere to land.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant