From 3f0180a73676ef6365802c2f2567be96191add37 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Fri, 26 May 2000 08:44:08 +0000 Subject: Ajout des m�thodes permettant l'�dition de texte, focus, selection, index. Correction des autres m�thodes et int�gration avec la structure partag�e dans WidgetInfo. --- generic/Text.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 393 insertions(+), 48 deletions(-) (limited to 'generic') diff --git a/generic/Text.c b/generic/Text.c index 187a228..61e5020 100644 --- a/generic/Text.c +++ b/generic/Text.c @@ -24,12 +24,21 @@ * */ +/* + * Some functions in this file are derived from tkCanvText.c and thus + * copyrighted: + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * + */ #include #include #include #include #include +#include #include "Item.h" #include "Geo.h" @@ -42,16 +51,11 @@ static const char rcsid[] = "$Imagine: Text.c,v 1.13 1997/05/15 11:35:46 lecoane static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; -static Bool got_selection = True; - - /* * Bit offset of flags. */ #define UNDERLINED 1 #define OVERSTRIKED 2 -#define HAS_FOCUS 4 /* True if the text has the focus and should display - * the insertion cursor */ /* @@ -88,9 +92,8 @@ typedef struct _TextItemStruct { /* Private data */ ZnPoint pos_dev; + int num_chars; int insert_index; - int sel_start; - int sel_end; ZnList text_info; int max_width; } TextItemStruct, *TextItem; @@ -145,7 +148,7 @@ static ZnAttrConfig text_attrs[] = { { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(TextItemStruct, header.flags), VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, - { ZN_CONFIG_INT, "-width", NULL, + { ZN_CONFIG_DIM, "-width", NULL, Tk_Offset(TextItemStruct, width), 0, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, @@ -179,6 +182,7 @@ Init(Item item, text->pos.x = text->pos.y = 0.0; text->text = ""; + text->num_chars = 0; text->fill_pattern = ZnUnspecifiedPattern; text->anchor = ZnAnchorNW; text->connection_anchor = ZnAnchorSW; @@ -190,11 +194,8 @@ Init(Item item, text->spacing = 0; text->insert_index = 0; - text->sel_start = 0; - text->sel_end = 0; CLEAR(text->flags, UNDERLINED); CLEAR(text->flags, OVERSTRIKED); - CLEAR(text->flags, HAS_FOCUS); return ZN_OK; } @@ -343,12 +344,16 @@ ComputeCoordinates(Item item, TextItem text = (TextItem) item; TextLineInfo infos; Tk_FontMetrics fm; - int i, num_lines; + int i, fuzz, num_lines; int cur_dy; int font_height, height; ResetBBox(&item->item_bounding_box); - if (strlen(text->text) == 0) { + 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; } @@ -469,6 +474,8 @@ ComputeCoordinates(Item item, } else { ZnTransformPoint(wi->current_transfo, &text->pos, &text->pos_dev); + text->pos_dev.x = REAL_TO_INT(text->pos_dev.x); + text->pos_dev.y = REAL_TO_INT(text->pos_dev.y); } Anchor2Origin(&text->pos_dev, text->max_width, height, text->anchor, @@ -480,10 +487,11 @@ ComputeCoordinates(Item item, AddPointToBBox(&item->item_bounding_box, text->pos_dev.x, text->pos_dev.y); AddPointToBBox(&item->item_bounding_box, text->pos_dev.x+text->max_width+1, text->pos_dev.y+height); - item->item_bounding_box.orig.x -= 1; - item->item_bounding_box.orig.y -= 1; - item->item_bounding_box.corner.x += 1; - item->item_bounding_box.corner.y += 1; + fuzz = 1+(wi->text_info.insert_width/2); + item->item_bounding_box.orig.x -= fuzz; + item->item_bounding_box.orig.y -= fuzz; + item->item_bounding_box.corner.x += fuzz; + item->item_bounding_box.corner.y += fuzz; /* * Update connected items. @@ -587,7 +595,7 @@ Draw(Item item) * position along the X axis. */ line_index = lines_ptr->start - text->text; - if (ISSET(text->flags, HAS_FOCUS) && + if ((wi->text_info.focus_item == item) && wi->text_info.got_focus && text->insert_index >= line_index && text->insert_index <= line_index + lines_ptr->num_chars) { cursor_line = i; @@ -599,22 +607,23 @@ Draw(Item item) * Compute the selection first and last line as well as * the positions along the X axis. */ - if (text->sel_end >= line_index && - text->sel_start <= line_index + lines_ptr->num_chars) { + 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 (sel_first_line < 0) { - char_index = text->sel_start - line_index; + char_index = wi->text_info.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); + /*printf("sel_start_offset 1 : %d\n", sel_start_offset);*/ } 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); - //printf("sel_start_offset 2 : %d\n", sel_start_offset); + /*printf("sel_start_offset 2 : %d\n", sel_start_offset);*/ } } - char_index = text->sel_end - line_index; + char_index = wi->text_info.sel_last - line_index; sel_last_line = i; if (char_index == lines_ptr->num_chars+1) sel_stop_offset = lines_ptr->width; @@ -628,10 +637,10 @@ Draw(Item item) /* * Setup the gc for the selection and fill the selection. */ - if ((sel_first_line >= 0) && got_selection) { + if ((wi->text_info.sel_item == item) && (sel_first_line >= 0)) { int x, y; - values.foreground = ZnPixel(text->fill_color); + values.foreground = ZnPixel(wi->text_info.sel_color); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCForeground, &values); @@ -645,21 +654,42 @@ Draw(Item item) x = (int)(text->pos_dev.x + lines[sel_first_line].text_origin.x + sel_start_offset); y = (int)(text->pos_dev.y + lines[sel_first_line].text_origin.y - fm.ascent); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, - x, y, lines[sel_first_line].width - sel_start_offset, font_height); + x, y, + text->max_width-lines[sel_first_line].text_origin.x-sel_start_offset, + font_height); for (i = sel_first_line+1, lines_ptr = &lines[sel_first_line+1]; i < sel_last_line; i++, lines_ptr++) { - x = (int)(text->pos_dev.x + lines_ptr->text_origin.x); - y = (int)(text->pos_dev.y + lines_ptr->text_origin.y - fm.ascent); + x = (int) text->pos_dev.x; + y = (int) (text->pos_dev.y + lines_ptr->text_origin.y - fm.ascent); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, - x, y, lines_ptr->width, font_height); + x, y, text->max_width, font_height); } x = (int)text->pos_dev.x; y = (int)(text->pos_dev.y + lines[sel_last_line].text_origin.y - fm.ascent); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, - x, y, sel_stop_offset, font_height); + x, y, lines[sel_last_line].text_origin.x+sel_stop_offset, + font_height); } } + //printf("cursor line : %d, cursor offset : %d\n", cursor_line, cursor_offset); + /* + * Setup the gc for the cursor and draw it. + */ + if ((cursor_line >= 0) && + (wi->text_info.focus_item == item) && wi->text_info.cursor_on) { + int xs, ys; + + values.fill_style = FillSolid; + values.line_width = wi->text_info.insert_width; + values.foreground = ZnPixel(wi->text_info.insert_color); + XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle|GCLineWidth, &values); + + xs = (int)(text->pos_dev.x + lines[cursor_line].text_origin.x + cursor_offset); + ys = (int)(text->pos_dev.y + lines[cursor_line].text_origin.y - fm.ascent + 1); + XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, xs, ys, xs, ys + font_height - 1); + } + /* * Setup the gc to render the text and draw it. */ @@ -709,22 +739,6 @@ Draw(Item item) tmp_x, y_over, tmp_x+lines_ptr->width, y_over); } } - - //printf("cursor line : %d, cursor offset : %d\n", cursor_line, cursor_offset); - /* - * Setup the gc for the cursor and draw it. - */ - if ((cursor_line >= 0) && ISSET(text->flags, HAS_FOCUS)) { - int xs, ys; - - values.fill_style = FillSolid; - values.line_width = 2; - XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCLineWidth, &values); - - xs = (int)(text->pos_dev.x + lines[cursor_line].text_origin.x + cursor_offset + 1); - ys = (int)(text->pos_dev.y + lines[cursor_line].text_origin.y - fm.ascent + 1); - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, xs, ys, xs, ys + font_height - 1); - } } @@ -823,7 +837,7 @@ GetAnchor(Item item, { TextItem text = (TextItem) item; - if (strlen(text->text) != 0) { + if (text->num_chars != 0) { Origin2Anchor(&text->pos_dev, item->item_bounding_box.corner.x-item->item_bounding_box.orig.x, item->item_bounding_box.corner.y-item->item_bounding_box.orig.y, @@ -904,6 +918,332 @@ Coords(Item item, /* ********************************************************************************** * + * Index -- + * Parse a text index and return its value and aa + * error status (standard Tcl result). + * + ********************************************************************************** + */ +static int +PointToChar(Item item, + int x, + int y) +{ + TextItem text = (TextItem) item; + int i, n, num_lines, dummy; + TextLineInfo lines, p; + Tk_FontMetrics fm; + + x -= text->pos_dev.x; + y -= text->pos_dev.y; + + /* + * Point above text, returns index 0. + */ + if (y < 0) { + return 0; + } + + /* + * Find the text line under point. + */ + num_lines = ZnListSize(text->text_info); + lines = p = (TextLineInfo) 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) { + if (x < p->text_origin.x) { + /* + * Point to the left of the current line, returns + * index of first char. + */ + return p->start - text->text; + } + 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; + } + n = Tk_MeasureChars(text->font, p->start, p->num_chars, + x + 2 - p->text_origin.x, TK_PARTIAL_OK, &dummy); + return (p->start + n - 1) - text->text; + } + } + /* + * Point below all lines, return the index after + * the last char in text. + */ + p--; + return p->start + p->num_chars - text->text; +} + +static int +Index(Item item, + char *index_str, + int *index) +{ + TextItem text = (TextItem) item; + WidgetInfo *wi = item->wi; + int c, length; + int x, y; + double tmp; + char *end, *p; + + c = index_str[0]; + length = strlen(index_str); + + if ((c == 'e') && (strncmp(index_str, "end", length) == 0)) { + *index = text->num_chars; + } + else if ((c == 'i') && (strncmp(index_str, "insert", length) == 0)) { + *index = text->insert_index; + } + else if ((c == 's') && (strncmp(index_str, "sel.first", length) == 0) && + (length >= 5)) { + if (wi->text_info.sel_item != item) { + Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); + return TCL_ERROR; + } + *index = wi->text_info.sel_first; + } + else if ((c == 's') && (strncmp(index_str, "sel.last", length) == 0) && + (length >= 5)) { + if (wi->text_info.sel_item != item) { + Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); + return TCL_ERROR; + } + *index = wi->text_info.sel_last; + } + else if (c == '@') { + p = index_str+1; + tmp = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + /*x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);*/ + x = tmp; + p = end+1; + tmp = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + /*y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);*/ + y = tmp; + + *index = PointToChar(item, x-wi->inset, y-wi->inset); + } + else if (Tcl_GetInt(wi->interp, index_str, index) == TCL_OK) { + if (*index < 0){ + *index = 0; + } + else if (*index > text->num_chars) { + *index = text->num_chars; + } + } + else { + badIndex: + Tcl_AppendResult(wi->interp, "bad index \"", index_str, "\"", (char *) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + + +/* + ********************************************************************************** + * + * InsertChars -- + * + ********************************************************************************** + */ +static void +InsertChars(Item item, + 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 > 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); + 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) { + text->insert_index += length; + } + + ITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); +} + + +/* + ********************************************************************************** + * + * DeleteChars -- + * + ********************************************************************************** + */ +static void +DeleteChars(Item item, + int first, + int last) +{ + TextItem text = (TextItem) item; + WidgetInfo *wi = item->wi; + int count; + char *new; + + if (first < 0) { + first = 0; + } + if (last >= text->num_chars) { + last = text->num_chars-1; + } + if (first > last) { + return; + } + 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); + 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) { + text->insert_index -= count; + if (text->insert_index < first) { + text->insert_index = first; + } + } + + ITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); +} + + +/* + ********************************************************************************** + * + * Cursor -- + * + ********************************************************************************** + */ +static void +TextCursor(Item item, + int index) +{ + TextItem text = (TextItem) item; + + if (index < 0) { + text->insert_index = 0; + } + else if (index > text->num_chars) { + text->insert_index = text->num_chars; + } + else { + text->insert_index = index; + } +} + + +/* + ********************************************************************************** + * + * Selection -- + * + ********************************************************************************** + */ +static int +Selection(Item item, + int offset, + char *chars, + int max_chars) +{ + TextItem text = (TextItem) item; + WidgetInfo *wi = item->wi; + int count; + + count = wi->text_info.sel_last - wi->text_info.sel_first - offset; + if (count > max_chars) { + count = max_chars; + } + if (count <= 0) { + return 0; + } + strncpy(chars, text->text + wi->text_info.sel_first + offset, (size_t) count); + chars[count] = '\0'; + + return count; +} + + +/* + ********************************************************************************** + * * Exported functions struct * ********************************************************************************** @@ -924,6 +1264,11 @@ static ItemClassStruct TEXT_ITEM_CLASS = { GetAnchor, GetClipVertices, Coords, + InsertChars, + DeleteChars, + TextCursor, + Index, + Selection, NULL, /* Contour */ ComputeCoordinates, ToArea, -- cgit v1.1