passgo/cmd/passgo-gui/ui.go
Greg Pomerantz 4b74367a55 GUI: fix invisible text on Linux, tiny button hit-areas, missing labels.
Found by running and debugging the Linux build on a virtual display:

- impl_linux.go: set fontSize (16, like Darwin). It was only defined
  for the Android and Darwin builds, so on Linux every label and
  button was rendered at size zero (all text invisible).
- ui.go: extend the Button click area to the full button width, not
  just the label width. Short labels (e.g. a few characters in a
  full-width list row) had a tiny tap target that was easy to miss.
- main.go: set Color: black on the insert-page buttons (<, >, generate,
  @, #). A zero-value NRGBA has A=0 (transparent), so their labels
  were invisible even though the buttons worked.
- main.go: gofmt (modern operator spacing).
2026-08-21 13:48:14 -04:00

151 lines
3.2 KiB
Go

package main
import (
"image"
"image/color"
"gioui.org/gesture"
"gioui.org/io/event"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
"gioui.org/widget/material"
)
var (
black = color.NRGBA{A: 0xff, R: 0, G: 0, B: 0}
white = color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}
gray = color.NRGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0}
darkgray = color.NRGBA{A: 0xff, R: 0xa0, G: 0xa0, B: 0xa0}
)
type Overlay struct {
Size unit.Sp
Text string
Click gesture.Click
Color color.NRGBA
Background color.NRGBA
Alignment text.Alignment
}
func (b *Overlay) Layout(gtx C) D {
ins := layout.UniformInset(unit.Dp(1))
return ins.Layout(gtx, func(gtx C) D {
st := layout.Stack{}
c2 := layout.Stacked(func(gtx C) D {
l := material.Label(th, b.Size, b.Text)
ins := layout.UniformInset(unit.Dp(4))
l.Color = b.Color
return ins.Layout(gtx, func(gtx C) D {
return l.Layout(gtx)
})
})
c1 := layout.Expanded(func(gtx C) D {
return layoutRRect(b.Background, gtx)
})
return st.Layout(gtx, c1, c2)
})
}
type SelButton struct {
Button
SelColor color.NRGBA
Selected bool
}
type Button struct {
Size unit.Sp
Label string
Click gesture.Click
Color color.NRGBA
Background color.NRGBA
Alignment text.Alignment
clicked bool
}
func layoutRRect(col color.NRGBA, gtx C) D {
r := gtx.Dp(4)
sz := image.Point{X: gtx.Constraints.Min.X, Y: gtx.Constraints.Min.Y}
// Push the rounded-rect clip, paint, then restore the previous clip.
stk := clip.UniformRRect(image.Rectangle{Max: sz}, r).Push(gtx.Ops)
paint.ColorOp{Color: col}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
stk.Pop()
return layout.Dimensions{Size: sz}
}
func (b *Button) Layout(gtx C) D {
mwidth := gtx.Constraints.Min.X
b.clicked = false
ins := layout.UniformInset(unit.Dp(1))
return ins.Layout(gtx, func(gtx C) D {
st := layout.Stack{}
c2 := layout.Stacked(func(gtx C) D {
l := material.Label(th, b.Size, b.Label)
l.Color = b.Color
ins := layout.UniformInset(unit.Dp(4))
ret := ins.Layout(gtx, func(gtx C) D {
return l.Layout(gtx)
})
// Register the click handler for the whole button area, not
// just the label: otherwise buttons with short labels (in
// full-width rows, for example) have a tiny tap target.
hit := ret.Size
if hit.X < gtx.Constraints.Max.X {
hit.X = gtx.Constraints.Max.X
}
stk := clip.Rect(image.Rectangle{Max: hit}).Push(gtx.Ops)
event.Op(gtx.Ops, b)
b.Click.Add(gtx.Ops)
stk.Pop()
for {
ev, ok := b.Click.Update(gtx.Source)
if !ok {
break
}
if ev.Kind == gesture.KindClick {
b.clicked = true
}
}
return ret
})
c1 := layout.Expanded(func(gtx C) D {
gtx.Constraints.Min.X = mwidth
return layoutRRect(b.Background, gtx)
})
return st.Layout(gtx, c1, c2)
})
}
func (b *Button) Clicked() bool {
return b.clicked
}
func (b *SelButton) Toggle() {
b.Selected = !b.Selected
b.SelColor, b.Background = b.Background, b.SelColor
}
func (b *SelButton) Select() {
if !b.Selected {
b.Toggle()
}
}
func (b *SelButton) Deselect() {
if b.Selected {
b.Toggle()
}
}
func (b *SelButton) Clicked() bool {
if b.clicked {
b.Toggle()
return true
} else {
return false
}
}