package ui import ( "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" "golang.org/x/image/math/fixed" ) // ShapedText holds the result from ShapeText: width for positioning, // plus the path data ready to draw. Must be drawn before the next ShapeText call. type ShapedText struct { Width int // total width in pixels PathSpec clip.PathSpec // glyph path data Bitmaps op.CallOp // bitmap glyphs (may be empty) FirstX fixed.Int26_6 // first glyph X offset FirstY int32 // first glyph Y offset } // ShapeText layouts text and returns width + path data for drawing. // The returned ShapedText must be drawn before the next ShapeText call. func (r *Renderer) ShapeText(gtx layout.Context, str string, size unit.Sp) ShapedText { r.shp.LayoutString(text.Parameters{ PxPerEm: fixed.I(gtx.Sp(size)), MinWidth: 0, MaxWidth: 1000, MaxLines: 1, }, str) // Collect glyphs and measure width var glyphs []text.Glyph var cumWidth fixed.Int26_6 var firstX fixed.Int26_6 var firstY int32 for { g, ok := r.shp.NextGlyph() if !ok { break } if len(glyphs) == 0 { firstX = g.X firstY = g.Y } cumWidth += g.Advance glyphs = append(glyphs, g) } // capture path spec var spec clip.PathSpec var bitmaps op.CallOp spec = r.shp.Shape(glyphs) bitmaps = r.shp.Bitmaps(glyphs) return ShapedText{ Width: int(cumWidth >> 6), PathSpec: spec, Bitmaps: bitmaps, FirstX: firstX, FirstY: firstY, } } // DrawShapedText draws a ShapedText at the given position. func (r *Renderer) DrawShapedText(gtx layout.Context, st ShapedText, x, y Dp, col color.NRGBA) { xPx := r.toPx(x) yPx := r.toPx(y) m := op.Record(gtx.Ops) offX := float32(xPx) + float32(st.FirstX)/64.0 offY := float32(yPx) + float32(st.FirstY) t := op.Affine(f32.Affine2D{}.Offset(f32.Pt(offX, offY))).Push(gtx.Ops) outline := clip.Outline{Path: st.PathSpec}.Op().Push(gtx.Ops) paint.ColorOp{Color: col}.Add(gtx.Ops) paint.PaintOp{}.Add(gtx.Ops) outline.Pop() if st.Bitmaps != (op.CallOp{}) { st.Bitmaps.Add(gtx.Ops) } t.Pop() call := m.Stop() call.Add(gtx.Ops) }