gioui.org/ui@v0.0.0-20190926171558-ce74bc0cbaea/text/measure.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package text
     4  
     5  import (
     6  	"fmt"
     7  	"image"
     8  
     9  	"gioui.org/ui"
    10  	"gioui.org/ui/layout"
    11  	"golang.org/x/image/math/fixed"
    12  )
    13  
    14  // A Line contains the measurements of a line of text.
    15  type Line struct {
    16  	Text String
    17  	// Width is the width of the line.
    18  	Width fixed.Int26_6
    19  	// Ascent is the height above the baseline.
    20  	Ascent fixed.Int26_6
    21  	// Descent is the height below the baseline, including
    22  	// the line gap.
    23  	Descent fixed.Int26_6
    24  	// Bounds is the visible bounds of the line.
    25  	Bounds fixed.Rectangle26_6
    26  }
    27  
    28  type String struct {
    29  	String string
    30  	// Advances contain the advance of each rune in String.
    31  	Advances []fixed.Int26_6
    32  }
    33  
    34  // A Layout contains the measurements of a body of text as
    35  // a list of Lines.
    36  type Layout struct {
    37  	Lines []Line
    38  }
    39  
    40  // LayoutOptions specify the constraints of a text layout.
    41  type LayoutOptions struct {
    42  	// MaxWidth set the maximum width of the layout.
    43  	MaxWidth int
    44  	// SingleLine specify that line breaks are ignored.
    45  	SingleLine bool
    46  }
    47  
    48  type Face interface {
    49  	// Layout returns the text layout for a string given a set of
    50  	// options.
    51  	Layout(s string, opts LayoutOptions) *Layout
    52  	// Path returns the ClipOp outline of a text recorded in a macro.
    53  	Path(s String) ui.MacroOp
    54  }
    55  
    56  type Alignment uint8
    57  
    58  const (
    59  	Start Alignment = iota
    60  	End
    61  	Middle
    62  )
    63  
    64  func linesDimens(lines []Line) layout.Dimensions {
    65  	var width fixed.Int26_6
    66  	var h int
    67  	var baseline int
    68  	if len(lines) > 0 {
    69  		baseline = lines[0].Ascent.Ceil()
    70  		var prevDesc fixed.Int26_6
    71  		for _, l := range lines {
    72  			h += (prevDesc + l.Ascent).Ceil()
    73  			prevDesc = l.Descent
    74  			if l.Width > width {
    75  				width = l.Width
    76  			}
    77  		}
    78  		h += lines[len(lines)-1].Descent.Ceil()
    79  	}
    80  	w := width.Ceil()
    81  	return layout.Dimensions{
    82  		Size: image.Point{
    83  			X: w,
    84  			Y: h,
    85  		},
    86  		Baseline: baseline,
    87  	}
    88  }
    89  
    90  func align(align Alignment, width fixed.Int26_6, maxWidth int) fixed.Int26_6 {
    91  	mw := fixed.I(maxWidth)
    92  	switch align {
    93  	case Middle:
    94  		return fixed.I(((mw - width) / 2).Floor())
    95  	case End:
    96  		return fixed.I((mw - width).Floor())
    97  	case Start:
    98  		return 0
    99  	default:
   100  		panic(fmt.Errorf("unknown alignment %v", align))
   101  	}
   102  }
   103  
   104  func (a Alignment) String() string {
   105  	switch a {
   106  	case Start:
   107  		return "Start"
   108  	case End:
   109  		return "End"
   110  	case Middle:
   111  		return "Middle"
   112  	default:
   113  		panic("unreachable")
   114  	}
   115  }