-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptions.go
331 lines (280 loc) · 9.45 KB
/
options.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
package wordwrap
import (
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
"log"
)
/*
At a later stage I'm going to change how this works. Currently, it isn't great but open to suggestions.
*/
// FolderOption for folders
type FolderOption interface {
// WrapperOption Allows you to pass the option to a Wrapper and assume it gets passed to the constructor of the
// Folder
WrapperOption
// ApplyFoldConfig applies the config.
ApplyFoldConfig(interface{})
}
// BoxerOption for folders
type BoxerOption interface {
// WrapperOption Allows you to pass the option to a Wrapper and assume it gets passed to the constructor of the
// Boxer
WrapperOption
// ApplyBoxConfig applies the config.
ApplyBoxConfig(interface{})
}
// WrapperOption for folders
type WrapperOption interface {
// ApplyWrapperConfig applies the config.
ApplyWrapperConfig(interface{})
}
// boxerOptionFunc Wrapper function that automatically fills: WrapperOption requirement for the FolderOption interface
type boxerOptionFunc func(interface{})
// Reports interface adherence
var _ BoxerOption = boxerOptionFunc(nil)
var _ WrapperOption = boxerOptionFunc(nil)
// addBoxConfig interface that applies the config
type addBoxConfig interface {
addBoxConfig(BoxerOption)
}
// Reports interface adherence
var _ addBoxConfig = (*SimpleWrapper)(nil)
// ApplyWrapperConfig function that fills the: WrapperOption requirement for the BoxerOption interface
func (b boxerOptionFunc) ApplyWrapperConfig(wr interface{}) {
if wr, ok := wr.(interface{ addBoxConfig(BoxerOption) }); ok {
wr.addBoxConfig(b)
} else {
log.Printf("can't apply")
}
}
// ApplyBoxConfig Converts function into an object to match interface
func (b boxerOptionFunc) ApplyBoxConfig(br interface{}) {
b(br)
}
// folderOptionFunc Wrapper function that automatically fills: WrapperOption requirement for the FolderOption interface
type folderOptionFunc func(interface{})
// Reports interface adherence
var _ FolderOption = folderOptionFunc(nil)
var _ WrapperOption = folderOptionFunc(nil)
// addFoldConfig interface that applies the config
type addFoldConfig interface {
addFoldConfig(FolderOption)
}
// Reports interface adherence
var _ addFoldConfig = (*SimpleWrapper)(nil)
// ApplyWrapperConfig function that fills the: WrapperOption requirement for the FolderOption interface
func (f folderOptionFunc) ApplyWrapperConfig(wr interface{}) {
if wr, ok := wr.(addFoldConfig); ok {
wr.addFoldConfig(f)
} else {
log.Printf("can't apply")
}
}
// ApplyFoldConfig Converts function into an object to match interface
func (f folderOptionFunc) ApplyFoldConfig(fr interface{}) {
f(fr)
}
// wrapperOptionFunc that converts a function into a WrapperOption interface
type wrapperOptionFunc func(interface{})
// Reports interface adherence
var _ WrapperOption = wrapperOptionFunc(nil)
// Commented out until used because of... linter.
//type addWrapperConfig interface {
// addWrapperConfig(WrapperOption)
//}
// ApplyWrapperConfig Converts function into an object to match interface
func (f wrapperOptionFunc) ApplyWrapperConfig(fr interface{}) {
f(fr)
}
// BoxLine is a FolderOption that tells the Liner to draw a box around the line mostly for debugging purposes but will be
// the basis of how select and highlighting could work
var BoxLine = folderOptionFunc(func(f interface{}) {
if f, ok := f.(*SimpleFolder); ok {
f.lineOptions = append(f.lineOptions, func(line Line) {
switch line := line.(type) {
case interface{ turnOnBox() }:
line.turnOnBox()
default:
log.Printf("can't apply")
}
})
}
})
// NewPageBreakBox is a FolderOption that tells the Liner to add a chevron image to the end of every text block that continues
// past the given rect.
func NewPageBreakBox(b Box, opts ...BoxerOption) WrapperOption {
return folderOptionFunc(func(f interface{}) {
for _, o := range opts {
o.ApplyBoxConfig(b)
}
switch f := f.(type) {
case interface{ setPageBreakBox(b Box) }:
f.setPageBreakBox(b)
default:
log.Printf("can't apply")
}
})
}
// YOverflow is a FolderOption that sets the type over overflow mode we will allow
func YOverflow(i OverflowMode) WrapperOption {
return folderOptionFunc(func(f interface{}) {
if f, ok := f.(*SimpleFolder); ok {
f.yOverflow = i
}
})
}
// BoxBox is a BoxerOption that tells the Box to draw a box around itself mostly for debugging purposes but will be
// the basis of how select and highlighting could work, such as the cursor
var BoxBox = boxerOptionFunc(func(f interface{}) {
bf := func(box Box) {
switch box := box.(type) {
case interface{ turnOnBox() }:
box.turnOnBox()
}
}
switch f := f.(type) {
case *SimpleBoxer:
f.postBoxOptions = append(f.postBoxOptions, bf)
case Box:
bf(f)
}
})
// ImageBoxOption modifiers for the ImageBox
type ImageBoxOption interface {
applyImageBoxOption(box *ImageBox)
}
//
type imageBoxOptionMetricCalcFunc func(ib2 *ImageBox) font.Metrics
func (i imageBoxOptionMetricCalcFunc) applyImageBoxOption(box *ImageBox) {
box.metricCalc = i
}
var _ ImageBoxOption = (imageBoxOptionMetricCalcFunc)(nil)
// ImageBoxMetricAboveTheLine Puts the image above the baseline as you would expect if you were using a word processor
var ImageBoxMetricAboveTheLine imageBoxOptionMetricCalcFunc = func(ib *ImageBox) font.Metrics {
return font.Metrics{
Height: fixed.I(ib.I.Bounds().Dy()),
Ascent: fixed.I(ib.I.Bounds().Dy()),
}
}
// ImageBoxMetricBelowTheLine Puts the image above the baseline. Rarely done
var ImageBoxMetricBelowTheLine imageBoxOptionMetricCalcFunc = func(ib *ImageBox) font.Metrics {
return font.Metrics{
Height: fixed.I(ib.I.Bounds().Dy()),
Descent: fixed.I(ib.I.Bounds().Dy()),
}
}
// ImageBoxMetricCenter Puts the image running from the top down
var ImageBoxMetricCenter = func(fd *font.Drawer) imageBoxOptionMetricCalcFunc {
return func(ib *ImageBox) font.Metrics {
if fd == nil {
fd = ib.fontDrawer
}
if fd == nil {
return ImageBoxMetricBelowTheLine(ib)
}
m := fd.Face.Metrics()
return font.Metrics{
Height: fixed.I(ib.I.Bounds().Dy()),
Descent: fixed.I(ib.I.Bounds().Dy())/2 - m.Descent/2,
Ascent: fixed.I(ib.I.Bounds().Dy())/2 + m.Descent/2,
}
}
}
// FontDrawer a wrapper around *font.Draw used to set the font
type FontDrawer struct {
d *font.Drawer
}
// NewFontDrawer a wrapper around *font.Draw used to set the font mostly for image
func NewFontDrawer(d *font.Drawer) *FontDrawer {
return &FontDrawer{
d: d,
}
}
// applyImageBoxOption
func (f *FontDrawer) applyImageBoxOption(box *ImageBox) {
box.fontDrawer = f.d
}
var (
// Enforce interface adherence
_ ImageBoxOption = (*FontDrawer)(nil)
)
// HorizontalLinePosition is the type for per-line level alignment.
type HorizontalLinePosition int
const (
// LeftLines default, produces lines that are individually left justified.
LeftLines HorizontalLinePosition = iota
// HorizontalCenterLines produces lines that are individually center justified.
HorizontalCenterLines
// RightLines produces lines that are individually right justified.
RightLines
)
var (
// Ensures interface compliance
_ FolderOption = LeftLines
// Ensures interface compliance
_ WrapperOption = LeftLines
)
// ApplyWrapperConfig Is required to pass the configuration through to the appropriate level -- Hopefully will be
// refactored
func (hp HorizontalLinePosition) ApplyWrapperConfig(wr interface{}) {
if wr, ok := wr.(addFoldConfig); ok {
wr.addFoldConfig(hp)
} else {
log.Printf("can't apply")
}
}
// ApplyFoldConfig applies the configuration to the wrapper where it will be stored in the line.
func (hp HorizontalLinePosition) ApplyFoldConfig(f interface{}) {
if f, ok := f.(*SimpleFolder); ok {
f.lineOptions = append(f.lineOptions, func(line Line) {
switch line := line.(type) {
case interface{ horizontalPosition(HorizontalLinePosition) }:
line.horizontalPosition(hp)
default:
log.Printf("can't apply")
}
})
}
}
// HorizontalBlockPosition information about how to position the entire block of text rather than just the line horizontally
type HorizontalBlockPosition int
const (
// LeftBLock positions the entire block of text left rather than just the line horizontally (default)
LeftBLock HorizontalBlockPosition = iota
// HorizontalCenterBlock positions the entire block of text center rather than just the line horizontally
HorizontalCenterBlock
// RightBlock positions the entire block of text right rather than just the line horizontally
RightBlock
)
// Interface enforcement
var _ WrapperOption = LeftBLock
// ApplyWrapperConfig Stores the position against the wrapper object
func (hp HorizontalBlockPosition) ApplyWrapperConfig(wr interface{}) {
switch block := wr.(type) {
case interface{ horizontalPosition(HorizontalBlockPosition) }:
block.horizontalPosition(hp)
default:
log.Printf("can't apply")
}
}
// VerticalBlockPosition information about how to position the entire block of text rather than just the line vertically
type VerticalBlockPosition int
const (
// TopBLock positions the entire block of text top
TopBLock VerticalBlockPosition = iota
// VerticalCenterBlock positions the entire block of text center
VerticalCenterBlock
// BottomBlock positions the entire block of text bottom
BottomBlock
)
// Interface enforcement
var _ WrapperOption = TopBLock
// ApplyWrapperConfig Stores the position against the wrapper object
func (hp VerticalBlockPosition) ApplyWrapperConfig(wr interface{}) {
switch block := wr.(type) {
case interface{ verticalPosition(VerticalBlockPosition) }:
block.verticalPosition(hp)
default:
log.Printf("can't apply")
}
}