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