diff options
-rw-r--r-- | generic/Text.c | 286 |
1 files changed, 188 insertions, 98 deletions
diff --git a/generic/Text.c b/generic/Text.c index 3f8cba3..302f5c4 100644 --- a/generic/Text.c +++ b/generic/Text.c @@ -230,16 +230,14 @@ Clone(Item item) text->color = ZnGetGradientByValue(text->color); text->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(text->font)); - if (text->text_info) { - text->text_info = ZnListDuplicate(text->text_info); - } - else { - /* - * Needed in case the layout of the model has not been - * done yet. - */ - SET(item->inv_flags, ZN_LAYOUT_FLAG); - } + /* + * We always need to invalidate, either because the model + * has not done its layout (text_info == NULL) or because + * we must unshare the pointers to the text that are in + * text_info. + */ + text->text_info = NULL; + ITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); } @@ -285,15 +283,22 @@ Configure(Item item, Tcl_Obj *CONST argv[], int *flags) { - Item old_connected; - ZnFont old_font; TextItem text = (TextItem) item; - - old_connected = item->connected_item; - old_font = text->font; - if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == ZN_ERROR) { + Item old_connected = item->connected_item; +#ifdef GLX + ZnFont old_font = text->font; +#endif + + if (ZnConfigureAttributes(item->wi, item, text_attrs, + argc, argv, flags) == ZN_ERROR) { return ZN_ERROR; - } + } + +#ifdef GLX + if (old_font != text->font) { + text->txf = NULL; + } +#endif if (ISSET(*flags, ZN_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up @@ -325,7 +330,7 @@ Query(Item item, int argc, Tcl_Obj *CONST argv[]) { - if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == ZN_ERROR) { + if (ZnQueryAttribute(item->wi, item, text_attrs, argv[0]) == ZN_ERROR) { return ZN_ERROR; } @@ -592,7 +597,7 @@ ComputeCursorAndSel(Item item, * position along the X axis. */ line_index = lines_ptr->start - text->text; - if ((wi->text_info.focus_item == item) && wi->text_info.got_focus && + if ((wi->focus_item == item) && wi->got_focus && wi->text_info.cursor_on && text->insert_index >= line_index && text->insert_index <= line_index + lines_ptr->num_chars) { *cursor_line = i; @@ -616,7 +621,8 @@ ComputeCursorAndSel(Item item, } else if (char_index <= lines_ptr->num_chars) { *sel_first_line = i; - *sel_start_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, char_index); + *sel_start_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, + char_index); /*printf("sel_start_offset 2 : %d\n", *sel_start_offset);*/ } } @@ -625,7 +631,8 @@ ComputeCursorAndSel(Item item, 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); + *sel_stop_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, + char_index); } } } @@ -712,8 +719,7 @@ Draw(Item item) /* * Setup the gc for the cursor and draw it. */ - if ((cursor_line >= 0) && - (wi->text_info.focus_item == item) && wi->text_info.cursor_on) { + if (cursor_line >= 0) { int xs, ys; values.fill_style = FillSolid; @@ -795,6 +801,11 @@ Render(Item item) int i, num_lines; XColor *color; int alpha; + Tk_FontMetrics fm; + int font_height; + 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; if (!text->text_info) { return; @@ -805,26 +816,143 @@ Render(Item item) if (!text->txf) { return; } + + lines = (TextLineInfo) ZnListArray(text->text_info); + num_lines = ZnListSize(text->text_info); + Tk_GetFontMetrics(text->font, &fm); + font_height = fm.ascent+fm.descent; + + /* + * These 3 values should be fetched from the font. + * Currently I don't know how without diving into + * Tk internals. + */ + underline_thickness = 2; + underline_pos = fm.descent/2; + overstrike_pos = fm.ascent*3/10; + + /* + * Compute the selection and the cursor geometry. + */ + ComputeCursorAndSel(item, lines, num_lines, + &sel_first_line, &sel_last_line, + &cursor_line, &sel_start_offset, + &sel_stop_offset, &cursor_offset); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + /* + * Render the selection. + */ + color = ZnGetGradientColor(wi->text_info.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)) { + ZnReal xo, yo, xc, yc; + + glBegin(GL_QUADS); + if (sel_first_line == sel_last_line) { + xo = text->pos_dev.x + lines[sel_first_line].text_origin.x + sel_start_offset; + yo = text->pos_dev.y + lines[sel_first_line].text_origin.y - fm.ascent; + xc = xo + sel_stop_offset - sel_start_offset; + yc = yo + font_height; + glVertex2f(xo, yo); + glVertex2f(xc, yo); + glVertex2f(xc, yc); + glVertex2f(xo, yc); + } + else { + xo = text->pos_dev.x + lines[sel_first_line].text_origin.x + sel_start_offset; + yo = text->pos_dev.y + lines[sel_first_line].text_origin.y - fm.ascent; + xc = xo + text->max_width-lines[sel_first_line].text_origin.x-sel_start_offset; + yc = yo + font_height; + glVertex2f(xo, yo); + glVertex2f(xc, yo); + glVertex2f(xc, yc); + glVertex2f(xo, yc); + for (i = sel_first_line+1, lines_ptr = &lines[sel_first_line+1]; + i < sel_last_line; i++, lines_ptr++) { + xo = text->pos_dev.x; + yo = text->pos_dev.y + lines_ptr->text_origin.y - fm.ascent; + xc = xo + text->max_width; + yc = yo + font_height; + glVertex2f(xo, yo); + glVertex2f(xc, yo); + glVertex2f(xc, yc); + glVertex2f(xo, yc); + } + xo = text->pos_dev.x; + yo = text->pos_dev.y + lines[sel_last_line].text_origin.y - fm.ascent; + xc = xo + lines[sel_last_line].text_origin.x+sel_stop_offset; + yc = yo + font_height; + glVertex2f(xo, yo); + glVertex2f(xc, yo); + glVertex2f(xc, yc); + glVertex2f(xo, yc); + } + glEnd(); + } + + /* + * Render the cursor. + */ + color = ZnGetGradientColor(wi->text_info.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) { + int xs, ys; + + glLineWidth(wi->text_info.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); + glVertex2f(xs, ys); + glVertex2f(xs, ys + font_height - 1); + glEnd(); + } + + /* + * Render the text. + */ glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, text->txf->texobj); color = ZnGetGradientColor(text->color, 0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); - glBindTexture(GL_TEXTURE_2D, text->txf->texobj); - - lines = (TextLineInfo) ZnListArray(text->text_info); - num_lines = ZnListSize(text->text_info); for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { + ZnReal xs, ys; + + xs = text->pos_dev.x + lines_ptr->text_origin.x; + ys = text->pos_dev.y + lines_ptr->text_origin.y; + glPushMatrix(); - glTranslatef(text->pos_dev.x + lines_ptr->text_origin.x, - text->pos_dev.y + lines_ptr->text_origin.y, - 0.0); + glTranslatef(xs, ys, 0.0); txfRenderString(text->txf, lines_ptr->start, lines_ptr->num_chars); - glPopMatrix(); + glPopMatrix(); + + if (ISSET(text->flags, UNDERLINED) || ISSET(text->flags, OVERSTRIKED)) { + glLineWidth(underline_thickness); + glDisable(GL_TEXTURE_2D); + if (ISSET(text->flags, UNDERLINED)) { + glBegin(GL_LINES); + glVertex2f(xs, ys+underline_pos); + glVertex2f(xs+lines_ptr->width, ys+underline_pos); + glEnd(); + } + if (ISSET(text->flags, OVERSTRIKED)) { + glBegin(GL_LINES); + glVertex2f(xs, ys-overstrike_pos); + glVertex2f(xs+lines_ptr->width, ys-overstrike_pos); + glEnd(); + } + glEnable(GL_TEXTURE_2D); + } } glDisable(GL_TEXTURE_2D); + #endif } @@ -1076,6 +1204,7 @@ PointToChar(Item item, static int Index(Item item, + int field, Tcl_Obj *index_spec, int *index) { @@ -1157,49 +1286,33 @@ Index(Item item, */ static void InsertChars(Item item, - int index, + int field, + int *index, char *chars) { TextItem text = (TextItem) item; - WidgetInfo *wi = item->wi; int length = strlen(chars); char *new; if (length == 0) { return; } - if (index < 0) { - index = 0; + if (*index < 0) { + *index = 0; } - if (index > text->num_chars) { - index = text->num_chars; + if (*index > text->num_chars) { + *index = text->num_chars; } new = ZnMalloc((unsigned) (text->num_chars + length + 1)); - strncpy(new, text->text, (size_t) index); - strcpy(new+index, chars); - strcpy(new+index+length, text->text+index); + strncpy(new, text->text, (size_t) *index); + strcpy(new + *index, chars); + strcpy(new + *index + length, text->text + *index); ZnFree(text->text); text->text = new; text->num_chars += length; - /* - * Inserting characters invalidates indices such as those for the - * selection and cursor. Update the indices appropriately. - */ - if (wi->text_info.sel_item == item) { - if (wi->text_info.sel_first >= index) { - wi->text_info.sel_first += length; - } - if (wi->text_info.sel_last >= index) { - wi->text_info.sel_last += length; - } - if ((wi->text_info.anchor_item == item) - && (wi->text_info.sel_anchor >= index)) { - wi->text_info.sel_anchor += length; - } - } - if (text->insert_index >= index) { + if (text->insert_index >= *index) { text->insert_index += length; } @@ -1216,11 +1329,11 @@ InsertChars(Item item, */ static void DeleteChars(Item item, - int first, - int last) + int field, + int *first, + int *last) { TextItem text = (TextItem) item; - WidgetInfo *wi = item->wi; int count; char *new; @@ -1228,56 +1341,28 @@ DeleteChars(Item item, return; } - if (first < 0) { - first = 0; + if (*first < 0) { + *first = 0; } - if (last >= text->num_chars) { - last = text->num_chars-1; + if (*last >= text->num_chars) { + *last = text->num_chars-1; } - if (first > last) { + if (*first > *last) { return; } - count = last + 1 - first; + count = *last + 1 - *first; new = (char *) ZnMalloc((unsigned) (text->num_chars + 1 - count)); strncpy(new, text->text, (size_t) first); - strcpy(new+first, text->text+last+1); + strcpy(new + *first, text->text + *last + 1); ZnFree(text->text); text->text = new; text->num_chars -= count; - /* - * Update indexes for the selection and cursor to reflect the - * renumbering of the remaining characters. - */ - if (wi->text_info.sel_item == item) { - if (wi->text_info.sel_first > first) { - wi->text_info.sel_first -= count; - if (wi->text_info.sel_first < first) { - wi->text_info.sel_first = first; - } - } - if (wi->text_info.sel_last >= first) { - wi->text_info.sel_last -= count; - if (wi->text_info.sel_last < (first-1)) { - wi->text_info.sel_last = (first-1); - } - } - if (wi->text_info.sel_first > wi->text_info.sel_last) { - wi->text_info.sel_item = ZN_NO_ITEM; - } - if ((wi->text_info.anchor_item == item) - && (wi->text_info.sel_anchor > first)) { - wi->text_info.sel_anchor -= count; - if (wi->text_info.sel_anchor < first) { - wi->text_info.sel_anchor = first; - } - } - } - if (text->insert_index > first) { + if (text->insert_index > *first) { text->insert_index -= count; - if (text->insert_index < first) { - text->insert_index = first; + if (text->insert_index < *first) { + text->insert_index = *first; } } @@ -1294,6 +1379,7 @@ DeleteChars(Item item, */ static void TextCursor(Item item, + int field, int index) { TextItem text = (TextItem) item; @@ -1319,6 +1405,7 @@ TextCursor(Item item, */ static int Selection(Item item, + int field, int offset, char *chars, int max_chars) @@ -1331,6 +1418,9 @@ Selection(Item item, if (count > max_chars) { count = max_chars; } + if (count > text->num_chars) { + count = text->num_chars; + } if (count <= 0) { return 0; } |