Add feedback components 106-130; inert scope, focus return, two-step deploy

This commit is contained in:
ZacharyZhang-NY committed 2026-10-11 20:58:30 -04:00
1 parent bce416182e
commit bd3877e1b1
87 files changed
+2492 -147

No files matched your search

+2 -2
View File
@@ -16,8 +16,8 @@ type AppFrameOptions struct {
// AppFrame arranges header, sidebar, main and footer; nil ones vanish.
func AppFrame(c *ui.Context, o AppFrameOptions, header, sidebar, main, footer func()) *ui.Element {
k := pixel.K(c)
sw := orDef("AppFrame SidebarWidth", o.SidebarWidth, 96)
fold := orDef("AppFrame FoldBelow", o.FoldBelow, 320)
sw := pixel.Or("AppFrame SidebarWidth", o.SidebarWidth, 96)
fold := pixel.Or("AppFrame FoldBelow", o.FoldBelow, 320)
if main == nil {
panic("layout: AppFrame needs main")
}
+1 -1
View File
@@ -14,7 +14,7 @@ type AspectBoxOptions struct {
// AspectBox fills the width and keeps W:H in whole dots.
func AspectBox(c *ui.Context, o AspectBoxOptions, children func()) *ui.Element {
k := pixel.K(c)
rw, rh := orDef("AspectBox W", o.W, 1), orDef("AspectBox H", o.H, 1)
rw, rh := pixel.Or("AspectBox W", o.W, 1), pixel.Or("AspectBox H", o.H, 1)
e := ui.Box(c).FillWidth().Clip()
w, check := pixel.WrapWidth(c, e)
return e.Height(k.D(w * rh / rw)).Draw(func(p *ui.Painter, r ui.Rect) { check(r) }).Children(children)
+3 -3
View File
@@ -27,9 +27,9 @@ type GridOptions struct {
// Grid lays n cells in equal columns, lines between them.
func Grid(c *ui.Context, n int, o GridOptions, cell func(i int)) *ui.Element {
k := pixel.K(c)
cols := orDef("Grid Columns", o.Columns, 2)
pad := orDef("Grid Pad", o.Pad, 4)
orDef("Grid n", n, 0)
cols := pixel.Or("Grid Columns", o.Columns, 2)
pad := pixel.Or("Grid Pad", o.Pad, 4)
pixel.Or("Grid n", n, 0)
if o.Lines > DottedLines {
panic(fmt.Sprintf("layout: unknown grid lines %d", o.Lines))
}
+1 -1
View File
@@ -27,7 +27,7 @@ const bezel = 8
// Handheld is a pocket console around screen; buttons report presses.
func Handheld(c *ui.Context, o HandheldOptions, screen func()) HandheldResult {
k := pixel.K(c)
sw, sh := orDef("Handheld ScreenW", o.ScreenW, 160), orDef("Handheld ScreenH", o.ScreenH, 144)
sw, sh := pixel.Or("Handheld ScreenW", o.ScreenW, 160), pixel.Or("Handheld ScreenH", o.ScreenH, 144)
res := HandheldResult{}
res.Element = ui.Column(c).Width(k.D(sw + 2*bezel + 40)).Padding(k.D(10)).Gap(k.D(6)).AlignItems(ui.Center).Role(ui.RoleGroup).Label(o.Label).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
+2 -2
View File
@@ -18,10 +18,10 @@ func panics(t *testing.T, name string, fn func()) {
}
func TestOrDef(t *testing.T) {
if orDef("x", 0, 7) != 7 || orDef("x", 3, 7) != 3 {
if pixel.Or("x", 0, 7) != 7 || pixel.Or("x", 3, 7) != 3 {
t.Fatal("orDef did not default zero or keep a value")
}
panics(t, "negative option", func() { orDef("x", -1, 7) })
panics(t, "negative option", func() { pixel.Or("x", -1, 7) })
panics(t, "unknown frame style", func() { border(pixel.FrameStyle(99)) })
}
-13
View File
@@ -2,24 +2,11 @@
package layout
import (
"fmt"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
// orDef is v, or def for zero; negative panics.
func orDef(name string, v, def int) int {
if v < 0 {
panic(fmt.Sprintf("layout: %s %d is negative", name, v))
}
if v == 0 {
return def
}
return v
}
// box frames the canvas unless it is too small.
func box(g pixel.Canvas, style pixel.FrameStyle, fill pixel.Slot) {
if g.W >= 3 && g.H >= 3 {
+2 -2
View File
@@ -18,8 +18,8 @@ type MasonryOptions struct {
// Masonry puts each item into the shortest column.
func Masonry(c *ui.Context, heights []int, o MasonryOptions, item func(i int)) *ui.Element {
k := pixel.K(c)
gap := orDef("Masonry Gap", o.Gap, 4)
n := orDef("Masonry Columns", o.Columns, 3)
gap := pixel.Or("Masonry Gap", o.Gap, 4)
n := pixel.Or("Masonry Columns", o.Columns, 3)
cols := lanes(heights, n, gap)
row := ui.Row(c).FillWidth().Gap(k.D(gap)).AlignItems(ui.Start)
w, check := pixel.WrapWidth(c, row)
+1 -1
View File
@@ -21,7 +21,7 @@ func Panel(c *ui.Context, o PanelOptions, children func()) *ui.Element {
if fill == pixel.Ink {
fill = pixel.Face
}
pad := border(o.Style) + orDef("Panel Padding", o.Padding, 4)
pad := border(o.Style) + pixel.Or("Panel Padding", o.Padding, 4)
return ui.Column(c).Padding(k.D(pad)).Draw(func(p *ui.Painter, r ui.Rect) {
box(k.Canvas(p, r), o.Style, fill)
}).Children(children)
+2 -2
View File
@@ -26,8 +26,8 @@ type ResizableResult struct {
// Resizable is a *w×*h dot box with a ◢ grip.
func Resizable(c *ui.Context, w, h *int, o ResizableOptions, children func()) ResizableResult {
k := pixel.K(c)
minW, minH := orDef("Resizable MinW", o.MinW, 24), orDef("Resizable MinH", o.MinH, 24)
maxW, maxH := orDef("Resizable MaxW", o.MaxW, 0), orDef("Resizable MaxH", o.MaxH, 0)
minW, minH := pixel.Or("Resizable MinW", o.MinW, 24), pixel.Or("Resizable MinH", o.MinH, 24)
maxW, maxH := pixel.Or("Resizable MaxW", o.MaxW, 0), pixel.Or("Resizable MaxH", o.MaxH, 0)
if maxW > 0 && maxW < minW || maxH > 0 && maxH < minH {
panic(fmt.Sprintf("layout: Resizable max %d×%d under min %d×%d", maxW, maxH, minW, minH))
}
+1 -1
View File
@@ -15,7 +15,7 @@ type ScreenOptions struct {
// Screen fills the window with Back; children form a column.
func Screen(c *ui.Context, o ScreenOptions, children func()) *ui.Element {
k := pixel.K(c)
pad := orDef("Screen Padding", o.Padding, 0)
pad := pixel.Or("Screen Padding", o.Padding, 0)
return ui.Column(c).Fill().Padding(k.D(pad)).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
g.Rect(0, 0, g.W, g.H, pixel.Back)
+1 -1
View File
@@ -17,7 +17,7 @@ type SectionOptions struct {
func Section(c *ui.Context, title string, o SectionOptions, children func()) *ui.Element {
k := pixel.K(c)
up := strings.ToUpper(title)
return ui.Column(c).Gap(k.D(orDef("Section Gap", o.Gap, 4))).Role(ui.RoleGroup).Label(title).Children(func() {
return ui.Column(c).Gap(k.D(pixel.Or("Section Gap", o.Gap, 4))).Role(ui.RoleGroup).Label(title).Children(func() {
ui.Box(c).FillWidth().Height(k.D(pixel.LineHeight)).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
mid, tw := pixel.LineHeight/2, pixel.Measure(up)
+1 -1
View File
@@ -27,7 +27,7 @@ type SplitResult struct {
// Split shows two panes and a grip moving *size dots.
func Split(c *ui.Context, size *int, o SplitOptions, first, second func()) SplitResult {
k := pixel.K(c)
least := orDef("Split Min", o.Min, 24)
least := pixel.Or("Split Min", o.Min, 24)
var e *ui.Element
var total float32
back, fwd := ui.KeyLeft, ui.KeyRight
+4 -4
View File
@@ -16,10 +16,10 @@ type TilesOptions struct {
// Tiles wraps n equal tiles into rows.
func Tiles(c *ui.Context, n int, o TilesOptions, tile func(i int)) *ui.Element {
k := pixel.K(c)
w := orDef("Tiles W", o.W, 48)
h := orDef("Tiles H", o.H, w)
orDef("Tiles n", n, 0)
return ui.Row(c).Wrap().Gap(k.D(orDef("Tiles Gap", o.Gap, 4))).Children(func() {
w := pixel.Or("Tiles W", o.W, 48)
h := pixel.Or("Tiles H", o.H, w)
pixel.Or("Tiles n", n, 0)
return ui.Row(c).Wrap().Gap(k.D(pixel.Or("Tiles Gap", o.Gap, 4))).Children(func() {
for i := range n {
ui.Box(c).Size(k.D(w), k.D(h)).Clip().Children(func() { tile(i) })
}
+1 -1
View File
@@ -14,7 +14,7 @@ type ViewportOptions struct {
// Viewport fills its parent and draws children at W×H dots.
func Viewport(c *ui.Context, o ViewportOptions, children func()) *ui.Element {
k := pixel.K(c)
vw, vh := orDef("Viewport W", o.W, 160), orDef("Viewport H", o.H, 144)
vw, vh := pixel.Or("Viewport W", o.W, 160), pixel.Or("Viewport H", o.H, 144)
base := int(k.Dot())
outer := ui.Box(c).Fill()
was := outer.Bounds()
+1 -1
View File
@@ -18,7 +18,7 @@ type WindowOptions struct {
// Window is a beveled window with an optional title tab.
func Window(c *ui.Context, o WindowOptions, children func()) *ui.Element {
k := pixel.K(c)
pad := 3 + orDef("Window Padding", o.Padding, 6)
pad := 3 + pixel.Or("Window Padding", o.Padding, 6)
top := 0
e := ui.Column(c)
if o.Title != "" {