aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/Text.c933
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;