diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-11 13:38:29 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-11 13:38:29 +0300 |
commit | c17b4bc36de5d610c477e7cdca66e165260c94b8 (patch) | |
tree | decb4a0484d285f46c6b2d920c0fae04e48735b6 | |
parent | d6a9b598a9d469ece721c2ee9dbddd56ca526643 (diff) |
DocumentWidget: Fixed text selection regressions
The HarfBuzz and wrapped text changes introduced subtle differences in how text selection works. Fixed a bunch of issues regarding how the individual character selection mode works in edge cases.
IssueID #357
-rw-r--r-- | src/gmdocument.c | 8 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 35 |
2 files changed, 27 insertions, 16 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 2f4c7972..3e640f08 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -2067,14 +2067,20 @@ iRangecc findLoc_GmRun(const iGmRun *d, iInt2 pos) { | |||
2067 | if (pos.y < top_Rect(d->bounds)) { | 2067 | if (pos.y < top_Rect(d->bounds)) { |
2068 | return (iRangecc){ d->text.start, d->text.start }; | 2068 | return (iRangecc){ d->text.start, d->text.start }; |
2069 | } | 2069 | } |
2070 | if (pos.y > bottom_Rect(d->bounds)) { | ||
2071 | return (iRangecc){ d->text.end, d->text.end }; | ||
2072 | } | ||
2070 | const int x = pos.x - left_Rect(d->bounds); | 2073 | const int x = pos.x - left_Rect(d->bounds); |
2071 | if (x <= 0) { | 2074 | if (x <= 0) { |
2072 | return (iRangecc){ d->text.start, d->text.start }; | 2075 | return (iRangecc){ d->text.start, d->text.start }; |
2073 | } | 2076 | } |
2077 | if (x > d->bounds.size.x) { | ||
2078 | return (iRangecc){ d->text.end, d->text.end }; | ||
2079 | } | ||
2074 | iRangecc loc; | 2080 | iRangecc loc; |
2075 | tryAdvanceNoWrap_Text(d->textParams.font, d->text, x, &loc.start); | 2081 | tryAdvanceNoWrap_Text(d->textParams.font, d->text, x, &loc.start); |
2076 | loc.end = loc.start; | 2082 | loc.end = loc.start; |
2077 | if (!contains_Range(&d->text, loc.start)) { | 2083 | if (!contains_Range(&d->text, loc.start) && loc.start != d->text.end) { |
2078 | return iNullRange; /* it's some other text */ | 2084 | return iNullRange; /* it's some other text */ |
2079 | } | 2085 | } |
2080 | iChar ch; | 2086 | iChar ch; |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 589b9e56..93b2166b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -3380,7 +3380,7 @@ static void beginMarkingSelection_DocumentWidget_(iDocumentWidget *d, iInt2 pos) | |||
3380 | invalidateWideRunsWithNonzeroOffset_DocumentWidget_(d); | 3380 | invalidateWideRunsWithNonzeroOffset_DocumentWidget_(d); |
3381 | resetWideRuns_DocumentWidget_(d); /* Selections don't support horizontal scrolling. */ | 3381 | resetWideRuns_DocumentWidget_(d); /* Selections don't support horizontal scrolling. */ |
3382 | iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iTrue); | 3382 | iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iTrue); |
3383 | d->selectMark = sourceLoc_DocumentWidget_(d, pos); | 3383 | d->initialSelectMark = d->selectMark = sourceLoc_DocumentWidget_(d, pos); |
3384 | refresh_Widget(as_Widget(d)); | 3384 | refresh_Widget(as_Widget(d)); |
3385 | } | 3385 | } |
3386 | 3386 | ||
@@ -3804,7 +3804,13 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3804 | } | 3804 | } |
3805 | } | 3805 | } |
3806 | else { | 3806 | else { |
3807 | d->selectMark.end = (d->selectMark.end > d->selectMark.start ? loc.end : loc.start); | 3807 | d->selectMark.end = loc.end;// (d->selectMark.end > d->selectMark.start ? loc.end : loc.start); |
3808 | if (loc.start < d->initialSelectMark.start) { | ||
3809 | d->selectMark.end = loc.start; | ||
3810 | } | ||
3811 | if (isEmpty_Range(&d->selectMark)) { | ||
3812 | d->selectMark = d->initialSelectMark; | ||
3813 | } | ||
3808 | } | 3814 | } |
3809 | } | 3815 | } |
3810 | iAssert((!d->selectMark.start && !d->selectMark.end) || | 3816 | iAssert((!d->selectMark.start && !d->selectMark.end) || |
@@ -3822,13 +3828,13 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3822 | d->initialSelectMark.start = | 3828 | d->initialSelectMark.start = |
3823 | d->initialSelectMark.end = d->selectMark.start; | 3829 | d->initialSelectMark.end = d->selectMark.start; |
3824 | } | 3830 | } |
3825 | if (!isEmpty_Range(&d->initialSelectMark)) { | 3831 | } |
3826 | if (d->selectMark.end > d->selectMark.start) { | 3832 | if (d->initialSelectMark.start) { |
3827 | d->selectMark.start = d->initialSelectMark.start; | 3833 | if (d->selectMark.end > d->selectMark.start) { |
3828 | } | 3834 | d->selectMark.start = d->initialSelectMark.start; |
3829 | else if (d->selectMark.end < d->selectMark.start) { | 3835 | } |
3830 | d->selectMark.start = d->initialSelectMark.end; | 3836 | else if (d->selectMark.end < d->selectMark.start) { |
3831 | } | 3837 | d->selectMark.start = d->initialSelectMark.end; |
3832 | } | 3838 | } |
3833 | } | 3839 | } |
3834 | // printf("mark %zu ... %zu\n", d->selectMark.start - cstr_String(source_GmDocument(d->doc)), | 3840 | // printf("mark %zu ... %zu\n", d->selectMark.start - cstr_String(source_GmDocument(d->doc)), |
@@ -4026,12 +4032,11 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
4026 | } | 4032 | } |
4027 | int w = width_Rect(run->visBounds) - x; | 4033 | int w = width_Rect(run->visBounds) - x; |
4028 | if (contains_Range(&run->text, mark.end) || mark.end < run->text.start) { | 4034 | if (contains_Range(&run->text, mark.end) || mark.end < run->text.start) { |
4029 | w = measureRange_Text( | 4035 | iRangecc mk = !*isInside ? mark |
4030 | run->textParams.font, | 4036 | : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) }; |
4031 | !*isInside ? mark | 4037 | mk.start = iMax(mk.start, run->text.start); |
4032 | : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) }) | 4038 | w = measureRange_Text(run->textParams.font, mk).advance.x; |
4033 | .advance.x; | 4039 | *isInside = iFalse; |
4034 | *isInside = iFalse; | ||
4035 | } | 4040 | } |
4036 | else { | 4041 | else { |
4037 | *isInside = iTrue; /* at least until the next run */ | 4042 | *isInside = iTrue; /* at least until the next run */ |