summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-12-09 20:46:03 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-12-09 20:46:03 +0200
commitd72b54573599a8377d24d2812896ba2f8a11c6d3 (patch)
tree033013a65e8037b6447d46cd5792d0cb98eed234
parentcf8b7c568d1b537f833937ecf8dba19df379121e (diff)
InputWidget: Usability improvements
Select all when search bar gets focus, so it's easy to enter a new search term. One press of Escape will both unfocus and dismiss the search bar. IssueID #65
-rw-r--r--src/ui/inputwidget.c58
-rw-r--r--src/ui/inputwidget.h1
-rw-r--r--src/ui/window.c2
3 files changed, 36 insertions, 25 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index fbcbd4c2..4f9bd367 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -49,20 +49,25 @@ static void deinit_InputUndo_(iInputUndo *d) {
49 deinit_Array(&d->text); 49 deinit_Array(&d->text);
50} 50}
51 51
52enum iInputWidgetFlag {
53 isSensitive_InputWidgetFlag = iBit(1),
54 enterPressed_InputWidgetFlag = iBit(2),
55 selectAllOnFocus_InputWidgetFlag = iBit(3),
56 notifyEdits_InputWidgetFlag = iBit(4),
57 eatEscape_InputWidgetFlag = iBit(5),
58 isMarking_InputWidgetFlag = iBit(6),
59};
60
52struct Impl_InputWidget { 61struct Impl_InputWidget {
53 iWidget widget; 62 iWidget widget;
54 enum iInputMode mode; 63 enum iInputMode mode;
55 iBool isSensitive; 64 int inFlags;
56 iBool enterPressed;
57 iBool selectAllOnFocus;
58 iBool notifyEdits;
59 size_t maxLen; 65 size_t maxLen;
60 iArray text; /* iChar[] */ 66 iArray text; /* iChar[] */
61 iArray oldText; /* iChar[] */ 67 iArray oldText; /* iChar[] */
62 iString hint; 68 iString hint;
63 size_t cursor; 69 size_t cursor;
64 size_t lastCursor; 70 size_t lastCursor;
65 iBool isMarking;
66 iRanges mark; 71 iRanges mark;
67 iArray undoStack; 72 iArray undoStack;
68 int font; 73 int font;
@@ -96,11 +101,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
96 d->font = uiInput_FontId; 101 d->font = uiInput_FontId;
97 d->cursor = 0; 102 d->cursor = 0;
98 d->lastCursor = 0; 103 d->lastCursor = 0;
99 d->isMarking = iFalse; 104 d->inFlags = eatEscape_InputWidgetFlag;
100 d->isSensitive = iFalse;
101 d->enterPressed = iFalse;
102 d->selectAllOnFocus = iFalse;
103 d->notifyEdits = iFalse;
104 iZap(d->mark); 105 iZap(d->mark);
105 setMaxLen_InputWidget(d, maxLen); 106 setMaxLen_InputWidget(d, maxLen);
106 /* Caller must arrange the width, but the height is fixed. */ 107 /* Caller must arrange the width, but the height is fixed. */
@@ -152,7 +153,7 @@ void setMode_InputWidget(iInputWidget *d, enum iInputMode mode) {
152} 153}
153 154
154void setSensitive_InputWidget(iInputWidget *d, iBool isSensitive) { 155void setSensitive_InputWidget(iInputWidget *d, iBool isSensitive) {
155 d->isSensitive = isSensitive; 156 iChangeFlags(d->inFlags, isSensitive_InputWidgetFlag, isSensitive);
156} 157}
157 158
158const iString *text_InputWidget(const iInputWidget *d) { 159const iString *text_InputWidget(const iInputWidget *d) {
@@ -182,7 +183,7 @@ static const iChar sensitiveChar_ = 0x25cf; /* black circle */
182 183
183static iString *visText_InputWidget_(const iInputWidget *d) { 184static iString *visText_InputWidget_(const iInputWidget *d) {
184 iString *text; 185 iString *text;
185 if (!d->isSensitive) { 186 if (~d->inFlags & isSensitive_InputWidgetFlag) {
186 text = newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text)); 187 text = newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text));
187 } 188 }
188 else { 189 else {
@@ -271,8 +272,8 @@ void begin_InputWidget(iInputWidget *d) {
271 showCursor_InputWidget_(d); 272 showCursor_InputWidget_(d);
272 refresh_Widget(w); 273 refresh_Widget(w);
273 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d); 274 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d);
274 d->enterPressed = iFalse; 275 d->inFlags &= ~enterPressed_InputWidgetFlag;
275 if (d->selectAllOnFocus) { 276 if (d->inFlags & selectAllOnFocus_InputWidgetFlag) {
276 d->mark = (iRanges){ 0, size_Array(&d->text) }; 277 d->mark = (iRanges){ 0, size_Array(&d->text) };
277 } 278 }
278 else { 279 else {
@@ -297,8 +298,11 @@ void end_InputWidget(iInputWidget *d, iBool accept) {
297 const char *id = cstr_String(id_Widget(as_Widget(d))); 298 const char *id = cstr_String(id_Widget(as_Widget(d)));
298 if (!*id) id = "_"; 299 if (!*id) id = "_";
299 refresh_Widget(w); 300 refresh_Widget(w);
300 postCommand_Widget( 301 postCommand_Widget(w,
301 w, "input.ended id:%s enter:%d arg:%d", id, d->enterPressed ? 1 : 0, accept ? 1 : 0); 302 "input.ended id:%s enter:%d arg:%d",
303 id,
304 d->inFlags & enterPressed_InputWidgetFlag ? 1 : 0,
305 accept ? 1 : 0);
302} 306}
303 307
304static void insertChar_InputWidget_(iInputWidget *d, iChar chr) { 308static void insertChar_InputWidget_(iInputWidget *d, iChar chr) {
@@ -351,11 +355,15 @@ void setCursor_InputWidget(iInputWidget *d, size_t pos) {
351} 355}
352 356
353void setSelectAllOnFocus_InputWidget(iInputWidget *d, iBool selectAllOnFocus) { 357void setSelectAllOnFocus_InputWidget(iInputWidget *d, iBool selectAllOnFocus) {
354 d->selectAllOnFocus = selectAllOnFocus; 358 iChangeFlags(d->inFlags, selectAllOnFocus_InputWidgetFlag, selectAllOnFocus);
355} 359}
356 360
357void setNotifyEdits_InputWidget(iInputWidget *d, iBool notifyEdits) { 361void setNotifyEdits_InputWidget(iInputWidget *d, iBool notifyEdits) {
358 d->notifyEdits = notifyEdits; 362 iChangeFlags(d->inFlags, notifyEdits_InputWidgetFlag, notifyEdits);
363}
364
365void setEatEscape_InputWidget(iInputWidget *d, iBool eatEscape) {
366 iChangeFlags(d->inFlags, eatEscape_InputWidgetFlag, eatEscape);
359} 367}
360 368
361static iRanges mark_InputWidget_(const iInputWidget *d) { 369static iRanges mark_InputWidget_(const iInputWidget *d) {
@@ -366,7 +374,7 @@ static iRanges mark_InputWidget_(const iInputWidget *d) {
366} 374}
367 375
368static void contentsWereChanged_InputWidget_(iInputWidget *d) { 376static void contentsWereChanged_InputWidget_(iInputWidget *d) {
369 if (d->notifyEdits) { 377 if (d->inFlags & notifyEdits_InputWidgetFlag) {
370 postCommand_Widget(d, "input.edited id:%s", cstr_String(id_Widget(constAs_Widget(d)))); 378 postCommand_Widget(d, "input.edited id:%s", cstr_String(id_Widget(constAs_Widget(d))));
371 } 379 }
372} 380}
@@ -521,7 +529,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
521 setFocus_Widget(w); 529 setFocus_Widget(w);
522 setCursor_InputWidget(d, coordIndex_InputWidget_(d, pos_Click(&d->click))); 530 setCursor_InputWidget(d, coordIndex_InputWidget_(d, pos_Click(&d->click)));
523 iZap(d->mark); 531 iZap(d->mark);
524 d->isMarking = iFalse; 532 d->inFlags &= ~isMarking_InputWidgetFlag;
525 return iTrue; 533 return iTrue;
526 case double_ClickResult: 534 case double_ClickResult:
527 case aborted_ClickResult: 535 case aborted_ClickResult:
@@ -529,8 +537,8 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
529 case drag_ClickResult: 537 case drag_ClickResult:
530 showCursor_InputWidget_(d); 538 showCursor_InputWidget_(d);
531 d->cursor = coordIndex_InputWidget_(d, pos_Click(&d->click)); 539 d->cursor = coordIndex_InputWidget_(d, pos_Click(&d->click));
532 if (!d->isMarking) { 540 if (~d->inFlags & isMarking_InputWidgetFlag) {
533 d->isMarking = iTrue; 541 d->inFlags |= isMarking_InputWidgetFlag;
534 d->mark.start = d->cursor; 542 d->mark.start = d->cursor;
535 } 543 }
536 d->mark.end = d->cursor; 544 d->mark.end = d->cursor;
@@ -577,13 +585,13 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
577 switch (key) { 585 switch (key) {
578 case SDLK_RETURN: 586 case SDLK_RETURN:
579 case SDLK_KP_ENTER: 587 case SDLK_KP_ENTER:
580 d->enterPressed = iTrue; 588 d->inFlags |= enterPressed_InputWidgetFlag;
581 setFocus_Widget(NULL); 589 setFocus_Widget(NULL);
582 return iTrue; 590 return iTrue;
583 case SDLK_ESCAPE: 591 case SDLK_ESCAPE:
584 end_InputWidget(d, iFalse); 592 end_InputWidget(d, iFalse);
585 setFocus_Widget(NULL); 593 setFocus_Widget(NULL);
586 return iTrue; 594 return (d->inFlags & eatEscape_InputWidgetFlag) != 0;
587 case SDLK_BACKSPACE: 595 case SDLK_BACKSPACE:
588 if (!isEmpty_Range(&d->mark)) { 596 if (!isEmpty_Range(&d->mark)) {
589 pushUndo_InputWidget_(d); 597 pushUndo_InputWidget_(d);
@@ -771,7 +779,7 @@ static void draw_InputWidget_(const iInputWidget *d) {
771 if (isFocused && d->cursorVis) { 779 if (isFocused && d->cursorVis) {
772 iString cur; 780 iString cur;
773 if (d->cursor < size_Array(&d->text)) { 781 if (d->cursor < size_Array(&d->text)) {
774 if (!d->isSensitive) { 782 if (~d->inFlags & isSensitive_InputWidgetFlag) {
775 initUnicodeN_String(&cur, constAt_Array(&d->text, d->cursor), 1); 783 initUnicodeN_String(&cur, constAt_Array(&d->text, d->cursor), 1);
776 } 784 }
777 else { 785 else {
diff --git a/src/ui/inputwidget.h b/src/ui/inputwidget.h
index f146ea00..7fb8a8bd 100644
--- a/src/ui/inputwidget.h
+++ b/src/ui/inputwidget.h
@@ -41,6 +41,7 @@ void setTextCStr_InputWidget (iInputWidget *, const char *cstr);
41void setCursor_InputWidget (iInputWidget *, size_t pos); 41void setCursor_InputWidget (iInputWidget *, size_t pos);
42void setSelectAllOnFocus_InputWidget (iInputWidget *, iBool selectAllOnFocus); 42void setSelectAllOnFocus_InputWidget (iInputWidget *, iBool selectAllOnFocus);
43void setNotifyEdits_InputWidget (iInputWidget *, iBool notifyEdits); 43void setNotifyEdits_InputWidget (iInputWidget *, iBool notifyEdits);
44void setEatEscape_InputWidget(iInputWidget *, iBool eatEscape);
44void begin_InputWidget (iInputWidget *); 45void begin_InputWidget (iInputWidget *);
45void end_InputWidget (iInputWidget *, iBool accept); 46void end_InputWidget (iInputWidget *, iBool accept);
46void selectAll_InputWidget (iInputWidget *); 47void selectAll_InputWidget (iInputWidget *);
diff --git a/src/ui/window.c b/src/ui/window.c
index 1bf9065e..867f535d 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -486,6 +486,8 @@ static void setupUserInterface_Window(iWindow *d) {
486 addChildFlags_Widget( 486 addChildFlags_Widget(
487 searchBar, iClob(new_LabelWidget("\U0001f50d Text", NULL)), frameless_WidgetFlag); 487 searchBar, iClob(new_LabelWidget("\U0001f50d Text", NULL)), frameless_WidgetFlag);
488 iInputWidget *input = new_InputWidget(0); 488 iInputWidget *input = new_InputWidget(0);
489 setSelectAllOnFocus_InputWidget(input, iTrue);
490 setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */
489 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), 491 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag),
490 "find.input"); 492 "find.input");
491 addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next"))); 493 addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9f ", 'g', KMOD_PRIMARY, "find.next")));