- Remove Renderer.scale field and SetScale method - Add ScaleProvider interface to avoid editor/ui import cycle - Add Scale() method to State, rename Scale field to scale - Renderer reads scale through r.scale.Scale() - Fix icons.go blank import preventing embed.FS usage - Update main.go to pass State as ScaleProvider to Renderer
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
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)
|
|
}
|