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"]) }