-
Notifications
You must be signed in to change notification settings - Fork 0
/
textbox.go
216 lines (179 loc) · 5.32 KB
/
textbox.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
package turdgl
import (
"image/color"
"github.com/veandco/go-sdl2/sdl"
)
// TextBox is a shape that can be typed in.
type TextBox struct {
Shape hoverable // the base shape the text box is built on
Text *Text // the text in the text box
selectedCB func() // callback function for when the text box is selected (optional)
deselectedCB func() // callback function for when the text box is deselected (optional)
modifiedCB func() // callback function for when the text changes (optional)
isEditing bool
prevText string
}
// NewTextBox constructs a new text box from a hoverable shape.
func NewTextBox(shape hoverable, text, fontPath string) *TextBox {
return &TextBox{
Shape: shape,
Text: NewText(text, shape.GetPos(), fontPath).SetAlignment(AlignCentre),
selectedCB: func() {},
deselectedCB: func() {},
modifiedCB: func() {},
isEditing: false,
prevText: text,
}
}
// Draw draws the text box onto the frame buffer.
func (t *TextBox) Draw(buf *FrameBuffer) {
t.Shape.Draw(buf)
// Align to centre of underlying shape
t.Text.SetPos(func() Vec {
switch t.Shape.(type) {
case *Rect, *CurvedRect:
p := t.Shape.GetPos()
return Vec{p.X + t.Shape.Width()/2, p.Y + t.Shape.Height()/2}
default:
return t.Shape.GetPos()
}
}())
t.Text.Draw(buf)
if t.isEditing {
// TODO: Draw cursor
// NOTE: this is complicated. Text editing may need its own package
}
}
// Update handles user interactions with the text box.
func (t *TextBox) Update(win *Window) {
// Enter editing mode if text box is clicked
if win.MouseButtonState() == LeftClick {
if t.Shape.IsWithin(win.MouseLocation()) {
t.isEditing = true
win.engine.textMutator.Load(t.Text.Text())
t.selectedCB() // user-defined callback
} else {
t.isEditing = false
t.deselectedCB() // user-defined callback
}
}
if t.isEditing {
t.SetText(win.engine.textMutator.String())
}
if t.Text.body != t.prevText {
t.modifiedCB()
}
t.prevText = t.Text.body
}
// SetSelectedCB sets the callback function which is triggered when the text box is selected.
func (t *TextBox) SetSelectedCB(fn func()) *TextBox {
t.selectedCB = fn
return t
}
// SetDeselectedCB sets the callback function which is triggered when the text box is deselected.
func (t *TextBox) SetDeselectedCB(fn func()) *TextBox {
t.deselectedCB = fn
return t
}
// SetModifiedCB sets the callback function which is triggered when the text is modified.
func (t *TextBox) SetModifiedCB(fn func()) *TextBox {
t.modifiedCB = fn
return t
}
// SetPos sets the position of the text box.
func (t *TextBox) SetPos(pos Vec) *TextBox {
t.Shape.SetPos(pos)
return t
}
// Move moves the text box by a given vector.
func (t *TextBox) Move(mov Vec) {
t.Shape.Move(mov)
t.Text.Move(mov)
}
// SetCallback configures a callback function to execute every time the text
// in the text box is updated by the user.
func (t *TextBox) SetCallback(callback func()) *TextBox {
t.modifiedCB = callback
return t
}
// IsEditing returns whether the text box is in edit mode.
func (t *TextBox) IsEditing() bool {
return t.isEditing
}
// SetEditing sets whether the text box is in edit mode or not.
func (t *TextBox) SetEditing(editMode bool) *TextBox {
t.isEditing = editMode
return t
}
// SetText sets the text to the given string.
func (t *TextBox) SetText(s string) *TextBox {
t.Text.SetText(s)
return t
}
// SetTextAlignment sets the alignment of the text relative to the text box.
func (t *TextBox) SetTextAlignment(align Alignment) *TextBox {
t.Text.SetAlignment(align)
return t
}
// SetTextOffset manually sets the text's offset, providing the text is in AlignCustom mode.
func (t *TextBox) SetTextOffset(offset Vec) *TextBox {
t.Text.SetOffset(offset)
return t
}
// SetTextColour sets the text colour.
func (t *TextBox) SetTextColour(c color.Color) *TextBox {
t.Text.SetColour(c)
return t
}
// SetTextFont sets the path fo the .ttf file that is used to generate the text.
func (t *TextBox) SetTextFont(path string) error {
return t.Text.SetFont(path)
}
// SetTextDPI sets the DPI of the text font.
func (t *TextBox) SetTextDPI(dpi float64) *TextBox {
t.Text.SetDPI(dpi)
return t
}
// SetTextSize sets the size of the text font.
func (t *TextBox) SetTextSize(size float64) *TextBox {
t.Text.SetSize(size)
return t
}
// SetTextSpacing sets the line spacing of the text.
func (t *TextBox) SetTextSpacing(spacing float64) *TextBox {
t.Text.SetSpacing(spacing)
return t
}
// textMutator allows the user to modify text.
type textMutator struct {
buffer string
}
// newTextTracker constructs a text tracker object.
func newTextTracker() *textMutator {
return &textMutator{}
}
// Load loads a string into the text mutator so it can be modified.
func (t *textMutator) Load(s string) {
t.buffer = s
}
// Append appends a string to the text mutator.
func (t *textMutator) Append(s string) {
t.buffer += s
}
// String returns the string stored in the text mutator.
func (t *textMutator) String() string {
return t.buffer
}
// handleEvent processes key press events.
func (t *textMutator) handleEvent(event *sdl.KeyboardEvent) {
if event.Keysym.Sym == KeyBackspace && event.State == sdl.PRESSED {
t.backspace()
}
}
// backspace removes the last character from the text.
func (t *textMutator) backspace() {
if len(t.buffer) == 0 {
return
}
t.buffer = t.buffer[:len(t.buffer)-1]
}