-
Notifications
You must be signed in to change notification settings - Fork 103
/
wrappedtext.go
153 lines (133 loc) · 3.09 KB
/
wrappedtext.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package render
import (
"image"
"image/color"
"github.com/tidbyt/gg"
"golang.org/x/image/font"
)
// WrappedText draws multi-line text.
//
// The optional `width` and `height` parameters limit the drawing
// area. If not set, WrappedText will use as much vertical and
// horizontal space as possible to fit the text.
//
// Alignment of the text is controlled by passing one of the following `align` values:
// - `"left"`: align text to the left
// - `"center"`: align text in the center
// - `"right"`: align text to the right
//
// DOC(Content): The text string to draw
// DOC(Font): Desired font face
// DOC(Height): Limits height of the area on which text may be drawn
// DOC(Width): Limits width of the area on which text may be drawn
// DOC(LineSpacing): Controls spacing between lines
// DOC(Color): Desired font color
// DOC(Align): Text Alignment
// EXAMPLE BEGIN
// render.WrappedText(
//
// content="this is a multi-line text string",
// width=50,
// color="#fa0",
//
// )
// EXAMPLE END
type WrappedText struct {
Widget
Content string `starlark:"content,required"`
Font string
Height int
Width int
LineSpacing int
Color color.Color
Align string
face font.Face
}
func (tw *WrappedText) Init() error {
if tw.Font == "" {
tw.Font = DefaultFontFace
}
face, err := GetFont(tw.Font)
if err != nil {
return err
}
tw.face = face
return nil
}
func (tw *WrappedText) PaintBounds(bounds image.Rectangle, frameIdx int) image.Rectangle {
// The bounds provided by user or parent widget
width := tw.Width
if width == 0 {
width = bounds.Dx()
}
height := tw.Height
if height == 0 {
height = bounds.Dy()
}
linespace := float64(tw.LineSpacing)
if linespace <= 0 {
linespace = 0
}
// Compute size of multi line string
//
// NOTE: Can't use dc.MeasureMultilineString() here. It only
// deals with texts that have actual \n in them.
dc := gg.NewContext(width, 0)
dc.SetFontFace(tw.face)
w := 0.0
h := 0.0
for _, line := range dc.WordWrap(tw.Content, float64(width)) {
lw, lh := dc.MeasureString(line)
if lw > w {
w = lw
}
h += lh + linespace
}
// Size of drawing context
if tw.Width != 0 {
width = tw.Width
} else if int(w) < bounds.Dx() {
width = int(w)
} else {
width = bounds.Dx()
}
if tw.Height != 0 {
height = tw.Height
} else if int(h) < bounds.Dy() {
height = int(h)
} else {
height = bounds.Dy()
}
return image.Rect(0, 0, width, height)
}
func (tw *WrappedText) Paint(dc *gg.Context, bounds image.Rectangle, frameIdx int) {
// Text alignment
align := gg.AlignLeft
if tw.Align == "center" {
align = gg.AlignCenter
} else if tw.Align == "right" {
align = gg.AlignRight
}
width := tw.PaintBounds(bounds, frameIdx).Dx()
metrics := tw.face.Metrics()
descent := metrics.Descent.Floor()
dc.SetFontFace(tw.face)
if tw.Color != nil {
dc.SetColor(tw.Color)
} else {
dc.SetColor(DefaultFontColor)
}
dc.DrawStringWrapped(
tw.Content,
0,
float64(-descent),
0,
0,
float64(width),
(float64(tw.LineSpacing)+dc.FontHeight())/dc.FontHeight(),
align,
)
}
func (tw *WrappedText) FrameCount() int {
return 1
}