Files
ZacharyZhang-NYandClaude Opus 5.5 03e1f91706 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>
2026-10-17 01:31:08 -04:00

85 lines
1.9 KiB
Go

package navigation
import (
"log/slog"
"strconv"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/icon"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
var star5 = pixel.MustSprite(`
..#..
.###.
#####
.###.
.#.#.
`)
type Stage struct {
Name string
// Locked stages cannot be entered.
Locked bool
// Cleared stages show Stars, 0 to 3.
Cleared bool
Stars int
}
type LevelSelectOptions struct {
// Columns is the grid's width; zero means 5.
Columns int
Disabled bool
}
type LevelSelectResult struct {
Element ui.Element
// Chosen is Enter or a click on an open stage.
Changed, Chosen bool
}
// LevelSelect is a grid of locked, open or starred stages.
func LevelSelect(c *ui.Context, text string, stages []Stage, selected *int, o LevelSelectOptions) LevelSelectResult {
k := pixel.K(c)
cols := pixel.Or("LevelSelect Columns", o.Columns, 5)
old := *selected
shell, base, st, picked := pixel.Pad(c, text, cols, len(stages), 30, 30, selected, o.Disabled)
res := LevelSelectResult{Element: shell, Changed: *selected != old, Chosen: picked >= 0 && !stages[picked].Locked}
base.Description(stages[*selected].Name)
shell.Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
for i, s := range stages {
x, y := i%cols*30, i/cols*30
fill := pixel.Face
if s.Locked {
fill = pixel.Shade
}
if i == *selected {
g.Cursor(x, y, 30, 30)
}
g.Frame(x+2, y+2, 26, 26, pixel.Raised, fill)
if s.Locked {
g.Sprite(x+9, y+8, icon.Lock, 0, pixel.Faint, 1)
continue
}
n := strconv.Itoa(i + 1)
g.Micro(x+15-pixel.MicroWidth(n), y+5, n, pixel.Ink, 2)
if s.Cleared {
for j := range 3 {
ink := pixel.Shade
if j < s.Stars {
ink = pixel.Warn
}
g.Sprite(x+5+j*7, y+20, star5, 0, ink, 1)
}
}
}
g.Finish(st)
})
if res.Chosen {
slog.Debug("8bit: stage chosen", "label", text, "stage", stages[*selected].Name)
}
return res
}