diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/Text.c | 933 |
1 files changed, 933 insertions, 0 deletions
diff --git a/generic/Text.c b/generic/Text.c new file mode 100644 index 0000000..6b0b4d0 --- /dev/null +++ b/generic/Text.c @@ -0,0 +1,933 @@ +/* + * 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 <math.h> +#include <ctype.h> +#include <X11/Xatom.h> +#include <malloc.h> +#include <string.h> + +#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; |