Add input components 066-085; gallery chrome on real components; deploy warms the edge

This commit is contained in:
ZacharyZhang-NY committed 2026-10-11 19:05:42 -04:00
1 parent 0247a130f5
commit 095eab2b4c
38 files changed
+2340 -172

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
package input
import (
"log/slog"
"math"
"strconv"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
type NumberInputOptions struct {
Min, Max float64
// Step is zero for 1.
Step float64
Width int
Disabled bool
}
type numberKey struct{}
type numberState struct {
text string
focused bool
// seen is the value last shown, to notice the caller's.
seen float64
}
type NumberInputResult = TextInputResult
// NumberInput edits *value as text; bad text reddens the edge.
func NumberInput(c *ui.Context, label string, value *float64, o NumberInputOptions) NumberInputResult {
lo, hi := bounds(o.Min, o.Max)
step := o.Step
if step <= 0 {
step = 1
}
wrap := ui.Box(c)
st := ui.Local(wrap, numberKey{}, func() numberState { return numberState{text: fmtValue(*value), seen: *value} })
var res TextInputResult
wrap.Children(func() {
k := pixel.K(c)
set := func(v float64) {
if v = max(lo, min(hi, v)); v != *value {
*value, res.Changed = v, true
}
st.text, st.seen = fmtValue(*value), *value
}
bad := func() bool {
v, err := strconv.ParseFloat(st.text, 64)
return err != nil || math.IsNaN(v) || math.IsInf(v, 0) || v < lo || v > hi
}
if *value != st.seen || !st.focused && !bad() && st.text != fmtValue(*value) {
st.text, st.seen = fmtValue(*value), *value
}
var ed pixel.Edit
ed, res.Element = field(c, &st.text, pixel.EditorOptions{Label: label, Disabled: o.Disabled}, o.Width, bad, nil, func() {
ui.Column(c).Children(func() {
if arrowBox(c, k, tinyUp, o.Disabled) {
set(*value + step)
}
if arrowBox(c, k, tinyDown, o.Disabled) {
set(*value - step)
}
})
})
if v, err := strconv.ParseFloat(st.text, 64); ed.Changed && !bad() && err == nil && v != *value {
*value, st.seen, res.Changed = v, v, true
}
st.focused = ed.Focused
if ed.Input.Shortcut(0, ui.KeyUp) {
set(*value + step)
}
if ed.Input.Shortcut(0, ui.KeyDown) {
set(*value - step)
}
res.Input, res.Submitted, res.Focused = ed.Input, ed.Submitted, ed.Focused
})
if res.Changed {
slog.Debug("8bit: number input", "label", label, "value", *value)
}
res.Element = wrap
return res
}
// arrowBox is a half-height step button the pointer presses.
func arrowBox(c *ui.Context, k pixel.Kit, sp *pixel.Sprite, disabled bool) bool {
b := ui.Box(c).Size(k.D(10), k.D(pixel.LineHeight/2)).Role(ui.RoleNone)
down := b.Pressed()
b.Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
dy := 0
if down {
dy = 1
}
g.Sprite((g.W-sp.W)/2, (g.H-sp.H)/2+dy, sp, 0, pixel.Faint, 1)
})
return b.Clicked() && !disabled
}