From 29d5058bf5ffa32c28134c7950e359208d6e9541 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Thu, 11 Apr 2002 09:23:07 +0000 Subject: Correction d'un core dans DeleteChars suite � un pointeur non d�r�f�renc�. Int�gration des nouveaux indices: bol, eol, bow, eow, up, down. Mise � jour des indices de s�lection et d'insertion lors d'une reconfiguration du texte (bug). L'indice sel.end retourne en fait l'index du caract�re de fin de s�lection plut�t que le point insertion entre celui-ci et le suivant. --- generic/Text.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 162 insertions(+), 36 deletions(-) (limited to 'generic/Text.c') diff --git a/generic/Text.c b/generic/Text.c index 302f5c4..64e0c21 100644 --- a/generic/Text.c +++ b/generic/Text.c @@ -285,6 +285,7 @@ Configure(Item item, { TextItem text = (TextItem) item; Item old_connected = item->connected_item; + int num_chars; #ifdef GLX ZnFont old_font = text->font; #endif @@ -299,6 +300,31 @@ Configure(Item item, text->txf = NULL; } #endif + num_chars = strlen(text->text); + if (text->num_chars != num_chars) { + TextInfo *ti = &item->wi->text_info; + /* + * The text has changed, update the selection and + * insertion pos to keep them valid. + */ + if (item == ti->sel_item) { + if (ti->sel_last > num_chars) { + ti->sel_last = num_chars; + } + if (ti->sel_first >= ti->sel_last) { + ti->sel_item = ZN_NO_ITEM; + ti->sel_field = ZN_NO_PART; + } + if ((ti->anchor_item == item) && (ti->sel_anchor > num_chars)) { + ti->sel_anchor = num_chars; + } + } + if (text->insert_index > text->num_chars) { + text->insert_index = text->num_chars; + } + text->num_chars = num_chars; + } + if (ISSET(*flags, ZN_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up @@ -358,10 +384,7 @@ ComputeCoordinates(Item item, int font_height, height; ResetBBox(&item->item_bounding_box); - text->num_chars = strlen(text->text); - if (text->insert_index > text->num_chars) { - text->insert_index = text->num_chars; - } + if (text->num_chars == 0) { return; } @@ -588,6 +611,7 @@ ComputeCursorAndSel(Item item, { TextItem text = (TextItem) item; WidgetInfo *wi = item->wi; + TextInfo *ti = &wi->text_info; TextLineInfo lines_ptr; int i, line_index, char_index; @@ -597,7 +621,7 @@ ComputeCursorAndSel(Item item, * position along the X axis. */ line_index = lines_ptr->start - text->text; - if ((wi->focus_item == item) && wi->got_focus && wi->text_info.cursor_on && + if ((wi->focus_item == item) && wi->got_focus && ti->cursor_on && text->insert_index >= line_index && text->insert_index <= line_index + lines_ptr->num_chars) { *cursor_line = i; @@ -609,11 +633,10 @@ ComputeCursorAndSel(Item item, * Compute the selection first and last line as well as * the positions along the X axis. */ - if ((wi->text_info.sel_item == item) && - (wi->text_info.sel_last >= line_index) && - (wi->text_info.sel_first <= (line_index + lines_ptr->num_chars))) { + if ((ti->sel_item == item) && (ti->sel_last >= line_index) && + (ti->sel_first <= (line_index + lines_ptr->num_chars))) { if (*sel_first_line < 0) { - char_index = wi->text_info.sel_first - line_index; + char_index = ti->sel_first - line_index; if (char_index <= 0) { *sel_first_line = i; *sel_start_offset = 0; @@ -626,7 +649,7 @@ ComputeCursorAndSel(Item item, /*printf("sel_start_offset 2 : %d\n", *sel_start_offset);*/ } } - char_index = wi->text_info.sel_last - line_index; + char_index = ti->sel_last - line_index; *sel_last_line = i; if (char_index == lines_ptr->num_chars+1) *sel_stop_offset = lines_ptr->width; @@ -655,6 +678,7 @@ Draw(Item item) int font_height; int num_lines, i; TextLineInfo lines, lines_ptr; + TextInfo *ti = &wi->text_info; int underline_thickness, underline_pos=0, overstrike_pos=0; int sel_first_line=-1, sel_last_line=-1, cursor_line=-1; int sel_start_offset=0, sel_stop_offset=0, cursor_offset=0; @@ -680,10 +704,10 @@ Draw(Item item) /* * Setup the gc for the selection and fill the selection. */ - if ((wi->text_info.sel_item == item) && (sel_first_line >= 0)) { + if ((ti->sel_item == item) && (sel_first_line >= 0)) { int x, y; - values.foreground = ZnPixel(ZnGetGradientColor(wi->text_info.sel_color, 0, NULL)); + values.foreground = ZnPixel(ZnGetGradientColor(ti->sel_color, 0, NULL)); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCForeground, &values); @@ -723,8 +747,8 @@ Draw(Item item) int xs, ys; values.fill_style = FillSolid; - values.line_width = wi->text_info.insert_width; - values.foreground = ZnPixel(ZnGetGradientColor(wi->text_info.insert_color, 0, NULL)); + values.line_width = ti->insert_width; + values.foreground = ZnPixel(ZnGetGradientColor(ti->insert_color, 0, NULL)); XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle|GCLineWidth, &values); xs = (int)(text->pos_dev.x + lines[cursor_line].text_origin.x + cursor_offset); @@ -798,6 +822,7 @@ Render(Item item) WidgetInfo *wi = item->wi; TextItem text = (TextItem) item; TextLineInfo lines, lines_ptr; + TextInfo *ti = &wi->text_info; int i, num_lines; XColor *color; int alpha; @@ -844,10 +869,10 @@ Render(Item item) /* * Render the selection. */ - color = ZnGetGradientColor(wi->text_info.sel_color, 0, &alpha); + color = ZnGetGradientColor(ti->sel_color, 0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); - if ((wi->text_info.sel_item == item) && (sel_first_line >= 0)) { + if ((ti->sel_item == item) && (sel_first_line >= 0)) { ZnReal xo, yo, xc, yc; glBegin(GL_QUADS); @@ -896,14 +921,14 @@ Render(Item item) /* * Render the cursor. */ - color = ZnGetGradientColor(wi->text_info.insert_color, 0, &alpha); + color = ZnGetGradientColor(ti->insert_color, 0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); if ((cursor_line >= 0) && - (wi->focus_item == item) && wi->text_info.cursor_on) { + (wi->focus_item == item) && ti->cursor_on) { int xs, ys; - glLineWidth(wi->text_info.insert_width); + glLineWidth(ti->insert_width); xs = text->pos_dev.x + lines[cursor_line].text_origin.x + cursor_offset; ys = text->pos_dev.y + lines[cursor_line].text_origin.y - fm.ascent + 1; glBegin(GL_LINES); @@ -1144,11 +1169,10 @@ Coords(Item item, ********************************************************************************** */ static int -PointToChar(Item item, +PointToChar(TextItem text, int x, int y) { - TextItem text = (TextItem) item; int i, n, num_lines, dummy; TextLineInfo lines, p; Tk_FontMetrics fm; @@ -1171,7 +1195,7 @@ PointToChar(Item item, * Find the text line under point. */ num_lines = ZnListSize(text->text_info); - lines = p = (TextLineInfo) ZnListArray(text->text_info); + lines = p = ZnListArray(text->text_info); Tk_GetFontMetrics(text->font, &fm); for (i = 0; i < num_lines; i++, p++) { if (y < p->text_origin.y + fm.descent) { @@ -1202,6 +1226,87 @@ PointToChar(Item item, return p->start + p->num_chars - text->text; } +/* + * Return a new index from a current index and a + * move command. + * + * 0 end of index line + * 1 beginning of index line + * 2 next word or end of word from index + * 3 previous word or beginning of word from index + * 4 previous line from index line + * 5 next line from index line + * + */ +static int +MoveFromIndex(TextItem text, + int index, + int move) +{ + int num_lines, num_chars; + int line_index, line_start; + TextLineInfo lines, p; + char *strp; + + num_lines = ZnListSize(text->text_info); + lines = p = ZnListArray(text->text_info); + for (line_index = 0; line_index < num_lines; line_index++, p++) { + line_start = p->start - text->text; + num_chars = p->num_chars; + if (line_start + num_chars >= index) { + break; + } + } + if (line_index == num_lines) { + line_index--; + p--; + } + + switch (move) { + case 0: + return line_start + num_chars; + case 1: + return line_start; + case 2: + strp = &text->text[index]; + while ((strp[1] == ' ') || (strp[1] == '\n')) { + strp++; + } + while ((strp[1] != ' ') && (strp[1] != '\n') && strp[1]) { + strp++; + } + return strp + 1 - text->text; + case 3: + strp = &text->text[index]; + while (((strp[-1] == ' ') || (strp[-1] == '\n')) && (strp != text->text)) { + strp--; + } + while ((strp[-1] != ' ') && (strp[-1] != '\n') && (strp != text->text)) { + strp--; + } + return strp - text->text; + case 4: + if (line_index > 0) { + index -= line_start; + p = &lines[line_index-1]; + index = MIN(index, p->num_chars); + line_start = p->start - text->text; + index += line_start; + } + return index; + case 5: + if (line_index < num_lines-1) { + index -= line_start; + p = &lines[line_index+1]; + index = MIN(index, p->num_chars); + line_start = p->start - text->text; + index += line_start; + } + default: + return index; + } +} + static int Index(Item item, int field, @@ -1210,6 +1315,7 @@ Index(Item item, { TextItem text = (TextItem) item; WidgetInfo *wi = item->wi; + TextInfo *ti = &wi->text_info; int c, length; int x, y; double tmp; @@ -1219,27 +1325,50 @@ Index(Item item, c = p[0]; length = strlen(p); - if ((c == 'e') && (strncmp(p, "end", length) == 0)) { + if ((c == 'e') && (length > 1) && (strncmp(p, "end", length) == 0)) { *index = text->num_chars; } + else if ((c == 'e') && (length > 1) && (strncmp(p, "eol", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 0); + } + else if ((c == 'b') && (length > 1) && (strncmp(p, "bol", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 1); + } + else if ((c == 'e') && (length > 1) && (strncmp(p, "eow", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 2); + } + else if ((c == 'b') && (length > 1) && (strncmp(p, "bow", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 3); + } + else if ((c == 'u') && (strncmp(p, "up", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 4); + } + else if ((c == 'd') && (strncmp(p, "down", length) == 0)) { + *index = MoveFromIndex(text, text->insert_index, 5); + } else if ((c == 'i') && (strncmp(p, "insert", length) == 0)) { *index = text->insert_index; } else if ((c == 's') && (strncmp(p, "sel.first", length) == 0) && (length >= 5)) { - if (wi->text_info.sel_item != item) { + if (ti->sel_item != item) { Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); return TCL_ERROR; } - *index = wi->text_info.sel_first; + *index = ti->sel_first; } else if ((c == 's') && (strncmp(p, "sel.last", length) == 0) && (length >= 5)) { - if (wi->text_info.sel_item != item) { + if (ti->sel_item != item) { Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); return TCL_ERROR; } - *index = wi->text_info.sel_last; + /* + * We return a modified selection end so that it reflect + * the text index of the last character _not_ the insertion + * point between the last and the next. + */ + *index = ti->sel_last-1; } else if (c == '@') { p++; @@ -1257,7 +1386,7 @@ Index(Item item, /*y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);*/ y = tmp; - *index = PointToChar(item, x, y); + *index = PointToChar(text, x, y); } else if (Tcl_GetIntFromObj(wi->interp, index_spec, index) == TCL_OK) { if (*index < 0){ @@ -1272,7 +1401,7 @@ Index(Item item, Tcl_AppendResult(wi->interp, "bad index \"", p, "\"", (char *) NULL); return TCL_ERROR; } - + return TCL_OK; } @@ -1337,10 +1466,6 @@ DeleteChars(Item item, int count; char *new; - if (!text->text_info) { - return; - } - if (*first < 0) { *first = 0; } @@ -1353,7 +1478,7 @@ DeleteChars(Item item, count = *last + 1 - *first; new = (char *) ZnMalloc((unsigned) (text->num_chars + 1 - count)); - strncpy(new, text->text, (size_t) first); + strncpy(new, text->text, (size_t) *first); strcpy(new + *first, text->text + *last + 1); ZnFree(text->text); text->text = new; @@ -1412,9 +1537,10 @@ Selection(Item item, { TextItem text = (TextItem) item; WidgetInfo *wi = item->wi; + TextInfo *ti = &wi->text_info; int count; - count = wi->text_info.sel_last - wi->text_info.sel_first - offset; + count = ti->sel_last - ti->sel_first - offset; if (count > max_chars) { count = max_chars; } @@ -1424,7 +1550,7 @@ Selection(Item item, if (count <= 0) { return 0; } - strncpy(chars, text->text + wi->text_info.sel_first + offset, (size_t) count); + strncpy(chars, text->text + ti->sel_first + offset, (size_t) count); chars[count] = 0; return count; -- cgit v1.1