/* * Field.c -- Implementation of fields. * * Authors : Patrick Lecoanet. * Creation date : * * $Id$ */ /* * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- * * See the file "Copyright" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ #include "Item.h" #include "Types.h" #include "WidgetInfo.h" #include "Draw.h" #include "Geo.h" #include "tkZinc.h" #include #include 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; ZnGradient *border_color; char *text; ZnImage image; ZnImage tile; Tk_Font font; unsigned short flags; ZnBorder border_edges; Tk_Justify alignment; ZnReliefStyle relief; ZnDim relief_thickness; ZnAutoAlign auto_alignment; /* Private data */ ZnGradient *gradient; ZnPoint *grad_geo; short orig_x; short orig_y; short corner_x; short corner_y; int insert_index; #ifdef GL ZnTexFontInfo *tfi; #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_ALIGNMENT, "-alignment", NULL, Tk_Offset(FieldStruct, alignment), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_AUTO_ALIGNMENT, "-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_EDGE_LIST, "-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_BITMAP, "-fillpattern", NULL, Tk_Offset(FieldStruct, tile), 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), 0, ZN_COORDS_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_STRING, "-text", NULL, Tk_Offset(FieldStruct, text), 0, ZN_COORDS_FLAG|ZN_CLFC_FLAG, False }, { ZN_CONFIG_IMAGE, "-tile", NULL, Tk_Offset(FieldStruct, tile), 0, ZN_COORDS_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, False } }; static void GetLabelBBox(ZnFieldSet field_set, ZnDim *w, ZnDim *h); /* ********************************************************************************** * * ComputeFieldAttachment -- * Compute the location/size of the field, computing attachments if any. * ********************************************************************************** */ static void ComputeFieldAttachment(ZnFieldSet field_set, unsigned int field, ZnBBox *field_bbox) { ZnBBox ref_bbox; ZnDim real_width, real_height; unsigned 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 fptr; Tk_FontMetrics fm; /*printf("ComputeFieldAttachment in\n");*/ fptr = &field_set->fields[field]; if (ISSET(fptr->flags, CACHE_OK)) { field_bbox->orig.x = (ZnPos) fptr->orig_x; field_bbox->orig.y = (ZnPos) fptr->orig_y; field_bbox->corner.x = fptr->corner_x; field_bbox->corner.y = fptr->corner_y; /*printf("ComputeFieldAttachment in cache\n");*/ return; } /* * Preset this field to a default position/size and pretend * its cache is ok to break any deadlocks. */ fptr->orig_x = fptr->orig_y = 0; fptr->corner_x = fptr->corner_y = 0; field_bbox->orig.x = field_bbox->orig.y = 0; field_bbox->corner.x = field_bbox->corner.y = 0; SET(fptr->flags, CACHE_OK); num_fields = ZnLFNumFields(field_set->label_format); ZnLFGetField(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 ((fptr->image != ZnUnspecifiedImage) && ((x_dim == ZN_LF_DIM_ICON) || (y_dim == ZN_LF_DIM_ICON) || (x_dim == ZN_LF_DIM_AUTO) || (y_dim == ZN_LF_DIM_AUTO))) { ZnSizeOfImage(fptr->image, &icon_width, &icon_height); } switch (x_dim) { case ZN_LF_DIM_FONT: real_width = (ZnDim) (width_spec*Tk_TextWidth(fptr->font, "N", 1)/100); break; case ZN_LF_DIM_ICON: real_width = (ZnDim) (width_spec*icon_width/100); break; case ZN_LF_DIM_AUTO: { int len = 0; ZnDim text_width; if (fptr->text) { len = strlen(fptr->text); } real_width = 0.0; if (fptr->image != ZnUnspecifiedImage) { real_width = (ZnDim) icon_width; } if (len) { /* * The 4 extra pixels are needed for border and padding. */ text_width = (ZnDim) Tk_TextWidth(fptr->font, fptr->text, len) + 4; real_width = text_width < real_width ? real_width : text_width; } real_width += (ZnDim) width_spec; break; } case ZN_LF_DIM_LABEL: { ZnDim lh; GetLabelBBox(field_set, &real_width, &lh); break; } case ZN_LF_DIM_PIXEL: default: real_width = (ZnDim) width_spec; break; } /*printf("field %d, width = %g\n", field, real_width);*/ switch (y_dim) { case ZN_LF_DIM_FONT: { Tk_GetFontMetrics(fptr->font, &fm); real_height = (ZnDim) (height_spec*(fm.ascent + fm.descent)/100); break; } case ZN_LF_DIM_ICON: real_height = (ZnDim) (height_spec*icon_height/100); break; case ZN_LF_DIM_AUTO: { ZnDim text_height; real_height = 0.0; if (fptr->image != ZnUnspecifiedImage) { real_height = (ZnDim) icon_height; } if (fptr->text && strlen(fptr->text)) { Tk_GetFontMetrics(fptr->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 ZN_LF_DIM_LABEL: { ZnDim lw; GetLabelBBox(field_set, &lw, &real_height); break; } case ZN_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 = real_width; field_bbox->corner.y = real_height; fptr->corner_x = (short) real_width; fptr->corner_y = (short) real_height; /* * Then try to deduce the position, resolving any attachments * if needed. */ /* * Do the x axis. */ if (x_dim != ZN_LF_DIM_LABEL) { if (x_attach == ZN_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 >= num_fields) { ZnWarning ("Attached (x) to an inexistant field geometry\n"); } else { ComputeFieldAttachment(field_set, ref_field, &ref_bbox); switch (x_attach) { case ZN_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 ZN_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 ZN_LF_ATTACH_LEFT: field_bbox->orig.x = ref_bbox.orig.x; field_bbox->corner.x = field_bbox->orig.x + real_width; break; case ZN_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 != ZN_LF_DIM_LABEL) { if (y_attach == ZN_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 >= num_fields) { ZnWarning ("Attached (y) to an inexistant field geometry\n"); } else { ComputeFieldAttachment(field_set, ref_field, &ref_bbox); switch (y_attach) { case ZN_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 ZN_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 ZN_LF_ATTACH_LEFT: field_bbox->orig.y = ref_bbox.orig.y; field_bbox->corner.y = field_bbox->orig.y + real_height; break; case ZN_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);*/ } fptr->orig_x = (short) field_bbox->orig.x; fptr->orig_y = (short) field_bbox->orig.y; fptr->corner_x = (short) field_bbox->corner.x; fptr->corner_y = (short) field_bbox->corner.y; SET(fptr->flags, CACHE_OK); /*printf("ComputeFieldAttachment out\n");*/ } /* ********************************************************************************** * * 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(ZnFieldSet field_set, int field) { unsigned 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_set->num_fields) { return; } 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 = ZnLFNumFields(field_set->label_format); if ((unsigned int) field >= num_fields) { return; } ZnLFGetField(field_set->label_format, (unsigned int) field, &x_attach, &y_attach, &x_dim, &y_dim, &x_spec, &y_spec, &width_spec, &height_spec); if ((x_dim != ZN_LF_DIM_PIXEL) || (y_dim != ZN_LF_DIM_PIXEL)) { CLEAR(field_set->fields[field].flags, CACHE_OK); clear_bbox = True; } for (i = 0; i < num_fields; i++) { ZnLFGetField(field_set->label_format, i, &x_attach, &y_attach, &x_dim, &y_dim, &x_spec, &y_spec, &width_spec, &height_spec); if ((x_attach == ZN_LF_ATTACH_PIXEL) && (y_attach == ZN_LF_ATTACH_PIXEL)) { continue; } if (x_attach != ZN_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, (int) i); clear_bbox = True; } } if (y_attach != ZN_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, (int) i); clear_bbox = True; } } } if (clear_bbox) { field_set->label_width = field_set->label_height = -1.0; } } /* ********************************************************************************** * * GetLabelBBox -- * ********************************************************************************** */ static void GetLabelBBox(ZnFieldSet field_set, ZnDim *w, ZnDim *h) { ZnBBox bbox, tmp_bbox; ZnLabelFormat lf; unsigned int i, num_fields; ZnDim clip_w, clip_h; /*printf("GetLabelBBox in\n");*/ if ((field_set->label_width >= 0.0) && (field_set->label_height >= 0.0)) { *w = field_set->label_width; *h = field_set->label_height; /*printf("GetLabelBBox in cache\n");*/ return; } lf = field_set->label_format; if (lf == NULL) { *w = *h = field_set->label_width = field_set->label_height = 0.0; /*printf("GetLabelBBox no labelformat\n");*/ return; } ZnResetBBox(&bbox); num_fields = ZnLFNumFields(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);*/ ZnAddBBoxToBBox(&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 (ZnLFGetClipBox(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(ZnFieldSet field_set, unsigned int index, ZnBBox *field_bbox) { ZnReal ox, oy; /*printf("GetFieldBBox in\n");*/ if (field_set->label_format) { ox = ZnNearestInt(field_set->label_pos.x); oy = ZnNearestInt(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 { ZnResetBBox(field_bbox); } /*printf("GetFieldBBox out\n");*/ } /* ********************************************************************************** * * 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 fptr, ZnBBox *bbox, ZnPoint *pos, ZnBBox *text_bbox) { ZnDim w, h; Tk_FontMetrics fm; Tk_GetFontMetrics(fptr->font, &fm); w = 0; if (fptr->text) { int width; Tk_MeasureChars(fptr->font, fptr->text, strlen(fptr->text), -1, 0, &width); w = width; } 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 (fptr->alignment) { case TK_JUSTIFY_LEFT: text_bbox->orig.x = bbox->orig.x + 2; break; case TK_JUSTIFY_RIGHT: 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(ZnFieldSet field_set, ZnPoint *start, ZnPoint *end) { int b_num; ZnPoint delta, inf, sup; ZnPos xt=0, yu=0, yw=0, xv=0; Field fptr; unsigned 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 = (int) (start->y*delta.x - start->x*delta.y); for (i = 0; i < ZnLFNumFields(field_set->label_format); i++) { fptr = &field_set->fields[i]; /* * If the field is made invisible or has no graphics of * its own, don't clip. */ if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT) || (!fptr->text && ISCLEAR(fptr->flags, FILLED_BIT) && (fptr->border_edges == ZN_NO_BORDER) && (fptr->relief == ZN_RELIEF_FLAT) && (fptr->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. */ if (fptr->text && ISCLEAR(fptr->flags, FILLED_BIT) && (fptr->border_edges == ZN_NO_BORDER) && (fptr->relief == ZN_RELIEF_FLAT) && (fptr->image == ZnUnspecifiedImage)) { ZnBBox text_bbox; ZnPoint text_pos; /* dummy */ int space_width; int scan_forw, scan_back; space_width = Tk_TextWidth(fptr->font, " ", 1); ComputeFieldTextLocation(fptr, &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 -= fptr->font->per_char[fptr->text[0]].lbearing + 3; * text_bbox.width += fptr->font->per_char[fptr->text[0]].lbearing + 3; */ /* * Change bbox according to leading and trailing spaces. */ scan_forw = 0; while (fptr->text[scan_forw] == ' ') { /* leading spaces */ text_bbox.orig.x += space_width; scan_forw++; } /* * Empty text. */ if (!fptr->text || (fptr->text[scan_forw] == 0)) { continue; } scan_back = strlen(fptr->text)-1; while ((fptr->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); } } } } /* ********************************************************************************** * * InitFields -- * * Perform the init of each field in a ZnFieldSet. The number of such * fields must have been inited before calling this fun. * ********************************************************************************** */ static void InitFields(ZnFieldSet field_set) { ZnWInfo *wi = field_set->item->wi; Field field; unsigned int i, num_fields; /*printf("size of a field = %d\n", sizeof(FieldStruct));*/ 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->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->text = NULL; field->image = ZnUnspecifiedImage; field->tile = ZnUnspecifiedImage; field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font)); #ifdef GL field->tfi = ZnGetTexFont(wi, field->font); #endif field->border_edges = ZN_NO_BORDER; field->alignment = TK_JUSTIFY_LEFT; field->auto_alignment.automatic = False; field->relief = ZN_RELIEF_FLAT; field->relief_thickness = 2; SET(field->flags, TEXT_ON_TOP_BIT); field->gradient = NULL; field->grad_geo = NULL; } 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(ZnFieldSet field_set) { ZnWInfo *wi = field_set->item->wi; Field field, fields_ret; unsigned int i, num_fields; char *text; num_fields = field_set->num_fields; if (!num_fields) { return; } if (field_set->label_format) { field_set->label_format = ZnLFDuplicate(field_set->label_format); } 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) { field->image = ZnGetImageByValue(field->image, ZnUpdateItemImage, field_set->item); } if (field->tile != ZnUnspecifiedImage) { field->tile = ZnGetImageByValue(field->tile, ZnUpdateItemImage, field_set->item); } field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(field->font)); #ifdef GL field->tfi = ZnGetTexFont(wi, field->font); #endif field->color = ZnGetGradientByValue(field->color); field->fill_color = ZnGetGradientByValue(field->fill_color); field->border_color = ZnGetGradientByValue(field->border_color); if (field->text) { text = (char *) ZnMalloc((strlen(field->text) + 1) * sizeof(char)); strcpy(text, field->text); field->text = text; } } } /* ********************************************************************************** * * ConfigureField -- * ********************************************************************************** */ static int ConfigureField(ZnFieldSet fs, int field, int argc, Tcl_Obj *CONST argv[], int *flags) { unsigned int i; Field fptr; ZnBBox bbox; ZnWInfo *wi = fs->item->wi; XColor *color; unsigned short alpha; int old_num_chars, num_chars; #ifdef GL Tk_Font old_font; #endif if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { Tcl_AppendResult(wi->interp, "invalid field index", NULL); return TCL_ERROR; } fptr = &fs->fields[field]; #ifdef GL old_font = fptr->font; #endif old_num_chars = 0; if (fptr->text) { old_num_chars = Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)); } if (ZnConfigureAttributes(wi, fs->item, fptr, field_attrs, argc, argv, flags) == TCL_ERROR) { return TCL_ERROR; } num_chars = 0; if (fptr->text) { num_chars = Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)); } if (old_num_chars != num_chars) { ZnTextInfo *ti = &wi->text_info; /* * The text has changed, update the selection and * insertion pos to keep them valid. */ if ((fs->item == ti->sel_item) && (field == ti->sel_field)) { if (ti->sel_last > num_chars) { ti->sel_last = num_chars; } if (ti->sel_first >= ti->sel_last) { ti->sel_item = ZN_NO_ITEM; ti->sel_field = ZN_NO_PART; } if ((ti->anchor_item == fs->item) && (ti->anchor_field == field) && (ti->sel_anchor > num_chars)) { ti->sel_anchor = num_chars; } } if (fptr->insert_index > num_chars) { fptr->insert_index = num_chars; } } #ifdef GL if (old_font != fptr->font) { if (fptr->tfi) { ZnFreeTexFont(fptr->tfi); fptr->tfi = ZnGetTexFont(wi, fptr->font); } } #endif if (ISSET(*flags, ZN_REPICK_FLAG)) { SET(wi->flags, ZN_INTERNAL_NEED_REPICK); } if (ISSET(*flags, ZN_CLFC_FLAG)) { ClearFieldCache(fs, field); } if (fptr->gradient && (ISSET(*flags, ZN_BORDER_FLAG) || (fptr->relief == ZN_RELIEF_FLAT))) { ZnFreeGradient(fptr->gradient); fptr->gradient = NULL; } if ((fptr->relief != ZN_RELIEF_FLAT) && !fptr->gradient) { color = ZnGetGradientColor(fptr->border_color, 51.0, &alpha); fptr->gradient = ZnGetReliefGradient(wi->interp, wi->win, Tk_NameOfColor(color), alpha); if (fptr->gradient == NULL) { return TCL_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 < ZnLFNumFields(fs->label_format); i++) { if (i == (unsigned int) field) { GetFieldBBox(fs, i, &bbox); ZnDamage(wi, &bbox); break; } } } return TCL_OK; } /* ********************************************************************************** * * QueryField -- * ********************************************************************************** */ static int QueryField(ZnFieldSet fs, int field, int argc, Tcl_Obj *CONST argv[]) { if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { Tcl_AppendResult(fs->item->wi->interp, "invalid field index \"", NULL); return TCL_ERROR; } if (ZnQueryAttribute(fs->item->wi->interp, &fs->fields[field], field_attrs, argv[0]) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; } /* ********************************************************************************** * * FreeFields -- * ********************************************************************************** */ static void FreeFields(ZnFieldSet field_set) { unsigned int i, num_fields; Field field; if (field_set->label_format) { ZnLFDelete(field_set->label_format); } num_fields = field_set->num_fields; for (i = 0; i < num_fields; i++) { field = &field_set->fields[i]; if (field->text) { ZnFree(field->text); } if (field->gradient) { ZnFreeGradient(field->gradient); } if (field->grad_geo) { ZnFree(field->grad_geo); } if (field->image != ZnUnspecifiedImage) { ZnFreeImage(field->image, ZnUpdateItemImage, &field->image); field->image = ZnUnspecifiedImage; } if (field->tile != ZnUnspecifiedImage) { ZnFreeImage(field->tile, ZnUpdateItemImage, &field->tile); field->tile = ZnUnspecifiedImage; } Tk_FreeFont(field->font); #ifdef GL if (field->tfi) { ZnFreeTexFont(field->tfi); } #endif 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(ZnFieldSet fs, unsigned int field, int x, int y) { Field fptr; int byte_index; ZnBBox f_bbox, t_bbox; ZnPoint t_orig; unsigned int num_bytes, n, dummy; fptr = &fs->fields[field]; num_bytes = 0; byte_index = 0; if (fptr->text) { num_bytes = strlen(fptr->text); } if (num_bytes == 0) { return 0; } GetFieldBBox(fs, field, &f_bbox); ComputeFieldTextLocation(fptr, &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. */ byte_index = num_bytes; goto convrt; } n = Tk_MeasureChars(fptr->font, fptr->text, num_bytes, x + 2 - (int) t_bbox.orig.x, TK_PARTIAL_OK, &dummy); byte_index = n - 1; goto convrt; } /* * Point below all lines, return the index after * the last char. */ byte_index = num_bytes; convrt: return Tcl_NumUtfChars(fptr->text, byte_index); } static int WordMoveFromIndex(char *text, int index, int fwd) { char const *strp; if (!text) { return index; } strp = Tcl_UtfAtIndex(text, index); if (fwd) { while ((strp[1] == ' ') || (strp[1] == '\n')) { strp++; } while ((strp[1] != ' ') && (strp[1] != '\n') && strp[1]) { strp++; } return Tcl_NumUtfChars(text, strp + 1 - text); } else { while ((strp != text) && ((strp[-1] == ' ') || (strp[-1] == '\n'))) { strp--; } while ((strp != text) && (strp[-1] != ' ') && (strp[-1] != '\n')) { strp--; } return Tcl_NumUtfChars(text, strp - text); } } static int FieldIndex(ZnFieldSet fs, int field, Tcl_Obj *index_spec, int *index) { Field fptr; ZnWInfo *wi = fs->item->wi; ZnTextInfo *ti = &wi->text_info; unsigned int length; int c, x, y; double tmp; char *end, *p; if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { *index = 0; return TCL_OK; } fptr = &fs->fields[field]; p = Tcl_GetString(index_spec); c = p[0]; length = strlen(p); if ((c == 'e') && (strncmp(p, "end", length) == 0)) { *index = fptr->text ? Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)) : 0; } else if ((c == 'e') && (length > 1) && (strncmp(p, "eol", length) == 0)) { *index = fptr->text ? Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)) : 0; } else if ((c == 'b') && (length > 1) && (strncmp(p, "bol", length) == 0)) { *index = 0; } else if ((c == 'e') && (length > 1) && (strncmp(p, "eow", length) == 0)) { *index = WordMoveFromIndex(fptr->text, fptr->insert_index, 1); } else if ((c == 'b') && (length > 1) && (strncmp(p, "bow", length) == 0)) { *index = WordMoveFromIndex(fptr->text, fptr->insert_index, 0); } else if ((c == 'u') && (strncmp(p, "up", length) == 0)) { *index = fptr->insert_index; } else if ((c == 'd') && (strncmp(p, "down", length) == 0)) { *index = fptr->insert_index; } else if ((c == 'i') && (strncmp(p, "insert", length) == 0)) { *index = fptr->insert_index; } else if ((c == 's') && (strncmp(p, "sel.first", length) == 0) && (length >= 5)) { if ((ti->sel_item != fs->item) || (ti->sel_field != field)) { sel_err: Tcl_AppendResult(wi->interp, "selection isn't in field", (char *) NULL); return TCL_ERROR; } *index = ti->sel_first; } else if ((c == 's') && (strncmp(p, "sel.last", length) == 0) && (length >= 5)) { if ((ti->sel_item != fs->item) || (ti->sel_field != field)) { goto sel_err; } /* * We return a modified selection end so that it reflect * the text index of the last character _not_ the insertion * point between the last and the next. */ *index = ti->sel_last-1; } else if (c == '@') { p++; tmp = strtod(p, &end); if ((end == p) || (*end != ',')) { goto badIndex; } x = (int) tmp; p = end+1; tmp = strtod(p, &end); if ((end == p) || (*end != 0)) { goto badIndex; } y = (int) tmp; *index = FieldPointToChar(fs, (unsigned int) field, x, y); } else if (Tcl_GetIntFromObj(wi->interp, index_spec, index) == TCL_OK) { int num_chars = fptr->text ? Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)) : 0; 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 TCL_ERROR; } return TCL_OK; } static ZnBool FieldInsertChars(ZnFieldSet fs, int field, int *index, char *chars) { Field fptr; ZnTextInfo *ti = &fs->item->wi->text_info; int num_chars, num_bytes, chars_added; unsigned int byte_index, bytes_added = strlen(chars); char *new; if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { return False; } if (bytes_added == 0) { return False; } fptr = &fs->fields[field]; num_chars = 0; num_bytes = 0; if (fptr->text) { num_bytes = strlen(fptr->text); num_chars = Tcl_NumUtfChars(fptr->text, num_bytes); } if (*index < 0) { *index = 0; } if (*index > num_chars) { *index = num_chars; } chars_added = Tcl_NumUtfChars(chars, (int) bytes_added); if (fptr->text) { byte_index = Tcl_UtfAtIndex(fptr->text, *index) - fptr->text; new = ZnMalloc(num_bytes + bytes_added + 1); /* * Copy the part before and the part after the new * text (if any). */ memcpy(new, fptr->text, (size_t) byte_index); strcpy(new + byte_index + bytes_added, fptr->text + byte_index); ZnFree(fptr->text); } else { byte_index = 0; new = ZnMalloc(num_bytes + 1); new[num_bytes] = 0; } /* * Insert the new text. */ memcpy(new + byte_index, chars, bytes_added); fptr->text = new; if (fptr->insert_index >= *index) { fptr->insert_index += chars_added; } if ((ti->sel_item == fs->item) && (ti->sel_field == field)) { if (ti->sel_first >= *index) { ti->sel_first += chars_added; } if (ti->sel_last >= *index) { ti->sel_last += chars_added; } if ((ti->anchor_item == fs->item) && (ti->anchor_field == field) && (ti->sel_anchor >= *index)) { ti->sel_anchor += chars_added; } } /* * Need to redo the fields layout (maybe). */ ClearFieldCache(fs, field); return True; } static ZnBool FieldDeleteChars(ZnFieldSet fs, int field, int *first, int *last) { Field fptr; ZnTextInfo *ti = &fs->item->wi->text_info; unsigned int char_count, byte_count; unsigned int num_bytes, num_chars, first_offset; char *new; if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { return False; } fptr = &fs->fields[field]; num_chars = 0; num_bytes = 0; if (fptr->text) { num_bytes = strlen(fptr->text); num_chars = Tcl_NumUtfChars(fptr->text, (int) num_bytes); } if (num_chars == 0) { return False; } if (*first < 0) { *first = 0; } if (*last >= (int) num_chars) { *last = num_chars-1; } if (*first > *last) { return False; } char_count = *last + 1 - *first; first_offset = Tcl_UtfAtIndex(fptr->text, *first)-fptr->text; byte_count = Tcl_UtfAtIndex(fptr->text + first_offset, (int) char_count) - (fptr->text+first_offset); if (num_bytes - byte_count) { new = ZnMalloc(num_bytes + 1 - byte_count); memcpy(new, fptr->text, (size_t) first_offset); strcpy(new + first_offset, fptr->text + first_offset + byte_count); ZnFree(fptr->text); fptr->text = new; } else { ZnFree(fptr->text); fptr->text = NULL; } /* * Update the cursor to reflect the new string. */ if (fptr->insert_index > *first) { fptr->insert_index -= char_count; if (fptr->insert_index < *first) { fptr->insert_index = *first; } } if ((ti->sel_item == fs->item) && (ti->sel_field == field)) { if (ti->sel_first > *first) { ti->sel_first -= char_count; if (ti->sel_first < *first) { ti->sel_first = *first; } } if (ti->sel_last >= *first) { ti->sel_last -= char_count; if (ti->sel_last < *first - 1) { ti->sel_last = *first - 1; } } if (ti->sel_first > ti->sel_last) { ti->sel_item = ZN_NO_ITEM; } if ((ti->anchor_item == fs->item) && (ti->anchor_field == field) && (ti->sel_anchor > *first)) { ti->sel_anchor -= char_count; if (ti->sel_anchor < *first) { ti->sel_anchor = *first; } } } /* * Need to redo the fields layout (maybe). */ ClearFieldCache(fs, field); return True; } static void FieldCursor(ZnFieldSet fs, int field, int index) { Field fptr; int num_chars; if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { return; } fptr = &fs->fields[field]; num_chars = 0; if (fptr->text) { num_chars = Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)); } if (index < 0) { fptr->insert_index = 0; } else if (index > num_chars) { fptr->insert_index = num_chars; } else { fptr->insert_index = index; } } static int FieldSelection(ZnFieldSet fs, int field, int offset, char *chars, int max_bytes) { Field fptr; int count; char const *sel_first, *sel_last; ZnTextInfo *ti; if ((field < 0) || ((unsigned int) field >= fs->num_fields)) { return 0; } ti = &fs->item->wi->text_info; if ((ti->sel_first < 0) || (ti->sel_first > ti->sel_last)) { return 0; } fptr = &fs->fields[field]; if (!fptr->text) { return 0; } sel_first = Tcl_UtfAtIndex(fptr->text, ti->sel_first); sel_last = Tcl_UtfAtIndex(sel_first, ti->sel_last + 1 - ti->sel_first); count = sel_last - sel_first - offset; if (count <= 0) { return 0; } if (count > max_bytes) { count = max_bytes; } memcpy(chars, 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 fptr, ZnBBox *bbox, ZnBBox *pm_bbox) { int width, height; ZnSizeOfImage(fptr->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 (fptr->alignment) { case TK_JUSTIFY_LEFT: pm_bbox->orig.x = bbox->orig.x; break; case TK_JUSTIFY_RIGHT: 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(ZnFieldSet field_set, void (*cb)()) { ZnWInfo *wi = field_set->item->wi; /*int i; This one *NEED* to be an int */ unsigned int i, num_fields, num_chars; Field fptr; ZnTextInfo *ti = &wi->text_info; 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; int sel_start, sel_stop; if (!field_set->num_fields) { return; } if (field_set->label_format && ZnLFNumFields(field_set->label_format)) { bbox.orig.x = ZnNearestInt(field_set->label_pos.x); bbox.orig.y = ZnNearestInt(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) { ZnIntersectBBox(global_clip_box, &bbox, &lclip_bbox); if (ZnIsEmptyBBox(&lclip_bbox)) { return; } } else { lclip_bbox = bbox; } num_fields = ZnLFNumFields(field_set->label_format); for (i = 0; i < num_fields; i++) { fptr = &field_set->fields[i]; if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT)) { continue; } GetFieldBBox(field_set, i, &bbox); ZnIntersectBBox(&lclip_bbox, &bbox, &fclip_bbox); if (ZnIsEmptyBBox(&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; cursor = ((field_set->item == wi->focus_item) && ((unsigned int) wi->focus_field == i) && ISSET(wi->flags, ZN_GOT_FOCUS) && ti->cursor_on) ? 0 : -1; sel_start = -1, sel_stop = -1; ComputeFieldTextLocation(fptr, &bbox, &text_pos, &text_bbox); if (fptr->text) { if (cursor != -1) { cursor = Tk_TextWidth(fptr->font, fptr->text, Tcl_UtfAtIndex(fptr->text, fptr->insert_index)-fptr->text); } num_chars = Tcl_NumUtfChars(fptr->text, (int) strlen(fptr->text)); if (num_chars) { if ((field_set->item == ti->sel_item) && ((unsigned int) ti->sel_field == i) && (ti->sel_last >= 0) && (ti->sel_first <= (int) num_chars)) { sel_start = Tk_TextWidth(fptr->font, fptr->text, Tcl_UtfAtIndex(fptr->text, ti->sel_first)-fptr->text); sel_stop = Tk_TextWidth(fptr->font, fptr->text, Tcl_UtfAtIndex(fptr->text, ti->sel_last)-fptr->text); } ZnIntersectBBox(&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 (fptr->image != ZnUnspecifiedImage) { ComputeFieldImageLocation(fptr, &bbox, &pm_bbox); ZnIntersectBBox(&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: %d\n", i);*/ pts[0] = fclip_bbox.orig; pts[1] = fclip_bbox.corner; ZnTriStrip1(&tristrip, pts, 2, False); ZnPushClip(wi, &tristrip, True, True); } (*cb)(wi, fptr, &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(ZnWInfo *wi, Field fptr, ZnBBox *bbox, ZnBBox *pm_bbox, ZnPoint *text_pos, ZnBBox *text_bbox, int cursor, int sel_start, int sel_stop) { ZnTextInfo *ti = &wi->text_info; XGCValues values; XRectangle r; int j, xs, num_bytes; int pw, ph, fw, fh; TkRegion clip_region; ZnBool simple; Pixmap pixmap; TkRegion photo_region, clip; ZnBBox2XRect(bbox, &r); /* * Draw the background. */ if (ISSET(fptr->flags, FILLED_BIT)) { values.foreground = ZnGetGradientPixel(fptr->fill_color, 0.0); if (fptr->tile != ZnUnspecifiedImage) { if (!ZnImageIsBitmap(fptr->tile)) { /* Fill tiled */ values.fill_style = FillTiled; values.tile = ZnImagePixmap(fptr->tile, wi->win); 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 { /* Fill stippled */ values.fill_style = FillStippled; values.stipple = ZnImagePixmap(fptr->tile, wi->win); 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); } 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(fptr->flags, TEXT_ON_TOP_BIT)) || (j == 1 && ISCLEAR(fptr->flags, TEXT_ON_TOP_BIT))) { /* * Draw the image. */ if (fptr->image != ZnUnspecifiedImage) { pw = ZnNearestInt(pm_bbox->corner.x - pm_bbox->orig.x); ph = ZnNearestInt(pm_bbox->corner.y - pm_bbox->orig.y); fw = ZnNearestInt(bbox->corner.x - bbox->orig.x); fh = ZnNearestInt(bbox->corner.y - bbox->orig.y); pixmap = ZnImagePixmap(fptr->image, wi->win); photo_region = ZnImageRegion(fptr->image); ZnCurrentClip(wi, &clip_region, NULL, &simple); clip = TkCreateRegion(); /* * ZnImageRegion may fail: perl/Tk 800.24 doesn't support * some internal TkPhoto functions. * This is a workaround using a rectangular region based * on the image size. */ if (photo_region == NULL) { XRectangle rect; rect.x = rect.y = 0; rect.width = pw; rect.height = ph; TkUnionRectWithRegion(&rect, clip, clip); } else { ZnUnionRegion(clip, photo_region, clip); } ZnOffsetRegion(clip, (int) pm_bbox->orig.x, (int) pm_bbox->orig.y); TkIntersectRegion(clip_region, clip, clip); TkSetRegion(wi->dpy, wi->gc, clip); XCopyArea(wi->dpy, pixmap, wi->draw_buffer, wi->gc, (int) ZnNearestInt(bbox->orig.x-pm_bbox->orig.x), (int) ZnNearestInt(bbox->orig.y-pm_bbox->orig.y), (unsigned int) MIN(pw, fw), (unsigned int) MIN(ph, fh), (int) MAX(bbox->orig.x, pm_bbox->orig.x), (int) MAX(bbox->orig.y, pm_bbox->orig.y)); TkSetRegion(wi->dpy, wi->gc, clip_region); TkDestroyRegion(clip); } } else if (fptr->text) { /* * Draw the text. */ num_bytes = strlen(fptr->text); if (num_bytes) { if (sel_start >= 0) { values.foreground = ZnGetGradientPixel(ti->sel_color, 0.0); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle, &values); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, (int) (text_bbox->orig.x+sel_start), (int) text_bbox->orig.y, (unsigned int) (sel_stop-sel_start), (unsigned int) (text_bbox->corner.y-text_bbox->orig.y)); } values.foreground = ZnGetGradientPixel(fptr->color, 0.0); values.fill_style = FillSolid; values.font = Tk_FontId(fptr->font); XChangeGC(wi->dpy, wi->gc, GCForeground | GCFillStyle | GCFont, &values); Tk_DrawChars(wi->dpy, wi->draw_buffer, wi->gc, fptr->font, fptr->text, num_bytes, (int) text_pos->x, (int) text_pos->y); } } } if (cursor >= 0) { values.line_width = ti->insert_width; values.foreground = ZnGetGradientPixel(ti->insert_color, 0.0); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCForeground|GCLineWidth|GCFillStyle, &values); xs = (int) text_bbox->orig.x + cursor; XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, xs, (int) text_bbox->orig.y, xs, (int) text_bbox->corner.y); } /* * Draw the border relief. */ if ((fptr->relief != ZN_RELIEF_FLAT) && (fptr->relief_thickness > 1)) { ZnDrawRectangleRelief(wi, fptr->relief, fptr->gradient, &r, fptr->relief_thickness); } /* * Draw the border line. */ if (fptr->border_edges != ZN_NO_BORDER) { values.foreground = ZnGetGradientPixel(fptr->border_color, 0.0); values.line_width = 0; values.line_style = LineSolid; values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCForeground | GCLineWidth | GCLineStyle | GCFillStyle, &values); if (fptr->border_edges & ZN_LEFT_BORDER) { XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.x, r.y + r.height - 1); } if (fptr->border_edges & ZN_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 (fptr->border_edges & ZN_TOP_BORDER) { XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.x + r.width - 1, r.y); } if (fptr->border_edges & ZN_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 (fptr->border_edges & ZN_OBLIQUE) { XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.x + r.width - 1, r.y + r.height - 1); } if (fptr->border_edges & ZN_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(ZnFieldSet field_set) { FieldsEngine(field_set, DrawField); } /* ********************************************************************************** * * RenderFields -- * ********************************************************************************** */ #ifdef GL static void FieldRenderCB(void *closure) { ZnBBox *bbox = (ZnBBox *) closure; glBegin(GL_QUADS); glVertex2d(bbox->orig.x, bbox->orig.y); glVertex2d(bbox->orig.x, bbox->corner.y); glVertex2d(bbox->corner.x, bbox->corner.y); glVertex2d(bbox->corner.x, bbox->orig.y); glEnd(); } static void RenderField(ZnWInfo *wi, Field fptr, ZnBBox *bbox, ZnBBox *pm_bbox, ZnPoint *text_pos, ZnBBox *text_bbox, int cursor, int sel_start, int sel_stop) { unsigned short alpha; unsigned int j, num_bytes; XColor *color; ZnReal xs; ZnTextInfo *ti = &wi->text_info; ZnGLMakeCurrent(wi->dpy, wi); /* * Draw the background. */ if (ISSET(fptr->flags, FILLED_BIT)) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (!ZnGradientFlat(fptr->fill_color)) { #if 0 /* TODO_GL Faire le dégradé dans le fond des champs. */ int type = fptr->fill_color->type; ZnBool fast = (type == ZN_AXIAL_GRADIENT) && !fptr->grad_geo; RenderGradient(wi, fptr->fill_color, fast ? NULL : FieldRenderCB, bbox, fast ? (ZnPoint *) bbox : fptr->grad_geo); #endif } else { if (fptr->tile != ZnUnspecifiedImage) { /* Fill tiled/stippled */ ZnRenderTile(wi, fptr->tile, fptr->fill_color, FieldRenderCB, bbox, (ZnPoint *) bbox); } else { /* Fill solid */ color = ZnGetGradientColor(fptr->fill_color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); FieldRenderCB(bbox); } } } /* * Draw the image and the text, which one is back depends on * the value of text_on_top. */ for (j = 0; j < 2; j++) { if ((j == 0 && ISSET(fptr->flags, TEXT_ON_TOP_BIT)) || (j == 1 && ISCLEAR(fptr->flags, TEXT_ON_TOP_BIT))) { /* * Draw the image. */ if (fptr->image != ZnUnspecifiedImage) { ZnRenderIcon(wi, fptr->image, fptr->fill_color, &pm_bbox->orig, False); } } else if (fptr->text) { /* * Draw the text. */ num_bytes = strlen(fptr->text); if (num_bytes) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (sel_start >= 0) { color = ZnGetGradientColor(ti->sel_color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); glBegin(GL_QUADS); glVertex2d(text_bbox->orig.x+sel_start, text_bbox->orig.y); glVertex2d(text_bbox->orig.x+sel_stop, text_bbox->orig.y); glVertex2d(text_bbox->orig.x+sel_stop, text_bbox->corner.y); glVertex2d(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(fptr->color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); glBindTexture(GL_TEXTURE_2D, ZnTexFontTex(fptr->tfi)); glPushMatrix(); glTranslated(text_pos->x, text_pos->y, 0.0); ZnRenderString(fptr->tfi, fptr->text, num_bytes); glPopMatrix(); glDisable(GL_TEXTURE_2D); } } if (cursor >= 0) { glLineWidth((GLfloat) ti->insert_width); color = ZnGetGradientColor(ti->insert_color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); xs = text_bbox->orig.x + cursor; glBegin(GL_LINES); glVertex2d(xs, text_bbox->orig.y); glVertex2d(xs, text_bbox->corner.y); glEnd(); } } /* * Draw the border relief. */ if ((fptr->relief != ZN_RELIEF_FLAT) && (fptr->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]; ZnRenderPolygonRelief(wi, fptr->relief, fptr->gradient, False, p, 5, fptr->relief_thickness); } /* * Draw the border line. */ if (fptr->border_edges != ZN_NO_BORDER) { color = ZnGetGradientColor(fptr->border_color, 0.0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); glColor4us(color->red, color->green, color->blue, alpha); glLineWidth(1.5); ZnSetLineStyle(wi, ZN_LINE_SIMPLE); glBegin(GL_LINES); if (fptr->border_edges & ZN_LEFT_BORDER) { glVertex2d(bbox->orig.x, bbox->orig.y); glVertex2d(bbox->orig.x, bbox->corner.y); } if (fptr->border_edges & ZN_RIGHT_BORDER) { glVertex2d(bbox->corner.x, bbox->orig.y); glVertex2d(bbox->corner.x, bbox->corner.y); } if (fptr->border_edges & ZN_TOP_BORDER) { glVertex2d(bbox->orig.x, bbox->orig.y); glVertex2d(bbox->corner.x, bbox->orig.y); } if (fptr->border_edges & ZN_BOTTOM_BORDER) { glVertex2d(bbox->orig.x, bbox->corner.y); glVertex2d(bbox->corner.x, bbox->corner.y); } if (fptr->border_edges & ZN_OBLIQUE) { glVertex2d(bbox->orig.x, bbox->orig.y); glVertex2d(bbox->corner.x, bbox->corner.y); } if (fptr->border_edges & ZN_COUNTER_OBLIQUE) { glVertex2d(bbox->orig.x, bbox->corner.y); glVertex2d(bbox->corner.x, bbox->orig.y); } glEnd(); } } #endif #ifdef GL static void RenderFields(ZnFieldSet field_set) { /* glDisable(GL_LINE_SMOOTH);*/ FieldsEngine(field_set, RenderField); /* glEnable(GL_LINE_SMOOTH);*/ } #else static void RenderFields(ZnFieldSet field_set) { } #endif /* ********************************************************************************** * * PostScriptFields -- * ********************************************************************************** */ static int PsField(ZnWInfo *wi, ZnBool prepass, Field fptr, ZnBBox *bbox, ZnBBox *pm_bbox, ZnPoint *text_pos, ZnBBox *text_bbox) { int j; char path[250]; /* * Must set the clip rect for the whole field, not only for stipple fill. */ if (ISSET(fptr->flags, FILLED_BIT)) { if (fptr->tile != ZnUnspecifiedImage) { if (!ZnImageIsBitmap(fptr->tile)) { /* Fill tiled */ /* TODO No support yet */ } else { /* Fill stippled */ Tcl_AppendResult(wi->interp, "gsave\n", NULL); if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(fptr->fill_color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } if (Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, ZnImagePixmap(fptr->tile, wi->win)) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "grestore\n", NULL); } } else { /* Fill solid */ if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(fptr->fill_color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "fill\n", NULL); } } /* * 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(fptr->flags, TEXT_ON_TOP_BIT)) || (j == 1 && ISCLEAR(fptr->flags, TEXT_ON_TOP_BIT))) { /* * Draw the image. */ if (fptr->image != ZnUnspecifiedImage) { int w, h; Tcl_AppendResult(wi->interp, "gsave\n", NULL); sprintf(path, "%.15g %.15g translate 1 -1 scale\n", pm_bbox->orig.x, pm_bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); w = ZnNearestInt(pm_bbox->corner.x - pm_bbox->orig.x); h = ZnNearestInt(pm_bbox->corner.y - pm_bbox->orig.y); if (Tk_PostscriptImage(ZnImageTkImage(fptr->image), wi->interp, wi->win, wi->ps_info, 0, 0, w, h, prepass) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "grestore\n", NULL); } } else if (fptr->text) { Tcl_AppendResult(wi->interp, "gsave\n", NULL); if (Tk_PostscriptFont(wi->interp, wi->ps_info, fptr->font) != TCL_OK) { return TCL_ERROR; } if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(fptr->color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } /* * TODO pourquoi la text_bbox ne donne pas un texte centré verticalement ? * Apparement la fonte PostScript n'est pas centrée comme la fonte X. * Il faut donc opérer le calcul dans le code PostScript de DrawText. */ sprintf(path, "%.15g %.15g translate 1 -1 scale 0 0 [\n", text_bbox->orig.x, text_bbox->orig.y); Tcl_AppendResult(wi->interp, path, NULL); /* * strlen should do the work of counting _bytes_ in the utf8 string. */ ZnPostscriptString(wi->interp, fptr->text, strlen(fptr->text)); Tcl_AppendResult(wi->interp, "] 0 0.0 0.0 0.0 false DrawText\n", NULL); Tcl_AppendResult(wi->interp, "grestore\n", NULL); } } /* * Draw the border relief. */ if ((fptr->relief != ZN_RELIEF_FLAT) && (fptr->relief_thickness > 1)) { } /* * Draw the border line. */ if (fptr->border_edges != ZN_NO_BORDER) { if (Tk_PostscriptColor(wi->interp, wi->ps_info, ZnGetGradientColor(fptr->border_color, 0.0, NULL)) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "1 setlinewidth 0 setlinejoin 2 setlinecap\n", NULL); if (fptr->border_edges & ZN_LEFT_BORDER) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->orig.x, bbox->orig.y, bbox->orig.x, bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); } if (fptr->border_edges & ZN_RIGHT_BORDER) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->corner.x, bbox->orig.y, bbox->corner.x, bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); } if (fptr->border_edges & ZN_TOP_BORDER) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->orig.x, bbox->orig.y, bbox->corner.x, bbox->orig.y); Tcl_AppendResult(wi->interp, path, NULL); } if (fptr->border_edges & ZN_BOTTOM_BORDER) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->orig.x, bbox->corner.y, bbox->corner.x, bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); } if (fptr->border_edges & ZN_OBLIQUE) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->orig.x, bbox->orig.y, bbox->corner.x, bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); } if (fptr->border_edges & ZN_COUNTER_OBLIQUE) { sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", bbox->corner.x, bbox->orig.y, bbox->orig.x, bbox->corner.y); Tcl_AppendResult(wi->interp, path, NULL); } } return TCL_OK; } static int PostScriptFields(ZnFieldSet field_set, ZnBool prepass, ZnBBox *area) { ZnWInfo *wi = field_set->item->wi; ZnBBox lclip_bbox, fclip_bbox; ZnBBox bbox, text_bbox, pm_bbox; ZnPoint text_pos; int i, num_fields; ZnDim lwidth, lheight; Field fptr; char path[250]; if (!field_set->num_fields) { return TCL_OK; } if (field_set->label_format && ZnLFNumFields(field_set->label_format)) { /* * Fields are drawn with respect to a point already converted * to device space, so we need to reinstate the initial transform. */ Tcl_AppendResult(wi->interp, "/InitialTransform load setmatrix\n", NULL); lclip_bbox.orig.x = ZnNearestInt(field_set->label_pos.x); lclip_bbox.orig.y = ZnNearestInt(field_set->label_pos.y); GetLabelBBox(field_set, &lwidth, &lheight); lclip_bbox.corner.x = lclip_bbox.orig.x + lwidth; lclip_bbox.corner.y = lclip_bbox.orig.y + lheight; num_fields = ZnLFNumFields(field_set->label_format); for (i = 0; i < num_fields; i++) { fptr = &field_set->fields[i]; if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT)) { continue; } GetFieldBBox(field_set, i, &bbox); ZnIntersectBBox(&lclip_bbox, &bbox, &fclip_bbox); if (ZnIsEmptyBBox(&fclip_bbox)) { /* The field is outside the label bbox */ continue; } /* * Setup a clip area around the field */ Tcl_AppendResult(wi->interp, "gsave\n", NULL); sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto %.15g %.15g lineto %.15g %.15g", fclip_bbox.orig.x, fclip_bbox.orig.y, fclip_bbox.corner.x+1, fclip_bbox.orig.y, fclip_bbox.corner.x+1, fclip_bbox.corner.y+1, fclip_bbox.orig.x, fclip_bbox.corner.y+1); Tcl_AppendResult(wi->interp, path, " lineto closepath clip\n", NULL); if (fptr->text) { ComputeFieldTextLocation(fptr, &bbox, &text_pos, &text_bbox); } if (fptr->image != ZnUnspecifiedImage) { ComputeFieldImageLocation(fptr, &bbox, &pm_bbox); } if (PsField(wi, prepass, fptr, &bbox, &pm_bbox, &text_pos, &text_bbox) != TCL_OK) { return TCL_ERROR; } Tcl_AppendResult(wi->interp, "grestore\n", NULL); } } return TCL_OK; } /* ********************************************************************************** * * IsFieldsSensitive -- * ********************************************************************************** */ static ZnBool IsFieldSensitive(ZnFieldSet field_set, int part) { if ((part >= 0) && ((unsigned int) 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(ZnFieldSet field_set, ZnPoint *p, int *part) { Field fptr; ZnBBox bbox; unsigned int best_field = 0; int i; ZnReal new_dist, dist = 1e40; if (!field_set->num_fields) { return dist; } if (field_set->label_format) { for (i = ZnLFNumFields(field_set->label_format)-1; i >= 0; i--) { fptr = &field_set->fields[i]; if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT) && ISCLEAR(fptr->flags, FIELD_SENSITIVE_BIT)) { continue; } GetFieldBBox(field_set, (unsigned int) i, &bbox); new_dist = ZnRectangleToPointDist(&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(ZnFieldSet field_set, ZnBBox *area) { Field fptr; ZnBBox bbox; int i, inside = -1; ZnBool first_done = False; if (!field_set->num_fields) { return inside; } for (i = ZnLFNumFields(field_set->label_format)-1; i >= 0; i--) { fptr = &field_set->fields[i]; if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT) && ISCLEAR(fptr->flags, FIELD_SENSITIVE_BIT)) { continue; } GetFieldBBox(field_set, (unsigned int) i, &bbox); if (!first_done) { first_done = True; inside = ZnBBoxInBBox(&bbox, area); if (inside == 0) { return 0; } } else { if (ZnBBoxInBBox(&bbox, area) != inside) { return 0; } } } return inside; } /* ********************************************************************************** * * SetFieldsAutoAlign -- * ********************************************************************************** */ static void SetFieldsAutoAlign(ZnFieldSet fs, int alignment) { unsigned int i; Field field; if (!fs->num_fields) { return; } if ((alignment >= ZN_AA_LEFT) && (alignment <= ZN_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(ZnFieldSet fs, int field) { if ((unsigned int) field >= fs->num_fields) { return NULL; } return (char *) &fs->fields[field]; } static unsigned int NumFields(ZnFieldSet fs) { return fs->num_fields; } struct _ZnFIELD ZnFIELD = { field_attrs, InitFields, CloneFields, FreeFields, ConfigureField, QueryField, DrawFields, RenderFields, PostScriptFields, FieldsToArea, IsFieldSensitive, FieldsPick, FieldIndex, FieldInsertChars, FieldDeleteChars, FieldCursor, FieldSelection, LeaderToLabel, GetLabelBBox, GetFieldBBox, SetFieldsAutoAlign, ClearFieldCache, GetFieldStruct, NumFields };