summaryrefslogtreecommitdiff
path: root/src/ui/inputwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-08-06 12:09:11 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-08-06 12:09:11 +0300
commit4c176d97043e33bb9d2db264f0ecb4912e32d553 (patch)
treea4f77b9e543e6c433abfce1793dbf78bc265a977 /src/ui/inputwidget.c
parent018bbd0f90809108c04019d7f661f157250edc1c (diff)
InputWidget: Return key, input focus behavior
In the long-form text entry mode, don't use the user's configured Return key behavior, since that's meant for shorter input fields. Input fields no longer lose focus when the window loses input focus, but the cursor will stop blinking. This makes it easier to resume typing after switching window focus, and also on macOS the symbol picker is easier to use.
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r--src/ui/inputwidget.c75
1 files changed, 54 insertions, 21 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index d31130f5..f1f368b6 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -190,6 +190,7 @@ enum iInputWidgetFlag {
190 enterKeyEnabled_InputWidgetFlag = iBit(10), 190 enterKeyEnabled_InputWidgetFlag = iBit(10),
191 lineBreaksEnabled_InputWidgetFlag= iBit(11), 191 lineBreaksEnabled_InputWidgetFlag= iBit(11),
192 needBackup_InputWidgetFlag = iBit(12), 192 needBackup_InputWidgetFlag = iBit(12),
193 useReturnKeyBehavior_InputWidgetFlag = iBit(13),
193}; 194};
194 195
195/*----------------------------------------------------------------------------------------------*/ 196/*----------------------------------------------------------------------------------------------*/
@@ -566,6 +567,28 @@ static void updateAllLinesAndResizeHeight_InputWidget_(iInputWidget *d) {
566 } 567 }
567} 568}
568 569
570static uint32_t cursorTimer_(uint32_t interval, void *w) {
571 iInputWidget *d = w;
572 if (d->cursorVis > 1) {
573 d->cursorVis--;
574 }
575 else {
576 d->cursorVis ^= 1;
577 }
578 refresh_Widget(w);
579 return interval;
580}
581
582static void startOrStopCursorTimer_InputWidget_(iInputWidget *d, iBool doStart) {
583 if (doStart && !d->timer) {
584 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d);
585 }
586 else if (!doStart && d->timer) {
587 SDL_RemoveTimer(d->timer);
588 d->timer = 0;
589 }
590}
591
569void init_InputWidget(iInputWidget *d, size_t maxLen) { 592void init_InputWidget(iInputWidget *d, size_t maxLen) {
570 iWidget *w = &d->widget; 593 iWidget *w = &d->widget;
571 init_Widget(w); 594 init_Widget(w);
@@ -588,7 +611,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
588 d->prevCursor = zero_I2(); 611 d->prevCursor = zero_I2();
589 d->lastUpdateWidth = 0; 612 d->lastUpdateWidth = 0;
590 d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag | 613 d->inFlags = eatEscape_InputWidgetFlag | enterKeyEnabled_InputWidgetFlag |
591 lineBreaksEnabled_InputWidgetFlag; 614 lineBreaksEnabled_InputWidgetFlag | useReturnKeyBehavior_InputWidgetFlag;
592 // if (deviceType_App() != desktop_AppDeviceType) { 615 // if (deviceType_App() != desktop_AppDeviceType) {
593 // d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag; 616 // d->inFlags |= enterKeyInsertsLineFeed_InputWidgetFlag;
594 // } 617 // }
@@ -627,9 +650,7 @@ void deinit_InputWidget(iInputWidget *d) {
627 delete_TextBuf(d->buffered); 650 delete_TextBuf(d->buffered);
628 clearUndo_InputWidget_(d); 651 clearUndo_InputWidget_(d);
629 deinit_Array(&d->undoStack); 652 deinit_Array(&d->undoStack);
630 if (d->timer) { 653 startOrStopCursorTimer_InputWidget_(d, iFalse);
631 SDL_RemoveTimer(d->timer);
632 }
633 deinit_String(&d->srcHint); 654 deinit_String(&d->srcHint);
634 deinit_String(&d->hint); 655 deinit_String(&d->hint);
635 deinit_String(&d->oldText); 656 deinit_String(&d->oldText);
@@ -740,6 +761,10 @@ void setEnterKeyEnabled_InputWidget(iInputWidget *d, iBool enterKeyEnabled) {
740 iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled); 761 iChangeFlags(d->inFlags, enterKeyEnabled_InputWidgetFlag, enterKeyEnabled);
741} 762}
742 763
764void setUseReturnKeyBehavior_InputWidget(iInputWidget *d, iBool useReturnKeyBehavior) {
765 iChangeFlags(d->inFlags, useReturnKeyBehavior_InputWidgetFlag, useReturnKeyBehavior);
766}
767
743void setHint_InputWidget(iInputWidget *d, const char *hintText) { 768void setHint_InputWidget(iInputWidget *d, const char *hintText) {
744 /* Keep original for retranslations. */ 769 /* Keep original for retranslations. */
745 setCStr_String(&d->srcHint, hintText); 770 setCStr_String(&d->srcHint, hintText);
@@ -866,18 +891,6 @@ void setTextCStr_InputWidget(iInputWidget *d, const char *cstr) {
866 delete_String(str); 891 delete_String(str);
867} 892}
868 893
869static uint32_t cursorTimer_(uint32_t interval, void *w) {
870 iInputWidget *d = w;
871 if (d->cursorVis > 1) {
872 d->cursorVis--;
873 }
874 else {
875 d->cursorVis ^= 1;
876 }
877 refresh_Widget(w);
878 return interval;
879}
880
881static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) { 894static size_t cursorToIndex_InputWidget_(const iInputWidget *d, iInt2 pos) {
882 if (pos.y < 0) { 895 if (pos.y < 0) {
883 return 0; 896 return 0;
@@ -930,7 +943,7 @@ void begin_InputWidget(iInputWidget *d) {
930 setFlags_Widget(w, selected_WidgetFlag, iTrue); 943 setFlags_Widget(w, selected_WidgetFlag, iTrue);
931 showCursor_InputWidget_(d); 944 showCursor_InputWidget_(d);
932 refresh_Widget(w); 945 refresh_Widget(w);
933 d->timer = SDL_AddTimer(refreshInterval_InputWidget_, cursorTimer_, d); 946 startOrStopCursorTimer_InputWidget_(d, iTrue);
934 d->inFlags &= ~enterPressed_InputWidgetFlag; 947 d->inFlags &= ~enterPressed_InputWidgetFlag;
935 if (d->inFlags & selectAllOnFocus_InputWidgetFlag) { 948 if (d->inFlags & selectAllOnFocus_InputWidgetFlag) {
936 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end }; 949 d->mark = (iRanges){ 0, lastLine_InputWidget_(d)->range.end };
@@ -955,8 +968,7 @@ void end_InputWidget(iInputWidget *d, iBool accept) {
955 splitToLines_(&d->oldText, &d->lines); 968 splitToLines_(&d->oldText, &d->lines);
956 } 969 }
957 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 970 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
958 SDL_RemoveTimer(d->timer); 971 startOrStopCursorTimer_InputWidget_(d, iFalse);
959 d->timer = 0;
960 SDL_StopTextInput(); 972 SDL_StopTextInput();
961 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse); 973 setFlags_Widget(w, selected_WidgetFlag | keepOnTop_WidgetFlag, iFalse);
962 const char *id = cstr_String(id_Widget(as_Widget(d))); 974 const char *id = cstr_String(id_Widget(as_Widget(d)));
@@ -1383,6 +1395,20 @@ static iBool isArrowUpDownConsumed_InputWidget_(const iInputWidget *d) {
1383 return d->maxWrapLines > 1; 1395 return d->maxWrapLines > 1;
1384} 1396}
1385 1397
1398static iBool checkLineBreakMods_InputWidget_(const iInputWidget *d, int mods) {
1399 if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) {
1400 return mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey);
1401 }
1402 return mods == 0;
1403}
1404
1405static iBool checkAcceptMods_InputWidget_(const iInputWidget *d, int mods) {
1406 if (d->inFlags & useReturnKeyBehavior_InputWidgetFlag) {
1407 return mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey);
1408 }
1409 return mods == 0;
1410}
1411
1386static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { 1412static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1387 iWidget *w = as_Widget(d); 1413 iWidget *w = as_Widget(d);
1388 /* Resize according to width immediately. */ 1414 /* Resize according to width immediately. */
@@ -1401,6 +1427,13 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1401 begin_InputWidget(d); 1427 begin_InputWidget(d);
1402 return iFalse; 1428 return iFalse;
1403 } 1429 }
1430 else if (isEditing_InputWidget_(d) && (isCommand_UserEvent(ev, "window.focus.lost") ||
1431 isCommand_UserEvent(ev, "window.focus.gained"))) {
1432 startOrStopCursorTimer_InputWidget_(d, isCommand_UserEvent(ev, "window.focus.gained"));
1433 d->cursorVis = 1;
1434 refresh_Widget(d);
1435 return iFalse;
1436 }
1404 else if (isCommand_UserEvent(ev, "keyroot.changed")) { 1437 else if (isCommand_UserEvent(ev, "keyroot.changed")) {
1405 d->inFlags |= needUpdateBuffer_InputWidgetFlag; 1438 d->inFlags |= needUpdateBuffer_InputWidgetFlag;
1406 } 1439 }
@@ -1617,7 +1650,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1617 if (~d->inFlags & isSensitive_InputWidgetFlag && 1650 if (~d->inFlags & isSensitive_InputWidgetFlag &&
1618 ~d->inFlags & isUrl_InputWidgetFlag && 1651 ~d->inFlags & isUrl_InputWidgetFlag &&
1619 d->inFlags & lineBreaksEnabled_InputWidgetFlag && d->maxLen == 0) { 1652 d->inFlags & lineBreaksEnabled_InputWidgetFlag && d->maxLen == 0) {
1620 if (mods == lineBreakKeyMod_ReturnKeyBehavior(prefs_App()->returnKey)) { 1653 if (checkLineBreakMods_InputWidget_(d, mods)) {
1621 pushUndo_InputWidget_(d); 1654 pushUndo_InputWidget_(d);
1622 deleteMarked_InputWidget_(d); 1655 deleteMarked_InputWidget_(d);
1623 insertChar_InputWidget_(d, '\n'); 1656 insertChar_InputWidget_(d, '\n');
@@ -1626,7 +1659,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1626 } 1659 }
1627 } 1660 }
1628 if (d->inFlags & enterKeyEnabled_InputWidgetFlag && 1661 if (d->inFlags & enterKeyEnabled_InputWidgetFlag &&
1629 (mods == acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey) || 1662 (checkAcceptMods_InputWidget_(d, mods) ||
1630 (~d->inFlags & lineBreaksEnabled_InputWidgetFlag))) { 1663 (~d->inFlags & lineBreaksEnabled_InputWidgetFlag))) {
1631 d->inFlags |= enterPressed_InputWidgetFlag; 1664 d->inFlags |= enterPressed_InputWidgetFlag;
1632 setFocus_Widget(NULL); 1665 setFocus_Widget(NULL);