Files
prevara/label.go
2025-11-30 16:45:22 +00:00

189 lines
4.6 KiB
Go

package gel
import (
"image"
"image/color"
"github.com/p9c/p9/pkg/gel/gio/font"
l "github.com/p9c/p9/pkg/gel/gio/layout"
"github.com/p9c/p9/pkg/gel/gio/op"
"github.com/p9c/p9/pkg/gel/gio/op/clip"
"github.com/p9c/p9/pkg/gel/gio/op/paint"
"github.com/p9c/p9/pkg/gel/gio/text"
"github.com/p9c/p9/pkg/gel/gio/unit"
"golang.org/x/image/math/fixed"
)
// Label is text drawn inside an empty box
type Label struct {
*Window
// Face defines the text style.
font font.Font
// Color is the text color.
color color.NRGBA
// Alignment specify the text alignment.
alignment text.Alignment
// MaxLines limits the number of lines. Zero means no limit.
maxLines int
text string
textSize unit.Sp
shaper *text.Shaper
}
// Fn renders the label as specified
func (lbl *Label) Fn(gtx l.Context) l.Dimensions {
cs := gtx.Constraints
textSize := fixed.I(gtx.Sp(lbl.textSize))
lbl.shaper.LayoutString(text.Parameters{
Font: lbl.font,
PxPerEm: textSize,
MaxLines: lbl.maxLines,
Alignment: lbl.alignment,
MaxWidth: cs.Max.X,
MinWidth: cs.Min.X,
Locale: gtx.Locale,
}, lbl.text)
// Record the material (color) for text
m := op.Record(gtx.Ops)
paint.ColorOp{Color: lbl.color}.Add(gtx.Ops)
textMaterial := m.Stop()
m2 := op.Record(gtx.Ops)
viewport := image.Rectangle{Max: cs.Max}
it := GlyphIterator{
Viewport: viewport,
MaxLines: lbl.maxLines,
Material: textMaterial,
}
var glyphs [32]text.Glyph
line := glyphs[:0]
for g, ok := lbl.shaper.NextGlyph(); ok; g, ok = lbl.shaper.NextGlyph() {
var ok bool
if line, ok = it.PaintGlyph(gtx, lbl.shaper, g, line); !ok {
break
}
}
call := m2.Stop()
viewport.Min = viewport.Min.Add(it.Padding.Min)
viewport.Max = viewport.Max.Add(it.Padding.Max)
clipStack := clip.Rect(viewport).Push(gtx.Ops)
call.Add(gtx.Ops)
dims := l.Dimensions{Size: it.Bounds.Size()}
dims.Size = cs.Constrain(dims.Size)
dims.Baseline = dims.Size.Y - it.Baseline
clipStack.Pop()
return dims
}
// Label creates a new label widget
func (w *Window) Label() *Label {
return &Label{
Window: w,
font: font.Font{},
color: w.Colors.GetNRGBAFromName("DocText"),
textSize: w.TextSize,
shaper: w.shaper,
}
}
// Text sets the label text
func (lbl *Label) Text(txt string) *Label {
lbl.text = txt
return lbl
}
// Color sets the text color
func (lbl *Label) Color(col string) *Label {
lbl.color = lbl.Theme.Colors.GetNRGBAFromName(col)
return lbl
}
// Font sets the font
func (lbl *Label) Font(fontName string) *Label {
if fnt, e := lbl.Theme.collection.Font(fontName); e == nil {
lbl.font = fnt
}
return lbl
}
// TextScale sets the text size as a scale factor
func (lbl *Label) TextScale(scale float32) *Label {
lbl.textSize = unit.Sp(float32(lbl.Theme.TextSize) * scale)
return lbl
}
// Alignment sets the text alignment
func (lbl *Label) Alignment(alignment text.Alignment) *Label {
lbl.alignment = alignment
return lbl
}
// MaxLines sets the maximum number of lines
func (lbl *Label) MaxLines(maxLines int) *Label {
lbl.maxLines = maxLines
return lbl
}
// H1 creates a large headline label
func (w *Window) H1(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H1"])
}
// H2 creates a headline label
func (w *Window) H2(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H2"])
}
// H3 creates a headline label
func (w *Window) H3(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H3"])
}
// H4 creates a headline label
func (w *Window) H4(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H4"])
}
// H5 creates a headline label
func (w *Window) H5(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H5"])
}
// H6 creates a headline label
func (w *Window) H6(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["H6"])
}
// Subtitle1 creates a subtitle label
func (w *Window) Subtitle1(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Subtitle1"])
}
// Subtitle2 creates a subtitle label
func (w *Window) Subtitle2(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Subtitle2"])
}
// Body1 creates a body text label
func (w *Window) Body1(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Body1"])
}
// Body2 creates a body text label
func (w *Window) Body2(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Body2"])
}
// Caption creates a caption label
func (w *Window) Caption(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Caption"])
}
// Overline creates an overline label
func (w *Window) Overline(txt string) *Label {
return w.Label().Text(txt).TextScale(Scales["Overline"])
}