Add text components 021-040 with demos and behavior tests
This commit is contained in:
30 files changed
+1702
-7
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user