diff options
Diffstat (limited to 'generic/Item.c')
-rw-r--r-- | generic/Item.c | 4363 |
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 +}; |