diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-27 15:13:55 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-27 15:13:55 +0200 |
commit | e5fa60b6f5fbc79c13ac98f53911f1e34d6cee18 (patch) | |
tree | c719b9577b9f3cc758aeb71dec04ef1c1dcae5eb /src/ui/inputwidget.c | |
parent | db7f835c320632ec4dea3b8baf5e21b62e2b75e1 (diff) |
InputWidget: Select by word
IssueID #134
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r-- | src/ui/inputwidget.c | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index 12bef08b..5593b5b9 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -73,6 +73,7 @@ enum iInputWidgetFlag { | |||
73 | notifyEdits_InputWidgetFlag = iBit(5), | 73 | notifyEdits_InputWidgetFlag = iBit(5), |
74 | eatEscape_InputWidgetFlag = iBit(6), | 74 | eatEscape_InputWidgetFlag = iBit(6), |
75 | isMarking_InputWidgetFlag = iBit(7), | 75 | isMarking_InputWidgetFlag = iBit(7), |
76 | markWords_InputWidgetFlag = iBit(8), | ||
76 | }; | 77 | }; |
77 | 78 | ||
78 | struct Impl_InputWidget { | 79 | struct Impl_InputWidget { |
@@ -89,6 +90,7 @@ struct Impl_InputWidget { | |||
89 | size_t cursor; | 90 | size_t cursor; |
90 | size_t lastCursor; | 91 | size_t lastCursor; |
91 | iRanges mark; | 92 | iRanges mark; |
93 | iRanges initialMark; | ||
92 | iArray undoStack; | 94 | iArray undoStack; |
93 | int font; | 95 | int font; |
94 | iClick click; | 96 | iClick click; |
@@ -664,6 +666,27 @@ static void paste_InputWidget_(iInputWidget *d) { | |||
664 | } | 666 | } |
665 | } | 667 | } |
666 | 668 | ||
669 | static iChar at_InputWidget_(const iInputWidget *d, size_t pos) { | ||
670 | return *(const iChar *) constAt_Array(&d->text, pos); | ||
671 | } | ||
672 | |||
673 | static void extendRange_InputWidget_(iInputWidget *d, size_t *pos, int dir) { | ||
674 | const size_t textLen = size_Array(&d->text); | ||
675 | if (dir < 0 && *pos > 0) { | ||
676 | for ((*pos)--; *pos > 0; (*pos)--) { | ||
677 | if (isSelectionBreaking_Char(at_InputWidget_(d, *pos))) { | ||
678 | (*pos)++; | ||
679 | break; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | if (dir > 0) { | ||
684 | for (; *pos < textLen && !isSelectionBreaking_Char(at_InputWidget_(d, *pos)); (*pos)++) { | ||
685 | /* continue */ | ||
686 | } | ||
687 | } | ||
688 | } | ||
689 | |||
667 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | 690 | static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { |
668 | iWidget *w = as_Widget(d); | 691 | iWidget *w = as_Widget(d); |
669 | if (isCommand_Widget(w, ev, "focus.gained")) { | 692 | if (isCommand_Widget(w, ev, "focus.gained")) { |
@@ -733,7 +756,19 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
733 | setFocus_Widget(w); | 756 | setFocus_Widget(w); |
734 | setCursor_InputWidget(d, coordIndex_InputWidget_(d, pos_Click(&d->click))); | 757 | setCursor_InputWidget(d, coordIndex_InputWidget_(d, pos_Click(&d->click))); |
735 | iZap(d->mark); | 758 | iZap(d->mark); |
736 | d->inFlags &= ~isMarking_InputWidgetFlag; | 759 | iZap(d->initialMark); |
760 | d->inFlags &= ~(isMarking_InputWidgetFlag | markWords_InputWidgetFlag); | ||
761 | if (d->click.count == 2) { | ||
762 | d->inFlags |= isMarking_InputWidgetFlag | markWords_InputWidgetFlag; | ||
763 | d->mark.start = d->mark.end = d->cursor; | ||
764 | extendRange_InputWidget_(d, &d->mark.start, -1); | ||
765 | extendRange_InputWidget_(d, &d->mark.end, +1); | ||
766 | d->initialMark = d->mark; | ||
767 | refresh_Widget(w); | ||
768 | } | ||
769 | if (d->click.count == 3) { | ||
770 | selectAll_InputWidget(d); | ||
771 | } | ||
737 | return iTrue; | 772 | return iTrue; |
738 | case aborted_ClickResult: | 773 | case aborted_ClickResult: |
739 | d->inFlags &= ~isMarking_InputWidgetFlag; | 774 | d->inFlags &= ~isMarking_InputWidgetFlag; |
@@ -746,13 +781,15 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
746 | d->mark.start = d->cursor; | 781 | d->mark.start = d->cursor; |
747 | } | 782 | } |
748 | d->mark.end = d->cursor; | 783 | d->mark.end = d->cursor; |
784 | if (d->inFlags & markWords_InputWidgetFlag) { | ||
785 | const iBool isFwd = d->mark.end >= d->mark.start; | ||
786 | extendRange_InputWidget_(d, &d->mark.end, isFwd ? +1 : -1); | ||
787 | d->mark.start = isFwd ? d->initialMark.start : d->initialMark.end; | ||
788 | } | ||
749 | refresh_Widget(w); | 789 | refresh_Widget(w); |
750 | return iTrue; | 790 | return iTrue; |
751 | case finished_ClickResult: | 791 | case finished_ClickResult: |
752 | if (d->click.count == 2) { | 792 | d->inFlags &= ~isMarking_InputWidgetFlag; |
753 | selectAll_InputWidget(d); | ||
754 | d->inFlags &= ~isMarking_InputWidgetFlag; | ||
755 | } | ||
756 | return iTrue; | 793 | return iTrue; |
757 | } | 794 | } |
758 | if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT && | 795 | if (ev->type == SDL_MOUSEBUTTONDOWN && ev->button.button == SDL_BUTTON_RIGHT && |