aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/Item.c4363
1 files changed, 4363 insertions, 0 deletions
diff --git a/generic/Item.c b/generic/Item.c
new file mode 100644
index 0000000..a81b16c
--- /dev/null
+++ b/generic/Item.c
@@ -0,0 +1,4363 @@
+/*
+ * Item.c -- Implementation of items.
+ *
+ * Authors : Patrick Lecoanet.
+ * Creation date :
+ *
+ * $Id$
+ */
+
+/*
+ * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet --
+ *
+ * This code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this code; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <limits.h> /* For INT_MAX */
+#include <sys/param.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Item.h"
+#include "Types.h"
+#include "WidgetInfo.h"
+#include "Geo.h"
+#include "Draw.h"
+#include "MapInfo.h"
+#include "Image.h"
+#include "Color.h"
+#include "tkRadar.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
+
+
+static RadarList item_classes = NULL;
+static RadarList item_stack = NULL;
+
+
+/*
+ * Field record.
+ */
+typedef struct _FieldStruct {
+ /* Public data */
+ RadarColor color;
+ RadarColor back_color;
+ RadarColor border_color;
+ Pixmap fill_pattern;
+ char *text;
+ char *image_name;
+ char *tile_name;
+ RadarFont font;
+ unsigned char flags;
+ Border border_edges;
+ RadarJustify alignment;
+ ReliefStyle relief;
+ int relief_thickness;
+ AutoAlign auto_alignment;
+
+ /* Private data */
+ RadarImage image;
+ RadarImage tile;
+ RadarColorGradient gradient;
+ short orig_x;
+ short orig_y;
+ short corner_x;
+ short corner_y;
+ FieldSet field_set;
+} FieldStruct, *Field;
+
+
+/*
+ * The -text, -image, -border, -relief, -visible and
+ * -filled attributes set the RADAR_COORDS_FLAG to update
+ * the leader that might protude if not clipped by the text.
+ */
+RadarAttrConfig field_attrs[] = {
+ { RADAR_CONFIG_JUSTIFY, "-alignment", NULL,
+ Tk_Offset(FieldStruct, alignment), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_AUTO_JUSTIFY, "-autoalignment", NULL,
+ Tk_Offset(FieldStruct, auto_alignment), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_COLOR, "-backcolor", NULL,
+ Tk_Offset(FieldStruct, back_color), 0,
+ RADAR_DRAW_FLAG|RADAR_BORDER_FLAG, False },
+ { RADAR_CONFIG_BORDER, "-border", NULL,
+ Tk_Offset(FieldStruct, border_edges), 0, RADAR_COORDS_FLAG, False },
+ { RADAR_CONFIG_COLOR, "-bordercolor", NULL,
+ Tk_Offset(FieldStruct, border_color), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_COLOR, "-color", NULL,
+ Tk_Offset(FieldStruct, color), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_BOOL, "-filled", NULL,
+ Tk_Offset(FieldStruct, flags), FILLED_BIT, RADAR_COORDS_FLAG, False },
+ { RADAR_CONFIG_PATTERN, "-fillpattern", NULL,
+ Tk_Offset(FieldStruct, fill_pattern), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_FONT|RADAR_CLFC_FLAG, "-font", NULL,
+ Tk_Offset(FieldStruct, font), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_IMAGE, "-image", NULL,
+ Tk_Offset(FieldStruct, image_name), 0,
+ RADAR_COORDS_FLAG|RADAR_IMAGE_FLAG|RADAR_CLFC_FLAG, False },
+ { RADAR_CONFIG_RELIEF, "-relief", NULL,
+ Tk_Offset(FieldStruct, relief), 0, RADAR_COORDS_FLAG, False },
+ { RADAR_CONFIG_DIM, "-reliefthickness", NULL,
+ Tk_Offset(FieldStruct, relief_thickness), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_BOOL, "-sensitive", NULL,
+ Tk_Offset(FieldStruct, flags), FIELD_SENSITIVE_BIT, RADAR_REPICK_FLAG, False },
+ { RADAR_CONFIG_TEXT, "-text", NULL,
+ Tk_Offset(FieldStruct, text), 0, RADAR_COORDS_FLAG, False },
+ { RADAR_CONFIG_IMAGE, "-tile", NULL,
+ Tk_Offset(FieldStruct, tile_name), 0,
+ RADAR_COORDS_FLAG|RADAR_TILE_FLAG|RADAR_CLFC_FLAG, False },
+ { RADAR_CONFIG_BOOL, "-visible", NULL,
+ Tk_Offset(FieldStruct, flags), FIELD_VISIBLE_BIT,
+ RADAR_COORDS_FLAG|RADAR_CLFC_FLAG, False }, /* Keep RADAR_COORDS_FLAG here */
+
+ { RADAR_CONFIG_END, NULL, NULL, 0, 0, 0 }
+};
+
+/*
+ * This array must be kept in sync with the
+ * corresponding defines in Types.h.
+ */
+static char *attribute_type_strings[] = {
+ "",
+ "color",
+ "boolean",
+ "pattern",
+ "text",
+ "font",
+ "border",
+ "relief",
+ "dimension",
+ "priority",
+ "justify",
+ "autojustify",
+ "lineend",
+ "labelformat",
+ "linestyle",
+ "lineshape",
+ "item",
+ "angle",
+ "integer",
+ "unsignedint",
+ "point",
+ "rectangle",
+ "patterns",
+ "anchor",
+ "tags",
+ "points",
+ "mapinfo",
+ "image",
+ "leaderanchors",
+ "JoinStyle",
+ "CapStyle"
+};
+
+
+/*
+ **********************************************************************************
+ *
+ * Forward functions
+ *
+ **********************************************************************************
+ */
+static void Damage(WidgetInfo *wi, RadarBBox *damage);
+static void Invalidate(Item item, int reason);
+static int ConfigureField(FieldSet field_set, unsigned int field,
+ int argc, RadarAttrList argv, int *flags);
+static int QueryField(FieldSet field_set, unsigned int field,
+ int argc, RadarAttrList argv);
+static Arg AttributeToString(WidgetInfo *wi, char *record, RadarAttrConfig *desc,
+ char *buffer, Tcl_FreeProc **free_proc);
+static void FieldImageChange(ClientData client_data, int x, int y, int width,
+ int height, int image_width, int image_height);
+static void FieldTileChange(ClientData client_data, int x, int y, int width,
+ int height, int image_width, int image_height);
+
+
+/*
+ **********************************************************************************
+ *
+ * InitAttrDesc --
+ *
+ **********************************************************************************
+ */
+static void
+InitAttrDesc(RadarAttrConfig *attr_desc)
+{
+ if (!attr_desc) {
+ return;
+ }
+
+ while (attr_desc->type != RADAR_CONFIG_END) {
+ attr_desc->uid = Tk_GetUid(attr_desc->name);
+ attr_desc++;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * AttributesInfo --
+ *
+ **********************************************************************************
+ */
+static int
+AttributesInfo(Item item,
+ int field, /* 0< means the item itself. */
+ int argc,
+ Arg *args)
+{
+ WidgetInfo *wi = item->wi;
+ char *record;
+ RadarAttrConfig *desc;
+ Tk_Uid attr_uid = NULL;
+#ifndef PTK
+ Arg entries[5];
+#else
+ Arg *entries;
+#endif
+ Arg result;
+ char buffer[256];
+ Tcl_FreeProc *free_proc;
+
+ if (field < 0) {
+ record = (char *) item;
+ desc = item->class->attr_desc;
+ }
+ else {
+ FieldSet field_set;
+ if (!item->class->has_fields) {
+ Tcl_AppendResult(wi->interp, "item class \"", item->class->name,
+ "\" doesn't support fields", NULL);
+ return RADAR_ERROR;
+ }
+ field_set = item->class->GetFieldSet(item);
+ if (field >= field_set->num_fields) {
+ Tcl_AppendResult(wi->interp, "invalid field index \"", NULL);
+ return RADAR_ERROR;
+ }
+ record = (char *) &field_set->fields[field];
+ desc = field_attrs;
+ }
+
+ if (argc == 1) {
+ attr_uid = Tk_GetUid(LangString(args[0]));
+
+ while (True) {
+ if (desc->type == RADAR_CONFIG_END) {
+ Tcl_AppendResult(wi->interp, "unknown attribute \"",
+ LangString(args[0]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ else if (attr_uid == desc->uid) {
+ break;
+ }
+ else {
+ desc++;
+ }
+ }
+#ifdef PTK
+ entries = LangAllocVec(5);
+ LangSetInt(&entries[2], desc->read_only ? 1 : 0);
+#else
+ entries[2] = desc->read_only ? "1" : "0";
+#endif
+ LangSetString(&entries[0], desc->name);
+ LangSetString(&entries[1], attribute_type_strings[desc->type]);
+ LangSetString(&entries[3], "");
+ LangSetArg(&entries[4], AttributeToString(wi, record, desc, buffer, &free_proc));
+ result = Tcl_Merge(5, entries);
+#ifndef PTK
+ if (free_proc == TCL_DYNAMIC) {
+ RadarFree(entries[4]);
+ }
+ Tcl_SetResult(wi->interp, result, TCL_DYNAMIC);
+#else
+ LangFreeVec(5, entries);
+ Tcl_ArgResult(wi->interp, result);
+#endif
+ }
+ else {
+ while (desc->type != RADAR_CONFIG_END) {
+#ifdef PTK
+ entries = LangAllocVec(5);
+ LangSetInt(&entries[2], desc->read_only ? 1 : 0);
+#else
+ entries[2] = desc->read_only ? "1" : "0";
+#endif
+ LangSetString(&entries[0], desc->name);
+ LangSetString(&entries[1], attribute_type_strings[desc->type]);
+ LangSetString(&entries[3], "");
+ LangSetArg(&entries[4], AttributeToString(wi, record, desc, buffer, &free_proc));
+ result = Tcl_Merge(5, entries);
+#ifndef PTK
+ if (free_proc == TCL_DYNAMIC) {
+ RadarFree(entries[4]);
+ }
+ Tcl_AppendElement(wi->interp, result);
+ RadarFree(result);
+#else
+ LangFreeVec(5, entries);
+ Tcl_AppendArg(wi->interp, result);
+#endif
+ desc++;
+ }
+ }
+
+ return TCL_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ConfigureAttributes --
+ *
+ **********************************************************************************
+ */
+static int
+ConfigureAttributes(char *record,
+ int field, /* 0< means item itself. */
+ int argc,
+ Arg *args,
+ int *flags)
+{
+ WidgetInfo *wi;
+ Item item = NULL;
+ int i;
+ Tk_Uid attr_uid;
+ RadarAttrConfig *desc;
+ RadarPtr valp;
+ RadarAttrConfig *attr_desc;
+ FieldSet field_set = NULL;
+
+
+ if (field < 0) {
+ item = (Item) record;
+ wi = item->wi;
+ attr_desc = item->class->attr_desc;
+ }
+ else {
+ field_set = (FieldSet) record;
+ wi = field_set->wi;
+ if (field >= field_set->num_fields) {
+ Tcl_AppendResult(wi->interp, "invalid field index \"", NULL);
+ return RADAR_ERROR;
+ }
+ record = (char *) &field_set->fields[field];
+ /*printf("record <0x%X>, field %d\n", record, field);*/
+ attr_desc = field_attrs;
+ }
+
+ for (i = 0; i < argc; i += 2) {
+ attr_uid = Tk_GetUid(LangString(args[i]));
+
+ desc = attr_desc;
+ while (True) {
+ if (desc->type == RADAR_CONFIG_END) {
+ /*printf("ERROR: record <0x%X>\n", record);*/
+ Tcl_AppendResult(wi->interp, "unknown attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ else if (attr_uid == desc->uid) {
+ if (desc->read_only) {
+ Tcl_AppendResult(wi->interp, "attribute \"",
+ LangString(args[i]), "\" can only be read", NULL);
+ return RADAR_ERROR;
+ }
+ valp = record + desc->offset;
+ /*printf("record <0x%X>, valp <0x%X>, offset %d\n", record, valp, desc->offset);*/
+ switch (desc->type) {
+ case RADAR_CONFIG_COLOR:
+ {
+ XColor *color;
+ Tk_Uid new_name = Tk_GetUid(LangString(args[i+1]));
+ char *name = NULL;
+ if (*((XColor **) valp)) {
+ name = RadarNameOfColor(*((XColor **) valp));
+ }
+ if (name != new_name) {
+ color = RadarGetColor(wi->interp, wi->win, new_name);
+ if (!color) {
+ Tcl_AppendResult(wi->interp, " color expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (*((XColor **) valp)) {
+ RadarFreeColor(*((XColor **) valp));
+ }
+ *((XColor **) valp) = color;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_BOOL:
+ {
+ int b;
+ if (Tcl_GetBoolean(wi->interp, args[i+1], &b) != RADAR_OK) {
+ Tcl_AppendResult(wi->interp, " boolean expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (b ^ (ISSET(*((char *) valp), desc->bool_bit) != 0)) {
+ ASSIGN(*((char *) valp), desc->bool_bit, b);
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_PATTERN:
+ {
+ Pixmap pattern = RadarUnspecifiedPattern;
+ char *name = "";
+ if (*((Pixmap *) valp) != RadarUnspecifiedPattern) {
+ name = Tk_NameOfBitmap(wi->dpy, *((Pixmap *) valp));
+ }
+ if (strcmp(name, LangString(args[i+1])) != 0) {
+ if (strlen(LangString(args[i+1])) != 0) {
+ pattern = Tk_GetBitmap(wi->interp, wi->win, Tk_GetUid(LangString(args[i+1])));
+ if (pattern == None) {
+ Tcl_AppendResult(wi->interp, " pattern expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ }
+ if (*((Pixmap *) valp) != RadarUnspecifiedPattern) {
+ Tk_FreeBitmap(wi->dpy, *((Pixmap *) valp));
+ }
+ *((Pixmap *) valp) = pattern;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_PATTERNS:
+ {
+ RadarList new_pat_list = NULL;
+ Pixmap *pats;
+ int num_pats, result, j;
+ Arg *elems;
+#ifdef PTK
+ LangFreeProc *freeProc = NULL;
+#endif
+
+ if (strlen(LangString(args[i+1])) != 0) {
+ result = Lang_SplitList(wi->interp, args[i+1], &num_pats, &elems, &freeProc);
+ if (result == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp,
+ " pattern list expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+#ifdef PTK
+ if (elems != NULL && freeProc) {
+ (*freeProc)(num_pats, elems);
+ }
+#endif
+ return RADAR_ERROR;
+ }
+ if (num_pats) {
+ new_pat_list = RadarListNew(num_pats, sizeof(Pixmap));
+ RadarListAssertSize(new_pat_list, num_pats);
+ pats = (Pixmap *) RadarListArray(new_pat_list);
+ for (j = 0; j < num_pats; j++) {
+ if (strlen(LangString(elems[j])) != 0) {
+ pats[j] = Tk_GetBitmap(wi->interp, wi->win,
+ Tk_GetUid(LangString(elems[j])));
+ if (pats[j] == None) {
+ Tcl_AppendResult(wi->interp,
+ " unknown pattern \"", LangString(elems[j]),
+ "\" in pattern list", NULL);
+ RadarListFree(new_pat_list);
+#ifndef PTK
+ RadarFree(elems);
+#else
+ if (freeProc) {
+ (*freeProc)(num_pats, elems);
+ }
+#endif
+ return RADAR_ERROR;
+ }
+ }
+ else {
+ pats[j] = RadarUnspecifiedPattern;
+ }
+ }
+ }
+ RadarFree(elems);
+ }
+ if (*((RadarList *) valp)) {
+ num_pats = RadarListSize(*((RadarList *) valp));
+ pats = (Pixmap *) RadarListArray(*((RadarList *) valp));
+ for (j = 0; j < num_pats; j++) {
+ if (pats[j] != RadarUnspecifiedPattern) {
+ Tk_FreeBitmap(wi->dpy, pats[j]);
+ }
+ }
+ RadarListFree(*((RadarList *) valp));
+ *((RadarList *) valp) = new_pat_list;
+ *flags |= desc->flags;
+ }
+ else {
+ if (new_pat_list) {
+ *((RadarList *) valp) = new_pat_list;
+ *flags |= desc->flags;
+ }
+ }
+ break;
+ }
+ case RADAR_CONFIG_TAGS:
+ {
+ int num_tags, result, j;
+ Arg *elems;
+#ifdef PTK
+ LangFreeProc *freeProc = NULL;
+#endif
+
+ if (strlen(LangString(args[i+1])) != 0) {
+ result = Lang_SplitList(wi->interp, args[i+1], &num_tags, &elems, &freeProc);
+ if (result == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp,
+ " tag list expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+#ifdef PTK
+ if (elems != NULL && freeProc) {
+ (*freeProc)(num_tags, elems);
+ }
+#endif
+ return RADAR_ERROR;
+ }
+ if (*((RadarList *) valp)) {
+ ITEM.FreeTags(item);
+ *flags |= desc->flags;
+ }
+ if (num_tags) {
+ for (j = 0; j < num_tags; j++) {
+ ITEM.AddTag(item, Tk_GetUid(LangString(elems[j])));
+ }
+ *flags |= desc->flags;
+ }
+#ifndef PTK
+ RadarFree(elems);
+#else
+ if (freeProc) {
+ (*freeProc)(num_tags, elems);
+ }
+#endif
+ }
+ break;
+ }
+ case RADAR_CONFIG_TEXT:
+ case RADAR_CONFIG_MAP_INFO:
+ case RADAR_CONFIG_IMAGE:
+ {
+ char *text = "";
+ if (strcmp(LangString(args[i+1]), *((char **) valp)) != 0) {
+ if (strlen(LangString(args[i+1])) != 0) {
+ text = (char *) RadarMalloc(strlen(LangString(args[i+1]))+1);
+ strcpy(text, LangString(args[i+1]));
+ }
+ if (strlen(*((char **) valp)) != 0) {
+ RadarFree(*((char **) valp));
+ }
+ *((char **) valp) = text;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_FONT:
+ {
+ Tk_Font font;
+ char *name = "";
+ if (*((Tk_Font *) valp)) {
+ name = Tk_NameOfFont(*((Tk_Font *) valp));
+ }
+ if (strcmp(name, LangString(args[i+1])) != 0) {
+ font = Tk_GetFont(wi->interp, wi->win, LangString(args[i+1]));
+ if (!font) {
+ Tcl_AppendResult(wi->interp, " font expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (*((Tk_Font *) valp)) {
+ Tk_FreeFont(*((Tk_Font *) valp));
+ }
+ *((Tk_Font *) valp) = font;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_BORDER:
+ {
+ Border border = NO_BORDER;
+ int j, len, largc, result;
+ Arg *largv;
+#ifdef PTK
+ LangFreeProc *freeProc = NULL;
+#endif
+
+ result = Lang_SplitList(wi->interp, args[i+1], &largc, &largv, &freeProc);
+ if (result == RADAR_ERROR) {
+ border_error:
+ Tcl_AppendResult(wi->interp, " border expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+#ifdef PTK
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ return RADAR_ERROR;
+ }
+ len = strlen(LangString(args[i+1]));
+ for (j = 0; j < largc; j++) {
+ if (strncasecmp(LangString(largv[j]), LEFT_SPEC, len) == 0) {
+ border |= LEFT_BORDER;
+ }
+ else if (strncasecmp(LangString(largv[j]), RIGHT_SPEC, len) == 0) {
+ border |= RIGHT_BORDER;
+ }
+ else if (strncasecmp(LangString(largv[j]), TOP_SPEC, len) == 0) {
+ border |= TOP_BORDER;
+ }
+ else if (strncasecmp(LangString(largv[j]), BOTTOM_SPEC, len) == 0) {
+ border |= BOTTOM_BORDER;
+ }
+ else if (strncasecmp(LangString(largv[j]), CONTOUR_SPEC, len) == 0) {
+ border |= CONTOUR_BORDER;
+ }
+ else if (strncasecmp(LangString(largv[j]), OBLIQUE_SPEC, len) == 0) {
+ border |= OBLIQUE;
+ }
+ else if (strncasecmp(LangString(largv[j]), COUNTER_OBLIQUE_SPEC, len) == 0) {
+ border |= COUNTER_OBLIQUE;
+ }
+ else if (strncasecmp(LangString(largv[j]), NO_BORDER_SPEC, len) == 0) {
+ border |= NO_BORDER;
+ }
+ else {
+#ifndef PTK
+ RadarFree(largv);
+#endif
+ goto border_error;
+ }
+ }
+#ifndef PTK
+ RadarFree(largv);
+#else
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ if (border != *((Border *) valp)) {
+ *((Border *) valp) = border;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LINE_SHAPE:
+ {
+ LineShape line_shape;
+ int len;
+ len = strlen(LangString(args[i+1]));
+ if (strncasecmp(LangString(args[i+1]), STRAIGHT_SPEC, len) == 0) {
+ line_shape = LINE_STRAIGHT;
+ }
+ else if (strncasecmp(LangString(args[i+1]), RIGHT_LIGHTNING_SPEC, len) == 0) {
+ line_shape = LINE_RIGHT_LIGHTNING;
+ }
+ else if (strncasecmp(LangString(args[i+1]), LEFT_LIGHTNING_SPEC, len) == 0) {
+ line_shape = LINE_LEFT_LIGHTNING;
+ }
+ else if (strncasecmp(LangString(args[i+1]), RIGHT_CORNER_SPEC, len) == 0) {
+ line_shape = LINE_LEFT_CORNER;
+ }
+ else if (strncasecmp(LangString(args[i+1]), LEFT_CORNER_SPEC, len) == 0) {
+ line_shape = LINE_LEFT_CORNER;
+ }
+ else if (strncasecmp(LangString(args[i+1]), DOUBLE_RIGHT_CORNER_SPEC, len) == 0) {
+ line_shape = LINE_DOUBLE_LEFT_CORNER;
+ }
+ else if (strncasecmp(LangString(args[i+1]), DOUBLE_LEFT_CORNER_SPEC, len) == 0) {
+ line_shape = LINE_DOUBLE_LEFT_CORNER;
+ }
+ else {
+ Tcl_AppendResult(wi->interp, " line shape expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (line_shape != *((LineShape *) valp)) {
+ *((LineShape *) valp) = line_shape;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LINE_STYLE:
+ {
+ LineStyle line_style;
+ int len;
+ len = strlen(LangString(args[i+1]));
+ if (strncasecmp(LangString(args[i+1]), SIMPLE_SPEC, len) == 0)
+ line_style = LINE_SIMPLE;
+ else if (strncasecmp(LangString(args[i+1]), DASHED_SPEC, len) == 0)
+ line_style = LINE_DASHED;
+ else if (strncasecmp(LangString(args[i+1]), MIXED_SPEC, len) == 0)
+ line_style = LINE_MIXED;
+ else if (strncasecmp(LangString(args[i+1]), DOTTED_SPEC, len) == 0)
+ line_style = LINE_DOTTED;
+ else {
+ Tcl_AppendResult(wi->interp, " line style expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (line_style != *((LineStyle *) valp)) {
+ *((LineStyle *) valp) = line_style;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LINE_END:
+ {
+ LineEnd line_end = NULL;
+ char *ptr = LangString(args[i+1]);
+ if (strlen(ptr) != 0) {
+ line_end = LineEndCreate(wi->interp, LangString(args[i+1]));
+ if (line_end == NULL) {
+ return RADAR_ERROR;
+ }
+ }
+ if (*((LineEnd *) valp) != NULL) {
+ LineEndDelete(*((LineEnd *) valp));
+ *((LineEnd *) valp) = line_end;
+ *flags |= desc->flags;
+ }
+ else {
+ if (line_end != NULL) {
+ *((LineEnd *) valp) = line_end;
+ *flags |= desc->flags;
+ }
+ }
+ break;
+ }
+ case RADAR_CONFIG_RELIEF:
+ {
+ int relief;
+ if (Tk_GetRelief(wi->interp, LangString(args[i+1]), &relief) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " relief expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (relief != *((ReliefStyle *) valp)) {
+ /*printf("valp <0x%X>, flags <0x%X>, relief %d\n", valp, flags, relief);*/
+ *((ReliefStyle *) valp) = relief;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_JOIN_STYLE:
+ {
+ int join;
+ if (Tk_GetJoinStyle(wi->interp, LangString(args[i+1]), &join) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " join expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (join != *((int *) valp)) {
+ *((int *) valp) = join;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_CAP_STYLE:
+ {
+ int cap;
+ if (Tk_GetCapStyle(wi->interp, LangString(args[i+1]), &cap) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " cap expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (cap != *((int *) valp)) {
+ *((int *) valp) = cap;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_POINT:
+ {
+ RadarPoint point;
+ int largc, result;
+ Arg *largv;
+#ifdef PTK
+ LangFreeProc *freeProc = NULL;
+#endif
+
+ result = Lang_SplitList(wi->interp, args[i+1], &largc, &largv, &freeProc);
+ if (result == RADAR_ERROR || largc != 2) {
+ point_error:
+#ifdef PTK
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ Tcl_AppendResult(wi->interp, " position expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if ((Tcl_GetDouble(wi->interp, largv[0], &point.x) == RADAR_ERROR) ||
+ (Tcl_GetDouble(wi->interp, largv[1], &point.y) == RADAR_ERROR)) {
+#ifndef PTK
+ RadarFree(largv);
+#endif
+ goto point_error;
+ }
+#ifndef PTK
+ RadarFree(largv);
+#else
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ if ((point.x != ((RadarPoint *) valp)->x) ||
+ (point.y != ((RadarPoint *) valp)->y)) {
+ *((RadarPoint *) valp) = point;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_RECT:
+ {
+ RadarRect rect;
+ int largc, result;
+ Arg *largv;
+#ifdef PTK
+ LangFreeProc *freeProc = NULL;
+#endif
+
+ result = Lang_SplitList(wi->interp, args[i+1], &largc, &largv, &freeProc);
+ if (result == RADAR_ERROR || largc != 4) {
+ rect_error:
+#ifdef PTK
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ Tcl_AppendResult(wi->interp, " rectangle expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if ((Tcl_GetDouble(wi->interp, largv[0], &rect.x) == RADAR_ERROR) ||
+ (Tcl_GetDouble(wi->interp, largv[1], &rect.y) == RADAR_ERROR) ||
+ (Tcl_GetDouble(wi->interp, largv[2], &rect.w) == RADAR_ERROR) ||
+ (Tcl_GetDouble(wi->interp, largv[3], &rect.h) == RADAR_ERROR)) {
+#ifndef PTK
+ RadarFree(largv);
+#endif
+ goto rect_error;
+ }
+#ifndef PTK
+ RadarFree(largv);
+#else
+ if (largv != NULL && freeProc) {
+ (*freeProc)(largc, largv);
+ }
+#endif
+ if ((rect.x != ((RadarRect *) valp)->x) &&
+ (rect.y != ((RadarRect *) valp)->y) &&
+ (rect.w != ((RadarRect *) valp)->w) &&
+ (rect.h != ((RadarRect *) valp)->h)) {
+ *((RadarRect *) valp) = rect;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_DIM:
+ {
+ int size;
+ if (Tk_GetPixels(wi->interp, wi->win, LangString(args[i+1]), &size) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " dimension expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (size != *((int *) valp)) {
+ *((int *) valp) = size;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_PRI:
+ {
+ int pri;
+ if (Tcl_GetInt(wi->interp, args[i+1], &pri) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+ if (pri < 0) {
+ Tcl_AppendResult(wi->interp, " priority must be a positive integer \"",
+ LangString(args[i+1]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (pri != *((int *) valp)) {
+ *((int *) valp) = pri;
+ ITEM.UpdateItemPriority((Item) record, RADAR_NO_ITEM, True);
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_ITEM:
+ /*
+ * Can be an item id or a tag. In this last case
+ * consider only the first item (unspecified order)
+ * associated with the tag.
+ */
+ {
+ Item item2;
+ int num;
+ if (strlen(LangString(args[i+1])) == 0) {
+ item2 = RADAR_NO_ITEM;
+ }
+ else {
+ num = RadarItemsWithTagOrId(wi, LangString(args[i+1]), &item2, NULL);
+ if (num == 0) {
+ return RADAR_ERROR;
+ }
+ }
+ if (item2 != *((Item *) valp)) {
+ *((Item *) valp) = item2;
+ *flags |= desc->flags;
+ }
+ }
+ break;
+ case RADAR_CONFIG_INT:
+ case RADAR_CONFIG_UINT:
+ case RADAR_CONFIG_ANGLE:
+ {
+ int integer;
+ if (Tcl_GetInt(wi->interp, args[i+1], &integer) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+ if (desc->type == RADAR_CONFIG_ANGLE) {
+ if ((integer < 0) || (integer > 360)) {
+ Tcl_AppendResult(wi->interp, " angle must be between 0 and 360 \"",
+ LangString(args[i+1]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ }
+ else if (desc->type == RADAR_CONFIG_UINT) {
+ if (integer < 0) {
+ Tcl_AppendResult(wi->interp, " positive integer expected for \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ }
+ if (integer != *((int *) valp)) {
+ *((int *) valp) = integer;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_JUSTIFY:
+ {
+ Tk_Justify justify;
+ if (Tk_GetJustify(wi->interp, LangString(args[i+1]), &justify) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " justify expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (justify != *((RadarJustify *) valp)) {
+ *((RadarJustify *) valp) = justify;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_ANCHOR:
+ {
+ Tk_Anchor anchor;
+ if (Tk_GetAnchor(wi->interp, LangString(args[i+1]), &anchor) == RADAR_ERROR) {
+ Tcl_AppendResult(wi->interp, " anchor expected for attribute \"",
+ LangString(args[i]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ if (anchor != *((RadarAnchor *) valp)) {
+ *((RadarAnchor *) valp) = anchor;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LABEL_FORMAT:
+ {
+ LabelFormat frmt = NULL;
+ char *ptr = LangString(args[i+1]);
+
+ while (*ptr && (*ptr == ' ')) {
+ ptr++;
+ }
+ if (strlen(ptr) != 0) {
+ frmt = LabelFormatCreate(wi->interp, ptr,
+ item->class->GetFieldSet(item)->num_fields);
+ if (frmt == NULL) {
+ return RADAR_ERROR;
+ }
+ }
+
+ if (*((LabelFormat *) valp) != NULL) {
+ LabelFormatDelete(*((LabelFormat *) valp));
+ *((LabelFormat *) valp) = frmt;
+ *flags |= desc->flags;
+ }
+ else {
+ if (frmt != NULL) {
+ *((LabelFormat *) valp) = frmt;
+ *flags |= desc->flags;
+ }
+ }
+ break;
+ }
+
+ case RADAR_CONFIG_AUTO_JUSTIFY:
+ {
+ AutoAlign aa;
+ int j;
+ if (strcmp(LangString(args[i+1]), "-") == 0) {
+ aa.automatic = False;
+ }
+ else if (strlen(LangString(args[i+1])) == 3) {
+ aa.automatic = True;
+ for (j = 0; j < 3; j++) {
+ switch(LangString(args[i+1])[j]) {
+ case 'l':
+ case 'L':
+ aa.align[j] = RadarJustifyLeft;
+ break;
+ case 'c':
+ case 'C':
+ aa.align[j] = RadarJustifyCenter;
+ break;
+ case 'r':
+ case 'R':
+ aa.align[j] = RadarJustifyRight;
+ break;
+ default:
+ Tcl_AppendResult(wi->interp, "invalid auto justify specifcation \"",
+ LangString(args[i+1]), "\" should be - or a triple of lcr", NULL);
+ return RADAR_ERROR;
+ }
+ }
+ }
+ else {
+ Tcl_AppendResult(wi->interp, "invalid auto alignment specification \"",
+ LangString(args[i+1]), "\" should be - or a triple of lcr", NULL);
+ return RADAR_ERROR;
+ }
+ if ((aa.automatic != ((AutoAlign *) valp)->automatic) ||
+ (aa.align[0] != ((AutoAlign *) valp)->align[0]) ||
+ (aa.align[1] != ((AutoAlign *) valp)->align[1]) ||
+ (aa.align[2] != ((AutoAlign *) valp)->align[2])) {
+ *((AutoAlign *) valp) = aa;
+ *flags |= desc->flags;
+ }
+ break;
+ }
+
+ case RADAR_CONFIG_LEADER_ANCHORS:
+ /*
+ * Format is: lChar leftLeaderAnchor [ lChar rightLeaderAnchor]
+ *
+ * If lChar is a '|', leftLeaderAnchor and rightLeaderAnchor are the indices
+ * of the fields that serve to anchor the label's leader. More specifically
+ * the bottom left corner of the left field and the bottom right corner of
+ * the right field are used as the anchors.
+ * If lChar is '%', leftLeaderAnchor and rightLeaderAnchor should be specified
+ * as 'valxval', 'val' being a percentage (max 100) of the width/height of
+ * the label bounding box. If rightLeaderAnchor is not specified it defaults to
+ * field 0. If rightLeaderField is not specified it defaults to
+ * leftLeaderAnchor. If neither of them are specified, the center of the label
+ * is used as an anchor.
+ *
+ */
+ {
+ LeaderAnchors lanch = NULL;
+ int anchors[4];
+ int index, num_tok, anchor_index=0;
+ char *ptr = LangString(args[i+1]);
+
+ while (*ptr && (*ptr == ' ')) {
+ ptr++;
+ }
+ while (!*ptr && (anchor_index < 4)) {
+ switch (*ptr) {
+ case '|':
+ num_tok = sscanf(ptr, "|%d%n", &anchors[anchor_index], &index);
+ if (num_tok != 1) {
+ la_error:
+ Tcl_AppendResult(wi->interp, " incorrect leader anchors \"",
+ LangString(args[i+1]), "\"", NULL);
+ return RADAR_ERROR;
+ }
+ anchors[anchor_index+1] = -1;
+ break;
+ case '%':
+ num_tok = sscanf(ptr, "%%%dx%d%n", &anchors[anchor_index],
+ &anchors[anchor_index+1], &index);
+ if (num_tok != 2) {
+ goto la_error;
+ }
+ if (anchors[anchor_index] < 0) {
+ anchors[anchor_index] = 0;
+ }
+ if (anchors[anchor_index] > 100) {
+ anchors[anchor_index] = 100;
+ }
+ if (anchors[anchor_index+1] < 0) {
+ anchors[anchor_index+1] = 0;
+ }
+ if (anchors[anchor_index+1] > 100) {
+ anchors[anchor_index+1] = 100;
+ }
+ break;
+ }
+ anchor_index += 2;
+ ptr += index;
+ }
+ /*
+ * If empty, pick the default (center of the bounding box).
+ */
+ if (anchor_index != 0) {
+ lanch = (LeaderAnchors ) RadarMalloc(sizeof(LeaderAnchorsStruct));
+ lanch->left_x = anchors[0];
+ lanch->left_y = anchors[1];
+ if (anchor_index == 2) {
+ lanch->right_x = lanch->left_x;
+ lanch->right_y = lanch->left_y;
+ }
+ else {
+ lanch->right_x = anchors[2];
+ lanch->right_y = anchors[3];
+ }
+ }
+ if (*((LeaderAnchors *) valp) != NULL) {
+ RadarFree(*((LeaderAnchors *) valp));
+ *((LeaderAnchors *) valp) = lanch;
+ *flags |= desc->flags;
+ }
+ else {
+ if (lanch != NULL) {
+ *((LeaderAnchors *) valp) = lanch;
+ *flags |= desc->flags;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ else {
+ desc++;
+ }
+ }
+ }
+ return RADAR_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * AttributeToString --
+ *
+ * Returns the string representation of the attribute pointed
+ * by 'valp'. The attribute type is given by 'type'. The function
+ * never fail. The buffer parameter should be able to
+ * contain 256 characters at least.
+ *
+ **********************************************************************************
+ */
+static Arg
+AttributeToString(WidgetInfo *wi,
+ char *record,
+ RadarAttrConfig *desc,
+ char *buffer,
+ Tcl_FreeProc **free_proc)
+{
+#ifndef PTK
+#define NUM_ELEMS 10
+ Arg elems[NUM_ELEMS];
+#endif
+ Arg *el_ptr;
+ Arg result = NULL;
+ char *valp = record + desc->offset;
+
+ *free_proc = TCL_STATIC;
+
+ switch (desc->type) {
+ case RADAR_CONFIG_COLOR:
+ LangSetString(&result, "");
+ if (*((XColor **) valp)) {
+ LangSetString(&result, RadarNameOfColor(*((XColor **) valp)));
+ }
+ break;
+ case RADAR_CONFIG_BOOL:
+#ifndef PTK
+ result = ISSET(*((char *) valp), desc->bool_bit) ? "1" : "0";
+#else
+ LangSetInt(&result, ISSET(*((char *) valp), desc->bool_bit) ? 1 : 0);
+#endif
+ break;
+ case RADAR_CONFIG_PATTERN:
+ LangSetString(&result, "");
+ if (*((Pixmap *) valp)) {
+ LangSetString(&result, Tk_NameOfBitmap(wi->dpy, *((Pixmap *) valp)));
+ }
+ break;
+ case RADAR_CONFIG_PATTERNS:
+ {
+ int num_pats, i;
+ Pixmap *pats;
+
+ if (*((RadarList *) valp)) {
+ pats = (Pixmap *) RadarListArray(*((RadarList *) valp));
+ num_pats = RadarListSize(*((RadarList *) valp));
+#ifndef PTK
+ if (num_pats > NUM_ELEMS) {
+ el_ptr = (char **) RadarMalloc(num_pats*sizeof(char *));
+ }
+ else {
+ el_ptr = elems;
+ }
+#else
+ el_ptr = LangAllocVec(num_pats);
+#endif
+ for (i = 0; i < num_pats; i++) {
+ if (pats[i] != RadarUnspecifiedPattern) {
+ LangSetString(&el_ptr[i], Tk_NameOfBitmap(wi->dpy, pats[i]));
+ }
+ else {
+ LangSetString(&el_ptr[i], "");
+ }
+ }
+ result = Tcl_Merge(num_pats, el_ptr);
+ *free_proc = TCL_DYNAMIC;
+#ifndef PTK
+ if (el_ptr != elems) {
+ RadarFree(el_ptr);
+ }
+#else
+ LangFreeVec(num_pats, el_ptr);
+#endif
+ }
+ else {
+ LangSetString(&result, "");
+ }
+ break;
+ }
+ case RADAR_CONFIG_TAGS:
+ {
+ int num_tags, i;
+ Tk_Uid *tags;
+
+ if (*((RadarList *) valp)) {
+ tags = (Tk_Uid *) RadarListArray(*((RadarList *) valp));
+ num_tags = RadarListSize(*((RadarList *) valp));
+#ifndef PTK
+ if (num_tags > NUM_ELEMS) {
+ el_ptr = (char **) RadarMalloc(num_tags*sizeof(char *));
+ }
+ else {
+ el_ptr = elems;
+ }
+#else
+ el_ptr = LangAllocVec(num_tags);
+#endif
+ for (i = 0; i < num_tags; i++) {
+ LangSetString(&el_ptr[i], tags[i]);
+ }
+ result = Tcl_Merge(num_tags, el_ptr);
+ *free_proc = TCL_DYNAMIC;
+#ifndef PTK
+ if (el_ptr != elems) {
+ RadarFree(el_ptr);
+ }
+#else
+ LangFreeVec(num_tags, el_ptr);
+#endif
+ }
+ else {
+ LangSetString(&result, "");
+ }
+ break;
+ }
+ case RADAR_CONFIG_TEXT:
+ case RADAR_CONFIG_MAP_INFO:
+ case RADAR_CONFIG_IMAGE:
+ LangSetString(&result, *((char **) valp));
+ break;
+ case RADAR_CONFIG_FONT:
+ LangSetString(&result, "");
+ if (*((Tk_Font *) valp)) {
+ LangSetString(&result, Tk_NameOfFont(*((Tk_Font *) valp)));
+ }
+ break;
+ case RADAR_CONFIG_BORDER:
+ {
+ Border border = *((Border *) valp);
+ if (border == NO_BORDER) {
+ LangSetString(&result, NO_BORDER_SPEC);
+ break;
+ }
+ *free_proc = TCL_VOLATILE;
+ buffer[0] = 0;
+ if ((border & CONTOUR_BORDER) == CONTOUR_BORDER) {
+ strcat(buffer, CONTOUR_SPEC);
+ }
+ else {
+ if (border & LEFT_BORDER) {
+ strcat(buffer, LEFT_SPEC);
+ }
+ if (border & RIGHT_BORDER) {
+ if (buffer[0] != 0) {
+ strcat(buffer, " ");
+ }
+ strcat(buffer, RIGHT_SPEC);
+ }
+ if (border & TOP_BORDER) {
+ if (buffer[0] != 0) {
+ strcat(buffer, " ");
+ }
+ strcat(buffer, TOP_SPEC);
+ }
+ if (border & BOTTOM_BORDER) {
+ if (buffer[0] != 0) {
+ strcat(buffer, " ");
+ }
+ strcat(buffer, BOTTOM_SPEC);
+ }
+ }
+ if (border & OBLIQUE) {
+ if (buffer[0] != 0) {
+ strcat(buffer, " ");
+ }
+ strcat(buffer, OBLIQUE_SPEC);
+ }
+ if (border & COUNTER_OBLIQUE) {
+ if (buffer[0] != 0) {
+ strcat(buffer, " ");
+ }
+ strcat(buffer, COUNTER_OBLIQUE_SPEC);
+ }
+ LangSetString(&result, buffer);
+ }
+ break;
+ case RADAR_CONFIG_LINE_SHAPE:
+ {
+ LineShape line_shape = *((LineShape *) valp);
+ switch (line_shape) {
+ case LINE_STRAIGHT:
+ LangSetString(&result, STRAIGHT_SPEC);
+ break;
+ case LINE_RIGHT_LIGHTNING:
+ LangSetString(&result, RIGHT_LIGHTNING_SPEC);
+ break;
+ case LINE_LEFT_LIGHTNING:
+ LangSetString(&result, LEFT_LIGHTNING_SPEC);
+ break;
+ case LINE_RIGHT_CORNER:
+ LangSetString(&result, RIGHT_CORNER_SPEC);
+ break;
+ case LINE_LEFT_CORNER:
+ LangSetString(&result, LEFT_CORNER_SPEC);
+ break;
+ case LINE_DOUBLE_RIGHT_CORNER:
+ LangSetString(&result, DOUBLE_RIGHT_CORNER_SPEC);
+ break;
+ case LINE_DOUBLE_LEFT_CORNER:
+ LangSetString(&result, DOUBLE_LEFT_CORNER_SPEC);
+ break;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LINE_STYLE:
+ {
+ LineStyle line_style = *((LineStyle *) valp);
+ switch (line_style) {
+ case LINE_SIMPLE:
+ LangSetString(&result, SIMPLE_SPEC);
+ break;
+ case LINE_DASHED:
+ LangSetString(&result, DASHED_SPEC);
+ break;
+ case LINE_MIXED:
+ LangSetString(&result, MIXED_SPEC);
+ break;
+ case LINE_DOTTED:
+ LangSetString(&result, DOTTED_SPEC);
+ break;
+ }
+ break;
+ }
+ case RADAR_CONFIG_LINE_END:
+ {
+ LineEnd line_end = *((LineEnd *) valp);
+
+ if (!line_end) {
+ LangSetString(&result, "");
+ }
+ else {
+ LangSetString(&result, LineEndGetString(line_end));
+ }
+ break;
+ }
+ case RADAR_CONFIG_RELIEF:
+ LangSetString(&result , Tk_NameOfRelief(*((ReliefStyle *) valp)));
+ break;
+ case RADAR_CONFIG_JOIN_STYLE:
+ LangSetString(&result , Tk_NameOfJoinStyle(*((int *) valp)));
+ break;
+ case RADAR_CONFIG_CAP_STYLE:
+ LangSetString(&result , Tk_NameOfCapStyle(*((int *) valp)));
+ break;
+ case RADAR_CONFIG_POINT:
+ {
+#ifndef PTK
+ *free_proc = TCL_VOLATILE;
+ sprintf(buffer, "%g %g", ((RadarPoint *) valp)->x, ((RadarPoint *) valp)->y);
+ result = buffer;
+#else
+ Arg *list = LangAllocVec(2);
+ LangSetInt(&list[0], ((RadarPoint *) valp)->x);
+ LangSetInt(&list[1], ((RadarPoint *) valp)->y);
+ result = Tcl_Merge(2, list);
+ LangFreeVec(2, list);
+#endif
+ break;
+ }
+ case RADAR_CONFIG_RECT:
+ {
+#ifndef PTK
+ *free_proc = TCL_VOLATILE;
+ sprintf(buffer, "%g %g %g %g",
+ ((RadarRect *) valp)->x, ((RadarRect *) valp)->y,
+ ((RadarRect *) valp)->w, ((RadarRect *) valp)->h);
+ result = buffer;
+#else
+ Arg *list = LangAllocVec(4);
+ LangSetInt(&list[0], ((RadarRect *) valp)->x);
+ LangSetInt(&list[1], ((RadarRect *) valp)->x);
+ LangSetInt(&list[2], ((RadarRect *) valp)->w);
+ LangSetInt(&list[3], ((RadarRect *) valp)->h);
+ result = Tcl_Merge(4, list);
+ LangFreeVec(4, list);
+#endif
+ break;
+ }
+ case RADAR_CONFIG_ITEM:
+ if (*((Item *) valp) == RADAR_NO_ITEM) {
+ LangSetString(&result, "");
+ }
+ else {
+ *free_proc = TCL_VOLATILE;
+ sprintf(buffer, "%d", (*((Item *) valp))->id);
+ LangSetString(&result, buffer);
+ }
+ break;
+ case RADAR_CONFIG_INT:
+ case RADAR_CONFIG_UINT:
+ case RADAR_CONFIG_DIM:
+ case RADAR_CONFIG_PRI:
+ case RADAR_CONFIG_ANGLE:
+ *free_proc = TCL_VOLATILE;
+ sprintf(buffer, "%d", *((int *) valp));
+ LangSetString(&result, buffer);
+ break;
+ case RADAR_CONFIG_JUSTIFY:
+ {
+ Tk_Justify justify = *((RadarJustify *) valp);
+ LangSetString(&result, Tk_NameOfJustify(justify));
+ break;
+ }
+ case RADAR_CONFIG_ANCHOR:
+ LangSetString(&result, Tk_NameOfAnchor(*((Tk_Anchor *) valp)));
+ break;
+ case RADAR_CONFIG_LABEL_FORMAT:
+ {
+ LabelFormat frmt = *((LabelFormat *) valp);
+
+ if (!frmt) {
+ LangSetString(&result, "");
+ }
+ else {
+ LangSetString(&result, LabelFormatGetString(frmt));
+ }
+ break;
+ }
+ case RADAR_CONFIG_AUTO_JUSTIFY:
+ {
+ AutoAlign *aa = (AutoAlign *) valp;
+ int i;
+ if (aa->automatic == False) {
+ LangSetString(&result, "-");
+ }
+ else {
+ *free_proc = TCL_VOLATILE;
+ buffer[0] = 0;
+ for (i = 0; i < 3; i++) {
+ switch (aa->align[i]) {
+ case RadarJustifyLeft:
+ strcat(buffer, "l");
+ break;
+ case RadarJustifyCenter:
+ strcat(buffer, "c");
+ break;
+ case RadarJustifyRight:
+ strcat(buffer, "r");
+ break;
+ }
+ }
+ LangSetString(&result, buffer);
+ }
+ }
+ break;
+
+ case RADAR_CONFIG_LEADER_ANCHORS:
+ {
+ LeaderAnchors lanch = (LeaderAnchors) valp;
+ char *ptr = buffer;
+ int count;
+
+ if (lanch->left_y < 0) {
+ count = sprintf(ptr, "|%d", lanch->left_x);
+ }
+ else {
+ count = sprintf(ptr, "%%%dx%d", lanch->left_x, lanch->left_y);
+ }
+ ptr += count;
+ if (lanch->right_y < 0) {
+ count = sprintf(ptr, "|%d", lanch->right_x);
+ }
+ else {
+ count = sprintf(ptr, "%%%dx%d", lanch->right_x, lanch->right_y);
+ }
+ LangSetString(&result, buffer);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * QueryAttribute --
+ *
+ **********************************************************************************
+ */
+static int
+QueryAttribute(char *record,
+ int field, /* 0< means item itself. */
+ Arg attr_name)
+{
+ WidgetInfo *wi;
+ Item item;
+ Tk_Uid attr_uid = Tk_GetUid(LangString(attr_name));
+ Arg result = NULL;
+ Tcl_FreeProc *free_proc;
+ char buffer[256];
+ RadarAttrConfig *desc;
+
+ if (field < 0) {
+ item = (Item) record;
+ wi = item->wi;
+ desc = item->class->attr_desc;
+ }
+ else {
+ FieldSet field_set = (FieldSet) record;
+ wi = field_set->wi;
+ if (field >= field_set->num_fields) {
+ Tcl_AppendResult(wi->interp, "invalid field index \"", NULL);
+ return RADAR_ERROR;
+ }
+ record = (char *) &field_set->fields[field];
+ desc = field_attrs;
+ }
+
+ while (True) {
+ if (desc->type == RADAR_CONFIG_END) {
+ Tcl_AppendResult(wi->interp, "unknown attribute \"",
+ attr_uid, "\"", NULL);
+ return RADAR_ERROR;
+ }
+ else if (attr_uid == desc->uid) {
+ result = AttributeToString(wi, record, desc, buffer, &free_proc);
+#ifndef PTK
+ Tcl_SetResult(wi->interp, result, free_proc);
+#else
+ Tcl_ArgResult(wi->interp, result);
+#endif
+ break;
+ }
+ else {
+ desc++;
+ }
+ }
+ return RADAR_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ItemClassList --
+ *
+ **********************************************************************************
+ */
+static RadarList
+ItemClassList()
+{
+ return item_classes;
+}
+
+/*
+ **********************************************************************************
+ *
+ * LookupItemClass --
+ *
+ **********************************************************************************
+ */
+static ItemClass
+LookupItemClass(char *class_name)
+{
+ ItemClass *class;
+ int i, num_classes;
+
+ class = (ItemClass *) RadarListArray(item_classes);
+ num_classes = RadarListSize(item_classes);
+ for (i = 0; i < num_classes; i++) {
+ if (strcasecmp((class[i])->name, class_name) == 0) {
+ return class[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ **********************************************************************************
+ *
+ * AddItemClass --
+ *
+ **********************************************************************************
+ */
+static void
+AddItemClass(ItemClass class)
+{
+ if (!LookupItemClass(class->name)) {
+ RadarListAdd(item_classes, &class, RadarListTail);
+ InitAttrDesc(class->attr_desc);
+ }
+}
+
+/*
+ **********************************************************************************
+ *
+ * GlobalModuleInit --
+ * Initialize classes static state.
+ *
+ **********************************************************************************
+ */
+static void
+GlobalModuleInit()
+{
+ /* First check if static part already inited */
+ if (item_classes == NULL) {
+ item_classes = RadarListNew(16, sizeof(ItemClass));
+ AddItemClass(RadarTrack);
+ AddItemClass(RadarWayPoint);
+ AddItemClass(RadarMap);
+ AddItemClass(RadarReticle);
+ AddItemClass(RadarTabular);
+ AddItemClass(RadarRectangle);
+ AddItemClass(RadarArc);
+ AddItemClass(RadarCurve);
+ AddItemClass(RadarGroup);
+ AddItemClass(RadarIcon);
+ AddItemClass(RadarText);
+ /*AddItemClass(RadarMosaic);*/
+ InitAttrDesc(field_attrs);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ComputeFieldAttachment --
+ * Compute the location/size of the field, computing attachments if any.
+ *
+ **********************************************************************************
+ */
+static void
+ComputeFieldAttachment(FieldSet field_set,
+ int field,
+ RadarBBox *field_bbox)
+{
+
+ RadarBBox ref_bbox;
+ RadarDim 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 = (RadarPos) field_ptr->orig_x;
+ field_bbox->orig.y = (RadarPos) field_ptr->orig_y;
+ field_bbox->corner.x = field_ptr->corner_x;
+ field_bbox->corner.y = field_ptr->corner_y;
+ return;
+ }
+
+ 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 != RadarUnspecifiedImage) &&
+ ((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 = (RadarDim) (width_spec*RadarTextWidth(field_ptr->font, "N", 1)/100);
+ break;
+ case LF_DIM_ICON:
+ real_width = (RadarDim) (width_spec*icon_width/100);
+ break;
+ case LF_DIM_AUTO:
+ {
+ int len = strlen(field_ptr->text);
+ RadarDim text_width;
+
+ real_width = 0.0;
+ if (field_ptr->image != RadarUnspecifiedImage) {
+ real_width = (RadarDim) icon_width;
+ }
+ if (len) {
+ text_width = (RadarDim) RadarTextWidth(field_ptr->font, field_ptr->text, len);
+ real_width = text_width < real_width ? real_width : text_width;
+ }
+ real_width += (RadarDim) width_spec;
+ break;
+ }
+ case LF_DIM_PIXEL:
+ default:
+ real_width = (RadarDim) 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 = (RadarDim) (height_spec*(fm.ascent + fm.descent)/100);
+ break;
+ }
+ case LF_DIM_ICON:
+ real_height = (RadarDim) (height_spec*icon_height/100);
+ break;
+ case LF_DIM_AUTO:
+ {
+ RadarDim text_height;
+
+ real_height = 0.0;
+ if (field_ptr->image != RadarUnspecifiedImage) {
+ real_height = (RadarDim) icon_height;
+ }
+ if (strlen(field_ptr->text)) {
+ Tk_GetFontMetrics(field_ptr->font, &fm);
+ text_height = (RadarDim) (fm.ascent + fm.descent);
+ real_height = text_height < real_height ? real_height : text_height;
+ }
+ real_height += (RadarDim) height_spec;
+ break;
+ }
+ case LF_DIM_PIXEL:
+ default:
+ real_height = (RadarDim) height_spec;
+ break;
+ }
+ /*printf("field %d, height = %g\n", field, real_height);*/
+
+ /*
+ * Then try to deduce the position, resolving any attachments
+ * if needed.
+ */
+ /*
+ * 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 = (short) real_width;
+ field_ptr->corner_y = (short) real_height;
+ SET(field_ptr->flags, CACHE_OK);
+
+ /*
+ * Do the x axis.
+ */
+ if (x_attach == LF_ATTACH_PIXEL) {
+ field_bbox->orig.x = (RadarPos) 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)) {
+ RadarWarning ("Attached (x) to an inexistant field geometry");
+ }
+ 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_attach == LF_ATTACH_PIXEL) {
+ field_bbox->orig.y = (RadarPos) 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)) {
+ RadarWarning ("Attached (y) to an inexistant field geometry");
+ }
+ 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.
+ *
+ **********************************************************************************
+ */
+void
+ClearFieldCache(FieldSet field_set,
+ int field)
+{
+ int i, num_fields;
+ RadarBool 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);
+ }
+ 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 --
+ *
+ **********************************************************************************
+ */
+void
+GetLabelBBox(FieldSet field_set,
+ RadarDim *w,
+ RadarDim *h)
+{
+ RadarBBox bbox, tmp_bbox;
+ LabelFormat lf;
+ int i, num_fields;
+ RadarDim 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);
+ AddBBoxToBBox(&bbox, &tmp_bbox);
+ }
+ field_set->label_width = (RadarDim) (bbox.corner.x - bbox.orig.x);
+ field_set->label_height = (RadarDim) (bbox.corner.y - bbox.orig.y);
+ if (bbox.orig.x < 0) {
+ field_set->label_width += (RadarDim) bbox.orig.x;
+ }
+ if (bbox.orig.y < 0) {
+ field_set->label_height += (RadarDim) bbox.orig.y;
+ }
+
+ 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;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * 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,
+ RadarBBox *field_bbox)
+{
+ if (field_set->label_format) {
+ ComputeFieldAttachment(field_set, index, field_bbox);
+ field_bbox->orig.x += field_set->label_pos.x;
+ field_bbox->orig.y += field_set->label_pos.y;
+ field_bbox->corner.x += field_set->label_pos.x;
+ field_bbox->corner.y += field_set->label_pos.y;
+ }
+ 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,
+ RadarBBox *bbox,
+ RadarPoint *pos,
+ RadarBBox *text_bbox)
+{
+ RadarBool relief_thickness;
+ RadarDim w, h;
+ Tk_FontMetrics fm;
+
+ relief_thickness = (field_ptr->relief != RELIEF_FLAT &&
+ field_ptr->relief_thickness > 1) ? field_ptr->relief_thickness : 0;
+ Tk_GetFontMetrics(field_ptr->font, &fm);
+ w = RadarTextWidth(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;
+ text_bbox->corner.y = text_bbox->orig.y + h;
+ pos->y = text_bbox->orig.y + fm.ascent;
+
+ switch (field_ptr->alignment) {
+ case RadarJustifyLeft:
+ text_bbox->orig.x = bbox->orig.x + 1 + relief_thickness;
+ break;
+ case RadarJustifyRight:
+ text_bbox->orig.x = bbox->corner.x - w - 1 - relief_thickness;
+ break;
+ default:
+ text_bbox->orig.x = (bbox->orig.x + bbox->corner.x - w) / 2;
+ break;
+ }
+ text_bbox->corner.x = text_bbox->orig.x + w;
+ pos->x = text_bbox->orig.x;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * LeaderToLabel --
+ * Compute the segment part of segment <start, end> that lies
+ * outside the fields of item.
+ *
+ **********************************************************************************
+ */
+static void
+LeaderToLabel(FieldSet field_set,
+ RadarPoint *start,
+ RadarPoint *end)
+{
+ int b_num;
+ RadarPoint delta, inf, sup;
+ RadarPos xt=0, yu=0, yw=0, xv=0;
+ Field field_ptr;
+ int i;
+ RadarBBox 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 == RadarUnspecifiedImage))) {
+ 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 == RadarUnspecifiedImage)) {
+ RadarBBox text_bbox;
+ RadarPoint text_pos; /* dummy */
+ int space_width;
+ int scan_forw, scan_back;
+ space_width = RadarTextWidth(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);
+ }
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * InsertDependentItem --
+ *
+ **********************************************************************************
+ */
+static void
+InsertDependentItem(Item item)
+{
+ GroupItem group = (GroupItem) item->parent;
+
+ if (!group) {
+ return;
+ }
+ if (!group->dependents) {
+ group->dependents = RadarListNew(2, sizeof(Item));
+ }
+ RadarListAdd(group->dependents, &item, RadarListTail);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ExtractDependentItem --
+ *
+ **********************************************************************************
+ */
+static int CmpItem(void *item1,
+ void *item2)
+{
+ return (item1 == item2);
+}
+
+static void
+ExtractDependentItem(Item item)
+{
+ GroupItem group = (GroupItem) item->parent;
+ int index;
+
+ if (!group || !group->dependents) {
+ return;
+ }
+ index = RadarListDo(group->dependents, item, CmpItem);
+ if (index >= 0) {
+ RadarListDelete(group->dependents, index);
+ if (RadarListSize(group->dependents) == 0) {
+ RadarListFree(group->dependents);
+ group->dependents = NULL;
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * UpdateItemDependency --
+ * Update the group dependency list following a change in the
+ * connection of an item.
+ *
+ **********************************************************************************
+ */
+static void
+UpdateItemDependency(Item item,
+ Item old_connection)
+{
+ if (old_connection == RADAR_NO_ITEM) {
+ /* Add a connection */
+ InsertDependentItem(item);
+ }
+ else if (item->connected_item == RADAR_NO_ITEM) {
+ /* Remove a connection */
+ ExtractDependentItem(item);
+ }
+ else {
+ /* Move at end to ensure that it will be updated after
+ * the (new) item it depends upon.
+ */
+ ExtractDependentItem(item);
+ InsertDependentItem(item);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * DisconnectDependentItems --
+ *
+ *
+ **********************************************************************************
+ */
+static void
+DisconnectDependentItems(Item item)
+{
+ Item current_item;
+ GroupItem group = (GroupItem) item->parent;
+ Item *deps;
+ int num_deps, i;
+
+ if (!group || !group->dependents) {
+ return;
+ }
+ deps = (Item *) RadarListArray(group->dependents);
+ num_deps = RadarListSize(group->dependents);
+
+ for (i = num_deps-1; i >= 0; i--) {
+ current_item = deps[i];
+ if (current_item->connected_item == item) {
+ current_item->connected_item = RADAR_NO_ITEM;
+ RadarListDelete(group->dependents, i);
+ Invalidate(current_item, RADAR_COORDS_FLAG);
+ }
+ }
+ if (RadarListSize(group->dependents) == 0) {
+ RadarListFree(group->dependents);
+ group->dependents = NULL;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * InsertItem --
+ *
+ * Insert an item in the display list according to its priority.
+ * It is inserted in front of items of lower or same priority. If
+ * mark_item is not RADAR_NO_ITEM the insertion is done relative
+ * to this item, before it if 'before' is True, after it otherwise.
+ * mark_item must be in the group 'group'.
+ *
+ **********************************************************************************
+ */
+static void
+InsertItem(Item item,
+ Item grp,
+ Item mark_item,
+ RadarBool before)
+{
+ WidgetInfo *wi = item->wi;
+ GroupItem group = (GroupItem) grp;
+
+ if (!group) {
+ group = (GroupItem) wi->top_group;
+ }
+ item->parent = (Item) group;
+
+ if (mark_item && (mark_item->parent != (Item) group)) {
+ mark_item = RADAR_NO_ITEM;
+ }
+ /*
+ * Empty list, add the first item.
+ */
+ if (group->head == RADAR_NO_ITEM) {
+ group->head = item;
+ group->tail = item;
+ item->previous = item->next = RADAR_NO_ITEM;
+ return;
+ }
+
+ if (mark_item != RADAR_NO_ITEM) {
+ /*
+ * Better leave here, mark_item will not
+ * have the links set right.
+ */
+ if (mark_item == item) {
+ return;
+ }
+ /*
+ * Force the priority to be the same as the reference
+ * item;
+ */
+ item->priority = mark_item->priority;
+ }
+ else {
+ mark_item = group->head;
+ while ((mark_item != RADAR_NO_ITEM) &&
+ (mark_item->priority > item->priority)) {
+ mark_item = mark_item->next;
+ }
+ before = True;
+ }
+
+ if (before && (mark_item != RADAR_NO_ITEM)) {
+ /*
+ * Insert before mark.
+ */
+ item->next = mark_item;
+ item->previous = mark_item->previous;
+ if (mark_item->previous == RADAR_NO_ITEM) {
+ group->head = item;
+ }
+ else {
+ mark_item->previous->next = item;
+ }
+ mark_item->previous = item;
+ }
+ else {
+ /*
+ * Insert after mark either because 'before' is False
+ * and mark_item valid or because the right place is at
+ * the end of the list and mark_item is RADAR_NO_ITEM.
+ */
+ if (mark_item == RADAR_NO_ITEM) {
+ group->tail->next = item;
+ item->previous = group->tail;
+ group->tail = item;
+ }
+ else {
+ item->previous = mark_item;
+ item->next = mark_item->next;
+ if (item->next == RADAR_NO_ITEM) {
+ group->tail = item;
+ }
+ else {
+ item->next->previous = item;
+ }
+ mark_item->next = item;
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ExtractItem --
+ *
+ **********************************************************************************
+ */
+static void
+ExtractItem(Item item)
+{
+ GroupItem group;
+
+ if (!item->parent) {
+ return;
+ }
+ group = (GroupItem) item->parent;
+
+ if (item->previous != RADAR_NO_ITEM) {
+ item->previous->next = item->next;
+ }
+ else {
+ group->head = item->next;
+ }
+
+ if (item->next != RADAR_NO_ITEM) {
+ item->next->previous = item->previous;
+ }
+ else {
+ group->tail = item->previous;
+ }
+
+ item->previous = RADAR_NO_ITEM;
+ item->next = RADAR_NO_ITEM;
+ item->parent = NULL;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * UpdateItemPriority --
+ * Reorder a group's item list following a change in an
+ * item priority or a call to lower/raise.
+ *
+ **********************************************************************************
+ */
+static void
+UpdateItemPriority(Item item,
+ Item mark_item,
+ RadarBool before)
+{
+ Item parent = item->parent;
+
+ ExtractItem(item);
+ InsertItem(item, parent, mark_item, before);
+ Invalidate(item, RADAR_DRAW_FLAG);
+ SET(item->wi->events_flags, INTERNAL_NEED_REPICK);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * SetId,
+ * FreeId --
+ * Get a fresh object id from the widget and enter the new
+ * object with this id in the object hash table. The id is
+ * incremented. FreeId on the other hand suppress the item
+ * from the hash table and set its object id to zero.
+ *
+ **********************************************************************************
+ */
+static void
+SetId(Item item)
+{
+ WidgetInfo *wi = item->wi;
+ Tcl_HashEntry *entry;
+ int dummy;
+
+ item->id = wi->obj_id;
+ wi->obj_id++;
+ entry = Tcl_CreateHashEntry(wi->id_table, (char *) item->id, &dummy);
+ Tcl_SetHashValue(entry, item);
+}
+
+static void
+FreeId(Item item)
+{
+ Tcl_HashEntry *entry;
+
+ if (item->id) {
+ entry = Tcl_FindHashEntry(item->wi->id_table, (char *) item->id);
+ if (entry) {
+ Tcl_DeleteHashEntry(entry);
+ item->id = 0;
+ }
+ }
+}
+
+/*
+ **********************************************************************************
+ *
+ * AddTag --
+ * Add a tag to the item. If the tag is already on the list it
+ * is not added. As a side effect the tag/item pair is added to
+ * the tag table of the widget.
+ * 'tag' must be a Tk_Uid.
+ *
+ **********************************************************************************
+ */
+static void
+AddTag(Item item,
+ Tk_Uid tag)
+{
+ int new_entry, num, i;
+ char **ptr;
+ Tcl_HashEntry *entry;
+ RadarList item_list;
+
+ /*
+ * No tags yet.
+ */
+ if (!item->tags) {
+ item->tags = RadarListNew(1, sizeof(char *));
+ }
+ else {
+ /*
+ * If the tag is already there, that's done.
+ */
+ ptr = (char **) RadarListArray(item->tags);
+ num = RadarListSize(item->tags);
+ for (i = 0; i < num; i++) {
+ if (ptr[i] == tag) {
+ return;
+ }
+ }
+ }
+ /*
+ * Add it.
+ */
+ RadarListAdd(item->tags, &tag, RadarListTail);
+ entry = Tcl_CreateHashEntry(item->wi->tag_table, tag, &new_entry);
+ if (new_entry) {
+ item_list = RadarListNew(1, sizeof(Item));
+ Tcl_SetHashValue(entry, item_list);
+ }
+ else {
+ item_list = (RadarList) Tcl_GetHashValue(entry);
+ }
+ RadarListAdd(item_list, &item, RadarListTail);
+}
+
+/*
+ **********************************************************************************
+ *
+ * RemoveTag --
+ *
+ **********************************************************************************
+ */
+static void
+RemoveTag(Item item,
+ Tk_Uid tag)
+{
+ int indx, num;
+ char **ptr;
+ Item *item_ptr;
+ Tcl_HashEntry *entry;
+ RadarList item_list;
+
+ if (!item->tags) {
+ return;
+ }
+ /*
+ * look up the tag in the list.
+ */
+ ptr = (char **) RadarListArray(item->tags);
+ num = RadarListSize(item->tags);
+ for (indx = 0; indx < num; indx++) {
+ if (ptr[indx] == tag) {
+ /* The tag list is not freed when empty to avoid
+ * overhead when using tags intensively. */
+ RadarListDelete(item->tags, indx);
+ entry = Tcl_FindHashEntry(item->wi->tag_table, tag);
+ if (entry) { /* Should not fail */
+ item_list = (RadarList) Tcl_GetHashValue(entry);
+ num = RadarListSize(item_list);
+ item_ptr = (Item *) RadarListArray(item_list);
+ for (indx = 0; indx < num; indx++) {
+ if (item_ptr[indx] == item) {
+ /* Should not fail to get here */
+ RadarListDelete(item_list, indx);
+ if (RadarListSize(item_list) == 0) {
+ RadarListFree(item_list);
+ Tcl_DeleteHashEntry(entry);
+ }
+ }
+ }
+ }
+ return;
+ }
+ }
+}
+
+/*
+ **********************************************************************************
+ *
+ * FreeTags --
+ *
+ **********************************************************************************
+ */
+static void
+FreeTags(Item item)
+{
+ int num, num_items, i, j;
+ char **ts;
+ Item *item_ptr;
+ Tcl_HashEntry *entry;
+ RadarList item_list;
+
+ if (!item->tags) {
+ return;
+ }
+ num = RadarListSize(item->tags);
+ ts = (char **) RadarListArray(item->tags);
+ for (i = 0; i < num; i++) {
+ entry = Tcl_FindHashEntry(item->wi->tag_table, ts[i]);
+ if (entry) { /* Should not fail */
+ item_list = (RadarList) Tcl_GetHashValue(entry);
+ item_ptr = (Item *) RadarListArray(item_list);
+ num_items = RadarListSize(item_list);
+ for (j = 0; j < num_items; j++) {
+ if (item_ptr[j] == item) {
+ /* Should not fail to get here */
+ RadarListDelete(item_list, j);
+ if (RadarListSize(item_list) == 0) {
+ RadarListFree(item_list);
+ Tcl_DeleteHashEntry(entry);
+ }
+ }
+ }
+ }
+ }
+ RadarListFree(item->tags);
+ item->tags = NULL;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * CreateItem --
+ *
+ * InsertItem and ConfigureItem must be called after CreateItem
+ * to finalize the setup of a new item. This is so even if
+ * there are no attributes to be changed after creation.
+ * ConfigureItem must be called in this case with the 'init'
+ * parameter set to True.
+ *
+ **********************************************************************************
+ */
+static Item
+CreateItem(WidgetInfo *wi,
+ ItemClass item_class,
+ int *argc,
+ Arg **args)
+{
+ Item item;
+
+ item = (Item) RadarMalloc(item_class->item_size);
+
+ /* Initialize common state */
+ item->class = item_class;
+ item->wi = wi;
+ item->parent = NULL;
+ item->previous = RADAR_NO_ITEM;
+ item->next = RADAR_NO_ITEM;
+ CLEAR(item->flags, UPDATE_DEPENDENT_BIT);
+ item->inv_flags = 0;
+ item->transfo = NULL;
+ item->parent = NULL;
+ item->connected_item = RADAR_NO_ITEM;
+
+ ResetBBox(&item->item_bounding_box);
+
+ /* Init item specific attributes */
+ if (item_class->Init(item, argc, args) == RADAR_ERROR) {
+ RadarFree(item);
+ return RADAR_NO_ITEM;
+ }
+ SetId(item);
+ item->tags = NULL;
+
+ SET(wi->events_flags, INTERNAL_NEED_REPICK);
+
+ return (item);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * CloneItem --
+ * Can't clone the top level group.
+ *
+ **********************************************************************************
+ */
+static Item
+CloneItem(Item model)
+{
+ WidgetInfo *wi = model->wi;
+ Item item;
+ Tk_Uid *tags;
+ int i, num_tags;
+
+ if (!model->parent) {
+ return RADAR_NO_ITEM;
+ }
+
+ item = (Item) RadarMalloc(model->class->item_size);
+ memcpy(item, model, model->class->item_size);
+
+ item->previous = RADAR_NO_ITEM;
+ item->next = RADAR_NO_ITEM;
+ item->connected_item = RADAR_NO_ITEM;
+ CLEAR(item->flags, UPDATE_DEPENDENT_BIT);
+ item->inv_flags = 0;
+ SetId(item);
+
+ if (model->tags) {
+ item->tags = NULL;
+ tags = (Tk_Uid *) RadarListArray(model->tags);
+ num_tags = RadarListSize(model->tags);
+ for (i = num_tags-1; i >= 0; i--, tags++) {
+ AddTag(item, *tags);
+ }
+ }
+
+ if (item->transfo) {
+ item->transfo = RadarTransfoDuplicate(item->transfo);
+ }
+
+ /* Call item's clone duplicate not shared resources */
+ item->class->Clone(item);
+
+ SET(wi->events_flags, INTERNAL_NEED_REPICK);
+ return item;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ConfigureItem --
+ *
+ **********************************************************************************
+ */
+static int
+ConfigureItem(Item item,
+ int field,
+ int argc,
+ RadarAttrList argv,
+ RadarBool init)
+{
+ WidgetInfo *wi = item->wi;
+ int flags;
+ RadarBool previous_visible = init ? False : ISSET(item->flags, VISIBLE_BIT);
+
+ flags = 0;
+ ASSIGN(flags, RADAR_COORDS_FLAG, init);
+ if (argv) {
+ if (field < 0){
+ if (item->class->Configure(item, argc, argv, &flags) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+ if (item->class->has_fields && ISSET(flags, RADAR_CLFC_FLAG)) {
+ ClearFieldCache(item->class->GetFieldSet(item), -1);
+ }
+ }
+ else if (item->class->has_fields) {
+ FieldSet field_set = item->class->GetFieldSet(item);
+ if (ConfigureField(field_set, field, argc, argv, &flags) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+ }
+ else {
+ return RADAR_ERROR;
+ }
+ }
+
+ if (previous_visible && ISCLEAR(item->flags, VISIBLE_BIT)) {
+ /*
+ * Special case when the item has its visibility
+ * just turned out.
+ */
+ Damage(wi, &item->item_bounding_box);
+ RadarNeedRedisplay(wi);
+ }
+
+ Invalidate(item, flags);
+
+ return RADAR_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * QueryItem --
+ *
+ **********************************************************************************
+ */
+static int
+QueryItem(Item item,
+ int field,
+ int argc,
+ RadarAttrList argv)
+{
+ if (field < 0) {
+ return item->class->Query(item, argc, argv);
+ }
+ else if (item->class->has_fields) {
+ FieldSet field_set = item->class->GetFieldSet(item);
+ return QueryField(field_set, field, argc, argv);
+ }
+
+ return RADAR_ERROR;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ComposeItemTransform --
+ * Compose the item transform with current_t transform in new_t.
+ *
+ **********************************************************************************
+ */
+static void
+ComposeItemTransform(Item item,
+ RadarTransfo *current_t,
+ RadarTransfo *new_t)
+{
+ RadarBool full;
+
+ full = (ISSET(item->flags, COMPOSE_SCALE_BIT) &&
+ ISSET(item->flags, COMPOSE_ROTATION_BIT));
+
+ if (!item->transfo && full) {
+ *new_t = *current_t;
+ return;
+ }
+ if (full) {
+ /*
+ * Full concatenation.
+ */
+ /*printf("Item transfo for item: 0x%X;", item); RadarPrintTransfo(item->transfo);*/
+ RadarTransfoCompose(new_t, item->transfo, current_t);
+ }
+ else {
+ RadarPoint scale, trans, local_scale, local_trans;
+ RadarReal local_rot, rot;
+ RadarTransfo t, t2;
+
+ /*
+ * Need to decompose the local transform in translation,
+ * rotation and scale.
+ */
+ RadarTransfoSetIdentity(&t);
+ RadarTransfoSetIdentity(new_t);
+ RadarTransfoDecompose(item->transfo, &local_scale, &local_trans, &local_rot, NULL);
+ RadarTranslate(&t, local_trans.x, local_trans.y);
+ RadarTransfoCompose(&t2, &t, current_t);
+ RadarTransfoDecompose(&t2, &scale, &trans, &rot, NULL);
+ if (ISSET(item->flags, COMPOSE_SCALE_BIT)) {
+ RadarScale(new_t, scale.x, scale.y);
+ }
+ if (ISSET(item->flags, COMPOSE_ROTATION_BIT)) {
+ RadarRotateRad(new_t, rot);
+ }
+ RadarScale(new_t, local_scale.x, local_scale.y);
+ RadarRotateRad(new_t, local_rot);
+ RadarTranslate(new_t, trans.x, trans.y);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * GetTransform --
+ * Compute the current transform for an item.
+ *
+ **********************************************************************************
+ */
+static void
+GetTransform(Item item,
+ RadarTransfo *t)
+{
+ Item *items;
+ int i;
+ RadarTransfo t_tmp, *t1, *t2, *swap;
+
+ if (item_stack == NULL) {
+ item_stack = RadarListNew(16, sizeof(Item));
+ }
+ else {
+ RadarListEmpty(item_stack);
+ }
+
+ while (item != RADAR_NO_ITEM) {
+ RadarListAdd(item_stack, &item, RadarListTail);
+ item = item->parent;
+ }
+
+ RadarTransfoSetIdentity(t);
+ t1 = t;
+ t2 = &t_tmp;
+ items = (Item *) RadarListArray(item_stack);
+ for (i = RadarListSize(item_stack)-1; i >= 0; i--) {
+ ComposeItemTransform(items[i], t1, t2);
+ swap = t2;
+ t2 = t1;
+ t1 = swap;
+ }
+ if (t1 != t) {
+ *t = *t1;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ResetTransformStack --
+ * Empty the transform stack and restore the first transform on the stack.
+ *
+ **********************************************************************************
+ */
+static void
+ResetTransformStack(WidgetInfo *wi)
+{
+ RadarListAssertSize(wi->transfo_stack, 1);
+ wi->current_transfo = (RadarTransfo *) RadarListAt(wi->transfo_stack, 0);
+ RadarTransfoSetIdentity(wi->current_transfo);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ResetClipStack --
+ *
+ **********************************************************************************
+ */
+static void
+ResetClipStack(WidgetInfo *wi)
+{
+ int i;
+ ClipState *clips = (ClipState *) RadarListArray(wi->clip_stack);
+
+ /*
+ * Should not happen, clip stack should be
+ * empty when this function is called.
+ */
+ for (i = RadarListSize(wi->clip_stack)-1; i >= 0; i--) {
+ XDestroyRegion(clips[i].region);
+ }
+ RadarListEmpty(wi->clip_stack);
+ wi->current_clip = NULL;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Invalidate --
+ *
+ **********************************************************************************
+ */
+static void
+Invalidate(Item item,
+ int reason)
+{
+ if (ISSET(item->inv_flags, RADAR_TRANSFO_FLAG)) {
+ return;
+ }
+
+ if (ISSET(reason, RADAR_COORDS_FLAG) ||
+ ISSET(reason, RADAR_TRANSFO_FLAG)) {
+ Item parent = item->parent;
+ while ((parent != NULL) &&
+ ISCLEAR(parent->inv_flags, RADAR_COORDS_FLAG) &&
+ ISCLEAR(parent->inv_flags, RADAR_TRANSFO_FLAG)) {
+ SET(parent->inv_flags, RADAR_COORDS_FLAG);
+ /*printf("invalidate coords for parent %d\n", parent->id);*/
+ parent = parent->parent;
+ }
+ /*
+ * There is no need to set the DRAW flag to force the invalidation
+ * of the current bounding box. This will be done by ComputeCoordinates
+ * in Group.
+ */
+ item->inv_flags |= reason;
+ /*printf("invalidate %s for item %d, flags %s\n",
+ ISSET(reason, RADAR_TRANSFO_FLAG)?"TRANSFO":"COORDS", item->id,
+ ISSET(item->inv_flags, RADAR_TRANSFO_FLAG)?"TRANSFO":"COORDS");*/
+ RadarNeedRedisplay(item->wi);
+ }
+ else if (ISSET(reason, RADAR_DRAW_FLAG)) {
+ if (ISSET(item->flags, VISIBLE_BIT)) {
+ /*printf("invalidate graphics for item %d\n", item->id);*/
+ Damage(item->wi, &item->item_bounding_box);
+ RadarNeedRedisplay(item->wi);
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * InvalidateItems --
+ * Invalidate the geometric state of all items of a group
+ * belonging to a given class.
+ *
+ **********************************************************************************
+ */
+static void
+InvalidateItems(Item group,
+ ItemClass item_class)
+{
+ Item item;
+
+ if (group->class != RadarGroup) {
+ return;
+ }
+ item = ((GroupItem) group)->head;
+ while (item != RADAR_NO_ITEM) {
+ if (item->class == item_class) {
+ Invalidate(item, RADAR_COORDS_FLAG);
+ }
+ item = item->next;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ResetTransfo
+ * SetTransfo
+ * TranslateItem
+ * ScaleItem
+ * RotateItem --
+ * Set of functions that deal with item transform. They take care
+ * of all details including managing NULL transforms and invalidating
+ * the item hierarchy.
+ *
+ **********************************************************************************
+ */
+static void
+ResetTransfo(Item item)
+{
+ if (item->transfo) {
+ RadarFree(item->transfo);
+ item->transfo = NULL;
+ }
+ Invalidate(item, RADAR_TRANSFO_FLAG);
+}
+
+
+static void
+SetTransfo(Item item,
+ RadarTransfo *t)
+{
+ if (item->transfo) {
+ RadarFree(item->transfo);
+ }
+ if (!t || RadarTransfoIsIdentity(t)) {
+ item->transfo = NULL;
+ }
+ else {
+ item->transfo = RadarTransfoDuplicate(t);
+ }
+ Invalidate(item, RADAR_TRANSFO_FLAG);
+}
+
+
+static void
+TranslateItem(Item item,
+ RadarReal dx,
+ RadarReal dy)
+{
+ if (!item->transfo) {
+ item->transfo = RadarTransfoNew();
+ }
+ RadarTranslate(item->transfo, dx, dy);
+ Invalidate(item, RADAR_TRANSFO_FLAG);
+}
+
+
+static void
+ScaleItem(Item item,
+ RadarReal sx,
+ RadarReal sy)
+{
+ if (!item->transfo) {
+ item->transfo = RadarTransfoNew();
+ }
+ RadarScale(item->transfo, sx, sy);
+ Invalidate(item, RADAR_TRANSFO_FLAG);
+}
+
+
+static void
+RotateItem(Item item,
+ RadarReal angle,
+ RadarPoint *p)
+{
+ if (!item->transfo) {
+ item->transfo = RadarTransfoNew();
+ }
+ if (p) {
+ RadarTranslate(item->transfo, -p->x, -p->y);
+ }
+ RadarRotateRad(item->transfo, angle);
+ if (p) {
+ RadarTranslate(item->transfo, p->x, p->y);
+ }
+
+ Invalidate(item, RADAR_TRANSFO_FLAG);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * RemoveItem --
+ * Extract an item from its context, includes updating graphic
+ * state flags.
+ *
+ **********************************************************************************
+ */
+static void
+RemoveItem(Item item)
+{
+ WidgetInfo *wi = item->wi;
+ GroupItem group;
+
+ group = (GroupItem) item->parent;
+
+ /* damage bounding boxes */
+ if (ISSET(item->flags, VISIBLE_BIT)) {
+ Damage(wi, &item->item_bounding_box);
+ RadarNeedRedisplay(wi);
+ }
+
+ /*
+ * Tell that we need to repick
+ */
+ if (item->class != RadarGroup) {
+ SET(wi->events_flags, INTERNAL_NEED_REPICK);
+ }
+
+ if (group) {
+ if (group->dependents) {
+ /* Remove me from dependency list. */
+ ExtractDependentItem(item);
+
+ /* Disconnect all dependents on me. */
+ DisconnectDependentItems(item);
+ }
+ /*
+ * Remove me from item list.
+ */
+ ExtractItem(item);
+ /*
+ * Remove me as a clip item.
+ */
+ if (group->clip == item) {
+ group->clip = RADAR_NO_ITEM;
+ Invalidate((Item) group, RADAR_COORDS_FLAG);
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * DestroyItem --
+ *
+ **********************************************************************************
+ */
+static void
+DestroyItem(Item item)
+{
+ WidgetInfo *wi = item->wi;
+
+ /*
+ * Extract it from its group.
+ */
+ RemoveItem(item);
+
+ /*
+ * Update state variables to prevent dangling pointers.
+ */
+ if (wi->current_item == item) {
+ wi->current_item = RADAR_NO_ITEM;
+ wi->current_part = RADAR_NO_PART;
+ }
+ if (wi->new_item == item) {
+ wi->new_item = RADAR_NO_ITEM;
+ wi->new_part = RADAR_NO_PART;
+ }
+
+ /*
+ * Call per class removal code.
+ */
+ (item->class->Destroy)(item);
+ /*
+ * Free the transform if any.
+ */
+ if (item->transfo) {
+ RadarFree(item->transfo);
+ }
+ /*
+ * Remove the item from the item table and free
+ * all its tags.
+ */
+ FreeId(item);
+ FreeTags(item);
+ /*
+ * Free the item own memory
+ */
+ RadarFree(item);
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * 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;
+ RadarBBox bbox;
+
+ if (field->image != RadarUnspecifiedImage) {
+ i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct);
+ GetFieldBBox(field->field_set, i, &bbox);
+ Damage(field->field_set->wi, &bbox);
+ RadarNeedRedisplay(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;
+ RadarBBox bbox;
+
+ if (field->tile != RadarUnspecifiedImage) {
+ i = (((char *) field) - ((char *) field->field_set->fields)) / sizeof(FieldStruct);
+ InvalidateImage(field->tile);
+ GetFieldBBox(field->field_set, i, &bbox);
+ Damage(field->field_set->wi, &bbox);
+ RadarNeedRedisplay(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) RadarMalloc(num_fields*sizeof(FieldStruct));
+
+ for (i = 0; i < num_fields; i++){
+ field = &field_set->fields[i];
+
+ field->field_set = field_set;
+ field->color = RadarGetColorByValue(wi->win, wi->fore_color);
+ field->back_color = RadarGetColorByValue(wi->win, wi->back_color);
+ field->border_color = RadarGetColorByValue(wi->win, 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 = RadarUnspecifiedPattern;
+ field->text = "";
+ field->image = RadarUnspecifiedImage;
+ field->image_name = "";
+ field->tile = RadarUnspecifiedImage;
+ field->tile_name = "";
+ field->font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->font));
+ field->border_edges = NO_BORDER;
+ field->alignment = RadarJustifyLeft;
+ field->auto_alignment.automatic = False;
+
+ field->relief = RELIEF_FLAT;
+ field->relief_thickness = 2;
+ SET(field->flags, TEXT_ON_TOP_BIT);
+
+ field->gradient = 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(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) RadarMalloc(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 = RadarGetColorGradientByValue(field->gradient);
+ }
+
+ if (strlen(field->image_name) != 0) {
+ text = RadarMalloc((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 (strlen(field->tile_name) != 0) {
+ text = RadarMalloc((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 != RadarUnspecifiedPattern) {
+ 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 = RadarGetColorByValue(wi->win, field->color);
+ field->back_color = RadarGetColorByValue(wi->win, field->back_color);
+ field->border_color = RadarGetColorByValue(wi->win, field->border_color);
+
+ if (strlen(field->text) != 0) {
+ text = (char *) RadarMalloc((strlen(field->text) + 1) * sizeof(char));
+ strcpy(text, field->text);
+ field->text = text;
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ConfigureField --
+ *
+ **********************************************************************************
+ */
+static int
+ConfigureField(FieldSet field_set,
+ unsigned int field,
+ int argc,
+ RadarAttrList argv,
+ int *flags)
+{
+ int i;
+ Field field_ptr;
+ RadarBBox bbox;
+ WidgetInfo *wi = field_set->wi;
+
+ if (field >= field_set->num_fields) {
+ return RADAR_ERROR;
+ }
+
+ field_ptr = &field_set->fields[field];
+
+ if (ConfigureAttributes((char *) field_set, field, argc, argv, flags) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+
+ if (ISSET(*flags, RADAR_REPICK_FLAG)) {
+ SET(wi->events_flags, INTERNAL_NEED_REPICK);
+ }
+ if (ISSET(*flags, RADAR_CLFC_FLAG)) {
+ ClearFieldCache(field_set, field);
+ }
+
+ if (field_ptr->gradient &&
+ (ISSET(*flags, RADAR_BORDER_FLAG) || (field_ptr->relief == RELIEF_FLAT))) {
+ RadarFreeColorGradient(field_ptr->gradient);
+ field_ptr->gradient = NULL;
+ }
+ if ((field_ptr->relief != RELIEF_FLAT) && !field_ptr->gradient) {
+ field_ptr->gradient = RadarGetReliefGradient(wi->interp, wi->win,
+ RadarNameOfColor(field_ptr->back_color));
+ }
+
+ if (ISSET(*flags, RADAR_IMAGE_FLAG)) {
+ Tk_Image image;
+
+ if (strcmp(field_ptr->image_name, "") != 0) {
+ image = Tk_GetImage(wi->interp, wi->win, field_ptr->image_name,
+ FieldImageChange, (ClientData) field_ptr);
+ if (image == NULL) {
+ /*
+ * The name will not be in sync with the image in
+ * this case.
+ */
+ return RADAR_ERROR;
+ }
+ }
+ else {
+ image = RadarUnspecifiedImage;
+ }
+ if (field_ptr->image != RadarUnspecifiedImage) {
+ Tk_FreeImage(field_ptr->image);
+ }
+ field_ptr->image = image;
+ }
+
+ if (ISSET(*flags, RADAR_TILE_FLAG)) {
+ Tk_Image tile;
+
+ if (strcmp(field_ptr->tile_name, "") != 0) {
+ tile = Tk_GetImage(wi->interp, wi->win, field_ptr->tile_name,
+ FieldTileChange, (ClientData) field_ptr);
+ if (tile == NULL) {
+ return RADAR_ERROR;
+ }
+ }
+ else {
+ tile = RadarUnspecifiedImage;
+ }
+ if (field_ptr->tile != RadarUnspecifiedImage) {
+ Tk_FreeImage(field_ptr->tile);
+ }
+ field_ptr->tile = tile;
+ }
+
+ /*
+ * This is done here to limit the redraw to the area of the
+ * modified fields.
+ */
+ if (ISCLEAR(*flags, RADAR_COORDS_FLAG) &&
+ field_set->label_format && ISSET(*flags, RADAR_DRAW_FLAG)) {
+ for (i = 0; i < LabelFormatNumFields(field_set->label_format); i++) {
+ if (i == field) {
+ GetFieldBBox(field_set, i, &bbox);
+ Damage(wi, &bbox);
+ break;
+ }
+ }
+ }
+
+ return RADAR_OK;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * QueryField --
+ *
+ **********************************************************************************
+ */
+static int
+QueryField(FieldSet field_set,
+ unsigned int field,
+ int argc,
+ RadarAttrList argv)
+{
+ Field field_ptr;
+
+ if (field >= field_set->num_fields) {
+ return RADAR_ERROR;
+ }
+
+ field_ptr = &field_set->fields[field];
+ if (QueryAttribute((char *) field_set, field, argv[0]) == RADAR_ERROR) {
+ return RADAR_ERROR;
+ }
+
+ return RADAR_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) {
+ RadarFree(field->text);
+ }
+ if (field->gradient) {
+ RadarFreeColorGradient(field->gradient);
+ }
+ if (strlen(field->image_name) != 0) {
+ RadarFree(field->image_name);
+ }
+ if (field->image != RadarUnspecifiedImage) {
+ Tk_FreeImage(field->image);
+ field->image = RadarUnspecifiedImage;
+ }
+ if (strlen(field->tile_name) != 0) {
+ RadarFree(field->tile_name);
+ }
+ if (field->tile != RadarUnspecifiedImage) {
+ Tk_FreeImage(field->tile);
+ field->tile = RadarUnspecifiedImage;
+ }
+ if (field->fill_pattern != RadarUnspecifiedPattern) {
+ Tk_FreeBitmap(wi->dpy, field->fill_pattern);
+ field->fill_pattern = RadarUnspecifiedPattern;
+ }
+ /*printf("freeing a font\n");*/
+ Tk_FreeFont(field->font);
+ RadarFreeColor(field->color);
+ RadarFreeColor(field->back_color);
+ RadarFreeColor(field->border_color);
+ }
+ if (num_fields) {
+ RadarFree(field_set->fields);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * 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,
+ RadarBBox *bbox,
+ RadarBBox *pm_bbox)
+{
+ RadarBool relief_thickness;
+ 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;
+ relief_thickness = (field_ptr->relief != RELIEF_FLAT &&
+ field_ptr->relief_thickness > 1) ? field_ptr->relief_thickness : 0;
+
+ switch (field_ptr->alignment) {
+ case RadarJustifyLeft:
+ pm_bbox->orig.x = bbox->orig.x + 1 + relief_thickness;
+ break;
+ case RadarJustifyRight:
+ pm_bbox->orig.x = bbox->corner.x - width - 1 - relief_thickness;
+ break;
+ default:
+ pm_bbox->orig.x = (bbox->orig.x + bbox->corner.x - width) / 2;
+ break;
+ }
+ pm_bbox->corner.x = pm_bbox->orig.x + width;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * DrawFields --
+ *
+ **********************************************************************************
+ */
+static void
+DrawFields(FieldSet field_set)
+{
+ WidgetInfo *wi = field_set->wi;
+ int i; /* This one *NEED* to be an int */
+ int j, num;
+ Field field_ptr;
+ XGCValues values;
+ RadarBBox label_clip_box, clip_bbox, bbox, *global_clip_box;
+ RadarBBox text_bbox, clip_text_bbox;
+ XRectangle r;
+ Region reg, reg2;
+ RadarPoint text_pos;
+ RadarBBox pm_bbox, clip_pm_bbox;
+ RadarBool restore = False;
+ RadarDim lwidth, lheight;
+
+ if (field_set->label_format && LabelFormatNumFields(field_set->label_format)) {
+ bbox.orig = field_set->label_pos;
+ GetLabelBBox(field_set, &lwidth, &lheight);
+ bbox.corner.x = field_set->label_pos.x + lwidth;
+ bbox.corner.y = field_set->label_pos.y + lheight;
+ if (wi->current_clip) {
+ global_clip_box = &wi->current_clip->clip_box;
+ }
+ else {
+ global_clip_box = &wi->damaged_area;
+ }
+ IntersectBBox(global_clip_box, &bbox, &label_clip_box);
+ if (IsEmptyBBox(&label_clip_box)) {
+ return;
+ }
+
+ num = LabelFormatNumFields(field_set->label_format);
+ for (i = 0; i < num; i++) {
+ field_ptr = &field_set->fields[i];
+
+ if (ISCLEAR(field_ptr->flags, FIELD_VISIBLE_BIT)) {
+ continue;
+ }
+
+ GetFieldBBox(field_set, i, &bbox);
+ IntersectBBox(&label_clip_box, &bbox, &clip_bbox);
+ if (IsEmptyBBox(&clip_bbox)) {
+ continue;
+ }
+
+ if (field_ptr->text) {
+ ComputeFieldTextLocation(field_ptr, &bbox, &text_pos, &text_bbox);
+ }
+ else {
+ ResetBBox(&text_bbox);
+ }
+
+ IntersectBBox(&clip_bbox, &text_bbox, &clip_text_bbox);
+
+ if (field_ptr->image != RadarUnspecifiedImage) {
+ ComputeFieldImageLocation(field_ptr, &bbox, &pm_bbox);
+ }
+ else {
+ ResetBBox(&pm_bbox);
+ }
+
+ IntersectBBox(&clip_bbox, &pm_bbox, &clip_pm_bbox);
+
+ /* we must call XSetClipRectangles only if it's required */
+ if (clip_bbox.orig.x != bbox.orig.x || clip_bbox.orig.y != bbox.orig.y ||
+ clip_bbox.corner.x != bbox.corner.x || clip_bbox.corner.y != bbox.corner.y ||
+ clip_text_bbox.orig.x != text_bbox.orig.x ||
+ clip_text_bbox.orig.y != text_bbox.orig.y ||
+ clip_text_bbox.corner.x != text_bbox.corner.x ||
+ clip_text_bbox.corner.y != text_bbox.corner.y ||
+ clip_pm_bbox.orig.x != pm_bbox.orig.x || clip_pm_bbox.orig.y != pm_bbox.orig.y ||
+ clip_pm_bbox.corner.x != pm_bbox.corner.x ||
+ clip_pm_bbox.corner.y != pm_bbox.corner.y) {
+ /* we must clip. */
+ BBox2XRect(&clip_bbox, &r);
+ /*printf("must clip to %g %g %g %g, clip rect %d %d %d %d\n",
+ clip_bbox.orig.x, clip_bbox.orig.y,
+ clip_bbox.corner.x, clip_bbox.corner.y,
+ r.x, r.y, r.x+r.width, r.y+r.height);*/
+ reg = XCreateRegion();
+ XUnionRectWithRegion(&r, reg, reg);
+ if (wi->current_clip) {
+ reg2 = XCreateRegion();
+ XIntersectRegion(reg, wi->current_clip->region, reg2);
+ XDestroyRegion(reg);
+ reg = reg2;
+ }
+ XSetRegion(wi->dpy, wi->gc, reg);
+ XDestroyRegion(reg);
+ restore = True;
+ }
+ else {
+ if (restore) {
+ /* Restore the previous clip. */
+ if (wi->current_clip) {
+ XSetRegion(wi->dpy, wi->gc, wi->current_clip->region);
+ }
+ else {
+ XSetRegion(wi->dpy, wi->gc, wi->damaged_region);
+ }
+ restore = False;
+ }
+ }
+
+ /*
+ * Draw the background.
+ */
+ if (ISSET(field_ptr->flags, FILLED_BIT)) {
+ values.foreground = RadarPixel(field_ptr->back_color);
+
+ if (field_ptr->tile != RadarUnspecifiedImage) { /* Fill tiled */
+ Pixmap pmap = GetImagePixmap(wi->win, field_ptr->tile);
+ 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 != RadarUnspecifiedPattern) { /* 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(&clip_bbox, &r);
+ XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height);
+ }
+
+ /*
+ * Draw the image and the text, whichever 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 != RadarUnspecifiedImage) {
+ Tk_RedrawImage(field_ptr->image,
+ clip_pm_bbox.orig.x-pm_bbox.orig.x,
+ clip_pm_bbox.orig.y-pm_bbox.orig.y,
+ REAL_TO_INT(clip_pm_bbox.corner.x-clip_pm_bbox.orig.x),
+ REAL_TO_INT(clip_pm_bbox.corner.y-clip_pm_bbox.orig.y),
+ wi->draw_buffer,
+ clip_pm_bbox.orig.x, clip_pm_bbox.orig.y);
+ }
+ }
+ else {
+ /*
+ * Draw the text.
+ */
+ if (field_ptr->text && strlen(field_ptr->text)) {
+ values.foreground = RadarPixel(field_ptr->color);
+ values.fill_style = FillSolid;
+ values.font = RadarFontId(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, strlen(field_ptr->text),
+ text_pos.x, text_pos.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 = RadarPixel(field_ptr->border_color);
+ 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);
+ }
+ }
+ }
+
+ if (restore) {
+ /* Restore the previous clip. */
+ if (wi->current_clip) {
+ XSetRegion(wi->dpy, wi->gc, wi->current_clip->region);
+ }
+ else {
+ XSetRegion(wi->dpy, wi->gc, wi->damaged_region);
+ }
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * IsFieldsSensitive --
+ *
+ **********************************************************************************
+ */
+static RadarBool
+IsFieldSensitive(FieldSet field_set,
+ int part)
+{
+ if ((part >= 0) && (part < field_set->num_fields)) {
+ return ISSET(field_set->fields[part].flags, FIELD_SENSITIVE_BIT);
+ }
+ else {
+ return False;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * FieldsPick --
+ * Return the first field that contains <x, y>.
+ * A field is selected if <x, y> is over a non transparent area.
+ * Such areas are : a solid filled background, a text, an icon.
+ * This does *NOT* do with *GLOBAL* visible and sensitive.
+ * But we need to take into account local field visible and
+ * sensitive as they modifiy local transparency. Local means
+ * within a single item.
+ *
+ **********************************************************************************
+ */
+static double
+FieldsPick(FieldSet field_set,
+ RadarPoint *p,
+ int *part)
+{
+ Field field_ptr;
+ RadarBBox 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,
+ RadarBBox *area)
+{
+ Field field_ptr;
+ RadarBBox bbox;
+ int inside = -1;
+ int i;
+ RadarBool 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(Item item,
+ int alignment)
+{
+ int i;
+ FieldSet field_set;
+ Field field;
+
+ if (!item->class->has_fields) {
+ return;
+ }
+ if ((alignment >= AA_LEFT) && (alignment <= AA_RIGHT)) {
+ field_set = item->class->GetFieldSet(item);
+ for (i = 0; i < field_set->num_fields; i++) {
+ field = &field_set->fields[i];
+ if (field->auto_alignment.automatic) {
+ field->alignment = field->auto_alignment.align[alignment];
+ }
+ }
+ }
+}
+
+
+static void
+Damage(WidgetInfo *wi,
+ RadarBBox *damage)
+{
+ if ((damage == NULL) || IsEmptyBBox(damage)) {
+ return;
+ }
+
+ /*printf("damaging area: %g %g %g %g\n", damage->orig.x,
+ damage->orig.y, damage->corner.x, damage->corner.y);*/
+
+ if (IsEmptyBBox(&wi->damaged_area)) {
+ wi->damaged_area.orig.x = damage->orig.x;
+ wi->damaged_area.orig.y = damage->orig.y;
+ wi->damaged_area.corner.x = damage->corner.x;
+ wi->damaged_area.corner.y = damage->corner.y;
+ }
+ else {
+ wi->damaged_area.orig.x = MIN(wi->damaged_area.orig.x, damage->orig.x);
+ wi->damaged_area.orig.y = MIN(wi->damaged_area.orig.y, damage->orig.y);
+ wi->damaged_area.corner.x = MAX(wi->damaged_area.corner.x, damage->corner.x);
+ wi->damaged_area.corner.y = MAX(wi->damaged_area.corner.y, damage->corner.y);
+ }
+ if (wi->damaged_area.orig.x < 0) {
+ wi->damaged_area.orig.x = 0;
+ }
+ if (wi->damaged_area.orig.y < 0) {
+ wi->damaged_area.orig.y = 0;
+ }
+ if (wi->damaged_area.corner.x > wi->width) {
+ wi->damaged_area.corner.x = wi->width;
+ }
+ if (wi->damaged_area.orig.y > wi->height) {
+ wi->damaged_area.orig.y = wi->height;
+ }
+ /*printf("damaged area: %g %g %g %g\n", wi->damaged_area.orig.x,
+ wi->damaged_area.orig.y, wi->damaged_area.corner.x,
+ wi->damaged_area.corner.y);*/
+}
+
+
+static void
+Update(WidgetInfo *wi)
+{
+ if (ISSET(wi->top_group->inv_flags, RADAR_COORDS_FLAG) ||
+ ISSET(wi->top_group->inv_flags, RADAR_TRANSFO_FLAG)) {
+ wi->top_group->class->ComputeCoordinates(wi->top_group, False);
+ }
+}
+
+
+static void
+Repair(WidgetInfo *wi)
+{
+ XGCValues values;
+ XRectangle r;
+
+ /* To be done only if we are realized and
+ there is something to update. */
+ if (wi->realized && !IsEmptyBBox(&wi->damaged_area)) {
+
+ /* Set the whole damaged area as clip rect. */
+ /*printf("damaged area %g %g %g %g\n",
+ wi->damaged_area.orig.x, wi->damaged_area.orig.y,
+ wi->damaged_area.corner.x, wi->damaged_area.corner.y);*/
+
+ BBox2XRect(&wi->damaged_area, &r);
+ wi->damaged_region = XCreateRegion();
+ XUnionRectWithRegion(&r, wi->damaged_region, wi->damaged_region);
+
+#ifdef PERFOS
+ XStartChrono(draw_time, wi->dpy, wi->draw_buffer);
+ /*StartChrono(int_draw_time);*/
+#endif
+ /* Fill the background */
+ if (wi->tile == RadarUnspecifiedImage) {
+ values.foreground = RadarPixel(wi->back_color);
+ values.fill_style = FillSolid;
+ XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCForeground, &values);
+ }
+ else {
+ values.fill_style = FillTiled;
+ values.tile = GetImagePixmap(wi->win, wi->tile);
+ values.ts_x_origin = values.ts_y_origin = 0;
+ XChangeGC(wi->dpy, wi->gc,
+ GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin,
+ &values);
+ }
+ /*printf("filling rectangle: %d %d %d %d\n", r.x, r.y, r.width, r.height);*/
+ XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, r.x, r.y, r.width, r.height);
+
+ /* Draw the items */
+ /*printf("Drawing\n");*/
+ wi->top_group->class->Draw(wi->top_group);
+
+#ifdef PERFOS
+ /*StopChrono(int_draw_time);*/
+ XStopChrono(draw_time, wi->dpy, wi->draw_buffer);
+#endif
+ XDestroyRegion(wi->damaged_region);
+ wi->damaged_region = None;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Exported functions structs --
+ *
+ **********************************************************************************
+ */
+struct _ITEM_P ITEM_P = {
+ GlobalModuleInit,
+ CreateItem,
+ AddItemClass,
+ LookupItemClass,
+ ItemClassList,
+ Damage,
+ Repair,
+ Update,
+ ConfigureAttributes,
+ QueryAttribute,
+ InitFields,
+ CloneFields,
+ FreeFields,
+ DrawFields,
+ FieldsToArea,
+ IsFieldSensitive,
+ FieldsPick,
+ LeaderToLabel,
+ GetLabelBBox,
+ GetFieldBBox,
+ ResetTransformStack,
+ ResetClipStack
+};
+
+struct _ITEM ITEM = {
+ CloneItem,
+ DestroyItem,
+ ConfigureItem,
+ QueryItem,
+ AttributesInfo,
+ SetFieldsAutoAlign,
+ InsertItem,
+ UpdateItemPriority,
+ InsertDependentItem,
+ UpdateItemDependency,
+ RemoveItem,
+ SetId,
+ FreeId,
+ AddTag,
+ RemoveTag,
+ FreeTags,
+ ResetTransfo,
+ SetTransfo,
+ TranslateItem,
+ ScaleItem,
+ RotateItem,
+ Invalidate,
+ InvalidateItems,
+ ComposeItemTransform,
+ GetTransform
+};