Add code components 366-385; ScrollArea Follow, editor sync

A terminal with history, a Go-colored code block, a log viewer that
follows, a hex viewer, a memory map, a JSON tree, a line diff, a GAME
OVER crash screen, an FPS meter, profiler bars, breakpoints,
variables, command history, a shortcut list, a debug grid, a pixel
editor that exports string art, a palette editor, a sprite sheet, a
glyph map and a 6502 register view.

layout.ScrollArea takes Follow, and ChatLog now uses it. data.TreeNode
takes a Value drawn in its Slot. pixel gains Has, and Sprite.Art
writes MustSprite art. pixel.Editor takes the caller's value at each
input event, so a value changed between frames is never typed onto.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-12 07:18:30 -04:00
1 parent 0e21870b64
commit 51af14709d
42 files changed
+3415 -37

No files matched your search

+15 -3
View File
@@ -3,6 +3,7 @@ package data
import (
"log/slog"
"strconv"
"strings"
"github.com/egoist/mygo/ui"
@@ -10,7 +11,10 @@ import (
)
type TreeNode struct {
Label string
Label string
// Value follows the label in Slot, as a key's value.
Value string
Slot pixel.Slot
Children []TreeNode
}
@@ -102,7 +106,7 @@ func Tree(c *ui.Context, text string, roots []TreeNode, selected *string, o Tree
}
*selected = rows[at].key
res.Changed = *selected != old
base.Description(nodes[*selected].Label)
base.Description(strings.TrimSpace(nodes[*selected].Label + " " + nodes[*selected].Value))
shown := rows
shell.Size(k.D(pixel.Or("Tree Width", o.Width, 160)), k.D(len(shown)*pixel.LineHeight)).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
@@ -119,7 +123,15 @@ func Tree(c *ui.Context, text string, roots []TreeNode, selected *string, o Tree
g.Sprite(x+4, y+5, pointer, 0, ink, 1)
}
}
g.Text(x+12, y, nodes[rw.key].Label, ink, 1)
n := nodes[rw.key]
g.Text(x+12, y, n.Label, ink, 1)
// On the chosen row the value takes its ink.
if vs := n.Slot; n.Value != "" {
if i == at {
vs = ink
}
g.Text(x+18+pixel.Measure(n.Label), y, n.Value, vs, 1)
}
}
g.Finish(st)
})
+40
View File
@@ -0,0 +1,40 @@
package data_test
import (
"testing"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/data"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
func TestTreeDrawsValuesInTheirSlot(t *testing.T) {
sel := "0"
roots := []data.TreeNode{{Label: "name", Value: `"Aria"`, Slot: pixel.Good}, {Label: "hp", Value: "42", Slot: pixel.Warn}}
tt := view(300, 200, newClock(), false, func(c *ui.Context) {
data.Tree(c, "Doc", roots, &sel, data.TreeOptions{})
})
r, img := find(t, tt, "Doc"), tt.Image()
count := func(row int, s pixel.Slot) int {
n, want := 0, pixel.SpringDay.Colors[s]
for y := int(r.Y) + row*2*pixel.LineHeight; y < int(r.Y)+(row+1)*2*pixel.LineHeight; y++ {
for x := int(r.X); x < int(r.X+r.W); x++ {
if c := img.RGBAAt(x, y); c.R == want.R && c.G == want.G && c.B == want.B {
n++
}
}
}
return n
}
// The chosen row inks its value; the other keeps Warn.
if count(0, pixel.Good) != 0 || count(1, pixel.Warn) == 0 {
t.Fatalf("values: Good on the chosen row %d, Warn below %d", count(0, pixel.Good), count(1, pixel.Warn))
}
// A click on the middle chooses the second row.
click(t, tt, "Doc")
img = tt.Image()
if sel != "1" || count(0, pixel.Good) == 0 || count(1, pixel.Warn) != 0 {
t.Fatalf("choosing hp (%q) did not swap which value is inked", sel)
}
}