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 }