mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
text: rename Face to Family and let Face denote a family configuration
While here, rename Family.Path to Shape which a more precise term. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+9
-5
@@ -23,10 +23,13 @@ import (
|
||||
|
||||
// Editor implements an editable and scrollable text area.
|
||||
type Editor struct {
|
||||
// Face defines the font and style of the text.
|
||||
// Family defines the font and style of the text.
|
||||
Family Family
|
||||
// Face specifies the font family configuration.
|
||||
Face Face
|
||||
// Size is the text size. If zero, a reasonable default is used.
|
||||
Size unit.Value
|
||||
// Size is the text size. If zero, a default size is used.
|
||||
Size unit.Value
|
||||
|
||||
Alignment Alignment
|
||||
// SingleLine force the text to stay on a single line.
|
||||
// SingleLine also sets the scrolling direction to
|
||||
@@ -241,7 +244,7 @@ func (e *Editor) Layout(gtx *layout.Context) {
|
||||
var stack op.StackOp
|
||||
stack.Push(gtx.Ops)
|
||||
op.TransformOp{}.Offset(lineOff).Add(gtx.Ops)
|
||||
e.Face.Path(tsize, str).Add(gtx.Ops)
|
||||
e.Family.Shape(e.Face, tsize, str).Add(gtx.Ops)
|
||||
paint.PaintOp{Rect: toRectF(clip).Sub(lineOff)}.Add(gtx.Ops)
|
||||
stack.Pop()
|
||||
}
|
||||
@@ -369,7 +372,8 @@ func (e *Editor) layoutText(c unit.Converter) {
|
||||
s = e.Hint
|
||||
}
|
||||
tsize := textSize(c, e.Size)
|
||||
textLayout := e.Face.Layout(tsize, s, LayoutOptions{SingleLine: e.SingleLine, MaxWidth: e.maxWidth})
|
||||
opts := LayoutOptions{SingleLine: e.SingleLine, MaxWidth: e.maxWidth}
|
||||
textLayout := e.Family.Layout(e.Face, tsize, s, opts)
|
||||
lines := textLayout.Lines
|
||||
dims := linesDimens(lines)
|
||||
for i := 0; i < len(lines)-1; i++ {
|
||||
|
||||
+5
-4
@@ -19,10 +19,11 @@ import (
|
||||
|
||||
// Label is a widget for laying out and drawing text.
|
||||
type Label struct {
|
||||
// Face defines the font and style of the text.
|
||||
// Face defines the style of the text.
|
||||
Face Face
|
||||
// Size is the text size. If zero, a default size is used.
|
||||
Size unit.Value
|
||||
|
||||
// Material is a macro recording the material to draw the
|
||||
// text. Use a ColorOp for colored text.
|
||||
Material op.MacroOp
|
||||
@@ -94,10 +95,10 @@ func (l *lineIterator) Next() (String, f32.Point, bool) {
|
||||
return String{}, f32.Point{}, false
|
||||
}
|
||||
|
||||
func (l Label) Layout(gtx *layout.Context) {
|
||||
func (l Label) Layout(gtx *layout.Context, family Family) {
|
||||
cs := gtx.Constraints
|
||||
tsize := textSize(gtx, l.Size)
|
||||
textLayout := l.Face.Layout(tsize, l.Text, LayoutOptions{MaxWidth: cs.Width.Max})
|
||||
textLayout := family.Layout(l.Face, tsize, l.Text, LayoutOptions{MaxWidth: cs.Width.Max})
|
||||
lines := textLayout.Lines
|
||||
if max := l.MaxLines; max > 0 && len(lines) > max {
|
||||
lines = lines[:max]
|
||||
@@ -124,7 +125,7 @@ func (l Label) Layout(gtx *layout.Context) {
|
||||
var stack op.StackOp
|
||||
stack.Push(gtx.Ops)
|
||||
op.TransformOp{}.Offset(off).Add(gtx.Ops)
|
||||
l.Face.Path(tsize, str).Add(gtx.Ops)
|
||||
family.Shape(l.Face, tsize, str).Add(gtx.Ops)
|
||||
// Set a default color in case the material is empty.
|
||||
paint.ColorOp{Color: color.RGBA{A: 0xff}}.Add(gtx.Ops)
|
||||
l.Material.Add(gtx.Ops)
|
||||
|
||||
+28
-3
@@ -45,12 +45,27 @@ type LayoutOptions struct {
|
||||
SingleLine bool
|
||||
}
|
||||
|
||||
type Face interface {
|
||||
// Face specify a particular configuration of a Family.
|
||||
type Face struct {
|
||||
// Weight is the text weight. If zero, Normal is used instead.
|
||||
Weight Weight
|
||||
Style Style
|
||||
}
|
||||
|
||||
// Style is the font style.
|
||||
type Style int
|
||||
|
||||
// Weight is a font weight, in CSS units.
|
||||
type Weight int
|
||||
|
||||
// Family implements a font family. It can layout and shape text from
|
||||
// a Face and size.
|
||||
type Family interface {
|
||||
// Layout returns the text layout for a string given a set of
|
||||
// options.
|
||||
Layout(size float32, s string, opts LayoutOptions) *Layout
|
||||
Layout(face Face, size float32, s string, opts LayoutOptions) *Layout
|
||||
// Path returns the ClipOp outline of a text recorded in a macro.
|
||||
Path(size float32, s String) op.MacroOp
|
||||
Shape(face Face, size float32, s String) op.MacroOp
|
||||
}
|
||||
|
||||
type Alignment uint8
|
||||
@@ -61,6 +76,16 @@ const (
|
||||
Middle
|
||||
)
|
||||
|
||||
const (
|
||||
Regular Style = iota
|
||||
Italic
|
||||
)
|
||||
|
||||
const (
|
||||
Normal Weight = 400
|
||||
Bold Weight = 700
|
||||
)
|
||||
|
||||
func linesDimens(lines []Line) layout.Dimensions {
|
||||
var width fixed.Int26_6
|
||||
var h int
|
||||
|
||||
+39
-42
@@ -19,9 +19,14 @@ import (
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// Faces is a cache of text layouts and paths.
|
||||
type Faces struct {
|
||||
faceCache map[faceKey]*Face
|
||||
// Family is an implementation of text.Family. It caches
|
||||
// layouts and paths.
|
||||
// A Family must specify at least the Regular font to be useful.
|
||||
type Family struct {
|
||||
Regular *sfnt.Font
|
||||
Italic *sfnt.Font
|
||||
Bold *sfnt.Font
|
||||
|
||||
layoutCache map[layoutKey]cachedLayout
|
||||
pathCache map[pathKey]cachedPath
|
||||
}
|
||||
@@ -49,20 +54,9 @@ type pathKey struct {
|
||||
str string
|
||||
}
|
||||
|
||||
type faceKey struct {
|
||||
font *sfnt.Font
|
||||
}
|
||||
|
||||
// Face is a cached implementation of text.Face.
|
||||
type Face struct {
|
||||
faces *Faces
|
||||
font *opentype
|
||||
}
|
||||
|
||||
// Reset the cache, discarding any measures or paths that
|
||||
// Reset the cache, discarding any layouts or paths that
|
||||
// haven't been used since the last call to Reset.
|
||||
func (f *Faces) Reset() {
|
||||
f.init()
|
||||
func (f *Family) Reset() {
|
||||
for pk, p := range f.pathCache {
|
||||
if !p.active {
|
||||
delete(f.pathCache, pk)
|
||||
@@ -81,62 +75,65 @@ func (f *Faces) Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
// For returns a Face for the given font.
|
||||
func (f *Faces) For(fnt *sfnt.Font) *Face {
|
||||
f.init()
|
||||
fk := faceKey{fnt}
|
||||
if f, exist := f.faceCache[fk]; exist {
|
||||
return f
|
||||
// for returns a font for the given face.
|
||||
func (f *Family) fontFor(face text.Face) *sfnt.Font {
|
||||
var font *sfnt.Font
|
||||
switch {
|
||||
case face.Style == text.Italic:
|
||||
font = f.Italic
|
||||
case face.Weight >= 600:
|
||||
font = f.Bold
|
||||
}
|
||||
face := &Face{
|
||||
faces: f,
|
||||
font: &opentype{Font: fnt, Hinting: font.HintingFull},
|
||||
if font == nil {
|
||||
font = f.Regular
|
||||
}
|
||||
f.faceCache[fk] = face
|
||||
return face
|
||||
return font
|
||||
}
|
||||
|
||||
func (f *Faces) init() {
|
||||
if f.faceCache != nil {
|
||||
func (f *Family) init() {
|
||||
if f.pathCache != nil {
|
||||
return
|
||||
}
|
||||
f.faceCache = make(map[faceKey]*Face)
|
||||
f.pathCache = make(map[pathKey]cachedPath)
|
||||
f.layoutCache = make(map[layoutKey]cachedLayout)
|
||||
}
|
||||
|
||||
func (f *Face) Layout(size float32, str string, opts text.LayoutOptions) *text.Layout {
|
||||
func (f *Family) Layout(face text.Face, size float32, str string, opts text.LayoutOptions) *text.Layout {
|
||||
f.init()
|
||||
fnt := f.fontFor(face)
|
||||
ppem := fixed.Int26_6(size * 64)
|
||||
lk := layoutKey{
|
||||
f: f.font.Font,
|
||||
f: fnt,
|
||||
ppem: ppem,
|
||||
str: str,
|
||||
opts: opts,
|
||||
}
|
||||
if l, ok := f.faces.layoutCache[lk]; ok {
|
||||
if l, ok := f.layoutCache[lk]; ok {
|
||||
l.active = true
|
||||
f.faces.layoutCache[lk] = l
|
||||
f.layoutCache[lk] = l
|
||||
return l.layout
|
||||
}
|
||||
l := layoutText(ppem, str, f.font, opts)
|
||||
f.faces.layoutCache[lk] = cachedLayout{active: true, layout: l}
|
||||
l := layoutText(ppem, str, &opentype{Font: fnt, Hinting: font.HintingFull}, opts)
|
||||
f.layoutCache[lk] = cachedLayout{active: true, layout: l}
|
||||
return l
|
||||
}
|
||||
|
||||
func (f *Face) Path(size float32, str text.String) op.MacroOp {
|
||||
func (f *Family) Shape(face text.Face, size float32, str text.String) op.MacroOp {
|
||||
f.init()
|
||||
fnt := f.fontFor(face)
|
||||
ppem := fixed.Int26_6(size * 64)
|
||||
pk := pathKey{
|
||||
f: f.font.Font,
|
||||
f: fnt,
|
||||
ppem: ppem,
|
||||
str: str.String,
|
||||
}
|
||||
if p, ok := f.faces.pathCache[pk]; ok {
|
||||
if p, ok := f.pathCache[pk]; ok {
|
||||
p.active = true
|
||||
f.faces.pathCache[pk] = p
|
||||
f.pathCache[pk] = p
|
||||
return p.path
|
||||
}
|
||||
p := textPath(ppem, f.font, str)
|
||||
f.faces.pathCache[pk] = cachedPath{active: true, path: p}
|
||||
p := textPath(ppem, &opentype{Font: fnt, Hinting: font.HintingFull}, str)
|
||||
f.pathCache[pk] = cachedPath{active: true, path: p}
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user