From eb9754fde0a77c2ef9208ecda09057f5a42e72ef Mon Sep 17 00:00:00 2001 From: Greg Pomerantz Date: Sat, 9 May 2026 13:11:03 -0400 Subject: [PATCH] Fix text offset: use (x, y) for X and subtract baseline Y so text top aligns with y Co-authored-by: Qwen-Coder --- internal/ui/render.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/ui/render.go b/internal/ui/render.go index b83a0f2..9374319 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -4,6 +4,7 @@ import ( "image" "image/color" + "gioui.org/f32" "gioui.org/layout" "gioui.org/op" "gioui.org/op/clip" @@ -259,10 +260,17 @@ func (r *Renderer) drawLineText(gtx layout.Context, shp *text.Shaper, x, y unit. // drawLine draws a line of glyphs using shaper.Shape() and shaper.Bitmaps(). func (r *Renderer) drawLine(gtx layout.Context, shp *text.Shaper, line []text.Glyph, x, y unit.Dp, col color.NRGBA) { - // Offset coordinate system to (x, y). - // The shaper's glyph positions (g.X, g.Y) are absolute within the text block. - // g.Y for the first line is the ascent, so the top of the text will be at y. - t := op.Offset(image.Pt(gtx.Dp(x), gtx.Dp(y))).Push(gtx.Ops) + if len(line) == 0 { + return + } + first := line[0] + // shaper.Shape(line) returns a path where glyph positions are relative to + // the first glyph (first.X == 0 in the returned path). So we offset by + // (x, y) and let the shaper handle the rest. + // first.Y is the baseline; we subtract it so the top of the text is at y. + offX := float32(gtx.Dp(x)) + offY := float32(gtx.Dp(y)) - float32(first.Y) + t := op.Affine(f32.Affine2D{}.Offset(f32.Pt(offX, offY))).Push(gtx.Ops) // Draw vector glyphs path := shp.Shape(line)