Upgrade MyGo to v0.5.5

Elements are now pass-scoped value handles: tests that read bounds
after a frame bind a ui.Handle. pixel tells frames apart by the build
pass's root, since the Tester clock no longer moves on its own.

Fix the regressions the upgrade brought:
- Clipboard reads in input handlers go through c.Services().
- MyGo notes an overlay's opener after building it, so AutoFocus
  inside lost it; pixel.AutoFocus focuses through a Handle, and
  archtest bans the raw call. Dialogs hand the focus back again.
- Elements around a press stay hovered: Tooltip tells a press-given
  focus by focus arriving under the pointer.
- The web host moves the Tester clock with real time, at most 500 ms
  a call, and gives components the real clock.

The gallery's source index also accepts CRLF checkouts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-17 01:31:08 -04:00
1 parent 1f3d38110e
commit 03e1f91706
532 files changed
+828 -735

No files matched your search

+6 -1
View File
@@ -3,6 +3,7 @@ package gallery
import (
"log/slog"
"strings"
"time"
"github.com/egoist/mygo/ui"
@@ -22,6 +23,7 @@ type App struct {
query string
search input.TextInputResult
logs map[string][]string
now func() time.Time
}
// New starts at path; the boot screen shows first.
@@ -43,8 +45,11 @@ func (a *App) Go(path string) {
}
}
// SetClock gives the components a clock other than the frame's.
func (a *App) SetClock(now func() time.Time) { a.now = now }
func (a *App) View(c *ui.Context) {
pixel.Use(c, pixel.Settings{Palette: pixel.Palettes[a.palette], Dot: Dot, Locale: a.locale})
pixel.Use(c, pixel.Settings{Palette: pixel.Palettes[a.palette], Dot: Dot, Locale: a.locale, Now: a.now})
if !a.started {
a.boot(c)
return
+2 -2
View File
@@ -20,7 +20,7 @@ func (a *App) boot(c *ui.Context) {
shown = 16
}
start := shown == 16 && (k.Reduce() || step%12 < 8)
shell, base, _ := pixel.Shell(c, func() *ui.Element { return ui.ButtonBase(c).Label("Press start") })
shell, base, _ := pixel.Shell(c, func() ui.Element { return ui.ButtonBase(c).Label("Press start") })
shell.Fill().Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
w := pixel.Measure(logo) * 4
@@ -34,7 +34,7 @@ func (a *App) boot(c *ui.Context) {
hint := "Enter · Space · Click 回车 · 空格 · 点击"
g.Text((g.W-pixel.Measure(hint))/2, g.H-28, hint, pixel.Faint, 1)
})
base.AutoFocus()
pixel.AutoFocus(c, base)
if base.Clicked() || c.Shortcut(0, ui.KeyEnter) || c.Shortcut(0, ui.KeySpace) {
slog.Debug("8bit: gallery start")
a.started = true
+1 -1
View File
@@ -110,7 +110,7 @@ func (a *App) statusBar(c *ui.Context) {
// press is a custom-drawn chrome tile; true when clicked.
func press(c *ui.Context, w, h int, name string, draw func(g pixel.Canvas, st pixel.State)) bool {
k := pixel.K(c)
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.ButtonBase(c).Label(name) })
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.ButtonBase(c).Label(name) })
if w > 0 {
shell.Width(k.D(w))
}
+2 -2
View File
@@ -30,7 +30,7 @@ func demoPalettes(c *ui.Context, log func(string)) {
s.Palette = pal
pixel.Scope(c, s, func() {
kp := pixel.K(c)
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.ButtonBase(c).Label(pal.Name) })
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.ButtonBase(c).Label(pal.Name) })
shell.Height(kp.D(52)).Draw(func(p *ui.Painter, r ui.Rect) {
g := kp.Canvas(p, r)
g.Frame(0, 0, g.W, g.H, pixel.Window, pixel.Face)
@@ -158,7 +158,7 @@ func demoSprites(c *ui.Context, log func(string)) {
sp = slimeLeft
}
k := pixel.K(c)
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.ButtonBase(c).Label("slime") })
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.ButtonBase(c).Label("slime") })
shell.Size(k.D(120), k.D(48)).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
g.Rect(0, 40, g.W, 8, pixel.Good)
+2 -2
View File
@@ -46,7 +46,7 @@ func demoCoachmark(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
tips := []string{"Your bag. Potions live here.", "The map. You are the red dot.", "Save often. Slimes are tricky."}
var targets [3]*ui.Element
var targets [3]ui.Element
ui.Row(c).Gap(k.D(6)).Children(func() {
for i, b := range []struct {
art *pixel.Sprite
@@ -71,7 +71,7 @@ func demoCoachmark(c *ui.Context, log func(string)) {
func demoSpotlight(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
var shop *ui.Element
var shop ui.Element
ui.Row(c).Gap(k.D(6)).Children(func() {
input.Button(c, "INN", input.ButtonOptions{})
shop = input.Button(c, "SHOP", input.ButtonOptions{Icon: icon.Cart}).Element
+3 -1
View File
@@ -106,7 +106,9 @@ func sources() map[string]string {
if err != nil {
panic(err)
}
for _, part := range strings.Split(string(b), "\nfunc ")[1:] {
// A Windows checkout may bring CRLF.
src := strings.ReplaceAll(string(b), "\r\n", "\n")
for _, part := range strings.Split(src, "\nfunc ")[1:] {
end := strings.Index(part, "\n}\n")
if end < 0 {
panic("gallery: unterminated func in " + f.Name())