Fix T46340: Auto scrolling in text editor with upward selection not work.

Cleanup and rework a bit text_cursor_set_to_pos_wrapped(), it did not handle correctly negative y valuesi,
because it was only checking lines starting from first visible one.

Mostly, we now directly get line matching given y position (be it an invisible one) from the helper
(renamed `get_line_pos_wrapped()`), instead of first visible one, which allows us to get rid of
additional complexity of looping over next lines until we find correct one.

This code remains rather complex to follow, added some asserts to ensure everything works as expected,
and tested it rather seriously, but DO NOT backport this to 2.76!
This commit is contained in:
Bastien Montagne 2015-10-01 15:27:11 +02:00
parent 29c2a64694
commit 066df84f73
Notes: blender-bot 2023-02-14 08:35:45 +01:00
Referenced by issue #46340, Auto scrolling in text editor with upward selection not work
1 changed files with 56 additions and 52 deletions

View File

@ -2367,21 +2367,23 @@ static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
return j;
}
static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y)
static TextLine *get_line_pos_wrapped(SpaceText *st, ARegion *ar, int *y)
{
TextLine *linep = st->text->lines.first;
int i;
for (i = st->top; i > 0 && linep; ) {
int lines = text_get_visible_lines(st, ar, linep->line);
if (i - lines < 0) {
*y += i;
int i, lines;
if (*y < -st->top) {
return NULL; /* We are beyond the first line... */
}
for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) {
lines = text_get_visible_lines(st, ar, linep->line);
if (i + lines > *y) {
/* We found the line matching given vertical 'coordinate', now set y relative to this line's start. */
*y -= i;
break;
}
else {
linep = linep->next;
i -= lines;
}
}
return linep;
}
@ -2391,23 +2393,22 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
Text *text = st->text;
int max = wrap_width(st, ar); /* column */
int charp = -1; /* mem */
int loop = 1, found = 0; /* flags */
char ch;
bool found = false; /* flags */
/* Point to first visible line */
TextLine *linep = get_first_visible_line(st, ar, &y);
while (loop && linep) {
/* Point to line matching given y position, if any. */
TextLine *linep = get_line_pos_wrapped(st, ar, &y);
if (linep) {
int i = 0, start = 0, end = max; /* column */
int j = 0, curs = 0, endj = 0; /* mem */
int chop = 1; /* flags */
for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) {
int j, curs = 0, endj = 0; /* mem */
bool chop = true; /* flags */
char ch;
for (j = 0 ; !found && ((ch = linep->line[j]) != '\0'); j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
ch = linep->line[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
@ -2420,7 +2421,8 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
/* Gone too far, go back to last wrap point */
if (y < 0) {
charp = endj;
loop = 0;
y = 0;
found = true;
break;
/* Exactly at the cursor */
}
@ -2428,7 +2430,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
charp = curs = j;
found = 1;
found = true;
/* Prepare curs for next wrap */
}
else if (i - end <= x && i + columns - end > x) {
@ -2438,68 +2440,70 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
end = MIN2(end, i);
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
if (charp > endj && !chop && ch != '\0') charp = endj;
loop = 0;
/* exact cursor position was found, check if it's still on needed line (hasn't been wrapped) */
if (charp > endj && !chop && ch != '\0')
charp = endj;
break;
}
if (chop) endj = j;
if (chop)
endj = j;
start = end;
end += max;
if (j < linep->len)
y--;
chop = 1;
chop = true;
if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
found = true;
break;
}
}
else if (ch == ' ' || ch == '-' || ch == '\0') {
if (found) {
loop = 0;
break;
}
if (y == 0 && i + columns - start > x) {
charp = curs;
loop = 0;
found = true;
break;
}
end = i + 1;
endj = j;
chop = 0;
chop = false;
}
i += columns;
}
if (ch == '\0') break;
}
BLI_assert(y == 0);
if (!loop || found) break;
if (!linep->next) {
if (!found) {
/* On correct line but didn't meet cursor, must be at end */
charp = linep->len;
break;
}
/* On correct line but didn't meet cursor, must be at end */
if (y == 0) {
charp = linep->len;
break;
}
linep = linep->next;
y--;
}
else if (y < 0) { /* Before start of text. */
linep = st->text->lines.first;
charp = 0;
}
else { /* Beyond end of text */
linep = st->text->lines.last;
charp = linep->len;
}
if (linep && charp != -1) {
if (sel) { text->sell = linep; text->selc = charp; }
else { text->curl = linep; text->curc = charp; }
BLI_assert(linep && charp != -1);
if (sel) {
text->sell = linep;
text->selc = charp;
}
else {
text->curl = linep;
text->curc = charp;
}
}