Add drawTruncatedText for single-pass layout, measure, and render

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Greg Pomerantz 2026-05-09 11:14:46 -04:00
parent 16719afb95
commit fcd2fea870
2 changed files with 52 additions and 13 deletions

View File

@ -95,23 +95,27 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar) {
// Truncate filename only if it doesn't fit // Truncate filename only if it doesn't fit
displayFilename := sb.Filename displayFilename := sb.Filename
availableWidth := int(reg.W - unit.Dp(8) - unit.Dp(40)) // left margin + right icons in DP availableWidth := int(reg.W - unit.Dp(8) - unit.Dp(40)) // left margin + right icons in DP
ellipsisWidths := charWidths(gtx, th.Shaper, "...", r.theme.FontSize)
// Layout ellipsis once and get its width
th.Shaper.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(r.theme.FontSize))}, "...")
var ellipsisWidths []int
for {
g, ok := th.Shaper.NextGlyph()
if !ok {
break
}
if len(ellipsisWidths) == 0 {
ellipsisWidths = append(ellipsisWidths, int(g.Advance>>6))
} else {
ellipsisWidths = append(ellipsisWidths, ellipsisWidths[len(ellipsisWidths)-1]+int(g.Advance>>6))
}
}
ellipsisWidth := ellipsisWidths[len(ellipsisWidths)-1] ellipsisWidth := ellipsisWidths[len(ellipsisWidths)-1]
// Measure how wide "..." is, then find how many chars fit in availableWidth - ellipsisWidth // Measure how wide "..." is, then find how many chars fit in availableWidth - ellipsisWidth
spaceForText := availableWidth - ellipsisWidth spaceForText := availableWidth - ellipsisWidth
widths := charWidths(gtx, th.Shaper, displayFilename, r.theme.FontSize)
if len(widths) > 0 && widths[len(widths)-1] > availableWidth {
// Find the largest index where the width fits
for i := len(widths)-1; i >= 0; i-- {
if widths[i] <= spaceForText {
displayFilename = displayFilename[:i] + "..."
break
}
}
}
// Position filename at (reg.X + 8, filenameLineY) - draw using shaper to avoid double-shaping // Layout filename, measure widths, and draw in a single pass
r.drawText(gtx, th.Shaper, displayFilename, r.theme.FontSize, reg.X+unit.Dp(8), filenameLineY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) r.drawTruncatedText(gtx, th.Shaper, displayFilename, r.theme.FontSize, reg.X+unit.Dp(8), filenameLineY, availableWidth, spaceForText, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
// Line 2: Icons // Line 2: Icons
iconsLineY := filenameLineY + filenameLineH iconsLineY := filenameLineY + filenameLineH
@ -196,6 +200,41 @@ func boolToString(b bool) string {
return "Off" return "Off"
} }
// drawTruncatedText layouts text, measures widths, truncates if needed, and draws in a single pass.
func (r *Renderer) drawTruncatedText(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp, x, y unit.Dp, availableWidth, spaceForText int, col color.NRGBA) {
// Layout text
shp.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(size))}, str)
// Measure widths and find truncation point
var widths []int
var cumWidth fixed.Int26_6
fullStr := str
for {
g, ok := shp.NextGlyph()
if !ok {
break
}
cumWidth += g.Advance
w := int(cumWidth >> 6)
widths = append(widths, w)
}
// Truncate if needed
if len(widths) > 0 && widths[len(widths)-1] > availableWidth {
// Find truncation point (from longest to shortest)
for i := len(widths)-1; i >= 0; i-- {
if widths[i] <= spaceForText {
fullStr = str[:i] + "..."
break
}
}
}
// Re-layout truncated text and draw
shp.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(size))}, fullStr)
r.drawText(gtx, shp, fullStr, size, x, y, col)
}
// drawText draws text using the same approach as Gio's textView: // drawText draws text using the same approach as Gio's textView:
// layout text, iterate glyphs, buffer into lines, and draw using shaper.Shape(). // layout text, iterate glyphs, buffer into lines, and draw using shaper.Shape().
func (r *Renderer) drawText(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp, x, y unit.Dp, col color.NRGBA) { func (r *Renderer) drawText(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp, x, y unit.Dp, col color.NRGBA) {

BIN
pad

Binary file not shown.