aboutsummaryrefslogtreecommitdiff
path: root/generic/Field.c
diff options
context:
space:
mode:
authorlecoanet2002-04-08 13:46:42 +0000
committerlecoanet2002-04-08 13:46:42 +0000
commit737920a9203af23d93d9c8352737b93651392776 (patch)
tree624ea9f045e7844c1d09e1e047c789b1accaa7f0 /generic/Field.c
parenta29924752c636cd1777747fe532398e687e08f49 (diff)
downloadtkzinc-737920a9203af23d93d9c8352737b93651392776.zip
tkzinc-737920a9203af23d93d9c8352737b93651392776.tar.gz
tkzinc-737920a9203af23d93d9c8352737b93651392776.tar.bz2
tkzinc-737920a9203af23d93d9c8352737b93651392776.tar.xz
*** empty log message ***
Diffstat (limited to 'generic/Field.c')
-rw-r--r--generic/Field.c2212
1 files changed, 2212 insertions, 0 deletions
diff --git a/generic/Field.c b/generic/Field.c
new file mode 100644
index 0000000..232fda9
--- /dev/null
+++ b/generic/Field.c
@@ -0,0 +1,2212 @@
+/*
+ * Field.c -- Implementation of fields.
+ *
+ * Authors : Patrick Lecoanet.
+ * Creation date :
+ *
+ * $Id$
+ */
+
+/*
+ * Copyright (c) 1993 - 2002 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 <malloc.h>
+#include <string.h>
+#ifdef GLX
+#include <GL/glx.h>
+#endif
+
+#include "Item.h"
+#include "Types.h"
+#include "WidgetInfo.h"
+#include "Draw.h"
+#include "Geo.h"
+#include "tkZinc.h"
+
+
+static const char rcsid[] = "$Id$";
+static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $";
+
+
+#define FIELD_SENSITIVE_BIT 1
+#define FIELD_VISIBLE_BIT 2
+#define FILLED_BIT 4
+#define TEXT_ON_TOP_BIT 8
+#define CACHE_OK 16
+
+
+/*
+ * Field record.
+ */
+typedef struct _FieldStruct {
+ /* Public data */
+ ZnGradient *color;
+ ZnGradient *fill_color;
+ Pixmap fill_pattern;
+ ZnGradient *border_color;
+ char *text;
+ char *image_name;
+ char *tile_name;
+ ZnFont font;
+ unsigned short flags;
+ Border border_edges;
+ ZnJustify alignment;
+ ReliefStyle relief;
+ ZnDim relief_thickness;
+ AutoAlign auto_alignment;
+
+ /* Private data */
+ ZnImage image;
+ ZnImage tile;
+ ZnGradient *gradient;
+ ZnPoint *grad_geo;
+ short orig_x;
+ short orig_y;
+ short corner_x;
+ short corner_y;
+ FieldSet field_set;
+ int insert_index;
+#ifdef GLX
+ TexFont *txf;
+#endif
+} FieldStruct, *Field;
+
+
+/*
+ * The -text, -image, -border, -relief, -visible and
+ * -filled attributes set the ZN_COORDS_FLAG to update
+ * the leader that might protude if not clipped by the text.
+ */
+ZnAttrConfig field_attrs[] = {
+ { ZN_CONFIG_JUSTIFY, "-alignment", NULL,
+ Tk_Offset(FieldStruct, alignment), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_AUTO_JUSTIFY, "-autoalignment", NULL,
+ Tk_Offset(FieldStruct, auto_alignment), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_GRADIENT, "-backcolor", NULL,
+ Tk_Offset(FieldStruct, fill_color), 0,
+ ZN_DRAW_FLAG|ZN_BORDER_FLAG, False },
+ { ZN_CONFIG_BORDER, "-border", NULL,
+ Tk_Offset(FieldStruct, border_edges), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_GRADIENT, "-bordercolor", NULL,
+ Tk_Offset(FieldStruct, border_color), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_GRADIENT, "-color", NULL,
+ Tk_Offset(FieldStruct, color), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_BOOL, "-filled", NULL,
+ Tk_Offset(FieldStruct, flags), FILLED_BIT, ZN_COORDS_FLAG, False },
+ { ZN_CONFIG_PATTERN, "-fillpattern", NULL,
+ Tk_Offset(FieldStruct, fill_pattern), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_FONT, "-font", NULL,
+ Tk_Offset(FieldStruct, font), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False },
+ { ZN_CONFIG_IMAGE, "-image", NULL,
+ Tk_Offset(FieldStruct, image_name), 0,
+ ZN_COORDS_FLAG|ZN_IMAGE_FLAG|ZN_CLFC_FLAG, False },
+ { ZN_CONFIG_RELIEF, "-relief", NULL,
+ Tk_Offset(FieldStruct, relief), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_DIM, "-reliefthickness", NULL,
+ Tk_Offset(FieldStruct, relief_thickness), 0, ZN_DRAW_FLAG, False },
+ { ZN_CONFIG_BOOL, "-sensitive", NULL,
+ Tk_Offset(FieldStruct, flags),
+ FIELD_SENSITIVE_BIT, ZN_REPICK_FLAG, False },
+ { ZN_CONFIG_TEXT, "-text", NULL,
+ Tk_Offset(FieldStruct, text), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False },
+ { ZN_CONFIG_IMAGE, "-tile", NULL,
+ Tk_Offset(FieldStruct, tile_name), 0,
+ ZN_COORDS_FLAG|ZN_TILE_FLAG, False },
+ { ZN_CONFIG_BOOL, "-visible", NULL,
+ Tk_Offset(FieldStruct, flags), FIELD_VISIBLE_BIT,
+ ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, /* Keep ZN_COORDS_FLAG here */
+
+ { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 }
+};
+
+static void GetLabelBBox(FieldSet field_set, ZnDim *w, ZnDim *h);
+
+
+
+/*
+ **********************************************************************************
+ *
+ * ComputeFieldAttachment --
+ * Compute the location/size of the field, computing attachments if any.
+ *
+ **********************************************************************************
+ */
+static void
+ComputeFieldAttachment(FieldSet field_set,
+ int field,
+ ZnBBox *field_bbox)
+{
+
+ ZnBBox ref_bbox;
+ ZnDim real_width, real_height;
+ int ref_field, num_fields;
+ char x_attach, y_attach, x_dim, y_dim;
+ short width_spec, height_spec;
+ int x_spec, y_spec, icon_width=0, icon_height=0;
+ Field field_ptr;
+ Tk_FontMetrics fm;
+
+ field_ptr = &field_set->fields[field];
+ if (ISSET(field_ptr->flags, CACHE_OK)) {
+ field_bbox->orig.x = (ZnPos) field_ptr->orig_x;
+ field_bbox->orig.y = (ZnPos) field_ptr->orig_y;
+ field_bbox->corner.x = field_ptr->corner_x;
+ field_bbox->corner.y = field_ptr->corner_y;
+ return;
+ }
+
+ /*
+ * Preset this field to a default position/size and pretend
+ * its cache is ok to break any deadlocks.
+ */
+ field_ptr->orig_x = field_ptr->orig_y = 0;
+ field_ptr->corner_x = field_ptr->corner_y = 0;
+ field_bbox->orig.x = field_bbox->orig.y = 0;
+ field_bbox->corner.x = field_bbox->corner.y = 0;
+ SET(field_ptr->flags, CACHE_OK);
+
+ num_fields = LabelFormatNumFields(field_set->label_format);
+ LabelFormatGetField(field_set->label_format, field,
+ &x_attach, &y_attach, &x_dim, &y_dim,
+ &x_spec, &y_spec, &width_spec, &height_spec);
+
+ /*
+ * First try to compute the field size which may be a factor
+ * of the field content (but not a factor of other fields).
+ */
+ if ((field_ptr->image != ZnUnspecifiedImage) &&
+ ((x_dim == LF_DIM_ICON) || (y_dim == LF_DIM_ICON) ||
+ (x_dim == LF_DIM_AUTO) || (y_dim == LF_DIM_AUTO))) {
+ Tk_SizeOfImage(field_ptr->image, &icon_width, &icon_height);
+ }
+
+ switch (x_dim) {
+ case LF_DIM_FONT:
+ real_width = (ZnDim) (width_spec*ZnTextWidth(field_ptr->font, "N", 1)/100);
+ break;
+ case LF_DIM_ICON:
+ real_width = (ZnDim) (width_spec*icon_width/100);
+ break;
+ case LF_DIM_AUTO:
+ {
+ int len = strlen(field_ptr->text);
+ ZnDim text_width;
+
+ real_width = 0.0;
+ if (field_ptr->image != ZnUnspecifiedImage) {
+ real_width = (ZnDim) icon_width;
+ }
+ if (len) {
+ /*
+ * The 4 extra pixels are needed for border and padding.
+ */
+ text_width = (ZnDim) ZnTextWidth(field_ptr->font, field_ptr->text, len) + 4;
+ real_width = text_width < real_width ? real_width : text_width;
+ }
+ real_width += (ZnDim) width_spec;
+ break;
+ }
+ case LF_DIM_LABEL:
+ {
+ ZnDim lh;
+
+ GetLabelBBox(field_set, &real_width, &lh);
+ break;
+ }
+ case LF_DIM_PIXEL:
+ default:
+ real_width = (ZnDim) width_spec;
+ break;
+ }
+ /*printf("field %d, width = %g\n", field, real_width);*/
+
+ switch (y_dim) {
+ case LF_DIM_FONT:
+ {
+ Tk_GetFontMetrics(field_ptr->font, &fm);
+ real_height = (ZnDim) (height_spec*(fm.ascent + fm.descent)/100);
+ break;
+ }
+ case LF_DIM_ICON:
+ real_height = (ZnDim) (height_spec*icon_height/100);
+ break;
+ case LF_DIM_AUTO:
+ {
+ ZnDim text_height;
+
+ real_height = 0.0;
+ if (field_ptr->image != ZnUnspecifiedImage) {
+ real_height = (ZnDim) icon_height;
+ }
+ if (strlen(field_ptr->text)) {
+ Tk_GetFontMetrics(field_ptr->font, &fm);
+ text_height = (ZnDim) (fm.ascent + fm.descent);
+ real_height = text_height < real_height ? real_height : text_height;
+ }
+ real_height += (ZnDim) height_spec;
+ break;
+ }
+ case LF_DIM_LABEL:
+ {
+ ZnDim lw;
+
+ GetLabelBBox(field_set, &lw, &real_height);
+ break;
+ }
+ case LF_DIM_PIXEL:
+ default:
+ real_height = (ZnDim) height_spec;
+ break;
+ }
+ /*printf("field %d, height = %g\n", field, real_height);*/
+
+ /*
+ * Update the cache with the newly computed infos
+ * (breaking of deadlocks).
+ */
+ field_bbox->corner.x = field_ptr->corner_x = real_width;
+ field_bbox->corner.y = field_ptr->corner_y = real_height;
+
+ /*
+ * Then try to deduce the position, resolving any attachments
+ * if needed.
+ */
+
+ /*
+ * Do the x axis.
+ */
+ if (x_dim != LF_DIM_LABEL) {
+ if (x_attach == LF_ATTACH_PIXEL) {
+ field_bbox->orig.x = (ZnPos) x_spec;
+ field_bbox->corner.x = field_bbox->orig.x + real_width;
+ }
+ else {
+ ref_field = x_spec;
+ field_bbox->orig.x = field_bbox->corner.x = 0;
+ if ((ref_field < 0) || (ref_field >= num_fields)) {
+ ZnWarning ("Attached (x) to an inexistant field geometry\n");
+ }
+ else {
+ ComputeFieldAttachment(field_set, ref_field, &ref_bbox);
+ switch (x_attach) {
+ case LF_ATTACH_FWD:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->orig.x = ref_bbox.corner.x;
+ }
+ else {
+ field_bbox->orig.x = ref_bbox.orig.x;
+ }
+ field_bbox->corner.x = field_bbox->orig.x + real_width;
+ break;
+ case LF_ATTACH_BWD:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->corner.x = ref_bbox.orig.x;
+ }
+ else {
+ field_bbox->corner.x = ref_bbox.corner.x;
+ }
+ field_bbox->orig.x = field_bbox->corner.x - real_width;
+ break;
+ case LF_ATTACH_LEFT:
+ field_bbox->orig.x = ref_bbox.orig.x;
+ field_bbox->corner.x = field_bbox->orig.x + real_width;
+ break;
+ case LF_ATTACH_RIGHT:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->corner.x = ref_bbox.corner.x;
+ }
+ else {
+ field_bbox->corner.x = ref_bbox.orig.x;
+ }
+ field_bbox->orig.x = field_bbox->corner.x - real_width;
+ break;
+ }
+ }
+ }
+ /*printf("field %d, x = %g\n", field, field_bbox->orig.x);*/
+ }
+
+ /*
+ * Then the y axis.
+ */
+ if (y_dim != LF_DIM_LABEL) {
+ if (y_attach == LF_ATTACH_PIXEL) {
+ field_bbox->orig.y = (ZnPos) y_spec;
+ field_bbox->corner.y = field_bbox->orig.y + real_height;
+ }
+ else {
+ ref_field = y_spec;
+ field_bbox->orig.y = field_bbox->corner.y = 0;
+ if ((ref_field < 0) || (ref_field >= num_fields)) {
+ ZnWarning ("Attached (y) to an inexistant field geometry\n");
+ }
+ else {
+ ComputeFieldAttachment(field_set, ref_field, &ref_bbox);
+ switch (y_attach) {
+ case LF_ATTACH_FWD:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->orig.y = ref_bbox.corner.y;
+ }
+ else {
+ field_bbox->orig.y = ref_bbox.orig.y;
+ }
+ field_bbox->corner.y = field_bbox->orig.y + real_height;
+ break;
+ case LF_ATTACH_BWD:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->corner.y = ref_bbox.orig.y;
+ }
+ else {
+ field_bbox->corner.y = ref_bbox.corner.y;
+ }
+ field_bbox->orig.y = field_bbox->corner.y - real_height;
+ break;
+ case LF_ATTACH_LEFT:
+ field_bbox->orig.y = ref_bbox.orig.y;
+ field_bbox->corner.y = field_bbox->orig.y + real_height;
+ break;
+ case LF_ATTACH_RIGHT:
+ if (ISSET(field_set->fields[ref_field].flags, FIELD_VISIBLE_BIT)) {
+ field_bbox->corner.y = ref_bbox.corner.y;
+ }
+ else {
+ field_bbox->corner.y = ref_bbox.orig.y;
+ }
+ field_bbox->orig.y = field_bbox->corner.y - real_height;
+ break;
+ }
+ }
+ }
+ /*printf("field %d, y = %g\n", field, field_bbox->orig.y);*/
+ }
+
+ field_ptr->orig_x = (short) field_bbox->orig.x;
+ field_ptr->orig_y = (short) field_bbox->orig.y;
+ field_ptr->corner_x = (short) field_bbox->corner.x;
+ field_ptr->corner_y = (short) field_bbox->corner.y;
+ SET(field_ptr->flags, CACHE_OK);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ClearFieldCache --
+ * Reset the geometric cache of all fields depending on a given field (or
+ * of all fields if the field is < 0). Clear also the label bounding box
+ * cache if some action has been taken on a field.
+ *
+ **********************************************************************************
+ */
+static void
+ClearFieldCache(FieldSet field_set,
+ int field)
+{
+ int i, num_fields;
+ ZnBool clear_bbox;
+ int x_spec, y_spec;
+ char x_attach, y_attach, x_dim, y_dim;
+ short width_spec, height_spec;
+
+ if (field < 0) {
+ for (i = 0; i < field_set->num_fields; i++) {
+ CLEAR(field_set->fields[i].flags, CACHE_OK);
+ }
+ field_set->label_width = field_set->label_height = -1.0;
+ return;
+ }
+
+ clear_bbox = False;
+ if (!field_set->label_format) {
+ return;
+ }
+ num_fields = LabelFormatNumFields(field_set->label_format);
+ if (field >= num_fields) {
+ return;
+ }
+ LabelFormatGetField(field_set->label_format, field,
+ &x_attach, &y_attach, &x_dim, &y_dim,
+ &x_spec, &y_spec, &width_spec, &height_spec);
+ if ((x_dim != LF_DIM_PIXEL) || (y_dim != LF_DIM_PIXEL)) {
+ CLEAR(field_set->fields[field].flags, CACHE_OK);
+ clear_bbox = True;
+ }
+ for (i = 0; i < num_fields; i++) {
+ LabelFormatGetField(field_set->label_format, i,
+ &x_attach, &y_attach, &x_dim, &y_dim,
+ &x_spec, &y_spec, &width_spec, &height_spec);
+ if ((x_attach == LF_ATTACH_PIXEL) && (y_attach == LF_ATTACH_PIXEL)) {
+ continue;
+ }
+ if (x_attach != LF_ATTACH_PIXEL) {
+ if ((x_spec == field) && ISSET(field_set->fields[i].flags, CACHE_OK)) {
+ CLEAR(field_set->fields[i].flags, CACHE_OK);
+ ClearFieldCache(field_set, i);
+ clear_bbox = True;
+ }
+ }
+ if (y_attach != LF_ATTACH_PIXEL) {
+ if ((y_spec == field) && ISSET(field_set->fields[i].flags, CACHE_OK)) {
+ CLEAR(field_set->fields[i].flags, CACHE_OK);
+ ClearFieldCache(field_set, i);
+ clear_bbox = True;
+ }
+ }
+ }
+
+ if (clear_bbox) {
+ field_set->label_width = field_set->label_height = -1.0;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * GetLabelBBox --
+ *
+ **********************************************************************************
+ */
+static void
+GetLabelBBox(FieldSet field_set,
+ ZnDim *w,
+ ZnDim *h)
+{
+ ZnBBox bbox, tmp_bbox;
+ ZnLabelFormat lf;
+ int i, num_fields;
+ ZnDim clip_w, clip_h;
+
+ if ((field_set->label_width >= 0.0) && (field_set->label_height >= 0.0)) {
+ *w = field_set->label_width;
+ *h = field_set->label_height;
+ return;
+ }
+
+ lf = field_set->label_format;
+ if (lf == NULL) {
+ *w = *h = field_set->label_width = field_set->label_height = 0.0;
+ return;
+ }
+
+ ResetBBox(&bbox);
+ num_fields = LabelFormatNumFields(lf);
+ for (i = 0; i < num_fields; i++) {
+ ComputeFieldAttachment(field_set, i, &tmp_bbox);
+ /*printf("field %d bbox %g %g %g %g\n", i, tmp_bbox.orig.x, tmp_bbox.orig.y,
+ tmp_bbox.corner.x, tmp_bbox.corner.y);*/
+ AddBBoxToBBox(&bbox, &tmp_bbox);
+ }
+ field_set->label_width = bbox.corner.x;
+ field_set->label_height = bbox.corner.y;
+
+ /*printf("GetLabelBBox size before clipping; w = %g, h = %g\n",
+ field_set->label_width, field_set->label_height);*/
+ if (LabelFormatGetClipBox(lf, &clip_w, &clip_h)) {
+ if (clip_w < field_set->label_width) {
+ field_set->label_width = clip_w;
+ }
+ if (clip_h < field_set->label_height) {
+ field_set->label_height = clip_h;
+ }
+ }
+
+ *w = field_set->label_width;
+ *h = field_set->label_height;
+ /*printf("GetLabelBBox returns computed size; w = %g, h = %g\n", *w, *h);*/
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * GetFieldBBox --
+ * Compute the location of the field described
+ * by the field entry index in the item current LabelFormat.
+ *
+ **********************************************************************************
+ */
+static void
+GetFieldBBox(FieldSet field_set,
+ unsigned int index,
+ ZnBBox *field_bbox)
+{
+ ZnReal ox, oy;
+
+ if (field_set->label_format) {
+ ox = REAL_TO_INT(field_set->label_pos.x);
+ oy = REAL_TO_INT(field_set->label_pos.y);
+ ComputeFieldAttachment(field_set, index, field_bbox);
+ field_bbox->orig.x += ox;
+ field_bbox->orig.y += oy;
+ field_bbox->corner.x += ox;
+ field_bbox->corner.y += oy;
+ }
+ else {
+ ResetBBox(field_bbox);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ComputeFieldTextLocation --
+ * Compute the position of the text in a field. This is a position
+ * that we can give to XDrawText. The position is deduced from the
+ * field bounding box passed in bbox.
+ * Return also the text bounding box.
+ *
+ **********************************************************************************
+ */
+static void
+ComputeFieldTextLocation(Field field_ptr,
+ ZnBBox *bbox,
+ ZnPoint *pos,
+ ZnBBox *text_bbox)
+{
+ ZnDim w, h;
+ Tk_FontMetrics fm;
+
+ Tk_GetFontMetrics(field_ptr->font, &fm);
+ w = ZnTextWidth(field_ptr->font, field_ptr->text, strlen(field_ptr->text));
+ h = fm.ascent + fm.descent;
+ text_bbox->orig.y = (bbox->orig.y + bbox->corner.y - h) / 2.0;
+ text_bbox->corner.y = text_bbox->orig.y + h;
+ pos->y = text_bbox->orig.y + fm.ascent;
+
+ switch (field_ptr->alignment) {
+ case ZnJustifyLeft:
+ text_bbox->orig.x = bbox->orig.x + 2;
+ break;
+ case ZnJustifyRight:
+ text_bbox->orig.x = bbox->corner.x - w - 2;
+ break;
+ default:
+ text_bbox->orig.x = (bbox->orig.x + bbox->corner.x - w) / 2.0;
+ break;
+ }
+ text_bbox->corner.x = text_bbox->orig.x + w;
+ pos->x = text_bbox->orig.x;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * LeaderToLabel --
+ * Compute the segment part of segment <start, end> that lies
+ * outside the fields of item.
+ *
+ **********************************************************************************
+ */
+static void
+LeaderToLabel(FieldSet field_set,
+ ZnPoint *start,
+ ZnPoint *end)
+{
+ int b_num;
+ ZnPoint delta, inf, sup;
+ ZnPos xt=0, yu=0, yw=0, xv=0;
+ Field field_ptr;
+ int i;
+ ZnBBox field_bbox;
+
+ /* Intersection points : */
+ /* T |xt / delta_y U |x1 V |y1 W |yw / delta_x */
+ /* |y2 |yu / delta_x |xv / delta_y |x2 */
+ /* */
+ /* y = ax + b; */
+ /* a = delta_y / delta_x */
+ /* b = (y * delta_x - x * delta_y) / delta_x */
+
+ delta.x = start->x - end->x;
+ delta.y = start->y - end->y;
+ b_num = start->y*delta.x - start->x*delta.y;
+
+ for (i = 0; i < LabelFormatNumFields(field_set->label_format); i++) {
+ field_ptr = &field_set->fields[i];
+ /*
+ * If the field is made invisible or has no graphics of
+ * its own, don't clip.
+ */
+ if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) ||
+ ((*field_ptr->text == 0) &&
+ ISCLEAR(field_ptr->flags, FILLED_BIT) &&
+ (field_ptr->border_edges == NO_BORDER) &&
+ (field_ptr->relief == RELIEF_FLAT) &&
+ (field_ptr->image == ZnUnspecifiedImage))) {
+ continue;
+ }
+
+ /*
+ * field_bbox is in absolute device coordinates.
+ */
+ GetFieldBBox(field_set, i, &field_bbox);
+
+ /*
+ * Adjust leader on real text, not on field boundaries. This is
+ * important when there are leading and trailing spaces.
+ * The correct test here is really *field_ptr->text, an empty
+ * text is represented by an empty string NOT by a NULL pointer.
+ */
+ if (*field_ptr->text && ISCLEAR(field_ptr->flags, FILLED_BIT) &&
+ (field_ptr->border_edges == NO_BORDER) &&
+ (field_ptr->relief == RELIEF_FLAT) &&
+ (field_ptr->image == ZnUnspecifiedImage)) {
+ ZnBBox text_bbox;
+ ZnPoint text_pos; /* dummy */
+ int space_width;
+ int scan_forw, scan_back;
+ space_width = ZnTextWidth(field_ptr->font, " ", 1);
+
+ ComputeFieldTextLocation(field_ptr, &field_bbox, &text_pos, &text_bbox);
+ /*
+ * Correct adjusments made by ComputeFieldTextLocation (Vincent Pomey).
+ *
+ * PLC: IMHO, this is to compensate for exotic fonts like 'symbolesATC'.
+ * I am not planning to port this to Tk for two reasons:
+ * 1/ Current positions are no longer implemented as characters
+ * and 2/ Tk does not give access (easily) to lbearings and rbearings.
+ * This patch has been contributed by Phidias team. I don't know the
+ * problem it was meant to solve.
+ * text_bbox.x -= field_ptr->font->per_char[field_ptr->text[0]].lbearing + 3;
+ * text_bbox.width += field_ptr->font->per_char[field_ptr->text[0]].lbearing + 3;
+ */
+ /*
+ * Change bbox according to leading and trailing spaces.
+ */
+ scan_forw = 0;
+ while (field_ptr->text[scan_forw] == ' ') {
+ /* leading spaces */
+ text_bbox.orig.x += space_width;
+ scan_forw++;
+ }
+
+ /*
+ * Empty text.
+ */
+ if (field_ptr->text[scan_forw] == 0) {
+ continue;
+ }
+
+ scan_back = strlen(field_ptr->text)-1;
+ while ((field_ptr->text[scan_back] == ' ') && (scan_back > scan_forw)) {
+ /* trailing spaces */
+ text_bbox.corner.x -= space_width;
+ scan_back--;
+ }
+
+ field_bbox = text_bbox;
+ }
+
+ if (field_bbox.corner.x <= field_bbox.orig.x) {
+ continue;
+ }
+
+ if ((start->x >= field_bbox.orig.x) && (start->x < field_bbox.corner.x) &&
+ (start->y >= field_bbox.orig.y) && (start->y < field_bbox.corner.y)) {
+ end->x = start->x;
+ end->y = start->y;
+ }
+ if (delta.x) {
+ yu = (field_bbox.orig.x*delta.y + b_num) / delta.x;
+ yw = (field_bbox.corner.x*delta.y + b_num) / delta.x;
+ }
+ if (delta.y) {
+ xt = (field_bbox.corner.y*delta.x - b_num) / delta.y;
+ xv = (field_bbox.orig.y*delta.x - b_num) / delta.y;
+ }
+
+ inf.x = MIN(start->x, end->x);
+ sup.x = MAX(start->x, end->x);
+ inf.y = MIN(start->y, end->y);
+ sup.y = MAX(start->y, end->y);
+
+ if (delta.x) {
+ if ((yu >= field_bbox.orig.y) && (yu <= field_bbox.corner.y) &&
+ (field_bbox.orig.x >= inf.x) && (field_bbox.orig.x <= sup.x) &&
+ (yu >= inf.y) && (yu <= sup.y)) {
+ end->x = field_bbox.orig.x;
+ end->y = yu;
+ inf.x = MIN(start->x, end->x);
+ sup.x = MAX(start->x, end->x);
+ inf.y = MIN(start->y, end->y);
+ sup.y = MAX(start->y, end->y);
+ }
+ if ((yw >= field_bbox.orig.y) && (yw <= field_bbox.corner.y) &&
+ (field_bbox.corner.x >= inf.x) && (field_bbox.corner.x <= sup.x) &&
+ (yw >= inf.y) && (yw <= sup.y)) {
+ end->x = field_bbox.corner.x;
+ end->y = yw;
+ inf.x = MIN(start->x, end->x);
+ sup.x = MAX(start->x, end->x);
+ inf.y = MIN(start->y, end->y);
+ sup.y = MAX(start->y, end->y);
+ }
+ }
+ if (delta.y) {
+ if ((xt >= field_bbox.orig.x) && (xt <= field_bbox.corner.x) &&
+ (xt >= inf.x) && (xt <= sup.x) &&
+ (field_bbox.corner.y >= inf.y) && (field_bbox.corner.y <= sup.y)) {
+ end->x = xt;
+ end->y = field_bbox.corner.y;
+ inf.x = MIN(start->x, end->x);
+ sup.x = MAX(start->x, end->x);
+ inf.y = MIN(start->y, end->y);
+ sup.y = MAX(start->y, end->y);
+ }
+ if ((xv >= field_bbox.orig.x) && (xv <= field_bbox.corner.x) &&
+ (xv >= inf.x) && (xv <= sup.x) &&
+ (field_bbox.orig.y >= inf.y) && (field_bbox.orig.y <= sup.y)) {
+ end->x = xv;
+ end->y = field_bbox.orig.y;
+ inf.x = MIN(start->x, end->x);
+ sup.x = MAX(start->x, end->x);
+ inf.y = MIN(start->y, end->y);
+ sup.y = MAX(start->y, end->y);
+ }
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldImageChange --
+ *
+ **********************************************************************************
+ */
+static void
+FieldImageChange(ClientData client_data,
+ int x,
+ int y,
+ int width,
+ int height,
+ int image_width,
+ int image_height)
+{
+ Field field = (Field) client_data;
+ int i;
+ ZnBBox bbox;
+
+ if (field->image != ZnUnspecifiedImage) {
+ i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct);
+ GetFieldBBox(field->field_set, i, &bbox);
+ ZnDamage(field->field_set->wi, &bbox);
+ ZnNeedRedisplay(field->field_set->wi);
+ ClearFieldCache(field->field_set, i);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldTileChange --
+ *
+ **********************************************************************************
+ */
+static void
+FieldTileChange(ClientData client_data,
+ int x,
+ int y,
+ int width,
+ int height,
+ int image_width,
+ int image_height)
+{
+ Field field = (Field) client_data;
+ int i;
+ ZnBBox bbox;
+
+ if (field->tile != ZnUnspecifiedImage) {
+ i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct);
+ InvalidateImage(field->tile_name);
+ GetFieldBBox(field->field_set, i, &bbox);
+ ZnDamage(field->field_set->wi, &bbox);
+ ZnNeedRedisplay(field->field_set->wi);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * InitFields --
+ *
+ * Perform the init of each field in a FieldSet. The number of such
+ * fields must have been inited before calling this fun.
+ *
+ **********************************************************************************
+ */
+static void
+InitFields(FieldSet field_set)
+{
+ WidgetInfo *wi = field_set->wi;
+ Field field;
+ unsigned int i, num_fields;
+
+ /*printf("size of a field = %d\n", sizeof(FieldStruct));*/
+
+ if (field_set->num_fields < 0) {
+ field_set->num_fields = 0;
+ }
+ if (!field_set->num_fields) {
+ return;
+ }
+ num_fields = field_set->num_fields;
+ field_set->fields = (Field) ZnMalloc(num_fields*sizeof(FieldStruct));
+
+ for (i = 0; i < num_fields; i++){
+ field = &field_set->fields[i];
+
+ field->field_set = field_set;
+ field->color = ZnGetGradientByValue(wi->fore_color);
+ field->fill_color = ZnGetGradientByValue(wi->back_color);
+ field->border_color = ZnGetGradientByValue(wi->fore_color);
+ SET(field->flags, FIELD_VISIBLE_BIT);
+ SET(field->flags, FIELD_SENSITIVE_BIT);
+ CLEAR(field->flags, FILLED_BIT);
+ CLEAR(field->flags, CACHE_OK);
+ field->fill_pattern = ZnUnspecifiedPattern;
+ field->text = "";
+ field->image = ZnUnspecifiedImage;
+ field->image_name = "";
+ field->tile = ZnUnspecifiedImage;
+ field->tile_name = "";
+ field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font));
+ field->border_edges = NO_BORDER;
+ field->alignment = ZnJustifyLeft;
+ field->auto_alignment.automatic = False;
+
+ field->relief = RELIEF_FLAT;
+ field->relief_thickness = 2;
+ SET(field->flags, TEXT_ON_TOP_BIT);
+
+ field->gradient = NULL;
+ field->grad_geo = NULL;
+#ifdef GLX
+ field->txf = NULL;
+#endif
+ }
+ field_set->label_pos.x = field_set->label_pos.y = 0.0;
+ field_set->label_width = field_set->label_height = -1.0;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * CloneFields --
+ *
+ **********************************************************************************
+ */
+static void
+CloneFields(FieldSet field_set)
+{
+ WidgetInfo *wi = field_set->wi;
+ Field field, fields_ret;
+ unsigned int i, num_fields;
+ char *text;
+
+ if (field_set->label_format) {
+ field_set->label_format = LabelFormatDuplicate(field_set->label_format);
+ }
+ num_fields = field_set->num_fields;
+ if (!num_fields) {
+ return;
+ }
+ fields_ret = (Field) ZnMalloc(num_fields*sizeof(FieldStruct));
+ memcpy(fields_ret, field_set->fields, num_fields*sizeof(FieldStruct));
+ field_set->fields = fields_ret;
+
+ for (i = 0; i < num_fields; i++) {
+ field = &fields_ret[i];
+ if (field->gradient) {
+ field->gradient = ZnGetGradientByValue(field->gradient);
+ }
+ if (field->grad_geo) {
+ ZnPoint *grad_geo = ZnMalloc(4*sizeof(ZnPoint));
+ memcpy(grad_geo, field->grad_geo, 4*sizeof(ZnPoint));
+ field->grad_geo = grad_geo;
+ }
+ if (field->image != ZnUnspecifiedImage) {
+ text = ZnMalloc((strlen(field->image_name) + 1) * sizeof(char));
+ strcpy(text, field->image_name);
+ field->image_name = text;
+ field->image = Tk_GetImage(wi->interp, wi->win, field->image_name,
+ FieldImageChange, (ClientData) field);
+ }
+ if (field->tile != ZnUnspecifiedImage) {
+ text = ZnMalloc((strlen(field->tile_name) + 1) * sizeof(char));
+ strcpy(text, field->tile_name);
+ field->tile_name = text;
+ field->tile = Tk_GetImage(wi->interp, wi->win, field->tile_name,
+ FieldTileChange, (ClientData) field);
+ }
+ if (field->fill_pattern != ZnUnspecifiedPattern) {
+ field->fill_pattern = Tk_GetBitmap(wi->interp, wi->win,
+ Tk_NameOfBitmap(wi->dpy, field->fill_pattern));
+ }
+ field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(field->font));
+ field->color = ZnGetGradientByValue(field->color);
+ field->fill_color = ZnGetGradientByValue(field->fill_color);
+ field->border_color = ZnGetGradientByValue(field->border_color);
+
+ if (strlen(field->text) != 0) {
+ text = (char *) ZnMalloc((strlen(field->text) + 1) * sizeof(char));
+ strcpy(text, field->text);
+ field->text = text;
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ConfigureField --
+ *
+ **********************************************************************************
+ */
+static int
+ConfigureField(FieldSet fs,
+ unsigned int field,
+ int argc,
+ Tcl_Obj *CONST argv[],
+ int *flags)
+{
+ int i;
+ Field field_ptr;
+ ZnBBox bbox;
+ WidgetInfo *wi = fs->wi;
+ XColor *color;
+ int alpha;
+#ifdef GLX
+ ZnFont old_font;
+#endif
+
+ if (field >= fs->num_fields) {
+ Tcl_AppendResult(wi->interp, "invalid field index \"", NULL);
+ return ZN_ERROR;
+ }
+
+ field_ptr = &fs->fields[field];
+ old_font = field_ptr->font;
+
+ if (ZnConfigureAttributes(wi, field_ptr, field_attrs,
+ argc, argv, flags) == ZN_ERROR) {
+ return ZN_ERROR;
+ }
+
+#ifdef GLX
+ if (old_font != field_ptr->font) {
+ field_ptr->txf = NULL;
+ }
+#endif
+
+ if (ISSET(*flags, ZN_REPICK_FLAG)) {
+ SET(wi->events_flags, INTERNAL_NEED_REPICK);
+ }
+ if (ISSET(*flags, ZN_CLFC_FLAG)) {
+ ClearFieldCache(fs, field);
+ }
+
+ if (field_ptr->gradient &&
+ (ISSET(*flags, ZN_BORDER_FLAG) || (field_ptr->relief == RELIEF_FLAT))) {
+ ZnFreeGradient(field_ptr->gradient);
+ field_ptr->gradient = NULL;
+ }
+ if ((field_ptr->relief != RELIEF_FLAT) && !field_ptr->gradient) {
+ color = ZnGetGradientColor(field_ptr->border_color, 51.0, &alpha);
+ field_ptr->gradient = ZnGetReliefGradient(wi->interp, wi->win,
+ ZnNameOfColor(color), alpha);
+ if (field_ptr->gradient == NULL) {
+ return ZN_ERROR;
+ }
+ }
+
+ if (ISSET(*flags, ZN_IMAGE_FLAG)) {
+ if (ValidateImage(wi, field_ptr, field_ptr->image_name, FieldImageChange,
+ &field_ptr->image, "field -image") == ZN_ERROR) {
+ return ZN_ERROR;
+ }
+ }
+
+ if (ISSET(*flags, ZN_TILE_FLAG)) {
+ if (ValidateImage(wi, field_ptr, field_ptr->tile_name, FieldTileChange,
+ &field_ptr->tile, "field -tile") == ZN_ERROR) {
+ return ZN_ERROR;
+ }
+ }
+
+ /*
+ * This is done here to limit the redraw to the area of the
+ * modified fields.
+ */
+ if (ISCLEAR(*flags, ZN_COORDS_FLAG) &&
+ fs->label_format && ISSET(*flags, ZN_DRAW_FLAG)) {
+ for (i = 0; i < LabelFormatNumFields(fs->label_format); i++) {
+ if (i == field) {
+ GetFieldBBox(fs, i, &bbox);
+ ZnDamage(wi, &bbox);
+ break;
+ }
+ }
+ }
+
+ return ZN_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * QueryField --
+ *
+ **********************************************************************************
+ */
+static int
+QueryField(FieldSet fs,
+ unsigned int field,
+ int argc,
+ Tcl_Obj *CONST argv[])
+{
+ if (field >= fs->num_fields) {
+ Tcl_AppendResult(fs->wi->interp, "invalid field index \"", NULL);
+ return ZN_ERROR;
+ }
+
+ if (ZnQueryAttribute(fs->wi, &fs->fields[field], field_attrs,
+ argv[0]) == ZN_ERROR) {
+ return ZN_ERROR;
+ }
+
+ return ZN_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FreeFields --
+ *
+ **********************************************************************************
+ */
+static void
+FreeFields(FieldSet field_set)
+{
+ WidgetInfo *wi = field_set->wi;
+ unsigned int i, num_fields;
+ Field field;
+
+ if (field_set->label_format) {
+ LabelFormatDelete(field_set->label_format);
+ }
+
+ num_fields = field_set->num_fields;
+ for (i = 0; i < num_fields; i++) {
+ field = &field_set->fields[i];
+
+ if (strlen(field->text) != 0) {
+ ZnFree(field->text);
+ }
+ if (field->gradient) {
+ ZnFreeGradient(field->gradient);
+ }
+ if (field->grad_geo) {
+ ZnFree(field->grad_geo);
+ }
+ if (field->image != ZnUnspecifiedImage) {
+ Tk_FreeImage(field->image);
+ field->image = ZnUnspecifiedImage;
+ }
+ if (strlen(field->image_name) != 0) {
+ ZnFree(field->image_name);
+ }
+ if (field->tile != ZnUnspecifiedImage) {
+ Tk_FreeImage(field->tile);
+ field->tile = ZnUnspecifiedImage;
+ }
+ if (strlen(field->tile_name) != 0) {
+ ZnFree(field->tile_name);
+ }
+ if (field->fill_pattern != ZnUnspecifiedPattern) {
+ Tk_FreeBitmap(wi->dpy, field->fill_pattern);
+ field->fill_pattern = ZnUnspecifiedPattern;
+ }
+ /*printf("freeing a font\n");*/
+ Tk_FreeFont(field->font);
+ ZnFreeGradient(field->color);
+ ZnFreeGradient(field->fill_color);
+ ZnFreeGradient(field->border_color);
+ }
+ if (num_fields) {
+ ZnFree(field_set->fields);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldIndex,
+ * FieldInsertChars,
+ * FieldDeleteChars,
+ * FieldCursor,
+ * FieldSelection --
+ * These functions implement text edition in fields. The behavior
+ * is the same as for Text items.
+ *
+ **********************************************************************************
+ */
+static int
+FieldPointToChar(FieldSet fs,
+ int field,
+ int x,
+ int y)
+{
+ Field field_ptr = &fs->fields[field];
+ int num_chars = strlen(field_ptr->text);
+ ZnBBox f_bbox, t_bbox;
+ ZnPoint t_orig;
+ int n, dummy;
+
+ if (num_chars == 0) {
+ return 0;
+ }
+
+ GetFieldBBox(fs, field, &f_bbox);
+ ComputeFieldTextLocation(field_ptr, &f_bbox, &t_orig, &t_bbox);
+
+ /*
+ * Point above text, returns index 0.
+ */
+ if (y < t_bbox.orig.y) {
+ return 0;
+ }
+
+ if (y < t_bbox.corner.y) {
+ if (x < t_bbox.orig.x) {
+ /*
+ * Point to the left of the current line, returns
+ * index of first char.
+ */
+ return 0;
+ }
+ if (x >= t_bbox.corner.x) {
+ /*
+ * Point to the right of the current line, returns
+ * index past the last char.
+ */
+ return num_chars;
+ }
+ n = Tk_MeasureChars(field_ptr->font, field_ptr->text, num_chars,
+ x + 2 - t_bbox.orig.x, TK_PARTIAL_OK, &dummy);
+ return n - 1;
+ }
+ /*
+ * Point below all lines, return the index after
+ * the last char.
+ */
+ return num_chars;
+}
+
+static int
+FieldIndex(FieldSet fs,
+ int field,
+ Item item,
+ Tcl_Obj *index_spec,
+ int *index)
+{
+ Field field_ptr;
+ TextInfo *ti;
+ int num_chars;
+ WidgetInfo *wi = fs->wi;
+ int c, length;
+ int x, y;
+ double tmp;
+ char *end, *p;
+
+ if (field == ZN_NO_PART) {
+ goto sel_err;
+ }
+
+ field_ptr = &fs->fields[field];
+ num_chars = strlen(field_ptr->text);
+ ti = &wi->text_info;
+
+ p = Tcl_GetString(index_spec);
+ c = p[0];
+ length = strlen(p);
+
+ if ((c == 'e') && (strncmp(p, "end", length) == 0)) {
+ *index = num_chars;
+ }
+ else if ((c == 'i') && (strncmp(p, "insert", length) == 0)) {
+ *index = field_ptr->insert_index;
+ }
+ else if ((c == 's') && (strncmp(p, "sel.first", length) == 0) &&
+ (length >= 5)) {
+ if ((ti->sel_item != item) || (ti->sel_field != field)) {
+ sel_err:
+ Tcl_AppendResult(wi->interp, "selection isn't in field", (char *) NULL);
+ return ZN_ERROR;
+ }
+ *index = wi->text_info.sel_first;
+ }
+ else if ((c == 's') && (strncmp(p, "sel.last", length) == 0) &&
+ (length >= 5)) {
+ if ((ti->sel_item != item) || (ti->sel_field != field)) {
+ goto sel_err;
+ }
+ *index = wi->text_info.sel_last;
+ }
+ else if (c == '@') {
+ p++;
+ tmp = strtod(p, &end);
+ if ((end == p) || (*end != ',')) {
+ goto badIndex;
+ }
+ x = tmp;
+ p = end+1;
+ tmp = strtod(p, &end);
+ if ((end == p) || (*end != 0)) {
+ goto badIndex;
+ }
+ y = tmp;
+
+ *index = FieldPointToChar(fs, field, x, y);
+ }
+ else if (Tcl_GetIntFromObj(wi->interp, index_spec, index) == TCL_OK) {
+ if (*index < 0){
+ *index = 0;
+ }
+ else if (*index > num_chars) {
+ *index = num_chars;
+ }
+ }
+ else {
+ badIndex:
+ Tcl_AppendResult(wi->interp, "bad index \"", p, "\"", (char *) NULL);
+ return ZN_ERROR;
+ }
+
+ return ZN_OK;
+}
+
+static void
+FieldInsertChars(FieldSet fs,
+ int field,
+ int *index,
+ char *chars)
+{
+ ZnBBox bbox;
+ Field field_ptr;
+ int num_chars;
+ int length;
+ char *new;
+
+ if (field == ZN_NO_PART) {
+ return;
+ }
+
+ length = strlen(chars);
+ if (length == 0) {
+ return;
+ }
+
+ field_ptr = &fs->fields[field];
+ num_chars = strlen(field_ptr->text);
+ if (*index < 0) {
+ *index = 0;
+ }
+ if (*index > num_chars) {
+ *index = num_chars;
+ }
+
+ new = ZnMalloc(num_chars + length + 1);
+ strncpy(new, field_ptr->text, (size_t) *index);
+ strcpy(new + *index, chars);
+ strcpy(new + *index + length, field_ptr->text + *index);
+ ZnFree(field_ptr->text);
+ field_ptr->text = new;
+
+ if (field_ptr->insert_index >= *index) {
+ field_ptr->insert_index += length;
+ }
+
+ /*
+ * Need to update the field area later.
+ */
+ GetFieldBBox(fs, field, &bbox);
+ ZnDamage(fs->wi, &bbox);
+}
+
+static void
+FieldDeleteChars(FieldSet fs,
+ int field,
+ int *first,
+ int *last)
+{
+ ZnBBox bbox;
+ Field field_ptr;
+ int count, num_chars;
+ char *new;
+
+ if (field == ZN_NO_PART) {
+ return;
+ }
+
+ field_ptr = &fs->fields[field];
+ num_chars = strlen(field_ptr->text);
+ if (num_chars == 0) {
+ return;
+ }
+
+ if (*first < 0) {
+ *first = 0;
+ }
+ if (*last >= num_chars) {
+ *last = num_chars-1;
+ }
+ if (*first > *last) {
+ return;
+ }
+ count = *last + 1 - *first;
+
+ new = ZnMalloc(num_chars + 1 - count);
+ strncpy(new, field_ptr->text, (size_t) *first);
+ strcpy(new + *first, field_ptr->text + *last + 1);
+ ZnFree(field_ptr->text);
+ field_ptr->text = new;
+
+ /*
+ * Update the cursor to reflect the new string.
+ */
+ if (field_ptr->insert_index > *first) {
+ field_ptr->insert_index -= count;
+ if (field_ptr->insert_index < *first) {
+ field_ptr->insert_index = *first;
+ }
+ }
+
+ /*
+ * Need to update the field area later.
+ */
+ GetFieldBBox(fs, field, &bbox);
+ ZnDamage(fs->wi, &bbox);
+}
+
+static void
+FieldCursor(FieldSet fs,
+ int field,
+ int index)
+{
+ Field field_ptr;
+ int num_chars;
+
+ if (field == ZN_NO_PART) {
+ return;
+ }
+
+ field_ptr = &fs->fields[field];
+ num_chars = strlen(field_ptr->text);
+
+ if (index < 0) {
+ field_ptr->insert_index = 0;
+ }
+ else if (index > num_chars) {
+ field_ptr->insert_index = num_chars;
+ }
+ else {
+ field_ptr->insert_index = index;
+ }
+}
+
+static int
+FieldSelection(FieldSet fs,
+ int field,
+ int offset,
+ char *chars,
+ int max_chars)
+{
+ Field field_ptr;
+ int count, num_chars;
+ TextInfo *ti;
+
+ if (field == ZN_NO_PART) {
+ return 0;
+ }
+
+ ti = &fs->wi->text_info;
+ count = ti->sel_last - ti->sel_first - offset;
+ if (count > max_chars) {
+ count = max_chars;
+ }
+ field_ptr = &fs->fields[field];
+ num_chars = strlen(field_ptr->text);
+ if (count > num_chars) {
+ count = num_chars;
+ }
+ if (count <= 0) {
+ return 0;
+ }
+
+ strncpy(chars, field_ptr->text + ti->sel_first + offset, (size_t) count);
+ chars[count] = 0;
+
+ return count;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ComputeFieldImageLocation --
+ * Compute the bounding box of the pixmap in a field. The position is
+ * deduced from the field bounding box passed in bbox.
+ *
+ **********************************************************************************
+ */
+static void
+ComputeFieldImageLocation(Field field_ptr,
+ ZnBBox *bbox,
+ ZnBBox *pm_bbox)
+{
+ int width, height;
+
+ Tk_SizeOfImage(field_ptr->image, &width, &height);
+ pm_bbox->orig.y = (bbox->orig.y + bbox->corner.y - height) / 2;
+ pm_bbox->corner.y = pm_bbox->orig.y + height;
+
+ switch (field_ptr->alignment) {
+ case ZnJustifyLeft:
+ pm_bbox->orig.x = bbox->orig.x;
+ break;
+ case ZnJustifyRight:
+ pm_bbox->orig.x = bbox->corner.x - width - 1;
+ break;
+ default:
+ pm_bbox->orig.x = (bbox->orig.x + bbox->corner.x - width) / 2;
+ break;
+ }
+ pm_bbox->corner.x = pm_bbox->orig.x + width;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldsEngine --
+ *
+ **********************************************************************************
+ */
+static void
+FieldsEngine(FieldSet field_set,
+ Item item,
+ void (*cb)())
+{
+ WidgetInfo *wi = field_set->wi;
+ int i; /* This one *NEED* to be an int */
+ int num_fields, num_chars;
+ Field field_ptr;
+ ZnBBox lclip_bbox, fclip_bbox, bbox, *global_clip_box;
+ ZnBBox tmp_bbox, text_bbox, pm_bbox;
+ ZnPoint pts[2];
+ ZnTriStrip tristrip;
+ ZnPoint text_pos;
+ ZnBool restore = False;
+ ZnDim lwidth, lheight;
+ ZnReal val;
+ int cursor = -1;
+ int sel_start = -1, sel_stop = -1;
+
+ if (field_set->label_format && LabelFormatNumFields(field_set->label_format)) {
+ bbox.orig.x = REAL_TO_INT(field_set->label_pos.x);
+ bbox.orig.y = REAL_TO_INT(field_set->label_pos.y);
+ GetLabelBBox(field_set, &lwidth, &lheight);
+ bbox.corner.x = bbox.orig.x + lwidth;
+ bbox.corner.y = bbox.orig.y + lheight;
+ ZnCurrentClip(wi, NULL, &global_clip_box, NULL);
+
+ if (!wi->render) {
+ IntersectBBox(global_clip_box, &bbox, &lclip_bbox);
+ if (IsEmptyBBox(&lclip_bbox)) {
+ return;
+ }
+ }
+ else {
+ lclip_bbox = bbox;
+ }
+
+ num_fields = LabelFormatNumFields(field_set->label_format);
+ for (i = 0; i < num_fields; i++) {
+ field_ptr = &field_set->fields[i];
+
+ if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT)) {
+ continue;
+ }
+
+ GetFieldBBox(field_set, i, &bbox);
+ IntersectBBox(&lclip_bbox, &bbox, &fclip_bbox);
+ if (IsEmptyBBox(&fclip_bbox)) {
+ continue;
+ }
+
+ /* we must call XSetClipRectangles only if it's required */
+ val = fclip_bbox.orig.x - bbox.orig.x;
+ restore = val > 0;
+ val = fclip_bbox.orig.y - bbox.orig.y;
+ restore |= val > 0;
+ val = fclip_bbox.corner.x - bbox.corner.x;
+ restore |= val < 0;
+ val = fclip_bbox.corner.y - bbox.corner.y;
+ restore |= val < 0;
+
+ num_chars = strlen(field_ptr->text);
+ if (num_chars) {
+ ComputeFieldTextLocation(field_ptr, &bbox, &text_pos, &text_bbox);
+ if ((wi->focus_item == item) && (wi->focus_field == i) &&
+ wi->got_focus && wi->text_info.cursor_on) {
+ cursor = Tk_TextWidth(field_ptr->font, field_ptr->text,
+ field_ptr->insert_index);
+ }
+ if ((wi->text_info.sel_item == item) && (wi->text_info.sel_field == i) &&
+ (wi->text_info.sel_last >= 0) &&
+ (wi->text_info.sel_first <= num_chars)) {
+ sel_start = Tk_TextWidth(field_ptr->font, field_ptr->text,
+ wi->text_info.sel_first);
+ sel_stop = Tk_TextWidth(field_ptr->font, field_ptr->text,
+ wi->text_info.sel_last);
+ }
+
+ IntersectBBox(&fclip_bbox, &text_bbox, &tmp_bbox);
+
+ val = tmp_bbox.orig.x - text_bbox.orig.x;
+ restore |= val > 0;
+ val = tmp_bbox.orig.y - text_bbox.orig.y;
+ restore |= val > 0;
+ val = tmp_bbox.corner.x - text_bbox.corner.x;
+ restore |= val < 0;
+ val = tmp_bbox.corner.y - text_bbox.corner.y;
+ restore |= val < 0;
+ }
+
+ if (field_ptr->image != ZnUnspecifiedImage) {
+ ComputeFieldImageLocation(field_ptr, &bbox, &pm_bbox);
+
+ IntersectBBox(&fclip_bbox, &pm_bbox, &tmp_bbox);
+
+ val = tmp_bbox.orig.x - pm_bbox.orig.x;
+ restore |= val > 0;
+ val = tmp_bbox.orig.y - pm_bbox.orig.y;
+ restore |= val > 0;
+ val = tmp_bbox.corner.x - pm_bbox.corner.x;
+ restore |= val < 0;
+ val = tmp_bbox.corner.y - pm_bbox.corner.y;
+ restore |= val < 0;
+ }
+
+ /*restore = True;*/
+ if (restore) {
+ /* we must clip. */
+ /*printf("clip\n");*/
+ pts[0] = fclip_bbox.orig;
+ pts[1] = fclip_bbox.corner;
+ TRI_STRIP1(&tristrip, pts, 2);
+ ZnPushClip(wi, &tristrip, True, True);
+ }
+
+ (*cb)(wi, field_ptr, &bbox, &pm_bbox,
+ &text_pos, &text_bbox, cursor, sel_start, sel_stop);
+
+ if (restore) {
+ /* Restore the previous clip. */
+ ZnPopClip(wi, True);
+ restore = False;
+ }
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * DrawFields --
+ *
+ **********************************************************************************
+ */
+static void
+DrawField(WidgetInfo *wi,
+ Field field_ptr,
+ ZnBBox *bbox,
+ ZnBBox *pm_bbox,
+ ZnPoint *text_pos,
+ ZnBBox *text_bbox,
+ int cursor,
+ int sel_start,
+ int sel_stop)
+{
+ XGCValues values;
+ XRectangle r;
+ int j, xs, num_chars;
+
+ /*
+ * Draw the background.
+ */
+ if (ISSET(field_ptr->flags, FILLED_BIT)) {
+ values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->fill_color, 0.0, NULL));
+
+ if (field_ptr->tile != ZnUnspecifiedImage) { /* Fill tiled */
+ Pixmap pmap = GetImagePixmap(wi->win, field_ptr->tile_name,
+ field_ptr->tile, NULL);
+ values.fill_style = FillTiled;
+ values.tile = pmap;
+ values.ts_x_origin = (int) bbox->orig.x;
+ values.ts_y_origin = (int) bbox->orig.y;
+ XChangeGC(wi->dpy, wi->gc,
+ GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCTile,
+ &values);
+ }
+ else if (field_ptr->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */
+ values.fill_style = FillStippled;
+ values.stipple = field_ptr->fill_pattern;
+ values.ts_x_origin = (int) bbox->orig.x;
+ values.ts_y_origin = (int) bbox->orig.y;
+ XChangeGC(wi->dpy, wi->gc,
+ GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCStipple|GCForeground,
+ &values);
+ }
+ else { /* Fill solid */
+ values.fill_style = FillSolid;
+ XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle, &values);
+ }
+ BBox2XRect(bbox, &r);
+ XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height);
+ }
+
+ /*
+ * Draw the image and the text, which is in back depends on
+ * the value of text_on_top.
+ */
+ for (j = 0; j < 2; j++) {
+ if ((j == 0 && ISSET(field_ptr->flags, TEXT_ON_TOP_BIT)) ||
+ (j == 1 && ISCLEAR(field_ptr->flags, TEXT_ON_TOP_BIT))) {
+ /*
+ * Draw the image.
+ */
+ if (field_ptr->image != ZnUnspecifiedImage) {
+ Tk_RedrawImage(field_ptr->image,
+ 0, 0,
+ REAL_TO_INT(pm_bbox->corner.x - pm_bbox->orig.x),
+ REAL_TO_INT(pm_bbox->corner.y - pm_bbox->orig.y),
+ wi->draw_buffer,
+ pm_bbox->orig.x, pm_bbox->orig.y);
+ }
+ }
+ else {
+ /*
+ * Draw the text.
+ */
+ num_chars = strlen(field_ptr->text);
+ if (num_chars) {
+ if (sel_start >= 0) {
+ values.foreground = ZnPixel(ZnGetGradientColor(wi->text_info.sel_color, 0,
+ NULL));
+ XChangeGC(wi->dpy, wi->gc, GCForeground, &values);
+ XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc,
+ text_bbox->orig.x+sel_start, text_bbox->orig.y,
+ sel_stop-sel_start,
+ text_bbox->corner.y-text_bbox->orig.y);
+ }
+ values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->color, 0, NULL));
+ values.fill_style = FillSolid;
+ values.font = ZnFontId(field_ptr->font);
+ XChangeGC(wi->dpy, wi->gc, GCForeground | GCFillStyle | GCFont, &values);
+ Tk_DrawChars(wi->dpy, wi->draw_buffer, wi->gc, field_ptr->font,
+ field_ptr->text, num_chars,
+ text_pos->x, text_pos->y);
+ if (cursor >= 0) {
+ values.line_width = wi->text_info.insert_width;
+ values.foreground = ZnPixel(ZnGetGradientColor(wi->text_info.insert_color,
+ 0, NULL));
+ XChangeGC(wi->dpy, wi->gc, GCForeground|GCLineWidth, &values);
+ xs = text_bbox->orig.x + cursor;
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ xs, text_bbox->orig.y,
+ xs, text_bbox->corner.y);
+ }
+ }
+ }
+ }
+
+ BBox2XRect(bbox, &r);
+ /*
+ * Draw the border relief.
+ */
+ if ((field_ptr->relief != RELIEF_FLAT) && (field_ptr->relief_thickness > 1)) {
+ DrawRectangleRelief(wi, field_ptr->relief, field_ptr->gradient,
+ &r, (unsigned int) field_ptr->relief_thickness);
+ }
+
+ /*
+ * Draw the border line.
+ */
+ if (field_ptr->border_edges != NO_BORDER) {
+ values.foreground = ZnPixel(ZnGetGradientColor(field_ptr->border_color, 0, NULL));
+ values.line_width = 0;
+ values.line_style = LineSolid;
+ values.fill_style = FillSolid;
+ XChangeGC(wi->dpy, wi->gc,
+ GCForeground | GCLineWidth | GCLineStyle | GCFillStyle, &values);
+ if (field_ptr->border_edges & LEFT_BORDER) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y,
+ r.x, r.y + r.height - 1);
+ }
+ if (field_ptr->border_edges & RIGHT_BORDER) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ r.x + r.width - 1, r.y,
+ r.x + r.width - 1, r.y + r.height - 1);
+ }
+ if (field_ptr->border_edges & TOP_BORDER) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ r.x, r.y, r.x + r.width - 1, r.y);
+ }
+ if (field_ptr->border_edges & BOTTOM_BORDER) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ r.x, r.y + r.height - 1,
+ r.x + r.width - 1, r.y + r.height - 1);
+ }
+ if (field_ptr->border_edges & OBLIQUE) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ r.x, r.y, r.x + r.width - 1, r.y + r.height - 1);
+ }
+ if (field_ptr->border_edges & COUNTER_OBLIQUE) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ r.x, r.y + r.height - 1,
+ r.x + r.width - 1, r.y);
+ }
+ }
+}
+
+static void
+DrawFields(FieldSet field_set,
+ Item item)
+{
+ FieldsEngine(field_set, item, DrawField);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * RenderFields --
+ *
+ **********************************************************************************
+ */
+static void
+FieldRenderCB(void *closure)
+{
+#ifdef GLX
+ ZnBBox *bbox = (ZnBBox *) closure;
+
+ glBegin(GL_QUADS);
+ glVertex2f(bbox->orig.x, bbox->orig.y);
+ glVertex2f(bbox->orig.x, bbox->corner.y);
+ glVertex2f(bbox->corner.x, bbox->corner.y);
+ glVertex2f(bbox->corner.x, bbox->orig.y);
+ glEnd();
+#endif
+}
+
+static void
+RenderField(WidgetInfo *wi,
+ Field field_ptr,
+ ZnBBox *bbox,
+ ZnBBox *pm_bbox,
+ ZnPoint *text_pos,
+ ZnBBox *text_bbox,
+ int cursor,
+ int sel_start,
+ int sel_stop)
+{
+#ifdef GLX
+ int j, alpha, num_chars;
+ XColor *color;
+ ZnReal xs;
+
+ /*
+ * Draw the background.
+ */
+ if (ISSET(field_ptr->flags, FILLED_BIT)) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if (!ZnGradientFlat(field_ptr->fill_color)) {
+#if 0 /* TODO_GLX Faire le dégradé dans le fond des champs. */
+ int type = field_ptr->fill_color->type;
+ ZnBool fast = (type == ZN_AXIAL_GRADIENT) && !field_ptr->grad_geo;
+
+ RenderGradient(wi, field_ptr->fill_color,
+ fast ? NULL : FieldRenderCB,
+ bbox, fast ? (ZnPoint *) bbox : field_ptr->grad_geo);
+#endif
+ }
+ else {
+ if (field_ptr->tile != ZnUnspecifiedImage) { /* Fill tiled */
+ RenderTile(wi, GetImageTexture(wi->win, field_ptr->tile_name, field_ptr->tile),
+ field_ptr->fill_color, FieldRenderCB, bbox, (ZnPoint *) bbox);
+ }
+ else { /* Fill solid */
+ if (field_ptr->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */
+ /*
+ * Setup polygon stippling.
+ */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(GetBitmapMask(wi->dpy, field_ptr->fill_pattern)->pixels);
+ }
+ color = ZnGetGradientColor(field_ptr->fill_color, 0.0, &alpha);
+ alpha = ZnComposeAlpha(alpha, wi->alpha);
+ glColor4us(color->red, color->green, color->blue, alpha);
+ FieldRenderCB(bbox);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+
+ /*
+ * Draw the image and the text, which one is in back depends on
+ * the value of text_on_top.
+ */
+ for (j = 0; j < 2; j++) {
+ if ((j == 0 && ISSET(field_ptr->flags, TEXT_ON_TOP_BIT)) ||
+ (j == 1 && ISCLEAR(field_ptr->flags, TEXT_ON_TOP_BIT))) {
+ /*
+ * Draw the image.
+ */
+ if (field_ptr->image != ZnUnspecifiedImage) {
+ RenderImage(wi, GetImageTexture(wi->win, field_ptr->image_name,
+ field_ptr->image),
+ field_ptr->fill_color, &(pm_bbox->orig), False);
+ }
+ }
+ else {
+ /*
+ * Draw the text.
+ */
+ num_chars = strlen(field_ptr->text);
+ if (num_chars) {
+ if (!field_ptr->txf) {
+ field_ptr->txf = GetTexFont(wi->win, field_ptr->font);
+ }
+ if (field_ptr->txf) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if (sel_start >= 0) {
+ color = ZnGetGradientColor(wi->text_info.sel_color, 0, &alpha);
+ alpha = ZnComposeAlpha(alpha, wi->alpha);
+ glColor4us(color->red, color->green, color->blue, alpha);
+ glBegin(GL_QUADS);
+ glVertex2f(text_bbox->orig.x+sel_start, text_bbox->orig.y);
+ glVertex2f(text_bbox->orig.x+sel_stop, text_bbox->orig.y);
+ glVertex2f(text_bbox->orig.x+sel_stop, text_bbox->corner.y);
+ glVertex2f(text_bbox->orig.x+sel_start, text_bbox->corner.y);
+ glEnd();
+ }
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ color = ZnGetGradientColor(field_ptr->color, 0, &alpha);
+ alpha = ZnComposeAlpha(alpha, wi->alpha);
+ glColor4us(color->red, color->green, color->blue, alpha);
+ glBindTexture(GL_TEXTURE_2D, field_ptr->txf->texobj);
+ glPushMatrix();
+ glTranslatef(text_pos->x, text_pos->y, 0.0);
+ txfRenderString(field_ptr->txf, field_ptr->text, num_chars);
+ glPopMatrix();
+ glDisable(GL_TEXTURE_2D);
+ if (cursor >= 0) {
+ glLineWidth(wi->text_info.insert_width);
+ color = ZnGetGradientColor(wi->text_info.insert_color, 0, &alpha);
+ alpha = ZnComposeAlpha(alpha, wi->alpha);
+ glColor4us(color->red, color->green, color->blue, alpha);
+ xs = text_bbox->orig.x + cursor;
+ glBegin(GL_LINES);
+ glVertex2f(xs, text_bbox->orig.y);
+ glVertex2f(xs, text_bbox->corner.y);
+ glEnd();
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Draw the border relief.
+ */
+ if ((field_ptr->relief != RELIEF_FLAT) && (field_ptr->relief_thickness > 1)) {
+ ZnPoint p[5];
+
+ p[0].x = bbox->orig.x;
+ p[0].y = bbox->orig.y;
+ p[2].x = bbox->corner.x;
+ p[2].y = bbox->corner.y;
+ p[1].x = p[0].x;
+ p[1].y = p[2].y;
+ p[3].x = p[2].x;
+ p[3].y = p[0].y;
+ p[4] = p[0];
+ RenderPolygonRelief(wi, field_ptr->relief, field_ptr->gradient,
+ False, p, 5, field_ptr->relief_thickness);
+ }
+
+ /*
+ * Draw the border line.
+ */
+ if (field_ptr->border_edges != NO_BORDER) {
+ color = ZnGetGradientColor(field_ptr->border_color, 0, &alpha);
+ glColor4us(color->red, color->green, color->blue, alpha);
+ glLineWidth(1);
+ SetLineStyle(wi, LINE_SIMPLE);
+ glBegin(GL_LINES);
+ if (field_ptr->border_edges & LEFT_BORDER) {
+ glVertex2f(bbox->orig.x, bbox->orig.y);
+ glVertex2f(bbox->orig.x, bbox->corner.y);
+ }
+ if (field_ptr->border_edges & RIGHT_BORDER) {
+ glVertex2f(bbox->corner.x, bbox->orig.y);
+ glVertex2f(bbox->corner.x, bbox->corner.y);
+ }
+ if (field_ptr->border_edges & TOP_BORDER) {
+ glVertex2f(bbox->orig.x, bbox->orig.y);
+ glVertex2f(bbox->corner.x, bbox->orig.y);
+ }
+ if (field_ptr->border_edges & BOTTOM_BORDER) {
+ glVertex2f(bbox->orig.x, bbox->corner.y);
+ glVertex2f(bbox->corner.x, bbox->corner.y);
+ }
+ if (field_ptr->border_edges & OBLIQUE) {
+ glVertex2f(bbox->orig.x, bbox->orig.y);
+ glVertex2f(bbox->corner.x, bbox->corner.y);
+ }
+ if (field_ptr->border_edges & COUNTER_OBLIQUE) {
+ glVertex2f(bbox->orig.x, bbox->corner.y);
+ glVertex2f(bbox->corner.x, bbox->orig.y);
+ }
+ glEnd();
+ }
+#endif
+}
+
+static void
+RenderFields(FieldSet field_set,
+ Item item)
+{
+ FieldsEngine(field_set, item, RenderField);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * IsFieldsSensitive --
+ *
+ **********************************************************************************
+ */
+static ZnBool
+IsFieldSensitive(FieldSet field_set,
+ int part)
+{
+ if ((part >= 0) && (part < field_set->num_fields)) {
+ return ISSET(field_set->fields[part].flags, FIELD_SENSITIVE_BIT);
+ }
+ else {
+ return False;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldsPick --
+ * Return the first field that contains <x, y>.
+ * A field is selected if <x, y> is over a non transparent area.
+ * Such areas are : a solid filled background, a text, an icon.
+ * This does *NOT* do with *GLOBAL* visible and sensitive.
+ * But we need to take into account local field visible and
+ * sensitive as they modifiy local transparency. Local means
+ * within a single item.
+ *
+ **********************************************************************************
+ */
+static double
+FieldsPick(FieldSet field_set,
+ ZnPoint *p,
+ int *part)
+{
+ Field field_ptr;
+ ZnBBox bbox;
+ int i, best_field = 0;
+ double new_dist, dist = 1e40;
+
+ if (field_set->label_format) {
+ for (i = LabelFormatNumFields(field_set->label_format)-1; i >= 0; i--) {
+ field_ptr = &field_set->fields[i];
+
+ if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) &&
+ ISCLEAR(field_ptr->flags, FIELD_SENSITIVE_BIT)) {
+ continue;
+ }
+
+ GetFieldBBox(field_set, i, &bbox);
+
+ new_dist = RectangleToPointDist(&bbox, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ best_field = i;
+ }
+ if (dist <= 0.0) {
+ dist = 0.0;
+ break;
+ }
+ }
+ }
+
+ *part = best_field;
+ return dist;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldsToArea --
+ * Return -1 if no field is in the given area, 1 if they are
+ * all in it or 0 if there is some overlap. The function consider
+ * only fields that are either sensible or visible.
+ *
+ **********************************************************************************
+ */
+static int
+FieldsToArea(FieldSet field_set,
+ ZnBBox *area)
+{
+ Field field_ptr;
+ ZnBBox bbox;
+ int inside = -1;
+ int i;
+ ZnBool first_done = False;
+
+ for (i = LabelFormatNumFields(field_set->label_format)-1; i >= 0; i--) {
+ field_ptr = &field_set->fields[i];
+
+ if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT) &&
+ ISCLEAR(field_ptr->flags, FIELD_SENSITIVE_BIT)) {
+ continue;
+ }
+
+ GetFieldBBox(field_set, i, &bbox);
+ if (!first_done) {
+ first_done = True;
+ inside = BBoxInBBox(&bbox, area);
+ if (inside == 0) {
+ return 0;
+ }
+ }
+ else {
+ if (BBoxInBBox(&bbox, area) != inside) {
+ return 0;
+ }
+ }
+ }
+
+ return inside;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * SetFieldsAutoAlign --
+ *
+ **********************************************************************************
+ */
+static void
+SetFieldsAutoAlign(FieldSet fs,
+ int alignment)
+{
+ int i;
+ Field field;
+
+ if ((alignment >= AA_LEFT) && (alignment <= AA_RIGHT)) {
+ for (i = 0; i < fs->num_fields; i++) {
+ field = &fs->fields[i];
+ if (field->auto_alignment.automatic) {
+ field->alignment = field->auto_alignment.align[alignment];
+ }
+ }
+ }
+}
+
+static char *
+GetFieldStruct(FieldSet fs,
+ int field)
+{
+ if (field >= fs->num_fields) {
+ return NULL;
+ }
+ return (char *) &fs->fields[field];
+}
+
+
+static int
+NumFields(FieldSet fs)
+{
+ return fs->num_fields;
+}
+
+
+struct _FIELD FIELD = {
+ field_attrs,
+
+ InitFields,
+ CloneFields,
+ FreeFields,
+ ConfigureField,
+ QueryField,
+ DrawFields,
+ RenderFields,
+ FieldsToArea,
+ IsFieldSensitive,
+ FieldsPick,
+ FieldIndex,
+ FieldInsertChars,
+ FieldDeleteChars,
+ FieldCursor,
+ FieldSelection,
+ LeaderToLabel,
+ GetLabelBBox,
+ GetFieldBBox,
+ SetFieldsAutoAlign,
+ ClearFieldCache,
+ GetFieldStruct,
+ NumFields
+};