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
@@ -18,7 +18,7 @@ type AutocompleteOptions struct {
|
||||
}
|
||||
|
||||
type AutocompleteResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Accepted reports a completion taken by Tab or Enter.
|
||||
Changed, Accepted, Submitted bool
|
||||
}
|
||||
|
||||
+3
-3
@@ -20,9 +20,9 @@ type ButtonOptions struct {
|
||||
}
|
||||
|
||||
type ButtonResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Base is the focusable inside Element.
|
||||
Base *ui.Element
|
||||
Base ui.Element
|
||||
Clicked bool
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func Button(c *ui.Context, text string, o ButtonOptions) ButtonResult {
|
||||
k := pixel.K(c)
|
||||
h, pad, top, sc := o.Size.metrics()
|
||||
name := label(o.Label, text)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.ButtonBase(c).Label(name).Disabled(o.Disabled || o.Loading)
|
||||
})
|
||||
w := pixel.Measure(text) * sc
|
||||
|
||||
@@ -17,7 +17,7 @@ type ButtonGroupOptions struct {
|
||||
}
|
||||
|
||||
type ButtonGroupResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Clicked is the button clicked this frame, or -1.
|
||||
Clicked int
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func ButtonGroup(c *ui.Context, labels []string, o ButtonGroupOptions) ButtonGro
|
||||
res := ButtonGroupResult{Clicked: -1}
|
||||
res.Element = ui.Row(c).Role(ui.RoleToolbar).Label(o.Label).FocusGroup(ui.Horizontal).Children(func() {
|
||||
for i, l := range labels {
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.ButtonBase(c).Label(l).Disabled(o.Disabled) })
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.ButtonBase(c).Label(l).Disabled(o.Disabled) })
|
||||
w := pixel.Measure(l)*sc + 2*pad
|
||||
if i > 0 {
|
||||
shell.Margin(0, 0, 0, k.D(-1))
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ type CheatCodeOptions struct {
|
||||
}
|
||||
|
||||
type CheatCodeResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Unlocked bool
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func CheatCode(c *ui.Context, text string, o CheatCodeOptions) CheatCodeResult {
|
||||
if seq == nil {
|
||||
seq = konami
|
||||
}
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleGroup).Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
s := ui.Local(base, cheatKey{}, func() cheat { return cheat{} })
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ type CheckboxOptions struct {
|
||||
}
|
||||
|
||||
type CheckboxResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func Checkbox(c *ui.Context, text string, checked *bool, o CheckboxOptions) Chec
|
||||
k := pixel.K(c)
|
||||
// The base turns before it learns it is off.
|
||||
on := *checked
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.CheckboxBase(c, &on).Label(text).Disabled(o.Disabled) })
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.CheckboxBase(c, &on).Label(text).Disabled(o.Disabled) })
|
||||
changed := on != *checked && !base.IsDisabled()
|
||||
if changed {
|
||||
*checked = on
|
||||
|
||||
@@ -14,7 +14,7 @@ type CheckboxGroupOptions struct {
|
||||
}
|
||||
|
||||
type CheckboxGroupResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func CheckboxGroup(c *ui.Context, text string, items []string, checked []bool, o
|
||||
all := count(checked) == len(checked) && len(checked) > 0
|
||||
res := CheckboxGroupResult{}
|
||||
res.Element = ui.Column(c).Gap(k.D(2)).Role(ui.RoleGroup).Children(func() {
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.CheckboxBase(c, &all).Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
shell.Size(k.D(12+pixel.Measure(text)), k.D(pixel.LineHeight)).Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ type ColorSlotOptions struct {
|
||||
}
|
||||
|
||||
type ColorSlotResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -18,7 +18,7 @@ type ComboboxOptions struct {
|
||||
}
|
||||
|
||||
type ComboboxResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Changed reports a new *value; Chosen, an option taken.
|
||||
Changed, Chosen bool
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func Combobox(c *ui.Context, text string, value *string, options []string, o Com
|
||||
st.open = false
|
||||
}
|
||||
show, held := st.open && len(shown) > 0, false
|
||||
panel := ui.PopoverBase(c, e, &show, func(panel *ui.Element) {
|
||||
panel := ui.PopoverBase(c, e, &show, func(panel ui.Element) {
|
||||
panel.MinWidth(e.Bounds().W)
|
||||
panel.HandleInput(func(ev ui.InputEvent) bool {
|
||||
if ev.Kind != ui.InputScroll {
|
||||
@@ -105,7 +105,7 @@ func Combobox(c *ui.Context, text string, value *string, options []string, o Com
|
||||
moved := over && [2]float32{px, py} != st.ptr
|
||||
st.ptr = [2]float32{px, py}
|
||||
menu(c, panel, func() {
|
||||
items := make([]*ui.Element, len(shown))
|
||||
items := make([]ui.Element, len(shown))
|
||||
for i := st.top; i < end; i++ {
|
||||
opt := shown[i]
|
||||
items[i] = ui.Row(c).Role(ui.RoleListItem).Label(opt)
|
||||
@@ -128,10 +128,10 @@ func Combobox(c *ui.Context, text string, value *string, options []string, o Com
|
||||
st.open = false
|
||||
}
|
||||
// Losing focus closes it, unless pressing on the list.
|
||||
if panel != nil && panel.Pressed() {
|
||||
if panel.Valid() && panel.Pressed() {
|
||||
held = true
|
||||
}
|
||||
if panel != nil && st.open && !ed.Focused && !held {
|
||||
if panel.Valid() && st.open && !ed.Focused && !held {
|
||||
st.open = false
|
||||
// This frame built the list: hide it, rebuild without it.
|
||||
panel.Invisible()
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ type DPadOptions struct {
|
||||
}
|
||||
|
||||
type DPadResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Pressed is the arm pressed this frame.
|
||||
Pressed Direction
|
||||
}
|
||||
@@ -43,7 +43,7 @@ type flash struct {
|
||||
// DPad is a cross pad reporting arrows and pressed arms.
|
||||
func DPad(c *ui.Context, text string, o DPadOptions) DPadResult {
|
||||
k := pixel.K(c)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleGroup).Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
lit := ui.Local(base, dpadKey{}, func() flash { return flash{} })
|
||||
|
||||
@@ -17,7 +17,7 @@ type EditableTextOptions struct {
|
||||
}
|
||||
|
||||
type EditableTextResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func EditableText(c *ui.Context, text string, value *string, o EditableTextOptio
|
||||
box.Children(func() {
|
||||
if s.on {
|
||||
ed, e := field(c, &s.draft, pixel.EditorOptions{Label: text, Placeholder: o.Placeholder}, w, nil, nil, nil)
|
||||
ed.Input.AutoFocus()
|
||||
pixel.AutoFocus(c, ed.Input)
|
||||
// Keys reach the wrapper; the editor's state gates them.
|
||||
on := !ed.Input.IsDisabled()
|
||||
enter, escape := on && pixel.Shortcut(e, 0, ui.KeyEnter), on && pixel.Shortcut(e, 0, ui.KeyEscape)
|
||||
@@ -54,7 +54,7 @@ func EditableText(c *ui.Context, text string, value *string, o EditableTextOptio
|
||||
}
|
||||
return
|
||||
}
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleButton).Label(text).Description(*value).Disabled(o.Disabled)
|
||||
})
|
||||
if s.refocus {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ type FieldOptions struct {
|
||||
}
|
||||
|
||||
// Field puts a label above a control, notes below.
|
||||
func Field(c *ui.Context, label string, o FieldOptions, control func()) *ui.Element {
|
||||
func Field(c *ui.Context, label string, o FieldOptions, control func()) ui.Element {
|
||||
k := pixel.K(c)
|
||||
return ui.Column(c).Gap(k.D(2)).Role(ui.RoleGroup).Label(label).Children(func() {
|
||||
pixel.Text(c, label, pixel.TextOptions{})
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import (
|
||||
type FieldsetOptions struct{}
|
||||
|
||||
// Fieldset frames a group of fields under a legend.
|
||||
func Fieldset(c *ui.Context, legend string, o FieldsetOptions, content func()) *ui.Element {
|
||||
func Fieldset(c *ui.Context, legend string, o FieldsetOptions, content func()) ui.Element {
|
||||
k := pixel.K(c)
|
||||
lw := pixel.Measure(legend)
|
||||
return ui.Column(c).Padding(k.D(pixel.LineHeight), k.D(8), k.D(8), k.D(8)).Gap(k.D(6)).Role(ui.RoleGroup).Label(legend).Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ type HoldButtonOptions struct {
|
||||
}
|
||||
|
||||
type HoldButtonResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Confirmed bool
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func HoldButton(c *ui.Context, text string, o HoldButtonOptions) HoldButtonResul
|
||||
if d == 0 {
|
||||
d = time.Second
|
||||
}
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.ButtonBase(c).Label(text).Description(k.Msg("hold")).Disabled(o.Disabled)
|
||||
})
|
||||
h := ui.Local(base, holdButtonKey{}, func() holding { return holding{} })
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ type JoystickOptions struct {
|
||||
}
|
||||
|
||||
type JoystickResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// X and Y are in −1…1; Y grows downward.
|
||||
X, Y float64
|
||||
Moved bool
|
||||
@@ -38,7 +38,7 @@ const (
|
||||
// Joystick drags a knob in a ring; arrows nudge it.
|
||||
func Joystick(c *ui.Context, text string, o JoystickOptions) JoystickResult {
|
||||
k := pixel.K(c)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleGroup).Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
s := ui.Local(base, stickKey{}, func() stick { return stick{} })
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ func Knob(c *ui.Context, text string, value *float64, o KnobOptions) KnobResult
|
||||
k := pixel.K(c)
|
||||
lo, hi := bounds(o.Min, o.Max)
|
||||
r := rail{lo: lo, hi: hi, step: o.Step}
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleSlider).Label(text).Description(fmtValue(*value)).Disabled(o.Disabled)
|
||||
})
|
||||
old, set := *value, r.snap(value)
|
||||
|
||||
@@ -18,7 +18,7 @@ type MultiSelectOptions struct {
|
||||
}
|
||||
|
||||
type MultiSelectResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type popup struct{ open, held bool }
|
||||
// MultiSelect checks many options in a popup; tags show them.
|
||||
func MultiSelect(c *ui.Context, text string, chosen *[]string, options []string, o MultiSelectOptions) MultiSelectResult {
|
||||
k := pixel.K(c)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.ButtonBase(c).Role(ui.RolePopUpButton).Label(text).Description(strings.Join(*chosen, ", ")).Disabled(o.Disabled)
|
||||
})
|
||||
pop := ui.Local(base, multiKey{}, func() popup { return popup{} })
|
||||
@@ -58,15 +58,15 @@ func MultiSelect(c *ui.Context, text string, chosen *[]string, options []string,
|
||||
})
|
||||
res := MultiSelectResult{Element: shell}
|
||||
pop.held = false
|
||||
ui.PopoverBase(c, base, open, func(panel *ui.Element) {
|
||||
ui.PopoverBase(c, base, open, func(panel ui.Element) {
|
||||
menu(c, panel, func() {
|
||||
col := ui.Column(c).Gap(k.D(1)).FocusGroup(ui.Vertical)
|
||||
col.Children(func() {
|
||||
for i, opt := range options {
|
||||
on := slices.Contains(*chosen, opt)
|
||||
item, cb, cst := pixel.Shell(c, func() *ui.Element { return ui.CheckboxBase(c, &on).Label(opt) })
|
||||
item, cb, cst := pixel.Shell(c, func() ui.Element { return ui.CheckboxBase(c, &on).Label(opt) })
|
||||
if i == 0 {
|
||||
cb.AutoFocus()
|
||||
pixel.AutoFocus(c, cb)
|
||||
}
|
||||
// Focused, not FocusWithin: MyGo links parents after frames.
|
||||
pop.held = pop.held || cb.Focused()
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ type NameEntryOptions struct {
|
||||
}
|
||||
|
||||
type NameEntryResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed, Confirmed bool
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ type PinInputOptions struct {
|
||||
}
|
||||
|
||||
type PinInputResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
// Complete reports the last box filled.
|
||||
Changed, Complete bool
|
||||
}
|
||||
@@ -34,7 +34,7 @@ const pinBox, pinGap = 12, 4
|
||||
func PinInput(c *ui.Context, text string, value *string, o PinInputOptions) PinInputResult {
|
||||
k := pixel.K(c)
|
||||
n := pixel.Or("PinInput Length", o.Length, 4)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleTextField).Label(text).Description(*value).Disabled(o.Disabled)
|
||||
})
|
||||
p := ui.Local(base, pinKey{}, func() pin { return pin{} })
|
||||
@@ -60,7 +60,7 @@ func PinInput(c *ui.Context, text string, value *string, o PinInputOptions) PinI
|
||||
put(ev.Text)
|
||||
// Browsers paste by command, native hosts by Cmd+V.
|
||||
case ev.Kind == ui.InputCommand && ev.Text == "paste", ev.Kind == ui.InputKeyDown && ev.Key == ui.KeyV && ev.Mods == ui.Cmd:
|
||||
put(c.ReadClipboard())
|
||||
put(c.Services().ReadClipboard())
|
||||
case ev.Kind == ui.InputKeyDown && ev.Key == ui.KeyBackspace && ev.Mods == 0:
|
||||
if len(*value) > 0 {
|
||||
*value, *changed = (*value)[:len(*value)-1], true
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ type RadioOptions struct {
|
||||
}
|
||||
|
||||
type RadioResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func Radio[T comparable](c *ui.Context, text string, value T, selected *T, o Rad
|
||||
k := pixel.K(c)
|
||||
was := *selected == value
|
||||
on := was
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.CheckboxBase(c, &on).Role(ui.RoleRadio).Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
res := RadioResult{Element: shell}
|
||||
|
||||
+3
-3
@@ -18,14 +18,14 @@ type RadioGroupOptions struct {
|
||||
type radioKey struct{}
|
||||
|
||||
type RadioGroupResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
// RadioGroup chooses *selected; one Tab stop, arrows choose.
|
||||
func RadioGroup(c *ui.Context, labels []string, selected *int, o RadioGroupOptions) RadioGroupResult {
|
||||
k := pixel.K(c)
|
||||
var e *ui.Element
|
||||
var e ui.Element
|
||||
if o.Row {
|
||||
e = ui.Row(c).Gap(k.D(10)).FocusGroup(ui.Horizontal)
|
||||
} else {
|
||||
@@ -38,7 +38,7 @@ func RadioGroup(c *ui.Context, labels []string, selected *int, o RadioGroupOptio
|
||||
for i, l := range labels {
|
||||
was := *selected == i
|
||||
on := was
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.CheckboxBase(c, &on).Role(ui.RoleRadio).Label(l).Disabled(o.Disabled)
|
||||
})
|
||||
if base.Focused() {
|
||||
|
||||
@@ -44,8 +44,8 @@ func RangeSlider(c *ui.Context, text string, low, high *float64, o RangeSliderOp
|
||||
}
|
||||
|
||||
// knob is one draggable end, fenced by r.lo and r.hi.
|
||||
func knob(c *ui.Context, k pixel.Kit, track *ui.Element, v *float64, r rail, lo, hi float64, w int) {
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
func knob(c *ui.Context, k pixel.Kit, track ui.Element, v *float64, r rail, lo, hi float64, w int) {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleSlider).Label(r.label).Description(fmtValue(*v)).Disabled(r.disabled)
|
||||
})
|
||||
set := func(x float64) { *v = max(r.lo, min(r.hi, x)) }
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ type RatingOptions struct {
|
||||
}
|
||||
|
||||
type RatingResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func Rating(c *ui.Context, text string, value *int, o RatingOptions) RatingResul
|
||||
for i := 1; i <= n; i++ {
|
||||
was := *value == i
|
||||
on := was
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.CheckboxBase(c, &on).Role(ui.RoleRadio).Label(fmt.Sprintf("%d/%d", i, n)).Disabled(o.Disabled)
|
||||
})
|
||||
if base.Focused() {
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ type SegmentedOptions struct {
|
||||
}
|
||||
|
||||
type SegmentedResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func Segmented(c *ui.Context, text string, labels []string, selected *int, o Seg
|
||||
g.Frame(0, 0, g.W, g.H, pixel.Notched, pixel.Face)
|
||||
}).Children(func() {
|
||||
for i, l := range labels {
|
||||
shell, _, st := pixel.Shell(c, func() *ui.Element { return p.Segment(i).Label(l).Disabled(o.Disabled) })
|
||||
shell, _, st := pixel.Shell(c, func() ui.Element { return p.Segment(i).Label(l).Disabled(o.Disabled) })
|
||||
shell.Size(k.D(pixel.Measure(l)+12), k.D(pixel.LineHeight+4)).Draw(func(pt *ui.Painter, r ui.Rect) {
|
||||
g := k.Canvas(pt, r)
|
||||
ink := pixel.Ink
|
||||
|
||||
+7
-7
@@ -15,7 +15,7 @@ type SelectOptions struct {
|
||||
}
|
||||
|
||||
type SelectResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ type SelectResult struct {
|
||||
func Select(c *ui.Context, text string, value *string, options []string, o SelectOptions) SelectResult {
|
||||
k := pixel.K(c)
|
||||
off := o.Disabled || pixel.Current(c).Inert
|
||||
var sel *ui.SelectParts[string]
|
||||
var shell, base *ui.Element
|
||||
var sel ui.SelectParts[string]
|
||||
var shell, base ui.Element
|
||||
var st pixel.State
|
||||
// Re-keying on each off state forgets an open popup.
|
||||
ui.Box(c).Key(off).Children(func() {
|
||||
shell, base, st = pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st = pixel.Shell(c, func() ui.Element {
|
||||
sel = ui.SelectBase(c, value)
|
||||
return sel.Trigger.Label(text).Disabled(o.Disabled)
|
||||
})
|
||||
@@ -41,7 +41,7 @@ func Select(c *ui.Context, text string, value *string, options []string, o Selec
|
||||
g.Finish(st)
|
||||
})
|
||||
if !off {
|
||||
sel.Popup(func(panel *ui.Element) {
|
||||
sel.Popup(func(panel ui.Element) {
|
||||
menu(c, panel, func() {
|
||||
for _, opt := range options {
|
||||
item := sel.Item(opt).Label(opt)
|
||||
@@ -67,7 +67,7 @@ func widest(options []string) int {
|
||||
}
|
||||
|
||||
// menu frames a popup panel as a game window.
|
||||
func menu(c *ui.Context, panel *ui.Element, fn func()) {
|
||||
func menu(c *ui.Context, panel ui.Element, fn func()) {
|
||||
k := pixel.K(c)
|
||||
panel.Padding(k.D(3)).Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
g := k.Canvas(p, r)
|
||||
@@ -78,7 +78,7 @@ func menu(c *ui.Context, panel *ui.Element, fn func()) {
|
||||
}
|
||||
|
||||
// row draws an option; a hand marks the lit one.
|
||||
func row(k pixel.Kit, item *ui.Element, text string, lit, chosen bool) {
|
||||
func row(k pixel.Kit, item ui.Element, text string, lit, chosen bool) {
|
||||
item.Height(k.D(pixel.LineHeight)).MinWidth(k.D(pixel.Measure(text) + 16)).Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
g := k.Canvas(p, r)
|
||||
ink := pixel.Ink
|
||||
|
||||
+6
-6
@@ -19,7 +19,7 @@ type SliderOptions struct {
|
||||
}
|
||||
|
||||
type SliderResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ type RailOptions struct {
|
||||
}
|
||||
|
||||
// SlideBase is an undrawn slider: pointer and keys set *value.
|
||||
func SlideBase(c *ui.Context, text string, value *float64, o RailOptions) (shell *ui.Element, st pixel.State, changed bool) {
|
||||
func SlideBase(c *ui.Context, text string, value *float64, o RailOptions) (shell ui.Element, st pixel.State, changed bool) {
|
||||
lo, hi := bounds(o.Min, o.Max)
|
||||
return slide(c, value, rail{lo: lo, hi: hi, step: o.Step, vertical: o.Vertical, label: text, disabled: o.Disabled})
|
||||
}
|
||||
@@ -62,8 +62,8 @@ type rail struct {
|
||||
}
|
||||
|
||||
// slide is a focusable track; pointer and keys set *v.
|
||||
func slide(c *ui.Context, v *float64, r rail) (*ui.Element, pixel.State, bool) {
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
func slide(c *ui.Context, v *float64, r rail) (ui.Element, pixel.State, bool) {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleSlider).Label(r.label).Description(fmtValue(*v)).Disabled(r.disabled)
|
||||
})
|
||||
old := *v
|
||||
@@ -102,7 +102,7 @@ func (r rail) snap(v *float64) func(float64) {
|
||||
}
|
||||
|
||||
// keys step *v by arrows; Home and End jump.
|
||||
func (r rail) keys(base *ui.Element, v *float64, set func(float64)) {
|
||||
func (r rail) keys(base ui.Element, v *float64, set func(float64)) {
|
||||
step := r.step
|
||||
if step == 0 {
|
||||
step = (r.hi - r.lo) / 20
|
||||
@@ -144,7 +144,7 @@ func groove(g pixel.Canvas, x, y int) {
|
||||
}
|
||||
|
||||
// report logs a change and wraps the result.
|
||||
func report(e *ui.Element, changed bool, kind, text string, v float64) SliderResult {
|
||||
func report(e ui.Element, changed bool, kind, text string, v float64) SliderResult {
|
||||
if changed {
|
||||
slog.Debug("8bit: "+kind, "label", text, "value", v)
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ type SlotPickerOptions struct {
|
||||
}
|
||||
|
||||
type SlotPickerResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func SlotPicker(c *ui.Context, text string, value *int, options []string, o Slot
|
||||
if *value < 0 || *value >= n {
|
||||
panic(fmt.Sprintf("input: SlotPicker value %d outside %d options", *value, n))
|
||||
}
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleSlider).Label(text).Description(options[*value]).Disabled(o.Disabled)
|
||||
})
|
||||
s := ui.Local(base, reelKey{}, func() reel { return reel{} })
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ type StepperOptions struct {
|
||||
}
|
||||
|
||||
type StepperResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func Stepper(c *ui.Context, text string, value *int, o StepperOptions) StepperRe
|
||||
w := max(pixel.Measure(strconv.Itoa(o.Min)), pixel.Measure(strconv.Itoa(o.Max))) + 8
|
||||
e := ui.Row(c).Gap(k.D(2)).AlignItems(ui.Center).Children(func() {
|
||||
set(*value - step*held(c, k, tinyLeft, o.Disabled))
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.Box(c).Focusable().Role(ui.RoleStepper).Label(text).Description(strconv.Itoa(*value)).Disabled(o.Disabled)
|
||||
})
|
||||
if !o.Disabled {
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ type SwitchOptions struct {
|
||||
}
|
||||
|
||||
type SwitchResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func Switch(c *ui.Context, text string, on *bool, o SwitchOptions) SwitchResult
|
||||
k := pixel.K(c)
|
||||
// The base turns before it learns it is off.
|
||||
v := *on
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.SwitchBase(c, &v).Label(label(o.Label, text)).Disabled(o.Disabled) })
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.SwitchBase(c, &v).Label(label(o.Label, text)).Disabled(o.Disabled) })
|
||||
changed := v != *on && !base.IsDisabled()
|
||||
if changed {
|
||||
*on = v
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ type TextInputOptions struct {
|
||||
|
||||
type TextInputResult struct {
|
||||
// Element is laid out; Input takes the focus.
|
||||
Element, Input *ui.Element
|
||||
Element, Input ui.Element
|
||||
Changed, Submitted, Focused bool
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func TextInput(c *ui.Context, label string, value *string, o TextInputOptions) T
|
||||
}
|
||||
|
||||
// field frames an editor in a well with extras.
|
||||
func field(c *ui.Context, value *string, eo pixel.EditorOptions, width int, bad func() bool, icon *pixel.Sprite, after func()) (pixel.Edit, *ui.Element) {
|
||||
func field(c *ui.Context, value *string, eo pixel.EditorOptions, width int, bad func() bool, icon *pixel.Sprite, after func()) (pixel.Edit, ui.Element) {
|
||||
k := pixel.K(c)
|
||||
var ed pixel.Edit
|
||||
e := ui.Row(c).Width(k.D(pixel.Or("Width", width, 120))).Height(k.D(pixel.LineHeight+6)).Padding(0, k.D(4)).Gap(k.D(3)).AlignItems(ui.Center)
|
||||
@@ -69,7 +69,7 @@ func well(g pixel.Canvas, edge pixel.Slot, focus bool) {
|
||||
}
|
||||
|
||||
// result wraps an editor's events and logs submits.
|
||||
func result(e *ui.Element, ed pixel.Edit, label string) TextInputResult {
|
||||
func result(e ui.Element, ed pixel.Edit, label string) TextInputResult {
|
||||
if ed.Submitted {
|
||||
slog.Debug("8bit: field submitted", "label", label)
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ type ToggleOptions struct {
|
||||
}
|
||||
|
||||
type ToggleResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func Toggle(c *ui.Context, text string, on *bool, o ToggleOptions) ToggleResult
|
||||
h, pad, top, sc := o.Size.metrics()
|
||||
// The base turns before it learns it is off.
|
||||
v := *on
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element {
|
||||
return ui.ToggleBase(c, &v).Label(label(o.Label, text)).Disabled(o.Disabled)
|
||||
})
|
||||
changed := v != *on && !base.IsDisabled()
|
||||
|
||||
@@ -18,7 +18,7 @@ type ToggleGroupOptions struct {
|
||||
}
|
||||
|
||||
type ToggleGroupResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func ToggleGroup(c *ui.Context, labels []string, on []bool, o ToggleGroupOptions
|
||||
for i, l := range labels {
|
||||
// The base turns before it learns it is off.
|
||||
v := on[i]
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element { return ui.ToggleBase(c, &v).Label(l).Disabled(o.Disabled) })
|
||||
shell, base, st := pixel.Shell(c, func() ui.Element { return ui.ToggleBase(c, &v).Label(l).Disabled(o.Disabled) })
|
||||
if i > 0 {
|
||||
shell.Margin(0, 0, 0, k.D(-1))
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ type TokenFieldOptions struct {
|
||||
}
|
||||
|
||||
type TokenFieldResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ type VirtualKeyboardOptions struct {
|
||||
}
|
||||
|
||||
type VirtualKeyboardResult struct {
|
||||
Element *ui.Element
|
||||
Element ui.Element
|
||||
Changed, Submitted bool
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user