/* * 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 /* For INT_MAX */ #include #include #include #include #include #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, "-font", NULL, Tk_Offset(FieldStruct, font), 0, RADAR_DRAW_FLAG|RADAR_CLFC_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) = (ReliefStyle) 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 = real_width; field_ptr->corner_y = 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); /*printf("field %d bbox %g %g %g %g\n", i, tmp_bbox.orig.x, tmp_bbox.orig.y, tmp_bbox.corner.x, tmp_bbox.corner.y);*/ AddBBoxToBBox(&bbox, &tmp_bbox); } field_set->label_width = bbox.corner.x; field_set->label_height = bbox.corner.y; /*printf("GetLabelBBox size before clipping; w = %g, h = %g\n", field_set->label_width, field_set->label_height);*/ if (LabelFormatGetClipBox(lf, &clip_w, &clip_h)) { if (clip_w < field_set->label_width) { field_set->label_width = clip_w; } if (clip_h < field_set->label_height) { field_set->label_height = clip_h; } } *w = field_set->label_width; *h = field_set->label_height; /*printf("GetLabelBBox returns computed size; w = %g, h = %g\n", *w, *h);*/ } /* ********************************************************************************** * * GetFieldBBox -- * Compute the location of the field described * by the field entry index in the item current LabelFormat. * ********************************************************************************** */ static void GetFieldBBox(FieldSet field_set, unsigned int index, 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 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 . * A field is selected if is over a non transparent area. * Such areas are : a solid filled background, a text, an icon. * This does *NOT* do with *GLOBAL* visible and sensitive. * But we need to take into account local field visible and * sensitive as they modifiy local transparency. Local means * within a single item. * ********************************************************************************** */ static double FieldsPick(FieldSet field_set, 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 };