Add input components 066-085; gallery chrome on real components; deploy warms the edge
This commit is contained in:
38 files changed
+2340
-172
No files matched your search
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user