Add palettes and frame settings

This commit is contained in:
ZacharyZhang-NY committed 2026-10-11 15:31:34 -04:00
1 parent 7dfb19d1a9
commit 1af6cd61bf
7 files changed
+542 -1

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
package pixel
import (
"fmt"
"log/slog"
"time"
"github.com/egoist/mygo/ui"
)
type Locale uint8
const (
En Locale = iota
Zh
)
type Settings struct {
Palette *Palette
// Dot is DIPs per dot, 1–4; zero means 2.
Dot int
Locale Locale
// Now replaces the frame clock, for tests.
Now func() time.Time
}
// Kit is one frame's settings, captured by components.
type Kit struct {
pal *Palette
dot float32
locale Locale
now time.Time
reduce bool
}
func (k Kit) Palette() *Palette { return k.pal }
func (k Kit) C(s Slot) ui.Color { return k.pal.Colors[s] }
func (k Kit) Dot() float32 { return k.dot }
func (k Kit) D(n int) float32 { return float32(n) * k.dot }
func (k Kit) Locale() Locale { return k.locale }
func (k Kit) Now() time.Time { return k.now }
func (k Kit) Reduce() bool { return k.reduce }
type frame struct {
cur Settings
at time.Time
}
type frameKey struct{}
// Use must run once per frame, before any component.
func Use(c *ui.Context, s Settings) {
s = s.valid()
f := frameOf(c)
if f.cur.Palette != s.Palette {
slog.Debug("8bit: palette", "name", s.Palette.Name)
}
f.cur, f.at = s, c.Now()
c.SetTheme(theme(s.Palette))
}
// Scope builds fn under other settings.
func Scope(c *ui.Context, s Settings, fn func()) {
f := current(c)
prev := f.cur
f.cur = s.valid()
fn()
f.cur = prev
}
// Lazy keeps this scope for rows MyGo builds during layout.
func Lazy[T any](c *ui.Context, fn func(T)) func(T) {
s := current(c).cur
return func(v T) { Scope(c, s, func() { fn(v) }) }
}
func K(c *ui.Context) Kit {
s := current(c).cur
now := c.Now()
if s.Now != nil {
now = s.Now()
}
return Kit{pal: s.Palette, dot: float32(s.Dot), locale: s.Locale, now: now, reduce: c.Preferences().ReduceMotion}
}
func frameOf(c *ui.Context) *frame {
return ui.Local(c.Root(), frameKey{}, func() frame { return frame{} })
}
func current(c *ui.Context) *frame {
f := frameOf(c)
if !f.at.Equal(c.Now()) {
panic("pixel: Use was not called in this frame")
}
return f
}
func (s Settings) valid() Settings {
if s.Palette == nil {
panic("pixel: Settings.Palette is nil")
}
if s.Dot == 0 {
s.Dot = 2
}
if s.Dot < 1 || s.Dot > 4 {
panic(fmt.Sprintf("pixel: Settings.Dot %d outside 1–4", s.Dot))
}
if s.Locale > Zh {
panic(fmt.Sprintf("pixel: unknown Locale %d", s.Locale))
}
return s
}
// theme keeps MyGo's own drawing inside the palette.
func theme(p *Palette) *ui.Theme {
t := ui.LightTheme()
c := p.Colors
t.Dark = p.Night
t.Background, t.Surface, t.SurfaceHover, t.SurfacePressed = c[Back], c[Face], c[Lit], c[Shade]
t.Border, t.Text, t.TextMuted = c[Edge], c[Ink], c[Faint]
t.Accent, t.AccentHover, t.AccentPressed, t.AccentText = c[Accent], c[AccentLit], c[Accent], c[AccentInk]
t.Danger, t.Warning, t.Success = c[Bad], c[Warn], c[Good]
t.Selection, t.Focus, t.Scrollbar, t.Radius = c[AccentLit], c[Accent], ui.Transparent, 0
return t
}