Use shaper.Shape() and shaper.Bitmaps() to draw glyphs directly (no double-shaping)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
0fdaea990f
commit
16719afb95
|
|
@ -2,10 +2,13 @@ package ui
|
|||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"gioui.org/f32"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/text"
|
||||
"gioui.org/unit"
|
||||
"gioui.org/widget/material"
|
||||
|
|
@ -107,10 +110,8 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar) {
|
|||
}
|
||||
}
|
||||
|
||||
// Position filename at (reg.X + 8, filenameLineY)
|
||||
call1 := op.Offset(image.Point{X: int(reg.X + unit.Dp(8)), Y: int(filenameLineY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, displayFilename).Layout(gtx)
|
||||
call1.Pop()
|
||||
// Position filename at (reg.X + 8, filenameLineY) - draw using shaper to avoid double-shaping
|
||||
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})
|
||||
|
||||
// Line 2: Icons
|
||||
iconsLineY := filenameLineY + filenameLineH
|
||||
|
|
@ -120,21 +121,15 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar) {
|
|||
iconY := iconsLineY
|
||||
|
||||
if sb.CutCopy {
|
||||
call := op.Offset(image.Point{X: int(leftX), Y: int(iconY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, "✂").Layout(gtx)
|
||||
call.Pop()
|
||||
r.drawText(gtx, th.Shaper, "✂", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
leftX += unit.Dp(36)
|
||||
}
|
||||
if sb.Copy {
|
||||
call := op.Offset(image.Point{X: int(leftX), Y: int(iconY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, "⎘").Layout(gtx)
|
||||
call.Pop()
|
||||
r.drawText(gtx, th.Shaper, "⎘", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
leftX += unit.Dp(36)
|
||||
}
|
||||
if sb.Paste {
|
||||
call := op.Offset(image.Point{X: int(leftX), Y: int(iconY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, "⎘").Layout(gtx)
|
||||
call.Pop()
|
||||
r.drawText(gtx, th.Shaper, "⎘", r.theme.FontSize, leftX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
leftX += unit.Dp(36)
|
||||
}
|
||||
|
||||
|
|
@ -142,15 +137,11 @@ func (r *Renderer) drawStatusBar(gtx layout.Context, sb StatusBar) {
|
|||
rightX := reg.X + reg.W - unit.Dp(8)
|
||||
if sb.Search {
|
||||
rightX -= unit.Dp(36)
|
||||
call := op.Offset(image.Point{X: int(rightX), Y: int(iconY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, "🔍").Layout(gtx)
|
||||
call.Pop()
|
||||
r.drawText(gtx, th.Shaper, "🔍", r.theme.FontSize, rightX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
}
|
||||
if sb.ConflictIcon {
|
||||
rightX -= unit.Dp(36)
|
||||
call := op.Offset(image.Point{X: int(rightX), Y: int(iconY)}).Push(gtx.Ops)
|
||||
material.Label(th, r.theme.FontSize, "⚠").Layout(gtx)
|
||||
call.Pop()
|
||||
r.drawText(gtx, th.Shaper, "⚠", r.theme.FontSize, rightX, iconY, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
}
|
||||
|
||||
c.Pop()
|
||||
|
|
@ -205,6 +196,48 @@ func boolToString(b bool) string {
|
|||
return "Off"
|
||||
}
|
||||
|
||||
// drawText draws text using the same approach as Gio's textView:
|
||||
// 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) {
|
||||
// Layout text
|
||||
shp.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(size))}, str)
|
||||
|
||||
// Draw glyphs using the same approach as Gio's textView
|
||||
var glyphs [32]text.Glyph
|
||||
line := glyphs[:0]
|
||||
for g, ok := shp.NextGlyph(); ok; g, ok = shp.NextGlyph() {
|
||||
line = append(line, g)
|
||||
if g.Flags&text.FlagLineBreak != 0 || cap(line)-len(line) == 0 {
|
||||
r.drawLine(gtx, shp, line, x, y, col)
|
||||
line = line[:0]
|
||||
}
|
||||
}
|
||||
if len(line) > 0 {
|
||||
r.drawLine(gtx, shp, line, x, y, col)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Apply offset transform
|
||||
off := f32.Point{X: float32(x), Y: float32(y)}
|
||||
t := op.Affine(f32.Affine2D{}.Offset(off)).Push(gtx.Ops)
|
||||
|
||||
// Draw vector glyphs
|
||||
path := shp.Shape(line)
|
||||
outline := clip.Outline{Path: path}.Op().Push(gtx.Ops)
|
||||
paint.ColorOp{Color: col}.Add(gtx.Ops)
|
||||
paint.PaintOp{}.Add(gtx.Ops)
|
||||
outline.Pop()
|
||||
|
||||
// Draw bitmap glyphs (emoji, etc.)
|
||||
if call := shp.Bitmaps(line); call != (op.CallOp{}) {
|
||||
call.Add(gtx.Ops)
|
||||
}
|
||||
|
||||
t.Pop()
|
||||
}
|
||||
|
||||
// charWidths returns the cumulative width after each rune in str.
|
||||
func charWidths(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp) []int {
|
||||
// Match Gio's textView: PxPerEm = font size in device pixels
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user