Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions accordion.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (a *Accordion) sectionRects() (headers, bodies []Rect) {
headers = make([]Rect, n)
bodies = make([]Rect, n)

remaining := r.H - ExpanderHeaderH*n
remaining := r.H - ExpanderHeaderHeight()*n
if remaining < 0 {
remaining = 0
}
Expand All @@ -123,8 +123,8 @@ func (a *Accordion) sectionRects() (headers, bodies []Rect) {
y := r.Y
seen := 0
for i := 0; i < n; i++ {
headers[i] = Rect{X: r.X, Y: y, W: r.W, H: ExpanderHeaderH}
y += ExpanderHeaderH
headers[i] = Rect{X: r.X, Y: y, W: r.W, H: ExpanderHeaderHeight()}
y += ExpanderHeaderHeight()
if a.isExpanded(i) {
h := perBody
seen++
Expand All @@ -149,9 +149,9 @@ func (a *Accordion) Draw(p painter.Painter, theme *Theme) {
hr := headers[i]
fillRect(p, hr.X, hr.Y, hr.W, hr.H, theme.SurfaceAlt)
cx := hr.X + 6
cy := hr.Y + ExpanderHeaderH/2
cy := hr.Y + ExpanderHeaderHeight()/2
drawDisclosureChevron(p, cx, cy, a.isExpanded(i), theme.OnSurface)
textY := hr.Y + (ExpanderHeaderH-a.glyphHeight())/2
textY := hr.Y + (ExpanderHeaderHeight()-a.glyphHeight())/2
a.drawText(p, hr.X+16, textY, sec.Title, theme.OnSurface)
if sec.Body == nil {
continue
Expand Down
18 changes: 13 additions & 5 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ type CheckButton struct {
OnToggle func(checked bool)
}

// checkBoxSize is the default pixel side length of the box (used when Size == 0).
// checkBoxSize is the default LOGICAL side length of the box (used when
// Size == 0); the effective size is this at the current metric scale.
const checkBoxSize = 12

// checkLabelGap is the logical gap between the box and its label.
const checkLabelGap = 4

// boxSize returns the effective box side length.
func (c *CheckButton) boxSize() int {
if c.Size > 0 {
return c.Size
return c.Size // a caller-chosen size is already in the units it chose
}
return checkBoxSize
return scaled(checkBoxSize)
}

// NewCheckButton constructs a CheckButton with the given label +
Expand All @@ -55,7 +59,11 @@ func (c *CheckButton) Draw(p painter.Painter, theme *Theme) {
fillRect(p, r.X, boxY, box, box, fill)
strokeRect(p, r.X, boxY, box, box, border)
if c.Checked {
if c.Size > 0 {
if box != checkBoxSize {
// Any box that is not the classic 12 -- a caller-chosen Size, or the
// default one at a metric scale above 1 -- gets the proportional
// tick, so the mark grows with the box instead of sitting in its
// top-left corner.
drawCheckmark(p, r.X, boxY, box, tick)
} else {
// The classic fixed 12px checkmark (byte-identical to prior releases).
Expand All @@ -69,7 +77,7 @@ func (c *CheckButton) Draw(p painter.Painter, theme *Theme) {
}
// Label to the right of the box, vertically centred on glyph row.
textY := r.Y + (r.H-c.glyphHeight())/2
c.drawText(p, r.X+box+4, textY, c.Label, labelInk)
c.drawText(p, r.X+box+scaled(checkLabelGap), textY, c.Label, labelInk)
c.drawFocusRing(p, theme, r)
}

Expand Down
24 changes: 15 additions & 9 deletions expander.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ type Expander struct {
OnExpand func(expanded bool)
}

// ExpanderHeaderH is the pixel height of the clickable header row.
// ExpanderHeaderH is the LOGICAL height of the clickable header row. Use
// [ExpanderHeaderHeight] for the height to lay out with: at a metric scale
// above 1 the header is taller, like every other metric.
const ExpanderHeaderH = 24

// ExpanderHeaderHeight is the header height in device pixels at the current
// [MetricScale].
func ExpanderHeaderHeight() int { return scaled(ExpanderHeaderH) }

// NewExpander builds an Expander with a label + initial content
// widget (may be nil to render header-only).
func NewExpander(label string, content Widget) *Expander {
Expand All @@ -35,11 +41,11 @@ func NewExpander(label string, content Widget) *Expander {
func (e *Expander) Draw(p painter.Painter, theme *Theme) {
r := e.Bounds()
// Header background.
fillRect(p, r.X, r.Y, r.W, ExpanderHeaderH, theme.SurfaceAlt)
fillRect(p, r.X, r.Y, r.W, ExpanderHeaderHeight(), theme.SurfaceAlt)
// Chevron: small triangle in Theme.OnSurface. Collapsed → right-
// pointing (▶), expanded → down-pointing (▼). 5-px tall.
cx := r.X + 6
cy := r.Y + ExpanderHeaderH/2
cy := r.Y + ExpanderHeaderHeight()/2
if e.Expanded {
// ▼ : flat top (widest row), point at bottom (narrow tip).
// At t=0 the 1-pixel tip lands at cy+2; at t=4 the 9-pixel
Expand All @@ -55,16 +61,16 @@ func (e *Expander) Draw(p painter.Painter, theme *Theme) {
fillRect(p, cx+2-t, cy-t, 1, 1+2*t, theme.OnSurface)
}
}
textY := r.Y + (ExpanderHeaderH-e.glyphHeight())/2
textY := r.Y + (ExpanderHeaderHeight()-e.glyphHeight())/2
e.drawText(p, r.X+16, textY, e.Label, theme.OnSurface)
if e.Expanded && e.Content != nil {
body := Rect{X: r.X, Y: r.Y + ExpanderHeaderH, W: r.W, H: r.H - ExpanderHeaderH}
body := Rect{X: r.X, Y: r.Y + ExpanderHeaderHeight(), W: r.W, H: r.H - ExpanderHeaderHeight()}
e.Content.SetBounds(body)
e.Content.Draw(p, theme)
}
// Focus ring around the clickable header row (paints nothing when unfocused,
// so an unfocused render is byte-identical).
e.drawFocusRing(p, theme, Rect{X: r.X, Y: r.Y, W: r.W, H: ExpanderHeaderH})
e.drawFocusRing(p, theme, Rect{X: r.X, Y: r.Y, W: r.W, H: ExpanderHeaderHeight()})
}

// OnEvent: click on the header toggles Expanded + fires OnExpand;
Expand All @@ -84,17 +90,17 @@ func (e *Expander) OnEvent(ev Event) {
if ev.Kind != EventClick {
return
}
if ev.Y < ExpanderHeaderH {
if ev.Y < ExpanderHeaderHeight() {
e.toggle()
return
}
if e.Expanded && e.Content != nil {
// Content occupies the body below the ExpanderHeaderH-tall header. Bound
// Content occupies the body below the ExpanderHeaderHeight()-tall header. Bound
// it (matching Draw) and translate the click into its local frame, so a
// click on interactive content isn't shifted down by the header height
// (plus the Expander's own origin) and misrouted.
r := e.Bounds()
body := Rect{X: r.X, Y: r.Y + ExpanderHeaderH, W: r.W, H: r.H - ExpanderHeaderH}
body := Rect{X: r.X, Y: r.Y + ExpanderHeaderHeight(), W: r.W, H: r.H - ExpanderHeaderHeight()}
e.Content.SetBounds(body)
e.Content.OnEvent(translateEvent(ev, r, body))
}
Expand Down
4 changes: 2 additions & 2 deletions gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/go-widgets/painter"
)

// GaugeThickness is the default arc stroke width in pixels, used when
// GaugeThickness is the default arc stroke width in LOGICAL pixels, used when
// Gauge.Thickness is left at its zero value. It leaves room inside the
// ring for the centred Caption on the toolkit's 5x7 font while keeping
// the track visually prominent.
Expand Down Expand Up @@ -114,7 +114,7 @@ func (g *Gauge) Draw(p painter.Painter, theme *Theme) {
}
thick := g.Thickness
if thick <= 0 {
thick = GaugeThickness
thick = scaled(GaugeThickness)
}
innerR := outerR - thick
if innerR < 0 {
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/go-widgets/toolkit

go 1.26.4

require github.com/go-widgets/painter v0.9.0
require github.com/go-widgets/painter v0.11.0

require github.com/go-opentype/opentype v0.5.0

Expand All @@ -16,3 +16,5 @@ require github.com/go-opentype/fonts v0.6.0
require github.com/go-widgets/mvvm v0.5.0

require github.com/go-images/images v0.0.0-20260811115337-bc5d586f8e38

require github.com/go-gfx/gfx v0.1.0 // indirect
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/go-gfx/gfx v0.1.0 h1:tBwT4YYnsdZlESY5MRp8aptg30iZxIH0G/8pZ/Ve3ZY=
github.com/go-gfx/gfx v0.1.0/go.mod h1:bFt/MWyYWRU3Ic9IaB8XOC9KLMMHRRmahMk4FaIGK7g=
github.com/go-images/images v0.0.0-20260811115337-bc5d586f8e38 h1:p+DjIujiwUvBiyD0oS9SUatf3pMKo0GpcA4p/Kyv7d8=
github.com/go-images/images v0.0.0-20260811115337-bc5d586f8e38/go.mod h1:nWwQCf77xG1GhaSD3rvlp7FNjjDhz47vrztyeBvIerk=
github.com/go-opentype/bidi v0.2.1 h1:7xCGqywPYxmwSfPBgP1Ewrp2Iwg2S03NeKxGWTz2guo=
Expand All @@ -10,7 +12,5 @@ github.com/go-opentype/shape v0.4.0 h1:Yz8ooo9+7HlzuzS72YWjJVM22GNGFf6jcxWfNNJOs
github.com/go-opentype/shape v0.4.0/go.mod h1:7kybm69yrtRgQnjaxPyYI9nPRFFdBdzlrmjcYCBfCbg=
github.com/go-widgets/mvvm v0.5.0 h1:o5hh6HAxbApONcbZxmyV9q12pCAPGRd6L24aS3gaCbA=
github.com/go-widgets/mvvm v0.5.0/go.mod h1:Phdrd434RLxXW1D6dL1PPQH1tABwYLIN2X7jQVC4TbY=
github.com/go-widgets/painter v0.8.0 h1:QeBiNalv84+qvjRJ/SywMNXHaxHA0lF5uN0oJCQX01s=
github.com/go-widgets/painter v0.8.0/go.mod h1:ccmlkH2UmcXQh6rt9Fu2eDt2RI0B5V0POaGmUKeW0EQ=
github.com/go-widgets/painter v0.9.0 h1:/y0qn0+TP3bhdLMi4+/vmUUBnSp3/L2RQBBgwAmJkes=
github.com/go-widgets/painter v0.9.0/go.mod h1:ccmlkH2UmcXQh6rt9Fu2eDt2RI0B5V0POaGmUKeW0EQ=
github.com/go-widgets/painter v0.11.0 h1:xsj4zTz8B43rOZnWrx7ZsaUBMgJyvgaE/Pq2FfcG2Sw=
github.com/go-widgets/painter v0.11.0/go.mod h1:IPRLqdUJuJX8sfuHeYLZCzjoLvA0ApbOlyIAVmguJDQ=
Loading
Loading