Add text components 021-040 with demos and behavior tests

This commit is contained in:
ZacharyZhang-NY committed 2026-10-11 18:20:12 -04:00
1 parent 43098065bf
commit 59fde4096d
30 files changed
+1702 -7

No files matched your search

+24
View File
@@ -221,6 +221,30 @@ func (g Canvas) Text(x, y int, s string, ink Slot, scale int) {
}
}
// TextBlend draws s, glyph dots dithered from top to bottom.
func (g Canvas) TextBlend(x, y int, s string, top, bottom Slot, scale int) {
checkScale(scale)
span := LineHeight * scale
for _, r := range s {
gl := glyphOf(r)
gx := x + gl.x*scale
for j := range gl.h * scale {
yy := y + gl.top()*scale + j
level := min(16, (yy-y)*17/span)
row := bayer[(g.gy+yy)&3]
for _, part := range [2]struct {
s Slot
down bool
}{{top, false}, {bottom, true}} {
runs(gl.w*scale, func(i int) bool {
return gl.on(i/scale, j/scale) && (row[(g.gx+gx+i)&3] < level) == part.down
}, func(a, b int) { g.Rect(gx+a, yy, b-a, 1, part.s) })
}
}
x += gl.adv * scale
}
}
// Micro draws s in the 3×5 micro font.
func (g Canvas) Micro(x, y int, s string, ink Slot, scale int) {
checkScale(scale)
+29
View File
@@ -239,3 +239,32 @@ func TestTextAndMicroDraw(t *testing.T) {
}
}
}
func TestTextBlend(t *testing.T) {
plain := canvas(t, 40, 20, func(g pixel.Canvas) { g.Text(2, 2, "HM", pixel.Ink, 1) })
blend := canvas(t, 40, 20, func(g pixel.Canvas) { g.TextBlend(2, 2, "HM", pixel.Accent, pixel.Good, 1) })
tops, bottoms := 0, 0
for y := range 20 {
for x := range 40 {
ink, got := plain.at(x, y) == pixel.Ink, blend.at(x, y)
if ink != (got == pixel.Accent || got == pixel.Good) {
t.Fatalf("dot %d,%d: text %v, blend %v", x, y, ink, got)
}
if got == pixel.Accent && y > 2+pixel.LineHeight*3/4 || got == pixel.Good && y < 2+pixel.LineHeight/4 {
t.Fatalf("dot %d,%d has %v on the wrong end", x, y, got)
}
tops += boolInt(got == pixel.Accent)
bottoms += boolInt(got == pixel.Good)
}
}
if tops == 0 || bottoms == 0 {
t.Fatalf("blend used %d top and %d bottom dots", tops, bottoms)
}
}
func boolInt(b bool) int {
if b {
return 1
}
return 0
}
+3 -3
View File
@@ -25,7 +25,7 @@ func Text(c *ui.Context, s string, o TextOptions) *ui.Element {
if o.Wrap {
width, check = WrapWidth(c, e)
}
lines := textLines(s, width/scale, o.MaxLines)
lines := Wrap(s, width/scale, o.MaxLines)
if o.Wrap {
e.Height(k.D(len(lines) * LineHeight * scale))
} else {
@@ -44,8 +44,8 @@ func Text(c *ui.Context, s string, o TextOptions) *ui.Element {
})
}
// textLines wraps s, cutting to maxLines with an ellipsis.
func textLines(s string, width, maxLines int) []string {
// Wrap wraps s to width; past maxLines, an ellipsis.
func Wrap(s string, width, maxLines int) []string {
if maxLines < 0 {
panic(fmt.Sprintf("pixel: MaxLines %d", maxLines))
}
+3 -3
View File
@@ -24,7 +24,7 @@ func TestRuns(t *testing.T) {
}
}
func TestTextLinesEllipsis(t *testing.T) {
func TestWrapEllipsis(t *testing.T) {
cases := []struct {
s string
width, n int
@@ -37,8 +37,8 @@ func TestTextLinesEllipsis(t *testing.T) {
{"像素风格组件库", 36, 2, []string{"像素风", "格组…"}},
}
for _, c := range cases {
if got := textLines(c.s, c.width, c.n); !slices.Equal(got, c.want) {
t.Errorf("textLines(%q, %d, %d) = %q, want %q", c.s, c.width, c.n, got, c.want)
if got := Wrap(c.s, c.width, c.n); !slices.Equal(got, c.want) {
t.Errorf("Wrap(%q, %d, %d) = %q, want %q", c.s, c.width, c.n, got, c.want)
}
}
}