188 {
189
190 bool didEdit = false, didCaptureEvent = false;
191
193
195
196 if (this->isEditable) {
197 if (event->type == SDL_EVENT_TEXT_INPUT) {
199 if (this->position == this->attributedText->length) {
200 $(this->attributedText, appendCharacters, event->text.text);
201 } else {
202 $(this->attributedText, insertCharactersAtIndex, event->text.text, this->position);
203 }
204 this->position += strlen(event->text.text);
205 didEdit = true;
206 didCaptureEvent = true;
207 }
208 } else if (event->type == SDL_EVENT_KEY_DOWN) {
209 didCaptureEvent = true;
210
211 const char *chars = this->attributedText->chars;
212 const size_t len = this->attributedText->length;
213
214 switch (event->key.key) {
215
216 case SDLK_ESCAPE:
217 case SDLK_KP_ENTER:
218 case SDLK_RETURN:
219 case SDLK_TAB:
220 case SDLK_KP_TAB:
222 break;
223
224 case SDLK_BACKSPACE:
225 case SDLK_KP_BACKSPACE:
226 if (this->position > 0) {
227 const Range range = { .location = this->position - 1, .length = 1 };
228 $(this->attributedText, deleteCharactersInRange, range);
229 this->position--;
230 didEdit = true;
231 }
232 break;
233
234 case SDLK_DELETE:
235 if (this->position < len) {
236 const Range range = { .location = this->position, .length = 1 };
237 $(this->attributedText, deleteCharactersInRange, range);
238 didEdit = true;
239 }
240 break;
241
242 case SDLK_LEFT:
243 if (SDL_GetModState() & SDL_KMOD_CTRL) {
244 while (this->position > 0 && chars[this->position] == ' ') {
245 this->position--;
246 }
247 while (this->position > 0 && chars[this->position] != ' ') {
248 this->position--;
249 }
250 } else if (this->position > 0) {
251 this->position--;
252 }
253 break;
254
255 case SDLK_RIGHT:
256 if (SDL_GetModState() & SDL_KMOD_CTRL) {
257 while (this->position < len && chars[this->position] == ' ') {
258 this->position++;
259 }
260 while (this->position < len && chars[this->position] != ' ') {
261 this->position++;
262 }
263 if (this->position < len) {
264 this->position++;
265 }
266 } else if (this->position < len) {
267 this->position++;
268 }
269 break;
270
271 case SDLK_HOME:
272 this->position = 0;
273 break;
274
275 case SDLK_END:
276 this->position = len;
277 break;
278
279 case SDLK_A:
280 if (SDL_GetModState() & SDL_KMOD_CTRL) {
281 this->position = 0;
282 }
283 break;
284 case SDLK_E:
285 if (SDL_GetModState() & SDL_KMOD_CTRL) {
286 this->position = len;
287 }
288 break;
289
290 case SDLK_V:
291 if ((SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_GUI)) && SDL_HasClipboardText()) {
292 char *text = SDL_GetClipboardText();
293 if (text != NULL) {
294 if (*text != '\0') {
295 if (this->position == len) {
296 $(this->attributedText, appendCharacters, text);
297 } else {
298 $(this->attributedText, insertCharactersAtIndex, text, this->position);
299 }
300 this->position += strlen(text);
301 didEdit = true;
302 }
303 SDL_free(text);
304 }
305 }
306 break;
307 }
308 }
309
310 if (didEdit) {
312 if (this->delegate.didEdit) {
313 this->delegate.didEdit(this);
314 }
315
317 }
318 }
319
320 if (didCaptureEvent) {
321 return true;
322 }
323
325}
static bool isFocused(const Control *self)
static bool captureEvent(Control *self, const SDL_Event *event)
static void resignKeyResponder(View *self)
@ ViewEventChange
A Control's input value has changed.
static void emitViewEvent(View *self, ViewEvent code, ident data)
Controls are Views which capture and respond to events.
bool needsLayout
If true, this View will layout its subviews before it is drawn.