From 960cdf29197bc3f5922110cf26627aa9709ac79b Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Fri, 10 Jun 2005 10:29:11 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'bogue40'. --- generic/Text.c | 2061 -------------------------------------------------------- 1 file changed, 2061 deletions(-) delete mode 100644 generic/Text.c (limited to 'generic/Text.c') diff --git a/generic/Text.c b/generic/Text.c deleted file mode 100644 index b2e83f8..0000000 --- a/generic/Text.c +++ /dev/null @@ -1,2061 +0,0 @@ -/* - * Text.c -- Implementation of Text item. - * - * Authors : Patrick LECOANET - * Creation date : Sat Mar 25 13:58:39 1995 - */ - -/* - * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- - * - * See the file "Copyright" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - */ - -/* - * 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 "Item.h" -#include "Geo.h" -#include "Draw.h" -#include "Types.h" -#include "WidgetInfo.h" -#include "tkZinc.h" -#include "Image.h" - - -static const char rcsid[] = "$Imagine: Text.c,v 1.13 1997/05/15 11:35:46 lecoanet Exp $"; -static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; - - -/* - * Bit offset of flags. - */ -#define UNDERLINED 1 -#define OVERSTRIKED 2 - - -/* - ********************************************************************************** - * - * Specific Text item record - * - ********************************************************************************** - */ -typedef struct _TextLineInfo -{ - char *start; /* Index of first char in line */ - unsigned short num_bytes; /* Number of displayed bytes in line (NOT chars)*/ - unsigned short width; /* Line width in pixels */ - unsigned short origin_x; /* X pos for drawing the line */ - unsigned short origin_y; -} TextLineInfoStruct, *TextLineInfo; - -typedef struct _TextItemStruct { - ZnItemStruct header; - - /* Public data */ - ZnPoint pos; /* Position at anchor */ - ZnGradient *color; - char *text; - ZnImage fill_pattern; - Tk_Font font; - unsigned short width; - short spacing; - unsigned short flags; - Tk_Anchor anchor; - Tk_Anchor connection_anchor; - Tk_Justify alignment; - - /* Private data */ - unsigned short num_chars; - unsigned short insert_index; - ZnList text_info; - unsigned short max_width; - unsigned short height; - ZnPoint poly[4]; -#ifdef GL - ZnTexFontInfo *tfi; -#endif -} TextItemStruct, *TextItem; - - -static ZnAttrConfig text_attrs[] = { - { ZN_CONFIG_ALIGNMENT, "-alignment", NULL, - Tk_Offset(TextItemStruct, alignment), 0, - ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, - { ZN_CONFIG_ANCHOR, "-anchor", NULL, - Tk_Offset(TextItemStruct, anchor), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-color", NULL, - Tk_Offset(TextItemStruct, color), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-composealpha", NULL, - Tk_Offset(TextItemStruct, header.flags), ZN_COMPOSE_ALPHA_BIT, - ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-composerotation", NULL, - Tk_Offset(TextItemStruct, header.flags), ZN_COMPOSE_ROTATION_BIT, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_BOOL, "-composescale", NULL, - Tk_Offset(TextItemStruct, header.flags), ZN_COMPOSE_SCALE_BIT, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_ITEM, "-connecteditem", NULL, - Tk_Offset(TextItemStruct, header.connected_item), 0, - ZN_COORDS_FLAG|ZN_ITEM_FLAG, False }, - { ZN_CONFIG_ANCHOR, "-connectionanchor", NULL, - Tk_Offset(TextItemStruct, connection_anchor), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_BITMAP, "-fillpattern", NULL, - Tk_Offset(TextItemStruct, fill_pattern), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_FONT, "-font", NULL, - Tk_Offset(TextItemStruct, font), 0, - ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, - { ZN_CONFIG_BOOL, "-overstriked", NULL, - Tk_Offset(TextItemStruct, flags), OVERSTRIKED, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_POINT, "-position", NULL, Tk_Offset(TextItemStruct, pos), 0, - ZN_COORDS_FLAG, False}, - { ZN_CONFIG_PRI, "-priority", NULL, - Tk_Offset(TextItemStruct, header.priority), 0, - ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, - { ZN_CONFIG_BOOL, "-sensitive", NULL, - Tk_Offset(TextItemStruct, header.flags), ZN_SENSITIVE_BIT, - ZN_REPICK_FLAG, False }, - { ZN_CONFIG_SHORT, "-spacing", NULL, - Tk_Offset(TextItemStruct, spacing), 0, - ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, - { ZN_CONFIG_TAG_LIST, "-tags", NULL, - Tk_Offset(TextItemStruct, header.tags), 0, 0, False }, - { ZN_CONFIG_STRING, "-text", NULL, - Tk_Offset(TextItemStruct, text), 0, - ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, - { ZN_CONFIG_BOOL, "-underlined", NULL, - Tk_Offset(TextItemStruct, flags), UNDERLINED, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-visible", NULL, - Tk_Offset(TextItemStruct, header.flags), ZN_VISIBLE_BIT, - ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, - { ZN_CONFIG_USHORT, "-width", NULL, - Tk_Offset(TextItemStruct, width), 0, - ZN_COORDS_FLAG|ZN_LAYOUT_FLAG, False }, - - { ZN_CONFIG_END, NULL, NULL, 0, 0, 0, False } -}; - - -/* - ********************************************************************************** - * - * Init -- - * - ********************************************************************************** - */ -static int -Init(ZnItem item, - int *argc, - Tcl_Obj *CONST *args[]) -{ - ZnWInfo *wi = item->wi; - TextItem text = (TextItem) item; - - /*printf("size of a text(header) = %d(%d) %d\n", - sizeof(TextItemStruct), sizeof(ZnItemStruct), sizeof(TextLineInfoStruct));*/ - - text->text_info = NULL; - - /* Init attributes */ - SET(item->flags, ZN_VISIBLE_BIT); - SET(item->flags, ZN_SENSITIVE_BIT); - SET(item->flags, ZN_COMPOSE_ALPHA_BIT); - CLEAR(item->flags, ZN_COMPOSE_ROTATION_BIT); - CLEAR(item->flags, ZN_COMPOSE_SCALE_BIT); - item->priority = 1; - - text->pos.x = text->pos.y = 0.0; - text->text = NULL; - text->num_chars = 0; - text->fill_pattern = ZnUnspecifiedImage; - text->anchor = TK_ANCHOR_NW; - text->connection_anchor = TK_ANCHOR_SW; - text->color = ZnGetGradientByValue(wi->fore_color); - text->alignment = TK_JUSTIFY_LEFT; - text->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font)); -#ifdef GL - text->tfi = ZnGetTexFont(wi, text->font); -#endif - text->width = 0; - text->spacing = 0; - text->insert_index = 0; - CLEAR(text->flags, UNDERLINED); - CLEAR(text->flags, OVERSTRIKED); - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * Clone -- - * - ********************************************************************************** - */ -static void -Clone(ZnItem item) -{ - TextItem text = (TextItem) item; - ZnWInfo *wi = item->wi; - char *str; - - if (text->text) { - str = ZnMalloc((strlen(text->text) + 1) * sizeof(char)); - strcpy(str, text->text); - text->text = str; - } - if (text->fill_pattern != ZnUnspecifiedImage) { - text->fill_pattern = ZnGetImageByValue(text->fill_pattern, NULL, NULL); - } - text->color = ZnGetGradientByValue(text->color); - text->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(text->font)); -#ifdef GL - text->tfi = ZnGetTexFont(wi, text->font); -#endif - - /* - * 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; - ZnITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); -} - - -/* - ********************************************************************************** - * - * Destroy -- - * - ********************************************************************************** - */ -static void -Destroy(ZnItem item) -{ - TextItem text = (TextItem) item; - - if (text->text) { - ZnFree(text->text); - } - if (text->fill_pattern != ZnUnspecifiedImage) { - ZnFreeImage(text->fill_pattern, NULL, NULL); - text->fill_pattern = ZnUnspecifiedImage; - } - ZnFreeGradient(text->color); - Tk_FreeFont(text->font); -#ifdef GL - if (text->tfi) { - ZnFreeTexFont(text->tfi); - } -#endif - - if (text->text_info) { - ZnListFree(text->text_info); - } -} - - -/* - ********************************************************************************** - * - * Configure -- - * - ********************************************************************************** - */ -static int -Configure(ZnItem item, - int argc, - Tcl_Obj *CONST argv[], - int *flags) -{ - TextItem text = (TextItem) item; - ZnItem old_connected = item->connected_item; - unsigned int num_chars; -#ifdef GL - Tk_Font old_font = text->font; -#endif - - if (ZnConfigureAttributes(item->wi, item, item, text_attrs, - argc, argv, flags) == TCL_ERROR) { - return TCL_ERROR; - } - -#ifdef GL - if (old_font != text->font) { - if (text->tfi) { - ZnFreeTexFont(text->tfi); - text->tfi = ZnGetTexFont(item->wi, text->font); - } - } -#endif - num_chars = 0; - if (text->text) { - num_chars = Tcl_NumUtfChars(text->text, (int) strlen(text->text)); - } - if (text->num_chars != num_chars) { - ZnTextInfo *ti = &item->wi->text_info; - /* - * The text has changed, update the selection and - * insertion pos to keep them valid. - */ - if (item == ti->sel_item) { - if (ti->sel_last > (int) num_chars) { - ti->sel_last = num_chars; - } - if (ti->sel_first >= ti->sel_last) { - ti->sel_item = ZN_NO_ITEM; - ti->sel_field = ZN_NO_PART; - } - if ((ti->anchor_item == item) && (ti->sel_anchor > (int) num_chars)) { - ti->sel_anchor = num_chars; - } - } - if (text->insert_index > num_chars) { - text->insert_index = num_chars; - } - text->num_chars = num_chars; - } - - if (ISSET(*flags, ZN_ITEM_FLAG)) { - /* - * If the new connected item is not appropriate back up - * to the old one. - */ - if ((item->connected_item == ZN_NO_ITEM) || - (ISSET(item->connected_item->class->flags, ZN_CLASS_HAS_ANCHORS) && - (item->parent == item->connected_item->parent))) { - ZnITEM.UpdateItemDependency(item, old_connected); - } - else { - item->connected_item = old_connected; - } - } - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * Query -- - * - ********************************************************************************** - */ -static int -Query(ZnItem item, - int argc, - Tcl_Obj *CONST argv[]) -{ - if (ZnQueryAttribute(item->wi->interp, item, text_attrs, argv[0]) == TCL_ERROR) { - return TCL_ERROR; - } - - return TCL_OK; -} - - -/* - * Compute the transformation to be used and the origin - * of the text (upper left point in item coordinates). - */ -static ZnTransfo * -ComputeTransfoAndOrigin(ZnItem item, - ZnPoint *origin) -{ - TextItem text = (TextItem) item; - - /* - * The connected item support anchors, this is checked by configure. - */ - if (item->connected_item != ZN_NO_ITEM) { - ZnTransfo inv; - - item->connected_item->class->GetAnchor(item->connected_item, - text->connection_anchor, - origin); - - /* GetAnchor return a position in device coordinates not in - * the item coordinate space. To compute the text origin - * (upper left corner), we must apply the inverse transform - * to the ref point before calling anchor2origin. - */ - ZnTransfoInvert(item->transfo, &inv); - ZnTransformPoint(&inv, origin, origin); - ZnAnchor2Origin(origin, (ZnReal) text->max_width, - (ZnReal) text->height, text->anchor, origin); - origin->x = ZnNearestInt(origin->x); - origin->y = ZnNearestInt(origin->y); - /* - * The relevant transform in case of an attachment is the item - * transform alone. This is case of local coordinate space where - * only the translation is a function of the whole transform - * stack, scale and rotation are reset. - */ - return item->transfo; - } - else { - ZnPoint p; - p.x = p.y = 0; - ZnAnchor2Origin(&p, (ZnReal) text->max_width, - (ZnReal) text->height, text->anchor, origin); - origin->x = ZnNearestInt(origin->x); - origin->y = ZnNearestInt(origin->y); - - return item->wi->current_transfo; - } -} - - -/* - * Compute the selection and the cursor geometry. - */ -void -ComputeCursor(ZnItem item, - int *cursor_line, - unsigned int *cursor_offset) -{ - TextItem text = (TextItem) item; - ZnWInfo *wi = item->wi; - ZnTextInfo *ti = &wi->text_info; - TextLineInfo lines, lines_ptr; - unsigned int i, line_index, insert_index, num_lines; - - num_lines = ZnListSize(text->text_info); - if (num_lines == 0) { - *cursor_line = 0; - } - - lines = ZnListArray(text->text_info); - if ((wi->focus_item == item) && ISSET(wi->flags, ZN_GOT_FOCUS) && ti->cursor_on) { - insert_index = Tcl_UtfAtIndex(text->text, (int) 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); - } - } - } - -} - -static void -ComputeSelection(ZnItem item, - int *sel_first_line, - int *sel_last_line, - unsigned int *sel_start_offset, - unsigned int *sel_stop_offset) -{ - TextItem text = (TextItem) item; - ZnWInfo *wi = item->wi; - ZnTextInfo *ti = &wi->text_info; - TextLineInfo lines_ptr, lines; - int i, num_lines, byte_index; - unsigned int line_index; - unsigned int sel_first, sel_last; - - num_lines = ZnListSize(text->text_info); - - if ((ti->sel_item != item) || !num_lines) { - return; - } - - lines = ZnListArray(text->text_info); - - sel_first = Tcl_UtfAtIndex(text->text, ti->sel_first)-text->text; - sel_last = Tcl_UtfAtIndex(text->text, ti->sel_last+1)-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, - byte_index); - /*printf("sel_start_offset 2 : %d\n", *sel_start_offset);*/ - } - } - byte_index = ti->sel_last+1 - 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); - } - } -} - - -/* - ********************************************************************************** - * - * ComputeCoordinates -- - * - ********************************************************************************** - */ -static void -ComputeCoordinates(ZnItem item, - ZnBool force) -{ - ZnWInfo *wi = item->wi; - TextItem text = (TextItem) item; - TextLineInfo infos; - Tk_FontMetrics fm; - ZnTransfo *transfo; - int i, num_lines, cur_dy, font_height; - - ZnResetBBox(&item->item_bounding_box); - - Tk_GetFontMetrics(text->font, &fm); - font_height = fm.ascent+fm.descent; - - /* - * The layout need not be done each time the item is moved, scaled - * or rotated. - */ - if (ISSET(item->inv_flags, ZN_LAYOUT_FLAG)) { - char *scan; - int wrap, prev_num_lines; - - text->max_width = 0; - if (text->text_info != NULL) { - prev_num_lines = ZnListSize(text->text_info); - ZnListEmpty(text->text_info); - } - else { - prev_num_lines = 0; - text->text_info = ZnListNew(1, sizeof(TextLineInfoStruct)); - } - - if (text->width > 0) { - wrap = text->width; - } - else { - wrap = 100000; - } - - if ((scan = text->text) != NULL) { - TextLineInfoStruct info; - - while (*scan) { - char *special; - int num, w; - - /* - * Limit the excursion of Tk_MeasureChars to the end - * of the line. Do not include \n in the measure done. - */ - num = strcspn(scan, "\r\n"); - special = scan + num; - info.num_bytes = Tk_MeasureChars(text->font, scan, num, wrap, - TK_WHOLE_WORDS|TK_AT_LEAST_ONE, &w); - - info.width = w; - info.start = scan; - text->max_width = MAX(info.width, text->max_width); - - scan += info.num_bytes; - - /* - * Skip the newline line character. - */ - if ((*scan == '\r') || (*scan == '\n')) { - scan++; - } - else { - /* - * Skip white spaces occuring after an - * automatic line break. - */ - while (*scan == ' ') { - scan++; - } - } - - ZnListAdd(text->text_info, &info, ZnListTail); - /*printf("adding a text info : %s, num_bytes : %d, width : %d\n", - info.start, info.num_bytes, info.width);*/ - } - if (*text->text && ((scan[-1] == '\r') || (scan[-1] == '\n'))) { - /* Build a text info even for an empty line - * at the end of text or for an empty text. - * It is needed to enable selection and cursor - * insertion to behave correctly. - */ - info.num_bytes = 0; - info.width = 0; - info.start = scan; - ZnListAdd(text->text_info, &info, ZnListTail); - } - } - - /* - * Compute x & y positions for all lines in text_info. The coordinates are - * in text natural units NOT transformed units. - */ - cur_dy = fm.ascent; - num_lines = ZnListSize(text->text_info); - infos = (TextLineInfo) ZnListArray(text->text_info); - - for (i = 0; i < num_lines; i++) { - switch (text->alignment) { - case TK_JUSTIFY_LEFT: - infos[i].origin_x = 0; - break; - case TK_JUSTIFY_CENTER: - infos[i].origin_x = (text->max_width + 1 - infos[i].width)/2; - break; - case TK_JUSTIFY_RIGHT: - infos[i].origin_x = text->max_width + 1 - infos[i].width; - break; - } - infos[i].origin_y = cur_dy; - cur_dy += font_height + text->spacing; - /*printf("fixing line %d x : %d, y : %d\n", i, infos[i].origin_x, - infos[i].origin_y);*/ - } - } /* ISSET(item->inv_flags, INV_TEXT_LAYOUT) */ - - text->height = font_height; - if (text->text_info && text->max_width) { - unsigned int h, cursor_offset; - int cursor_line; - ZnPoint origin, box[4]; - - num_lines = ZnListSize(text->text_info); - infos = ZnListArray(text->text_info); - h = num_lines * font_height + (num_lines-1) * text->spacing; - text->height = MAX(text->height, h); - - transfo = ComputeTransfoAndOrigin(item, &origin); - - text->poly[0].x = origin.x; - text->poly[0].y = origin.y; - text->poly[3].x = text->poly[0].x + text->max_width; - text->poly[3].y = text->poly[0].y + text->height; - text->poly[1].x = text->poly[0].x; - text->poly[1].y = text->poly[3].y; - text->poly[2].x = text->poly[3].x; - text->poly[2].y = text->poly[0].y; - ZnTransformPoints(transfo, text->poly, text->poly, 4); - - /* - * Add to the bounding box. - */ - ZnAddPointsToBBox(&item->item_bounding_box, text->poly, 4); - - /* - * Add the cursor shape to the bbox. - */ - cursor_line = -1; - ComputeCursor(item, &cursor_line, &cursor_offset); - if (cursor_line >= 0) { - if (num_lines) { - box[0].x = origin.x + infos[cursor_line].origin_x + cursor_offset - - wi->text_info.insert_width/2; - box[0].y = origin.y + infos[cursor_line].origin_y - fm.ascent + 1; - } - else { - box[0].x = origin.x; - box[0].y = origin.y; - } - box[2].x = box[0].x + wi->text_info.insert_width; - box[2].y = box[0].y + font_height - 1; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - ZnAddPointsToBBox(&item->item_bounding_box, box, 4); - } - } - - /*printf("bbox origin: %g %g corner %g %g\n", - item->item_bounding_box.orig.x, item->item_bounding_box.orig.y, - item->item_bounding_box.corner.x, item->item_bounding_box.corner.y);*/ - /* - * Update connected items. - */ - SET(item->flags, ZN_UPDATE_DEPENDENT_BIT); -} - - -/* - ********************************************************************************** - * - * ToArea -- - * Tell if the object is entirely outside (-1), - * entirely inside (1) or in between (0). - * - ********************************************************************************** - */ -static int -ToArea(ZnItem item, - ZnToArea ta) -{ - TextItem text = (TextItem) item; - int inside = -1; - ZnBool first_done = False; - int num_lines, i; - TextLineInfo lines, lines_ptr; - Tk_FontMetrics fm; - int font_height; - ZnBBox line_bbox, *area = ta->area; - ZnPoint box[4], p, origin; - ZnTransfo inv, *transfo; - - if (!text->text_info || !text->text) { - return -1; - } - - transfo = ComputeTransfoAndOrigin(item, &origin); - box[0] = area->orig; - box[2] = area->corner; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransfoInvert(transfo, &inv); - ZnTransformPoints(&inv, box, box, 4); - - lines = (TextLineInfo) ZnListArray(text->text_info); - num_lines = ZnListSize(text->text_info); - Tk_GetFontMetrics(text->font, &fm); - font_height = fm.descent + fm.ascent; - if (text->spacing > 0) { - font_height += text->spacing; - } - - /*printf("text %d, num lines=%d\n", item->id, num_lines);*/ - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - ZnResetBBox(&line_bbox); - p.x = origin.x + lines_ptr->origin_x; - p.y = origin.y + lines_ptr->origin_y - fm.ascent; - ZnAddPointToBBox(&line_bbox, p.x, p.y); - ZnAddPointToBBox(&line_bbox, p.x + lines_ptr->width, p.y + font_height); - if (!first_done) { - first_done = True; - inside = ZnPolygonInBBox(box, 4, &line_bbox, NULL); - if (inside == 0) { - return 0; - } - } - else { - if (ZnPolygonInBBox(box, 4, &line_bbox, NULL) == 0) { - return 0; - } - } - } - - return inside; -} - - -/* - ********************************************************************************** - * - * Draw -- - * - ********************************************************************************** - */ -static void -Draw(ZnItem item) -{ - ZnWInfo *wi = item->wi; - TextItem text = (TextItem) item; - XGCValues values; - ZnPoint pos, box[4], origin; - ZnTransfo *transfo; - Drawable drw; - GC gc; - XImage *src_im, *dest_im=NULL; - unsigned int dest_im_width=0, dest_im_height=0; - unsigned int gc_mask = 0; - Tk_FontMetrics fm; - unsigned int font_height; - int num_lines, i; - TextLineInfo lines, lines_ptr; - ZnTextInfo *ti = &wi->text_info; - unsigned int underline_thickness, underline_pos=0, overstrike_pos=0; - int sel_first_line=-1, sel_last_line=-1, cursor_line=-1; - unsigned int sel_start_offset=0, sel_stop_offset=0, cursor_offset=0; - - if (!text->text_info/* || !text->text*/) { - return; - } - - lines = (TextLineInfo) ZnListArray(text->text_info); - num_lines = ZnListSize(text->text_info); - Tk_GetFontMetrics(text->font, &fm); - font_height = fm.ascent+fm.descent; - - transfo = ComputeTransfoAndOrigin(item, &origin); - - /* - * Compute the selection and the cursor geometry. - */ - ComputeCursor(item, &cursor_line, &cursor_offset); - ComputeSelection(item, &sel_first_line, &sel_last_line, - &sel_start_offset, &sel_stop_offset); - - - ZnTransformPoint(transfo, &origin, &pos); - - /*printf("sel 1st : %d offset : %d, sel last : %d offset : %d\n", - sel_first_line, sel_start_offset, sel_last_line, sel_stop_offset);*/ - /* - * Setup the gc for the selection and fill the selection. - */ - if ((ti->sel_item == item) && (sel_first_line >= 0)) { - XPoint xp[4]; - - values.foreground = ZnGetGradientPixel(ti->sel_color, 0.0); - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCForeground, &values); - - if (sel_first_line == sel_last_line) { - box[0].x = origin.x + - lines[sel_first_line].origin_x + sel_start_offset; - box[0].y = origin.y + - lines[sel_first_line].origin_y - fm.ascent; - box[2].x = box[0].x + sel_stop_offset - sel_start_offset; - box[2].y = box[0].y + font_height; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - for (i = 0; i < 4; i++) { - xp[i].x = (short) box[i].x; - xp[i].y = (short) box[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, 4, Convex, CoordModeOrigin); - } - else { - box[0].x = origin.x + - lines[sel_first_line].origin_x + sel_start_offset; - box[0].y = origin.y + - lines[sel_first_line].origin_y - fm.ascent; - box[2].x = box[0].x + - text->max_width-lines[sel_first_line].origin_x-sel_start_offset; - box[2].y = box[0].y + font_height; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - for (i = 0; i < 4; i++) { - xp[i].x = (short) box[i].x; - xp[i].y = (short) box[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, 4, Convex, CoordModeOrigin); - for (i = sel_first_line+1, lines_ptr = &lines[sel_first_line+1]; - i < sel_last_line; i++, lines_ptr++) { - box[0].x = origin.x; - box[0].y = origin.y + lines_ptr->origin_y - fm.ascent; - box[2].x = box[0].x + text->max_width; - box[2].y = box[0].y + font_height; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - for (i = 0; i < 4; i++) { - xp[i].x = (short) box[i].x; - xp[i].y = (short) box[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, 4, Convex, CoordModeOrigin); - } - box[0].x = origin.x; - box[0].y = origin.y + lines[sel_last_line].origin_y - fm.ascent; - box[2].x = box[0].x + lines[sel_last_line].origin_x + sel_stop_offset; - box[2].y = box[0].y + font_height; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - for (i = 0; i < 4; i++) { - xp[i].x = (short) box[i].x; - xp[i].y = (short) box[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, 4, Convex, CoordModeOrigin); - } - } - - /*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->focus_item == item) && ti->cursor_on) { - values.fill_style = FillSolid; - values.line_width = ti->insert_width; - values.foreground = ZnGetGradientPixel(ti->insert_color, 0.0); - XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle|GCLineWidth, &values); - - box[0].x = origin.x + lines[cursor_line].origin_x + cursor_offset; - box[0].y = origin.y + lines[cursor_line].origin_y - fm.ascent + 1; - box[1].x = box[0].x; - box[1].y = box[0].y + font_height - 1; - ZnTransformPoints(transfo, box, box, 2); - XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, - (int) box[0].x, (int) box[0].y, (int) box[1].x, (int) box[1].y); - } - - - /* - * If the current transform is a pure translation, it is - * possible to optimize by directly drawing to the X back - * buffer. Else, we draw in a temporary buffer, get - * its content as an image, transform the image into another - * one and use this last image as a mask to draw in the X - * back buffer. - */ - if (ZnTransfoIsTranslation(transfo)) { - drw = wi->draw_buffer; - - gc = wi->gc; - values.foreground = ZnGetGradientPixel(text->color, 0.0); - } - else { - dest_im_width = (unsigned int) (item->item_bounding_box.corner.x - - item->item_bounding_box.orig.x); - dest_im_height = (unsigned int) (item->item_bounding_box.corner.y - - item->item_bounding_box.orig.y); - - drw = Tk_GetPixmap(wi->dpy, wi->draw_buffer, - MAX(dest_im_width, text->max_width), - MAX(dest_im_height, text->height), 1); - gc = XCreateGC(wi->dpy, drw, 0, NULL); - XSetForeground(wi->dpy, gc, 0); - XFillRectangle(wi->dpy, drw, gc, 0, 0, - MAX(dest_im_width, text->max_width), - MAX(dest_im_height, text->height)); - dest_im = XCreateImage(wi->dpy, Tk_Visual(wi->win), 1, - XYPixmap, 0, NULL, dest_im_width, dest_im_height, - 8, 0); - dest_im->data = ZnMalloc(dest_im->bytes_per_line * dest_im->height); - memset(dest_im->data, 0, dest_im->bytes_per_line * dest_im->height); - - values.foreground = 1; - - pos.x = 0; - pos.y = 0; - } - - /* - * Setup the gc to render the text and draw it. - */ - values.font = Tk_FontId(text->font); - gc_mask = GCFont | GCForeground; - if (text->fill_pattern != ZnUnspecifiedImage) { - values.fill_style = FillStippled; - values.stipple = ZnImagePixmap(text->fill_pattern, wi->win); - gc_mask |= GCFillStyle | GCStipple; - } - else { - values.fill_style = FillSolid; - gc_mask |= GCFillStyle; - } - if (ISSET(text->flags, UNDERLINED) || ISSET(text->flags, OVERSTRIKED)) { - /* - * 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; - values.line_style = LineSolid; - values.line_width = underline_thickness; - gc_mask |= GCLineStyle | GCLineWidth; - } - XChangeGC(wi->dpy, gc, gc_mask, &values); - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - int tmp_x, tmp_y; - - tmp_x = (int)(pos.x + lines_ptr->origin_x); - tmp_y = (int)(pos.y + lines_ptr->origin_y); - Tk_DrawChars(wi->dpy, drw, gc, - text->font, (char *) lines_ptr->start, - (int) lines_ptr->num_bytes, tmp_x, tmp_y); - if (ISSET(text->flags, UNDERLINED)) { - int y_under = tmp_y + underline_pos; - - XDrawLine(wi->dpy, drw, gc, - tmp_x, y_under, tmp_x + (int) lines_ptr->width, y_under); - } - if (ISSET(text->flags, OVERSTRIKED)) { - int y_over = tmp_y-overstrike_pos; - - XDrawLine(wi->dpy, drw, gc, - tmp_x, y_over, tmp_x + (int) lines_ptr->width, y_over); - } - } - - if (dest_im != NULL) { - src_im = XGetImage(wi->dpy, drw, 0, 0, text->max_width, text->height, - 1, XYPixmap); - - box[0].x = origin.x; - box[0].y = origin.y; - box[3].x = box[0].x + text->max_width; - box[3].y = box[0].y + text->height; - box[1].x = box[0].x; - box[1].y = box[3].y; - box[2].x = box[3].x; - box[2].y = box[0].y; - ZnTransformPoints(transfo, box, box, 4); - for (i = 0; i < 4; i++) { - box[i].x -= item->item_bounding_box.orig.x; - box[i].y -= item->item_bounding_box.orig.y; - box[i].x = ZnNearestInt(box[i].x); - box[i].y = ZnNearestInt(box[i].y); - } - - ZnMapImage(src_im, dest_im, box); - - TkPutImage(NULL, 0,wi->dpy, drw, gc, dest_im, - 0, 0, 0, 0, dest_im_width, dest_im_height); - - values.foreground = ZnGetGradientPixel(text->color, 0.0); - values.stipple = drw; - values.ts_x_origin = (int) item->item_bounding_box.orig.x; - values.ts_y_origin = (int) item->item_bounding_box.orig.y; - values.fill_style = FillStippled; - XChangeGC(wi->dpy, wi->gc, - GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin|GCForeground, - &values); - XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, - (int) item->item_bounding_box.orig.x, - (int) item->item_bounding_box.orig.y, - dest_im_width, dest_im_height); - - XFreeGC(wi->dpy, gc); - Tk_FreePixmap(wi->dpy, drw); - XDestroyImage(src_im); - XDestroyImage(dest_im); - } -} - - -/* -********************************************************************************** - * - * Render -- - * - ********************************************************************************** - */ -#ifdef GL -static void -Render(ZnItem item) -{ - ZnWInfo *wi = item->wi; - TextItem text = (TextItem) item; - TextLineInfo lines, lines_ptr; - ZnTextInfo *ti = &wi->text_info; - ZnPoint o, c, origin; - ZnTransfo *transfo; - GLdouble m[16]; - int i, num_lines; - XColor *color; - unsigned short 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; - } - -#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); - 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; - - transfo = ComputeTransfoAndOrigin(item, &origin); - - /* - * Compute the selection and the cursor geometry. - */ - ComputeCursor(item, &cursor_line, &cursor_offset); - ComputeSelection(item, &sel_first_line, &sel_last_line, - &sel_start_offset, &sel_stop_offset); - - ZnGLMakeCurrent(wi->dpy, wi); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glPushMatrix(); - memset(m, 0, sizeof(m)); - m[0] = m[5] = m[15] = 1.0; - if (transfo) { - m[0] = transfo->_[0][0]; m[1] = transfo->_[0][1]; - m[4] = transfo->_[1][0]; m[5] = transfo->_[1][1]; - m[12] = ZnNearestInt(transfo->_[2][0]); - m[13] = ZnNearestInt(transfo->_[2][1]); - } - glLoadMatrixd(m); - glTranslated(origin.x, origin.y, 0.0); - glPushMatrix(); - - /* - * Render the selection. - */ - if ((ti->sel_item == item) && (sel_first_line >= 0)) { - color = ZnGetGradientColor(ti->sel_color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - o.x = lines[sel_first_line].origin_x + sel_start_offset; - o.y = lines[sel_first_line].origin_y - fm.ascent; - glBegin(GL_QUADS); - if (sel_first_line == sel_last_line) { - c.x = o.x + sel_stop_offset - sel_start_offset; - c.y = o.y + font_height; - glVertex2d(o.x, o.y); - glVertex2d(o.x, c.y); - glVertex2d(c.x, c.y); - glVertex2d(c.x, o.y); - } - else { - c.x = o.x + (text->max_width - - lines[sel_first_line].origin_x - sel_start_offset); - c.y = o.y + font_height; - glVertex2d(o.x, o.y); - glVertex2d(o.x, c.y); - glVertex2d(c.x, c.y); - glVertex2d(c.x, o.y); - for (i = sel_first_line+1, lines_ptr = &lines[sel_first_line+1]; - i < sel_last_line; i++, lines_ptr++) { - o.x = 0; - o.y = lines_ptr->origin_y - fm.ascent; - c.x = o.x + text->max_width; - c.y = o.y + font_height; - glVertex2d(o.x, o.y); - glVertex2d(o.x, c.y); - glVertex2d(c.x, c.y); - glVertex2d(c.x, o.y); - } - o.x = 0; - o.y = lines[sel_last_line].origin_y - fm.ascent; - c.x = o.x + lines[sel_last_line].origin_x + sel_stop_offset; - c.y = o.y + font_height; - glVertex2d(o.x, o.y); - glVertex2d(o.x, c.y); - glVertex2d(c.x, c.y); - glVertex2d(c.x, o.y); - } - glEnd(); - } - - /* - * Render the cursor. - */ - if ((cursor_line >= 0) && - (wi->focus_item == item) && ti->cursor_on) { - color = ZnGetGradientColor(ti->insert_color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - glLineWidth((GLfloat) ti->insert_width); - - o.x = lines[cursor_line].origin_x + cursor_offset; - o.y = lines[cursor_line].origin_y - fm.ascent + 1; - c.x = o.x; - c.y = o.y + font_height - 1; - - glBegin(GL_LINES); - glVertex2d(o.x, o.y); - glVertex2d(c.x, c.y); - glEnd(); - } - - /* - * Render the text. - */ - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBindTexture(GL_TEXTURE_2D, ZnTexFontTex(text->tfi)); - color = ZnGetGradientColor(text->color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - glTranslated(lines_ptr->origin_x, lines_ptr->origin_y, 0.0); - - if (ISSET(text->flags, UNDERLINED) || ISSET(text->flags, OVERSTRIKED)) { - glLineWidth((GLfloat) underline_thickness); - glDisable(GL_TEXTURE_2D); - if (ISSET(text->flags, UNDERLINED)) { - glBegin(GL_LINES); - glVertex2d(0, underline_pos); - glVertex2d(lines_ptr->width, underline_pos); - glEnd(); - } - if (ISSET(text->flags, OVERSTRIKED)) { - glBegin(GL_LINES); - glVertex2d(0, -overstrike_pos); - glVertex2d(lines_ptr->width, -overstrike_pos); - glEnd(); - } - glEnable(GL_TEXTURE_2D); - } - - ZnRenderString(text->tfi, lines_ptr->start, lines_ptr->num_bytes); - glPopMatrix(); - glPushMatrix(); - } - - glPopMatrix(); - glPopMatrix(); - - glDisable(GL_TEXTURE_2D); -#ifdef GL_LIST - glEndList(); - } - - glCallList(item->gl_list); -#endif -} -#else -static void -Render(ZnItem item) -{ -} -#endif - - -/* - ********************************************************************************** - * - * IsSensitive -- - * - ********************************************************************************** - */ -static ZnBool -IsSensitive(ZnItem item, - int item_part) -{ - return (ISSET(item->flags, ZN_SENSITIVE_BIT) && - item->parent->class->IsSensitive(item->parent, ZN_NO_PART)); -} - - -/* - ********************************************************************************** - * - * Pick -- - * - ********************************************************************************** - */ -static double -Pick(ZnItem item, - ZnPick ps) -{ - TextItem text = (TextItem) item; - double dist = 1.0e40, new_dist; - int num_lines, i; - TextLineInfo lines, lines_ptr; - Tk_FontMetrics fm; - int font_height; - ZnPoint box[4], origin, *p = ps->point; - ZnTransfo *transfo; - - if (!text->text_info || !text->text) { - return dist; - } - - transfo = ComputeTransfoAndOrigin(item, &origin); - - lines = ZnListArray(text->text_info); - num_lines = ZnListSize(text->text_info); - Tk_GetFontMetrics(text->font, &fm); - font_height = fm.descent + fm.ascent; - if (text->spacing > 0) { - font_height += text->spacing; - } - - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - box[0].x = origin.x + lines_ptr->origin_x; - box[0].y = origin.y + lines_ptr->origin_y - fm.ascent; - box[2].x = box[0].x + lines_ptr->width; - box[2].y = box[0].y + font_height; - box[1].x = box[2].x; - box[1].y = box[0].y; - box[3].x = box[0].x; - box[3].y = box[2].y; - ZnTransformPoints(transfo, box, box, 4); - new_dist = ZnPolygonToPointDist(box, 4, p); - dist = MIN(dist, new_dist); - if (dist <= 0.0) { - dist = 0.0; - break; - } - } - - return dist; -} - - -/* - ********************************************************************************** - * - * PostScript -- - * - ********************************************************************************** - */ -static int -PostScript(ZnItem item, - ZnBool prepass, - ZnBBox *area) -{ - ZnWInfo *wi = item->wi; - TextItem text = (TextItem) item; - Tk_FontMetrics fm; - TextLineInfo lines, lines_ptr; - ZnPoint origin; - ZnReal alignment; - int i, num_lines; - char path[150]; - - lines = (TextLineInfo) ZnListArray(text->text_info); - num_lines = ZnListSize(text->text_info); - - if (Tk_PostscriptFont(wi->interp, wi->ps_info, text->font) != TCL_OK) { - return TCL_ERROR; - } - if (Tk_PostscriptColor(wi->interp, wi->ps_info, - ZnGetGradientColor(text->color, 0.0, NULL)) != TCL_OK) { - return TCL_ERROR; - } - if (text->fill_pattern != ZnUnspecifiedImage) { - Tcl_AppendResult(wi->interp, "/StippleText {\n ", NULL); - Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, - ZnImagePixmap(text->fill_pattern, wi->win)); - Tcl_AppendResult(wi->interp, "} bind def\n", NULL); - } - - ComputeTransfoAndOrigin(item, &origin); - - sprintf(path, "/InitialTransform load setmatrix\n" - "[%.15g %.15g %.15g %.15g %.15g %.15g] concat\n" - "1 -1 scale\n", - wi->current_transfo->_[0][0], wi->current_transfo->_[0][1], - wi->current_transfo->_[1][0], wi->current_transfo->_[1][1], - wi->current_transfo->_[2][0], wi->current_transfo->_[2][1]); - Tcl_AppendResult(wi->interp, path, NULL); - - sprintf(path, "%.15g %.15g [\n", origin.x, origin.y); - Tcl_AppendResult(wi->interp, path, NULL); - - /* - * Emit code to draw the lines. - */ - for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { - ZnPostscriptString(wi->interp, lines_ptr->start, lines_ptr->num_bytes); - } - - switch (text->alignment) { - default: - case TK_JUSTIFY_LEFT: - alignment = 0; - break; - case TK_JUSTIFY_CENTER: - alignment = 0.5; - break; - case TK_JUSTIFY_RIGHT: - alignment = 1; - break; - } - Tk_GetFontMetrics(text->font, &fm); - /* DrawText should not mess with anchors, they are already accounted for */ - sprintf(path, "] %d %g %g %g %s DrawText\n", fm.linespace, 0.0, 0.0, - alignment, (text->fill_pattern == ZnUnspecifiedImage) ? "false" : "true"); - Tcl_AppendResult(wi->interp, path, NULL); - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * GetAnchor -- - * - ********************************************************************************** - */ -static void -GetAnchor(ZnItem item, - Tk_Anchor anchor, - ZnPoint *p) -{ - TextItem text = (TextItem) item; - - if (text->num_chars != 0) { - ZnRectOrigin2Anchor(text->poly, anchor, p); - } - else { - *p = *text->poly; - } -} - - -/* - ********************************************************************************** - * - * GetClipVertices -- - * Get the clipping shape. - * Never ever call ZnTriFree on the tristrip returned by GetClipVertices. - * - ********************************************************************************** - */ -static ZnBool -GetClipVertices(ZnItem item, - ZnTriStrip *tristrip) -{ - TextItem text = (TextItem) item; - - ZnTriStrip1(tristrip, text->poly, 4, False); - - return False; -} - - -/* - ********************************************************************************** - * - * Coords -- - * Return or edit the item origin. This doesn't take care of - * the possible attachment. The change will be effective at the - * end of the attachment. - * - ********************************************************************************** - */ -static int -Coords(ZnItem item, - int contour, - int index, - int cmd, - ZnPoint **pts, - char **controls, - unsigned int *num_pts) -{ - TextItem text = (TextItem) item; - - if ((cmd == ZN_COORDS_ADD) || (cmd == ZN_COORDS_ADD_LAST) || (cmd == ZN_COORDS_REMOVE)) { - Tcl_AppendResult(item->wi->interp, - " texts can't add or remove vertices", NULL); - return TCL_ERROR; - } - else if ((cmd == ZN_COORDS_REPLACE) || (cmd == ZN_COORDS_REPLACE_ALL)) { - if (*num_pts == 0) { - Tcl_AppendResult(item->wi->interp, - " coords command need 1 point on texts", NULL); - return TCL_ERROR; - } - text->pos = (*pts)[0]; - ZnITEM.Invalidate(item, ZN_COORDS_FLAG); - } - else if ((cmd == ZN_COORDS_READ) || (cmd == ZN_COORDS_READ_ALL)) { - *num_pts = 1; - *pts = &text->pos; - } - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * Index -- - * Parse a text index and return its value and a - * error status (standard Tcl result). - * - ********************************************************************************** - */ -static int -PointToChar(TextItem text, - int x, - int y) -{ - int i, n, num_lines, dummy, byte_index; - ZnPoint p; - TextLineInfo ti; - Tk_FontMetrics fm; - ZnReal a, b; - - byte_index = 0; - if (!text->text_info) { - return 0; - } - - p.x = x; - p.y = y; - a = ZnLineToPointDist(&text->poly[0], &text->poly[2], &p, NULL); - b = ZnLineToPointDist(&text->poly[0], &text->poly[1], &p, NULL); - p.x = (text->max_width * b / - hypot(text->poly[2].x - text->poly[0].x, text->poly[2].y - text->poly[0].y)); - p.y = (text->height * a / - hypot(text->poly[1].x - text->poly[0].x, text->poly[1].y - text->poly[0].y)); - p.x = ZnNearestInt(p.x); - p.y = ZnNearestInt(p.y); - - /* - * Point above text, returns index 0. - */ - if (p.y < 0) { - return 0; - } - - /* - * Find the text line under point. - */ - num_lines = ZnListSize(text->text_info); - ti = ZnListArray(text->text_info); - Tk_GetFontMetrics(text->font, &fm); - for (i = 0; i < num_lines; i++, ti++) { - if (p.y < ti->origin_y + fm.descent) { - if (p.x < ti->origin_x) { - /* - * Point to the left of the current line, returns - * index of first char. - */ - byte_index = ti->start - text->text; - break; - } - if (p.x >= (ti->origin_x + ti->width)) { - /* - * Point to the right of the current line, returns - * index past the last char. - */ - byte_index = ti->start + ti->num_bytes - text->text; - break; - } - n = Tk_MeasureChars(text->font, ti->start, (int) ti->num_bytes, - (int) (p.x + 2 - ti->origin_x), TK_PARTIAL_OK, - &dummy); -#ifdef PTK_800 - byte_index = (ti->start + n - 1) - text->text; -#else - byte_index = Tcl_UtfPrev(ti->start + n, ti->start) - text->text; -#endif - break; - } - } - if (i == num_lines) { - /* - * Point below all lines, return the index after - * the last char in text. - */ - ti--; - byte_index = ti->start + ti->num_bytes - text->text; - } - - return Tcl_NumUtfChars(text->text, byte_index); -} - -/* - * Return a new index from a current index and a - * move command. - * - * 0 end of index line - * 1 beginning of index line - * 2 next word or end of word from index - * 3 previous word or beginning of word from index - * 4 previous line from index line - * 5 next line from index line - * - */ -static int -MoveFromIndex(TextItem text, - unsigned int char_index, - int move) -{ - unsigned int num_lines, byte_index, num_bytes=0; - unsigned int line_index, line_start=0; - TextLineInfo lines, p; - char *strp; - - if (!text->text_info || !text->text) { - return char_index; - } - byte_index = Tcl_UtfAtIndex(text->text, (int) 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_bytes = p->num_bytes; - if (line_start + num_bytes >= byte_index) { - break; - } - } - if (line_index == num_lines) { - line_index--; - p--; - } - - switch (move) { - case 0: - byte_index = line_start + num_bytes; - goto convert_it; - case 1: - byte_index = line_start; - goto convert_it; - case 2: - strp = &text->text[byte_index]; - while ((strp[1] == ' ') || (strp[1] == '\n')) { - strp++; - } - while ((strp[1] != ' ') && (strp[1] != '\n') && strp[1]) { - strp++; - } - byte_index = strp + 1 - text->text; - goto convert_it; - case 3: - strp = &text->text[byte_index]; - while ((strp != text->text) && ((strp[-1] == ' ') || (strp[-1] == '\n'))) { - strp--; - } - while ((strp != text->text) && (strp[-1] != ' ') && (strp[-1] != '\n')) { - strp--; - } - byte_index = strp - text->text; - goto convert_it; - case 4: - if (line_index > 0) { - byte_index -= line_start; - p = &lines[line_index-1]; - byte_index = MIN(byte_index, p->num_bytes); - line_start = p->start - text->text; - byte_index += line_start; - } - goto convert_it; - case 5: - if (line_index < num_lines-1) { - byte_index -= line_start; - p = &lines[line_index+1]; - byte_index = MIN(byte_index, p->num_bytes); - line_start = p->start - text->text; - byte_index += line_start; - } - convert_it: - char_index = Tcl_NumUtfChars(text->text, (int) byte_index); - default: - return char_index; - } -} - -static int -Index(ZnItem item, - int field, - Tcl_Obj *index_spec, - int *index) -{ - TextItem text = (TextItem) item; - ZnWInfo *wi = item->wi; - ZnTextInfo *ti = &wi->text_info; - unsigned int length; - int c, x, y; - double tmp; - char *end, *p; - - p = Tcl_GetString(index_spec); - c = p[0]; - length = strlen(p); - - if ((c == 'e') && (length > 1) && (strncmp(p, "end", length) == 0)) { - *index = text->num_chars; - } - else if ((c == 'e') && (length > 1) && (strncmp(p, "eol", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 0); - } - else if ((c == 'b') && (length > 1) && (strncmp(p, "bol", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 1); - } - else if ((c == 'e') && (length > 1) && (strncmp(p, "eow", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 2); - } - else if ((c == 'b') && (length > 1) && (strncmp(p, "bow", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 3); - } - else if ((c == 'u') && (strncmp(p, "up", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 4); - } - else if ((c == 'd') && (strncmp(p, "down", length) == 0)) { - *index = MoveFromIndex(text, text->insert_index, 5); - } - else if ((c == 'i') && (strncmp(p, "insert", length) == 0)) { - *index = text->insert_index; - } - else if ((c == 's') && (strncmp(p, "sel.first", length) == 0) && - (length >= 5)) { - if (ti->sel_item != item) { - Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); - return TCL_ERROR; - } - *index = ti->sel_first; - } - else if ((c == 's') && (strncmp(p, "sel.last", length) == 0) && - (length >= 5)) { - if (ti->sel_item != item) { - Tcl_AppendResult(wi->interp, "selection isn't in item", (char *) NULL); - return TCL_ERROR; - } - /* - * We return a modified selection end so that it reflect - * the text index of the last character _not_ the insertion - * point between the last and the next. - */ - *index = ti->sel_last-1; - } - else if (c == '@') { - p++; - tmp = strtod(p, &end); - if ((end == p) || (*end != ',')) { - goto badIndex; - } - /*x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);*/ - x = (int) 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 = (int) tmp; - - *index = PointToChar(text, x, y); - } - else if (Tcl_GetIntFromObj(wi->interp, index_spec, index) == TCL_OK) { - if (*index < 0){ - *index = 0; - } - else if ((unsigned int) *index > text->num_chars) { - *index = text->num_chars; - } - } - else { - badIndex: - Tcl_AppendResult(wi->interp, "bad index \"", p, "\"", (char *) NULL); - return TCL_ERROR; - } - - return TCL_OK; -} - - -/* - ********************************************************************************** - * - * InsertChars -- - * - ********************************************************************************** - */ -static void -InsertChars(ZnItem item, - int field, - int *index, - char *chars) -{ - TextItem text = (TextItem) item; - ZnTextInfo *ti = &item->wi->text_info; - unsigned int num_chars, byte_index, num_bytes = strlen(chars); - char *new; - - if (num_bytes == 0) { - return; - } - if (*index < 0) { - *index = 0; - } - if ((unsigned int) *index > text->num_chars) { - *index = text->num_chars; - } - num_chars = Tcl_NumUtfChars(chars, (int) num_bytes); - - if (text->text) { - byte_index = Tcl_UtfAtIndex(text->text, *index)-text->text; - 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); - } - else { - byte_index = 0; - new = ZnMalloc(num_bytes + 1); - new[num_bytes] = 0; - } - memcpy(new + byte_index, chars, num_bytes); - text->text = new; - text->num_chars += num_chars; - - if (text->insert_index >= (unsigned int) *index) { - 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; - } - } - - ZnITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); -} - - -/* - ********************************************************************************** - * - * DeleteChars -- - * - ********************************************************************************** - */ -static void -DeleteChars(ZnItem item, - int field, - int *first, - int *last) -{ - TextItem text = (TextItem) item; - int byte_count, first_offset; - int char_count, num_bytes; - ZnTextInfo *ti = &item->wi->text_info; - char *new; - - if (!text->text) { - return; - } - if (*first < 0) { - *first = 0; - } - if (*last >= (int) text->num_chars) { - *last = text->num_chars-1; - } - if (*first > *last) { - return; - } - 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 (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 -= char_count; - } - else { - ZnFree(text->text); - text->text = NULL; - text->num_chars = 0; - } - - if (text->insert_index > (unsigned int) *first) { - text->insert_index -= char_count; - if (text->insert_index < (unsigned int) *first) { - text->insert_index = *first; - } - else if (*first == 0) { - text->insert_index = 0; - } - } - 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; - } - } - } - - ZnITEM.Invalidate(item, ZN_COORDS_FLAG|ZN_LAYOUT_FLAG); -} - - -/* - ********************************************************************************** - * - * Cursor -- - * - ********************************************************************************** - */ -static void -TextCursor(ZnItem item, - int field, - int index) -{ - TextItem text = (TextItem) item; - - if (index < 0) { - text->insert_index = 0; - } - else if ((unsigned int) index > text->num_chars) { - text->insert_index = text->num_chars; - } - else { - text->insert_index = index; - } -} - - -/* - ********************************************************************************** - * - * Selection -- - * - ********************************************************************************** - */ -static int -Selection(ZnItem item, - int field, - int offset, - char *chars, - int max_bytes) -{ - TextItem text = (TextItem) item; - ZnWInfo *wi = item->wi; - ZnTextInfo *ti = &wi->text_info; - int count; - char const *sel_first, *sel_last; - - if (!text->text) { - return 0; - } - 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; - } - if (count > max_bytes) { - count = max_bytes; - } - memcpy(chars, sel_first + offset, (size_t) count); - chars[count] = 0; - - return count; -} - - -/* - ********************************************************************************** - * - * Exported functions struct - * - ********************************************************************************** - */ -static ZnItemClassStruct TEXT_ITEM_CLASS = { - "text", - sizeof(TextItemStruct), - text_attrs, - 0, /* num_parts */ - ZN_CLASS_HAS_ANCHORS|ZN_CLASS_ONE_COORD, /* flags */ - Tk_Offset(TextItemStruct, pos), - Init, - Clone, - Destroy, - Configure, - Query, - NULL, /* GetFieldSet */ - GetAnchor, - GetClipVertices, - NULL, /* GetContours */ - Coords, - InsertChars, - DeleteChars, - TextCursor, - Index, - NULL, /* Part */ - Selection, - NULL, /* Contour */ - ComputeCoordinates, - ToArea, - Draw, - Render, - IsSensitive, - Pick, - NULL, /* PickVertex */ - PostScript -}; - -ZnItemClassId ZnText = (ZnItemClassId) &TEXT_ITEM_CLASS; -- cgit v1.1