...
1 package messeji
2
3 import (
4 "sync"
5
6 "github.com/hajimehoshi/ebiten/v2"
7 "github.com/hajimehoshi/ebiten/v2/inpututil"
8 "github.com/hajimehoshi/ebiten/v2/text/v2"
9 )
10
11
12
13
14
15
16 type InputField struct {
17 *TextField
18
19
20
21 changedFunc func(r rune) (accept bool)
22
23
24
25 selectedFunc func() (accept bool)
26
27
28 readBuffer []rune
29
30
31 keyBuffer []ebiten.Key
32
33
34 rawRuneBuffer []rune
35
36
37 rawKeyBuffer []ebiten.Key
38
39 sync.Mutex
40 }
41
42
43 func NewInputField(fontSource *text.GoTextFaceSource, fontSize int, fontMutex *sync.Mutex) *InputField {
44 f := &InputField{
45 TextField: NewTextField(fontSource, fontSize, fontMutex),
46 }
47 f.TextField.SetFollow(true)
48 f.TextField.suffix = "_"
49 return f
50 }
51
52
53
54 func (f *InputField) SetHandleKeyboard(handle bool) {
55 f.Lock()
56 defer f.Unlock()
57
58 f.handleKeyboard = handle
59 }
60
61
62
63 func (f *InputField) SetChangedFunc(changedFunc func(r rune) (accept bool)) {
64 f.changedFunc = changedFunc
65 }
66
67
68
69
70 func (f *InputField) SetSelectedFunc(selectedFunc func() (accept bool)) {
71 f.selectedFunc = selectedFunc
72 }
73
74
75 func (f *InputField) HandleKeyboardEvent(key ebiten.Key, r rune) (handled bool, err error) {
76 f.Lock()
77 defer f.Unlock()
78
79 if !f.visible || rectIsZero(f.r) {
80 return
81 }
82
83 if !f.handleKeyboard {
84 return
85 }
86
87
88 if r > 0 {
89 ok := f.handleRunes([]rune{r})
90 if ok {
91 f.resizeFont()
92 }
93 return true, nil
94 }
95
96
97 ok := f.handleKeys([]ebiten.Key{key})
98 if ok {
99 f.resizeFont()
100 }
101 return true, nil
102 }
103
104 func (f *InputField) handleRunes(runes []rune) bool {
105 var redraw bool
106 for _, r := range runes {
107 if f.changedFunc != nil {
108 f.Unlock()
109 accept := f.changedFunc(r)
110 f.Lock()
111 if !accept {
112 continue
113 }
114 }
115
116 f.TextField._write([]byte(string(r)))
117 redraw = true
118 }
119
120 return redraw
121 }
122
123 func (f *InputField) handleKeys(keys []ebiten.Key) bool {
124 var redraw bool
125 for _, key := range keys {
126 switch key {
127 case ebiten.KeyBackspace:
128 l := len(f.buffer)
129 if l > 0 {
130 if f.changedFunc != nil {
131 f.Unlock()
132 accept := f.changedFunc(0)
133 f.Lock()
134 if !accept {
135 continue
136 }
137 }
138
139 var rewrap bool
140 if len(f.incoming) != 0 {
141 line := string(f.incoming)
142 f.incoming = append(f.incoming, []byte(line[:len(line)-1])...)
143 } else if len(f.buffer[l-1]) == 0 {
144 f.buffer = f.buffer[:l-1]
145 rewrap = true
146 } else {
147 line := string(f.buffer[l-1])
148 f.buffer[l-1] = []byte(line[:len(line)-1])
149 rewrap = true
150 }
151 if rewrap && (f.needWrap == -1 || f.needWrap > l-1) {
152 f.needWrap = l - 1
153 }
154 redraw = true
155 f.modified = true
156 f.redraw = true
157 }
158 case ebiten.KeyEnter, ebiten.KeyKPEnter:
159 if f.selectedFunc != nil {
160 f.Unlock()
161 accept := f.selectedFunc()
162 f.Lock()
163
164
165 if accept {
166 f.incoming = f.incoming[:0]
167 f.buffer = f.buffer[:0]
168 f.bufferWrapped = f.bufferWrapped[:0]
169 f.lineWidths = f.lineWidths[:0]
170 f.needWrap = 0
171 f.wrapStart = 0
172 f.modified = true
173 f.redraw = true
174 redraw = true
175 }
176 } else if !f.singleLine {
177
178 f.incoming = append(f.incoming, '\n')
179 f.modified = true
180 f.redraw = true
181 redraw = true
182 }
183 }
184 }
185 return redraw
186 }
187
188
189
190 func (f *InputField) Update() error {
191 f.Lock()
192 defer f.Unlock()
193
194 if !f.visible || rectIsZero(f.r) {
195 return nil
196 }
197
198 if !f.handleKeyboard {
199 return f.TextField.Update()
200 }
201
202 var redraw bool
203
204
205 f.readBuffer = ebiten.AppendInputChars(f.readBuffer[:0])
206 if f.handleRunes(f.readBuffer) {
207 redraw = true
208 }
209 if f.handleRunes(f.rawRuneBuffer) {
210 redraw = true
211 }
212 f.rawRuneBuffer = f.rawRuneBuffer[:0]
213
214
215 f.keyBuffer = inpututil.AppendJustPressedKeys(f.keyBuffer[:0])
216 if f.handleKeys(f.keyBuffer) {
217 redraw = true
218 }
219 if f.handleKeys(f.rawKeyBuffer) {
220 redraw = true
221 }
222 f.rawKeyBuffer = f.rawKeyBuffer[:0]
223
224 if redraw {
225 f.resizeFont()
226 f.bufferModified()
227 }
228
229 return f.TextField.Update()
230 }
231
View as plain text