Files
8bitMyGoUI/datetime/monthpicker.go
T
ZacharyZhang-NY a2f2796455 Add datetime components 196-215; Kit.At; inert stepper arrows
Calendars, date and time inputs, pickers, clocks, timers, a sun dial,
a season wheel, an agenda and a day schedule. Kit.At rebuilds at a
moment (relative times, midnight). Stepper and NumberInput arrows stop
under Inert. DateInput parks a popup focus as its own.
2026-10-11 23:56:10 -04:00

89 lines
2.6 KiB
Go

package datetime
import (
"log/slog"
"strconv"
"time"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/icon"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/input"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
type MonthPickerOptions struct {
Disabled bool
}
type MonthPickerResult struct {
Element *ui.Element
Changed bool
}
type monthKey struct{}
// paging is the year or decade shown, and a cell.
type paging struct {
at, cur int
}
// MonthPicker lays out twelve months; ◀ ▶ turn years.
func MonthPicker(c *ui.Context, text string, month *time.Time, o MonthPickerOptions) MonthPickerResult {
k := pixel.K(c)
col := ui.Column(c).Gap(k.D(2))
st := ui.Local(col, monthKey{}, func() paging { return paging{at: month.Year(), cur: int(month.Month()) - 1} })
res := MonthPickerResult{Element: col}
// Cells fit the widest name in the frame's locale.
cw := 28
for m := range 12 {
cw = max(cw, pixel.Measure(monthName(k, time.Month(m+1)))+6)
}
col.Children(func() {
pager(c, strconv.Itoa(st.at), 4*cw, o.Disabled, func(d int) {
st.at += d
slog.Debug("8bit: month picker turned", "label", text, "year", st.at)
})
shell, _, ps, picked := pixel.Pad(c, text, 4, 12, cw, cell, &st.cur, o.Disabled)
if picked >= 0 {
*month = time.Date(st.at, time.Month(picked+1), 1, 0, 0, 0, 0, month.Location())
res.Changed = true
}
y, m := month.Year(), int(month.Month())-1
at, cur := st.at, st.cur
shell.Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
for i := range 12 {
x, yy := i%4*cw, i/4*cell
if ps.Focus && i == cur {
g.Cursor(x, yy, cw, cell)
}
if at == y && i == m {
g.Frame(x+1, yy, cw-2, cell, pixel.Sunken, pixel.Well)
}
name := monthName(k, time.Month(i+1))
g.Text(x+(cw-pixel.Measure(name))/2, yy, name, pixel.Ink, 1)
}
g.Finish(ps)
})
})
if res.Changed {
slog.Debug("8bit: month picker", "label", text, "month", month.Format("2006-01"))
}
return res
}
// pager heads a grid: ◀ title ▶ call turn.
func pager(c *ui.Context, title string, w int, disabled bool, turn func(d int)) {
k := pixel.K(c)
ui.Row(c).Width(k.D(w)).AlignItems(ui.Center).Children(func() {
if input.IconButton(c, icon.ChevronLeft, k.Msg("prev"), input.IconButtonOptions{Size: input.Small, Disabled: disabled}).Clicked {
turn(-1)
}
ui.Row(c).Grow(1).Justify(ui.Center).Children(func() { pixel.Text(c, title, pixel.TextOptions{}) })
if input.IconButton(c, icon.ChevronRight, k.Msg("next"), input.IconButtonOptions{Size: input.Small, Disabled: disabled}).Clicked {
turn(1)
}
})
}