diff options
-rw-r--r-- | generic/Text.c | 300 |
1 files changed, 189 insertions, 111 deletions
diff --git a/generic/Text.c b/generic/Text.c index 804670c..657ce8f 100644 --- a/generic/Text.c +++ b/generic/Text.c @@ -70,7 +70,7 @@ static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ typedef struct _TextLineInfo { char *start; /* Index of first char in line */ - int num_chars; /* Number of displayed chars in line */ + int num_bytes; /* Number of displayed bytes in line (NOT chars)*/ ZnPoint text_origin; /* X pos for drawing the line */ int width; /* Line width in pixels */ } TextLineInfoStruct, *TextLineInfo; @@ -325,7 +325,7 @@ Configure(Item item, #endif num_chars = 0; if (text->text) { - num_chars = strlen(text->text); + num_chars = Tcl_NumUtfChars(text->text, strlen(text->text)); } if (text->num_chars != num_chars) { TextInfo *ti = &item->wi->text_info; @@ -345,8 +345,8 @@ Configure(Item item, ti->sel_anchor = num_chars; } } - if (text->insert_index > text->num_chars) { - text->insert_index = text->num_chars; + if (text->insert_index > num_chars) { + text->insert_index = num_chars; } text->num_chars = num_chars; } @@ -420,8 +420,8 @@ ComputeCoordinates(Item item, */ if (ISSET(item->inv_flags, ZN_LAYOUT_FLAG)) { char *scan; - int wrap, line_index, prev_num_lines; - + int wrap, prev_num_lines; + text->max_width = 0; if (text->text_info != NULL) { prev_num_lines = ZnListSize(text->text_info); @@ -444,8 +444,7 @@ ComputeCoordinates(Item item, TextLineInfoStruct info; char *ptr; int num; - - line_index = scan - text->text; + /* * Limit the excursion of Tk_MeasureChars to the end * of the line. Do not include \n in the measure done. @@ -457,14 +456,15 @@ ComputeCoordinates(Item item, else { num = strlen(scan); } - info.num_chars = Tk_MeasureChars(text->font, scan, num, wrap, + info.num_bytes = Tk_MeasureChars(text->font, scan, num, wrap, TK_WHOLE_WORDS|TK_AT_LEAST_ONE, &info.width); info.start = scan; text->max_width = MAX(info.width, text->max_width); - scan += info.num_chars; + scan += info.num_bytes; + /* * Adjust for the newline at the end of line. */ @@ -478,8 +478,8 @@ ComputeCoordinates(Item item, * insertion to behave correctly. */ ZnListAdd(text->text_info, &info, ZnListTail); - /*printf("adding a line : %s, num_chars : %d, width : %d\n", - info.start, info.num_chars, info.width);*/ + /*printf("adding a line : %s, num_bytes : %d, width : %d\n", + info.start, info.num_bytes, info.width);*/ /* * Skip terminating space or return char if any. @@ -639,52 +639,62 @@ ComputeCursorAndSel(Item item, WidgetInfo *wi = item->wi; TextInfo *ti = &wi->text_info; TextLineInfo lines_ptr; - int i, line_index, char_index; + int i, line_index, byte_index; + int insert_index, sel_first, sel_last; if (num_lines == 0) { *cursor_line = 0; } - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - /* - * Mark the line with the cursor and compute its - * position along the X axis. - */ - line_index = lines_ptr->start - text->text; - 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; - *cursor_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, - text->insert_index - line_index); + if ((wi->focus_item == item) && wi->got_focus && ti->cursor_on) { + insert_index = Tcl_UtfAtIndex(text->text, text->insert_index)-text->text; + for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { + /* + * Mark the line with the cursor and compute its + * position along the X axis. + */ + line_index = lines_ptr->start - text->text; + if ((insert_index >= line_index) && + (insert_index <= line_index + lines_ptr->num_bytes)) { + *cursor_line = i; + *cursor_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, + insert_index - line_index); + } } - - /* - * Compute the selection first and last line as well as - * the positions along the X axis. - */ - 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 = ti->sel_first - line_index; - if (char_index <= 0) { - *sel_first_line = i; - *sel_start_offset = 0; - /*printf("sel_start_offset 1 : %d\n", *sel_start_offset);*/ - } - else if (char_index <= lines_ptr->num_chars) { + } + + if (ti->sel_item == item) { + sel_first = Tcl_UtfAtIndex(text->text, ti->sel_first)-text->text; + sel_last = Tcl_UtfAtIndex(text->text, ti->sel_last)-text->text; + for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { + /* + * Compute the selection first and last line as well as + * the positions along the X axis. + */ + line_index = lines_ptr->start - text->text; + if ((sel_last >= line_index) && + (sel_first <= (line_index + lines_ptr->num_bytes))) { + if (*sel_first_line < 0) { + byte_index = sel_first - line_index; + if (byte_index <= 0) { + *sel_first_line = i; + *sel_start_offset = 0; + /*printf("sel_start_offset 1 : %d\n", *sel_start_offset);*/ + } + else if (byte_index <= lines_ptr->num_bytes) { *sel_first_line = i; *sel_start_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, - char_index); + byte_index); /*printf("sel_start_offset 2 : %d\n", *sel_start_offset);*/ + } } + byte_index = ti->sel_last - line_index; + *sel_last_line = i; + if (byte_index == lines_ptr->num_bytes+1) + *sel_stop_offset = lines_ptr->width; + else if (byte_index <= lines_ptr->num_bytes) + *sel_stop_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, + byte_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; - else if (char_index <= lines_ptr->num_chars) - *sel_stop_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, - char_index); } } } @@ -820,8 +830,9 @@ Draw(Item item) tmp_x = (int)(text->pos_dev.x + lines_ptr->text_origin.x); tmp_y = (int)(text->pos_dev.y + lines_ptr->text_origin.y); - XDrawString(wi->dpy, wi->draw_buffer, wi->gc, - tmp_x, tmp_y, (char *) lines_ptr->start, lines_ptr->num_chars); + Tk_DrawChars(wi->dpy, wi->draw_buffer, wi->gc, + text->font, (char *) lines_ptr->start, lines_ptr->num_bytes, + tmp_x, tmp_y); if (ISSET(text->flags, UNDERLINED)) { int y_under = tmp_y + underline_pos; @@ -866,10 +877,11 @@ Render(Item item) return; } +#ifdef GL_LIST if (!item->gl_list) { item->gl_list = glGenLists(1); glNewList(item->gl_list, GL_COMPILE); - +#endif lines = (TextLineInfo) ZnListArray(text->text_info); num_lines = ZnListSize(text->text_info); Tk_GetFontMetrics(text->font, &fm); @@ -983,7 +995,7 @@ Render(Item item) glPushMatrix(); glTranslatef(xs, ys, 0.0); - ZnRenderString(text->tfi, lines_ptr->start, lines_ptr->num_chars); + ZnRenderString(text->tfi, lines_ptr->start, lines_ptr->num_bytes); glPopMatrix(); if (ISSET(text->flags, UNDERLINED) || ISSET(text->flags, OVERSTRIKED)) { @@ -1005,12 +1017,13 @@ Render(Item item) } } glDisable(GL_TEXTURE_2D); - +#ifdef GL_LIST glEndList(); } glCallList(item->gl_list); #endif +#endif } @@ -1192,7 +1205,7 @@ Coords(Item item, ********************************************************************************** * * Index -- - * Parse a text index and return its value and aa + * Parse a text index and return its value and a * error status (standard Tcl result). * ********************************************************************************** @@ -1202,10 +1215,11 @@ PointToChar(TextItem text, int x, int y) { - int i, n, num_lines, dummy; + int i, n, num_lines, dummy, byte_index; TextLineInfo lines, p; Tk_FontMetrics fm; + byte_index = 0; if (!text->text_info) { return 0; } @@ -1233,26 +1247,33 @@ PointToChar(TextItem text, * Point to the left of the current line, returns * index of first char. */ - return p->start - text->text; + byte_index = p->start - text->text; + break; } if (x >= (p->text_origin.x + p->width)) { /* * Point to the right of the current line, returns * index past the last char. */ - return p->start + p->num_chars - text->text; + byte_index = p->start + p->num_bytes - text->text; + break; } - n = Tk_MeasureChars(text->font, p->start, p->num_chars, + n = Tk_MeasureChars(text->font, p->start, p->num_bytes, x + 2 - p->text_origin.x, TK_PARTIAL_OK, &dummy); - return (p->start + n - 1) - text->text; + byte_index = (p->start + n - 1) - text->text; + break; } } - /* - * Point below all lines, return the index after - * the last char in text. - */ - p--; - return p->start + p->num_chars - text->text; + if (i == num_lines) { + /* + * Point below all lines, return the index after + * the last char in text. + */ + p--; + byte_index = p->start + p->num_bytes - text->text; + } + + return Tcl_NumUtfChars(text->text, byte_index); } /* @@ -1269,23 +1290,24 @@ PointToChar(TextItem text, */ static int MoveFromIndex(TextItem text, - int index, + int char_index, int move) { - int num_lines, num_chars=0; + int num_lines, byte_index, num_bytes=0; int line_index, line_start=0; TextLineInfo lines, p; char *strp; if (!text->text_info || !text->text) { - return index; + return char_index; } + byte_index = Tcl_UtfAtIndex(text->text, char_index)-text->text; 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) { + num_bytes = p->num_bytes; + if (line_start + num_bytes >= byte_index) { break; } } @@ -1296,46 +1318,52 @@ MoveFromIndex(TextItem text, switch (move) { case 0: - return line_start + num_chars; + byte_index = line_start + num_bytes; + goto convert_it; case 1: - return line_start; + byte_index = line_start; + goto convert_it; case 2: - strp = &text->text[index]; + strp = &text->text[byte_index]; while ((strp[1] == ' ') || (strp[1] == '\n')) { strp++; } while ((strp[1] != ' ') && (strp[1] != '\n') && strp[1]) { strp++; } - return strp + 1 - text->text; + byte_index = strp + 1 - text->text; + goto convert_it; case 3: - strp = &text->text[index]; - while (((strp[-1] == ' ') || (strp[-1] == '\n')) && (strp != text->text)) { + strp = &text->text[byte_index]; + while ((strp != text->text) && ((strp[-1] == ' ') || (strp[-1] == '\n'))) { strp--; } - while ((strp[-1] != ' ') && (strp[-1] != '\n') && (strp != text->text)) { + while ((strp != text->text) && (strp[-1] != ' ') && (strp[-1] != '\n')) { strp--; } - return strp - text->text; + byte_index = strp - text->text; + goto convert_it; case 4: if (line_index > 0) { - index -= line_start; + byte_index -= line_start; p = &lines[line_index-1]; - index = MIN(index, p->num_chars); + byte_index = MIN(byte_index, p->num_bytes); line_start = p->start - text->text; - index += line_start; + byte_index += line_start; } - return index; + goto convert_it; case 5: if (line_index < num_lines-1) { - index -= line_start; + byte_index -= line_start; p = &lines[line_index+1]; - index = MIN(index, p->num_chars); + byte_index = MIN(byte_index, p->num_bytes); line_start = p->start - text->text; - index += line_start; + byte_index += line_start; } + convert_it: + Tcl_NumUtfChars(text->text, byte_index); default: - return index; + return char_index; } } @@ -1452,10 +1480,11 @@ InsertChars(Item item, char *chars) { TextItem text = (TextItem) item; - int length = strlen(chars); + TextInfo *ti = &item->wi->text_info; + int num_chars, byte_index, num_bytes = strlen(chars); char *new; - if (length == 0) { + if (num_bytes == 0) { return; } if (*index < 0) { @@ -1464,19 +1493,35 @@ InsertChars(Item item, if (*index > text->num_chars) { *index = text->num_chars; } - - new = ZnMalloc((unsigned) (text->num_chars + length + 1)); + byte_index = Tcl_UtfAtIndex(text->text, *index)-text->text; + num_chars = Tcl_NumUtfChars(chars, num_bytes); + if (text->text) { - strncpy(new, text->text, (size_t) *index); - strcpy(new + *index + length, text->text + *index); + new = ZnMalloc(strlen(text->text) + num_bytes + 1); + memcpy(new, text->text, (size_t) byte_index); + strcpy(new + byte_index + num_bytes, text->text + byte_index); ZnFree(text->text); } - strcpy(new + *index, chars); + else { + new = ZnMalloc(num_bytes + 1); + } + strcpy(new + byte_index, chars); text->text = new; - text->num_chars += length; + text->num_chars += num_chars; if (text->insert_index >= *index) { - text->insert_index += length; + text->insert_index += num_chars; + } + if (ti->sel_item == item) { + if (ti->sel_first >= *index) { + ti->sel_first += num_chars; + } + if (ti->sel_last >= *index) { + ti->sel_last += num_chars; + } + if ((ti->anchor_item == item) && (ti->sel_anchor >= *index)) { + ti->sel_anchor += num_chars; + } } ITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); @@ -1497,7 +1542,9 @@ DeleteChars(Item item, int *last) { TextItem text = (TextItem) item; - int count; + int byte_count, first_offset; + int char_count, num_bytes; + TextInfo *ti = &item->wi->text_info; char *new; if (!text->text) { @@ -1512,15 +1559,19 @@ DeleteChars(Item item, if (*first > *last) { return; } - count = *last + 1 - *first; + char_count = *last + 1 - *first; + first_offset = Tcl_UtfAtIndex(text->text, *first)-text->text; + byte_count = Tcl_UtfAtIndex(text->text + first_offset, char_count)- + (text->text+first_offset); + num_bytes = strlen(text->text); - if (text->num_chars - count) { - new = (char *) ZnMalloc((unsigned) (text->num_chars + 1 - count)); - strncpy(new, text->text, (size_t) *first); - strcpy(new + *first, text->text + *last + 1); + if (num_bytes - byte_count) { + new = (char *) ZnMalloc((unsigned) (num_bytes + 1 - byte_count)); + memcpy(new, text->text, (size_t) first_offset); + strcpy(new + first_offset, text->text + first_offset + byte_count); ZnFree(text->text); text->text = new; - text->num_chars -= count; + text->num_chars -= char_count; } else { ZnFree(text->text); @@ -1529,11 +1580,34 @@ DeleteChars(Item item, } if (text->insert_index > *first) { - text->insert_index -= count; + text->insert_index -= char_count; if (text->insert_index < *first) { text->insert_index = *first; } } + if (ti->sel_item == item) { + if (ti->sel_first > *first) { + ti->sel_first -= char_count; + if (ti->sel_first < *first) { + ti->sel_first = *first; + } + } + if (ti->sel_last >= *first) { + ti->sel_last -= char_count; + if (ti->sel_last < *first - 1) { + ti->sel_last = *first - 1; + } + } + if (ti->sel_first > ti->sel_last) { + ti->sel_item = ZN_NO_ITEM; + } + if ((ti->anchor_item == item) && (ti->sel_anchor > *first)) { + ti->sel_anchor -= char_count; + if (ti->sel_anchor < *first) { + ti->sel_anchor = *first; + } + } + } ITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); } @@ -1577,27 +1651,31 @@ Selection(Item item, int field, int offset, char *chars, - int max_chars) + int max_bytes) { TextItem text = (TextItem) item; WidgetInfo *wi = item->wi; TextInfo *ti = &wi->text_info; int count; + char *sel_first, *sel_last; if (!text->text) { return 0; } - count = ti->sel_last - ti->sel_first - offset; - if (count > max_chars) { - count = max_chars; - } - if (count > text->num_chars) { - count = text->num_chars; + if ((ti->sel_first < 0) || + (ti->sel_first > ti->sel_last)) { + return 0; } + sel_first = Tcl_UtfAtIndex(text->text, ti->sel_first); + sel_last = Tcl_UtfAtIndex(sel_first, ti->sel_last + 1 - ti->sel_first); + count = sel_last - sel_first - offset; if (count <= 0) { return 0; } - strncpy(chars, text->text + ti->sel_first + offset, (size_t) count); + if (count > max_bytes) { + count = max_bytes; + } + memcpy(chars, sel_first + offset, (size_t) count); chars[count] = 0; return count; |