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:
1 parent
1f3d38110e
commit
03e1f91706
532 files changed
+828
-735
No files matched your search
+3
-3
@@ -97,7 +97,7 @@ type heading struct {
|
||||
}
|
||||
|
||||
// Toward steps 0–n toward on, turning from where it is.
|
||||
func (k Kit) Toward(c *ui.Context, e *ui.Element, on bool, fps, n int) int {
|
||||
func (k Kit) Toward(c *ui.Context, e ui.Element, on bool, fps, n int) int {
|
||||
checkFPS(fps)
|
||||
if n < 1 {
|
||||
panic(fmt.Sprintf("pixel: Toward needs steps, got %d", n))
|
||||
@@ -137,7 +137,7 @@ type shot struct {
|
||||
}
|
||||
|
||||
// Shot steps a cued one-shot; Reduce Motion spends it whole.
|
||||
func (k Kit) Shot(c *ui.Context, e *ui.Element, cue, fps, done int) int {
|
||||
func (k Kit) Shot(c *ui.Context, e ui.Element, cue, fps, done int) int {
|
||||
checkFPS(fps)
|
||||
// Before any change the zero start reads as done.
|
||||
s := ui.Local(e, shotKey{}, func() shot { return shot{cue: cue} })
|
||||
@@ -162,7 +162,7 @@ type cued struct {
|
||||
}
|
||||
|
||||
// Cue is when n last changed on e, zero before.
|
||||
func (k Kit) Cue(e *ui.Element, n int) time.Time {
|
||||
func (k Kit) Cue(e ui.Element, n int) time.Time {
|
||||
s := ui.Local(e, cueKey{}, func() cued { return cued{n: n} })
|
||||
if s.n != n {
|
||||
s.n, s.at = n, k.now
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ type EditorOptions struct {
|
||||
|
||||
type Edit struct {
|
||||
// Element is laid out; Input takes the focus.
|
||||
Element, Input *ui.Element
|
||||
Element, Input ui.Element
|
||||
Changed, Submitted, Focused bool
|
||||
// Line is the caret's line, from 0.
|
||||
Line int
|
||||
@@ -53,7 +53,7 @@ func Editor(c *ui.Context, value *string, o EditorOptions) Edit {
|
||||
if o.EnterSends && !o.Multiline {
|
||||
panic("pixel: EnterSends needs a multi-line field")
|
||||
}
|
||||
shell, base, _ := Shell(c, func() *ui.Element {
|
||||
shell, base, _ := Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleTextField).Label(o.Label).Disabled(o.Disabled)
|
||||
})
|
||||
s := ui.Local(base, editKey{}, func() editState { return editState{} })
|
||||
@@ -73,7 +73,7 @@ func Editor(c *ui.Context, value *string, o EditorOptions) Edit {
|
||||
base.Description(*value)
|
||||
}
|
||||
width, check := WrapWidth(c, shell)
|
||||
env := editEnv{multi: o.Multiline, sends: o.EnterSends, maxLen: o.MaxLength, mask: o.Mask, width: width, dot: k.dot, read: c.ReadClipboard, write: func(v string) { s.clip, s.clipped = v, true }}
|
||||
env := editEnv{multi: o.Multiline, sends: o.EnterSends, maxLen: o.MaxLength, mask: o.Mask, width: width, dot: k.dot, read: c.Services().ReadClipboard, write: func(v string) { s.clip, s.clipped = v, true }}
|
||||
shown := s.view(o.Mask, true)
|
||||
caret := s.caret + s.composeCaret
|
||||
lines := editLayout(shown, width, o.Multiline)
|
||||
|
||||
+19
-7
@@ -17,7 +17,7 @@ type TextOptions struct {
|
||||
}
|
||||
|
||||
// Text is a pixel-font label that screen readers read.
|
||||
func Text(c *ui.Context, s string, o TextOptions) *ui.Element {
|
||||
func Text(c *ui.Context, s string, o TextOptions) ui.Element {
|
||||
k := K(c)
|
||||
scale := scaleOr1(o.Scale)
|
||||
e := ui.Box(c).Label(s).Role(ui.RoleText)
|
||||
@@ -65,7 +65,7 @@ func Wrap(s string, width, maxLines int) []string {
|
||||
type wrapKey struct{}
|
||||
|
||||
// WrapWidth is e's last painted width; Draw must call check.
|
||||
func WrapWidth(c *ui.Context, e *ui.Element) (int, func(r ui.Rect)) {
|
||||
func WrapWidth(c *ui.Context, e ui.Element) (int, func(r ui.Rect)) {
|
||||
dot := K(c).dot
|
||||
w := ui.Local(e, wrapKey{}, func() int { return 0 })
|
||||
used := *w
|
||||
@@ -89,7 +89,7 @@ func scaleOr1(s int) int {
|
||||
type State struct{ Hover, Press, Focus, Disabled bool }
|
||||
|
||||
// Shell wraps base in an enabled box that paints.
|
||||
func Shell(c *ui.Context, base func() *ui.Element) (shell, b *ui.Element, st State) {
|
||||
func Shell(c *ui.Context, base func() ui.Element) (shell, b ui.Element, st State) {
|
||||
shell = ui.Box(c)
|
||||
shell.Children(func() { b = base().Fill().FocusRing(false) })
|
||||
own, inert := b.IsDisabled(), current(c).cur.Inert
|
||||
@@ -103,7 +103,7 @@ func Shell(c *ui.Context, base func() *ui.Element) (shell, b *ui.Element, st Sta
|
||||
}
|
||||
|
||||
// Shortcut is e's key this frame, while e is enabled.
|
||||
func Shortcut(e *ui.Element, mods ui.Modifiers, key ui.Key) bool {
|
||||
func Shortcut(e ui.Element, mods ui.Modifiers, key ui.Key) bool {
|
||||
// MyGo still hands keys to a base just turned off.
|
||||
return e.Shortcut(mods, key) && !e.IsDisabled()
|
||||
}
|
||||
@@ -111,10 +111,10 @@ func Shortcut(e *ui.Element, mods ui.Modifiers, key ui.Key) bool {
|
||||
type parkKey struct{}
|
||||
|
||||
// Park moves focus off e while off, back once on.
|
||||
func Park(c *ui.Context, e *ui.Element, off bool) {
|
||||
func Park(c *ui.Context, e ui.Element, off bool) {
|
||||
parked := ui.Local(e, parkKey{}, func() bool { return false })
|
||||
spot := c.Root()
|
||||
if h := current(c).harbor; h != nil {
|
||||
if h := current(c).harbor; h.Valid() {
|
||||
spot = h
|
||||
}
|
||||
switch {
|
||||
@@ -130,8 +130,20 @@ func Park(c *ui.Context, e *ui.Element, off bool) {
|
||||
}
|
||||
}
|
||||
|
||||
type autoKey struct{}
|
||||
|
||||
// AutoFocus focuses e as it appears, after overlays note openers.
|
||||
func AutoFocus(c *ui.Context, e ui.Element) {
|
||||
first := false
|
||||
h := ui.Local(e, autoKey{}, func() ui.Handle { first = true; return ui.Handle{} })
|
||||
e.Bind(h)
|
||||
if first {
|
||||
h.Focus(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Harbor keeps focus in e while controls in fn rest.
|
||||
func Harbor(c *ui.Context, e *ui.Element, fn func()) {
|
||||
func Harbor(c *ui.Context, e ui.Element, fn func()) {
|
||||
f := current(c)
|
||||
prev := f.harbor
|
||||
f.harbor = e
|
||||
|
||||
@@ -85,8 +85,8 @@ func TestClock(t *testing.T) {
|
||||
if step != 0 || busy == 0 {
|
||||
t.Fatalf("under Reduce Motion: Step %d (want 0), Busy %d", step, busy)
|
||||
}
|
||||
if due := time.Until(pixel.Due()); due <= 0 || due > 125*time.Millisecond {
|
||||
t.Fatalf("Due in %v, want the 8 fps wait on the real clock", due)
|
||||
if due := pixel.Due().Sub(tt.Now()); due <= 0 || due > 125*time.Millisecond {
|
||||
t.Fatalf("Due in %v, want the 8 fps wait on the frame clock", due)
|
||||
}
|
||||
pixel.ResetDue()
|
||||
if !pixel.Due().IsZero() {
|
||||
@@ -166,7 +166,7 @@ func shellView(disabled *bool, clicks *int, st *pixel.State) func(c *ui.Context)
|
||||
ui.Box(c).Size(k.D(16), k.D(4))
|
||||
ui.Row(c).Children(func() {
|
||||
ui.Box(c).Size(k.D(16), k.D(8))
|
||||
shell, base, s := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, s := pixel.Shell(c, func() ui.Element {
|
||||
return ui.ButtonBase(c).Label("go").Disabled(*disabled)
|
||||
})
|
||||
*st = s
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ package pixel
|
||||
import "github.com/egoist/mygo/ui"
|
||||
|
||||
// Pad is a focusable grid; it returns the picked cell.
|
||||
func Pad(c *ui.Context, text string, cols, n, cw, ch int, cur *int, disabled bool) (shell, base *ui.Element, st State, picked int) {
|
||||
func Pad(c *ui.Context, text string, cols, n, cw, ch int, cur *int, disabled bool) (shell, base ui.Element, st State, picked int) {
|
||||
k := K(c)
|
||||
shell, base, st = Shell(c, func() *ui.Element {
|
||||
shell, base, st = Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleGroup).Label(text).Disabled(disabled)
|
||||
})
|
||||
shell.Size(k.D(cols*cw), k.D((n+cols-1)/cols*ch))
|
||||
|
||||
+6
-5
@@ -47,11 +47,12 @@ 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
|
||||
cur Settings
|
||||
// pass is the root of the pass Use ran in.
|
||||
pass ui.Element
|
||||
typing bool
|
||||
// harbor holds the focus of controls turning off.
|
||||
harbor *ui.Element
|
||||
harbor ui.Element
|
||||
}
|
||||
|
||||
type frameKey struct{}
|
||||
@@ -63,7 +64,7 @@ func Use(c *ui.Context, s Settings) {
|
||||
if f.cur.Palette != s.Palette {
|
||||
slog.Debug("8bit: palette", "name", s.Palette.Name)
|
||||
}
|
||||
f.cur, f.at, f.typing, f.harbor = s, c.Now(), false, nil
|
||||
f.cur, f.pass, f.typing, f.harbor = s, c.Root(), false, ui.Element{}
|
||||
c.SetTheme(theme(s.Palette))
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ func frameOf(c *ui.Context) *frame {
|
||||
|
||||
func current(c *ui.Context) *frame {
|
||||
f := frameOf(c)
|
||||
if !f.at.Equal(c.Now()) {
|
||||
if f.pass != c.Root() {
|
||||
panic("pixel: Use was not called in this frame")
|
||||
}
|
||||
return f
|
||||
|
||||
Reference in new issue
Block a user