/* * Text.c -- Implementation of Text item. * * Authors : Patrick LECOANET * Creation date : Sat Mar 25 13:58:39 1995 */ /* * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet -- * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this code; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include "Item.h" #include "Geo.h" #include "Draw.h" #include "Types.h" #include "WidgetInfo.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__ " $"; 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 */ /* ********************************************************************************** * * Specific Text item record * ********************************************************************************** */ typedef struct _TextLineInfo { char *start; /* Index of first char in line */ int num_chars; /* Number of displayed chars in line */ RadarPoint text_origin; /* X pos for drawing the line */ int width; /* Line width in pixels */ } TextLineInfoStruct, *TextLineInfo; typedef struct _TextItemStruct { ItemStruct header; /* Public data */ RadarPoint pos; RadarAnchor anchor; RadarAnchor connection_anchor; RadarColor color; RadarColor fill_color; char *text; Pixmap fill_pattern; RadarFont font; RadarJustify alignment; int width; int spacing; unsigned char flags; /* Private data */ RadarPoint pos_dev; int insert_index; int sel_start; int sel_end; RadarList text_info; int max_width; } TextItemStruct, *TextItem; static RadarAttrConfig text_attrs[] = { { RADAR_CONFIG_JUSTIFY, "-alignment", NULL, Tk_Offset(TextItemStruct, alignment), 0, RADAR_COORDS_FLAG|RADAR_LAYOUT_FLAG, False }, { RADAR_CONFIG_ANCHOR, "-anchor", NULL, Tk_Offset(TextItemStruct, anchor), 0, RADAR_COORDS_FLAG, False }, { RADAR_CONFIG_COLOR, "-color", NULL, Tk_Offset(TextItemStruct, color), 0, RADAR_DRAW_FLAG, False }, { RADAR_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(TextItemStruct, header.flags), COMPOSE_ROTATION_BIT, RADAR_COORDS_FLAG, False }, { RADAR_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(TextItemStruct, header.flags), COMPOSE_SCALE_BIT, RADAR_COORDS_FLAG, False }, { RADAR_CONFIG_ITEM, "-connecteditem", NULL, Tk_Offset(TextItemStruct, header.connected_item), 0, RADAR_COORDS_FLAG|RADAR_ITEM_FLAG, False }, { RADAR_CONFIG_ANCHOR, "-connectionanchor", NULL, Tk_Offset(TextItemStruct, connection_anchor), 0, RADAR_COORDS_FLAG, False }, { RADAR_CONFIG_COLOR, "-fillcolor", NULL, Tk_Offset(TextItemStruct, fill_color), 0, RADAR_DRAW_FLAG, False }, { RADAR_CONFIG_PATTERN, "-fillpattern", NULL, Tk_Offset(TextItemStruct, fill_pattern), 0, RADAR_DRAW_FLAG, False }, { RADAR_CONFIG_FONT, "-font", NULL, Tk_Offset(TextItemStruct, font), 0, RADAR_COORDS_FLAG|RADAR_LAYOUT_FLAG, False }, { RADAR_CONFIG_BOOL, "-overstriked", NULL, Tk_Offset(TextItemStruct, flags), OVERSTRIKED, RADAR_DRAW_FLAG, False }, { RADAR_CONFIG_POINT, "-position", NULL, Tk_Offset(TextItemStruct, pos), 0, RADAR_COORDS_FLAG, False}, { RADAR_CONFIG_PRI, "-priority", NULL, Tk_Offset(TextItemStruct, header.priority), 0, RADAR_DRAW_FLAG|RADAR_REPICK_FLAG, False }, { RADAR_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(TextItemStruct, header.flags), SENSITIVE_BIT, RADAR_REPICK_FLAG, False }, { RADAR_CONFIG_DIM, "-spacing", NULL, Tk_Offset(TextItemStruct, spacing), 0, RADAR_COORDS_FLAG|RADAR_LAYOUT_FLAG, False }, { RADAR_CONFIG_TAGS, "-tags", NULL, Tk_Offset(TextItemStruct, header.tags), 0, 0, False }, { RADAR_CONFIG_TEXT, "-text", NULL, Tk_Offset(TextItemStruct, text), 0, RADAR_COORDS_FLAG|RADAR_LAYOUT_FLAG, False }, { RADAR_CONFIG_BOOL, "-underlined", NULL, Tk_Offset(TextItemStruct, flags), UNDERLINED, RADAR_DRAW_FLAG, False }, { RADAR_CONFIG_BOOL, "-visible", NULL, Tk_Offset(TextItemStruct, header.flags), VISIBLE_BIT, RADAR_DRAW_FLAG|RADAR_REPICK_FLAG|RADAR_VIS_FLAG, False }, { RADAR_CONFIG_INT, "-width", NULL, Tk_Offset(TextItemStruct, width), 0, RADAR_COORDS_FLAG|RADAR_LAYOUT_FLAG, False }, { RADAR_CONFIG_END, NULL, NULL, 0, 0, 0 } }; /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(Item item, int *argc, Arg **args) { WidgetInfo *wi = item->wi; TextItem text = (TextItem) item; text->text_info = NULL; /* Init attributes */ SET(item->flags, VISIBLE_BIT); SET(item->flags, SENSITIVE_BIT); SET(item->flags, COMPOSE_ROTATION_BIT); SET(item->flags, COMPOSE_SCALE_BIT); item->priority = DEFAULT_TEXT_PRIORITY; text->pos.x = text->pos.y = 0.0; text->text = ""; text->fill_pattern = RadarUnspecifiedPattern; text->anchor = RadarAnchorNW; text->connection_anchor = RadarAnchorSW; text->color = RadarGetColorByValue(wi->win, wi->fore_color); text->fill_color = RadarGetColorByValue(wi->win, wi->back_color); text->alignment = RadarJustifyLeft; text->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font)); text->width = 0; 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 RADAR_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(Item item) { TextItem text = (TextItem) item; WidgetInfo *wi = item->wi; char *str; if (strlen(text->text) != 0) { str = RadarMalloc((strlen(text->text) + 1) * sizeof(char)); strcpy(str, text->text); text->text = str; } if (text->fill_pattern != RadarUnspecifiedPattern) { text->fill_pattern = Tk_GetBitmap(wi->interp, wi->win, Tk_NameOfBitmap(wi->dpy, text->fill_pattern)); } text->color = RadarGetColorByValue(wi->win, text->color); text->fill_color = RadarGetColorByValue(wi->win, text->fill_color); text->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(text->font)); if (text->text_info) { text->text_info = RadarListDuplicate(text->text_info); } else { /* * Needed in case the layout of the model has not been * done yet. */ SET(item->inv_flags, RADAR_LAYOUT_FLAG); } } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(Item item) { WidgetInfo *wi = item->wi; TextItem text = (TextItem) item; if (strlen(text->text) != 0) { RadarFree(text->text); } if (text->fill_pattern != RadarUnspecifiedPattern) { Tk_FreeBitmap(wi->dpy, text->fill_pattern); text->fill_pattern = RadarUnspecifiedPattern; } RadarFreeColor(text->color); RadarFreeColor(text->fill_color); Tk_FreeFont(text->font); if (text->text_info) { RadarListFree(text->text_info); } } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(Item item, int argc, RadarAttrList argv, int *flags) { Item old_connected; old_connected = item->connected_item; if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == RADAR_ERROR) { return RADAR_ERROR; } if (ISSET(*flags, RADAR_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up * to the old one. */ if ((item->connected_item == RADAR_NO_ITEM) || (item->connected_item->class->has_anchors && (item->parent == item->connected_item->parent))) { ITEM.UpdateItemDependency(item, old_connected); } else { item->connected_item = old_connected; } } return RADAR_OK; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(Item item, int argc, RadarAttrList argv) { if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == RADAR_ERROR) { return RADAR_ERROR; } return RADAR_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(Item item, RadarBool force) { WidgetInfo *wi = item->wi; TextItem text = (TextItem) item; TextLineInfo infos; Tk_FontMetrics fm; int i, num_lines; int cur_dy; int font_height, height; ResetBBox(&item->item_bounding_box); if (strlen(text->text) == 0) { return; } 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, RADAR_LAYOUT_FLAG)) { char *scan; int wrap, line_index, prev_num_lines; /*printf("layout\n");*/ text->max_width = 0; if (text->text_info != NULL) { prev_num_lines = RadarListSize(text->text_info); RadarListEmpty(text->text_info); } else { prev_num_lines = 0; text->text_info = RadarListNew(1, sizeof(TextLineInfoStruct)); } if (text->width > 0) { wrap = text->width; } else { wrap = 100000; } scan = text->text; while (*scan) { TextLineInfoStruct info; char *ptr; int num; line_index = scan - text->text; /* * Limit the excursion of Tk_MeasureChars to the end * of the line. Do not include \n in the measure done. */ ptr = strchr(scan, '\n'); if (ptr) { num = ptr-scan; } else { num = strlen(scan); } info.num_chars = Tk_MeasureChars(text->font, scan, num, wrap, TK_WHOLE_WORDS|TK_AT_LEAST_ONE, &info.width); /* * Adjust for the newline at the end of line. */ if (ptr) { info.num_chars++; } info.start = scan; text->max_width = MAX(info.width, text->max_width); scan += info.num_chars; /* Build a line 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. */ RadarListAdd(text->text_info, &info, RadarListTail); /*printf("adding a line : %s, num_chars : %d, width : %d\n", info.start, info.num_chars, info.width);*/ /* * Skip terminating space or return char if any. */ if (isspace(*scan) || *scan == '\n') { scan++; } } /* * 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 = RadarListSize(text->text_info); infos = (TextLineInfo) RadarListArray(text->text_info); for (i = 0; i < num_lines; i++) { switch (text->alignment) { case RadarJustifyLeft: infos[i].text_origin.x = 0; break; case RadarJustifyCenter: infos[i].text_origin.x = (text->max_width + 1 - infos[i].width)/2; break; case RadarJustifyRight: infos[i].text_origin.x = text->max_width + 1 - infos[i].width; break; } infos[i].text_origin.y = cur_dy; cur_dy += font_height + text->spacing; /*printf("fixing line %d x : %f, y : %f\n", i, infos[i].text_origin.x, infos[i].text_origin.y);*/ } } /* ISSET(item->inv_flags, INV_TEXT_LAYOUT) */ num_lines = RadarListSize(text->text_info); height = num_lines * font_height + (num_lines-1) * text->spacing; /* * The connected item support anchors, this is checked by * configure. */ if (item->connected_item != RADAR_NO_ITEM) { item->connected_item->class->GetAnchor(item->connected_item, text->connection_anchor, &text->pos_dev); } else { RadarTransformPoint(wi->current_transfo, &text->pos, &text->pos_dev); } Anchor2Origin(&text->pos_dev, text->max_width, height, text->anchor, &text->pos_dev); /* * Compute the bounding box. */ 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; /* * Update connected items. */ SET(item->flags, UPDATE_DEPENDENT_BIT); } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(Item item, RadarBBox *area, Tk_Uid tag_uid, int enclosed, RadarBool report) { TextItem text = (TextItem) item; int inside = -1; RadarBool first_done = False; int num_lines, i; TextLineInfo lines, lines_ptr; Tk_FontMetrics fm; int font_height; RadarBBox line_bbox; RadarPoint o; lines = (TextLineInfo) RadarListArray(text->text_info); num_lines = RadarListSize(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++) { ResetBBox(&line_bbox); o.x = text->pos_dev.x + lines_ptr->text_origin.x; o.y = text->pos_dev.y + lines_ptr->text_origin.y - fm.ascent; AddPointToBBox(&line_bbox, o.x, o.y); AddPointToBBox(&line_bbox, o.x + lines_ptr->width, o.y + font_height); if (!first_done) { first_done = True; inside = BBoxInBBox(&line_bbox, area); if (inside == 0) { return 0; } } else { if (BBoxInBBox(&line_bbox, area) == 0) { return 0; } } } return inside; } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(Item item) { WidgetInfo *wi = item->wi; TextItem text = (TextItem) item; XGCValues values; int gc_mask = 0; Tk_FontMetrics fm; int font_height; int num_lines, i, line_index, char_index; TextLineInfo lines, lines_ptr; int underline_thickness, underline_pos, overstrike_pos; int sel_first_line = -1, sel_last_line = -1, cursor_line = -1; int sel_start_offset, sel_stop_offset, cursor_offset; lines = (TextLineInfo) RadarListArray(text->text_info); num_lines = RadarListSize(text->text_info); Tk_GetFontMetrics(text->font, &fm); font_height = fm.ascent+fm.descent; /* * Compute the selection and the cursor geometry. */ 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 (ISSET(text->flags, HAS_FOCUS) && text->insert_index >= line_index && text->insert_index <= line_index + lines_ptr->num_chars) { cursor_line = i; cursor_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, text->insert_index - line_index); } /* * 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 (sel_first_line < 0) { char_index = text->sel_start - line_index; if (char_index <= 0) { sel_first_line = i; sel_start_offset = 0; //printf("sel_start_offset 1 : %d\n", sel_start_offset); } else if (char_index <= lines_ptr->num_chars) { 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); } } char_index = text->sel_end - line_index; sel_last_line = i; if (char_index == lines_ptr->num_chars+1) sel_stop_offset = lines_ptr->width; else if (char_index <= lines_ptr->num_chars) sel_stop_offset = Tk_TextWidth(text->font, (char *) lines_ptr->start, char_index); } } /*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 ((sel_first_line >= 0) && got_selection) { int x, y; values.foreground = RadarPixel(text->fill_color); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCForeground, &values); if (sel_first_line == sel_last_line) { 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, sel_stop_offset - sel_start_offset, font_height); } else { 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); 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); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, x, y, lines_ptr->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); } } /* * Setup the gc to render the text and draw it. */ values.font = RadarFontId(text->font); values.foreground = RadarPixel(text->color); gc_mask = GCFont | GCForeground; if (text->fill_pattern != RadarUnspecifiedPattern) { values.fill_style = FillStippled; values.stipple = text->fill_pattern; 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, wi->gc, gc_mask, &values); for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { int tmp_x, tmp_y; tmp_x = (int)(text->pos_dev.x + lines_ptr->text_origin.x); tmp_y = (int)(text->pos_dev.y + lines_ptr->text_origin.y); XDrawString(wi->dpy, wi->draw_buffer, wi->gc, tmp_x, tmp_y, (char *) lines_ptr->start, lines_ptr->num_chars); if (ISSET(text->flags, UNDERLINED)) { int y_under = tmp_y + underline_pos; XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, tmp_x, y_under, tmp_x+lines_ptr->width, y_under); } if (ISSET(text->flags, OVERSTRIKED)) { int y_over = tmp_y-overstrike_pos; XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, 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); } } /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static RadarBool IsSensitive(Item item, int item_part) { return (ISSET(item->flags, SENSITIVE_BIT) && item->parent->class->IsSensitive(item->parent, RADAR_NO_PART)); } /* ********************************************************************************** * * Pick -- * ********************************************************************************** */ static double Pick(Item item, RadarPoint *p, Item start_item, int aperture, Item *a_item, int *part) { TextItem text = (TextItem) item; double dist, new_dist; int num_lines, i; TextLineInfo lines, lines_ptr; Tk_FontMetrics fm; int font_height; RadarBBox line_bbox; RadarPoint o; lines = (TextLineInfo) RadarListArray(text->text_info); num_lines = RadarListSize(text->text_info); dist = 1.0e40; 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++) { ResetBBox(&line_bbox); o.x = text->pos_dev.x + lines_ptr->text_origin.x; o.y = text->pos_dev.y + lines_ptr->text_origin.y - fm.ascent; AddPointToBBox(&line_bbox, o.x, o.y); AddPointToBBox(&line_bbox, o.x + lines_ptr->width, o.y + font_height); new_dist = RectangleToPointDist(&line_bbox, p); dist = MIN(dist, new_dist); if (dist <= 0.0) { dist = 0.0; break; } } return dist; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(Item item, PostScriptInfo ps_info) { } /* ********************************************************************************** * * GetAnchor -- * ********************************************************************************** */ static void GetAnchor(Item item, RadarAnchor anchor, RadarPoint *p) { TextItem text = (TextItem) item; if (strlen(text->text) != 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, anchor, p); } else { p->x = p->y = 0.0; } } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * ********************************************************************************** */ static RadarBool GetClipVertices(Item item, RadarPoint **points, int *num_points) { RadarListAssertSize(item->wi->work_pts, 2); *points = (RadarPoint *) RadarListArray(item->wi->work_pts); *num_points = 2; (*points)[0] = item->item_bounding_box.orig; (*points)[1] = item->item_bounding_box.corner; return True; } /* ********************************************************************************** * * 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(Item item, int index, int cmd, RadarPoint **pts, int *num_pts) { TextItem text = (TextItem) item; if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST) || (cmd == COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " texts can't add or remove vertices", NULL); return RADAR_ERROR; } else if ((cmd == COORDS_REPLACE) || (cmd == COORDS_REPLACE_ALL)) { if (*num_pts == 0) { Tcl_AppendResult(item->wi->interp, " coords command need 1 point on texts", NULL); return RADAR_ERROR; } text->pos = (*pts)[0]; ITEM.Invalidate(item, RADAR_COORDS_FLAG); } else if ((cmd == COORDS_READ) || (cmd == COORDS_READ_ALL)) { *num_pts = 1; *pts = &text->pos; } return RADAR_OK; } /* ********************************************************************************** * * Exported functions struct * ********************************************************************************** */ static ItemClassStruct TEXT_ITEM_CLASS = { sizeof(TextItemStruct), False, False, True, "text", text_attrs, Init, Clone, Destroy, Configure, Query, NULL, GetAnchor, GetClipVertices, Coords, ComputeCoordinates, ToArea, Draw, IsSensitive, Pick, PostScript }; RadarItemClassId RadarText = (RadarItemClassId) &TEXT_ITEM_CLASS;