/* * Map.c -- Implementation of Map item. * * 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 "Types.h" #include "MapInfo.h" #include "Item.h" #include "Geo.h" #include "Draw.h" #include "WidgetInfo.h" #include "tkZinc.h" #ifdef PERFOS #include "perfos.h" #endif #include #include #include static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* ********************************************************************************** * * Specific Map item record * ********************************************************************************** */ typedef struct _MapItemStruct { ItemStruct header; /* Public data */ ZnBool filled; Pixmap fill_pattern; ZnColor color; ZnFont text_font; /* null value -> use zn_map_text_font */ char *map_info_name; ZnList symbol_patterns; /* Private data */ MapInfoId map_info; ZnList vectors; ZnList dashed_vectors; ZnList dotted_vectors; ZnList mixed_vectors; ZnList arcs; ZnList dashed_arcs; ZnList dotted_arcs; ZnList mixed_arcs; ZnList marks; ZnList symbols; ZnList texts; } MapItemStruct, *MapItem; static ZnAttrConfig map_attrs[] = { { ZN_CONFIG_COLOR, "-color", NULL, Tk_Offset(MapItemStruct, color), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(MapItemStruct, header.flags), COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(MapItemStruct, header.flags), COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-filled", NULL, Tk_Offset(MapItemStruct, filled), 1, ZN_COORDS_FLAG, False }, { ZN_CONFIG_PATTERN, "-fillpattern", NULL, Tk_Offset(MapItemStruct, fill_pattern), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_FONT, "-font", NULL, Tk_Offset(MapItemStruct, text_font), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_MAP_INFO, "-mapinfo", NULL, Tk_Offset(MapItemStruct, map_info_name), 0, ZN_COORDS_FLAG|ZN_MAP_INFO_FLAG, False }, { ZN_CONFIG_PRI, "-priority", NULL, Tk_Offset(MapItemStruct, header.priority), 0, ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, { ZN_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(MapItemStruct, header.flags), SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_PATTERNS, "-symbols", NULL, Tk_Offset(MapItemStruct, symbol_patterns), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_TAGS, "-tags", NULL, Tk_Offset(MapItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(MapItemStruct, header.flags), VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 } }; void UpdateMapInfo(ClientData client_data, MapInfoId map_info) { Item item = (Item) client_data; /*printf("updating a map 'cause of a change in mapinfo\n");*/ ITEM.Invalidate(item, ZN_COORDS_FLAG); } static void FreeLists(MapItem map) { if (map->vectors) { ZnListFree(map->vectors); } map->vectors = NULL; if (map->dashed_vectors) { ZnListFree(map->dashed_vectors); } map->dashed_vectors = NULL; if (map->dotted_vectors) { ZnListFree(map->dotted_vectors); } map->dotted_vectors = NULL; if (map->mixed_vectors) { ZnListFree(map->mixed_vectors); } map->mixed_vectors = NULL; if (map->arcs) { ZnListFree(map->arcs); } map->arcs = NULL; if (map->dashed_arcs) { ZnListFree(map->dashed_arcs); } map->dashed_arcs = NULL; if (map->dotted_arcs) { ZnListFree(map->dotted_arcs); } map->dotted_arcs = NULL; if (map->mixed_arcs) { ZnListFree(map->mixed_arcs); } map->mixed_arcs = NULL; if (map->marks) { ZnListFree(map->marks); } map->marks = NULL; if (map->symbols) { ZnListFree(map->symbols); } map->symbols = NULL; if (map->texts) { ZnListFree(map->texts); } map->texts = NULL; } /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(Item item, int *argc, Tcl_Obj *CONST *args[]) { MapItem map = (MapItem) item; WidgetInfo *wi = item->wi; SET(item->flags, VISIBLE_BIT); CLEAR(item->flags, SENSITIVE_BIT); SET(item->flags, COMPOSE_ROTATION_BIT); SET(item->flags, COMPOSE_SCALE_BIT); item->part_sensitive = 0; item->priority = DEFAULT_MAP_PRIORITY; map->filled = False; map->fill_pattern = ZnUnspecifiedPattern; map->symbol_patterns = NULL; map->color = ZnGetColorByValue(wi->win, wi->fore_color); map->text_font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(wi->map_text_font)); map->map_info_name = ""; map->map_info = NULL; map->vectors = NULL; map->dashed_vectors = NULL; map->dotted_vectors = NULL; map->mixed_vectors = NULL; map->arcs = NULL; map->dashed_arcs = NULL; map->dotted_arcs = NULL; map->mixed_arcs = NULL; map->marks = NULL; map->symbols = NULL; map->texts = NULL; return ZN_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(Item item) { MapItem map = (MapItem) item; WidgetInfo *wi = item->wi; if (map->vectors) { map->vectors = ZnListDuplicate(map->vectors); } if (map->dashed_vectors) { map->dashed_vectors = ZnListDuplicate(map->dashed_vectors); } if (map->dotted_vectors) { map->dotted_vectors = ZnListDuplicate(map->dotted_vectors); } if (map->mixed_vectors) { map->mixed_vectors = ZnListDuplicate(map->mixed_vectors); } if (map->arcs) { map->arcs = ZnListDuplicate(map->arcs); } if (map->dashed_arcs) { map->dashed_arcs = ZnListDuplicate(map->dashed_arcs); } if (map->dotted_arcs) { map->dotted_arcs = ZnListDuplicate(map->dotted_arcs); } if (map->mixed_arcs) { map->mixed_arcs = ZnListDuplicate(map->mixed_arcs); } if (map->marks) { map->marks = ZnListDuplicate(map->marks); } if (map->symbols) { map->symbols = ZnListDuplicate(map->symbols); } if (map->texts) { map->texts = ZnListDuplicate(map->texts); } if (strlen(map->map_info_name) != 0) { char *text; text = ZnMalloc((strlen(map->map_info_name) + 1) * sizeof(char)); strcpy(text, map->map_info_name); map->map_info_name = text; map->map_info = ZnGetMapInfo(wi->interp, map->map_info_name, UpdateMapInfo, (ClientData) map); } map->color = ZnGetColorByValue(wi->win, map->color); map->text_font = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(map->text_font)); if (map->fill_pattern != ZnUnspecifiedPattern) { map->fill_pattern = Tk_GetBitmap(wi->interp, wi->win, Tk_NameOfBitmap(wi->dpy, map->fill_pattern)); } if (map->symbol_patterns) { Pixmap *pats, *new_pats; int i, num_pats; pats = (Pixmap *) ZnListArray(map->symbol_patterns); num_pats = ZnListSize(map->symbol_patterns); map->symbol_patterns = ZnListNew(num_pats, sizeof(Pixmap)); new_pats = (Pixmap *) ZnListArray(map->symbol_patterns); for (i = 0; i < num_pats; i++) { new_pats[i] = Tk_GetBitmap(wi->interp, wi->win, Tk_NameOfBitmap(wi->dpy, pats[i])); } } } /* ********************************************************************************** * * Destroy -- * Free the Map storage. * ********************************************************************************** */ static void Destroy(Item item) { MapItem map = (MapItem) item; FreeLists(map); ZnFreeColor(map->color); Tk_FreeFont(map->text_font); if (map->fill_pattern != ZnUnspecifiedPattern) { Tk_FreeBitmap(item->wi->dpy, map->fill_pattern); } if (map->symbol_patterns) { Pixmap *pats; int i, num_pats; pats = (Pixmap *) ZnListArray(map->symbol_patterns); num_pats = ZnListSize(map->symbol_patterns); for (i = 0; i < num_pats; i++) { Tk_FreeBitmap(item->wi->dpy, pats[i]); } ZnListFree(map->symbol_patterns); } if (strlen(map->map_info_name) != 0) { ZnFree(map->map_info_name); } if (map->map_info != NULL) { ZnFreeMapInfo(map->map_info, UpdateMapInfo, (ClientData) map); } } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(Item item, int argc, Tcl_Obj *CONST argv[], int *flags) { WidgetInfo *wi = item->wi; MapItem map = (MapItem) item; if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == ZN_ERROR) { return ZN_ERROR; } if (ISSET(*flags, ZN_MAP_INFO_FLAG)) { MapInfoId map_info; ZnBool error = False; if (strlen(map->map_info_name) != 0) { map_info = ZnGetMapInfo(wi->interp, map->map_info_name, UpdateMapInfo, (ClientData) map); if (!map_info) { error = True; } } else { map_info = NULL; } if (!error) { if (map->map_info != NULL) { ZnFreeMapInfo(map->map_info, UpdateMapInfo, (ClientData) map); } map->map_info = map_info; } else { return ZN_ERROR; } } return ZN_OK; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(Item item, int argc, Tcl_Obj *CONST argv[]) { if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == ZN_ERROR) { return ZN_ERROR; } return ZN_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(Item item, ZnBool force) { WidgetInfo *wi = item->wi; MapItem map = (MapItem) item; MapInfoId map_info; MapInfoLineStyle line_style; int line_width; MapInfoTextStyle text_style; char symbol; char *text; unsigned int i, j, cnt; unsigned int num_points; unsigned int num_dashed_points; unsigned int num_dotted_points; unsigned int num_mixed_points; unsigned int num_arcs; unsigned int num_dashed_arcs; unsigned int num_dotted_arcs; unsigned int num_mixed_arcs; unsigned int num_marks; ZnPoint *vectors, *dashed_vectors, *dotted_vectors; ZnPoint *mixed_vectors, *marks; XArc *arcs, *dashed_arcs, *dotted_arcs, *mixed_arcs; ZnPoint *symbols, *texts; ZnPoint from, to, center; ZnPoint tmp_from, tmp_to; XArc arc; ZnBBox bbox, bbox_inter, zn_bbox; int x_from_w, y_from_w, x_to_w, y_to_w; int radius, start_angle, extend; unsigned int radius_w; MapInfoPoint new_marks; unsigned int n_new_marks; ZnFont text_font; int sym_w2=0, sym_h2=0; ResetBBox(&item->item_bounding_box); if (map->map_info == NULL) { return; } zn_bbox.orig.x = zn_bbox.orig.y = 0; zn_bbox.corner.x = wi->width; zn_bbox.corner.y = wi->height; map_info = map->map_info; num_points = 0; num_dashed_points = 0; num_dotted_points = 0; num_mixed_points = 0; num_marks = 0; num_arcs = 0; num_dashed_arcs = 0; num_dotted_arcs = 0; num_mixed_arcs = 0; /* * Experimental code to help trap out of bounds * errors occuring as the result of improper use * of MapInfo/Map (i.e not doing a configure on * the MapInfo attribute after a reconfiguration * of the MapInfo. This version is more secure * but slower than the previous one. */ /* * First discover how many component of each kind * there is in the MapInfo. */ cnt = MapInfoNumLines(map_info); for (i = 0; i < cnt; i++) { MapInfoGetLine(map_info, i, NULL, &line_style, NULL, NULL, NULL, NULL, NULL); switch (line_style) { case MapInfoLineSimple: num_points += 2; break; case MapInfoLineDashed: num_dashed_points += 2; break; case MapInfoLineDotted: num_dotted_points += 2; break; case MapInfoLineMixed: num_mixed_points += 2; break; case MapInfoLineMarked: num_points += 2; MapInfoGetMarks(map_info, i, NULL, &n_new_marks); num_marks += n_new_marks; break; } } cnt = MapInfoNumTexts(map_info); for (i = 0; i < cnt; i++) { MapInfoGetText(map_info, i, NULL, &text_style, &line_style, NULL, NULL, NULL); if (text_style == MapInfoUnderlinedText) { switch (line_style) { case MapInfoLineSimple: case MapInfoLineMarked: num_points += 2; break; case MapInfoLineDotted: num_dotted_points += 2; break; case MapInfoLineMixed: num_mixed_points += 2; break; case MapInfoLineDashed: num_dashed_points += 2; break; } } } cnt = MapInfoNumArcs(map_info); for (i = 0; i < cnt; i++) { MapInfoGetArc(map_info, i, NULL, &line_style, NULL, NULL, NULL, NULL, NULL, NULL); switch (line_style) { case MapInfoLineSimple: case MapInfoLineMarked: num_arcs += 2; break; case MapInfoLineDotted: num_dotted_arcs += 2; break; case MapInfoLineMixed: num_mixed_arcs += 2; break; case MapInfoLineDashed: num_dashed_arcs += 2; break; } } /* * Make sure the various lists are large enough * to contain the computed amount of points. * Later we will cut them to take into account the * clipping and the filled attribute. */ if (!map->vectors) { map->vectors = ZnListNew(num_points, sizeof(ZnPoint)); } ZnListAssertSize(map->vectors, num_points); if (!map->dashed_vectors) { map->dashed_vectors = ZnListNew(num_dashed_points, sizeof(ZnPoint)); } ZnListAssertSize(map->dashed_vectors, num_dashed_points); if (!map->dotted_vectors) { map->dotted_vectors = ZnListNew(num_dotted_points, sizeof(ZnPoint)); } ZnListAssertSize(map->dotted_vectors, num_dotted_points); if (!map->mixed_vectors) { map->mixed_vectors = ZnListNew(num_mixed_points, sizeof(ZnPoint)); } ZnListAssertSize(map->mixed_vectors, num_mixed_points); if (!map->arcs) { map->arcs = ZnListNew(num_arcs, sizeof(XArc)); } ZnListAssertSize(map->arcs, num_arcs); if (!map->dashed_arcs) { map->dashed_arcs = ZnListNew(num_dashed_arcs, sizeof(XArc)); } ZnListAssertSize(map->dashed_arcs, num_dashed_arcs); if (!map->dotted_arcs) { map->dotted_arcs = ZnListNew(num_dotted_arcs, sizeof(XArc)); } ZnListAssertSize(map->dotted_arcs, num_dotted_arcs); if (!map->mixed_arcs) { map->mixed_arcs = ZnListNew(num_mixed_arcs, sizeof(XArc)); } ZnListAssertSize(map->mixed_arcs, num_mixed_arcs); if (!map->marks) { map->marks = ZnListNew(num_marks, sizeof(ZnPoint)); } ZnListAssertSize(map->marks, num_marks); if (!map->symbols) { map->symbols = ZnListNew(MapInfoNumSymbols(map_info), sizeof(ZnPoint)); } ZnListAssertSize(map->symbols, MapInfoNumSymbols(map_info)); if (!map->texts) { map->texts = ZnListNew(MapInfoNumTexts(map_info), sizeof(ZnPoint)); } ZnListAssertSize(map->texts, MapInfoNumTexts(map_info)); /* * Ask the pointers to the actual arrays. */ vectors = (ZnPoint *) ZnListArray(map->vectors); dashed_vectors = (ZnPoint *) ZnListArray(map->dashed_vectors); dotted_vectors = (ZnPoint *) ZnListArray(map->dotted_vectors); mixed_vectors = (ZnPoint *) ZnListArray(map->mixed_vectors); arcs = (XArc *) ZnListArray(map->arcs); dashed_arcs = (XArc *) ZnListArray(map->dashed_arcs); dotted_arcs = (XArc *) ZnListArray(map->dotted_arcs); mixed_arcs = (XArc *) ZnListArray(map->mixed_arcs); marks = (ZnPoint *) ZnListArray(map->marks); symbols = (ZnPoint *) ZnListArray(map->symbols); texts = (ZnPoint *) ZnListArray(map->texts); if (num_marks && (wi->map_distance_symbol != ZnUnspecifiedPattern)) { Tk_SizeOfBitmap(wi->dpy, wi->map_distance_symbol, &sym_w2, &sym_h2); sym_w2 = (sym_w2+1)/2; sym_h2 = (sym_h2+1)/2; } /*printf("Map: %d %d %d %d %d, texts: %d, symbols: %d\n", num_points, num_dashed_points, num_dotted_points, num_mixed_points, num_marks, MapInfoNumTexts(map_info), MapInfoNumSymbols(map_info));*/ /* * Reset the counts of points to compute the actual * counts taking into account the clipping and the * filled attribute. */ num_points = 0; num_dashed_points = 0; num_dotted_points = 0; num_mixed_points = 0; num_marks = 0; num_arcs = 0; num_dashed_arcs = 0; num_dotted_arcs = 0; num_mixed_arcs = 0; cnt = MapInfoNumLines(map_info); for (i = 0; i < cnt; i++) { MapInfoGetLine(map_info, i, NULL, &line_style, &line_width, &x_from_w, &y_from_w, &x_to_w, &y_to_w); tmp_from.x = x_from_w; tmp_from.y = y_from_w; tmp_to.x = x_to_w; tmp_to.y = y_to_w; ZnTransformPoint(wi->current_transfo, &tmp_from, &from); ZnTransformPoint(wi->current_transfo, &tmp_to, &to); /* * Skip zero length and outside segments. */ if ((from.x == to.x) && (from.y == to.y)) { continue; } if (!map->filled) { if (LineInBBox(&from, &to, &zn_bbox) < 0) { continue; } } switch (line_style) { case MapInfoLineSimple: vectors[num_points] = from; num_points++; vectors[num_points] = to; num_points++; break; case MapInfoLineDashed: if (!map->filled) { dashed_vectors[num_dashed_points] = from; num_dashed_points++; dashed_vectors[num_dashed_points] = to; num_dashed_points++; } break; case MapInfoLineDotted: if (!map->filled) { dotted_vectors[num_dotted_points] = from; num_dotted_points++; dotted_vectors[num_dotted_points] = to; num_dotted_points++; } break; case MapInfoLineMixed: if (!map->filled) { mixed_vectors[num_mixed_points] = from; num_mixed_points++; mixed_vectors[num_mixed_points] = to; num_mixed_points++; } break; case MapInfoLineMarked: if (!map->filled) { vectors[num_points] = from; num_points++; vectors[num_points] = to; num_points++; if (wi->map_distance_symbol != ZnUnspecifiedPattern) { MapInfoGetMarks(map_info, i, &new_marks, &n_new_marks); for (j = 0; j < n_new_marks; j++) { /* * The transform can be put outside the loop when * MapInfo point type is modified to ZnPoint. * Will use then ZnTransformPoints. */ tmp_from.x = new_marks[j].x; tmp_from.y = new_marks[j].y; ZnTransformPoint(wi->current_transfo, &tmp_from, &marks[num_marks]); AddPointToBBox(&item->item_bounding_box, marks[num_marks].x-sym_w2, marks[num_marks].y-sym_h2); AddPointToBBox(&item->item_bounding_box, marks[num_marks].x+sym_w2, marks[num_marks].x+sym_h2); num_marks++; } } } break; } } cnt = MapInfoNumArcs(map_info); for (i = 0; i < cnt; i++) { ZnPoint xp; MapInfoGetArc(map_info, i, NULL, &line_style, &line_width, &x_from_w, &y_from_w, &radius_w, &start_angle, &extend); tmp_from.x = x_from_w; tmp_from.y = y_from_w; ZnTransformPoint(wi->current_transfo, &tmp_from, ¢er); tmp_from.x += radius_w; tmp_from.y = 0; ZnTransformPoint(wi->current_transfo, &tmp_from, &xp); radius = xp.x - center.x; bbox.orig.x = center.x - radius; bbox.orig.y = center.y - radius; bbox.corner.x = bbox.orig.x + (2 * radius); bbox.corner.y = bbox.orig.y + (2 * radius); /* * Skip zero length and outside arcs. */ if (!radius || !extend) { continue; } IntersectBBox(&zn_bbox, &bbox, &bbox_inter); if (IsEmptyBBox(&bbox_inter)) { continue; } arc.x = center.x - radius; arc.y = center.y - radius; arc.width = 2 * radius; arc.height = arc.width; arc.angle1 = start_angle; arc.angle2 = extend; switch (line_style) { case MapInfoLineSimple: case MapInfoLineMarked: arcs[num_arcs] = arc; num_arcs++; bbox.orig.x = arc.x; bbox.orig.y = arc.y; bbox.corner.x = bbox.orig.x + arc.width + 1; bbox.corner.y = bbox.orig.y + arc.height + 1; AddBBoxToBBox(&item->item_bounding_box, &bbox); break; case MapInfoLineDashed: if (!map->filled) { dashed_arcs[num_dashed_arcs] = arc; num_dashed_arcs++; bbox.orig.x = arc.x; bbox.orig.y = arc.y; bbox.corner.x = bbox.orig.x + arc.width + 1; bbox.corner.y = bbox.orig.y + arc.height + 1; AddBBoxToBBox(&item->item_bounding_box, &bbox); } break; case MapInfoLineDotted: if (!map->filled) { dotted_arcs[num_dotted_arcs] = arc; num_dotted_arcs++; bbox.orig.x = arc.x; bbox.orig.y = arc.y; bbox.corner.x = bbox.orig.x + arc.width + 1; bbox.corner.y = bbox.orig.y + arc.height + 1; AddBBoxToBBox(&item->item_bounding_box, &bbox); } break; case MapInfoLineMixed: if (!map->filled) { mixed_arcs[num_mixed_arcs] = arc; num_mixed_arcs++; bbox.orig.x = arc.x; bbox.orig.y = arc.y; bbox.corner.x = bbox.orig.x + arc.width + 1; bbox.corner.y = bbox.orig.y + arc.height + 1; AddBBoxToBBox(&item->item_bounding_box, &bbox); } break; } } /* * Truncate arc lists to the real size. */ ZnListAssertSize(map->arcs, num_arcs); ZnListAssertSize(map->dashed_arcs, num_dashed_arcs); ZnListAssertSize(map->dotted_arcs, num_dotted_arcs); ZnListAssertSize(map->mixed_arcs, num_mixed_arcs); /* If map is filled, only the vectors description is valid. */ if (!map->filled) { if (map->symbol_patterns) { Pixmap sym, *syms = (Pixmap *) ZnListArray(map->symbol_patterns); int num_syms = ZnListSize(map->symbol_patterns); cnt = MapInfoNumSymbols(map_info); for (i = 0; i < cnt; i++) { MapInfoGetSymbol(map_info, i, NULL, &x_from_w, &y_from_w, &symbol); tmp_from.x = x_from_w; tmp_from.y = y_from_w; ZnTransformPoint(wi->current_transfo, &tmp_from, &symbols[i]); sym = syms[symbol%num_syms]; if (sym != ZnUnspecifiedPattern) { Tk_SizeOfBitmap(wi->dpy, sym, &sym_w2, &sym_h2); sym_w2 = (sym_w2+1)/2; sym_h2 = (sym_h2+1)/2; AddPointToBBox(&item->item_bounding_box, symbols[i].x-sym_w2, symbols[i].y-sym_h2); AddPointToBBox(&item->item_bounding_box, symbols[i].x+sym_w2, symbols[i].y+sym_h2); } } ZnListAssertSize(map->symbols, cnt); } cnt = MapInfoNumTexts(map_info); text_font = map->text_font ? map->text_font : wi->map_text_font; for (i = 0; i < cnt; i++) { MapInfoGetText(map_info, i, NULL, &text_style, &line_style, &x_from_w, &y_from_w, &text); tmp_from.x = x_from_w; tmp_from.y = y_from_w; ZnTransformPoint(wi->current_transfo, &tmp_from, &texts[i]); AddStringToBBox(&item->item_bounding_box, text, text_font, texts[i].x, texts[i].y); if (text_style == MapInfoUnderlinedText) { GetStringBBox(text, text_font, texts[i].x, texts[i].y, &bbox); from.x = bbox.orig.x; from.y = bbox.corner.y; to.x = bbox.corner.x; to.y = bbox.corner.y; switch (line_style) { case MapInfoLineSimple: case MapInfoLineMarked: vectors[num_points] = from; num_points++; vectors[num_points] = to; num_points++; break; case MapInfoLineDashed: dashed_vectors[num_dashed_points] = from; num_dashed_points++; dashed_vectors[num_dashed_points] = to; num_dashed_points++; break; case MapInfoLineDotted: dotted_vectors[num_dotted_points] = from; num_dotted_points++; dotted_vectors[num_dotted_points] = to; num_dotted_points++; break; case MapInfoLineMixed: mixed_vectors[num_mixed_points] = from; num_mixed_points++; mixed_vectors[num_mixed_points] = to; num_mixed_points++; break; } } } ZnListAssertSize(map->texts, cnt); } /* * Truncate line lists to the real size. */ ZnListAssertSize(map->vectors, num_points); ZnListAssertSize(map->dashed_vectors, num_dashed_points); ZnListAssertSize(map->dotted_vectors, num_dotted_points); ZnListAssertSize(map->mixed_vectors, num_mixed_points); ZnListAssertSize(map->marks, num_marks); AddPointsToBBox(&item->item_bounding_box, (ZnPoint *) ZnListArray(map->vectors), ZnListSize(map->vectors)); AddPointsToBBox(&item->item_bounding_box, (ZnPoint *) ZnListArray(map->dashed_vectors), ZnListSize(map->dashed_vectors)); AddPointsToBBox(&item->item_bounding_box, (ZnPoint *) ZnListArray(map->dotted_vectors), ZnListSize(map->dotted_vectors)); AddPointsToBBox(&item->item_bounding_box, (ZnPoint *) ZnListArray(map->mixed_vectors), ZnListSize(map->mixed_vectors)); } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(Item item, ZnBBox *area, Tk_Uid tag_uid, int enclosed, ZnBool report) { return -1; } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(Item item) { WidgetInfo *wi = item->wi; MapItem map = (MapItem) item; MapInfoId map_info; ZnPoint *points; XPoint *xpoints; char *text; char tmp_str[] = "."; XGCValues values; unsigned int i, cnt, tst = 0; int line_width; if (map->map_info == NULL) { return; } map_info = map->map_info; values.foreground = ZnPixel(map->color); if (map->filled) { if (ZnListSize(map->vectors) || ZnListSize(map->arcs)) { if (map->fill_pattern == ZnUnspecifiedPattern) { /* Fill solid */ values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCForeground, &values); } else { /* Fill stippled */ values.fill_style = FillStippled; values.stipple = map->fill_pattern; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCStipple | GCForeground, &values); } cnt = ZnListSize(map->vectors); if (cnt) { ZnListAssertSize(wi->work_xpts, cnt); xpoints = (XPoint *) ZnListArray(wi->work_xpts); points = (ZnPoint *) ZnListArray(map->vectors); for (i = 0; i < cnt; i++) { xpoints[i].x = points[i].x; xpoints[i].y = points[i].y; } XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xpoints, cnt, Nonconvex, CoordModeOrigin); } if (ZnListSize(map->arcs)) { XFillArcs(wi->dpy, wi->draw_buffer, wi->gc, (XArc *) ZnListArray(map->arcs), ZnListSize(map->arcs)); } } } else { /* Not filled */ if (ZnListSize(map->vectors)) { SetLineStyle(wi->dpy, wi->gc, LINE_SIMPLE); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawSegments can't handle an unlimited number of segments in releases R4 and older */ /* XDrawSegments(wi->dpy, wi->draw_buffer, wi->gc, (XSegment *) ZnListArray(map->vectors), ZnListSize(map->vectors)/2);*/ cnt = ZnListSize(map->vectors); points = (ZnPoint *) ZnListArray(map->vectors); for (i = 0; i < cnt; i += 2) { if (LineInBBox(&points[i], &points[i+1], &wi->damaged_area) >= 0) { MapInfoGetLine(map_info, i/2, NULL, NULL, &line_width, NULL, NULL, NULL, NULL); if (line_width != values.line_width) { values.line_width = line_width; XChangeGC(wi->dpy, wi->gc, GCLineWidth, &values); } XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, points[i].x, points[i].y, points[i+1].x, points[i+1].y); tst++; } } } if (ZnListSize(map->dashed_vectors)) { SetLineStyle(wi->dpy, wi->gc, LINE_DASHED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawSegments can't handle an unlimited number of segments in releases R4 and older */ /* XDrawSegments(wi->dpy, wi->draw_buffer, wi->gc, (XSegment *) ZnListArray(map->dashed_vectors), ZnListSize(map->dashed_vectors)/2);*/ cnt = ZnListSize(map->dashed_vectors); points = (ZnPoint *) ZnListArray(map->dashed_vectors); for (i = 0; i < cnt; i += 2) { if (LineInBBox(&points[i], &points[i+1], &wi->damaged_area) >= 0) { MapInfoGetLine(map_info, i/2, NULL, NULL, &line_width, NULL, NULL, NULL, NULL); if (line_width != values.line_width) { values.line_width = line_width; XChangeGC(wi->dpy, wi->gc, GCLineWidth, &values); } XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, points[i].x, points[i].y, points[i+1].x, points[i+1].y); tst++; } } } if (ZnListSize(map->dotted_vectors)) { SetLineStyle(wi->dpy, wi->gc, LINE_DOTTED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawSegments can't handle an unlimited number of segments in releases R4 and older */ /* XDrawSegments(wi->dpy, wi->draw_buffer, wi->gc, (XSegment *) ZnListArray(map->dotted_vectors), ZnListSize(map->dotted_vectors)/2);*/ cnt = ZnListSize(map->dotted_vectors); points = (ZnPoint *) ZnListArray(map->dotted_vectors); for (i = 0; i < cnt; i += 2) { if (LineInBBox(&points[i], &points[i+1], &wi->damaged_area) >= 0) { MapInfoGetLine(map_info, i/2, NULL, NULL, &line_width, NULL, NULL, NULL, NULL); if (line_width != values.line_width) { values.line_width = line_width; XChangeGC(wi->dpy, wi->gc, GCLineWidth, &values); } XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, points[i].x, points[i].y, points[i+1].x, points[i+1].y); tst++; } } } if (ZnListSize(map->mixed_vectors)) { SetLineStyle(wi->dpy, wi->gc, LINE_MIXED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawSegments can't handle an unlimited number of segments in releases R4 and older */ /*XDrawSegments(wi->dpy, wi->draw_buffer, wi->gc, (XSegment *) ZnListArray(map->mixed_vectors), ZnListSize(map->mixed_vectors)/2);*/ cnt = ZnListSize(map->mixed_vectors); points = (ZnPoint *) ZnListArray(map->mixed_vectors); for (i = 0; i < cnt; i += 2) { if (LineInBBox(&points[i], &points[i+1], &wi->damaged_area) >= 0) { MapInfoGetLine(map_info, i/2, NULL, NULL, &line_width, NULL, NULL, NULL, NULL); if (line_width != values.line_width) { values.line_width = line_width; XChangeGC(wi->dpy, wi->gc, GCLineWidth, &values); } XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, points[i].x, points[i].y, points[i+1].x, points[i+1].y); tst++; } } } if (ZnListSize(map->arcs)) { SetLineStyle(wi->dpy, wi->gc, LINE_SIMPLE); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawArcs can't handle an unlimited number of arcs in releases R4 and older */ XDrawArcs(wi->dpy, wi->draw_buffer, wi->gc, (XArc *) ZnListArray(map->arcs), ZnListSize(map->arcs)); } if (ZnListSize(map->dashed_arcs)) { SetLineStyle(wi->dpy, wi->gc, LINE_DASHED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawArcs can't handle an unlimited number of arcs in releases R4 and older */ XDrawArcs(wi->dpy, wi->draw_buffer, wi->gc, (XArc *) ZnListArray(map->dashed_arcs), ZnListSize(map->dashed_arcs)); } if (ZnListSize(map->dotted_arcs)) { SetLineStyle(wi->dpy, wi->gc, LINE_DOTTED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawArcs can't handle an unlimited number of arcs in releases R4 and older */ XDrawArcs(wi->dpy, wi->draw_buffer, wi->gc, (XArc *) ZnListArray(map->dotted_arcs), ZnListSize(map->dotted_arcs)); } if (ZnListSize(map->mixed_arcs)) { SetLineStyle(wi->dpy, wi->gc, LINE_MIXED); values.fill_style = FillSolid; values.line_width = 0; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCLineWidth | GCForeground, &values); /* !! WARNING !! XDrawArcs can't handle an unlimited number of arcs in releases R4 and older */ XDrawArcs(wi->dpy, wi->draw_buffer, wi->gc, (XArc *) ZnListArray(map->mixed_arcs), ZnListSize(map->mixed_arcs)); } if (ZnListSize(map->texts)) { /* For the Tk widget we don't have to bother with old * compatibility issues. */ values.font = ZnFontId(map->text_font); values.fill_style = FillSolid; XChangeGC(wi->dpy, wi->gc, GCFillStyle | GCFont | GCForeground, &values); cnt = ZnListSize(map->texts); points = (ZnPoint *) ZnListArray(map->texts); for (i = 0; i < cnt; i++) { MapInfoGetText(map_info, i, NULL, NULL, NULL, NULL, NULL, &text); XDrawString(wi->dpy, wi->draw_buffer, wi->gc, points[i].x, points[i].y, text, strlen(text)); } } if (ZnListSize(map->symbols) || ZnListSize(map->marks)) { int w, h, ox, oy; Pixmap sym; values.fill_style = FillStippled; XChangeGC(wi->dpy, wi->gc, GCFillStyle, &values); if (map->symbol_patterns) { Pixmap *syms = (Pixmap *) ZnListArray(map->symbol_patterns); int num_syms = ZnListSize(map->symbol_patterns); cnt = ZnListSize(map->symbols); points = (ZnPoint *) ZnListArray(map->symbols); for (i = 0; i < cnt; i++) { MapInfoGetSymbol(map_info, i, NULL, NULL, NULL, &(tmp_str[0])); sym = syms[tmp_str[0]%num_syms]; if (sym != ZnUnspecifiedPattern) { Tk_SizeOfBitmap(wi->dpy, sym, &w, &h); ox = points[i].x-w/2; oy = points[i].y-h/2; values.stipple = sym; values.ts_x_origin = ox; values.ts_y_origin = oy; XChangeGC(wi->dpy, wi->gc, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &values); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, ox, oy, w, h); } } } if (wi->map_distance_symbol != ZnUnspecifiedPattern) { Tk_SizeOfBitmap(wi->dpy, wi->map_distance_symbol, &w, &h); cnt = ZnListSize(map->marks); points = (ZnPoint *) ZnListArray(map->marks); values.stipple = wi->map_distance_symbol; XChangeGC(wi->dpy, wi->gc, GCStipple, &values); for (i = 0; i < cnt; i++) { ox = points[i].x-w/2; oy = points[i].y-h/2; values.ts_x_origin = ox; values.ts_y_origin = oy; XChangeGC(wi->dpy, wi->gc, GCTileStipXOrigin|GCTileStipYOrigin, &values); XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, ox, oy, w, h); } } } } } /* ********************************************************************************** * * Render -- * ********************************************************************************** */ static void Render(Item item) { /*WidgetInfo *wi = item->wi; MapItem map = (MapItem) item;*/ } /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static ZnBool IsSensitive(Item item, int item_part) { return (ISSET(item->flags, SENSITIVE_BIT) && item->parent->class->IsSensitive(item->parent, ZN_NO_PART)); } /* ********************************************************************************** * * Pick -- * This is *NOT* correct but for now we will tell that we are * transparent even if we are solid filled. * * !!!! We need to say we are opaque at least if we are solid * filled. !!!! * ********************************************************************************** */ static double Pick(Item item, ZnPoint *p, Item start_item, int aperture, Item *a_item, int *part) { return 1e40; } /* ********************************************************************************** * * Coords -- * Nothing to do for maps (or too complex anyway). * ********************************************************************************** */ static int Coords(Item item, int contour, int index, int cmd, ZnPoint **pts, int *num_pts) { Tcl_AppendResult(item->wi->interp, " maps doesn't support the coords command", NULL); return ZN_ERROR; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(Item item, PostScriptInfo ps_info) { } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ItemClassStruct MAP_ITEM_CLASS = { sizeof(MapItemStruct), False, /* has_fields */ 0, /* num_parts */ False, /* has_anchors */ "map", map_attrs, Init, Clone, Destroy, Configure, Query, NULL, /* GetFieldSet */ NULL, /* GetAnchor */ NULL, /* GetClipVertices */ Coords, NULL, /* InsertChars */ NULL, /* DeleteChars */ NULL, /* Cursor */ NULL, /* Index */ NULL, /* Part */ NULL, /* Selection */ NULL, /* Contour */ ComputeCoordinates, ToArea, Draw, Render, IsSensitive, Pick, NULL, /* PickVertex */ PostScript }; ZnItemClassId ZnMap = (ZnItemClassId) &MAP_ITEM_CLASS;