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

190 lines
6.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package gallery
import (
"fmt"
"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/layout"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/overlay"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
var popupEntries = []Entry{
{186, "ChoicePrompt", "选项提示", "overlay", "A question and a hand. Arrows and Enter, or press 1–9.", demoChoicePrompt},
{187, "Coachmark", "新手引导", "overlay", "A guided tour: a bubble points at each button in turn.", demoCoachmark},
{188, "Spotlight", "探照灯", "overlay", "Everything but one button sinks into dither.", demoSpotlight},
{189, "Notification", "通知", "overlay", "Cards stack at the top right and leave on their own. × sends one away.", demoNotification},
{190, "Popconfirm", "气泡确认", "overlay", "A small YES / NO bubble before the button acts.", demoPopconfirm},
{191, "PauseMenu", "暂停菜单", "overlay", "PAUSED blinks over the game. Escape resumes.", demoPauseMenu},
{192, "PromptDialog", "输入对话框", "overlay", "ENTER YOUR NAME, eight letters at most.", demoPromptDialog},
{193, "ProgressDialog", "进度对话框", "overlay", "Saving, with a way out.", demoProgressDialog},
{194, "KeyHints", "按键提示", "overlay", "Pad buttons and keycaps beside what they do.", demoKeyHints},
{195, "TitleCard", "关卡标题", "overlay", "WORLD 1-1 dithers in, waits, and dithers out.", demoTitleCard},
}
func demoChoicePrompt(c *ui.Context, log func(string)) {
s := overlayState(c)
choices := []string{"Fight", "Talk", "Flee"}
if input.Button(c, "A SLIME APPEARS", input.ButtonOptions{}).Clicked {
s.choice = true
log("open")
}
r := overlay.ChoicePrompt(c, "A wild slime blocks the road. It wobbles.", choices, &s.choice, overlay.ChoicePromptOptions{})
if r.Chosen >= 0 {
log(choices[r.Chosen])
}
if r.Canceled {
log("stared at the slime")
}
}
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
ui.Row(c).Gap(k.D(6)).Children(func() {
for i, b := range []struct {
art *pixel.Sprite
name string
}{{icon.Chest, "Bag"}, {icon.Map, "Map"}, {icon.Save, "Save"}} {
targets[i] = input.Button(c, b.name, input.ButtonOptions{Icon: b.art}).Element
}
})
if s.step > len(tips) {
if input.Button(c, "TOUR AGAIN", input.ButtonOptions{Size: input.Small}).Clicked {
s.step = 1
log("tour again")
}
return
}
if overlay.Coachmark(c, targets[s.step-1], tips[s.step-1], s.step, len(tips), overlay.CoachmarkOptions{}).Next {
s.step++
log(fmt.Sprintf("step %d", s.step))
}
}
func demoSpotlight(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
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
input.Button(c, "GUILD", input.ButtonOptions{})
})
if input.Toggle(c, "SPOTLIGHT", &s.spot, input.ToggleOptions{Size: input.Small}).Changed {
log(fmt.Sprintf("spotlight %v", s.spot))
}
if s.spot {
overlay.Spotlight(c, shop, "Potions are on sale!", overlay.SpotlightOptions{})
}
}
func demoNotification(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
ui.Row(c).Gap(k.D(4)).Children(func() {
if input.Button(c, "NEW MAIL", input.ButtonOptions{Size: input.Small}).Clicked {
s.notes = append(s.notes, overlay.Notification{Icon: icon.Mail, Title: "Letter from Mom", Text: "Eat your vegetables."})
log("mail")
}
if input.Button(c, "LEVEL UP", input.ButtonOptions{Size: input.Small}).Clicked {
s.notes = append(s.notes, overlay.Notification{Icon: icon.Star, Title: "Level 8!", Text: "STR +2, LUCK +1.", For: 8 * time.Second})
log("level up")
}
})
if r := overlay.Notifications(c, &s.notes, overlay.NotificationsOptions{}); r.Dismissed != nil {
log("dismissed " + r.Dismissed.Title)
}
}
func demoPopconfirm(c *ui.Context, log func(string)) {
r := overlay.Popconfirm(c, "SELL CROWN", "Sell it for 5 gold?", overlay.PopconfirmOptions{})
if r.Confirmed {
log("sold. what a deal.")
}
if r.Canceled {
log("kept the crown")
}
}
func demoPauseMenu(c *ui.Context, log func(string)) {
s := overlayState(c)
if input.Button(c, "PAUSE", input.ButtonOptions{Icon: icon.Pause}).Clicked {
s.pause = true
log("open")
}
if r := overlay.PauseMenu(c, &s.pause, overlay.PauseMenuOptions{}); r.Chosen >= 0 {
log([]string{"resume", "options", "quit"}[r.Chosen])
}
}
func demoPromptDialog(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
ui.Row(c).Gap(k.D(6)).AlignItems(ui.Center).Children(func() {
if input.Button(c, "NEW GAME", input.ButtonOptions{}).Clicked {
s.prompt = true
log("open")
}
if s.name != "" {
pixel.Text(c, "Hero: "+s.name, pixel.TextOptions{})
}
})
r := overlay.PromptDialog(c, "ENTER YOUR NAME", &s.name, &s.prompt, overlay.PromptDialogOptions{Placeholder: "LINK", MaxLength: 8})
if r.Submitted {
log("named " + s.name)
}
if r.Canceled {
log("canceled")
}
}
func demoProgressDialog(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
if input.Button(c, "SAVE", input.ButtonOptions{Icon: icon.Save}).Clicked {
s.saving, s.since = true, k.Now()
log("saving")
}
// The pretend save takes three seconds.
done := 0
if s.saving {
done = k.Since(c, s.since, 10, 30)
}
if done == 30 {
s.saving = false
log("saved")
}
if overlay.ProgressDialog(c, "Saving", float64(done)/30, &s.saving, overlay.ProgressDialogOptions{}).Canceled {
log(fmt.Sprintf("canceled at %d%%", done*100/30))
}
}
func demoKeyHints(c *ui.Context, log func(string)) {
overlay.KeyHints(c, []overlay.KeyHint{{Key: "A", Action: "CONFIRM"}, {Key: "B", Action: "BACK"}, {Key: "START", Action: "MENU"}}, overlay.KeyHintsOptions{})
}
func demoTitleCard(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := overlayState(c)
layout.Layers(c, layout.LayersOptions{}, func() {
ui.Box(c).Fill().Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
g.Dither(0, 0, g.W, g.H, pixel.Well, pixel.Info, 4)
g.Rect(0, g.H-12, g.W, 12, pixel.Good)
})
}, func() {
overlay.TitleCard(c, "WORLD 1-1", overlay.TitleCardOptions{Cue: s.cue})
}).Size(k.D(200), k.D(90))
if input.Button(c, "ENTER WORLD", input.ButtonOptions{Size: input.Small}).Clicked {
s.cue++
log("world 1-1")
}
}