source: trunk/kitgen/8.x/blt/generic/bltGrMarker.c@ 176

Last change on this file since 176 was 175, checked in by demin, 12 years ago

initial commit

File size: 143.7 KB
Line 
1
2/*
3 * bltGrMarker.c --
4 *
5 * This module implements markers for the BLT graph widget.
6 *
7 * Copyright 1993-1998 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 */
27
28#include "bltGraph.h"
29#include "bltChain.h"
30#include "bltGrElem.h"
31
32#define GETBITMAP(b) \
33 (((b)->destBitmap == None) ? (b)->srcBitmap : (b)->destBitmap)
34
35#define MAX_OUTLINE_POINTS 12
36
37/* Map graph coordinates to normalized coordinates [0..1] */
38#define NORMALIZE(A,x) (((x) - (A)->axisRange.min) / (A)->axisRange.range)
39
40#define DEF_MARKER_ANCHOR "center"
41#define DEF_MARKER_BACKGROUND RGB_WHITE
42#define DEF_MARKER_BG_MONO RGB_WHITE
43#define DEF_MARKER_BITMAP (char *)NULL
44#define DEF_MARKER_CAP_STYLE "butt"
45#define DEF_MARKER_COORDS (char *)NULL
46#define DEF_MARKER_DASHES (char *)NULL
47#define DEF_MARKER_DASH_OFFSET "0"
48#define DEF_MARKER_ELEMENT (char *)NULL
49#define DEF_MARKER_FOREGROUND RGB_BLACK
50#define DEF_MARKER_FG_MONO RGB_BLACK
51#define DEF_MARKER_FILL_COLOR RGB_RED
52#define DEF_MARKER_FILL_MONO RGB_WHITE
53#define DEF_MARKER_FONT STD_FONT
54#define DEF_MARKER_GAP_COLOR RGB_PINK
55#define DEF_MARKER_GAP_MONO RGB_BLACK
56#define DEF_MARKER_HEIGHT "0"
57#define DEF_MARKER_HIDE "no"
58#define DEF_MARKER_JOIN_STYLE "miter"
59#define DEF_MARKER_JUSTIFY "left"
60#define DEF_MARKER_LINE_WIDTH "1"
61#define DEF_MARKER_MAP_X "x"
62#define DEF_MARKER_MAP_Y "y"
63#define DEF_MARKER_NAME (char *)NULL
64#define DEF_MARKER_OUTLINE_COLOR RGB_BLACK
65#define DEF_MARKER_OUTLINE_MONO RGB_BLACK
66#define DEF_MARKER_PAD "4"
67#define DEF_MARKER_ROTATE "0.0"
68#define DEF_MARKER_SCALE "1.0"
69#define DEF_MARKER_SHADOW_COLOR (char *)NULL
70#define DEF_MARKER_SHADOW_MONO (char *)NULL
71#define DEF_MARKER_STATE "normal"
72#define DEF_MARKER_STIPPLE (char *)NULL
73#define DEF_MARKER_TEXT (char *)NULL
74#define DEF_MARKER_UNDER "no"
75#define DEF_MARKER_WIDTH "0"
76#define DEF_MARKER_WINDOW (char *)NULL
77#define DEF_MARKER_XOR "no"
78#define DEF_MARKER_X_OFFSET "0"
79#define DEF_MARKER_Y_OFFSET "0"
80
81#define DEF_MARKER_TEXT_TAGS "Text all"
82#define DEF_MARKER_IMAGE_TAGS "Image all"
83#define DEF_MARKER_BITMAP_TAGS "Bitmap all"
84#define DEF_MARKER_WINDOW_TAGS "Window all"
85#define DEF_MARKER_POLYGON_TAGS "Polygon all"
86#define DEF_MARKER_LINE_TAGS "Line all"
87
88static Tk_OptionParseProc StringToCoordinates;
89static Tk_OptionPrintProc CoordinatesToString;
90static Tk_CustomOption coordsOption =
91{
92 StringToCoordinates, CoordinatesToString, (ClientData)0
93};
94extern Tk_CustomOption bltColorPairOption;
95extern Tk_CustomOption bltDashesOption;
96extern Tk_CustomOption bltDistanceOption;
97extern Tk_CustomOption bltListOption;
98extern Tk_CustomOption bltPadOption;
99extern Tk_CustomOption bltPositiveDistanceOption;
100extern Tk_CustomOption bltShadowOption;
101extern Tk_CustomOption bltStateOption;
102extern Tk_CustomOption bltXAxisOption;
103extern Tk_CustomOption bltYAxisOption;
104
105typedef Marker *(MarkerCreateProc) _ANSI_ARGS_((void));
106typedef void (MarkerDrawProc) _ANSI_ARGS_((Marker *markerPtr,
107 Drawable drawable));
108typedef void (MarkerFreeProc) _ANSI_ARGS_((Graph *graphPtr, Marker *markerPtr));
109typedef int (MarkerConfigProc) _ANSI_ARGS_((Marker *markerPtr));
110typedef void (MarkerMapProc) _ANSI_ARGS_((Marker *markerPtr));
111typedef void (MarkerPostScriptProc) _ANSI_ARGS_((Marker *markerPtr,
112 PsToken psToken));
113typedef int (MarkerPointProc) _ANSI_ARGS_((Marker *markerPtr,
114 Point2D *samplePtr));
115typedef int (MarkerRegionProc) _ANSI_ARGS_((Marker *markerPtr,
116 Extents2D *extsPtr, int enclosed));
117
118typedef struct {
119 Tk_ConfigSpec *configSpecs; /* Marker configuration specifications */
120
121 MarkerConfigProc *configProc;
122 MarkerDrawProc *drawProc;
123 MarkerFreeProc *freeProc;
124 MarkerMapProc *mapProc;
125 MarkerPointProc *pointProc;
126 MarkerRegionProc *regionProc;
127 MarkerPostScriptProc *postscriptProc;
128
129} MarkerClass;
130
131
132
133/*
134 * -------------------------------------------------------------------
135 *
136 * Marker --
137 *
138 * Structure defining the generic marker. In C++ parlance this
139 * would be the base type from which all markers are derived.
140 *
141 * This structure corresponds with the specific types of markers.
142 * Don't change this structure without changing the individual
143 * marker structures of each type below.
144 *
145 * -------------------------------------------------------------------
146 */
147struct MarkerStruct {
148 char *name; /* Identifier for marker in list */
149
150 Blt_Uid classUid; /* Type of marker. */
151
152 Graph *graphPtr; /* Graph widget of marker. */
153
154 unsigned int flags;
155
156 char **tags;
157
158 int hidden; /* If non-zero, don't display the marker. */
159
160 Blt_HashEntry *hashPtr;
161
162 Blt_ChainLink *linkPtr;
163
164 Point2D *worldPts; /* Coordinate array to position marker */
165 int nWorldPts; /* Number of points in above array */
166
167 char *elemName; /* Element associated with marker */
168
169 Axis2D axes;
170
171 int drawUnder; /* If non-zero, draw the marker
172 * underneath any elements. This can
173 * be a performance penalty because
174 * the graph must be redraw entirely
175 * each time the marker is redrawn. */
176
177 int clipped; /* Indicates if the marker is totally
178 * clipped by the plotting area. */
179
180 int xOffset, yOffset; /* Pixel offset from graph position */
181
182 MarkerClass *classPtr;
183
184 int state;
185};
186
187/*
188 * -------------------------------------------------------------------
189 *
190 * TextMarker --
191 *
192 * -------------------------------------------------------------------
193 */
194typedef struct {
195 char *name; /* Identifier for marker */
196 Blt_Uid classUid; /* Type of marker */
197 Graph *graphPtr; /* The graph this marker belongs to */
198 unsigned int flags;
199 char **tags;
200 int hidden; /* If non-zero, don't display the
201 * marker. */
202
203 Blt_HashEntry *hashPtr;
204 Blt_ChainLink *linkPtr;
205
206 Point2D *worldPts; /* Position of marker (1 X-Y coordinate) in
207 * world (graph) coordinates. */
208 int nWorldPts; /* Number of points */
209
210 char *elemName; /* Element associated with marker */
211 Axis2D axes;
212 int drawUnder; /* If non-zero, draw the marker
213 * underneath any elements. There can
214 * be a performance because the graph
215 * must be redraw entirely each time
216 * this marker is redrawn. */
217 int clipped; /* Indicates if the marker is totally
218 * clipped by the plotting area. */
219 int xOffset, yOffset; /* pixel offset from anchor */
220
221 MarkerClass *classPtr;
222
223 int state;
224 /*
225 * Text specific fields and attributes
226 */
227#ifdef notdef
228 char *textVarName; /* Name of variable (malloc'ed) or
229 * NULL. If non-NULL, graph displays
230 * the contents of this variable. */
231#endif
232 char *string; /* Text string to be display. The string
233 * make contain newlines. */
234
235 Tk_Anchor anchor; /* Indicates how to translate the given
236 * marker position. */
237
238 Point2D anchorPos; /* Translated anchor point. */
239
240 int width, height; /* Dimension of bounding box. */
241
242 TextStyle style; /* Text attributes (font, fg, anchor, etc) */
243
244 TextLayout *textPtr; /* Contains information about the layout
245 * of the text. */
246 Point2D outline[5];
247 XColor *fillColor;
248 GC fillGC;
249} TextMarker;
250
251
252static Tk_ConfigSpec textConfigSpecs[] =
253{
254 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
255 DEF_MARKER_ANCHOR, Tk_Offset(TextMarker, anchor), 0},
256 {TK_CONFIG_COLOR, "-background", "background", "MarkerBackground",
257 (char *)NULL, Tk_Offset(TextMarker, fillColor),
258 TK_CONFIG_NULL_OK},
259 {TK_CONFIG_SYNONYM, "-bg", "background", "Background",
260 (char *)NULL, 0, 0},
261 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
262 DEF_MARKER_TEXT_TAGS, Tk_Offset(Marker, tags),
263 TK_CONFIG_NULL_OK, &bltListOption},
264 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
265 DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts),
266 TK_CONFIG_NULL_OK, &coordsOption},
267 {TK_CONFIG_STRING, "-element", "element", "Element",
268 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
269 {TK_CONFIG_SYNONYM, "-fg", "foreground", "Foreground",
270 (char *)NULL, 0, 0},
271 {TK_CONFIG_SYNONYM, "-fill", "background", (char *)NULL,
272 (char *)NULL, 0, 0},
273 {TK_CONFIG_FONT, "-font", "font", "Font",
274 DEF_MARKER_FONT, Tk_Offset(TextMarker, style.font), 0},
275 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
276 DEF_MARKER_FOREGROUND, Tk_Offset(TextMarker, style.color),
277 TK_CONFIG_COLOR_ONLY},
278 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
279 DEF_MARKER_FG_MONO, Tk_Offset(TextMarker, style.color),
280 TK_CONFIG_MONO_ONLY},
281 {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
282 DEF_MARKER_JUSTIFY, Tk_Offset(TextMarker, style.justify),
283 TK_CONFIG_DONT_SET_DEFAULT},
284 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
285 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
286 TK_CONFIG_DONT_SET_DEFAULT},
287 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
288 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
289 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
290 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
291 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
292 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
293 {TK_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL,
294 (char *)NULL, 0, 0},
295 {TK_CONFIG_CUSTOM, "-padx", "padX", "PadX",
296 DEF_MARKER_PAD, Tk_Offset(TextMarker, style.padX),
297 TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption},
298 {TK_CONFIG_CUSTOM, "-pady", "padY", "PadY",
299 DEF_MARKER_PAD, Tk_Offset(TextMarker, style.padY),
300 TK_CONFIG_DONT_SET_DEFAULT, &bltPadOption},
301 {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate",
302 DEF_MARKER_ROTATE, Tk_Offset(TextMarker, style.theta),
303 TK_CONFIG_DONT_SET_DEFAULT},
304 {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow",
305 DEF_MARKER_SHADOW_COLOR, Tk_Offset(TextMarker, style.shadow),
306 TK_CONFIG_COLOR_ONLY, &bltShadowOption},
307 {TK_CONFIG_CUSTOM, "-shadow", "shadow", "Shadow",
308 DEF_MARKER_SHADOW_MONO, Tk_Offset(TextMarker, style.shadow),
309 TK_CONFIG_MONO_ONLY, &bltShadowOption},
310 {TK_CONFIG_CUSTOM, "-state", "state", "State",
311 DEF_MARKER_STATE, Tk_Offset(Marker, state),
312 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
313 {TK_CONFIG_STRING, "-text", "text", "Text",
314 DEF_MARKER_TEXT, Tk_Offset(TextMarker, string), TK_CONFIG_NULL_OK},
315 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
316 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
317 TK_CONFIG_DONT_SET_DEFAULT},
318 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
319 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
320 TK_CONFIG_DONT_SET_DEFAULT},
321 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
322 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
323 TK_CONFIG_DONT_SET_DEFAULT},
324 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
325};
326
327
328/*
329 * -------------------------------------------------------------------
330 *
331 * WindowMarker --
332 *
333 * -------------------------------------------------------------------
334 */
335typedef struct {
336 char *name; /* Identifier for marker */
337 Blt_Uid classUid; /* Type of marker */
338 Graph *graphPtr; /* Graph marker belongs to */
339 unsigned int flags;
340 char **tags;
341 int hidden; /* Indicates if the marker is
342 * currently hidden or not. */
343
344 Blt_HashEntry *hashPtr;
345 Blt_ChainLink *linkPtr;
346
347 Point2D *worldPts; /* Position of marker (1 X-Y coordinate) in
348 * world (graph) coordinates. */
349 int nWorldPts; /* Number of points */
350
351 char *elemName; /* Element associated with marker */
352 Axis2D axes;
353 int drawUnder; /* If non-zero, draw the marker
354 * underneath any elements. There can
355 * be a performance because the graph
356 * must be redraw entirely each time
357 * this marker is redrawn. */
358 int clipped; /* Indicates if the marker is totally
359 * clipped by the plotting area. */
360 int xOffset, yOffset; /* Pixel offset from anchor. */
361
362 MarkerClass *classPtr;
363
364 int state;
365
366 /*
367 * Window specific attributes
368 */
369 char *pathName; /* Name of child widget to be displayed. */
370 Tk_Window tkwin; /* Window to display. */
371 int reqWidth, reqHeight; /* If non-zero, this overrides the size
372 * requested by the child widget. */
373
374 Tk_Anchor anchor; /* Indicates how to translate the given
375 * marker position. */
376
377 Point2D anchorPos; /* Translated anchor point. */
378 int width, height; /* Current size of the child window. */
379
380} WindowMarker;
381
382static Tk_ConfigSpec windowConfigSpecs[] =
383{
384 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
385 DEF_MARKER_ANCHOR, Tk_Offset(WindowMarker, anchor), 0},
386 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
387 DEF_MARKER_WINDOW_TAGS, Tk_Offset(Marker, tags),
388 TK_CONFIG_NULL_OK, &bltListOption},
389 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
390 DEF_MARKER_COORDS, Tk_Offset(WindowMarker, worldPts),
391 TK_CONFIG_NULL_OK, &coordsOption},
392 {TK_CONFIG_STRING, "-element", "element", "Element",
393 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
394 {TK_CONFIG_CUSTOM, "-height", "height", "Height",
395 DEF_MARKER_HEIGHT, Tk_Offset(WindowMarker, reqHeight),
396 TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption},
397 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
398 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
399 TK_CONFIG_DONT_SET_DEFAULT},
400 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
401 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
402 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
403 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
404 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
405 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
406 {TK_CONFIG_CUSTOM, "-state", "state", "State",
407 DEF_MARKER_STATE, Tk_Offset(Marker, state),
408 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
409 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
410 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
411 TK_CONFIG_DONT_SET_DEFAULT},
412 {TK_CONFIG_CUSTOM, "-width", "width", "Width",
413 DEF_MARKER_WIDTH, Tk_Offset(WindowMarker, reqWidth),
414 TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption},
415 {TK_CONFIG_STRING, "-window", "window", "Window",
416 DEF_MARKER_WINDOW, Tk_Offset(WindowMarker, pathName),
417 TK_CONFIG_NULL_OK},
418 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
419 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
420 TK_CONFIG_DONT_SET_DEFAULT},
421 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
422 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
423 TK_CONFIG_DONT_SET_DEFAULT},
424 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
425};
426
427/*
428 * -------------------------------------------------------------------
429 *
430 * BitmapMarker --
431 *
432 * -------------------------------------------------------------------
433 */
434typedef struct {
435 char *name; /* Identifier for marker */
436 Blt_Uid classUid; /* Type of marker */
437 Graph *graphPtr; /* Graph marker belongs to */
438 unsigned int flags;
439 char **tags;
440 int hidden; /* Indicates if the marker is currently
441 * hidden or not. */
442
443 Blt_HashEntry *hashPtr;
444 Blt_ChainLink *linkPtr;
445
446 Point2D *worldPts; /* Position of marker in world (graph)
447 * coordinates. If 2 pairs of X-Y
448 * coordinates are specified, then the
449 * bitmap is resized to fit this area.
450 * Otherwise if 1 pair, then the bitmap
451 * is positioned at the coordinate at its
452 * normal size. */
453 int nWorldPts; /* Number of points */
454
455 char *elemName; /* Element associated with marker */
456 Axis2D axes;
457 int drawUnder; /* If non-zero, draw the marker
458 * underneath any elements. There can
459 * be a performance because the graph
460 * must be redraw entirely each time
461 * this marker is redrawn. */
462
463 int clipped; /* Indicates if the marker is totally
464 * clipped by the plotting area. */
465
466 int xOffset, yOffset; /* Pixel offset from origin of bitmap */
467
468 MarkerClass *classPtr;
469
470 int state;
471
472 /* Bitmap specific attributes */
473 Pixmap srcBitmap; /* Original bitmap. May be further
474 * scaled or rotated. */
475 double rotate; /* Requested rotation of the bitmap */
476 double theta; /* Normalized rotation (0..360
477 * degrees) */
478 Tk_Anchor anchor; /* If only one X-Y coordinate is
479 * given, indicates how to translate
480 * the given marker position. Otherwise,
481 * if there are two X-Y coordinates, then
482 * this value is ignored. */
483 Point2D anchorPos; /* Translated anchor point. */
484
485 XColor *outlineColor; /* Foreground color */
486 XColor *fillColor; /* Background color */
487
488 GC gc; /* Private graphic context */
489 GC fillGC; /* Shared graphic context */
490 Pixmap destBitmap; /* Bitmap to be drawn. */
491 int destWidth, destHeight; /* Dimensions of the final bitmap */
492
493 Point2D outline[MAX_OUTLINE_POINTS];
494 /* Polygon representing the background
495 * of the bitmap. */
496 int nOutlinePts;
497} BitmapMarker;
498
499static Tk_ConfigSpec bitmapConfigSpecs[] =
500{
501 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
502 DEF_MARKER_ANCHOR, Tk_Offset(BitmapMarker, anchor), 0},
503 {TK_CONFIG_COLOR, "-background", "background", "Background",
504 DEF_MARKER_BACKGROUND, Tk_Offset(BitmapMarker, fillColor),
505 TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK},
506 {TK_CONFIG_COLOR, "-background", "background", "Background",
507 DEF_MARKER_BG_MONO, Tk_Offset(BitmapMarker, fillColor),
508 TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK},
509 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL,
510 (char *)NULL, 0, 0},
511 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
512 DEF_MARKER_BITMAP_TAGS, Tk_Offset(Marker, tags),
513 TK_CONFIG_NULL_OK, &bltListOption},
514 {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap",
515 DEF_MARKER_BITMAP, Tk_Offset(BitmapMarker, srcBitmap),
516 TK_CONFIG_NULL_OK},
517 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
518 DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts),
519 TK_CONFIG_NULL_OK, &coordsOption},
520 {TK_CONFIG_STRING, "-element", "element", "Element",
521 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
522 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL,
523 (char *)NULL, 0, 0},
524 {TK_CONFIG_SYNONYM, "-fill", "background", (char *)NULL,
525 (char *)NULL, 0, 0},
526 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
527 DEF_MARKER_FOREGROUND, Tk_Offset(BitmapMarker, outlineColor),
528 TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK},
529 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
530 DEF_MARKER_FG_MONO, Tk_Offset(BitmapMarker, outlineColor),
531 TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK},
532 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
533 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
534 TK_CONFIG_DONT_SET_DEFAULT},
535 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
536 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
537 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
538 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
539 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
540 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
541 {TK_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL,
542 (char *)NULL, 0, 0},
543 {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate",
544 DEF_MARKER_ROTATE, Tk_Offset(BitmapMarker, rotate),
545 TK_CONFIG_DONT_SET_DEFAULT},
546 {TK_CONFIG_CUSTOM, "-state", "state", "State",
547 DEF_MARKER_STATE, Tk_Offset(Marker, state),
548 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
549 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
550 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
551 TK_CONFIG_DONT_SET_DEFAULT},
552 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
553 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
554 TK_CONFIG_DONT_SET_DEFAULT},
555 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
556 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
557 TK_CONFIG_DONT_SET_DEFAULT},
558 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
559};
560
561
562/*
563 * -------------------------------------------------------------------
564 *
565 * ImageMarker --
566 *
567 * -------------------------------------------------------------------
568 */
569typedef struct {
570 char *name; /* Identifier for marker */
571 Blt_Uid classUid; /* Type of marker */
572 Graph *graphPtr; /* Graph marker belongs to */
573 unsigned int flags;
574 char **tags;
575 int hidden; /* Indicates if the marker is
576 * currently hidden or not. */
577
578 Blt_HashEntry *hashPtr;
579 Blt_ChainLink *linkPtr;
580 Point2D *worldPts; /* Position of marker in world (graph)
581 * coordinates. If 2 pairs of X-Y
582 * coordinates are specified, then the
583 * image is resized to fit this area.
584 * Otherwise if 1 pair, then the image
585 * is positioned at the coordinate at
586 * its normal size. */
587 int nWorldPts; /* Number of points */
588
589 char *elemName; /* Element associated with marker */
590 Axis2D axes;
591 int drawUnder; /* If non-zero, draw the marker
592 * underneath any elements. There can
593 * be a performance because the graph
594 * must be redraw entirely each time
595 * this marker is redrawn. */
596 int clipped; /* Indicates if the marker is totally
597 * clipped by the plotting area. */
598 int xOffset, yOffset; /* Pixel offset from anchor */
599
600 MarkerClass *classPtr;
601
602 int state;
603
604 /* Image specific attributes */
605 char *imageName; /* Name of image to be displayed. */
606 Tk_Image tkImage; /* Tk image to be displayed. */
607 Tk_Anchor anchor; /* Indicates how to translate the given
608 * marker position. */
609 Point2D anchorPos; /* Translated anchor point. */
610 int width, height; /* Dimensions of the image */
611 Tk_Image tmpImage;
612 Pixmap pixmap; /* Pixmap containing the scaled image */
613 ColorTable colorTable; /* Pointer to color table */
614 Blt_ColorImage srcImage;
615 GC gc;
616
617} ImageMarker;
618
619static Tk_ConfigSpec imageConfigSpecs[] =
620{
621 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
622 DEF_MARKER_ANCHOR, Tk_Offset(ImageMarker, anchor), 0},
623 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
624 DEF_MARKER_IMAGE_TAGS, Tk_Offset(Marker, tags),
625 TK_CONFIG_NULL_OK, &bltListOption},
626 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
627 DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts),
628 TK_CONFIG_NULL_OK, &coordsOption},
629 {TK_CONFIG_STRING, "-element", "element", "Element",
630 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
631 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
632 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
633 TK_CONFIG_DONT_SET_DEFAULT},
634 {TK_CONFIG_STRING, "-image", "image", "Image",
635 (char *)NULL, Tk_Offset(ImageMarker, imageName), TK_CONFIG_NULL_OK},
636 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
637 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
638 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
639 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
640 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
641 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
642 {TK_CONFIG_CUSTOM, "-state", "state", "State",
643 DEF_MARKER_STATE, Tk_Offset(Marker, state),
644 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
645 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
646 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
647 TK_CONFIG_DONT_SET_DEFAULT},
648 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
649 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
650 TK_CONFIG_DONT_SET_DEFAULT},
651 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
652 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
653 TK_CONFIG_DONT_SET_DEFAULT},
654 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
655};
656
657/*
658 * -------------------------------------------------------------------
659 *
660 * LineMarker --
661 *
662 * -------------------------------------------------------------------
663 */
664typedef struct {
665 char *name; /* Identifier for marker */
666 Blt_Uid classUid; /* Type is "linemarker" */
667 Graph *graphPtr; /* Graph marker belongs to */
668 unsigned int flags;
669 char **tags;
670 int hidden; /* Indicates if the marker is currently
671 * hidden or not. */
672
673 Blt_HashEntry *hashPtr;
674 Blt_ChainLink *linkPtr;
675
676 Point2D *worldPts; /* Position of marker (X-Y coordinates) in
677 * world (graph) coordinates. */
678 int nWorldPts; /* Number of points */
679
680 char *elemName; /* Element associated with marker */
681 Axis2D axes;
682 int drawUnder; /* If non-zero, draw the marker
683 * underneath any elements. There can
684 * be a performance because the graph
685 * must be redraw entirely each time
686 * this marker is redrawn. */
687 int clipped; /* Indicates if the marker is totally
688 * clipped by the plotting area. */
689 int xOffset, yOffset; /* Pixel offset */
690
691 MarkerClass *classPtr;
692
693 int state;
694
695 /* Line specific attributes */
696 XColor *fillColor;
697 XColor *outlineColor; /* Foreground and background colors */
698
699 int lineWidth; /* Line width. */
700 int capStyle; /* Cap style. */
701 int joinStyle; /* Join style.*/
702 Blt_Dashes dashes; /* Dash list values (max 11) */
703
704 GC gc; /* Private graphic context */
705
706 Segment2D *segments; /* Malloc'ed array of points.
707 * Represents individual line segments
708 * (2 points per segment) comprising
709 * the mapped line. The segments may
710 * not necessarily be connected after
711 * clipping. */
712 int nSegments; /* # segments in the above array. */
713
714 int xor;
715 int xorState; /* State of the XOR drawing. Indicates
716 * if the marker is currently drawn. */
717} LineMarker;
718
719static Tk_ConfigSpec lineConfigSpecs[] =
720{
721 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
722 DEF_MARKER_LINE_TAGS, Tk_Offset(Marker, tags),
723 TK_CONFIG_NULL_OK, &bltListOption},
724 {TK_CONFIG_CAP_STYLE, "-cap", "cap", "Cap",
725 DEF_MARKER_CAP_STYLE, Tk_Offset(LineMarker, capStyle),
726 TK_CONFIG_DONT_SET_DEFAULT},
727 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
728 DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts),
729 TK_CONFIG_NULL_OK, &coordsOption},
730 {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
731 DEF_MARKER_DASHES, Tk_Offset(LineMarker, dashes),
732 TK_CONFIG_NULL_OK, &bltDashesOption},
733 {TK_CONFIG_CUSTOM, "-dashoffset", "dashOffset", "DashOffset",
734 DEF_MARKER_DASH_OFFSET, Tk_Offset(LineMarker, dashes.offset),
735 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
736 {TK_CONFIG_STRING, "-element", "element", "Element",
737 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
738 {TK_CONFIG_COLOR, "-fill", "fill", "Fill",
739 (char *)NULL, Tk_Offset(LineMarker, fillColor), TK_CONFIG_NULL_OK},
740 {TK_CONFIG_JOIN_STYLE, "-join", "join", "Join",
741 DEF_MARKER_JOIN_STYLE, Tk_Offset(LineMarker, joinStyle),
742 TK_CONFIG_DONT_SET_DEFAULT},
743 {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
744 DEF_MARKER_LINE_WIDTH, Tk_Offset(LineMarker, lineWidth),
745 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
746 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
747 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
748 TK_CONFIG_DONT_SET_DEFAULT},
749 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
750 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
751 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
752 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
753 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
754 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
755 {TK_CONFIG_COLOR, "-outline", "outline", "Outline",
756 DEF_MARKER_OUTLINE_COLOR, Tk_Offset(LineMarker, outlineColor),
757 TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK},
758 {TK_CONFIG_COLOR, "-outline", "outline", "Outline",
759 DEF_MARKER_OUTLINE_MONO, Tk_Offset(LineMarker, outlineColor),
760 TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK},
761 {TK_CONFIG_CUSTOM, "-state", "state", "State",
762 DEF_MARKER_STATE, Tk_Offset(Marker, state),
763 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
764 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
765 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
766 TK_CONFIG_DONT_SET_DEFAULT},
767 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
768 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
769 TK_CONFIG_DONT_SET_DEFAULT},
770 {TK_CONFIG_BOOLEAN, "-xor", "xor", "Xor",
771 DEF_MARKER_XOR, Tk_Offset(LineMarker, xor), TK_CONFIG_DONT_SET_DEFAULT},
772 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
773 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
774 TK_CONFIG_DONT_SET_DEFAULT},
775 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
776};
777
778/*
779 * -------------------------------------------------------------------
780 *
781 * PolygonMarker --
782 *
783 * -------------------------------------------------------------------
784 */
785typedef struct {
786 char *name; /* Identifier for marker */
787 Blt_Uid classUid; /* Type of marker */
788 Graph *graphPtr; /* Graph marker belongs to */
789 unsigned int flags;
790 char **tags;
791 int hidden; /* Indicates if the marker is currently
792 * hidden or not. */
793
794 Blt_HashEntry *hashPtr;
795 Blt_ChainLink *linkPtr;
796
797 Point2D *worldPts; /* Position of marker (X-Y coordinates) in
798 * world (graph) coordinates. */
799 int nWorldPts; /* Number of points */
800
801 char *elemName; /* Element associated with marker */
802 Axis2D axes;
803 int drawUnder; /* If non-zero, draw the marker
804 * underneath any elements. There can
805 * be a performance because the graph
806 * must be redraw entirely each time
807 * this marker is redrawn. */
808 int clipped; /* Indicates if the marker is totally
809 * clipped by the plotting area. */
810 int xOffset, yOffset; /* Pixel offset */
811
812 MarkerClass *classPtr;
813
814 int state;
815
816 /* Polygon specific attributes and fields */
817
818 Point2D *screenPts; /* Array of points representing the
819 * polygon in screen coordinates. It's
820 * not used for drawing, but to
821 * generate the outlinePts and fillPts
822 * arrays that are the coordinates of
823 * the possibly clipped outline and
824 * filled polygon. */
825
826 ColorPair outline;
827 ColorPair fill;
828
829 Pixmap stipple; /* Stipple pattern to fill the polygon. */
830 int lineWidth; /* Width of polygon outline. */
831 int capStyle;
832 int joinStyle;
833 Blt_Dashes dashes; /* List of dash values. Indicates how
834 * draw the dashed line. If no dash
835 * values are provided, or the first value
836 * is zero, then the line is drawn solid. */
837
838 GC outlineGC; /* Graphics context to draw the outline of
839 * the polygon. */
840 GC fillGC; /* Graphics context to draw the filled
841 * polygon. */
842
843 Point2D *fillPts; /* Malloc'ed array of points used to draw
844 * the filled polygon. These points may
845 * form a degenerate polygon after clipping.
846 */
847
848 int nFillPts; /* # points in the above array. */
849
850 Segment2D *outlinePts; /* Malloc'ed array of points.
851 * Represents individual line segments
852 * (2 points per segment) comprising
853 * the outline of the polygon. The
854 * segments may not necessarily be
855 * closed or connected after clipping. */
856
857 int nOutlinePts; /* # points in the above array. */
858
859 int xor;
860 int xorState; /* State of the XOR drawing. Indicates
861 * if the marker is visible. We have
862 * to drawn it again to erase it. */
863} PolygonMarker;
864
865static Tk_ConfigSpec polygonConfigSpecs[] =
866{
867 {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
868 DEF_MARKER_POLYGON_TAGS, Tk_Offset(Marker, tags),
869 TK_CONFIG_NULL_OK, &bltListOption},
870 {TK_CONFIG_CAP_STYLE, "-cap", "cap", "Cap",
871 DEF_MARKER_CAP_STYLE, Tk_Offset(PolygonMarker, capStyle),
872 TK_CONFIG_DONT_SET_DEFAULT},
873 {TK_CONFIG_CUSTOM, "-coords", "coords", "Coords",
874 DEF_MARKER_COORDS, Tk_Offset(Marker, worldPts),
875 TK_CONFIG_NULL_OK, &coordsOption},
876 {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
877 DEF_MARKER_DASHES, Tk_Offset(PolygonMarker, dashes),
878 TK_CONFIG_NULL_OK, &bltDashesOption},
879 {TK_CONFIG_STRING, "-element", "element", "Element",
880 DEF_MARKER_ELEMENT, Tk_Offset(Marker, elemName), TK_CONFIG_NULL_OK},
881 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
882 DEF_MARKER_FILL_COLOR, Tk_Offset(PolygonMarker, fill),
883 TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption},
884 {TK_CONFIG_CUSTOM, "-fill", "fill", "Fill",
885 DEF_MARKER_FILL_MONO, Tk_Offset(PolygonMarker, fill),
886 TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption},
887 {TK_CONFIG_JOIN_STYLE, "-join", "join", "Join",
888 DEF_MARKER_JOIN_STYLE, Tk_Offset(PolygonMarker, joinStyle),
889 TK_CONFIG_DONT_SET_DEFAULT},
890 {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
891 DEF_MARKER_LINE_WIDTH, Tk_Offset(PolygonMarker, lineWidth),
892 TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
893 {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
894 DEF_MARKER_HIDE, Tk_Offset(Marker, hidden),
895 TK_CONFIG_DONT_SET_DEFAULT},
896 {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
897 DEF_MARKER_MAP_X, Tk_Offset(Marker, axes.x), 0, &bltXAxisOption},
898 {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
899 DEF_MARKER_MAP_Y, Tk_Offset(Marker, axes.y), 0, &bltYAxisOption},
900 {TK_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL,
901 DEF_MARKER_NAME, Tk_Offset(Marker, name), TK_CONFIG_NULL_OK},
902 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
903 DEF_MARKER_OUTLINE_COLOR, Tk_Offset(PolygonMarker, outline),
904 TK_CONFIG_COLOR_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption},
905 {TK_CONFIG_CUSTOM, "-outline", "outline", "Outline",
906 DEF_MARKER_OUTLINE_MONO, Tk_Offset(PolygonMarker, outline),
907 TK_CONFIG_MONO_ONLY | TK_CONFIG_NULL_OK, &bltColorPairOption},
908 {TK_CONFIG_CUSTOM, "-state", "state", "State",
909 DEF_MARKER_STATE, Tk_Offset(Marker, state),
910 TK_CONFIG_DONT_SET_DEFAULT, &bltStateOption},
911 {TK_CONFIG_BITMAP, "-stipple", "stipple", "Stipple",
912 DEF_MARKER_STIPPLE, Tk_Offset(PolygonMarker, stipple),
913 TK_CONFIG_NULL_OK},
914 {TK_CONFIG_BOOLEAN, "-under", "under", "Under",
915 DEF_MARKER_UNDER, Tk_Offset(Marker, drawUnder),
916 TK_CONFIG_DONT_SET_DEFAULT},
917 {TK_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset",
918 DEF_MARKER_X_OFFSET, Tk_Offset(Marker, xOffset),
919 TK_CONFIG_DONT_SET_DEFAULT},
920 {TK_CONFIG_BOOLEAN, "-xor", "xor", "Xor",
921 DEF_MARKER_XOR, Tk_Offset(PolygonMarker, xor),
922 TK_CONFIG_DONT_SET_DEFAULT},
923 {TK_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset",
924 DEF_MARKER_Y_OFFSET, Tk_Offset(Marker, yOffset),
925 TK_CONFIG_DONT_SET_DEFAULT},
926 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
927};
928
929static MarkerCreateProc CreateBitmapMarker, CreateLineMarker, CreateImageMarker,
930 CreatePolygonMarker, CreateTextMarker, CreateWindowMarker;
931
932static MarkerDrawProc DrawBitmapMarker, DrawLineMarker, DrawImageMarker,
933 DrawPolygonMarker, DrawTextMarker, DrawWindowMarker;
934
935static MarkerFreeProc FreeBitmapMarker, FreeLineMarker, FreeImageMarker,
936 FreePolygonMarker, FreeTextMarker, FreeWindowMarker;
937
938static MarkerConfigProc ConfigureBitmapMarker, ConfigureLineMarker,
939 ConfigureImageMarker, ConfigurePolygonMarker, ConfigureTextMarker,
940 ConfigureWindowMarker;
941
942static MarkerMapProc MapBitmapMarker, MapLineMarker, MapImageMarker,
943 MapPolygonMarker, MapTextMarker, MapWindowMarker;
944
945static MarkerPostScriptProc BitmapMarkerToPostScript, LineMarkerToPostScript,
946 ImageMarkerToPostScript, PolygonMarkerToPostScript,
947 TextMarkerToPostScript, WindowMarkerToPostScript;
948
949static MarkerPointProc PointInBitmapMarker, PointInLineMarker,
950 PointInImageMarker, PointInPolygonMarker, PointInTextMarker,
951 PointInWindowMarker;
952
953static MarkerRegionProc RegionInBitmapMarker, RegionInLineMarker,
954 RegionInImageMarker, RegionInPolygonMarker, RegionInTextMarker,
955 RegionInWindowMarker;
956
957static Tk_ImageChangedProc ImageChangedProc;
958
959static MarkerClass bitmapMarkerClass = {
960 bitmapConfigSpecs,
961 ConfigureBitmapMarker,
962 DrawBitmapMarker,
963 FreeBitmapMarker,
964 MapBitmapMarker,
965 PointInBitmapMarker,
966 RegionInBitmapMarker,
967 BitmapMarkerToPostScript,
968};
969
970static MarkerClass imageMarkerClass = {
971 imageConfigSpecs,
972 ConfigureImageMarker,
973 DrawImageMarker,
974 FreeImageMarker,
975 MapImageMarker,
976 PointInImageMarker,
977 RegionInImageMarker,
978 ImageMarkerToPostScript,
979};
980
981static MarkerClass lineMarkerClass = {
982 lineConfigSpecs,
983 ConfigureLineMarker,
984 DrawLineMarker,
985 FreeLineMarker,
986 MapLineMarker,
987 PointInLineMarker,
988 RegionInLineMarker,
989 LineMarkerToPostScript,
990};
991
992static MarkerClass polygonMarkerClass = {
993 polygonConfigSpecs,
994 ConfigurePolygonMarker,
995 DrawPolygonMarker,
996 FreePolygonMarker,
997 MapPolygonMarker,
998 PointInPolygonMarker,
999 RegionInPolygonMarker,
1000 PolygonMarkerToPostScript,
1001};
1002
1003static MarkerClass textMarkerClass = {
1004 textConfigSpecs,
1005 ConfigureTextMarker,
1006 DrawTextMarker,
1007 FreeTextMarker,
1008 MapTextMarker,
1009 PointInTextMarker,
1010 RegionInTextMarker,
1011 TextMarkerToPostScript,
1012};
1013
1014static MarkerClass windowMarkerClass = {
1015 windowConfigSpecs,
1016 ConfigureWindowMarker,
1017 DrawWindowMarker,
1018 FreeWindowMarker,
1019 MapWindowMarker,
1020 PointInWindowMarker,
1021 RegionInWindowMarker,
1022 WindowMarkerToPostScript,
1023};
1024
1025#ifdef notdef
1026static MarkerClass rectangleMarkerClass = {
1027 rectangleConfigSpecs,
1028 ConfigureRectangleMarker,
1029 DrawRectangleMarker,
1030 FreeRectangleMarker,
1031 MapRectangleMarker,
1032 PointInRectangleMarker,
1033 RegionInRectangleMarker,
1034 RectangleMarkerToPostScript,
1035};
1036
1037static MarkerClass ovalMarkerClass = {
1038 ovalConfigSpecs,
1039 ConfigureOvalMarker,
1040 DrawOvalMarker,
1041 FreeOvalMarker,
1042 MapOvalMarker,
1043 PointInOvalMarker,
1044 RegionInOvalMarker,
1045 OvalMarkerToPostScript,
1046};
1047#endif
1048
1049/*
1050 * ----------------------------------------------------------------------
1051 *
1052 * BoxesDontOverlap --
1053 *
1054 * Tests if the bounding box of a marker overlaps the plotting
1055 * area in any way. If so, the marker will be drawn. Just do a
1056 * min/max test on the extents of both boxes.
1057 *
1058 * Note: It's assumed that the extents of the bounding box lie
1059 * within the area. So for a 10x10 rectangle, bottom and
1060 * left would be 9.
1061 *
1062 * Results:
1063 * Returns 0 is the marker is visible in the plotting area, and
1064 * 1 otherwise (marker is clipped).
1065 *
1066 * ----------------------------------------------------------------------
1067 */
1068static int
1069BoxesDontOverlap(graphPtr, extsPtr)
1070 Graph *graphPtr;
1071 Extents2D *extsPtr;
1072{
1073/*
1074 assert(extsPtr->right >= extsPtr->left);
1075 assert(extsPtr->bottom >= extsPtr->top);
1076 assert(graphPtr->right >= graphPtr->left);
1077 assert(graphPtr->bottom >= graphPtr->top);
1078*/
1079
1080 return (((double)graphPtr->right < extsPtr->left) ||
1081 ((double)graphPtr->bottom < extsPtr->top) ||
1082 (extsPtr->right < (double)graphPtr->left) ||
1083 (extsPtr->bottom < (double)graphPtr->top));
1084}
1085
1086
1087/*
1088 * ----------------------------------------------------------------------
1089 *
1090 * GetCoordinate --
1091 *
1092 * Convert the expression string into a floating point value. The
1093 * only reason we use this routine instead of Blt_ExprDouble is to
1094 * handle "elastic" bounds. That is, convert the strings "-Inf",
1095 * "Inf" into -(DBL_MAX) and DBL_MAX respectively.
1096 *
1097 * Results:
1098 * The return value is a standard Tcl result. The value of the
1099 * expression is passed back via valuePtr.
1100 *
1101 * ----------------------------------------------------------------------
1102 */
1103static int
1104GetCoordinate(interp, expr, valuePtr)
1105 Tcl_Interp *interp; /* Interpreter to send results back to */
1106 char *expr; /* Numeric expression string to parse */
1107 double *valuePtr; /* Real-valued result of expression */
1108{
1109 char c;
1110
1111 c = expr[0];
1112 if ((c == 'I') && (strcmp(expr, "Inf") == 0)) {
1113 *valuePtr = DBL_MAX; /* Elastic upper bound */
1114 } else if ((c == '-') && (expr[1] == 'I') && (strcmp(expr, "-Inf") == 0)) {
1115 *valuePtr = -DBL_MAX; /* Elastic lower bound */
1116 } else if ((c == '+') && (expr[1] == 'I') && (strcmp(expr, "+Inf") == 0)) {
1117 *valuePtr = DBL_MAX; /* Elastic upper bound */
1118 } else if (Tcl_ExprDouble(interp, expr, valuePtr) != TCL_OK) {
1119 return TCL_ERROR;
1120 }
1121 return TCL_OK;
1122}
1123
1124
1125/*
1126 * ----------------------------------------------------------------------
1127 *
1128 * PrintCoordinate --
1129 *
1130 * Convert the floating point value into its string
1131 * representation. The only reason this routine is used in
1132 * instead of sprintf, is to handle the "elastic" bounds. That
1133 * is, convert the values DBL_MAX and -(DBL_MAX) into "+Inf" and
1134 * "-Inf" respectively.
1135 *
1136 * Results:
1137 * The return value is a standard Tcl result. The string of the
1138 * expression is passed back via string.
1139 *
1140 * ---------------------------------------------------------------------- */
1141static char *
1142PrintCoordinate(interp, x)
1143 Tcl_Interp *interp;
1144 double x; /* Numeric value */
1145{
1146 if (x == DBL_MAX) {
1147 return "+Inf";
1148 } else if (x == -DBL_MAX) {
1149 return "-Inf";
1150 } else {
1151 static char string[TCL_DOUBLE_SPACE + 1];
1152
1153 Tcl_PrintDouble(interp, (double)x, string);
1154 return string;
1155 }
1156}
1157
1158/*
1159 * ----------------------------------------------------------------------
1160 *
1161 * ParseCoordinates --
1162 *
1163 * The Tcl coordinate list is converted to their floating point
1164 * values. It will then replace the current marker coordinates.
1165 *
1166 * Since different marker types require different number of
1167 * coordinates this must be checked here.
1168 *
1169 * Results:
1170 * The return value is a standard Tcl result.
1171 *
1172 * Side effects:
1173 * If the marker coordinates are reset, the graph is eventually
1174 * redrawn with at the new marker coordinates.
1175 *
1176 * ----------------------------------------------------------------------
1177 */
1178static int
1179ParseCoordinates(interp, markerPtr, nExprs, exprArr)
1180 Tcl_Interp *interp;
1181 Marker *markerPtr;
1182 int nExprs;
1183 char **exprArr;
1184{
1185 int nWorldPts;
1186 int minArgs, maxArgs;
1187 Point2D *worldPts;
1188 register int i;
1189 register Point2D *pointPtr;
1190 double x, y;
1191
1192 if (nExprs == 0) {
1193 return TCL_OK;
1194 }
1195 if (nExprs & 1) {
1196 Tcl_AppendResult(interp, "odd number of marker coordinates specified",
1197 (char *)NULL);
1198 return TCL_ERROR;
1199 }
1200 if (markerPtr->classUid == bltLineMarkerUid) {
1201 minArgs = 4, maxArgs = 0;
1202 } else if (markerPtr->classUid == bltPolygonMarkerUid) {
1203 minArgs = 6, maxArgs = 0;
1204 } else if ((markerPtr->classUid == bltWindowMarkerUid) ||
1205 (markerPtr->classUid == bltTextMarkerUid)) {
1206 minArgs = 2, maxArgs = 2;
1207 } else if ((markerPtr->classUid == bltImageMarkerUid) ||
1208 (markerPtr->classUid == bltBitmapMarkerUid)) {
1209 minArgs = 2, maxArgs = 4;
1210 } else {
1211 Tcl_AppendResult(interp, "unknown marker type", (char *)NULL);
1212 return TCL_ERROR;
1213 }
1214
1215 if (nExprs < minArgs) {
1216 Tcl_AppendResult(interp, "too few marker coordinates specified",
1217 (char *)NULL);
1218 return TCL_ERROR;
1219 }
1220 if ((maxArgs > 0) && (nExprs > maxArgs)) {
1221 Tcl_AppendResult(interp, "too many marker coordinates specified",
1222 (char *)NULL);
1223 return TCL_ERROR;
1224 }
1225 nWorldPts = nExprs / 2;
1226 worldPts = Blt_Malloc(nWorldPts * sizeof(Point2D));
1227 if (worldPts == NULL) {
1228 Tcl_AppendResult(interp, "can't allocate new coordinate array",
1229 (char *)NULL);
1230 return TCL_ERROR;
1231 }
1232
1233 /* Don't free the old coordinate array until we've parsed the new
1234 * coordinates without errors. */
1235 pointPtr = worldPts;
1236 for (i = 0; i < nExprs; i += 2) {
1237 if ((GetCoordinate(interp, exprArr[i], &x) != TCL_OK) ||
1238 (GetCoordinate(interp, exprArr[i + 1], &y) != TCL_OK)) {
1239 Blt_Free(worldPts);
1240 return TCL_ERROR;
1241 }
1242 pointPtr->x = x, pointPtr->y = y;
1243 pointPtr++;
1244 }
1245 if (markerPtr->worldPts != NULL) {
1246 Blt_Free(markerPtr->worldPts);
1247 }
1248 markerPtr->worldPts = worldPts;
1249 markerPtr->nWorldPts = nWorldPts;
1250 markerPtr->flags |= MAP_ITEM;
1251 return TCL_OK;
1252}
1253
1254/*
1255 * ----------------------------------------------------------------------
1256 *
1257 * StringToCoordinates --
1258 *
1259 * Given a Tcl list of numeric expression representing the
1260 * element values, convert into an array of floating point
1261 * values. In addition, the minimum and maximum values are saved.
1262 * Since elastic values are allow (values which translate to the
1263 * min/max of the graph), we must try to get the non-elastic
1264 * minimum and maximum.
1265 *
1266 * Results:
1267 * The return value is a standard Tcl result. The vector is
1268 * passed back via the vecPtr.
1269 *
1270 * ----------------------------------------------------------------------
1271 */
1272/*ARGSUSED*/
1273static int
1274StringToCoordinates(clientData, interp, tkwin, string, widgRec, offset)
1275 ClientData clientData; /* Not used. */
1276 Tcl_Interp *interp; /* Interpreter to send results back to */
1277 Tk_Window tkwin; /* Not used. */
1278 char *string; /* Tcl list of numeric expressions */
1279 char *widgRec; /* Marker record */
1280 int offset; /* Not used. */
1281{
1282 Marker *markerPtr = (Marker *)widgRec;
1283 int nExprs;
1284 char **exprArr;
1285 int result;
1286
1287 nExprs = 0;
1288 if ((string != NULL) &&
1289 (Tcl_SplitList(interp, string, &nExprs, &exprArr) != TCL_OK)) {
1290 return TCL_ERROR;
1291 }
1292 if (nExprs == 0) {
1293 if (markerPtr->worldPts != NULL) {
1294 Blt_Free(markerPtr->worldPts);
1295 markerPtr->worldPts = NULL;
1296 }
1297 markerPtr->nWorldPts = 0;
1298 return TCL_OK;
1299 }
1300 result = ParseCoordinates(interp, markerPtr, nExprs, exprArr);
1301 Blt_Free(exprArr);
1302 return result;
1303}
1304
1305/*
1306 * ----------------------------------------------------------------------
1307 *
1308 * CoordinatesToString --
1309 *
1310 * Convert the vector of floating point values into a Tcl list.
1311 *
1312 * Results:
1313 * The string representation of the vector is returned.
1314 *
1315 * ----------------------------------------------------------------------
1316 */
1317/*ARGSUSED*/
1318static char *
1319CoordinatesToString(clientData, tkwin, widgRec, offset, freeProcPtr)
1320 ClientData clientData; /* Not used. */
1321 Tk_Window tkwin; /* Not used. */
1322 char *widgRec; /* Marker record */
1323 int offset; /* Not used. */
1324 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
1325{
1326 Marker *markerPtr = (Marker *)widgRec;
1327 Tcl_Interp *interp;
1328 Tcl_DString dString;
1329 char *result;
1330 register int i;
1331 register Point2D *p;
1332
1333 if (markerPtr->nWorldPts < 1) {
1334 return "";
1335 }
1336 interp = markerPtr->graphPtr->interp;
1337
1338 Tcl_DStringInit(&dString);
1339 p = markerPtr->worldPts;
1340 for (i = 0; i < markerPtr->nWorldPts; i++) {
1341 Tcl_DStringAppendElement(&dString, PrintCoordinate(interp, p->x));
1342 Tcl_DStringAppendElement(&dString, PrintCoordinate(interp, p->y));
1343 p++;
1344 }
1345 result = Tcl_DStringValue(&dString);
1346
1347 /*
1348 * If memory wasn't allocated for the dynamic string, do it here (it's
1349 * currently on the stack), so that Tcl can free it normally.
1350 */
1351 if (result == dString.staticSpace) {
1352 result = Blt_Strdup(result);
1353 }
1354 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
1355 return result;
1356}
1357
1358/*
1359 * ----------------------------------------------------------------------
1360 *
1361 * HMap --
1362 *
1363 * Map the given graph coordinate value to its axis, returning a
1364 * window position.
1365 *
1366 * Results:
1367 * Returns a floating point number representing the window
1368 * coordinate position on the given axis.
1369 *
1370 * ----------------------------------------------------------------------
1371 */
1372static double
1373HMap(graphPtr, axisPtr, x)
1374 Graph *graphPtr;
1375 Axis *axisPtr;
1376 double x;
1377{
1378 register double norm;
1379
1380 if (x == DBL_MAX) {
1381 norm = 1.0;
1382 } else if (x == -DBL_MAX) {
1383 norm = 0.0;
1384 } else {
1385 if (axisPtr->logScale) {
1386 if (x > 0.0) {
1387 x = log10(x);
1388 } else if (x < 0.0) {
1389 x = 0.0;
1390 }
1391 }
1392 norm = NORMALIZE(axisPtr, x);
1393 }
1394 if (axisPtr->descending) {
1395 norm = 1.0 - norm;
1396 }
1397 /* Horizontal transformation */
1398 return ((norm * graphPtr->hRange) + graphPtr->hOffset);
1399}
1400
1401/*
1402 * ----------------------------------------------------------------------
1403 *
1404 * VMap --
1405 *
1406 * Map the given graph coordinate value to its axis, returning a
1407 * window position.
1408 *
1409 * Results:
1410 * Returns a double precision number representing the window
1411 * coordinate position on the given axis.
1412 *
1413 * ----------------------------------------------------------------------
1414 */
1415static double
1416VMap(graphPtr, axisPtr, y)
1417 Graph *graphPtr;
1418 Axis *axisPtr;
1419 double y;
1420{
1421 register double norm;
1422
1423 if (y == DBL_MAX) {
1424 norm = 1.0;
1425 } else if (y == -DBL_MAX) {
1426 norm = 0.0;
1427 } else {
1428 if (axisPtr->logScale) {
1429 if (y > 0.0) {
1430 y = log10(y);
1431 } else if (y < 0.0) {
1432 y = 0.0;
1433 }
1434 }
1435 norm = NORMALIZE(axisPtr, y);
1436 }
1437 if (axisPtr->descending) {
1438 norm = 1.0 - norm;
1439 }
1440 /* Vertical transformation */
1441 return (((1.0 - norm) * graphPtr->vRange) + graphPtr->vOffset);
1442}
1443
1444/*
1445 * ----------------------------------------------------------------------
1446 *
1447 * MapPoint --
1448 *
1449 * Maps the given graph x,y coordinate values to a window position.
1450 *
1451 * Results:
1452 * Returns a XPoint structure containing the window coordinates
1453 * of the given graph x,y coordinate.
1454 *
1455 * ----------------------------------------------------------------------
1456 */
1457static Point2D
1458MapPoint(graphPtr, pointPtr, axesPtr)
1459 Graph *graphPtr;
1460 Point2D *pointPtr; /* Graph X-Y coordinate. */
1461 Axis2D *axesPtr; /* Specifies which axes to use */
1462{
1463 Point2D result;
1464
1465 if (graphPtr->inverted) {
1466 result.x = HMap(graphPtr, axesPtr->y, pointPtr->y);
1467 result.y = VMap(graphPtr, axesPtr->x, pointPtr->x);
1468 } else {
1469 result.x = HMap(graphPtr, axesPtr->x, pointPtr->x);
1470 result.y = VMap(graphPtr, axesPtr->y, pointPtr->y);
1471 }
1472 return result; /* Result is screen coordinate. */
1473}
1474
1475static Marker *
1476CreateMarker(graphPtr, name, classUid)
1477 Graph *graphPtr;
1478 char *name;
1479 Blt_Uid classUid;
1480{
1481 Marker *markerPtr;
1482
1483 /* Create the new marker based upon the given type */
1484 if (classUid == bltBitmapMarkerUid) {
1485 markerPtr = CreateBitmapMarker(); /* bitmap */
1486 } else if (classUid == bltLineMarkerUid) {
1487 markerPtr = CreateLineMarker(); /* line */
1488 } else if (classUid == bltImageMarkerUid) {
1489 markerPtr = CreateImageMarker(); /* image */
1490 } else if (classUid == bltTextMarkerUid) {
1491 markerPtr = CreateTextMarker(); /* text */
1492 } else if (classUid == bltPolygonMarkerUid) {
1493 markerPtr = CreatePolygonMarker(); /* polygon */
1494 } else if (classUid == bltWindowMarkerUid) {
1495 markerPtr = CreateWindowMarker(); /* window */
1496 } else {
1497 return NULL;
1498 }
1499 assert(markerPtr);
1500 markerPtr->graphPtr = graphPtr;
1501 markerPtr->hidden = markerPtr->drawUnder = FALSE;
1502 markerPtr->flags |= MAP_ITEM;
1503 markerPtr->name = Blt_Strdup(name);
1504 markerPtr->classUid = classUid;
1505 return markerPtr;
1506}
1507
1508static void
1509DestroyMarker(markerPtr)
1510 Marker *markerPtr;
1511{
1512 Graph *graphPtr = markerPtr->graphPtr;
1513
1514 if (markerPtr->drawUnder) {
1515 graphPtr->flags |= REDRAW_BACKING_STORE;
1516 }
1517 /* Free the resources allocated for the particular type of marker */
1518 (*markerPtr->classPtr->freeProc) (graphPtr, markerPtr);
1519 if (markerPtr->worldPts != NULL) {
1520 Blt_Free(markerPtr->worldPts);
1521 }
1522 Blt_DeleteBindings(graphPtr->bindTable, markerPtr);
1523 Tk_FreeOptions(markerPtr->classPtr->configSpecs, (char *)markerPtr,
1524 graphPtr->display, 0);
1525 if (markerPtr->hashPtr != NULL) {
1526 Blt_DeleteHashEntry(&graphPtr->markers.table, markerPtr->hashPtr);
1527 }
1528 if (markerPtr->linkPtr != NULL) {
1529 Blt_ChainDeleteLink(graphPtr->markers.displayList, markerPtr->linkPtr);
1530 }
1531 if (markerPtr->name != NULL) {
1532 Blt_Free(markerPtr->name);
1533 }
1534 if (markerPtr->elemName != NULL) {
1535 Blt_Free(markerPtr->elemName);
1536 }
1537 if (markerPtr->tags != NULL) {
1538 Blt_Free(markerPtr->tags);
1539 }
1540 Blt_Free(markerPtr);
1541}
1542
1543/*
1544 * ----------------------------------------------------------------------
1545 *
1546 * ConfigureBitmapMarker --
1547 *
1548 * This procedure is called to process an argv/argc list, plus
1549 * the Tk option database, in order to configure (or reconfigure)
1550 * a bitmap marker.
1551 *
1552 * Results:
1553 * A standard Tcl result. If TCL_ERROR is returned, then
1554 * interp->result contains an error message.
1555 *
1556 * Side effects:
1557 * Configuration information, such as bitmap pixmap, colors,
1558 * rotation, etc. get set for markerPtr; old resources get freed,
1559 * if there were any. The marker is eventually redisplayed.
1560 *
1561 * ----------------------------------------------------------------------
1562 */
1563/* ARGSUSED */
1564static int
1565ConfigureBitmapMarker(markerPtr)
1566 Marker *markerPtr;
1567{
1568 Graph *graphPtr = markerPtr->graphPtr;
1569 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1570 GC newGC;
1571 XGCValues gcValues;
1572 unsigned long gcMask;
1573
1574 if (bmPtr->srcBitmap == None) {
1575 return TCL_OK;
1576 }
1577 bmPtr->theta = FMOD(bmPtr->rotate, 360.0);
1578 if (bmPtr->theta < 0.0) {
1579 bmPtr->theta += 360.0;
1580 }
1581 gcMask = 0;
1582 if (bmPtr->outlineColor != NULL) {
1583 gcMask |= GCForeground;
1584 gcValues.foreground = bmPtr->outlineColor->pixel;
1585 }
1586 if (bmPtr->fillColor != NULL) {
1587 gcValues.background = bmPtr->fillColor->pixel;
1588 gcMask |= GCBackground;
1589 } else {
1590 gcValues.clip_mask = bmPtr->srcBitmap;
1591 gcMask |= GCClipMask;
1592 }
1593
1594 /* Note that while this is a "shared" GC, we're going to change
1595 * the clip origin right before the bitmap is drawn anyways. This
1596 * assumes that any drawing code using this GC (with GCClipMask
1597 * set) is going to want to set the clip origin anyways. */
1598 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
1599 if (bmPtr->gc != NULL) {
1600 Tk_FreeGC(graphPtr->display, bmPtr->gc);
1601 }
1602 bmPtr->gc = newGC;
1603
1604 /* Create background GC color */
1605
1606 if (bmPtr->fillColor != NULL) {
1607 gcValues.foreground = bmPtr->fillColor->pixel;
1608 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
1609 if (bmPtr->fillGC != NULL) {
1610 Tk_FreeGC(graphPtr->display, bmPtr->fillGC);
1611 }
1612 bmPtr->fillGC = newGC;
1613 }
1614 bmPtr->flags |= MAP_ITEM;
1615 if (bmPtr->drawUnder) {
1616 graphPtr->flags |= REDRAW_BACKING_STORE;
1617 }
1618 Blt_EventuallyRedrawGraph(graphPtr);
1619 return TCL_OK;
1620}
1621
1622/*
1623 * ----------------------------------------------------------------------
1624 *
1625 * MapBitmapMarker --
1626 *
1627 * This procedure gets called each time the layout of the graph
1628 * changes. The x, y window coordinates of the bitmap marker are
1629 * saved in the marker structure.
1630 *
1631 * Additionly, if no background color was specified, the
1632 * GCTileStipXOrigin and GCTileStipYOrigin attributes are set in
1633 * the private GC.
1634 *
1635 * Results:
1636 * None.
1637 *
1638 * Side effects:
1639 * Window coordinates are saved and if no background color was
1640 * set, the GC stipple origins are changed to calculated window
1641 * coordinates.
1642 *
1643 * ----------------------------------------------------------------------
1644 */
1645static void
1646MapBitmapMarker(markerPtr)
1647 Marker *markerPtr;
1648{
1649 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1650 Extents2D exts;
1651 Graph *graphPtr = markerPtr->graphPtr;
1652 Point2D anchorPos;
1653 Point2D corner1, corner2;
1654 int destWidth, destHeight;
1655 int srcWidth, srcHeight;
1656 register int i;
1657
1658 if (bmPtr->srcBitmap == None) {
1659 return;
1660 }
1661 if (bmPtr->destBitmap != None) {
1662 Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap);
1663 bmPtr->destBitmap = None;
1664 }
1665 /*
1666 * Collect the coordinates. The number of coordinates will determine
1667 * the calculations to be made.
1668 *
1669 * x1 y1 A single pair of X-Y coordinates. They represent
1670 * the anchor position of the bitmap.
1671 *
1672 * x1 y1 x2 y2 Two pairs of X-Y coordinates. They represent
1673 * two opposite corners of a bounding rectangle. The
1674 * bitmap is possibly rotated and scaled to fit into
1675 * this box.
1676 *
1677 */
1678 Tk_SizeOfBitmap(graphPtr->display, bmPtr->srcBitmap, &srcWidth,
1679 &srcHeight);
1680 corner1 = MapPoint(graphPtr, bmPtr->worldPts, &bmPtr->axes);
1681 if (bmPtr->nWorldPts > 1) {
1682 double hold;
1683
1684 corner2 = MapPoint(graphPtr, bmPtr->worldPts + 1, &bmPtr->axes);
1685 /* Flip the corners if necessary */
1686 if (corner1.x > corner2.x) {
1687 hold = corner1.x, corner1.x = corner2.x, corner2.x = hold;
1688 }
1689 if (corner1.y > corner2.y) {
1690 hold = corner1.y, corner1.y = corner2.y, corner2.y = hold;
1691 }
1692 } else {
1693 corner2.x = corner1.x + srcWidth - 1;
1694 corner2.y = corner1.y + srcHeight - 1;
1695 }
1696 destWidth = (int)(corner2.x - corner1.x) + 1;
1697 destHeight = (int)(corner2.y - corner1.y) + 1;
1698
1699 if (bmPtr->nWorldPts == 1) {
1700 anchorPos = Blt_TranslatePoint(&corner1, destWidth, destHeight,
1701 bmPtr->anchor);
1702 } else {
1703 anchorPos = corner1;
1704 }
1705 anchorPos.x += bmPtr->xOffset;
1706 anchorPos.y += bmPtr->yOffset;
1707
1708 /* Check if the bitmap sits at least partially in the plot area. */
1709 exts.left = anchorPos.x;
1710 exts.top = anchorPos.y;
1711 exts.right = anchorPos.x + destWidth - 1;
1712 exts.bottom = anchorPos.y + destHeight - 1;
1713
1714 bmPtr->clipped = BoxesDontOverlap(graphPtr, &exts);
1715 if (bmPtr->clipped) {
1716 return; /* Bitmap is offscreen. Don't generate
1717 * rotated or scaled bitmaps. */
1718 }
1719
1720 /*
1721 * Scale the bitmap if necessary. It's a little tricky because we
1722 * only want to scale what's visible on the screen, not the entire
1723 * bitmap.
1724 */
1725 if ((bmPtr->theta != 0.0) || (destWidth != srcWidth) ||
1726 (destHeight != srcHeight)) {
1727 int regionWidth, regionHeight;
1728 Region2D region; /* Indicates the portion of the scaled
1729 * bitmap that we want to display. */
1730 double left, right, top, bottom;
1731
1732 /*
1733 * Determine the region of the bitmap visible in the plot area.
1734 */
1735 left = MAX(graphPtr->left, exts.left);
1736 right = MIN(graphPtr->right, exts.right);
1737 top = MAX(graphPtr->top, exts.top);
1738 bottom = MIN(graphPtr->bottom, exts.bottom);
1739
1740 region.left = region.top = 0;
1741 if (graphPtr->left > exts.left) {
1742 region.left = (int)(graphPtr->left - exts.left);
1743 }
1744 if (graphPtr->top > exts.top) {
1745 region.top = (int)(graphPtr->top - exts.top);
1746 }
1747 regionWidth = (int)(right - left) + 1;
1748 regionHeight = (int)(bottom - top) + 1;
1749 region.right = region.left + (int)(right - left);
1750 region.bottom = region.top + (int)(bottom - top);
1751
1752 anchorPos.x = left;
1753 anchorPos.y = top;
1754 bmPtr->destBitmap = Blt_ScaleRotateBitmapRegion(graphPtr->tkwin,
1755 bmPtr->srcBitmap, srcWidth, srcHeight,
1756 region.left, region.top, regionWidth, regionHeight,
1757 destWidth, destHeight, bmPtr->theta);
1758 bmPtr->destWidth = regionWidth;
1759 bmPtr->destHeight = regionHeight;
1760 } else {
1761 bmPtr->destWidth = srcWidth;
1762 bmPtr->destHeight = srcHeight;
1763 bmPtr->destBitmap = None;
1764 }
1765 bmPtr->anchorPos = anchorPos;
1766 {
1767 double xScale, yScale;
1768 double tx, ty;
1769 double rotWidth, rotHeight;
1770 Point2D polygon[5];
1771 int n;
1772
1773 /*
1774 * Compute a polygon to represent the background area of the bitmap.
1775 * This is needed for backgrounds of arbitrarily rotated bitmaps.
1776 * We also use it to print a background in PostScript.
1777 */
1778 Blt_GetBoundingBox(srcWidth, srcHeight, bmPtr->theta, &rotWidth,
1779 &rotHeight, polygon);
1780 xScale = (double)destWidth / rotWidth;
1781 yScale = (double)destHeight / rotHeight;
1782
1783 /*
1784 * Adjust each point of the polygon. Both scale it to the new size
1785 * and translate it to the actual screen position of the bitmap.
1786 */
1787 tx = exts.left + destWidth * 0.5;
1788 ty = exts.top + destHeight * 0.5;
1789 for (i = 0; i < 4; i++) {
1790 polygon[i].x = (polygon[i].x * xScale) + tx;
1791 polygon[i].y = (polygon[i].y * yScale) + ty;
1792 }
1793 Blt_GraphExtents(graphPtr, &exts);
1794 n = Blt_PolyRectClip(&exts, polygon, 4, bmPtr->outline);
1795 assert(n <= MAX_OUTLINE_POINTS);
1796 if (n < 3) {
1797 memcpy(&bmPtr->outline, polygon, sizeof(Point2D) * 4);
1798 bmPtr->nOutlinePts = 4;
1799 } else {
1800 bmPtr->nOutlinePts = n;
1801 }
1802 }
1803}
1804
1805/*
1806 * ----------------------------------------------------------------------
1807 *
1808 * PointInBitmapMarker --
1809 *
1810 * Indicates if the given point is over the bitmap marker. The
1811 * area of the bitmap is the rectangle.
1812 *
1813 * Results:
1814 * Returns 1 is the point is over the bitmap marker, 0 otherwise.
1815 *
1816 * ----------------------------------------------------------------------
1817 */
1818static int
1819PointInBitmapMarker(markerPtr, samplePtr)
1820 Marker *markerPtr;
1821 Point2D *samplePtr;
1822{
1823 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1824
1825 if (bmPtr->srcBitmap == None) {
1826 return 0;
1827 }
1828 if (bmPtr->theta != 0.0) {
1829 Point2D points[MAX_OUTLINE_POINTS];
1830 register int i;
1831
1832 /*
1833 * Generate the bounding polygon (isolateral) for the bitmap
1834 * and see if the point is inside of it.
1835 */
1836 for (i = 0; i < bmPtr->nOutlinePts; i++) {
1837 points[i].x = bmPtr->outline[i].x + bmPtr->anchorPos.x;
1838 points[i].y = bmPtr->outline[i].y + bmPtr->anchorPos.y;
1839 }
1840 return Blt_PointInPolygon(samplePtr, points, bmPtr->nOutlinePts);
1841 }
1842 return ((samplePtr->x >= bmPtr->anchorPos.x) &&
1843 (samplePtr->x < (bmPtr->anchorPos.x + bmPtr->destWidth)) &&
1844 (samplePtr->y >= bmPtr->anchorPos.y) &&
1845 (samplePtr->y < (bmPtr->anchorPos.y + bmPtr->destHeight)));
1846}
1847
1848
1849/*
1850 * ----------------------------------------------------------------------
1851 *
1852 * RegionInBitmapMarker --
1853 *
1854 * ----------------------------------------------------------------------
1855 */
1856static int
1857RegionInBitmapMarker(markerPtr, extsPtr, enclosed)
1858 Marker *markerPtr;
1859 Extents2D *extsPtr;
1860 int enclosed;
1861{
1862 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1863
1864 if (bmPtr->nWorldPts < 1) {
1865 return FALSE;
1866 }
1867 if (bmPtr->theta != 0.0) {
1868 Point2D points[MAX_OUTLINE_POINTS];
1869 register int i;
1870
1871 /*
1872 * Generate the bounding polygon (isolateral) for the bitmap
1873 * and see if the point is inside of it.
1874 */
1875 for (i = 0; i < bmPtr->nOutlinePts; i++) {
1876 points[i].x = bmPtr->outline[i].x + bmPtr->anchorPos.x;
1877 points[i].y = bmPtr->outline[i].y + bmPtr->anchorPos.y;
1878 }
1879 return Blt_RegionInPolygon(extsPtr, points, bmPtr->nOutlinePts,
1880 enclosed);
1881 }
1882 if (enclosed) {
1883 return ((bmPtr->anchorPos.x >= extsPtr->left) &&
1884 (bmPtr->anchorPos.y >= extsPtr->top) &&
1885 ((bmPtr->anchorPos.x + bmPtr->destWidth) <= extsPtr->right) &&
1886 ((bmPtr->anchorPos.y + bmPtr->destHeight) <= extsPtr->bottom));
1887 }
1888 return !((bmPtr->anchorPos.x >= extsPtr->right) ||
1889 (bmPtr->anchorPos.y >= extsPtr->bottom) ||
1890 ((bmPtr->anchorPos.x + bmPtr->destWidth) <= extsPtr->left) ||
1891 ((bmPtr->anchorPos.y + bmPtr->destHeight) <= extsPtr->top));
1892}
1893
1894/*
1895 * ----------------------------------------------------------------------
1896 *
1897 * DrawBitmapMarker --
1898 *
1899 * Draws the bitmap marker that have a transparent of filled
1900 * background.
1901 *
1902 * Results:
1903 * None.
1904 *
1905 * Side effects:
1906 * GC stipple origins are changed to current window coordinates.
1907 * Commands are output to X to draw the marker in its current
1908 * mode.
1909 *
1910 * ----------------------------------------------------------------------
1911 */
1912static void
1913DrawBitmapMarker(markerPtr, drawable)
1914 Marker *markerPtr;
1915 Drawable drawable; /* Pixmap or window to draw into */
1916{
1917 Graph *graphPtr = markerPtr->graphPtr;
1918 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1919 double theta;
1920 Pixmap bitmap;
1921
1922 bitmap = GETBITMAP(bmPtr);
1923 if ((bitmap == None) || (bmPtr->destWidth < 1) || (bmPtr->destHeight < 1)) {
1924 return;
1925 }
1926 theta = FMOD(bmPtr->theta, (double)90.0);
1927 if ((bmPtr->fillColor == NULL) || (theta != 0.0)) {
1928
1929 /*
1930 * If the bitmap is rotated and a filled background is
1931 * required, then a filled polygon is drawn before the
1932 * bitmap.
1933 */
1934
1935 if (bmPtr->fillColor != NULL) {
1936 int i;
1937 XPoint polygon[MAX_OUTLINE_POINTS];
1938
1939 for (i = 0; i < bmPtr->nOutlinePts; i++) {
1940 polygon[i].x = (short int)bmPtr->outline[i].x;
1941 polygon[i].y = (short int)bmPtr->outline[i].y;
1942 }
1943 XFillPolygon(graphPtr->display, drawable, bmPtr->fillGC,
1944 polygon, bmPtr->nOutlinePts, Convex, CoordModeOrigin);
1945 }
1946 XSetClipMask(graphPtr->display, bmPtr->gc, bitmap);
1947 XSetClipOrigin(graphPtr->display, bmPtr->gc, (int)bmPtr->anchorPos.x,
1948 (int)bmPtr->anchorPos.y);
1949 } else {
1950 XSetClipMask(graphPtr->display, bmPtr->gc, None);
1951 XSetClipOrigin(graphPtr->display, bmPtr->gc, 0, 0);
1952 }
1953 XCopyPlane(graphPtr->display, bitmap, drawable, bmPtr->gc, 0, 0,
1954 bmPtr->destWidth, bmPtr->destHeight, (int)bmPtr->anchorPos.x,
1955 (int)bmPtr->anchorPos.y, 1);
1956}
1957
1958/*
1959 * ----------------------------------------------------------------------
1960 *
1961 * BitmapMarkerToPostScript --
1962 *
1963 * Generates PostScript to print a bitmap marker.
1964 *
1965 * Results:
1966 * None.
1967 *
1968 * ----------------------------------------------------------------------
1969 */
1970static void
1971BitmapMarkerToPostScript(markerPtr, psToken)
1972 Marker *markerPtr; /* Marker to be printed */
1973 PsToken psToken;
1974{
1975 Graph *graphPtr = markerPtr->graphPtr;
1976 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
1977 Pixmap bitmap;
1978
1979 bitmap = GETBITMAP(bmPtr);
1980 if (bitmap == None) {
1981 return;
1982 }
1983 if (bmPtr->fillColor != NULL) {
1984 Blt_BackgroundToPostScript(psToken, bmPtr->fillColor);
1985 Blt_PolygonToPostScript(psToken, bmPtr->outline, 4);
1986 }
1987 Blt_ForegroundToPostScript(psToken, bmPtr->outlineColor);
1988
1989 Blt_FormatToPostScript(psToken,
1990 " gsave\n %g %g translate\n %d %d scale\n",
1991 bmPtr->anchorPos.x, bmPtr->anchorPos.y + bmPtr->destHeight,
1992 bmPtr->destWidth, -bmPtr->destHeight);
1993 Blt_FormatToPostScript(psToken, " %d %d true [%d 0 0 %d 0 %d] {",
1994 bmPtr->destWidth, bmPtr->destHeight, bmPtr->destWidth,
1995 -bmPtr->destHeight, bmPtr->destHeight);
1996 Blt_BitmapDataToPostScript(psToken, graphPtr->display, bitmap,
1997 bmPtr->destWidth, bmPtr->destHeight);
1998 Blt_AppendToPostScript(psToken, " } imagemask\n",
1999 "grestore\n", (char *)NULL);
2000}
2001
2002/*
2003 * ----------------------------------------------------------------------
2004 *
2005 * FreeBitmapMarker --
2006 *
2007 * Releases the memory and attributes of the bitmap marker.
2008 *
2009 * Results:
2010 * None.
2011 *
2012 * Side effects:
2013 * Bitmap attributes (GCs, colors, bitmap, etc) get destroyed.
2014 * Memory is released, X resources are freed, and the graph is
2015 * redrawn.
2016 *
2017 * ----------------------------------------------------------------------
2018 */
2019static void
2020FreeBitmapMarker(graphPtr, markerPtr)
2021 Graph *graphPtr;
2022 Marker *markerPtr;
2023{
2024 BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
2025
2026 if (bmPtr->gc != NULL) {
2027 Tk_FreeGC(graphPtr->display, bmPtr->gc);
2028 }
2029 if (bmPtr->fillGC != NULL) {
2030 Tk_FreeGC(graphPtr->display, bmPtr->fillGC);
2031 }
2032 if (bmPtr->destBitmap != None) {
2033 Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap);
2034 }
2035}
2036
2037/*
2038 * ----------------------------------------------------------------------
2039 *
2040 * CreateBitmapMarker --
2041 *
2042 * Allocate memory and initialize methods for the new bitmap marker.
2043 *
2044 * Results:
2045 * The pointer to the newly allocated marker structure is returned.
2046 *
2047 * Side effects:
2048 * Memory is allocated for the bitmap marker structure.
2049 *
2050 * ----------------------------------------------------------------------
2051 */
2052static Marker *
2053CreateBitmapMarker()
2054{
2055 BitmapMarker *bmPtr;
2056
2057 bmPtr = Blt_Calloc(1, sizeof(BitmapMarker));
2058 if (bmPtr != NULL) {
2059 bmPtr->classPtr = &bitmapMarkerClass;
2060 }
2061 return (Marker *)bmPtr;
2062}
2063
2064/*
2065 *----------------------------------------------------------------------
2066 *
2067 * ImageChangedProc
2068 *
2069 *
2070 * Results:
2071 * None.
2072 *
2073 *----------------------------------------------------------------------
2074 */
2075/* ARGSUSED */
2076static void
2077ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight)
2078 ClientData clientData;
2079 int x, y, width, height; /* Not used. */
2080 int imageWidth, imageHeight; /* Not used. */
2081{
2082 ImageMarker *imPtr = clientData;
2083 Tk_PhotoHandle photo;
2084
2085 photo = Blt_FindPhoto(imPtr->graphPtr->interp, imPtr->imageName);
2086 if (photo != NULL) {
2087 if (imPtr->srcImage != NULL) {
2088 Blt_FreeColorImage(imPtr->srcImage);
2089 }
2090 /* Convert the latest incarnation of the photo image back to a
2091 * color image that we can scale. */
2092 imPtr->srcImage = Blt_PhotoToColorImage(photo);
2093 }
2094 imPtr->graphPtr->flags |= REDRAW_BACKING_STORE;
2095 imPtr->flags |= MAP_ITEM;
2096 Blt_EventuallyRedrawGraph(imPtr->graphPtr);
2097}
2098
2099/*
2100 * ----------------------------------------------------------------------
2101 *
2102 * ConfigureImageMarker --
2103 *
2104 * This procedure is called to process an argv/argc list, plus
2105 * the Tk option database, in order to configure (or reconfigure)
2106 * a image marker.
2107 *
2108 * Results:
2109 * A standard Tcl result. If TCL_ERROR is returned, then
2110 * interp->result contains an error message.
2111 *
2112 * Side effects:
2113 * Configuration information, such as image pixmap, colors,
2114 * rotation, etc. get set for markerPtr; old resources get freed,
2115 * if there were any. The marker is eventually redisplayed.
2116 *
2117 * ----------------------------------------------------------------------
2118 */
2119static int
2120ConfigureImageMarker(markerPtr)
2121 Marker *markerPtr;
2122{
2123 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2124 Graph *graphPtr = markerPtr->graphPtr;
2125
2126 if (Blt_ConfigModified(markerPtr->classPtr->configSpecs, "-image",
2127 (char *)NULL)) {
2128 Tcl_Interp *interp = graphPtr->interp;
2129
2130 if (imPtr->tkImage != NULL) {
2131 Tk_FreeImage(imPtr->tkImage);
2132 imPtr->tkImage = NULL;
2133 }
2134 if (imPtr->imageName[0] != '\0') {
2135 GC newGC;
2136 Tk_PhotoHandle photo;
2137
2138 imPtr->tkImage = Tk_GetImage(interp, graphPtr->tkwin,
2139 imPtr->imageName, ImageChangedProc, imPtr);
2140 if (imPtr->tkImage == NULL) {
2141 Blt_Free(imPtr->imageName);
2142 imPtr->imageName = NULL;
2143 return TCL_ERROR;
2144 }
2145 photo = Blt_FindPhoto(interp, imPtr->imageName);
2146 if (photo != NULL) {
2147 if (imPtr->srcImage != NULL) {
2148 Blt_FreeColorImage(imPtr->srcImage);
2149 }
2150 /* Convert the photo into a color image */
2151 imPtr->srcImage = Blt_PhotoToColorImage(photo);
2152 }
2153 newGC = Tk_GetGC(graphPtr->tkwin, 0L, (XGCValues *)NULL);
2154 if (imPtr->gc != NULL) {
2155 Tk_FreeGC(graphPtr->display, imPtr->gc);
2156 }
2157 imPtr->gc = newGC;
2158 }
2159 }
2160 imPtr->flags |= MAP_ITEM;
2161 if (imPtr->drawUnder) {
2162 graphPtr->flags |= REDRAW_BACKING_STORE;
2163 }
2164 Blt_EventuallyRedrawGraph(graphPtr);
2165 return TCL_OK;
2166}
2167
2168/*
2169 * ----------------------------------------------------------------------
2170 *
2171 * MapImageMarker --
2172 *
2173 * This procedure gets called each time the layout of the graph
2174 * changes. The x, y window coordinates of the image marker are
2175 * saved in the marker structure.
2176 *
2177 * Additionly, if no background color was specified, the
2178 * GCTileStipXOrigin and GCTileStipYOrigin attributes are set in
2179 * the private GC.
2180 *
2181 * Results:
2182 * None.
2183 *
2184 * Side effects:
2185 * Window coordinates are saved and if no background color was *
2186 * set, the GC stipple origins are changed to calculated window
2187 * coordinates.
2188 *
2189 * ----------------------------------------------------------------------
2190 */
2191static void
2192MapImageMarker(markerPtr)
2193 Marker *markerPtr;
2194{
2195 Extents2D exts;
2196 Graph *graphPtr;
2197 ImageMarker *imPtr;
2198 Point2D anchorPos;
2199 Point2D corner1, corner2;
2200 int scaledWidth, scaledHeight;
2201 int srcWidth, srcHeight;
2202
2203 imPtr = (ImageMarker *)markerPtr;
2204 if (imPtr->tkImage == NULL) {
2205 return;
2206 }
2207 graphPtr = imPtr->graphPtr;
2208 corner1 = MapPoint(graphPtr, imPtr->worldPts, &imPtr->axes);
2209 if (imPtr->srcImage == NULL) {
2210 /*
2211 * Don't scale or rotate non-photo images.
2212 */
2213 Tk_SizeOfImage(imPtr->tkImage, &srcWidth, &srcHeight);
2214 imPtr->width = srcWidth;
2215 imPtr->height = srcHeight;
2216 imPtr->anchorPos.x = corner1.x + imPtr->xOffset;
2217 imPtr->anchorPos.y = corner1.y + imPtr->yOffset;
2218 exts.left = imPtr->anchorPos.x;
2219 exts.top = imPtr->anchorPos.y;
2220 exts.right = exts.left + srcWidth - 1;
2221 exts.bottom = exts.top + srcHeight - 1;
2222 imPtr->clipped = BoxesDontOverlap(graphPtr, &exts);
2223 return;
2224 }
2225
2226 imPtr->width = srcWidth = Blt_ColorImageWidth(imPtr->srcImage);
2227 imPtr->height = srcHeight = Blt_ColorImageHeight(imPtr->srcImage);
2228 if ((srcWidth == 0) && (srcHeight == 0)) {
2229 imPtr->clipped = TRUE;
2230 return; /* Empty image. */
2231 }
2232 if (imPtr->nWorldPts > 1) {
2233 double hold;
2234
2235 corner2 = MapPoint(graphPtr, imPtr->worldPts + 1, &imPtr->axes);
2236 /* Flip the corners if necessary */
2237 if (corner1.x > corner2.x) {
2238 hold = corner1.x, corner1.x = corner2.x, corner2.x = hold;
2239 }
2240 if (corner1.y > corner2.y) {
2241 hold = corner1.y, corner1.y = corner2.y, corner2.y = hold;
2242 }
2243 } else {
2244 corner2.x = corner1.x + srcWidth - 1;
2245 corner2.y = corner1.y + srcHeight - 1;
2246 }
2247 scaledWidth = (int)(corner2.x - corner1.x) + 1;
2248 scaledHeight = (int)(corner2.y - corner1.y) + 1;
2249
2250 if (imPtr->nWorldPts == 1) {
2251 anchorPos = Blt_TranslatePoint(&corner1, scaledWidth, scaledHeight,
2252 imPtr->anchor);
2253 } else {
2254 anchorPos = corner1;
2255 }
2256 anchorPos.x += imPtr->xOffset;
2257 anchorPos.y += imPtr->yOffset;
2258
2259 /* Check if the image sits at least partially in the plot area. */
2260 exts.left = anchorPos.x;
2261 exts.top = anchorPos.y;
2262 exts.right = anchorPos.x + scaledWidth - 1;
2263 exts.bottom = anchorPos.y + scaledHeight - 1;
2264
2265 imPtr->clipped = BoxesDontOverlap(graphPtr, &exts);
2266 if (imPtr->clipped) {
2267 return; /* Image is offscreen. Don't generate
2268 * rotated or scaled images. */
2269 }
2270 if ((scaledWidth != srcWidth) || (scaledHeight != srcHeight)) {
2271 Tk_PhotoHandle photo;
2272 Blt_ColorImage destImage;
2273 int x, y, width, height;
2274 int left, right, top, bottom;
2275
2276 /* Determine the region of the subimage inside of the
2277 * destination image. */
2278 left = MAX((int)exts.left, graphPtr->left);
2279 top = MAX((int)exts.top, graphPtr->top);
2280 right = MIN((int)exts.right, graphPtr->right);
2281 bottom = MIN((int)exts.bottom, graphPtr->bottom);
2282
2283 /* Reset image location and coordinates to that of the region */
2284 anchorPos.x = left;
2285 anchorPos.y = top;
2286
2287 x = y = 0;
2288 if (graphPtr->left > (int)exts.left) {
2289 x = graphPtr->left - (int)exts.left;
2290 }
2291 if (graphPtr->top > (int)exts.top) {
2292 y = graphPtr->top - (int)exts.top;
2293 }
2294 width = (int)(right - left + 1);
2295 height = (int)(bottom - top + 1);
2296
2297 destImage = Blt_ResizeColorSubimage(imPtr->srcImage, x, y, width,
2298 height, scaledWidth, scaledHeight);
2299#ifdef notyet
2300 /* Now convert the color image into a pixmap */
2301 if (imPtr->pixmap != None) {
2302 Blt_FreeColorTable(imPtr->colorTable);
2303 Tk_FreePixmap(Tk_Display(graphPtr->tkwin), imPtr->pixmap);
2304 imPtr->colorTable = NULL;
2305 }
2306 imPtr->pixmap = Blt_ColorImageToPixmap(graphPtr->interp,
2307 graphPtr->tkwin, destImage, &imPtr->colorTable);
2308#else
2309 imPtr->pixmap = None;
2310 if (imPtr->tmpImage == NULL) {
2311 imPtr->tmpImage = Blt_CreateTemporaryImage(graphPtr->interp,
2312 graphPtr->tkwin, imPtr);
2313 if (imPtr->tmpImage == NULL) {
2314 return;
2315 }
2316 }
2317 /* Put the scaled colorimage into the photo. */
2318 photo = Blt_FindPhoto(graphPtr->interp,
2319 Blt_NameOfImage(imPtr->tmpImage));
2320 Blt_ColorImageToPhoto(destImage, photo);
2321#endif
2322 Blt_FreeColorImage(destImage);
2323 imPtr->width = width;
2324 imPtr->height = height;
2325 }
2326 imPtr->anchorPos = anchorPos;
2327}
2328
2329/*
2330 * ----------------------------------------------------------------------
2331 *
2332 * PointInWindowMarker --
2333 *
2334 * Indicates if the given point is over the window marker. The
2335 * area of the window is the rectangle.
2336 *
2337 * Results:
2338 * Returns 1 is the point is over the window marker, 0 otherwise.
2339 *
2340 * ----------------------------------------------------------------------
2341 */
2342static int
2343PointInImageMarker(markerPtr, samplePtr)
2344 Marker *markerPtr;
2345 Point2D *samplePtr;
2346{
2347 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2348
2349 return ((samplePtr->x >= imPtr->anchorPos.x) &&
2350 (samplePtr->x < (imPtr->anchorPos.x + imPtr->width)) &&
2351 (samplePtr->y >= imPtr->anchorPos.y) &&
2352 (samplePtr->y < (imPtr->anchorPos.y + imPtr->height)));
2353}
2354
2355/*
2356 * ----------------------------------------------------------------------
2357 *
2358 * RegionInImageMarker --
2359 *
2360 * ----------------------------------------------------------------------
2361 */
2362static int
2363RegionInImageMarker(markerPtr, extsPtr, enclosed)
2364 Marker *markerPtr;
2365 Extents2D *extsPtr;
2366 int enclosed;
2367{
2368 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2369
2370 if (imPtr->nWorldPts < 1) {
2371 return FALSE;
2372 }
2373 if (enclosed) {
2374 return ((imPtr->anchorPos.x >= extsPtr->left) &&
2375 (imPtr->anchorPos.y >= extsPtr->top) &&
2376 ((imPtr->anchorPos.x + imPtr->width) <= extsPtr->right) &&
2377 ((imPtr->anchorPos.y + imPtr->height) <= extsPtr->bottom));
2378 }
2379 return !((imPtr->anchorPos.x >= extsPtr->right) ||
2380 (imPtr->anchorPos.y >= extsPtr->bottom) ||
2381 ((imPtr->anchorPos.x + imPtr->width) <= extsPtr->left) ||
2382 ((imPtr->anchorPos.y + imPtr->height) <= extsPtr->top));
2383}
2384
2385/*
2386 * ----------------------------------------------------------------------
2387 *
2388 * DrawImageMarker --
2389 *
2390 * This procedure is invoked to draw a image marker.
2391 *
2392 * Results:
2393 * None.
2394 *
2395 * Side effects:
2396 * GC stipple origins are changed to current window coordinates.
2397 * Commands are output to X to draw the marker in its current mode.
2398 *
2399 * ----------------------------------------------------------------------
2400 */
2401static void
2402DrawImageMarker(markerPtr, drawable)
2403 Marker *markerPtr;
2404 Drawable drawable; /* Pixmap or window to draw into */
2405{
2406 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2407 int width, height;
2408
2409 if ((imPtr->tkImage == NULL) || (Tk_ImageIsDeleted(imPtr->tkImage))) {
2410 return;
2411 }
2412 if (imPtr->pixmap == None) {
2413 Pixmap pixmap;
2414 Tk_Image tkImage;
2415
2416 tkImage = (imPtr->tmpImage != NULL) ? imPtr->tmpImage : imPtr->tkImage;
2417 Tk_SizeOfImage(tkImage, &width, &height);
2418 /* pixmap = Tk_ImageGetPhotoPixmap(tkImage); */
2419 pixmap = None;
2420 if (pixmap == None) { /* May not be a "photo" image. */
2421 Tk_RedrawImage(tkImage, 0, 0, width, height, drawable,
2422 (int)imPtr->anchorPos.x, (int)imPtr->anchorPos.y);
2423 } else {
2424 XCopyArea(imPtr->graphPtr->display, pixmap, drawable,
2425 imPtr->gc, 0, 0, width, height, (int)imPtr->anchorPos.x,
2426 (int)imPtr->anchorPos.y);
2427 }
2428 } else {
2429 XCopyArea(imPtr->graphPtr->display, imPtr->pixmap, drawable,
2430 imPtr->gc, 0, 0, imPtr->width, imPtr->height,
2431 (int)imPtr->anchorPos.x, (int)imPtr->anchorPos.y);
2432 }
2433}
2434
2435/*
2436 * ----------------------------------------------------------------------
2437 *
2438 * ImageMarkerToPostScript --
2439 *
2440 * This procedure is invoked to print a image marker.
2441 *
2442 * Results:
2443 * None.
2444 *
2445 * ----------------------------------------------------------------------
2446 */
2447static void
2448ImageMarkerToPostScript(markerPtr, psToken)
2449 Marker *markerPtr; /* Marker to be printed */
2450 PsToken psToken;
2451{
2452 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2453 char *imageName;
2454 Tk_PhotoHandle photo;
2455
2456 if ((imPtr->tkImage == NULL) || (Tk_ImageIsDeleted(imPtr->tkImage))) {
2457 return; /* Image doesn't exist anymore */
2458 }
2459 imageName = (imPtr->tmpImage == NULL)
2460 ? Blt_NameOfImage(imPtr->tkImage) : Blt_NameOfImage(imPtr->tmpImage);
2461 photo = Blt_FindPhoto(markerPtr->graphPtr->interp, imageName);
2462 if (photo == NULL) {
2463 return; /* Image isn't a photo image */
2464 }
2465 Blt_PhotoToPostScript(psToken, photo, imPtr->anchorPos.x,
2466 imPtr->anchorPos.y);
2467}
2468
2469/*
2470 * ----------------------------------------------------------------------
2471 *
2472 * FreeImageMarker --
2473 *
2474 * Destroys the structure containing the attributes of the image
2475 * marker.
2476 *
2477 * Results:
2478 * None.
2479 *
2480 * Side effects:
2481 * Image attributes (GCs, colors, image, etc) get destroyed.
2482 * Memory is released, X resources are freed, and the graph is
2483 * redrawn.
2484 *
2485 * ----------------------------------------------------------------------
2486 */
2487static void
2488FreeImageMarker(graphPtr, markerPtr)
2489 Graph *graphPtr;
2490 Marker *markerPtr;
2491{
2492 ImageMarker *imPtr = (ImageMarker *)markerPtr;
2493
2494 if (imPtr->pixmap != None) {
2495 Tk_FreePixmap(graphPtr->display, imPtr->pixmap);
2496 }
2497 if (imPtr->tkImage != NULL) {
2498 Tk_FreeImage(imPtr->tkImage);
2499 }
2500 if (imPtr->tmpImage != NULL) {
2501 Blt_DestroyTemporaryImage(graphPtr->interp, imPtr->tmpImage);
2502 }
2503 if (imPtr->srcImage != NULL) {
2504 Blt_FreeColorImage(imPtr->srcImage);
2505 }
2506 if (imPtr->gc != NULL) {
2507 Tk_FreeGC(graphPtr->display, imPtr->gc);
2508 }
2509}
2510
2511/*
2512 * ----------------------------------------------------------------------
2513 *
2514 * CreateImageMarker --
2515 *
2516 * Allocate memory and initialize methods for the new image marker.
2517 *
2518 * Results:
2519 * The pointer to the newly allocated marker structure is returned.
2520 *
2521 * Side effects:
2522 * Memory is allocated for the image marker structure.
2523 *
2524 * ----------------------------------------------------------------------
2525 */
2526static Marker *
2527CreateImageMarker()
2528{
2529 ImageMarker *imPtr;
2530
2531 imPtr = Blt_Calloc(1, sizeof(ImageMarker));
2532 if (imPtr != NULL) {
2533 imPtr->classPtr = &imageMarkerClass;
2534 }
2535 return (Marker *)imPtr;
2536}
2537
2538/*
2539 * ----------------------------------------------------------------------
2540 *
2541 * ConfigureTextMarker --
2542 *
2543 * This procedure is called to process an argv/argc list, plus
2544 * the Tk option database, in order to configure (or
2545 * reconfigure) a text marker.
2546 *
2547 * Results:
2548 * A standard Tcl result. If TCL_ERROR is returned, then
2549 * interp->result contains an error message.
2550 *
2551 * Side effects:
2552 * Configuration information, such as text string, colors, font,
2553 * etc. get set for markerPtr; old resources get freed, if there
2554 * were any. The marker is eventually redisplayed.
2555 *
2556 * ----------------------------------------------------------------------
2557 */
2558static int
2559ConfigureTextMarker(markerPtr)
2560 Marker *markerPtr;
2561{
2562 Graph *graphPtr = markerPtr->graphPtr;
2563 TextMarker *tmPtr = (TextMarker *)markerPtr;
2564 GC newGC;
2565 XGCValues gcValues;
2566 unsigned long gcMask;
2567
2568 tmPtr->style.theta = FMOD(tmPtr->style.theta, 360.0);
2569 if (tmPtr->style.theta < 0.0) {
2570 tmPtr->style.theta += 360.0;
2571 }
2572 newGC = NULL;
2573 if (tmPtr->fillColor != NULL) {
2574 gcMask = GCForeground;
2575 gcValues.foreground = tmPtr->fillColor->pixel;
2576 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
2577 }
2578 if (tmPtr->fillGC != NULL) {
2579 Tk_FreeGC(graphPtr->display, tmPtr->fillGC);
2580 }
2581 tmPtr->fillGC = newGC;
2582 Blt_ResetTextStyle(graphPtr->tkwin, &tmPtr->style);
2583
2584 if (Blt_ConfigModified(tmPtr->classPtr->configSpecs, "-text",
2585 (char *)NULL)) {
2586 if (tmPtr->textPtr != NULL) {
2587 Blt_Free(tmPtr->textPtr);
2588 tmPtr->textPtr = NULL;
2589 }
2590 tmPtr->width = tmPtr->height = 0;
2591 if (tmPtr->string != NULL) {
2592 register int i;
2593 double rotWidth, rotHeight;
2594
2595 tmPtr->textPtr = Blt_GetTextLayout(tmPtr->string, &tmPtr->style);
2596 Blt_GetBoundingBox(tmPtr->textPtr->width, tmPtr->textPtr->height,
2597 tmPtr->style.theta, &rotWidth, &rotHeight, tmPtr->outline);
2598 tmPtr->width = ROUND(rotWidth);
2599 tmPtr->height = ROUND(rotHeight);
2600 for (i = 0; i < 4; i++) {
2601 tmPtr->outline[i].x += ROUND(rotWidth * 0.5);
2602 tmPtr->outline[i].y += ROUND(rotHeight * 0.5);
2603 }
2604 tmPtr->outline[4].x = tmPtr->outline[0].x;
2605 tmPtr->outline[4].y = tmPtr->outline[0].y;
2606 }
2607 }
2608 tmPtr->flags |= MAP_ITEM;
2609 if (tmPtr->drawUnder) {
2610 graphPtr->flags |= REDRAW_BACKING_STORE;
2611 }
2612 Blt_EventuallyRedrawGraph(graphPtr);
2613 return TCL_OK;
2614}
2615
2616/*
2617 * ----------------------------------------------------------------------
2618 *
2619 * MapTextMarker --
2620 *
2621 * Calculate the layout position for a text marker. Positional
2622 * information is saved in the marker. If the text is rotated,
2623 * a bitmap containing the text is created.
2624 *
2625 * Results:
2626 * None.
2627 *
2628 * Side effects:
2629 * If no background color has been specified, the GC stipple
2630 * origins are changed to current window coordinates. For both
2631 * rotated and non-rotated text, if any old bitmap is leftover,
2632 * it is freed.
2633 *
2634 * ----------------------------------------------------------------------
2635 */
2636static void
2637MapTextMarker(markerPtr)
2638 Marker *markerPtr;
2639{
2640 Graph *graphPtr = markerPtr->graphPtr;
2641 TextMarker *tmPtr = (TextMarker *)markerPtr;
2642 Extents2D exts;
2643 Point2D anchorPos;
2644
2645 if (tmPtr->string == NULL) {
2646 return;
2647 }
2648 anchorPos = MapPoint(graphPtr, tmPtr->worldPts, &tmPtr->axes);
2649 anchorPos = Blt_TranslatePoint(&anchorPos, tmPtr->width, tmPtr->height,
2650 tmPtr->anchor);
2651 anchorPos.x += tmPtr->xOffset;
2652 anchorPos.y += tmPtr->yOffset;
2653 /*
2654 * Determine the bounding box of the text and test to see if it
2655 * is at least partially contained within the plotting area.
2656 */
2657 exts.left = anchorPos.x;
2658 exts.top = anchorPos.y;
2659 exts.right = anchorPos.x + tmPtr->width - 1;
2660 exts.bottom = anchorPos.y + tmPtr->height - 1;
2661 tmPtr->clipped = BoxesDontOverlap(graphPtr, &exts);
2662 tmPtr->anchorPos = anchorPos;
2663
2664}
2665
2666static int
2667PointInTextMarker(markerPtr, samplePtr)
2668 Marker *markerPtr;
2669 Point2D *samplePtr;
2670{
2671 TextMarker *tmPtr = (TextMarker *)markerPtr;
2672
2673 if (tmPtr->string == NULL) {
2674 return 0;
2675 }
2676 if (tmPtr->style.theta != 0.0) {
2677 Point2D points[5];
2678 register int i;
2679
2680 /*
2681 * Figure out the bounding polygon (isolateral) for the text
2682 * and see if the point is inside of it.
2683 */
2684
2685 for (i = 0; i < 5; i++) {
2686 points[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x;
2687 points[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y;
2688 }
2689 return Blt_PointInPolygon(samplePtr, points, 5);
2690 }
2691 return ((samplePtr->x >= tmPtr->anchorPos.x) &&
2692 (samplePtr->x < (tmPtr->anchorPos.x + tmPtr->width)) &&
2693 (samplePtr->y >= tmPtr->anchorPos.y) &&
2694 (samplePtr->y < (tmPtr->anchorPos.y + tmPtr->height)));
2695}
2696
2697/*
2698 * ----------------------------------------------------------------------
2699 *
2700 * RegionInTextMarker --
2701 *
2702 * ----------------------------------------------------------------------
2703 */
2704static int
2705RegionInTextMarker(markerPtr, extsPtr, enclosed)
2706 Marker *markerPtr;
2707 Extents2D *extsPtr;
2708 int enclosed;
2709{
2710 TextMarker *tmPtr = (TextMarker *)markerPtr;
2711
2712 if (tmPtr->nWorldPts < 1) {
2713 return FALSE;
2714 }
2715 if (tmPtr->style.theta != 0.0) {
2716 Point2D points[5];
2717 register int i;
2718
2719 /*
2720 * Generate the bounding polygon (isolateral) for the bitmap
2721 * and see if the point is inside of it.
2722 */
2723 for (i = 0; i < 4; i++) {
2724 points[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x;
2725 points[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y;
2726 }
2727 return Blt_RegionInPolygon(extsPtr, points, 4, enclosed);
2728 }
2729 if (enclosed) {
2730 return ((tmPtr->anchorPos.x >= extsPtr->left) &&
2731 (tmPtr->anchorPos.y >= extsPtr->top) &&
2732 ((tmPtr->anchorPos.x + tmPtr->width) <= extsPtr->right) &&
2733 ((tmPtr->anchorPos.y + tmPtr->height) <= extsPtr->bottom));
2734 }
2735 return !((tmPtr->anchorPos.x >= extsPtr->right) ||
2736 (tmPtr->anchorPos.y >= extsPtr->bottom) ||
2737 ((tmPtr->anchorPos.x + tmPtr->width) <= extsPtr->left) ||
2738 ((tmPtr->anchorPos.y + tmPtr->height) <= extsPtr->top));
2739}
2740
2741/*
2742 * ----------------------------------------------------------------------
2743 *
2744 * DrawTextMarker --
2745 *
2746 * Draws the text marker on the graph.
2747 *
2748 * Results:
2749 * None.
2750 *
2751 * Side effects:
2752 * Commands are output to X to draw the marker in its current
2753 * mode.
2754 *
2755 * ----------------------------------------------------------------------
2756 */
2757static void
2758DrawTextMarker(markerPtr, drawable)
2759 Marker *markerPtr;
2760 Drawable drawable; /* Pixmap or window to draw into */
2761{
2762 TextMarker *tmPtr = (TextMarker *)markerPtr;
2763 Graph *graphPtr = markerPtr->graphPtr;
2764
2765 if (tmPtr->string == NULL) {
2766 return;
2767 }
2768 if (tmPtr->fillGC != NULL) {
2769 XPoint pointArr[4];
2770 register int i;
2771
2772 /*
2773 * Simulate the rotated background of the bitmap by
2774 * filling a bounding polygon with the background color.
2775 */
2776 for (i = 0; i < 4; i++) {
2777 pointArr[i].x = (short int)
2778 (tmPtr->outline[i].x + tmPtr->anchorPos.x);
2779 pointArr[i].y = (short int)
2780 (tmPtr->outline[i].y + tmPtr->anchorPos.y);
2781 }
2782 XFillPolygon(graphPtr->display, drawable, tmPtr->fillGC, pointArr, 4,
2783 Convex, CoordModeOrigin);
2784 }
2785 if (tmPtr->style.color != NULL) {
2786 Blt_DrawTextLayout(graphPtr->tkwin, drawable, tmPtr->textPtr,
2787 &tmPtr->style, (int)tmPtr->anchorPos.x, (int)tmPtr->anchorPos.y);
2788 }
2789}
2790
2791/*
2792 * ----------------------------------------------------------------------
2793 *
2794 * TextMarkerToPostScript --
2795 *
2796 * Outputs PostScript commands to draw a text marker at a given
2797 * x,y coordinate, rotation, anchor, and font.
2798 *
2799 * Results:
2800 * None.
2801 *
2802 * Side effects:
2803 * PostScript font and color settings are changed.
2804 *
2805 * ----------------------------------------------------------------------
2806 */
2807static void
2808TextMarkerToPostScript(markerPtr, psToken)
2809 Marker *markerPtr;
2810 PsToken psToken;
2811{
2812 TextMarker *tmPtr = (TextMarker *)markerPtr;
2813
2814 if (tmPtr->string == NULL) {
2815 return;
2816 }
2817 if (tmPtr->fillGC != NULL) {
2818 Point2D polygon[4];
2819 register int i;
2820
2821 /*
2822 * Simulate the rotated background of the bitmap by
2823 * filling a bounding polygon with the background color.
2824 */
2825 for (i = 0; i < 4; i++) {
2826 polygon[i].x = tmPtr->outline[i].x + tmPtr->anchorPos.x;
2827 polygon[i].y = tmPtr->outline[i].y + tmPtr->anchorPos.y;
2828 }
2829 Blt_BackgroundToPostScript(psToken, tmPtr->fillColor);
2830 Blt_PolygonToPostScript(psToken, polygon, 4);
2831 }
2832 Blt_TextToPostScript(psToken, tmPtr->string, &tmPtr->style,
2833 tmPtr->anchorPos.x, tmPtr->anchorPos.y);
2834}
2835
2836/*
2837 * ----------------------------------------------------------------------
2838 *
2839 * FreeTextMarker --
2840 *
2841 * Destroys the structure containing the attributes of the text
2842 * marker.
2843 *
2844 * Results:
2845 * None.
2846 *
2847 * Side effects:
2848 * Text attributes (GCs, colors, stipple, font, etc) get destroyed.
2849 * Memory is released, X resources are freed, and the graph is
2850 * redrawn.
2851 *
2852 * ----------------------------------------------------------------------
2853 */
2854static void
2855FreeTextMarker(graphPtr, markerPtr)
2856 Graph *graphPtr;
2857 Marker *markerPtr;
2858{
2859 TextMarker *tmPtr = (TextMarker *)markerPtr;
2860
2861 Blt_FreeTextStyle(graphPtr->display, &tmPtr->style);
2862 if (tmPtr->textPtr != NULL) {
2863 Blt_Free(tmPtr->textPtr);
2864 }
2865}
2866
2867/*
2868 * ----------------------------------------------------------------------
2869 *
2870 * CreateTextMarker --
2871 *
2872 * Allocate memory and initialize methods for the new text marker.
2873 *
2874 * Results:
2875 * The pointer to the newly allocated marker structure is returned.
2876 *
2877 * Side effects:
2878 * Memory is allocated for the text marker structure.
2879 *
2880 * ----------------------------------------------------------------------
2881 */
2882static Marker *
2883CreateTextMarker()
2884{
2885 TextMarker *tmPtr;
2886
2887 tmPtr = Blt_Calloc(1, sizeof(TextMarker));
2888 assert(tmPtr);
2889
2890 tmPtr->classPtr = &textMarkerClass;
2891 Blt_InitTextStyle(&tmPtr->style);
2892 tmPtr->style.anchor = TK_ANCHOR_NW;
2893 tmPtr->style.padLeft = tmPtr->style.padRight = 4;
2894 tmPtr->style.padTop = tmPtr->style.padBottom = 4;
2895
2896 return (Marker *)tmPtr;
2897}
2898
2899
2900static void ChildEventProc _ANSI_ARGS_((ClientData clientData,
2901 XEvent *eventPtr));
2902static void ChildGeometryProc _ANSI_ARGS_((ClientData clientData,
2903 Tk_Window tkwin));
2904
2905static void ChildCustodyProc _ANSI_ARGS_((ClientData clientData,
2906 Tk_Window tkwin));
2907
2908static Tk_GeomMgr winMarkerMgrInfo =
2909{
2910 "graph", /* Name of geometry manager used by winfo */
2911 ChildGeometryProc, /* Procedure to for new geometry requests */
2912 ChildCustodyProc, /* Procedure when window is taken away */
2913};
2914
2915/*
2916 * ----------------------------------------------------------------------
2917 *
2918 * ConfigureWindowMarker --
2919 *
2920 * This procedure is called to process an argv/argc list, plus
2921 * the Tk option database, in order to configure (or reconfigure)
2922 * a window marker.
2923 *
2924 * Results:
2925 * A standard Tcl result. If TCL_ERROR is returned, then
2926 * interp->result contains an error message.
2927 *
2928 * Side effects:
2929 * Configuration information, such as window pathname, placement,
2930 * etc. get set for markerPtr; old resources get freed, if there
2931 * were any. The marker is eventually redisplayed.
2932 *
2933 * ----------------------------------------------------------------------
2934 */
2935static int
2936ConfigureWindowMarker(markerPtr)
2937 Marker *markerPtr;
2938{
2939 Graph *graphPtr = markerPtr->graphPtr;
2940 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
2941 Tk_Window tkwin;
2942
2943 if (wmPtr->pathName == NULL) {
2944 return TCL_OK;
2945 }
2946 tkwin = Tk_NameToWindow(graphPtr->interp, wmPtr->pathName,
2947 graphPtr->tkwin);
2948 if (tkwin == NULL) {
2949 return TCL_ERROR;
2950 }
2951 if (Tk_Parent(tkwin) != graphPtr->tkwin) {
2952 Tcl_AppendResult(graphPtr->interp, "\"", wmPtr->pathName,
2953 "\" is not a child of \"", Tk_PathName(graphPtr->tkwin), "\"",
2954 (char *)NULL);
2955 return TCL_ERROR;
2956 }
2957 if (tkwin != wmPtr->tkwin) {
2958 if (wmPtr->tkwin != NULL) {
2959 Tk_DeleteEventHandler(wmPtr->tkwin, StructureNotifyMask,
2960 ChildEventProc, wmPtr);
2961 Tk_ManageGeometry(wmPtr->tkwin, (Tk_GeomMgr *) 0, (ClientData)0);
2962 Tk_UnmapWindow(wmPtr->tkwin);
2963 }
2964 Tk_CreateEventHandler(tkwin, StructureNotifyMask, ChildEventProc,
2965 wmPtr);
2966 Tk_ManageGeometry(tkwin, &winMarkerMgrInfo, wmPtr);
2967 }
2968 wmPtr->tkwin = tkwin;
2969
2970 wmPtr->flags |= MAP_ITEM;
2971 if (wmPtr->drawUnder) {
2972 graphPtr->flags |= REDRAW_BACKING_STORE;
2973 }
2974 Blt_EventuallyRedrawGraph(graphPtr);
2975 return TCL_OK;
2976}
2977
2978/*
2979 * ----------------------------------------------------------------------
2980 *
2981 * MapWindowMarker --
2982 *
2983 * Calculate the layout position for a window marker. Positional
2984 * information is saved in the marker.
2985 *
2986 * Results:
2987 * None.
2988 *
2989 * ----------------------------------------------------------------------
2990 */
2991static void
2992MapWindowMarker(markerPtr)
2993 Marker *markerPtr;
2994{
2995 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
2996 Graph *graphPtr = markerPtr->graphPtr;
2997 Extents2D exts;
2998 int width, height;
2999
3000 if (wmPtr->tkwin == (Tk_Window)NULL) {
3001 return;
3002 }
3003 wmPtr->anchorPos = MapPoint(graphPtr, wmPtr->worldPts, &wmPtr->axes);
3004
3005 width = Tk_ReqWidth(wmPtr->tkwin);
3006 height = Tk_ReqHeight(wmPtr->tkwin);
3007 if (wmPtr->reqWidth > 0) {
3008 width = wmPtr->reqWidth;
3009 }
3010 if (wmPtr->reqHeight > 0) {
3011 height = wmPtr->reqHeight;
3012 }
3013 wmPtr->anchorPos = Blt_TranslatePoint(&wmPtr->anchorPos, width, height,
3014 wmPtr->anchor);
3015 wmPtr->anchorPos.x += wmPtr->xOffset;
3016 wmPtr->anchorPos.y += wmPtr->yOffset;
3017 wmPtr->width = width;
3018 wmPtr->height = height;
3019
3020 /*
3021 * Determine the bounding box of the window and test to see if it
3022 * is at least partially contained within the plotting area.
3023 */
3024 exts.left = wmPtr->anchorPos.x;
3025 exts.top = wmPtr->anchorPos.y;
3026 exts.right = wmPtr->anchorPos.x + wmPtr->width - 1;
3027 exts.bottom = wmPtr->anchorPos.y + wmPtr->height - 1;
3028 wmPtr->clipped = BoxesDontOverlap(graphPtr, &exts);
3029}
3030
3031/*
3032 * ----------------------------------------------------------------------
3033 *
3034 * PointInWindowMarker --
3035 *
3036 * ----------------------------------------------------------------------
3037 */
3038static int
3039PointInWindowMarker(markerPtr, samplePtr)
3040 Marker *markerPtr;
3041 Point2D *samplePtr;
3042{
3043 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
3044
3045 return ((samplePtr->x >= wmPtr->anchorPos.x) &&
3046 (samplePtr->x < (wmPtr->anchorPos.x + wmPtr->width)) &&
3047 (samplePtr->y >= wmPtr->anchorPos.y) &&
3048 (samplePtr->y < (wmPtr->anchorPos.y + wmPtr->height)));
3049}
3050
3051/*
3052 * ----------------------------------------------------------------------
3053 *
3054 * RegionInWindowMarker --
3055 *
3056 * ----------------------------------------------------------------------
3057 */
3058static int
3059RegionInWindowMarker(markerPtr, extsPtr, enclosed)
3060 Marker *markerPtr;
3061 Extents2D *extsPtr;
3062 int enclosed;
3063{
3064 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
3065
3066 if (wmPtr->nWorldPts < 1) {
3067 return FALSE;
3068 }
3069 if (enclosed) {
3070 return ((wmPtr->anchorPos.x >= extsPtr->left) &&
3071 (wmPtr->anchorPos.y >= extsPtr->top) &&
3072 ((wmPtr->anchorPos.x + wmPtr->width) <= extsPtr->right) &&
3073 ((wmPtr->anchorPos.y + wmPtr->height) <= extsPtr->bottom));
3074 }
3075 return !((wmPtr->anchorPos.x >= extsPtr->right) ||
3076 (wmPtr->anchorPos.y >= extsPtr->bottom) ||
3077 ((wmPtr->anchorPos.x + wmPtr->width) <= extsPtr->left) ||
3078 ((wmPtr->anchorPos.y + wmPtr->height) <= extsPtr->top));
3079}
3080
3081/*
3082 * ----------------------------------------------------------------------
3083 *
3084 * DrawWindowMarker --
3085 *
3086 * ----------------------------------------------------------------------
3087 */
3088/*ARGSUSED*/
3089static void
3090DrawWindowMarker(markerPtr, drawable)
3091 Marker *markerPtr;
3092 Drawable drawable; /* Pixmap or window to draw into */
3093{
3094 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
3095
3096 if (wmPtr->tkwin == NULL) {
3097 return;
3098 }
3099 if ((wmPtr->height != Tk_Height(wmPtr->tkwin)) ||
3100 (wmPtr->width != Tk_Width(wmPtr->tkwin)) ||
3101 ((int)wmPtr->anchorPos.x != Tk_X(wmPtr->tkwin)) ||
3102 ((int)wmPtr->anchorPos.y != Tk_Y(wmPtr->tkwin))) {
3103 Tk_MoveResizeWindow(wmPtr->tkwin, (int)wmPtr->anchorPos.x,
3104 (int)wmPtr->anchorPos.y, wmPtr->width, wmPtr->height);
3105 }
3106 if (!Tk_IsMapped(wmPtr->tkwin)) {
3107 Tk_MapWindow(wmPtr->tkwin);
3108 }
3109}
3110
3111/*
3112 * ----------------------------------------------------------------------
3113 *
3114 * WindowMarkerToPostScript --
3115 *
3116 * ----------------------------------------------------------------------
3117 */
3118static void
3119WindowMarkerToPostScript(markerPtr, psToken)
3120 Marker *markerPtr;
3121 PsToken psToken;
3122{
3123 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
3124
3125 if (wmPtr->tkwin == NULL) {
3126 return;
3127 }
3128 if (Tk_IsMapped(wmPtr->tkwin)) {
3129 Blt_WindowToPostScript(psToken, wmPtr->tkwin, wmPtr->anchorPos.x,
3130 wmPtr->anchorPos.y);
3131 }
3132}
3133
3134/*
3135 * ----------------------------------------------------------------------
3136 *
3137 * FreeWindowMarker --
3138 *
3139 * Destroys the structure containing the attributes of the window
3140 * marker.
3141 *
3142 * Results:
3143 * None.
3144 *
3145 * Side effects:
3146 * Window is destroyed and removed from the screen.
3147 *
3148 * ----------------------------------------------------------------------
3149 */
3150/*ARGSUSED*/
3151static void
3152FreeWindowMarker(graphPtr, markerPtr)
3153 Graph *graphPtr;
3154 Marker *markerPtr;
3155{
3156 WindowMarker *wmPtr = (WindowMarker *)markerPtr;
3157
3158 if (wmPtr->tkwin != NULL) {
3159 Tk_DeleteEventHandler(wmPtr->tkwin, StructureNotifyMask,
3160 ChildEventProc, wmPtr);
3161 Tk_ManageGeometry(wmPtr->tkwin, (Tk_GeomMgr *) 0, (ClientData)0);
3162 Tk_DestroyWindow(wmPtr->tkwin);
3163 }
3164}
3165
3166/*
3167 * ----------------------------------------------------------------------
3168 *
3169 * CreateWindowMarker --
3170 *
3171 * Allocate memory and initialize methods for the new window marker.
3172 *
3173 * Results:
3174 * The pointer to the newly allocated marker structure is returned.
3175 *
3176 * Side effects:
3177 * Memory is allocated for the window marker structure.
3178 *
3179 * ----------------------------------------------------------------------
3180 */
3181static Marker *
3182CreateWindowMarker()
3183{
3184 WindowMarker *wmPtr;
3185
3186 wmPtr = Blt_Calloc(1, sizeof(WindowMarker));
3187 if (wmPtr != NULL) {
3188 wmPtr->classPtr = &windowMarkerClass;
3189 }
3190 return (Marker *)wmPtr;
3191}
3192
3193/*
3194 * ----------------------------------------------------------------------
3195 *
3196 * ChildEventProc --
3197 *
3198 * This procedure is invoked whenever StructureNotify events
3199 * occur for a window that's managed as part of a graph window
3200 * marker. This procedure's only purpose is to clean up when
3201 * windows are deleted.
3202 *
3203 * Results:
3204 * None.
3205 *
3206 * Side effects:
3207 * The window is disassociated from the window item when it is
3208 * deleted.
3209 *
3210 * ----------------------------------------------------------------------
3211 */
3212static void
3213ChildEventProc(clientData, eventPtr)
3214 ClientData clientData; /* Pointer to record describing window item. */
3215 XEvent *eventPtr; /* Describes what just happened. */
3216{
3217 WindowMarker *wmPtr = clientData;
3218
3219 if (eventPtr->type == DestroyNotify) {
3220 wmPtr->tkwin = NULL;
3221 }
3222}
3223
3224/*
3225 * ----------------------------------------------------------------------
3226 *
3227 * ChildGeometryProc --
3228 *
3229 * This procedure is invoked whenever a window that's associated
3230 * with a window item changes its requested dimensions.
3231 *
3232 * Results:
3233 * None.
3234 *
3235 * Side effects:
3236 * The size and location on the window of the window may change,
3237 * depending on the options specified for the window item.
3238 *
3239 * ----------------------------------------------------------------------
3240 */
3241/* ARGSUSED */
3242static void
3243ChildGeometryProc(clientData, tkwin)
3244 ClientData clientData; /* Pointer to record for window item. */
3245 Tk_Window tkwin; /* Window that changed its desired size. */
3246{
3247 WindowMarker *wmPtr = clientData;
3248
3249 if (wmPtr->reqWidth == 0) {
3250 wmPtr->width = Tk_ReqWidth(tkwin);
3251 }
3252 if (wmPtr->reqHeight == 0) {
3253 wmPtr->height = Tk_ReqHeight(tkwin);
3254 }
3255}
3256
3257/*
3258 * ----------------------------------------------------------------------
3259 *
3260 * ChildCustodyProc --
3261 *
3262 * This procedure is invoked when an embedded window has been
3263 * stolen by another geometry manager. The information and
3264 * memory associated with the widget is released.
3265 *
3266 * Results:
3267 * None.
3268 *
3269 * Side effects:
3270 * Arranges for the graph to be redrawn without the embedded
3271 * widget at the next idle point.
3272 *
3273 * ----------------------------------------------------------------------
3274 */
3275 /* ARGSUSED */
3276static void
3277ChildCustodyProc(clientData, tkwin)
3278 ClientData clientData; /* Window marker to be destroyed. */
3279 Tk_Window tkwin; /* Not used. */
3280{
3281 Marker *markerPtr = clientData;
3282 Graph *graphPtr;
3283
3284 graphPtr = markerPtr->graphPtr;
3285 DestroyMarker(markerPtr);
3286 /*
3287 * Not really needed. We should get an Expose event when the
3288 * child window is unmapped.
3289 */
3290 Blt_EventuallyRedrawGraph(graphPtr);
3291}
3292
3293/*
3294 * ----------------------------------------------------------------------
3295 *
3296 * MapLineMarker --
3297 *
3298 * Calculate the layout position for a line marker. Positional
3299 * information is saved in the marker. The line positions are
3300 * stored in an array of points (malloc'ed).
3301 *
3302 * Results:
3303 * None.
3304 *
3305 * ----------------------------------------------------------------------
3306 */
3307static void
3308MapLineMarker(markerPtr)
3309 Marker *markerPtr;
3310{
3311 Graph *graphPtr = markerPtr->graphPtr;
3312 LineMarker *lmPtr = (LineMarker *)markerPtr;
3313 Point2D *srcPtr, *endPtr;
3314 Segment2D *segments, *segPtr;
3315 Point2D p, q, next;
3316 Extents2D exts;
3317
3318 lmPtr->nSegments = 0;
3319 if (lmPtr->segments != NULL) {
3320 Blt_Free(lmPtr->segments);
3321 }
3322 if (lmPtr->nWorldPts < 2) {
3323 return; /* Too few points */
3324 }
3325 Blt_GraphExtents(graphPtr, &exts);
3326
3327 /*
3328 * Allow twice the number of world coordinates. The line will
3329 * represented as series of line segments, not one continous
3330 * polyline. This is because clipping against the plot area may
3331 * chop the line into several disconnected segments.
3332 */
3333 segments = Blt_Malloc(lmPtr->nWorldPts * sizeof(Segment2D));
3334 srcPtr = lmPtr->worldPts;
3335 p = MapPoint(graphPtr, srcPtr, &lmPtr->axes);
3336 p.x += lmPtr->xOffset;
3337 p.y += lmPtr->yOffset;
3338
3339 segPtr = segments;
3340 for (srcPtr++, endPtr = lmPtr->worldPts + lmPtr->nWorldPts;
3341 srcPtr < endPtr; srcPtr++) {
3342 next = MapPoint(graphPtr, srcPtr, &lmPtr->axes);
3343 next.x += lmPtr->xOffset;
3344 next.y += lmPtr->yOffset;
3345 q = next;
3346 if (Blt_LineRectClip(&exts, &p, &q)) {
3347 segPtr->p = p;
3348 segPtr->q = q;
3349 segPtr++;
3350 }
3351 p = next;
3352 }
3353 lmPtr->nSegments = segPtr - segments;
3354 lmPtr->segments = segments;
3355 lmPtr->clipped = (lmPtr->nSegments == 0);
3356}
3357
3358static int
3359PointInLineMarker(markerPtr, samplePtr)
3360 Marker *markerPtr;
3361 Point2D *samplePtr;
3362{
3363 LineMarker *lmPtr = (LineMarker *)markerPtr;
3364
3365 return Blt_PointInSegments(samplePtr, lmPtr->segments, lmPtr->nSegments,
3366 (double)lmPtr->graphPtr->halo);
3367}
3368
3369/*
3370 * ----------------------------------------------------------------------
3371 *
3372 * RegionInLineMarker --
3373 *
3374 * ----------------------------------------------------------------------
3375 */
3376static int
3377RegionInLineMarker(markerPtr, extsPtr, enclosed)
3378 Marker *markerPtr;
3379 Extents2D *extsPtr;
3380 int enclosed;
3381{
3382 LineMarker *lmPtr = (LineMarker *)markerPtr;
3383
3384 if (lmPtr->nWorldPts < 2) {
3385 return FALSE;
3386 }
3387 if (enclosed) {
3388 Point2D p;
3389 Point2D *pointPtr, *endPtr;
3390
3391 for (pointPtr = lmPtr->worldPts,
3392 endPtr = lmPtr->worldPts + lmPtr->nWorldPts;
3393 pointPtr < endPtr; pointPtr++) {
3394 p = MapPoint(lmPtr->graphPtr, pointPtr, &lmPtr->axes);
3395 if ((p.x < extsPtr->left) && (p.x > extsPtr->right) &&
3396 (p.y < extsPtr->top) && (p.y > extsPtr->bottom)) {
3397 return FALSE;
3398 }
3399 }
3400 return TRUE; /* All points inside bounding box. */
3401 } else {
3402 Point2D p, q;
3403 int count;
3404 Point2D *pointPtr, *endPtr;
3405
3406 count = 0;
3407 for (pointPtr = lmPtr->worldPts,
3408 endPtr = lmPtr->worldPts + (lmPtr->nWorldPts - 1);
3409 pointPtr < endPtr; pointPtr++) {
3410 p = MapPoint(lmPtr->graphPtr, pointPtr, &lmPtr->axes);
3411 q = MapPoint(lmPtr->graphPtr, pointPtr + 1, &lmPtr->axes);
3412 if (Blt_LineRectClip(extsPtr, &p, &q)) {
3413 count++;
3414 }
3415 }
3416 return (count > 0); /* At least 1 segment passes through region. */
3417 }
3418}
3419
3420/*
3421 * ----------------------------------------------------------------------
3422 *
3423 * DrawLineMarker --
3424 *
3425 * ----------------------------------------------------------------------
3426 */
3427static void
3428DrawLineMarker(markerPtr, drawable)
3429 Marker *markerPtr;
3430 Drawable drawable; /* Pixmap or window to draw into */
3431{
3432 LineMarker *lmPtr = (LineMarker *)markerPtr;
3433
3434 if (lmPtr->nSegments > 0) {
3435 Graph *graphPtr = markerPtr->graphPtr;
3436
3437 Blt_Draw2DSegments(graphPtr->display, drawable, lmPtr->gc,
3438 lmPtr->segments, lmPtr->nSegments);
3439 if (lmPtr->xor) { /* Toggle the drawing state */
3440 lmPtr->xorState = (lmPtr->xorState == 0);
3441 }
3442 }
3443}
3444
3445/*
3446 * ----------------------------------------------------------------------
3447 *
3448 * ConfigureLineMarker --
3449 *
3450 * This procedure is called to process an argv/argc list, plus
3451 * the Tk option database, in order to configure (or reconfigure)
3452 * a line marker.
3453 *
3454 * Results:
3455 * A standard Tcl result. If TCL_ERROR is returned, then
3456 * interp->result contains an error message.
3457 *
3458 * Side effects:
3459 * Configuration information, such as line width, colors, dashes,
3460 * etc. get set for markerPtr; old resources get freed, if there
3461 * were any. The marker is eventually redisplayed.
3462 *
3463 * ----------------------------------------------------------------------
3464 */
3465/*ARGSUSED*/
3466static int
3467ConfigureLineMarker(markerPtr)
3468 Marker *markerPtr;
3469{
3470 Graph *graphPtr = markerPtr->graphPtr;
3471 LineMarker *lmPtr = (LineMarker *)markerPtr;
3472 GC newGC;
3473 XGCValues gcValues;
3474 unsigned long gcMask;
3475 Drawable drawable;
3476
3477 drawable = Tk_WindowId(graphPtr->tkwin);
3478 gcMask = (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
3479 if (lmPtr->outlineColor != NULL) {
3480 gcMask |= GCForeground;
3481 gcValues.foreground = lmPtr->outlineColor->pixel;
3482 }
3483 if (lmPtr->fillColor != NULL) {
3484 gcMask |= GCBackground;
3485 gcValues.background = lmPtr->fillColor->pixel;
3486 }
3487 gcValues.cap_style = lmPtr->capStyle;
3488 gcValues.join_style = lmPtr->joinStyle;
3489 gcValues.line_width = LineWidth(lmPtr->lineWidth);
3490 gcValues.line_style = LineSolid;
3491 if (LineIsDashed(lmPtr->dashes)) {
3492 gcValues.line_style =
3493 (gcMask & GCBackground) ? LineDoubleDash : LineOnOffDash;
3494 }
3495 if (lmPtr->xor) {
3496 unsigned long pixel;
3497 gcValues.function = GXxor;
3498
3499 gcMask |= GCFunction;
3500 if (graphPtr->plotBg == NULL) {
3501 pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin));
3502 } else {
3503 pixel = graphPtr->plotBg->pixel;
3504 }
3505 if (gcMask & GCBackground) {
3506 gcValues.background ^= pixel;
3507 }
3508 gcValues.foreground ^= pixel;
3509 if (drawable != None) {
3510 DrawLineMarker(markerPtr, drawable);
3511 }
3512 }
3513 newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
3514 if (lmPtr->gc != NULL) {
3515 Blt_FreePrivateGC(graphPtr->display, lmPtr->gc);
3516 }
3517 if (LineIsDashed(lmPtr->dashes)) {
3518 Blt_SetDashes(graphPtr->display, newGC, &lmPtr->dashes);
3519 }
3520 lmPtr->gc = newGC;
3521 if (lmPtr->xor) {
3522 if (drawable != None) {
3523 MapLineMarker(markerPtr);
3524 DrawLineMarker(markerPtr, drawable);
3525 }
3526 return TCL_OK;
3527 }
3528 lmPtr->flags |= MAP_ITEM;
3529 if (lmPtr->drawUnder) {
3530 graphPtr->flags |= REDRAW_BACKING_STORE;
3531 }
3532 Blt_EventuallyRedrawGraph(graphPtr);
3533 return TCL_OK;
3534}
3535
3536/*
3537 * ----------------------------------------------------------------------
3538 *
3539 * LineMarkerToPostScript --
3540 *
3541 * Prints postscript commands to display the connect line.
3542 * Dashed lines need to be handled specially, especially if a
3543 * background color is designated.
3544 *
3545 * Results:
3546 * None.
3547 *
3548 * Side effects:
3549 * PostScript output commands are saved in the interpreter
3550 * (infoPtr->interp) result field.
3551 *
3552 * ----------------------------------------------------------------------
3553 */
3554static void
3555LineMarkerToPostScript(markerPtr, psToken)
3556 Marker *markerPtr;
3557 PsToken psToken;
3558{
3559 LineMarker *lmPtr = (LineMarker *)markerPtr;
3560
3561 if (lmPtr->nSegments > 0) {
3562 Blt_LineAttributesToPostScript(psToken, lmPtr->outlineColor,
3563 lmPtr->lineWidth, &lmPtr->dashes, lmPtr->capStyle,
3564 lmPtr->joinStyle);
3565 if ((LineIsDashed(lmPtr->dashes)) && (lmPtr->fillColor != NULL)) {
3566 Blt_AppendToPostScript(psToken, "/DashesProc {\n gsave\n ",
3567 (char *)NULL);
3568 Blt_BackgroundToPostScript(psToken, lmPtr->fillColor);
3569 Blt_AppendToPostScript(psToken, " ", (char *)NULL);
3570 Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL);
3571 Blt_AppendToPostScript(psToken,
3572 "stroke\n",
3573 " grestore\n",
3574 "} def\n", (char *)NULL);
3575 } else {
3576 Blt_AppendToPostScript(psToken, "/DashesProc {} def\n",
3577 (char *)NULL);
3578 }
3579 Blt_2DSegmentsToPostScript(psToken, lmPtr->segments, lmPtr->nSegments);
3580 }
3581}
3582
3583/*
3584 * ----------------------------------------------------------------------
3585 *
3586 * FreeLineMarker --
3587 *
3588 * Destroys the structure and attributes of a line marker.
3589 *
3590 * Results:
3591 * None.
3592 *
3593 * Side effects:
3594 * Line attributes (GCs, colors, stipple, etc) get released.
3595 * Memory is deallocated, X resources are freed.
3596 *
3597 * ----------------------------------------------------------------------
3598 */
3599static void
3600FreeLineMarker(graphPtr, markerPtr)
3601 Graph *graphPtr;
3602 Marker *markerPtr;
3603{
3604 LineMarker *lmPtr = (LineMarker *)markerPtr;
3605
3606 if (lmPtr->gc != NULL) {
3607 Blt_FreePrivateGC(graphPtr->display, lmPtr->gc);
3608 }
3609 if (lmPtr->segments != NULL) {
3610 Blt_Free(lmPtr->segments);
3611 }
3612}
3613
3614
3615/*
3616 * ----------------------------------------------------------------------
3617 *
3618 * CreateLineMarker --
3619 *
3620 * Allocate memory and initialize methods for a new line marker.
3621 *
3622 * Results:
3623 * The pointer to the newly allocated marker structure is returned.
3624 *
3625 * Side effects:
3626 * Memory is allocated for the line marker structure.
3627 *
3628 * ----------------------------------------------------------------------
3629 */
3630static Marker *
3631CreateLineMarker()
3632{
3633 LineMarker *lmPtr;
3634
3635 lmPtr = Blt_Calloc(1, sizeof(LineMarker));
3636 if (lmPtr != NULL) {
3637 lmPtr->classPtr = &lineMarkerClass;
3638 lmPtr->xor = FALSE;
3639 lmPtr->capStyle = CapButt;
3640 lmPtr->joinStyle = JoinMiter;
3641 }
3642 return (Marker *)lmPtr;
3643}
3644
3645/*
3646 * ----------------------------------------------------------------------
3647 *
3648 * MapPolygonMarker --
3649 *
3650 * Calculate the layout position for a polygon marker. Positional
3651 * information is saved in the polygon in an array of points
3652 * (malloc'ed).
3653 *
3654 * Results:
3655 * None.
3656 *
3657 * ----------------------------------------------------------------------
3658 */
3659static void
3660MapPolygonMarker(markerPtr)
3661 Marker *markerPtr;
3662{
3663 Graph *graphPtr = markerPtr->graphPtr;
3664 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3665 Point2D *srcPtr, *destPtr, *endPtr;
3666 Point2D *screenPts;
3667 Extents2D exts;
3668 int nScreenPts;
3669
3670 if (pmPtr->outlinePts != NULL) {
3671 Blt_Free(pmPtr->outlinePts);
3672 pmPtr->outlinePts = NULL;
3673 pmPtr->nOutlinePts = 0;
3674 }
3675 if (pmPtr->fillPts != NULL) {
3676 Blt_Free(pmPtr->fillPts);
3677 pmPtr->fillPts = NULL;
3678 pmPtr->nFillPts = 0;
3679 }
3680 if (pmPtr->screenPts != NULL) {
3681 Blt_Free(pmPtr->screenPts);
3682 pmPtr->screenPts = NULL;
3683 }
3684 if (pmPtr->nWorldPts < 3) {
3685 return; /* Too few points */
3686 }
3687
3688 /*
3689 * Allocate and fill a temporary array to hold the screen
3690 * coordinates of the polygon.
3691 */
3692 nScreenPts = pmPtr->nWorldPts + 1;
3693 screenPts = Blt_Malloc((nScreenPts + 1) * sizeof(Point2D));
3694 endPtr = pmPtr->worldPts + pmPtr->nWorldPts;
3695 destPtr = screenPts;
3696 for (srcPtr = pmPtr->worldPts; srcPtr < endPtr; srcPtr++) {
3697 *destPtr = MapPoint(graphPtr, srcPtr, &pmPtr->axes);
3698 destPtr->x += pmPtr->xOffset;
3699 destPtr->y += pmPtr->yOffset;
3700 destPtr++;
3701 }
3702 *destPtr = screenPts[0];
3703
3704 Blt_GraphExtents(graphPtr, &exts);
3705 pmPtr->clipped = TRUE;
3706 if (pmPtr->fill.fgColor != NULL) { /* Polygon fill required. */
3707 Point2D *fillPts;
3708 int n;
3709
3710 fillPts = Blt_Malloc(sizeof(Point2D) * nScreenPts * 3);
3711 assert(fillPts);
3712 n = Blt_PolyRectClip(&exts, screenPts, pmPtr->nWorldPts, fillPts);
3713 if (n < 3) {
3714 Blt_Free(fillPts);
3715 } else {
3716 pmPtr->nFillPts = n;
3717 pmPtr->fillPts = fillPts;
3718 pmPtr->clipped = FALSE;
3719 }
3720 }
3721 if ((pmPtr->outline.fgColor != NULL) && (pmPtr->lineWidth > 0)) {
3722 Segment2D *outlinePts;
3723 register Segment2D *segPtr;
3724 /*
3725 * Generate line segments representing the polygon outline.
3726 * The resulting outline may or may not be closed from
3727 * viewport clipping.
3728 */
3729 outlinePts = Blt_Malloc(nScreenPts * sizeof(Segment2D));
3730 if (outlinePts == NULL) {
3731 return; /* Can't allocate point array */
3732 }
3733 /*
3734 * Note that this assumes that the point array contains an
3735 * extra point that closes the polygon.
3736 */
3737 segPtr = outlinePts;
3738 for (srcPtr = screenPts, endPtr = screenPts + (nScreenPts - 1);
3739 srcPtr < endPtr; srcPtr++) {
3740 segPtr->p = srcPtr[0];
3741 segPtr->q = srcPtr[1];
3742 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
3743 segPtr++;
3744 }
3745 }
3746 pmPtr->nOutlinePts = segPtr - outlinePts;
3747 pmPtr->outlinePts = outlinePts;
3748 if (pmPtr->nOutlinePts > 0) {
3749 pmPtr->clipped = FALSE;
3750 }
3751 }
3752 pmPtr->screenPts = screenPts;
3753}
3754
3755static int
3756PointInPolygonMarker(markerPtr, samplePtr)
3757 Marker *markerPtr;
3758 Point2D *samplePtr;
3759{
3760 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3761
3762 if ((pmPtr->nWorldPts >= 3) && (pmPtr->screenPts != NULL)) {
3763 return Blt_PointInPolygon(samplePtr, pmPtr->screenPts,
3764 pmPtr->nWorldPts + 1);
3765 }
3766 return FALSE;
3767}
3768
3769/*
3770 * ----------------------------------------------------------------------
3771 *
3772 * RegionInPolygonMarker --
3773 *
3774 * ----------------------------------------------------------------------
3775 */
3776static int
3777RegionInPolygonMarker(markerPtr, extsPtr, enclosed)
3778 Marker *markerPtr;
3779 Extents2D *extsPtr;
3780 int enclosed;
3781{
3782 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3783
3784 if ((pmPtr->nWorldPts >= 3) && (pmPtr->screenPts != NULL)) {
3785 return Blt_RegionInPolygon(extsPtr, pmPtr->screenPts, pmPtr->nWorldPts,
3786 enclosed);
3787 }
3788 return FALSE;
3789}
3790
3791static void
3792DrawPolygonMarker(markerPtr, drawable)
3793 Marker *markerPtr;
3794 Drawable drawable; /* Pixmap or window to draw into */
3795{
3796 Graph *graphPtr = markerPtr->graphPtr;
3797 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3798
3799 /* Draw polygon fill region */
3800 if ((pmPtr->nFillPts > 0) && (pmPtr->fill.fgColor != NULL)) {
3801 XPoint *destPtr, *pointArr;
3802 Point2D *srcPtr, *endPtr;
3803
3804 pointArr = Blt_Malloc(pmPtr->nFillPts * sizeof(XPoint));
3805 if (pointArr == NULL) {
3806 return;
3807 }
3808 destPtr = pointArr;
3809 for (srcPtr = pmPtr->fillPts,
3810 endPtr = pmPtr->fillPts + pmPtr->nFillPts; srcPtr < endPtr;
3811 srcPtr++) {
3812 destPtr->x = (short int)srcPtr->x;
3813 destPtr->y = (short int)srcPtr->y;
3814 destPtr++;
3815 }
3816 XFillPolygon(graphPtr->display, drawable, pmPtr->fillGC,
3817 pointArr, pmPtr->nFillPts, Complex, CoordModeOrigin);
3818 Blt_Free(pointArr);
3819 }
3820 /* and then the outline */
3821 if ((pmPtr->nOutlinePts > 0) && (pmPtr->lineWidth > 0) &&
3822 (pmPtr->outline.fgColor != NULL)) {
3823 Blt_Draw2DSegments(graphPtr->display, drawable, pmPtr->outlineGC,
3824 pmPtr->outlinePts, pmPtr->nOutlinePts);
3825 }
3826}
3827
3828
3829static void
3830PolygonMarkerToPostScript(markerPtr, psToken)
3831 Marker *markerPtr;
3832 PsToken psToken;
3833{
3834 Graph *graphPtr = markerPtr->graphPtr;
3835 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3836
3837 if (pmPtr->fill.fgColor != NULL) {
3838
3839 /*
3840 * Options: fg bg
3841 * Draw outline only.
3842 * x Draw solid or stipple.
3843 * x x Draw solid or stipple.
3844 */
3845
3846 /* Create a path to use for both the polygon and its outline. */
3847 Blt_PathToPostScript(psToken, pmPtr->fillPts, pmPtr->nFillPts);
3848 Blt_AppendToPostScript(psToken, "closepath\n", (char *)NULL);
3849
3850 /* If the background fill color was specified, draw the
3851 * polygon in a solid fashion with that color. */
3852 if (pmPtr->fill.bgColor != NULL) {
3853 Blt_BackgroundToPostScript(psToken, pmPtr->fill.bgColor);
3854 Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
3855 }
3856 Blt_ForegroundToPostScript(psToken, pmPtr->fill.fgColor);
3857 if (pmPtr->stipple != None) {
3858 /* Draw the stipple in the foreground color. */
3859 Blt_StippleToPostScript(psToken, graphPtr->display,
3860 pmPtr->stipple);
3861 } else {
3862 Blt_AppendToPostScript(psToken, "Fill\n", (char *)NULL);
3863 }
3864 }
3865
3866 /* Draw the outline in the foreground color. */
3867 if ((pmPtr->lineWidth > 0) && (pmPtr->outline.fgColor != NULL)) {
3868
3869 /* Set up the line attributes. */
3870 Blt_LineAttributesToPostScript(psToken, pmPtr->outline.fgColor,
3871 pmPtr->lineWidth, &pmPtr->dashes, pmPtr->capStyle,
3872 pmPtr->joinStyle);
3873
3874 /*
3875 * Define on-the-fly a PostScript macro "DashesProc" that
3876 * will be executed for each call to the Polygon drawing
3877 * routine. If the line isn't dashed, simply make this an
3878 * empty definition.
3879 */
3880 if ((pmPtr->outline.bgColor != NULL) && (LineIsDashed(pmPtr->dashes))) {
3881 Blt_AppendToPostScript(psToken,
3882 "/DashesProc {\n",
3883 "gsave\n ", (char *)NULL);
3884 Blt_BackgroundToPostScript(psToken, pmPtr->outline.bgColor);
3885 Blt_AppendToPostScript(psToken, " ", (char *)NULL);
3886 Blt_LineDashesToPostScript(psToken, (Blt_Dashes *)NULL);
3887 Blt_AppendToPostScript(psToken,
3888 "stroke\n",
3889 " grestore\n",
3890 "} def\n", (char *)NULL);
3891 } else {
3892 Blt_AppendToPostScript(psToken, "/DashesProc {} def\n",
3893 (char *)NULL);
3894 }
3895 Blt_2DSegmentsToPostScript(psToken, pmPtr->outlinePts,
3896 pmPtr->nOutlinePts);
3897 }
3898}
3899
3900/*
3901 * ----------------------------------------------------------------------
3902 *
3903 * ConfigurePolygonMarker --
3904 *
3905 * This procedure is called to process an argv/argc list, plus
3906 * the Tk option database, in order to configure (or reconfigure)
3907 * a polygon marker.
3908 *
3909 * Results:
3910 * A standard Tcl result. If TCL_ERROR is returned, then
3911 * interp->result contains an error message.
3912 *
3913 * Side effects:
3914 * Configuration information, such as polygon color, dashes,
3915 * fillstyle, etc. get set for markerPtr; old resources get
3916 * freed, if there were any. The marker is eventually
3917 * redisplayed.
3918 *
3919 * ----------------------------------------------------------------------
3920 */
3921/*ARGSUSED*/
3922static int
3923ConfigurePolygonMarker(markerPtr)
3924 Marker *markerPtr;
3925{
3926 Graph *graphPtr = markerPtr->graphPtr;
3927 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
3928 GC newGC;
3929 XGCValues gcValues;
3930 unsigned long gcMask;
3931 Drawable drawable;
3932
3933 drawable = Tk_WindowId(graphPtr->tkwin);
3934 gcMask = (GCLineWidth | GCLineStyle);
3935 if (pmPtr->outline.fgColor != NULL) {
3936 gcMask |= GCForeground;
3937 gcValues.foreground = pmPtr->outline.fgColor->pixel;
3938 }
3939 if (pmPtr->outline.bgColor != NULL) {
3940 gcMask |= GCBackground;
3941 gcValues.background = pmPtr->outline.bgColor->pixel;
3942 }
3943 gcMask |= (GCCapStyle | GCJoinStyle);
3944 gcValues.cap_style = pmPtr->capStyle;
3945 gcValues.join_style = pmPtr->joinStyle;
3946 gcValues.line_style = LineSolid;
3947 gcValues.dash_offset = 0;
3948 gcValues.line_width = LineWidth(pmPtr->lineWidth);
3949 if (LineIsDashed(pmPtr->dashes)) {
3950 gcValues.line_style = (pmPtr->outline.bgColor == NULL)
3951 ? LineOnOffDash : LineDoubleDash;
3952 }
3953 if (pmPtr->xor) {
3954 unsigned long pixel;
3955 gcValues.function = GXxor;
3956
3957 gcMask |= GCFunction;
3958 if (graphPtr->plotBg == NULL) {
3959 /* The graph's color option may not have been set yet */
3960 pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin));
3961 } else {
3962 pixel = graphPtr->plotBg->pixel;
3963 }
3964 if (gcMask & GCBackground) {
3965 gcValues.background ^= pixel;
3966 }
3967 gcValues.foreground ^= pixel;
3968 if (drawable != None) {
3969 DrawPolygonMarker(markerPtr, drawable);
3970 }
3971 }
3972 newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
3973 if (LineIsDashed(pmPtr->dashes)) {
3974 Blt_SetDashes(graphPtr->display, newGC, &pmPtr->dashes);
3975 }
3976 if (pmPtr->outlineGC != NULL) {
3977 Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC);
3978 }
3979 pmPtr->outlineGC = newGC;
3980
3981 gcMask = 0;
3982 if (pmPtr->fill.fgColor != NULL) {
3983 gcMask |= GCForeground;
3984 gcValues.foreground = pmPtr->fill.fgColor->pixel;
3985 }
3986 if (pmPtr->fill.bgColor != NULL) {
3987 gcMask |= GCBackground;
3988 gcValues.background = pmPtr->fill.bgColor->pixel;
3989 }
3990 if (pmPtr->stipple != None) {
3991 gcValues.stipple = pmPtr->stipple;
3992 gcValues.fill_style = (pmPtr->fill.bgColor != NULL)
3993 ? FillOpaqueStippled : FillStippled;
3994 gcMask |= (GCStipple | GCFillStyle);
3995 }
3996 newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
3997 if (pmPtr->fillGC != NULL) {
3998 Tk_FreeGC(graphPtr->display, pmPtr->fillGC);
3999 }
4000 pmPtr->fillGC = newGC;
4001
4002 if ((gcMask == 0) && !(graphPtr->flags & RESET_AXES) && (pmPtr->xor)) {
4003 if (drawable != None) {
4004 MapPolygonMarker(markerPtr);
4005 DrawPolygonMarker(markerPtr, drawable);
4006 }
4007 return TCL_OK;
4008 }
4009 pmPtr->flags |= MAP_ITEM;
4010 if (pmPtr->drawUnder) {
4011 graphPtr->flags |= REDRAW_BACKING_STORE;
4012 }
4013 Blt_EventuallyRedrawGraph(graphPtr);
4014 return TCL_OK;
4015}
4016
4017/*
4018 * ----------------------------------------------------------------------
4019 *
4020 * FreePolygonMarker --
4021 *
4022 * Release memory and resources allocated for the polygon element.
4023 *
4024 * Results:
4025 * None.
4026 *
4027 * Side effects:
4028 * Everything associated with the polygon element is freed up.
4029 *
4030 * ----------------------------------------------------------------------
4031 */
4032static void
4033FreePolygonMarker(graphPtr, markerPtr)
4034 Graph *graphPtr;
4035 Marker *markerPtr;
4036{
4037 PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
4038
4039 if (pmPtr->fillGC != NULL) {
4040 Tk_FreeGC(graphPtr->display, pmPtr->fillGC);
4041 }
4042 if (pmPtr->outlineGC != NULL) {
4043 Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC);
4044 }
4045 if (pmPtr->fillPts != NULL) {
4046 Blt_Free(pmPtr->fillPts);
4047 }
4048 if (pmPtr->outlinePts != NULL) {
4049 Blt_Free(pmPtr->outlinePts);
4050 }
4051 if (pmPtr->screenPts != NULL) {
4052 Blt_Free(pmPtr->screenPts);
4053 }
4054 Blt_FreeColorPair(&pmPtr->outline);
4055 Blt_FreeColorPair(&pmPtr->fill);
4056}
4057
4058/*
4059 * ----------------------------------------------------------------------
4060 *
4061 * CreatePolygonMarker --
4062 *
4063 * Allocate memory and initialize methods for the new polygon
4064 * marker.
4065 *
4066 * Results:
4067 * The pointer to the newly allocated marker structure is
4068 * returned.
4069 *
4070 * Side effects:
4071 * Memory is allocated for the polygon marker structure.
4072 *
4073 * ----------------------------------------------------------------------
4074 */
4075static Marker *
4076CreatePolygonMarker()
4077{
4078 PolygonMarker *pmPtr;
4079
4080 pmPtr = Blt_Calloc(1, sizeof(PolygonMarker));
4081 if (pmPtr != NULL) {
4082 pmPtr->classPtr = &polygonMarkerClass;
4083 pmPtr->capStyle = CapButt;
4084 pmPtr->joinStyle = JoinMiter;
4085
4086 }
4087 return (Marker *)pmPtr;
4088}
4089
4090static int
4091NameToMarker(graphPtr, name, markerPtrPtr)
4092 Graph *graphPtr;
4093 char *name;
4094 Marker **markerPtrPtr;
4095{
4096 Blt_HashEntry *hPtr;
4097
4098 hPtr = Blt_FindHashEntry(&graphPtr->markers.table, name);
4099 if (hPtr != NULL) {
4100 *markerPtrPtr = (Marker *)Blt_GetHashValue(hPtr);
4101 return TCL_OK;
4102 }
4103 Tcl_AppendResult(graphPtr->interp, "can't find marker \"", name,
4104 "\" in \"", Tk_PathName(graphPtr->tkwin), (char *)NULL);
4105 return TCL_ERROR;
4106}
4107
4108
4109static int
4110RenameMarker(graphPtr, markerPtr, oldName, newName)
4111 Graph *graphPtr;
4112 Marker *markerPtr;
4113 char *oldName, *newName;
4114{
4115 int isNew;
4116 Blt_HashEntry *hPtr;
4117
4118 /* Rename the marker only if no marker already exists by that name */
4119 hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, newName, &isNew);
4120 if (!isNew) {
4121 Tcl_AppendResult(graphPtr->interp, "can't rename marker: \"", newName,
4122 "\" already exists", (char *)NULL);
4123 return TCL_ERROR;
4124 }
4125 markerPtr->name = Blt_Strdup(newName);
4126 markerPtr->hashPtr = hPtr;
4127 Blt_SetHashValue(hPtr, (char *)markerPtr);
4128
4129 /* Delete the old hash entry */
4130 hPtr = Blt_FindHashEntry(&graphPtr->markers.table, oldName);
4131 Blt_DeleteHashEntry(&graphPtr->markers.table, hPtr);
4132 if (oldName != NULL) {
4133 Blt_Free(oldName);
4134 }
4135 return TCL_OK;
4136}
4137
4138/*
4139 * ----------------------------------------------------------------------
4140 *
4141 * NamesOp --
4142 *
4143 * Returns a list of marker identifiers in interp->result;
4144 *
4145 * Results:
4146 * The return value is a standard Tcl result.
4147 *
4148 * ----------------------------------------------------------------------
4149 */
4150static int
4151NamesOp(graphPtr, interp, argc, argv)
4152 Graph *graphPtr;
4153 Tcl_Interp *interp;
4154 int argc;
4155 char **argv;
4156{
4157 Marker *markerPtr;
4158 Blt_ChainLink *linkPtr;
4159 register int i;
4160
4161 Tcl_ResetResult(interp);
4162 for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList);
4163 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4164 markerPtr = Blt_ChainGetValue(linkPtr);
4165 if (argc == 3) {
4166 Tcl_AppendElement(interp, markerPtr->name);
4167 continue;
4168 }
4169 for (i = 3; i < argc; i++) {
4170 if (Tcl_StringMatch(markerPtr->name, argv[i])) {
4171 Tcl_AppendElement(interp, markerPtr->name);
4172 break;
4173 }
4174 }
4175 }
4176 return TCL_OK;
4177}
4178
4179ClientData
4180Blt_MakeMarkerTag(graphPtr, tagName)
4181 Graph *graphPtr;
4182 char *tagName;
4183{
4184 Blt_HashEntry *hPtr;
4185 int isNew;
4186
4187 hPtr = Blt_CreateHashEntry(&graphPtr->markers.tagTable, tagName, &isNew);
4188 assert(hPtr);
4189 return Blt_GetHashKey(&graphPtr->markers.tagTable, hPtr);
4190}
4191
4192/*
4193 *----------------------------------------------------------------------
4194 *
4195 * BindOp --
4196 *
4197 * .g element bind elemName sequence command
4198 *
4199 *----------------------------------------------------------------------
4200 */
4201/*ARGSUSED*/
4202static int
4203BindOp(graphPtr, interp, argc, argv)
4204 Graph *graphPtr;
4205 Tcl_Interp *interp;
4206 int argc;
4207 char **argv;
4208{
4209 if (argc == 3) {
4210 Blt_HashEntry *hPtr;
4211 Blt_HashSearch cursor;
4212 char *tag;
4213
4214 for (hPtr = Blt_FirstHashEntry(&graphPtr->markers.tagTable, &cursor);
4215 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
4216 tag = Blt_GetHashKey(&graphPtr->markers.tagTable, hPtr);
4217 Tcl_AppendElement(interp, tag);
4218 }
4219 return TCL_OK;
4220 }
4221 return Blt_ConfigureBindings(interp, graphPtr->bindTable,
4222 Blt_MakeMarkerTag(graphPtr, argv[3]), argc - 4, argv + 4);
4223}
4224
4225/*
4226 * ----------------------------------------------------------------------
4227 *
4228 * CgetOp --
4229 *
4230 * ----------------------------------------------------------------------
4231 */
4232/*ARGSUSED*/
4233static int
4234CgetOp(graphPtr, interp, argc, argv)
4235 Graph *graphPtr;
4236 Tcl_Interp *interp;
4237 int argc;
4238 char **argv;
4239{
4240 Marker *markerPtr;
4241
4242 if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) {
4243 return TCL_ERROR;
4244 }
4245 if (Tk_ConfigureValue(interp, graphPtr->tkwin,
4246 markerPtr->classPtr->configSpecs, (char *)markerPtr, argv[4], 0)
4247 != TCL_OK) {
4248 return TCL_ERROR;
4249 }
4250 return TCL_OK;
4251}
4252
4253/*
4254 * ----------------------------------------------------------------------
4255 *
4256 * ConfigureOp --
4257 *
4258 * Results:
4259 * The return value is a standard Tcl result.
4260 *
4261 * Side Effects:
4262 *
4263 * ----------------------------------------------------------------------
4264 */
4265static int
4266ConfigureOp(graphPtr, interp, argc, argv)
4267 Graph *graphPtr;
4268 Tcl_Interp *interp;
4269 int argc;
4270 char **argv;
4271{
4272 Marker *markerPtr;
4273 int flags = TK_CONFIG_ARGV_ONLY;
4274 char *oldName;
4275 int nNames, nOpts;
4276 char **options;
4277 register int i;
4278 int under;
4279
4280 /* Figure out where the option value pairs begin */
4281 argc -= 3;
4282 argv += 3;
4283 for (i = 0; i < argc; i++) {
4284 if (argv[i][0] == '-') {
4285 break;
4286 }
4287 if (NameToMarker(graphPtr, argv[i], &markerPtr) != TCL_OK) {
4288 return TCL_ERROR;
4289 }
4290 }
4291 nNames = i; /* Number of element names specified */
4292 nOpts = argc - i; /* Number of options specified */
4293 options = argv + nNames; /* Start of options in argv */
4294
4295 for (i = 0; i < nNames; i++) {
4296 NameToMarker(graphPtr, argv[i], &markerPtr);
4297 if (nOpts == 0) {
4298 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
4299 markerPtr->classPtr->configSpecs, (char *)markerPtr,
4300 (char *)NULL, flags);
4301 } else if (nOpts == 1) {
4302 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
4303 markerPtr->classPtr->configSpecs, (char *)markerPtr,
4304 options[0], flags);
4305 }
4306 /* Save the old marker. */
4307 oldName = markerPtr->name;
4308 under = markerPtr->drawUnder;
4309 if (Tk_ConfigureWidget(interp, graphPtr->tkwin,
4310 markerPtr->classPtr->configSpecs, nOpts, options,
4311 (char *)markerPtr, flags) != TCL_OK) {
4312 return TCL_ERROR;
4313 }
4314 if (oldName != markerPtr->name) {
4315 if (RenameMarker(graphPtr, markerPtr, oldName, markerPtr->name)
4316 != TCL_OK) {
4317 markerPtr->name = oldName;
4318 return TCL_ERROR;
4319 }
4320 }
4321 if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) {
4322 return TCL_ERROR;
4323 }
4324 if (markerPtr->drawUnder != under) {
4325 graphPtr->flags |= REDRAW_BACKING_STORE;
4326 }
4327 }
4328 return TCL_OK;
4329}
4330
4331/*
4332 * ----------------------------------------------------------------------
4333 *
4334 * CreateOp --
4335 *
4336 * This procedure creates and initializes a new marker.
4337 *
4338 * Results:
4339 * The return value is a pointer to a structure describing
4340 * the new element. If an error occurred, then the return
4341 * value is NULL and an error message is left in interp->result.
4342 *
4343 * Side effects:
4344 * Memory is allocated, etc.
4345 *
4346 * ----------------------------------------------------------------------
4347 */
4348static int
4349CreateOp(graphPtr, interp, argc, argv)
4350 Graph *graphPtr;
4351 Tcl_Interp *interp;
4352 int argc;
4353 char **argv;
4354{
4355 Marker *markerPtr;
4356 Blt_HashEntry *hPtr;
4357 int isNew;
4358 Blt_Uid classUid;
4359 register int i;
4360 char *name;
4361 char string[200];
4362 unsigned int length;
4363 char c;
4364 register Tk_ConfigSpec *specPtr;
4365
4366 c = argv[3][0];
4367 /* Create the new marker based upon the given type */
4368 if ((c == 't') && (strcmp(argv[3], "text") == 0)) {
4369 classUid = bltTextMarkerUid;
4370 } else if ((c == 'l') && (strcmp(argv[3], "line") == 0)) {
4371 classUid = bltLineMarkerUid;
4372 } else if ((c == 'p') && (strcmp(argv[3], "polygon") == 0)) {
4373 classUid = bltPolygonMarkerUid;
4374 } else if ((c == 'i') && (strcmp(argv[3], "image") == 0)) {
4375 classUid = bltImageMarkerUid;
4376 } else if ((c == 'b') && (strcmp(argv[3], "bitmap") == 0)) {
4377 classUid = bltBitmapMarkerUid;
4378 } else if ((c == 'w') && (strcmp(argv[3], "window") == 0)) {
4379 classUid = bltWindowMarkerUid;
4380 } else {
4381 Tcl_AppendResult(interp, "unknown marker type \"", argv[3],
4382 "\": should be \"text\", \"line\", \"polygon\", \"bitmap\", \"image\", or \
4383\"window\"", (char *)NULL);
4384 return TCL_ERROR;
4385 }
4386 /* Scan for "-name" option. We need it for the component name */
4387 name = NULL;
4388 for (i = 4; i < argc; i += 2) {
4389 length = strlen(argv[i]);
4390 if ((length > 1) && (strncmp(argv[i], "-name", length) == 0)) {
4391 name = argv[i + 1];
4392 break;
4393 }
4394 }
4395 /* If no name was given for the marker, make up one. */
4396 if (name == NULL) {
4397 sprintf(string, "marker%d", graphPtr->nextMarkerId++);
4398 name = string;
4399 } else if (name[0] == '-') {
4400 Tcl_AppendResult(interp, "name of marker \"", name,
4401 "\" can't start with a '-'", (char *)NULL);
4402 return TCL_ERROR;
4403 }
4404 markerPtr = CreateMarker(graphPtr, name, classUid);
4405 if (Blt_ConfigureWidgetComponent(interp, graphPtr->tkwin, name,
4406 markerPtr->classUid, markerPtr->classPtr->configSpecs,
4407 argc - 4, argv + 4, (char *)markerPtr, 0) != TCL_OK) {
4408 DestroyMarker(markerPtr);
4409 return TCL_ERROR;
4410 }
4411
4412 for (argc -= 4, argv += 4 ; argc > 0; argc -= 2, argv += 2)
4413 for (specPtr = markerPtr->classPtr->configSpecs; specPtr->type != TK_CONFIG_END; specPtr++)
4414 if ((Tcl_StringMatch(specPtr->argvName, *argv)))
4415 specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
4416
4417 if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) {
4418 DestroyMarker(markerPtr);
4419 return TCL_ERROR;
4420 }
4421 hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, name, &isNew);
4422 if (!isNew) {
4423 Marker *oldMarkerPtr;
4424 /*
4425 * Marker by the same name already exists. Delete the old
4426 * marker and it's list entry. But save the hash entry.
4427 */
4428 oldMarkerPtr = (Marker *)Blt_GetHashValue(hPtr);
4429 oldMarkerPtr->hashPtr = NULL;
4430 DestroyMarker(oldMarkerPtr);
4431 }
4432 Blt_SetHashValue(hPtr, markerPtr);
4433 markerPtr->hashPtr = hPtr;
4434 markerPtr->linkPtr =
4435 Blt_ChainAppend(graphPtr->markers.displayList, markerPtr);
4436 if (markerPtr->drawUnder) {
4437 graphPtr->flags |= REDRAW_BACKING_STORE;
4438 }
4439 Blt_EventuallyRedrawGraph(graphPtr);
4440 Tcl_SetResult(interp, name, TCL_VOLATILE);
4441 return TCL_OK;
4442}
4443
4444/*
4445 * ----------------------------------------------------------------------
4446 *
4447 * DeleteOp --
4448 *
4449 * Deletes the marker given by markerId.
4450 *
4451 * Results:
4452 * The return value is a standard Tcl result.
4453 *
4454 * Side Effects:
4455 * Graph will be redrawn to reflect the new display list.
4456 *
4457 * ----------------------------------------------------------------------
4458 */
4459/*ARGSUSED*/
4460static int
4461DeleteOp(graphPtr, interp, argc, argv)
4462 Graph *graphPtr;
4463 Tcl_Interp *interp; /* Not used. */
4464 int argc;
4465 char **argv;
4466{
4467 Marker *markerPtr;
4468 register int i;
4469
4470 for (i = 3; i < argc; i++) {
4471 if (NameToMarker(graphPtr, argv[i], &markerPtr) == TCL_OK) {
4472 DestroyMarker(markerPtr);
4473 }
4474 }
4475 Tcl_ResetResult(interp);
4476 Blt_EventuallyRedrawGraph(graphPtr);
4477 return TCL_OK;
4478}
4479
4480/*
4481 *----------------------------------------------------------------------
4482 *
4483 * GetOp --
4484 *
4485 * Find the legend entry from the given argument. The argument
4486 * can be either a screen position "@x,y" or the name of an
4487 * element.
4488 *
4489 * I don't know how useful it is to test with the name of an
4490 * element.
4491 *
4492 * Results:
4493 * A standard Tcl result.
4494 *
4495 * Side Effects:
4496 * Graph will be redrawn to reflect the new legend attributes.
4497 *
4498 *----------------------------------------------------------------------
4499 */
4500/*ARGSUSED*/
4501static int
4502GetOp(graphPtr, interp, argc, argv)
4503 Graph *graphPtr;
4504 Tcl_Interp *interp;
4505 int argc; /* Not used. */
4506 char *argv[];
4507{
4508 register Marker *markerPtr;
4509
4510 if ((argv[3][0] == 'c') && (strcmp(argv[3], "current") == 0)) {
4511 markerPtr = (Marker *)Blt_GetCurrentItem(graphPtr->bindTable);
4512 /* Report only on markers. */
4513 if (markerPtr == NULL) {
4514 return TCL_OK;
4515 }
4516 if ((markerPtr->classUid == bltBitmapMarkerUid) ||
4517 (markerPtr->classUid == bltLineMarkerUid) ||
4518 (markerPtr->classUid == bltWindowMarkerUid) ||
4519 (markerPtr->classUid == bltPolygonMarkerUid) ||
4520 (markerPtr->classUid == bltTextMarkerUid) ||
4521 (markerPtr->classUid == bltImageMarkerUid)) {
4522 Tcl_SetResult(interp, markerPtr->name, TCL_VOLATILE);
4523 }
4524 }
4525 return TCL_OK;
4526}
4527
4528/*
4529 * ----------------------------------------------------------------------
4530 *
4531 * RelinkOp --
4532 *
4533 * Reorders the marker (given by the first name) before/after
4534 * the another marker (given by the second name) in the
4535 * marker display list. If no second name is given, the
4536 * marker is placed at the beginning/end of the list.
4537 *
4538 * Results:
4539 * A standard Tcl result.
4540 *
4541 * Side Effects:
4542 * Graph will be redrawn to reflect the new display list.
4543 *
4544 * ----------------------------------------------------------------------
4545 */
4546/*ARGSUSED*/
4547static int
4548RelinkOp(graphPtr, interp, argc, argv)
4549 Graph *graphPtr;
4550 Tcl_Interp *interp; /* Not used. */
4551 int argc;
4552 char **argv;
4553{
4554 Blt_ChainLink *linkPtr, *placePtr;
4555 Marker *markerPtr;
4556
4557 /* Find the marker to be raised or lowered. */
4558 if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) {
4559 return TCL_ERROR;
4560 }
4561 /* Right now it's assumed that all markers are always in the
4562 display list. */
4563 linkPtr = markerPtr->linkPtr;
4564 Blt_ChainUnlinkLink(graphPtr->markers.displayList, markerPtr->linkPtr);
4565
4566 placePtr = NULL;
4567 if (argc == 5) {
4568 if (NameToMarker(graphPtr, argv[4], &markerPtr) != TCL_OK) {
4569 return TCL_ERROR;
4570 }
4571 placePtr = markerPtr->linkPtr;
4572 }
4573
4574 /* Link the marker at its new position. */
4575 if (argv[2][0] == 'a') {
4576 Blt_ChainLinkAfter(graphPtr->markers.displayList, linkPtr, placePtr);
4577 } else {
4578 Blt_ChainLinkBefore(graphPtr->markers.displayList, linkPtr, placePtr);
4579 }
4580 if (markerPtr->drawUnder) {
4581 graphPtr->flags |= REDRAW_BACKING_STORE;
4582 }
4583 Blt_EventuallyRedrawGraph(graphPtr);
4584 return TCL_OK;
4585}
4586
4587
4588/*
4589 * ----------------------------------------------------------------------
4590 *
4591 * FindOp --
4592 *
4593 * Returns if marker by a given ID currently exists.
4594 *
4595 * Results:
4596 * A standard Tcl result.
4597 *
4598 * ----------------------------------------------------------------------
4599 */
4600/*ARGSUSED*/
4601static int
4602FindOp(graphPtr, interp, argc, argv)
4603 Graph *graphPtr;
4604 Tcl_Interp *interp;
4605 int argc;
4606 char **argv;
4607{
4608 Blt_ChainLink *linkPtr;
4609 Extents2D exts;
4610 Marker *markerPtr;
4611 int mode;
4612 int left, right, top, bottom;
4613 int enclosed;
4614
4615#define FIND_ENCLOSED (1<<0)
4616#define FIND_OVERLAPPING (1<<1)
4617 if (strcmp(argv[3], "enclosed") == 0) {
4618 mode = FIND_ENCLOSED;
4619 } else if (strcmp(argv[3], "overlapping") == 0) {
4620 mode = FIND_OVERLAPPING;
4621 } else {
4622 Tcl_AppendResult(interp, "bad search type \"", argv[3],
4623 ": should be \"enclosed\", or \"overlapping\"", (char *)NULL);
4624 return TCL_ERROR;
4625 }
4626
4627 if ((Tcl_GetInt(interp, argv[4], &left) != TCL_OK) ||
4628 (Tcl_GetInt(interp, argv[5], &top) != TCL_OK) ||
4629 (Tcl_GetInt(interp, argv[6], &right) != TCL_OK) ||
4630 (Tcl_GetInt(interp, argv[7], &bottom) != TCL_OK)) {
4631 return TCL_ERROR;
4632 }
4633 if (left < right) {
4634 exts.left = (double)left;
4635 exts.right = (double)right;
4636 } else {
4637 exts.left = (double)right;
4638 exts.right = (double)left;
4639 }
4640 if (top < bottom) {
4641 exts.top = (double)top;
4642 exts.bottom = (double)bottom;
4643 } else {
4644 exts.top = (double)bottom;
4645 exts.bottom = (double)top;
4646 }
4647 enclosed = (mode == FIND_ENCLOSED);
4648 for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList);
4649 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4650 markerPtr = Blt_ChainGetValue(linkPtr);
4651 if (markerPtr->hidden) {
4652 continue;
4653 }
4654 if (markerPtr->elemName != NULL) {
4655 Blt_HashEntry *hPtr;
4656
4657 hPtr = Blt_FindHashEntry(&graphPtr->elements.table,
4658 markerPtr->elemName);
4659 if (hPtr != NULL) {
4660 Element *elemPtr;
4661
4662 elemPtr = (Element *)Blt_GetHashValue(hPtr);
4663 if (elemPtr->hidden) {
4664 continue;
4665 }
4666 }
4667 }
4668 if ((*markerPtr->classPtr->regionProc)(markerPtr, &exts, enclosed)) {
4669 Tcl_SetResult(interp, markerPtr->name, TCL_VOLATILE);
4670 return TCL_OK;
4671 }
4672 }
4673 Tcl_SetResult(interp, "", TCL_VOLATILE);
4674 return TCL_OK;
4675}
4676
4677/*
4678 * ----------------------------------------------------------------------
4679 *
4680 * ExistsOp --
4681 *
4682 * Returns if marker by a given ID currently exists.
4683 *
4684 * Results:
4685 * A standard Tcl result.
4686 *
4687 * ----------------------------------------------------------------------
4688 */
4689/*ARGSUSED*/
4690static int
4691ExistsOp(graphPtr, interp, argc, argv)
4692 Graph *graphPtr;
4693 Tcl_Interp *interp;
4694 int argc;
4695 char **argv;
4696{
4697 Blt_HashEntry *hPtr;
4698
4699 hPtr = Blt_FindHashEntry(&graphPtr->markers.table, argv[3]);
4700 Blt_SetBooleanResult(interp, (hPtr != NULL));
4701 return TCL_OK;
4702}
4703
4704/*
4705 * ----------------------------------------------------------------------
4706 *
4707 * TypeOp --
4708 *
4709 * Returns a symbolic name for the type of the marker whose ID is
4710 * given.
4711 *
4712 * Results:
4713 * A standard Tcl result. interp->result will contain the symbolic
4714 * type of the marker.
4715 *
4716 * ----------------------------------------------------------------------
4717 */
4718/*ARGSUSED*/
4719static int
4720TypeOp(graphPtr, interp, argc, argv)
4721 Graph *graphPtr;
4722 Tcl_Interp *interp;
4723 int argc;
4724 char **argv;
4725{
4726 Marker *markerPtr;
4727
4728 if (NameToMarker(graphPtr, argv[3], &markerPtr) != TCL_OK) {
4729 return TCL_ERROR;
4730 }
4731 Tcl_SetResult(interp, markerPtr->classUid, TCL_STATIC);
4732 return TCL_OK;
4733}
4734
4735/* Public routines */
4736
4737/*
4738 * ----------------------------------------------------------------------
4739 *
4740 * Blt_MarkerOp --
4741 *
4742 * This procedure is invoked to process the Tcl command
4743 * that corresponds to a widget managed by this module.
4744 * See the user documentation for details on what it does.
4745 *
4746 * Results:
4747 * A standard Tcl result.
4748 *
4749 * Side effects:
4750 * See the user documentation.
4751 *
4752 * ----------------------------------------------------------------------
4753 */
4754
4755static Blt_OpSpec markerOps[] =
4756{
4757 {"after", 1, (Blt_Op)RelinkOp, 4, 5, "marker ?afterMarker?",},
4758 {"before", 2, (Blt_Op)RelinkOp, 4, 5, "marker ?beforeMarker?",},
4759 {"bind", 2, (Blt_Op)BindOp, 3, 6, "marker sequence command",},
4760 {"cget", 2, (Blt_Op)CgetOp, 5, 5, "marker option",},
4761 {"configure", 2, (Blt_Op)ConfigureOp, 4, 0,
4762 "marker ?marker?... ?option value?...",},
4763 {"create", 2, (Blt_Op)CreateOp, 4, 0,
4764 "type ?option value?...",},
4765 {"delete", 1, (Blt_Op)DeleteOp, 3, 0, "?marker?...",},
4766 {"exists", 1, (Blt_Op)ExistsOp, 4, 4, "marker",},
4767 {"find", 1, (Blt_Op)FindOp, 8, 8, "enclosed|overlapping x1 y1 x2 y2",},
4768 {"get", 1, (Blt_Op)GetOp, 4, 4, "name",},
4769 {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",},
4770 {"type", 1, (Blt_Op)TypeOp, 4, 4, "marker",},
4771};
4772static int nMarkerOps = sizeof(markerOps) / sizeof(Blt_OpSpec);
4773
4774/*ARGSUSED*/
4775int
4776Blt_MarkerOp(graphPtr, interp, argc, argv)
4777 Graph *graphPtr;
4778 Tcl_Interp *interp; /* Not used. */
4779 int argc;
4780 char **argv;
4781{
4782 Blt_Op proc;
4783 int result;
4784
4785 proc = Blt_GetOp(interp, nMarkerOps, markerOps, BLT_OP_ARG2, argc, argv,0);
4786 if (proc == NULL) {
4787 return TCL_ERROR;
4788 }
4789 result = (*proc) (graphPtr, interp, argc, argv);
4790 return result;
4791}
4792
4793/*
4794 * -------------------------------------------------------------------------
4795 *
4796 * Blt_MarkersToPostScript --
4797 *
4798 * -------------------------------------------------------------------------
4799 */
4800void
4801Blt_MarkersToPostScript(graphPtr, psToken, under)
4802 Graph *graphPtr;
4803 PsToken psToken;
4804 int under;
4805{
4806 Blt_ChainLink *linkPtr;
4807 register Marker *markerPtr;
4808
4809 for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList);
4810 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4811 markerPtr = Blt_ChainGetValue(linkPtr);
4812 if ((markerPtr->classPtr->postscriptProc == NULL) ||
4813 (markerPtr->nWorldPts == 0)) {
4814 continue;
4815 }
4816 if (markerPtr->drawUnder != under) {
4817 continue;
4818 }
4819 if (markerPtr->hidden) {
4820 continue;
4821 }
4822 if (markerPtr->elemName != NULL) {
4823 Blt_HashEntry *hPtr;
4824
4825 hPtr = Blt_FindHashEntry(&graphPtr->elements.table,
4826 markerPtr->elemName);
4827 if (hPtr != NULL) {
4828 Element *elemPtr;
4829
4830 elemPtr = (Element *)Blt_GetHashValue(hPtr);
4831 if (elemPtr->hidden) {
4832 continue;
4833 }
4834 }
4835 }
4836 Blt_AppendToPostScript(psToken, "\n% Marker \"", markerPtr->name,
4837 "\" is a ", markerPtr->classUid, " marker\n", (char *)NULL);
4838 (*markerPtr->classPtr->postscriptProc) (markerPtr, psToken);
4839 }
4840}
4841
4842/*
4843 * -------------------------------------------------------------------------
4844 *
4845 * Blt_DrawMarkers --
4846 *
4847 * Calls the individual drawing routines (based on marker type)
4848 * for each marker in the display list.
4849 *
4850 * A marker will not be drawn if
4851 *
4852 * 1) An element linked to the marker (indicated by elemName)
4853 * is currently hidden.
4854 *
4855 * 2) No coordinates have been specified for the marker.
4856 *
4857 * 3) The marker is requesting to be drawn at a different level
4858 * (above/below the elements) from the current mode.
4859 *
4860 * 4) The marker is configured as hidden (-hide option).
4861 *
4862 * 5) The marker isn't visible in the current viewport
4863 * (i.e. clipped).
4864 *
4865 * Results:
4866 * None
4867 *
4868 * Side Effects:
4869 * Markers are drawn into the drawable (pixmap) which will eventually
4870 * be displayed in the graph window.
4871 *
4872 * -------------------------------------------------------------------------
4873 */
4874void
4875Blt_DrawMarkers(graphPtr, drawable, under)
4876 Graph *graphPtr;
4877 Drawable drawable; /* Pixmap or window to draw into */
4878 int under;
4879{
4880 Blt_ChainLink *linkPtr;
4881 Marker *markerPtr;
4882
4883 for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList);
4884 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4885 markerPtr = Blt_ChainGetValue(linkPtr);
4886
4887 if ((markerPtr->nWorldPts == 0) ||
4888 (markerPtr->drawUnder != under) ||
4889 (markerPtr->hidden) ||
4890 (markerPtr->clipped)) {
4891 continue;
4892 }
4893 if (markerPtr->elemName != NULL) {
4894 Blt_HashEntry *hPtr;
4895
4896 /* Look up the named element and see if it's hidden */
4897 hPtr = Blt_FindHashEntry(&graphPtr->elements.table,
4898 markerPtr->elemName);
4899 if (hPtr != NULL) {
4900 Element *elemPtr;
4901
4902 elemPtr = (Element *)Blt_GetHashValue(hPtr);
4903 if (elemPtr->hidden) {
4904 continue;
4905 }
4906 }
4907 }
4908
4909 (*markerPtr->classPtr->drawProc) (markerPtr, drawable);
4910 }
4911}
4912
4913void
4914Blt_MapMarkers(graphPtr)
4915 Graph *graphPtr;
4916{
4917 Blt_ChainLink *linkPtr;
4918 Marker *markerPtr;
4919
4920 for (linkPtr = Blt_ChainFirstLink(graphPtr->markers.displayList);
4921 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4922 markerPtr = Blt_ChainGetValue(linkPtr);
4923 if ((markerPtr->nWorldPts == 0) || (markerPtr->hidden)) {
4924 continue;
4925 }
4926 if ((graphPtr->flags & MAP_ALL) || (markerPtr->flags & MAP_ITEM)) {
4927 (*markerPtr->classPtr->mapProc) (markerPtr);
4928 markerPtr->flags &= ~MAP_ITEM;
4929 }
4930 }
4931}
4932
4933
4934void
4935Blt_DestroyMarkers(graphPtr)
4936 Graph *graphPtr;
4937{
4938 Blt_HashEntry *hPtr;
4939 Blt_HashSearch cursor;
4940 Marker *markerPtr;
4941
4942 for (hPtr = Blt_FirstHashEntry(&graphPtr->markers.table, &cursor);
4943 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
4944 markerPtr = (Marker *)Blt_GetHashValue(hPtr);
4945 /*
4946 * Dereferencing the pointer to the hash table prevents the
4947 * hash table entry from being automatically deleted.
4948 */
4949 markerPtr->hashPtr = NULL;
4950 DestroyMarker(markerPtr);
4951 }
4952 Blt_DeleteHashTable(&graphPtr->markers.table);
4953 Blt_DeleteHashTable(&graphPtr->markers.tagTable);
4954 Blt_ChainDestroy(graphPtr->markers.displayList);
4955}
4956
4957Marker *
4958Blt_NearestMarker(graphPtr, x, y, under)
4959 Graph *graphPtr;
4960 int x, y; /* Screen coordinates */
4961 int under;
4962{
4963 Blt_ChainLink *linkPtr;
4964 Marker *markerPtr;
4965 Point2D point;
4966
4967 point.x = (double)x;
4968 point.y = (double)y;
4969 for (linkPtr = Blt_ChainLastLink(graphPtr->markers.displayList);
4970 linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) {
4971 markerPtr = Blt_ChainGetValue(linkPtr);
4972 /*
4973 * Don't consider markers that are pending to be mapped. Even
4974 * if the marker has already been mapped, the coordinates
4975 * could be invalid now. Better to pick no marker than the
4976 * wrong marker.
4977 */
4978 if ((markerPtr->drawUnder == under) && (markerPtr->nWorldPts > 0) &&
4979 ((markerPtr->flags & MAP_ITEM) == 0) &&
4980 (!markerPtr->hidden) && (markerPtr->state == STATE_NORMAL)) {
4981 if ((*markerPtr->classPtr->pointProc) (markerPtr, &point)) {
4982 return markerPtr;
4983 }
4984 }
4985 }
4986 return NULL;
4987}
Note: See TracBrowser for help on using the repository browser.