From 737920a9203af23d93d9c8352737b93651392776 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Mon, 8 Apr 2002 13:46:42 +0000 Subject: *** empty log message *** --- generic/Field.c | 2212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ generic/Field.h | 99 +++ generic/Group.h | 45 ++ 3 files changed, 2356 insertions(+) create mode 100644 generic/Field.c create mode 100644 generic/Field.h create mode 100644 generic/Group.h 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 +#include +#ifdef GLX +#include +#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 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 . + * A field is selected if 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 +}; diff --git a/generic/Field.h b/generic/Field.h new file mode 100644 index 0000000..7aaae54 --- /dev/null +++ b/generic/Field.h @@ -0,0 +1,99 @@ +/* + * Field.h -- Header for field item parts. + * + * Authors : Patrick Lecoanet. + * Creation date : + * + * $Id$ + */ + +/* + * Copyright (c) 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. + * + */ + + +#ifndef _Field_h +#define _Field_h + +#include "Attrs.h" +#include "Types.h" +#include "List.h" +#include "Color.h" +#include "Image.h" + + +struct _ItemStruct; +struct _WidgetInfo; + + +/* + * Field array management record. + * + * This structure should be used only for internal + * management by items with fields. The rest of the code + * should use the methods in FIELD. + * + */ +typedef struct _FieldSetStruct { + struct _WidgetInfo *wi; + ZnLabelFormat label_format; + unsigned int num_fields; + struct _FieldStruct *fields; + ZnDim label_width; /* Describe the label size. Access these */ + ZnDim label_height; /* 2 only with GetLabelBBox. -1 means + * not up to date. */ + ZnPoint label_pos; /* Describe the label origin. */ +} FieldSetStruct, *FieldSet; + + + +extern struct _FIELD { + ZnAttrConfig *attr_desc; + + void (*InitFields)(FieldSet fs); + void (*CloneFields)(FieldSet fs); + void (*FreeFields)(FieldSet fs); + int (*ConfigureField)(FieldSet fs, unsigned int field, + int argc, Tcl_Obj *CONST argv[], int *flags); + int (*QueryField)(FieldSet fs, unsigned int field, + int argc, Tcl_Obj *CONST argv[]); + void (*DrawFields)(FieldSet fs, struct _ItemStruct *item); + void (*RenderFields)(FieldSet fs, struct _ItemStruct *item); + int (*FieldsToArea)(FieldSet fs, ZnBBox *area); + ZnBool (*IsFieldSensitive)(FieldSet fs, int part); + double (*FieldsPick)(FieldSet fs, ZnPoint *p, int *part); + int (*FieldIndex)(FieldSet fs, int field, + struct _ItemStruct *item, Tcl_Obj *index_spec, int *index); + void (*FieldInsertChars)(FieldSet fs, int field, int *index, char *chars); + void (*FieldDeleteChars)(FieldSet fs, int field, + int *first, int *last); + void (*FieldCursor)(FieldSet fs, int field, int index); + int (*FieldSelection)(FieldSet fs, int field, int offset, + char *chars, int max_chars); + void (*LeaderToLabel)(FieldSet fs, ZnPoint *start, ZnPoint *end); + void (*GetLabelBBox)(FieldSet fs, ZnDim *w, ZnDim *h); + void (*GetFieldBBox)(FieldSet fs, unsigned int index, + ZnBBox *field_bbox); + void (*SetFieldsAutoAlign)(FieldSet fs, int alignment); + void (*ClearFieldCache)(FieldSet fs, int field); + char *(*GetFieldStruct)(FieldSet fs, int field); + int (*NumFields)(FieldSet fs); +} FIELD; + + +#endif /* _Field_h */ diff --git a/generic/Group.h b/generic/Group.h new file mode 100644 index 0000000..de81eaf --- /dev/null +++ b/generic/Group.h @@ -0,0 +1,45 @@ +/* + * Group.h -- Header for Group items. + * + * Authors : Patrick Lecoanet. + * Creation date : + * + * $Id$ + */ + +/* + * Copyright (c) 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. + * + */ + + +#ifndef _Group_h +#define _Group_h + + +Item ZnGroupHead(Item group); +Item ZnGroupTail(Item group); +ZnBool ZnGroupCallOm(Item group); +void ZnGroupSetCallOm(Item group, ZnBool set); +void ZnInsertDependentItem(Item item); +void ZnExtractDependentItem(Item item); +void ZnDisconnectDependentItems(Item item); +void ZnGroupInsertItem(Item group, Item item, Item mark_item, ZnBool before); +void ZnGroupExtractItem(Item item); +void ZnGroupRemoveClip(Item group, Item clip); + +#endif /* _Group_h */ -- cgit v1.1