diff options
-rw-r--r-- | src/ui/inputwidget.c | 47 | ||||
-rw-r--r-- | src/ui/util.c | 6 | ||||
-rw-r--r-- | src/ui/util.h | 4 |
3 files changed, 48 insertions, 9 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 && |
diff --git a/src/ui/util.c b/src/ui/util.c index 8074223b..19fba3a4 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -164,7 +164,7 @@ iRangei union_Rangei(iRangei a, iRangei b) { | |||
164 | return (iRangei){ iMin(a.start, b.start), iMax(a.end, b.end) }; | 164 | return (iRangei){ iMin(a.start, b.start), iMax(a.end, b.end) }; |
165 | } | 165 | } |
166 | 166 | ||
167 | static iBool isSelectionBreakingChar_(iChar c) { | 167 | iBool isSelectionBreaking_Char(iChar c) { |
168 | return isSpace_Char(c) || (c == '@' || c == '-' || c == '/' || c == '\\' || c == ','); | 168 | return isSpace_Char(c) || (c == '@' || c == '-' || c == '/' || c == '\\' || c == ','); |
169 | } | 169 | } |
170 | 170 | ||
@@ -173,7 +173,7 @@ static const char *moveBackward_(const char *pos, iRangecc bounds, int mode) { | |||
173 | while (pos > bounds.start) { | 173 | while (pos > bounds.start) { |
174 | int len = decodePrecedingBytes_MultibyteChar(pos, bounds.start, &ch); | 174 | int len = decodePrecedingBytes_MultibyteChar(pos, bounds.start, &ch); |
175 | if (len > 0) { | 175 | if (len > 0) { |
176 | if (mode & word_RangeExtension && isSelectionBreakingChar_(ch)) break; | 176 | if (mode & word_RangeExtension && isSelectionBreaking_Char(ch)) break; |
177 | if (mode & line_RangeExtension && ch == '\n') break; | 177 | if (mode & line_RangeExtension && ch == '\n') break; |
178 | pos -= len; | 178 | pos -= len; |
179 | } | 179 | } |
@@ -187,7 +187,7 @@ static const char *moveForward_(const char *pos, iRangecc bounds, int mode) { | |||
187 | while (pos < bounds.end) { | 187 | while (pos < bounds.end) { |
188 | int len = decodeBytes_MultibyteChar(pos, bounds.end, &ch); | 188 | int len = decodeBytes_MultibyteChar(pos, bounds.end, &ch); |
189 | if (len > 0) { | 189 | if (len > 0) { |
190 | if (mode & word_RangeExtension && isSelectionBreakingChar_(ch)) break; | 190 | if (mode & word_RangeExtension && isSelectionBreaking_Char(ch)) break; |
191 | if (mode & line_RangeExtension && ch == '\n') break; | 191 | if (mode & line_RangeExtension && ch == '\n') break; |
192 | pos += len; | 192 | pos += len; |
193 | } | 193 | } |
diff --git a/src/ui/util.h b/src/ui/util.h index 9e00e495..2be38384 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -88,7 +88,9 @@ enum iRangeExtension { | |||
88 | bothStartAndEnd_RangeExtension = iBit(3), | 88 | bothStartAndEnd_RangeExtension = iBit(3), |
89 | }; | 89 | }; |
90 | 90 | ||
91 | void extendRange_Rangecc (iRangecc *, iRangecc bounds, int mode); | 91 | void extendRange_Rangecc (iRangecc *, iRangecc bounds, int mode); |
92 | |||
93 | iBool isSelectionBreaking_Char(iChar); | ||
92 | 94 | ||
93 | /*-----------------------------------------------------------------------------------------------*/ | 95 | /*-----------------------------------------------------------------------------------------------*/ |
94 | 96 | ||