diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-28 14:14:06 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-28 14:14:06 +0200 |
commit | a5c03e9464d2c2d2f07aff7d26617c6de6dda5d9 (patch) | |
tree | 585ba5940b742e138a4d5f040e79f62b5ccdc1f6 /src/ui/inputwidget.c | |
parent | 0a93ff20b1a855222a158b13071cc48f4f03aba1 (diff) |
InputWidget: Buffer contents of unfocused input fields
No need to redraw the text string on every frame.
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r-- | src/ui/inputwidget.c | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 0fcca40a..56192e27 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -69,6 +69,7 @@ struct Impl_InputWidget { | |||
69 | iClick click; | 69 | iClick click; |
70 | int cursorVis; | 70 | int cursorVis; |
71 | uint32_t timer; | 71 | uint32_t timer; |
72 | iTextBuf * buffered; | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | iDefineObjectConstructionArgs(InputWidget, (size_t maxLen), maxLen) | 75 | iDefineObjectConstructionArgs(InputWidget, (size_t maxLen), maxLen) |
@@ -108,9 +109,11 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) { | |||
108 | init_Click(&d->click, d, SDL_BUTTON_LEFT); | 109 | init_Click(&d->click, d, SDL_BUTTON_LEFT); |
109 | d->timer = 0; | 110 | d->timer = 0; |
110 | d->cursorVis = 0; | 111 | d->cursorVis = 0; |
112 | d->buffered = NULL; | ||
111 | } | 113 | } |
112 | 114 | ||
113 | void deinit_InputWidget(iInputWidget *d) { | 115 | void deinit_InputWidget(iInputWidget *d) { |
116 | delete_TextBuf(d->buffered); | ||
114 | clearUndo_InputWidget_(d); | 117 | clearUndo_InputWidget_(d); |
115 | deinit_Array(&d->undoStack); | 118 | deinit_Array(&d->undoStack); |
116 | if (d->timer) { | 119 | if (d->timer) { |
@@ -175,6 +178,36 @@ void setHint_InputWidget(iInputWidget *d, const char *hintText) { | |||
175 | setCStr_String(&d->hint, hintText); | 178 | setCStr_String(&d->hint, hintText); |
176 | } | 179 | } |
177 | 180 | ||
181 | static const iChar sensitiveChar_ = 0x25cf; /* black circle */ | ||
182 | |||
183 | static iString *visText_InputWidget_(const iInputWidget *d) { | ||
184 | iString *text; | ||
185 | if (!d->isSensitive) { | ||
186 | text = newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text)); | ||
187 | } | ||
188 | else { | ||
189 | text = new_String(); | ||
190 | for (size_t i = 0; i < size_Array(&d->text); ++i) { | ||
191 | appendChar_String(text, sensitiveChar_); | ||
192 | } | ||
193 | } | ||
194 | return text; | ||
195 | } | ||
196 | |||
197 | static void invalidateBuffered_InputWidget_(iInputWidget *d) { | ||
198 | if (d->buffered) { | ||
199 | delete_TextBuf(d->buffered); | ||
200 | d->buffered = NULL; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void updateBuffered_InputWidget_(iInputWidget *d) { | ||
205 | invalidateBuffered_InputWidget_(d); | ||
206 | iString *visText = visText_InputWidget_(d); | ||
207 | d->buffered = new_TextBuf(d->font, cstr_String(visText)); | ||
208 | delete_String(visText); | ||
209 | } | ||
210 | |||
178 | void setText_InputWidget(iInputWidget *d, const iString *text) { | 211 | void setText_InputWidget(iInputWidget *d, const iString *text) { |
179 | clearUndo_InputWidget_(d); | 212 | clearUndo_InputWidget_(d); |
180 | clear_Array(&d->text); | 213 | clear_Array(&d->text); |
@@ -189,6 +222,9 @@ void setText_InputWidget(iInputWidget *d, const iString *text) { | |||
189 | d->cursor = iMin(d->cursor, size_Array(&d->text)); | 222 | d->cursor = iMin(d->cursor, size_Array(&d->text)); |
190 | iZap(d->mark); | 223 | iZap(d->mark); |
191 | } | 224 | } |
225 | if (!isFocused_Widget(d)) { | ||
226 | updateBuffered_InputWidget_(d); | ||
227 | } | ||
192 | refresh_Widget(as_Widget(d)); | 228 | refresh_Widget(as_Widget(d)); |
193 | } | 229 | } |
194 | 230 | ||
@@ -221,6 +257,7 @@ void begin_InputWidget(iInputWidget *d) { | |||
221 | /* Already active. */ | 257 | /* Already active. */ |
222 | return; | 258 | return; |
223 | } | 259 | } |
260 | invalidateBuffered_InputWidget_(d); | ||
224 | setFlags_Widget(w, hidden_WidgetFlag | disabled_WidgetFlag, iFalse); | 261 | setFlags_Widget(w, hidden_WidgetFlag | disabled_WidgetFlag, iFalse); |
225 | setCopy_Array(&d->oldText, &d->text); | 262 | setCopy_Array(&d->oldText, &d->text); |
226 | if (d->mode == overwrite_InputMode) { | 263 | if (d->mode == overwrite_InputMode) { |
@@ -252,6 +289,7 @@ void end_InputWidget(iInputWidget *d, iBool accept) { | |||
252 | if (!accept) { | 289 | if (!accept) { |
253 | setCopy_Array(&d->text, &d->oldText); | 290 | setCopy_Array(&d->text, &d->oldText); |
254 | } | 291 | } |
292 | updateBuffered_InputWidget_(d); | ||
255 | SDL_RemoveTimer(d->timer); | 293 | SDL_RemoveTimer(d->timer); |
256 | d->timer = 0; | 294 | d->timer = 0; |
257 | SDL_StopTextInput(); | 295 | SDL_StopTextInput(); |
@@ -393,22 +431,6 @@ static size_t skipWord_InputWidget_(const iInputWidget *d, size_t pos, int dir) | |||
393 | return pos; | 431 | return pos; |
394 | } | 432 | } |
395 | 433 | ||
396 | static const iChar sensitiveChar_ = 0x25cf; /* black circle */ | ||
397 | |||
398 | static iString *visText_InputWidget_(const iInputWidget *d) { | ||
399 | iString *text; | ||
400 | if (!d->isSensitive) { | ||
401 | text = newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text)); | ||
402 | } | ||
403 | else { | ||
404 | text = new_String(); | ||
405 | for (size_t i = 0; i < size_Array(&d->text); ++i) { | ||
406 | appendChar_String(text, sensitiveChar_); | ||
407 | } | ||
408 | } | ||
409 | return text; | ||
410 | } | ||
411 | |||
412 | iLocalDef iInt2 padding_(void) { | 434 | iLocalDef iInt2 padding_(void) { |
413 | return init_I2(gap_UI / 2, gap_UI / 2); | 435 | return init_I2(gap_UI / 2, gap_UI / 2); |
414 | } | 436 | } |
@@ -467,6 +489,12 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
467 | end_InputWidget(d, iTrue); | 489 | end_InputWidget(d, iTrue); |
468 | return iFalse; | 490 | return iFalse; |
469 | } | 491 | } |
492 | else if (isCommand_UserEvent(ev, "theme.changed")) { | ||
493 | if (d->buffered) { | ||
494 | updateBuffered_InputWidget_(d); | ||
495 | } | ||
496 | return iFalse; | ||
497 | } | ||
470 | switch (processEvent_Click(&d->click, ev)) { | 498 | switch (processEvent_Click(&d->click, ev)) { |
471 | case none_ClickResult: | 499 | case none_ClickResult: |
472 | break; | 500 | break; |
@@ -715,13 +743,19 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
715 | init_I2(iAbs(m2 - m1), lineHeight_Text(d->font)) }, | 743 | init_I2(iAbs(m2 - m1), lineHeight_Text(d->font)) }, |
716 | uiMarked_ColorId); | 744 | uiMarked_ColorId); |
717 | } | 745 | } |
718 | draw_Text(d->font, | 746 | if (d->buffered && !isFocused && !isHint) { |
719 | textOrigin, | 747 | /* Most input widgets will use this, since only one is focused at a time. */ |
720 | isHint ? uiAnnotation_ColorId | 748 | draw_TextBuf(d->buffered, textOrigin, uiInputText_ColorId); |
721 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId | 749 | } |
722 | : uiInputText_ColorId, | 750 | else { |
723 | "%s", | 751 | draw_Text(d->font, |
724 | cstr_String(text)); | 752 | textOrigin, |
753 | isHint ? uiAnnotation_ColorId | ||
754 | : isFocused && !isEmpty_Array(&d->text) ? uiInputTextFocused_ColorId | ||
755 | : uiInputText_ColorId, | ||
756 | "%s", | ||
757 | cstr_String(text)); | ||
758 | } | ||
725 | unsetClip_Paint(&p); | 759 | unsetClip_Paint(&p); |
726 | /* Cursor blinking. */ | 760 | /* Cursor blinking. */ |
727 | if (isFocused && d->cursorVis) { | 761 | if (isFocused && d->cursorVis) { |