summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-11 13:38:29 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-11 13:38:29 +0300
commitc17b4bc36de5d610c477e7cdca66e165260c94b8 (patch)
treedecb4a0484d285f46c6b2d920c0fae04e48735b6
parentd6a9b598a9d469ece721c2ee9dbddd56ca526643 (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.c8
-rw-r--r--src/ui/documentwidget.c35
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 */