From e5fa60b6f5fbc79c13ac98f53911f1e34d6cee18 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 27 Mar 2021 15:13:55 +0200 Subject: InputWidget: Select by word IssueID #134 --- src/ui/inputwidget.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- src/ui/util.c | 6 +++--- src/ui/util.h | 4 +++- 3 files changed, 48 insertions(+), 9 deletions(-) (limited to 'src') 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 { notifyEdits_InputWidgetFlag = iBit(5), eatEscape_InputWidgetFlag = iBit(6), isMarking_InputWidgetFlag = iBit(7), + markWords_InputWidgetFlag = iBit(8), }; struct Impl_InputWidget { @@ -89,6 +90,7 @@ struct Impl_InputWidget { size_t cursor; size_t lastCursor; iRanges mark; + iRanges initialMark; iArray undoStack; int font; iClick click; @@ -664,6 +666,27 @@ static void paste_InputWidget_(iInputWidget *d) { } } +static iChar at_InputWidget_(const iInputWidget *d, size_t pos) { + return *(const iChar *) constAt_Array(&d->text, pos); +} + +static void extendRange_InputWidget_(iInputWidget *d, size_t *pos, int dir) { + const size_t textLen = size_Array(&d->text); + if (dir < 0 && *pos > 0) { + for ((*pos)--; *pos > 0; (*pos)--) { + if (isSelectionBreaking_Char(at_InputWidget_(d, *pos))) { + (*pos)++; + break; + } + } + } + if (dir > 0) { + for (; *pos < textLen && !isSelectionBreaking_Char(at_InputWidget_(d, *pos)); (*pos)++) { + /* continue */ + } + } +} + static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { iWidget *w = as_Widget(d); if (isCommand_Widget(w, ev, "focus.gained")) { @@ -733,7 +756,19 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { setFocus_Widget(w); setCursor_InputWidget(d, coordIndex_InputWidget_(d, pos_Click(&d->click))); iZap(d->mark); - d->inFlags &= ~isMarking_InputWidgetFlag; + iZap(d->initialMark); + d->inFlags &= ~(isMarking_InputWidgetFlag | markWords_InputWidgetFlag); + if (d->click.count == 2) { + d->inFlags |= isMarking_InputWidgetFlag | markWords_InputWidgetFlag; + d->mark.start = d->mark.end = d->cursor; + extendRange_InputWidget_(d, &d->mark.start, -1); + extendRange_InputWidget_(d, &d->mark.end, +1); + d->initialMark = d->mark; + refresh_Widget(w); + } + if (d->click.count == 3) { + selectAll_InputWidget(d); + } return iTrue; case aborted_ClickResult: d->inFlags &= ~isMarking_InputWidgetFlag; @@ -746,13 +781,15 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { d->mark.start = d->cursor; } d->mark.end = d->cursor; + if (d->inFlags & markWords_InputWidgetFlag) { + const iBool isFwd = d->mark.end >= d->mark.start; + extendRange_InputWidget_(d, &d->mark.end, isFwd ? +1 : -1); + d->mark.start = isFwd ? d->initialMark.start : d->initialMark.end; + } refresh_Widget(w); return iTrue; case finished_ClickResult: - if (d->click.count == 2) { - selectAll_InputWidget(d); - d->inFlags &= ~isMarking_InputWidgetFlag; - } + d->inFlags &= ~isMarking_InputWidgetFlag; return iTrue; } 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) { return (iRangei){ iMin(a.start, b.start), iMax(a.end, b.end) }; } -static iBool isSelectionBreakingChar_(iChar c) { +iBool isSelectionBreaking_Char(iChar c) { return isSpace_Char(c) || (c == '@' || c == '-' || c == '/' || c == '\\' || c == ','); } @@ -173,7 +173,7 @@ static const char *moveBackward_(const char *pos, iRangecc bounds, int mode) { while (pos > bounds.start) { int len = decodePrecedingBytes_MultibyteChar(pos, bounds.start, &ch); if (len > 0) { - if (mode & word_RangeExtension && isSelectionBreakingChar_(ch)) break; + if (mode & word_RangeExtension && isSelectionBreaking_Char(ch)) break; if (mode & line_RangeExtension && ch == '\n') break; pos -= len; } @@ -187,7 +187,7 @@ static const char *moveForward_(const char *pos, iRangecc bounds, int mode) { while (pos < bounds.end) { int len = decodeBytes_MultibyteChar(pos, bounds.end, &ch); if (len > 0) { - if (mode & word_RangeExtension && isSelectionBreakingChar_(ch)) break; + if (mode & word_RangeExtension && isSelectionBreaking_Char(ch)) break; if (mode & line_RangeExtension && ch == '\n') break; pos += len; } 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 { bothStartAndEnd_RangeExtension = iBit(3), }; -void extendRange_Rangecc (iRangecc *, iRangecc bounds, int mode); +void extendRange_Rangecc (iRangecc *, iRangecc bounds, int mode); + +iBool isSelectionBreaking_Char(iChar); /*-----------------------------------------------------------------------------------------------*/ -- cgit v1.2.3