aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generic/Text.c300
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;