summaryrefslogtreecommitdiffstats
path: root/src/bltGrMarker.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/bltGrMarker.C')
-rw-r--r--src/bltGrMarker.C5196
1 files changed, 5196 insertions, 0 deletions
diff --git a/src/bltGrMarker.C b/src/bltGrMarker.C
new file mode 100644
index 0000000..c9546f6
--- /dev/null
+++ b/src/bltGrMarker.C
@@ -0,0 +1,5196 @@
+
+/*
+ * bltGrMarker.c --
+ *
+ * This module implements markers for the BLT graph widget.
+ *
+ * Copyright 1993-2004 George A Howlett.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "bltGraph.h"
+#include "bltOp.h"
+#include "bltImage.h"
+#include "bltPicture.h"
+#include "bltPainter.h"
+#include "bltChain.h"
+#include "bltGrElem.h"
+#include "bltBitmap.h"
+
+typedef int (GraphMarkerProc)(Graph *graphPtr, Tcl_Interp *interp, int objc,
+ Tcl_Obj *const *objv);
+
+#define GETBITMAP(b) \
+ (((b)->destBitmap == None) ? (b)->srcBitmap : (b)->destBitmap)
+
+#define MAX_OUTLINE_POINTS 12
+
+#define IMAGE_PHOTO (1<<7)
+
+/* Map graph coordinates to normalized coordinates [0..1] */
+#define NORMALIZE(A,x) (((x) - (A)->axisRange.min) * (A)->axisRange.scale)
+
+#define DEF_MARKER_ANCHOR "center"
+#define DEF_MARKER_BACKGROUND RGB_WHITE
+#define DEF_MARKER_BITMAP (char *)NULL
+#define DEF_MARKER_CAP_STYLE "butt"
+#define DEF_MARKER_COORDS (char *)NULL
+#define DEF_MARKER_DASHES (char *)NULL
+#define DEF_MARKER_DASH_OFFSET "0"
+#define DEF_MARKER_ELEMENT (char *)NULL
+#define DEF_MARKER_FOREGROUND RGB_BLACK
+#define DEF_MARKER_FILL_COLOR RGB_RED
+#define DEF_MARKER_FONT STD_FONT
+#define DEF_MARKER_GAP_COLOR RGB_PINK
+#define DEF_MARKER_HEIGHT "0"
+#define DEF_MARKER_HIDE "no"
+#define DEF_MARKER_JOIN_STYLE "miter"
+#define DEF_MARKER_JUSTIFY "left"
+#define DEF_MARKER_LINE_WIDTH "1"
+#define DEF_MARKER_MAP_X "x"
+#define DEF_MARKER_MAP_Y "y"
+#define DEF_MARKER_NAME (char *)NULL
+#define DEF_MARKER_OUTLINE_COLOR RGB_BLACK
+#define DEF_MARKER_PAD "4"
+#define DEF_MARKER_ANGLE "0.0"
+#define DEF_MARKER_SCALE "1.0"
+#define DEF_MARKER_STATE "normal"
+#define DEF_MARKER_STIPPLE (char *)NULL
+#define DEF_MARKER_TEXT (char *)NULL
+#define DEF_MARKER_UNDER "no"
+#define DEF_MARKER_WIDTH "0"
+#define DEF_MARKER_WINDOW (char *)NULL
+#define DEF_MARKER_XOR "no"
+#define DEF_MARKER_X_OFFSET "0"
+#define DEF_MARKER_Y_OFFSET "0"
+#define DEF_MARKER_FILTER "box"
+
+#define DEF_TEXT_TAGS "Text all"
+#define DEF_IMAGE_TAGS "Image all"
+#define DEF_BITMAP_TAGS "Bitmap all"
+#define DEF_WINDOW_TAGS "Window all"
+#define DEF_POLYGON_TAGS "Polygon all"
+#define DEF_LINE_TAGS "Line all"
+
+static Blt_OptionParseProc ObjToCoordsProc;
+static Blt_OptionPrintProc CoordsToObjProc;
+static Blt_OptionFreeProc FreeCoordsProc;
+static Blt_CustomOption coordsOption =
+{
+ ObjToCoordsProc, CoordsToObjProc, FreeCoordsProc, (ClientData)0
+};
+static Blt_OptionFreeProc FreeColorPairProc;
+static Blt_OptionParseProc ObjToColorPairProc;
+static Blt_OptionPrintProc ColorPairToObjProc;
+static Blt_CustomOption colorPairOption =
+{
+ ObjToColorPairProc, ColorPairToObjProc, FreeColorPairProc, (ClientData)0
+};
+
+static Blt_OptionParseProc ObjToPictImageProc;
+static Blt_OptionPrintProc PictImageToObjProc;
+static Blt_OptionFreeProc FreePictImageProc;
+static Blt_CustomOption pictImageOption =
+{
+ ObjToPictImageProc, PictImageToObjProc, FreePictImageProc, (ClientData)0
+};
+
+BLT_EXTERN Blt_CustomOption bltXAxisOption;
+BLT_EXTERN Blt_CustomOption bltYAxisOption;
+BLT_EXTERN Blt_CustomOption bltFilterOption;
+
+typedef Marker *(MarkerCreateProc)(void);
+typedef void (MarkerDrawProc)(Marker *markerPtr, Drawable drawable);
+typedef void (MarkerFreeProc)(Marker *markerPtr);
+typedef int (MarkerConfigProc)(Marker *markerPtr);
+typedef void (MarkerMapProc)(Marker *markerPtr);
+typedef void (MarkerPostscriptProc)(Marker *markerPtr, Blt_Ps ps);
+typedef int (MarkerPointProc)(Marker *markerPtr, Point2d *samplePtr);
+typedef int (MarkerRegionProc)(Marker *markerPtr, Region2d *extsPtr,
+ int enclosed);
+
+static Tcl_FreeProc FreeMarker;
+
+typedef struct {
+ Blt_ConfigSpec *configSpecs; /* Marker configuration
+ * specifications */
+ MarkerConfigProc *configProc;
+ MarkerDrawProc *drawProc;
+ MarkerFreeProc *freeProc;
+ MarkerMapProc *mapProc;
+ MarkerPointProc *pointProc;
+ MarkerRegionProc *regionProc;
+ MarkerPostscriptProc *postscriptProc;
+
+} MarkerClass;
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Marker --
+ *
+ * Structure defining the generic marker. In C++ parlance this would be
+ * the base class from which all markers are derived.
+ *
+ * This structure corresponds with the specific types of markers. Don't
+ * change this structure without changing the individual marker
+ * structures of each type below.
+ *
+ * --------------------------------------------------------------------------
+ */
+struct _Marker {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+ Point2d *worldPts; /* Coordinate array to position
+ * marker */
+ int nWorldPts; /* Number of points in above array */
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+};
+/*
+ *---------------------------------------------------------------------------
+ *
+ * BitmapMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+
+ Point2d *worldPts; /* Coordinate array to position
+ * marker. */
+ int nWorldPts; /* # of points in above array. */
+
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+
+ /* Fields specific to bitmap markers. */
+
+ Pixmap srcBitmap; /* Original bitmap. May be further
+ * scaled or rotated. */
+ float reqAngle; /* Requested rotation of the bitmap */
+ float angle; /* Normalized rotation (0..360
+ * degrees) */
+ Tk_Anchor anchor; /* If only one X-Y coordinate is given,
+ * indicates how to translate the given
+ * marker position. Otherwise, if there
+ * are two X-Y coordinates, then this
+ * value is ignored. */
+ Point2d anchorPt; /* Translated anchor point. */
+
+ XColor *outlineColor; /* Foreground color */
+ XColor *fillColor; /* Background color */
+
+ GC gc; /* Private graphic context */
+ GC fillGC; /* Shared graphic context */
+ Pixmap destBitmap; /* Bitmap to be drawn. */
+ int destWidth, destHeight; /* Dimensions of the final bitmap */
+
+ Point2d outline[MAX_OUTLINE_POINTS];/* Polygon representing the background
+ * of the bitmap. */
+ int nOutlinePts;
+} BitmapMarker;
+
+static Blt_ConfigSpec bitmapConfigSpecs[] =
+{
+ {BLT_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR,
+ Blt_Offset(BitmapMarker, anchor), 0},
+ {BLT_CONFIG_COLOR, "-background", "background", "Background",
+ DEF_MARKER_BACKGROUND, Blt_Offset(BitmapMarker, fillColor),
+ BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_BITMAP_TAGS,
+ Blt_Offset(BitmapMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", DEF_MARKER_BITMAP,
+ Blt_Offset(BitmapMarker, srcBitmap), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(BitmapMarker, worldPts), BLT_CONFIG_NULL_OK,
+ &coordsOption},
+ {BLT_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT,
+ Blt_Offset(BitmapMarker, elemName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0},
+ {BLT_CONFIG_SYNONYM, "-fill", "background", (char *)NULL, (char *)NULL,
+ 0, 0},
+ {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_MARKER_FOREGROUND, Blt_Offset(BitmapMarker, outlineColor),
+ BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(BitmapMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(BitmapMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(BitmapMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(BitmapMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL, (char *)NULL,
+ 0, 0},
+ {BLT_CONFIG_FLOAT, "-rotate", "rotate", "Rotate", DEF_MARKER_ANGLE,
+ Blt_Offset(BitmapMarker, reqAngle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(BitmapMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(BitmapMarker, drawUnder), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(BitmapMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(BitmapMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigureBitmapProc;
+static MarkerCreateProc CreateBitmapProc;
+static MarkerDrawProc DrawBitmapProc;
+static MarkerFreeProc FreeBitmapProc;
+static MarkerMapProc MapBitmapProc;
+static MarkerPointProc PointInBitmapProc;
+static MarkerPostscriptProc BitmapToPostscriptProc;
+static MarkerRegionProc RegionInBitmapProc;
+
+static MarkerClass bitmapMarkerClass = {
+ bitmapConfigSpecs,
+ ConfigureBitmapProc,
+ DrawBitmapProc,
+ FreeBitmapProc,
+ MapBitmapProc,
+ PointInBitmapProc,
+ RegionInBitmapProc,
+ BitmapToPostscriptProc,
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ImageMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+
+ Point2d *worldPts; /* Coordinate array to position
+ * marker. */
+
+ int nWorldPts; /* # of points in above array. */
+
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+
+ Tk_Image tkImage; /* Tk image to be displayed. */
+ Tk_Anchor anchor; /* Indicates how to translate the given
+ * marker position. */
+ Point2d anchorPt; /* Translated anchor point. */
+ int width, height; /* Dimensions of the possibly scaled
+ * image. */
+ Blt_Painter painter;
+ Blt_Picture picture;
+ Blt_ResampleFilter filter;
+ int pictX, pictY; /* */
+ Blt_Picture scaled; /* Pixmap containing the scaled image */
+ GC gc;
+
+} ImageMarker;
+
+static Blt_ConfigSpec imageConfigSpecs[] =
+{
+ {BLT_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR,
+ Blt_Offset(ImageMarker, anchor), 0},
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_IMAGE_TAGS,
+ Blt_Offset(ImageMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(ImageMarker, worldPts), BLT_CONFIG_NULL_OK, &coordsOption},
+ {BLT_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT,
+ Blt_Offset(ImageMarker, elemName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(ImageMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-image", "image", "Image", (char *)NULL,
+ Blt_Offset(ImageMarker, picture), BLT_CONFIG_NULL_OK, &pictImageOption},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(ImageMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(ImageMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(ImageMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-resamplefilter", "resampleFilter", "ResampleFilter",
+ DEF_MARKER_FILTER, Blt_Offset(ImageMarker, filter),
+ BLT_CONFIG_NULL_OK | BLT_CONFIG_DONT_SET_DEFAULT, &bltFilterOption},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(ImageMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(ImageMarker, drawUnder), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(ImageMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(ImageMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigureImageProc;
+static MarkerCreateProc CreateImageProc;
+static MarkerDrawProc DrawImageProc;
+static MarkerFreeProc FreeImageProc;
+static MarkerMapProc MapImageProc;
+static MarkerPointProc PointInImageProc;
+static MarkerPostscriptProc ImageToPostscriptProc;
+static MarkerRegionProc RegionInImageProc;
+
+static MarkerClass imageMarkerClass = {
+ imageConfigSpecs,
+ ConfigureImageProc,
+ DrawImageProc,
+ FreeImageProc,
+ MapImageProc,
+ PointInImageProc,
+ RegionInImageProc,
+ ImageToPostscriptProc,
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * LineMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+
+ Point2d *worldPts; /* Coordinate array to position
+ * marker. */
+
+ int nWorldPts; /* Number of points in above array */
+
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+
+ XColor *fillColor;
+ XColor *outlineColor; /* Foreground and background colors */
+
+ int lineWidth; /* Line width. */
+ int capStyle; /* Cap style. */
+ int joinStyle; /* Join style.*/
+ Blt_Dashes dashes; /* Dash list values (max 11) */
+
+ GC gc; /* Private graphic context */
+
+ Segment2d *segments; /* Malloc'ed array of points.
+ * Represents individual line segments
+ * (2 points per segment) comprising the
+ * mapped line. The segments may not
+ * necessarily be connected after
+ * clipping. */
+ int nSegments; /* # segments in the above array. */
+ int xor;
+ int xorState; /* State of the XOR drawing. Indicates
+ * if the marker is currently drawn. */
+} LineMarker;
+
+static Blt_ConfigSpec lineConfigSpecs[] =
+{
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_LINE_TAGS,
+ Blt_Offset(LineMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CAP_STYLE, "-cap", "cap", "Cap", DEF_MARKER_CAP_STYLE,
+ Blt_Offset(LineMarker, capStyle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(LineMarker, worldPts), BLT_CONFIG_NULL_OK, &coordsOption},
+ {BLT_CONFIG_DASHES, "-dashes", "dashes", "Dashes", DEF_MARKER_DASHES,
+ Blt_Offset(LineMarker, dashes), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_PIXELS_NNEG, "-dashoffset", "dashOffset", "DashOffset",
+ DEF_MARKER_DASH_OFFSET, Blt_Offset(LineMarker, dashes.offset),
+ BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT,
+ Blt_Offset(LineMarker, elemName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_COLOR, "-fill", "fill", "Fill", (char *)NULL,
+ Blt_Offset(LineMarker, fillColor), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_JOIN_STYLE, "-join", "join", "Join", DEF_MARKER_JOIN_STYLE,
+ Blt_Offset(LineMarker, joinStyle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS_NNEG, "-linewidth", "lineWidth", "LineWidth",
+ DEF_MARKER_LINE_WIDTH, Blt_Offset(LineMarker, lineWidth),
+ BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(LineMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(LineMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(LineMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(LineMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_COLOR, "-outline", "outline", "Outline",
+ DEF_MARKER_OUTLINE_COLOR, Blt_Offset(LineMarker, outlineColor),
+ BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(LineMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(LineMarker, drawUnder), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(LineMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-xor", "xor", "Xor", DEF_MARKER_XOR,
+ Blt_Offset(LineMarker, xor), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(LineMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigureLineProc;
+static MarkerCreateProc CreateLineProc;
+static MarkerDrawProc DrawLineProc;
+static MarkerFreeProc FreeLineProc;
+static MarkerMapProc MapLineProc;
+static MarkerPointProc PointInLineProc;
+static MarkerPostscriptProc LineToPostscriptProc;
+static MarkerRegionProc RegionInLineProc;
+
+static MarkerClass lineMarkerClass = {
+ lineConfigSpecs,
+ ConfigureLineProc,
+ DrawLineProc,
+ FreeLineProc,
+ MapLineProc,
+ PointInLineProc,
+ RegionInLineProc,
+ LineToPostscriptProc,
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PolygonMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+
+ Point2d *worldPts; /* Coordinate array to position
+ * marker. */
+
+ int nWorldPts; /* Number of points in above array */
+
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+
+ Point2d *screenPts; /* Array of points representing the
+ * polygon in screen coordinates. It's
+ * not used for drawing, but to generate
+ * the outlinePts and fillPts arrays
+ * that are the coordinates of the
+ * possibly clipped outline and filled
+ * polygon. */
+
+ ColorPair outline;
+ ColorPair fill;
+
+ Pixmap stipple; /* Stipple pattern to fill the
+ * polygon. */
+ int lineWidth; /* Width of polygon outline. */
+ int capStyle;
+ int joinStyle;
+ Blt_Dashes dashes; /* List of dash values. Indicates how
+ * to draw the dashed line. If no dash
+ * values are provided, or the first
+ * value is zero, then the line is drawn
+ * solid. */
+
+ GC outlineGC; /* Graphics context to draw the outline
+ * of the polygon. */
+ GC fillGC; /* Graphics context to draw the filled
+ * polygon. */
+
+ Point2d *fillPts; /* Malloc'ed array of points used to
+ * draw the filled polygon. These points
+ * may form a degenerate polygon after
+ * clipping. */
+ int nFillPts; /* # points in the above array. */
+ Segment2d *outlinePts; /* Malloc'ed array of points.
+ * Represents individual line segments
+ * (2 points per segment) comprising the
+ * outline of the polygon. The segments
+ * may not necessarily be closed or
+ * connected after clipping. */
+ int nOutlinePts; /* # points in the above array. */
+ int xor;
+ int xorState; /* State of the XOR drawing. Indicates
+ * if the marker is visible. We have to
+ * drawn it again to erase it. */
+} PolygonMarker;
+
+static Blt_ConfigSpec polygonConfigSpecs[] =
+{
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_POLYGON_TAGS,
+ Blt_Offset(PolygonMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CAP_STYLE, "-cap", "cap", "Cap", DEF_MARKER_CAP_STYLE,
+ Blt_Offset(PolygonMarker, capStyle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(PolygonMarker, worldPts), BLT_CONFIG_NULL_OK, &coordsOption},
+ {BLT_CONFIG_DASHES, "-dashes", "dashes", "Dashes", DEF_MARKER_DASHES,
+ Blt_Offset(PolygonMarker, dashes), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT,
+ Blt_Offset(PolygonMarker, elemName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-fill", "fill", "Fill", DEF_MARKER_FILL_COLOR,
+ Blt_Offset(PolygonMarker, fill), BLT_CONFIG_NULL_OK, &colorPairOption},
+ {BLT_CONFIG_JOIN_STYLE, "-join", "join", "Join", DEF_MARKER_JOIN_STYLE,
+ Blt_Offset(PolygonMarker, joinStyle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS_NNEG, "-linewidth", "lineWidth", "LineWidth",
+ DEF_MARKER_LINE_WIDTH, Blt_Offset(PolygonMarker, lineWidth),
+ BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(PolygonMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(PolygonMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(PolygonMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(PolygonMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-outline", "outline", "Outline",
+ DEF_MARKER_OUTLINE_COLOR, Blt_Offset(PolygonMarker, outline),
+ BLT_CONFIG_NULL_OK, &colorPairOption},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(PolygonMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BITMAP, "-stipple", "stipple", "Stipple", DEF_MARKER_STIPPLE,
+ Blt_Offset(PolygonMarker, stipple), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(PolygonMarker, drawUnder),
+ BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(PolygonMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-xor", "xor", "Xor", DEF_MARKER_XOR,
+ Blt_Offset(PolygonMarker, xor), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(PolygonMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigurePolygonProc;
+static MarkerCreateProc CreatePolygonProc;
+static MarkerDrawProc DrawPolygonProc;
+static MarkerFreeProc FreePolygonProc;
+static MarkerMapProc MapPolygonProc;
+static MarkerPointProc PointInPolygonProc;
+static MarkerPostscriptProc PolygonToPostscriptProc;
+static MarkerRegionProc RegionInPolygonProc;
+
+static MarkerClass polygonMarkerClass = {
+ polygonConfigSpecs,
+ ConfigurePolygonProc,
+ DrawPolygonProc,
+ FreePolygonProc,
+ MapPolygonProc,
+ PointInPolygonProc,
+ RegionInPolygonProc,
+ PolygonToPostscriptProc,
+};
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TextMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+ MarkerClass *classPtr;
+ Blt_HashEntry *hashPtr;
+ Blt_ChainLink link;
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+ Point2d *worldPts; /* Coordinate array to position
+ * marker. */
+ int nWorldPts; /* # of points in above array */
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+ int state;
+
+ /* Fields specific to text markers. */
+#ifdef notdef
+ const char *textVarName; /* Name of variable (malloc'ed) or
+ * NULL. If non-NULL, graph displays the
+ * contents of this variable. */
+#endif
+ const char *string; /* Text string to be display. The
+ * string make contain newlines. */
+ Tk_Anchor anchor; /* Indicates how to translate the given
+ * marker position. */
+ Point2d anchorPt; /* Translated anchor point. */
+ int width, height; /* Dimension of bounding box. */
+ TextStyle style; /* Text attributes (font, fg, anchor,
+ * etc) */
+ Point2d outline[5];
+ XColor *fillColor;
+ GC fillGC;
+} TextMarker;
+
+
+static Blt_ConfigSpec textConfigSpecs[] =
+{
+ {BLT_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR,
+ Blt_Offset(TextMarker, anchor), 0},
+ {BLT_CONFIG_COLOR, "-background", "background", "MarkerBackground",
+ (char *)NULL, Blt_Offset(TextMarker, fillColor), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-bg", "background", "Background", (char *)NULL, 0, 0},
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_TEXT_TAGS,
+ Blt_Offset(TextMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(TextMarker, worldPts), BLT_CONFIG_NULL_OK,
+ &coordsOption},
+ {BLT_CONFIG_STRING, "-element", "element", "Element",
+ DEF_MARKER_ELEMENT, Blt_Offset(TextMarker, elemName),
+ BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-fg", "foreground", "Foreground", (char *)NULL, 0, 0},
+ {BLT_CONFIG_SYNONYM, "-fill", "background", (char *)NULL, (char *)NULL,
+ 0, 0},
+ {BLT_CONFIG_FONT, "-font", "font", "Font", DEF_MARKER_FONT,
+ Blt_Offset(TextMarker, style.font), 0},
+ {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_MARKER_FOREGROUND, Blt_Offset(TextMarker, style.color), 0},
+ {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
+ DEF_MARKER_JUSTIFY, Blt_Offset(TextMarker, style.justify),
+ BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(TextMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(TextMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(TextMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(TextMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_SYNONYM, "-outline", "foreground", (char *)NULL, (char *)NULL,
+ 0, 0},
+ {BLT_CONFIG_PAD, "-padx", "padX", "PadX", DEF_MARKER_PAD,
+ Blt_Offset(TextMarker, style.xPad), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PAD, "-pady", "padY", "PadY", DEF_MARKER_PAD,
+ Blt_Offset(TextMarker, style.yPad), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_FLOAT, "-rotate", "rotate", "Rotate", DEF_MARKER_ANGLE,
+ Blt_Offset(TextMarker, style.angle), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(TextMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_STRING, "-text", "text", "Text", DEF_MARKER_TEXT,
+ Blt_Offset(TextMarker, string), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(TextMarker, drawUnder), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(TextMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(TextMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigureTextProc;
+static MarkerCreateProc CreateTextProc;
+static MarkerDrawProc DrawTextProc;
+static MarkerFreeProc FreeTextProc;
+static MarkerMapProc MapTextProc;
+static MarkerPointProc PointInTextProc;
+static MarkerPostscriptProc TextToPostscriptProc;
+static MarkerRegionProc RegionInTextProc;
+
+static MarkerClass textMarkerClass = {
+ textConfigSpecs,
+ ConfigureTextProc,
+ DrawTextProc,
+ FreeTextProc,
+ MapTextProc,
+ PointInTextProc,
+ RegionInTextProc,
+ TextToPostscriptProc,
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * WindowMarker --
+ *
+ *---------------------------------------------------------------------------
+ */
+typedef struct {
+ GraphObj obj; /* Must be first field in marker. */
+
+ MarkerClass *classPtr;
+
+ Blt_HashEntry *hashPtr;
+
+ Blt_ChainLink link;
+
+ const char *elemName; /* Element associated with marker. Let's
+ * you link a marker to an element. The
+ * marker is drawn only if the element
+ * is also visible. */
+ Axis2d axes;
+
+ Point2d *worldPts; /* Coordinate array to position
+ * marker */
+
+ int nWorldPts; /* # of points in above array */
+
+ int drawUnder; /* If non-zero, draw the marker
+ * underneath any elements. This can be
+ * a performance penalty because the
+ * graph must be redraw entirely each
+ * time the marker is redrawn. */
+
+ int clipped; /* Indicates if the marker is totally
+ * clipped by the plotting area. */
+
+ unsigned int flags;
+
+
+ int xOffset, yOffset; /* Pixel offset from graph position */
+
+ int state;
+
+ /* Fields specific to window markers. */
+
+ const char *childName; /* Name of child widget. */
+ Tk_Window child; /* Window to display. */
+ int reqWidth, reqHeight; /* If non-zero, this overrides the size
+ * requested by the child widget. */
+
+ Tk_Anchor anchor; /* Indicates how to translate the given
+ * marker position. */
+
+ Point2d anchorPt; /* Translated anchor point. */
+ int width, height; /* Current size of the child window. */
+
+} WindowMarker;
+
+static Blt_ConfigSpec windowConfigSpecs[] =
+{
+ {BLT_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_MARKER_ANCHOR,
+ Blt_Offset(WindowMarker, anchor), 0},
+ {BLT_CONFIG_LIST, "-bindtags", "bindTags", "BindTags", DEF_WINDOW_TAGS,
+ Blt_Offset(WindowMarker, obj.tags), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_CUSTOM, "-coords", "coords", "Coords", DEF_MARKER_COORDS,
+ Blt_Offset(WindowMarker, worldPts), BLT_CONFIG_NULL_OK,
+ &coordsOption},
+ {BLT_CONFIG_STRING, "-element", "element", "Element", DEF_MARKER_ELEMENT,
+ Blt_Offset(WindowMarker, elemName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_PIXELS_POS, "-height", "height", "Height", DEF_MARKER_HEIGHT,
+ Blt_Offset(WindowMarker, reqHeight), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BITMASK, "-hide", "hide", "Hide", DEF_MARKER_HIDE,
+ Blt_Offset(WindowMarker, flags), BLT_CONFIG_DONT_SET_DEFAULT,
+ (Blt_CustomOption *)HIDE},
+ {BLT_CONFIG_CUSTOM, "-mapx", "mapX", "MapX", DEF_MARKER_MAP_X,
+ Blt_Offset(WindowMarker, axes.x), 0, &bltXAxisOption},
+ {BLT_CONFIG_CUSTOM, "-mapy", "mapY", "MapY", DEF_MARKER_MAP_Y,
+ Blt_Offset(WindowMarker, axes.y), 0, &bltYAxisOption},
+ {BLT_CONFIG_STRING, "-name", (char *)NULL, (char *)NULL, DEF_MARKER_NAME,
+ Blt_Offset(WindowMarker, obj.name), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_STATE, "-state", "state", "State", DEF_MARKER_STATE,
+ Blt_Offset(WindowMarker, state), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_BOOLEAN, "-under", "under", "Under", DEF_MARKER_UNDER,
+ Blt_Offset(WindowMarker, drawUnder), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS_POS, "-width", "width", "Width", DEF_MARKER_WIDTH,
+ Blt_Offset(WindowMarker, reqWidth), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_STRING, "-window", "window", "Window", DEF_MARKER_WINDOW,
+ Blt_Offset(WindowMarker, childName), BLT_CONFIG_NULL_OK},
+ {BLT_CONFIG_PIXELS, "-xoffset", "xOffset", "XOffset", DEF_MARKER_X_OFFSET,
+ Blt_Offset(WindowMarker, xOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_PIXELS, "-yoffset", "yOffset", "YOffset", DEF_MARKER_Y_OFFSET,
+ Blt_Offset(WindowMarker, yOffset), BLT_CONFIG_DONT_SET_DEFAULT},
+ {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
+};
+
+static MarkerConfigProc ConfigureWindowProc;
+static MarkerCreateProc CreateWindowProc;
+static MarkerDrawProc DrawWindowProc;
+static MarkerFreeProc FreeWindowProc;
+static MarkerMapProc MapWindowProc;
+static MarkerPointProc PointInWindowProc;
+static MarkerPostscriptProc WindowToPostscriptProc;
+static MarkerRegionProc RegionInWindowProc;
+
+static MarkerClass windowMarkerClass = {
+ windowConfigSpecs,
+ ConfigureWindowProc,
+ DrawWindowProc,
+ FreeWindowProc,
+ MapWindowProc,
+ PointInWindowProc,
+ RegionInWindowProc,
+ WindowToPostscriptProc,
+};
+
+static Tk_ImageChangedProc ImageChangedProc;
+
+
+
+#ifdef notdef
+static MarkerClass rectangleMarkerClass = {
+ rectangleConfigSpecs,
+ ConfigureRectangleProc,
+ DrawRectangleProc,
+ FreeRectangleProc,
+ MapRectangleProc,
+ PointInRectangleProc,
+ RegionInRectangleProc,
+ RectangleToPostscriptProc,
+};
+
+static MarkerClass ovalMarkerClass = {
+ ovalConfigSpecs,
+ ConfigureOvalProc,
+ DrawOvalProc,
+ FreeOvalProc,
+ MapOvalProc,
+ PointInOvalProc,
+ RegionInOvalProc,
+ OvalToPostscriptProc,
+};
+#endif
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * BoxesDontOverlap --
+ *
+ * Tests if the bounding box of a marker overlaps the plotting area in
+ * any way. If so, the marker will be drawn. Just do a min/max test on
+ * the extents of both boxes.
+ *
+ * Note: It's assumed that the extents of the bounding box lie
+ * within the area. So for a 10x10 rectangle, bottom and
+ * left would be 9.
+ *
+ * Results:
+ * Returns 0 is the marker is visible in the plotting area, and 1
+ * otherwise (marker is clipped).
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+BoxesDontOverlap(Graph *graphPtr, Region2d *extsPtr)
+{
+ assert(extsPtr->right >= extsPtr->left);
+ assert(extsPtr->bottom >= extsPtr->top);
+ assert(graphPtr->right >= graphPtr->left);
+ assert(graphPtr->bottom >= graphPtr->top);
+
+ return (((double)graphPtr->right < extsPtr->left) ||
+ ((double)graphPtr->bottom < extsPtr->top) ||
+ (extsPtr->right < (double)graphPtr->left) ||
+ (extsPtr->bottom < (double)graphPtr->top));
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetCoordinate --
+ *
+ * Convert the expression string into a floating point value. The * only
+ * reason we use this routine instead of Blt_ExprDouble is to * handle
+ * "elastic" bounds. That is, convert the strings "-Inf", * "Inf" into
+ * -(DBL_MAX) and DBL_MAX respectively.
+ *
+ * Results:
+ * The return value is a standard TCL result. The value of the
+ * expression is passed back via valuePtr.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+GetCoordinate(
+ Tcl_Interp *interp, /* Interpreter to return results */
+ Tcl_Obj *objPtr, /* Numeric expression string to
+ * parse */
+ double *valuePtr) /* Real-valued result of expression */
+{
+ char c;
+ const char *expr;
+
+ expr = Tcl_GetString(objPtr);
+ c = expr[0];
+ if ((c == 'I') && (strcmp(expr, "Inf") == 0)) {
+ *valuePtr = DBL_MAX; /* Elastic upper bound */
+ } else if ((c == '-') && (expr[1] == 'I') && (strcmp(expr, "-Inf") == 0)) {
+ *valuePtr = -DBL_MAX; /* Elastic lower bound */
+ } else if ((c == '+') && (expr[1] == 'I') && (strcmp(expr, "+Inf") == 0)) {
+ *valuePtr = DBL_MAX; /* Elastic upper bound */
+ } else if (Blt_ExprDoubleFromObj(interp, objPtr, valuePtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PrintCoordinate --
+ *
+ * Convert the floating point value into its string representation. The
+ * only reason this routine is used in instead of sprintf, is to handle
+ * the "elastic" bounds. That is, convert the values DBL_MAX and
+ * -(DBL_MAX) into "+Inf" and "-Inf" respectively.
+ *
+ * Results:
+ * The return value is a standard TCL result. The string of the *
+ * expression is passed back via string.
+ *
+ * -------------------------------------------------------------------------- */
+static Tcl_Obj *
+PrintCoordinate(double x)
+{
+ if (x == DBL_MAX) {
+ return Tcl_NewStringObj("+Inf", -1);
+ } else if (x == -DBL_MAX) {
+ return Tcl_NewStringObj("-Inf", -1);
+ } else {
+ return Tcl_NewDoubleObj(x);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ParseCoordinates --
+ *
+ * The TCL coordinate list is converted to their floating point
+ * values. It will then replace the current marker coordinates.
+ *
+ * Since different marker types require different number of coordinates
+ * this must be checked here.
+ *
+ * Results:
+ * The return value is a standard TCL result.
+ *
+ * Side effects:
+ * If the marker coordinates are reset, the graph is eventually redrawn
+ * with at the new marker coordinates.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+ParseCoordinates(
+ Tcl_Interp *interp,
+ Marker *markerPtr,
+ int objc,
+ Tcl_Obj *const *objv)
+{
+ int nWorldPts;
+ int minArgs, maxArgs;
+ Point2d *worldPts;
+ int i;
+
+ if (objc == 0) {
+ return TCL_OK;
+ }
+ if (objc & 1) {
+ Tcl_AppendResult(interp, "odd number of marker coordinates specified",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ switch (markerPtr->obj.classId) {
+ case CID_MARKER_LINE:
+ minArgs = 4, maxArgs = 0;
+ break;
+ case CID_MARKER_POLYGON:
+ minArgs = 6, maxArgs = 0;
+ break;
+ case CID_MARKER_WINDOW:
+ case CID_MARKER_TEXT:
+ minArgs = 2, maxArgs = 2;
+ break;
+ case CID_MARKER_IMAGE:
+ case CID_MARKER_BITMAP:
+ minArgs = 2, maxArgs = 4;
+ break;
+ default:
+ Tcl_AppendResult(interp, "unknown marker type", (char *)NULL);
+ return TCL_ERROR;
+ }
+
+ if (objc < minArgs) {
+ Tcl_AppendResult(interp, "too few marker coordinates specified",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ if ((maxArgs > 0) && (objc > maxArgs)) {
+ Tcl_AppendResult(interp, "too many marker coordinates specified",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ nWorldPts = objc / 2;
+ worldPts = Blt_Malloc(nWorldPts * sizeof(Point2d));
+ if (worldPts == NULL) {
+ Tcl_AppendResult(interp, "can't allocate new coordinate array",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+
+ {
+ Point2d *pp;
+
+ pp = worldPts;
+ for (i = 0; i < objc; i += 2) {
+ double x, y;
+
+ if ((GetCoordinate(interp, objv[i], &x) != TCL_OK) ||
+ (GetCoordinate(interp, objv[i + 1], &y) != TCL_OK)) {
+ Blt_Free(worldPts);
+ return TCL_ERROR;
+ }
+ pp->x = x, pp->y = y, pp++;
+ }
+ }
+ /* Don't free the old coordinate array until we've parsed the new
+ * coordinates without errors. */
+ if (markerPtr->worldPts != NULL) {
+ Blt_Free(markerPtr->worldPts);
+ }
+ markerPtr->worldPts = worldPts;
+ markerPtr->nWorldPts = nWorldPts;
+ markerPtr->flags |= MAP_ITEM;
+ return TCL_OK;
+}
+
+/*ARGSUSED*/
+static void
+FreeCoordsProc(
+ ClientData clientData, /* Not used. */
+ Display *display, /* Not used. */
+ char *widgRec,
+ int offset)
+{
+ Marker *markerPtr = (Marker *)widgRec;
+ Point2d **pointsPtr = (Point2d **)(widgRec + offset);
+
+ if (*pointsPtr != NULL) {
+ Blt_Free(*pointsPtr);
+ *pointsPtr = NULL;
+ }
+ markerPtr->nWorldPts = 0;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ObjToCoordsProc --
+ *
+ * Given a TCL list of numeric expression representing the element
+ * values, convert into an array of floating point values. In addition,
+ * the minimum and maximum values are saved. Since elastic values are
+ * allow (values which translate to the min/max of the graph), we must
+ * try to get the non-elastic minimum and maximum.
+ *
+ * Results:
+ * The return value is a standard TCL result. The vector is
+ * passed back via the vecPtr.
+ *
+ * --------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ObjToCoordsProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp, /* Interpreter to return results */
+ Tk_Window tkwin, /* Not used. */
+ Tcl_Obj *objPtr, /* TCL list of numeric expressions */
+ char *widgRec, /* Marker record */
+ int offset, /* Not used. */
+ int flags) /* Not used. */
+{
+ Marker *markerPtr = (Marker *)widgRec;
+ int objc;
+ Tcl_Obj **objv;
+
+ if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (objc == 0) {
+ return TCL_OK;
+ }
+ return ParseCoordinates(interp, markerPtr, objc, objv);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CoordsToObjProc --
+ *
+ * Convert the vector of floating point values into a TCL list.
+ *
+ * Results:
+ * The string representation of the vector is returned.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static Tcl_Obj *
+CoordsToObjProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp,
+ Tk_Window tkwin, /* Not used. */
+ char *widgRec, /* Marker record */
+ int offset, /* Not used. */
+ int flags) /* Not used. */
+{
+ Marker *markerPtr = (Marker *)widgRec;
+ Tcl_Obj *listObjPtr;
+ Point2d *pp, *pend;
+
+ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ for (pp = markerPtr->worldPts, pend = pp + markerPtr->nWorldPts; pp < pend;
+ pp++) {
+ Tcl_ListObjAppendElement(interp, listObjPtr, PrintCoordinate(pp->x));
+ Tcl_ListObjAppendElement(interp, listObjPtr, PrintCoordinate(pp->y));
+ }
+ return listObjPtr;
+}
+
+/*LINTLIBRARY*/
+static int
+GetColorPair(
+ Tcl_Interp *interp,
+ Tk_Window tkwin,
+ Tcl_Obj *fgObjPtr, Tcl_Obj *bgObjPtr,
+ ColorPair *pairPtr,
+ int allowDefault)
+{
+ XColor *fgColor, *bgColor;
+ const char *string;
+
+ fgColor = bgColor = NULL;
+ if (fgObjPtr != NULL) {
+ int length;
+
+ string = Tcl_GetStringFromObj(fgObjPtr, &length);
+ if (string[0] == '\0') {
+ fgColor = NULL;
+ } else if ((allowDefault) && (string[0] == 'd') &&
+ (strncmp(string, "defcolor", length) == 0)) {
+ fgColor = COLOR_DEFAULT;
+ } else {
+ fgColor = Tk_AllocColorFromObj(interp, tkwin, fgObjPtr);
+ if (fgColor == NULL) {
+ return TCL_ERROR;
+ }
+ }
+ }
+ if (bgObjPtr != NULL) {
+ int length;
+
+ string = Tcl_GetStringFromObj(bgObjPtr, &length);
+ if (string[0] == '\0') {
+ bgColor = NULL;
+ } else if ((allowDefault) && (string[0] == 'd') &&
+ (strncmp(string, "defcolor", length) == 0)) {
+ bgColor = COLOR_DEFAULT;
+ } else {
+ bgColor = Tk_AllocColorFromObj(interp, tkwin, bgObjPtr);
+ if (bgColor == NULL) {
+ return TCL_ERROR;
+ }
+ }
+ }
+ if (pairPtr->fgColor != NULL) {
+ Tk_FreeColor(pairPtr->fgColor);
+ }
+ if (pairPtr->bgColor != NULL) {
+ Tk_FreeColor(pairPtr->bgColor);
+ }
+ pairPtr->fgColor = fgColor;
+ pairPtr->bgColor = bgColor;
+ return TCL_OK;
+}
+
+void
+Blt_FreeColorPair(ColorPair *pairPtr)
+{
+ if ((pairPtr->bgColor != NULL) && (pairPtr->bgColor != COLOR_DEFAULT)) {
+ Tk_FreeColor(pairPtr->bgColor);
+ }
+ if ((pairPtr->fgColor != NULL) && (pairPtr->fgColor != COLOR_DEFAULT)) {
+ Tk_FreeColor(pairPtr->fgColor);
+ }
+ pairPtr->bgColor = pairPtr->fgColor = NULL;
+}
+
+static void
+FreeColorPairProc(
+ ClientData clientData, /* Not used. */
+ Display *display, /* Not used. */
+ char *widgRec,
+ int offset)
+{
+ ColorPair *pairPtr = (ColorPair *)(widgRec + offset);
+
+ Blt_FreeColorPair(pairPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ObjToColorPairProc --
+ *
+ * Convert the color names into pair of XColor pointers.
+ *
+ * Results:
+ * A standard TCL result. The color pointer is written into the
+ * widget record.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ObjToColorPairProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp, /* Interpreter to return results */
+ Tk_Window tkwin, /* Not used. */
+ Tcl_Obj *objPtr, /* String representing color */
+ char *widgRec, /* Widget record */
+ int offset, /* Offset to field in structure */
+ int flags) /* Not used. */
+{
+ ColorPair *pairPtr = (ColorPair *)(widgRec + offset);
+ long longValue = (long)clientData;
+ int bool;
+ int objc;
+ Tcl_Obj **objv;
+
+ if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (objc > 2) {
+ Tcl_AppendResult(interp, "too many names in colors list",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ if (objc == 0) {
+ Blt_FreeColorPair(pairPtr);
+ return TCL_OK;
+ }
+ bool = (int)longValue;
+ if (objc == 1) {
+ if (GetColorPair(interp, tkwin, objv[0], NULL, pairPtr, bool)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ } else {
+ if (GetColorPair(interp, tkwin, objv[0], objv[1], pairPtr, bool)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * NameOfColor --
+ *
+ * Convert the color option value into a string.
+ *
+ * Results:
+ * The static string representing the color option is returned.
+ *
+ *---------------------------------------------------------------------------
+ */
+static const char *
+NameOfColor(XColor *colorPtr)
+{
+ if (colorPtr == NULL) {
+ return "";
+ } else if (colorPtr == COLOR_DEFAULT) {
+ return "defcolor";
+ } else {
+ return Tk_NameOfColor(colorPtr);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ColorPairToObjProc --
+ *
+ * Convert the color pairs into color names.
+ *
+ * Results:
+ * The string representing the symbol color is returned.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static Tcl_Obj *
+ColorPairToObjProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp,
+ Tk_Window tkwin, /* Not used. */
+ char *widgRec, /* Element information record */
+ int offset, /* Offset to field in structure */
+ int flags) /* Not used. */
+{
+ ColorPair *pairPtr = (ColorPair *)(widgRec + offset);
+ Tcl_Obj *listObjPtr;
+
+ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(NameOfColor(pairPtr->fgColor), -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(NameOfColor(pairPtr->bgColor), -1));
+ return listObjPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ImageChangedProc
+ *
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static void
+ImageChangedProc(
+ ClientData clientData,
+ int x, int y, int w, int h, /* Not used. */
+ int imageWidth, int imageHeight) /* Not used. */
+{
+ Graph *graphPtr;
+ ImageMarker *imPtr = clientData;
+ int isPhoto;
+
+ graphPtr = imPtr->obj.graphPtr;
+ if ((imPtr->picture != NULL) && (imPtr->flags & IMAGE_PHOTO)) {
+ Blt_FreePicture(imPtr->picture);
+ }
+ imPtr->picture = NULL;
+ imPtr->flags &= ~IMAGE_PHOTO;
+ if (Blt_Image_IsDeleted(imPtr->tkImage)) {
+ Tk_FreeImage(imPtr->tkImage);
+ imPtr->tkImage = NULL;
+ return;
+ }
+ imPtr->picture = Blt_GetPictureFromImage(graphPtr->interp, imPtr->tkImage,
+ &isPhoto);
+ if (isPhoto) {
+ imPtr->flags |= IMAGE_PHOTO;
+ }
+ graphPtr->flags |= CACHE_DIRTY;
+ imPtr->flags |= MAP_ITEM;
+ Blt_EventuallyRedrawGraph(graphPtr);
+}
+
+/*ARGSUSED*/
+static void
+FreePictImageProc(
+ ClientData clientData,
+ Display *display, /* Not used. */
+ char *widgRec,
+ int offset)
+{
+ ImageMarker *imPtr = (ImageMarker *)widgRec;
+
+ if ((imPtr->picture != NULL) && (imPtr->flags & IMAGE_PHOTO)) {
+ Blt_FreePicture(imPtr->picture);
+ }
+ imPtr->picture = NULL;
+ if (imPtr->tkImage != NULL) {
+ Tk_FreeImage(imPtr->tkImage);
+ }
+ imPtr->tkImage = NULL;
+ imPtr->flags &= ~IMAGE_PHOTO;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ObjToPictImageProc --
+ *
+ * Given an image name, get the Tk image associated with it.
+ *
+ * Results:
+ * The return value is a standard TCL result.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ObjToPictImageProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp, /* Interpreter to return results */
+ Tk_Window tkwin, /* Not used. */
+ Tcl_Obj *objPtr, /* String representation of value. */
+ char *widgRec, /* Widget record. */
+ int offset, /* Offset to field in structure */
+ int flags)
+{
+ Blt_Picture *picturePtr = (Blt_Picture *)(widgRec + offset);
+ Graph *graphPtr;
+ ImageMarker *imPtr = (ImageMarker *)widgRec;
+ Tk_Image tkImage;
+ const char *name;
+ int isPhoto;
+
+ name = Tcl_GetString(objPtr);
+ tkImage = Tk_GetImage(interp, tkwin, name, ImageChangedProc, imPtr);
+ if (tkImage == NULL) {
+ return TCL_ERROR;
+ }
+ if (imPtr->tkImage != NULL) {
+ Tk_FreeImage(imPtr->tkImage);
+ }
+ imPtr->flags &= ~IMAGE_PHOTO;
+ if (*picturePtr != NULL) {
+ Blt_FreePicture(*picturePtr);
+ }
+ *picturePtr = NULL;
+ imPtr->tkImage = tkImage;
+ graphPtr = imPtr->obj.graphPtr;
+ *picturePtr = Blt_GetPictureFromImage(graphPtr->interp, tkImage, &isPhoto);
+ if (isPhoto) {
+ imPtr->flags |= IMAGE_PHOTO;
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PictImageToObjProc --
+ *
+ * Convert the image name into a string Tcl_Obj.
+ *
+ * Results:
+ * The string representation of the image is returned.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static Tcl_Obj *
+PictImageToObjProc(
+ ClientData clientData, /* Not used. */
+ Tcl_Interp *interp,
+ Tk_Window tkwin, /* Not used. */
+ char *widgRec, /* Widget record */
+ int offset, /* Offset to field in structure */
+ int flags)
+{
+ ImageMarker *imPtr = (ImageMarker *)(widgRec);
+
+ if (imPtr->tkImage == NULL) {
+ return Tcl_NewStringObj("", -1);
+ }
+ return Tcl_NewStringObj(Blt_Image_Name(imPtr->tkImage), -1);
+}
+
+static INLINE int
+IsElementHidden(Marker *markerPtr)
+{
+ Blt_HashEntry *hPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ /* Look up the named element and see if it's hidden */
+ hPtr = Blt_FindHashEntry(&graphPtr->elements.table, markerPtr->elemName);
+ if (hPtr != NULL) {
+ Element *elemPtr;
+
+ elemPtr = Blt_GetHashValue(hPtr);
+ if ((elemPtr->link == NULL) || (elemPtr->flags & HIDE)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * HMap --
+ *
+ * Maps the given graph coordinate value to its axis, returning a window
+ * position. This is a slight variation on the normal Blt_HMap routine.
+ * It treats -Inf as the minimum axis value and Inf as the maximum.
+ *
+ * Results:
+ * Returns a floating point number representing the window coordinate
+ * position on the given axis.
+ *
+ * --------------------------------------------------------------------------
+ */
+static double
+HMap(Axis *axisPtr, double x)
+{
+ if (x == DBL_MAX) {
+ x = 1.0;
+ } else if (x == -DBL_MAX) {
+ x = 0.0;
+ } else {
+ if (axisPtr->logScale) {
+ if (x > 0.0) {
+ x = log10(x);
+ } else if (x < 0.0) {
+ x = 0.0;
+ }
+ }
+ x = NORMALIZE(axisPtr, x);
+ }
+ if (axisPtr->descending) {
+ x = 1.0 - x;
+ }
+ /* Horizontal transformation */
+ return (x * axisPtr->screenRange + axisPtr->screenMin);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * VMap --
+ *
+ * Map the given graph coordinate value to its axis, returning a window
+ * position. This is a slight variation on the normal Blt_VMap routine.
+ * It treats -Inf as the minimum axis value and Inf as the maximum.
+ *
+ * Results:
+ * Returns a double precision number representing the window coordinate
+ * position on the given axis.
+ *
+ *---------------------------------------------------------------------------
+ */
+static double
+VMap(Axis *axisPtr, double y)
+{
+ if (y == DBL_MAX) {
+ y = 1.0;
+ } else if (y == -DBL_MAX) {
+ y = 0.0;
+ } else {
+ if (axisPtr->logScale) {
+ if (y > 0.0) {
+ y = log10(y);
+ } else if (y < 0.0) {
+ y = 0.0;
+ }
+ }
+ y = NORMALIZE(axisPtr, y);
+ }
+ if (axisPtr->descending) {
+ y = 1.0 - y;
+ }
+ /* Vertical transformation. */
+ return (((1.0 - y) * axisPtr->screenRange) + axisPtr->screenMin);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapPoint --
+ *
+ * Maps the given graph x,y coordinate values to a window position.
+ *
+ * Results:
+ * Returns a XPoint structure containing the window coordinates of the
+ * given graph x,y coordinate.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Point2d
+MapPoint(
+ Point2d *pointPtr, /* Graph X-Y coordinate. */
+ Axis2d *axesPtr) /* Specifies which axes to use */
+{
+ Point2d result;
+ Graph *graphPtr = axesPtr->y->obj.graphPtr;
+
+ if (graphPtr->inverted) {
+ result.x = HMap(axesPtr->y, pointPtr->y);
+ result.y = VMap(axesPtr->x, pointPtr->x);
+ } else {
+ result.x = HMap(axesPtr->x, pointPtr->x);
+ result.y = VMap(axesPtr->y, pointPtr->y);
+ }
+ return result; /* Result is screen coordinate. */
+}
+
+static Marker *
+CreateMarker(
+ Graph *graphPtr,
+ const char *name,
+ ClassId classId)
+{
+ Marker *markerPtr;
+
+ /* Create the new marker based upon the given type */
+ switch (classId) {
+ case CID_MARKER_BITMAP:
+ markerPtr = CreateBitmapProc(); /* bitmap */
+ break;
+ case CID_MARKER_LINE:
+ markerPtr = CreateLineProc(); /* line */
+ break;
+ case CID_MARKER_IMAGE:
+ markerPtr = CreateImageProc(); /* image */
+ break;
+ case CID_MARKER_TEXT:
+ markerPtr = CreateTextProc(); /* text */
+ break;
+ case CID_MARKER_POLYGON:
+ markerPtr = CreatePolygonProc(); /* polygon */
+ break;
+ case CID_MARKER_WINDOW:
+ markerPtr = CreateWindowProc(); /* window */
+ break;
+ default:
+ return NULL;
+ }
+ markerPtr->obj.graphPtr = graphPtr;
+ markerPtr->drawUnder = FALSE;
+ markerPtr->flags |= MAP_ITEM;
+ markerPtr->obj.name = Blt_AssertStrdup(name);
+ Blt_GraphSetObjectClass(&markerPtr->obj, classId);
+ return markerPtr;
+}
+
+
+static void
+DestroyMarker(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (markerPtr->drawUnder) {
+ /* If the marker to be deleted is currently displayed below the
+ * elements, then backing store needs to be repaired. */
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ /*
+ * Call the marker's type-specific deallocation routine. We do it first
+ * while all the marker fields are still valid.
+ */
+ (*markerPtr->classPtr->freeProc)(markerPtr);
+
+ /* Dump any bindings that might be registered for the marker. */
+ Blt_DeleteBindings(graphPtr->bindTable, markerPtr);
+
+ /* Release all the X resources associated with the marker. */
+ Blt_FreeOptions(markerPtr->classPtr->configSpecs, (char *)markerPtr,
+ graphPtr->display, 0);
+
+ if (markerPtr->hashPtr != NULL) {
+ Blt_DeleteHashEntry(&graphPtr->markers.table,
+ markerPtr->hashPtr);
+ }
+ if (markerPtr->link != NULL) {
+ Blt_Chain_DeleteLink(graphPtr->markers.displayList, markerPtr->link);
+ }
+ if (markerPtr->obj.name != NULL) {
+ Blt_Free(markerPtr->obj.name);
+ }
+ Blt_Free(markerPtr);
+}
+
+static void
+FreeMarker(DestroyData dataPtr)
+{
+ Marker *markerPtr = (Marker *)dataPtr;
+ DestroyMarker(markerPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureBitmapProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a bitmap
+ * marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as bitmap pixmap, colors, rotation,
+ * etc. get set for markerPtr; old resources get freed, if there were
+ * any. The marker is eventually redisplayed.
+ *
+ *---------------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static int
+ConfigureBitmapProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+ GC newGC;
+ XGCValues gcValues;
+ unsigned long gcMask;
+
+ if (bmPtr->srcBitmap == None) {
+ return TCL_OK;
+ }
+ bmPtr->angle = FMOD(bmPtr->reqAngle, 360.0);
+ if (bmPtr->angle < 0.0) {
+ bmPtr->angle += 360.0;
+ }
+ gcMask = 0;
+
+ if (bmPtr->outlineColor != NULL) {
+ gcMask |= GCForeground;
+ gcValues.foreground = bmPtr->outlineColor->pixel;
+ }
+
+ if (bmPtr->fillColor != NULL) {
+ /* Opaque bitmap: both foreground and background (fill) colors
+ * are used. */
+ gcValues.background = bmPtr->fillColor->pixel;
+ gcMask |= GCBackground;
+ } else {
+ /* Transparent bitmap: set the clip mask to the current bitmap. */
+ gcValues.clip_mask = bmPtr->srcBitmap;
+ gcMask |= GCClipMask;
+ }
+
+ /*
+ * This is technically a shared GC, but we're going to set/change the clip
+ * origin anyways before we draw the bitmap. This relies on the fact that
+ * no other client will be allocated this GC with the GCClipMask set to
+ * this particular bitmap.
+ */
+ newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
+ if (bmPtr->gc != NULL) {
+ Tk_FreeGC(graphPtr->display, bmPtr->gc);
+ }
+ bmPtr->gc = newGC;
+
+ /* Create the background GC containing the fill color. */
+
+ if (bmPtr->fillColor != NULL) {
+ gcValues.foreground = bmPtr->fillColor->pixel;
+ newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
+ if (bmPtr->fillGC != NULL) {
+ Tk_FreeGC(graphPtr->display, bmPtr->fillGC);
+ }
+ bmPtr->fillGC = newGC;
+ }
+
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+#ifdef notdef
+static void
+PrintPolyPoint(char *mesg, Point2d *points, int nPoints)
+{
+ int i;
+
+ fprintf(stderr, "%s:\t\tpoint[0]=%g,%g\n", mesg, points[0].x, points[0].y);
+ for (i = 1; i < nPoints; i++) {
+ fprintf(stderr, "\t\tpoint[%d]=%g,%g\n", i, points[i].x, points[i].y);
+ }
+}
+#endif
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapBitmapProc --
+ *
+ * This procedure gets called each time the layout of the graph changes.
+ * The x, y window coordinates of the bitmap marker are saved in the
+ * marker structure.
+ *
+ * Additionly, if no background color was specified, the
+ * GCTileStipXOrigin and GCTileStipYOrigin attributes are set in the
+ * private GC.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Window coordinates are saved and if no background color was set, the
+ * GC stipple origins are changed to calculated window coordinates.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapBitmapProc(Marker *markerPtr)
+{
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+ Region2d extents;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ Point2d anchorPt;
+ Point2d corner1, corner2;
+ int destWidth, destHeight;
+ int srcWidth, srcHeight;
+ int i;
+
+ if (bmPtr->srcBitmap == None) {
+ return;
+ }
+ if (bmPtr->destBitmap != None) {
+ Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap);
+ bmPtr->destBitmap = None;
+ }
+ /*
+ * Collect the coordinates. The number of coordinates will determine the
+ * calculations to be made.
+ *
+ * x1 y1 A single pair of X-Y coordinates. They represent
+ * the anchor position of the bitmap.
+ *
+ * x1 y1 x2 y2 Two pairs of X-Y coordinates. They represent
+ * two opposite corners of a bounding rectangle. The
+ * bitmap is possibly rotated and scaled to fit into
+ * this box.
+ *
+ */
+ Tk_SizeOfBitmap(graphPtr->display, bmPtr->srcBitmap, &srcWidth,
+ &srcHeight);
+ corner1 = MapPoint(markerPtr->worldPts, &markerPtr->axes);
+ if (markerPtr->nWorldPts > 1) {
+ double hold;
+
+ corner2 = MapPoint(markerPtr->worldPts + 1, &markerPtr->axes);
+ /* Flip the corners if necessary */
+ if (corner1.x > corner2.x) {
+ hold = corner1.x, corner1.x = corner2.x, corner2.x = hold;
+ }
+ if (corner1.y > corner2.y) {
+ hold = corner1.y, corner1.y = corner2.y, corner2.y = hold;
+ }
+ } else {
+ corner2.x = corner1.x + srcWidth - 1;
+ corner2.y = corner1.y + srcHeight - 1;
+ }
+ destWidth = (int)(corner2.x - corner1.x) + 1;
+ destHeight = (int)(corner2.y - corner1.y) + 1;
+
+ if (markerPtr->nWorldPts == 1) {
+ anchorPt = Blt_AnchorPoint(corner1.x, corner1.y, (double)destWidth,
+ (double)destHeight, bmPtr->anchor);
+ } else {
+ anchorPt = corner1;
+ }
+ anchorPt.x += markerPtr->xOffset;
+ anchorPt.y += markerPtr->yOffset;
+
+ /* Check if the bitmap sits at least partially in the plot area. */
+ extents.left = anchorPt.x;
+ extents.top = anchorPt.y;
+ extents.right = anchorPt.x + destWidth - 1;
+ extents.bottom = anchorPt.y + destHeight - 1;
+ markerPtr->clipped = BoxesDontOverlap(graphPtr, &extents);
+ if (markerPtr->clipped) {
+ return; /* Bitmap is offscreen. Don't generate
+ * rotated or scaled bitmaps. */
+ }
+
+ /*
+ * Scale the bitmap if necessary. It's a little tricky because we only
+ * want to scale what's visible on the screen, not the entire bitmap.
+ */
+ if ((bmPtr->angle != 0.0f) || (destWidth != srcWidth) ||
+ (destHeight != srcHeight)) {
+ int regionX, regionY, regionWidth, regionHeight;
+ double left, right, top, bottom;
+
+ /* Ignore parts of the bitmap outside of the plot area. */
+ left = MAX(graphPtr->left, extents.left);
+ right = MIN(graphPtr->right, extents.right);
+ top = MAX(graphPtr->top, extents.top);
+ bottom = MIN(graphPtr->bottom, extents.bottom);
+
+ /* Determine the portion of the scaled bitmap to display. */
+ regionX = regionY = 0;
+ if (graphPtr->left > extents.left) {
+ regionX = (int)(graphPtr->left - extents.left);
+ }
+ if (graphPtr->top > extents.top) {
+ regionY = (int)(graphPtr->top - extents.top);
+ }
+ regionWidth = (int)(right - left) + 1;
+ regionHeight = (int)(bottom - top) + 1;
+
+ anchorPt.x = left;
+ anchorPt.y = top;
+ bmPtr->destBitmap = Blt_ScaleRotateBitmapArea(graphPtr->tkwin,
+ bmPtr->srcBitmap, srcWidth, srcHeight, regionX, regionY,
+ regionWidth, regionHeight, destWidth, destHeight, bmPtr->angle);
+ bmPtr->destWidth = regionWidth;
+ bmPtr->destHeight = regionHeight;
+ } else {
+ bmPtr->destWidth = srcWidth;
+ bmPtr->destHeight = srcHeight;
+ bmPtr->destBitmap = None;
+ }
+ bmPtr->anchorPt = anchorPt;
+ {
+ double xScale, yScale;
+ double tx, ty;
+ double rotWidth, rotHeight;
+ Point2d polygon[5];
+ int n;
+
+ /*
+ * Compute a polygon to represent the background area of the bitmap.
+ * This is needed for backgrounds of arbitrarily rotated bitmaps. We
+ * also use it to print a background in PostScript.
+ */
+ Blt_GetBoundingBox(srcWidth, srcHeight, bmPtr->angle, &rotWidth,
+ &rotHeight, polygon);
+ xScale = (double)destWidth / rotWidth;
+ yScale = (double)destHeight / rotHeight;
+
+ /*
+ * Adjust each point of the polygon. Both scale it to the new size and
+ * translate it to the actual screen position of the bitmap.
+ */
+ tx = extents.left + destWidth * 0.5;
+ ty = extents.top + destHeight * 0.5;
+ for (i = 0; i < 4; i++) {
+ polygon[i].x = (polygon[i].x * xScale) + tx;
+ polygon[i].y = (polygon[i].y * yScale) + ty;
+ }
+ Blt_GraphExtents(graphPtr, &extents);
+ n = Blt_PolyRectClip(&extents, polygon, 4, bmPtr->outline);
+ assert(n <= MAX_OUTLINE_POINTS);
+ if (n < 3) {
+ memcpy(&bmPtr->outline, polygon, sizeof(Point2d) * 4);
+ bmPtr->nOutlinePts = 4;
+ } else {
+ bmPtr->nOutlinePts = n;
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PointInBitmapProc --
+ *
+ * Indicates if the given point is over the bitmap marker. The area of
+ * the bitmap is the rectangle.
+ *
+ * Results:
+ * Returns 1 is the point is over the bitmap marker, 0 otherwise.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+PointInBitmapProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+
+ if (bmPtr->srcBitmap == None) {
+ return 0;
+ }
+ if (bmPtr->angle != 0.0f) {
+ Point2d points[MAX_OUTLINE_POINTS];
+ int i;
+
+ /*
+ * Generate the bounding polygon (isolateral) for the bitmap and see
+ * if the point is inside of it.
+ */
+ for (i = 0; i < bmPtr->nOutlinePts; i++) {
+ points[i].x = bmPtr->outline[i].x + bmPtr->anchorPt.x;
+ points[i].y = bmPtr->outline[i].y + bmPtr->anchorPt.y;
+ }
+ return Blt_PointInPolygon(samplePtr, points, bmPtr->nOutlinePts);
+ }
+ return ((samplePtr->x >= bmPtr->anchorPt.x) &&
+ (samplePtr->x < (bmPtr->anchorPt.x + bmPtr->destWidth)) &&
+ (samplePtr->y >= bmPtr->anchorPt.y) &&
+ (samplePtr->y < (bmPtr->anchorPt.y + bmPtr->destHeight)));
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInBitmapProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInBitmapProc(Marker *markerPtr, Region2d *extsPtr, int enclosed)
+{
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+
+ if (markerPtr->nWorldPts < 1) {
+ return FALSE;
+ }
+ if (bmPtr->angle != 0.0f) {
+ Point2d points[MAX_OUTLINE_POINTS];
+ int i;
+
+ /*
+ * Generate the bounding polygon (isolateral) for the bitmap and see
+ * if the point is inside of it.
+ */
+ for (i = 0; i < bmPtr->nOutlinePts; i++) {
+ points[i].x = bmPtr->outline[i].x + bmPtr->anchorPt.x;
+ points[i].y = bmPtr->outline[i].y + bmPtr->anchorPt.y;
+ }
+ return Blt_RegionInPolygon(extsPtr, points, bmPtr->nOutlinePts,
+ enclosed);
+ }
+ if (enclosed) {
+ return ((bmPtr->anchorPt.x >= extsPtr->left) &&
+ (bmPtr->anchorPt.y >= extsPtr->top) &&
+ ((bmPtr->anchorPt.x + bmPtr->destWidth) <= extsPtr->right) &&
+ ((bmPtr->anchorPt.y + bmPtr->destHeight) <= extsPtr->bottom));
+ }
+ return !((bmPtr->anchorPt.x >= extsPtr->right) ||
+ (bmPtr->anchorPt.y >= extsPtr->bottom) ||
+ ((bmPtr->anchorPt.x + bmPtr->destWidth) <= extsPtr->left) ||
+ ((bmPtr->anchorPt.y + bmPtr->destHeight) <= extsPtr->top));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DrawBitmapProc --
+ *
+ * Draws the bitmap marker that have a transparent of filled background.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * GC stipple origins are changed to current window coordinates.
+ * Commands are output to X to draw the marker in its current mode.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+DrawBitmapProc(Marker *markerPtr, Drawable drawable)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+ double rangle;
+ Pixmap bitmap;
+
+ bitmap = GETBITMAP(bmPtr);
+ if ((bitmap == None) || (bmPtr->destWidth < 1) || (bmPtr->destHeight < 1)) {
+ return;
+ }
+ rangle = FMOD(bmPtr->angle, 90.0);
+ if ((bmPtr->fillColor == NULL) || (rangle != 0.0)) {
+
+ /*
+ * If the bitmap is rotated and a filled background is required, then
+ * a filled polygon is drawn before the bitmap.
+ */
+ if (bmPtr->fillColor != NULL) {
+ int i;
+ XPoint polygon[MAX_OUTLINE_POINTS];
+
+ for (i = 0; i < bmPtr->nOutlinePts; i++) {
+ polygon[i].x = (short int)bmPtr->outline[i].x;
+ polygon[i].y = (short int)bmPtr->outline[i].y;
+ }
+ XFillPolygon(graphPtr->display, drawable, bmPtr->fillGC,
+ polygon, bmPtr->nOutlinePts, Convex, CoordModeOrigin);
+ }
+ XSetClipMask(graphPtr->display, bmPtr->gc, bitmap);
+ XSetClipOrigin(graphPtr->display, bmPtr->gc, (int)bmPtr->anchorPt.x,
+ (int)bmPtr->anchorPt.y);
+ } else {
+ XSetClipMask(graphPtr->display, bmPtr->gc, None);
+ XSetClipOrigin(graphPtr->display, bmPtr->gc, 0, 0);
+ }
+ XCopyPlane(graphPtr->display, bitmap, drawable, bmPtr->gc, 0, 0,
+ bmPtr->destWidth, bmPtr->destHeight, (int)bmPtr->anchorPt.x,
+ (int)bmPtr->anchorPt.y, 1);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * BitmapToPostscriptProc --
+ *
+ * Generates PostScript to print a bitmap marker.
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+BitmapToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+ Pixmap bitmap;
+
+ bitmap = GETBITMAP(bmPtr);
+ if ((bitmap == None) || (bmPtr->destWidth < 1) || (bmPtr->destHeight < 1)) {
+ return; /* No bitmap to display. */
+ }
+ if (bmPtr->fillColor != NULL) {
+ Blt_Ps_XSetBackground(ps, bmPtr->fillColor);
+ Blt_Ps_XFillPolygon(ps, bmPtr->outline, 4);
+ }
+ Blt_Ps_XSetForeground(ps, bmPtr->outlineColor);
+
+ Blt_Ps_Format(ps,
+ " gsave\n %g %g translate\n %d %d scale\n",
+ bmPtr->anchorPt.x, bmPtr->anchorPt.y + bmPtr->destHeight,
+ bmPtr->destWidth, -bmPtr->destHeight);
+ Blt_Ps_Format(ps, " %d %d true [%d 0 0 %d 0 %d] {",
+ bmPtr->destWidth, bmPtr->destHeight, bmPtr->destWidth,
+ -bmPtr->destHeight, bmPtr->destHeight);
+ Blt_Ps_XSetBitmapData(ps, graphPtr->display, bitmap,
+ bmPtr->destWidth, bmPtr->destHeight);
+ Blt_Ps_VarAppend(ps,
+ " } imagemask\n",
+ "grestore\n", (char *)NULL);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeBitmapProc --
+ *
+ * Releases the memory and attributes of the bitmap marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitmap attributes (GCs, colors, bitmap, etc) get destroyed. Memory is
+ * released, X resources are freed, and the graph is redrawn.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreeBitmapProc(Marker *markerPtr)
+{
+ BitmapMarker *bmPtr = (BitmapMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (bmPtr->gc != NULL) {
+ Tk_FreeGC(graphPtr->display, bmPtr->gc);
+ }
+ if (bmPtr->fillGC != NULL) {
+ Tk_FreeGC(graphPtr->display, bmPtr->fillGC);
+ }
+ if (bmPtr->destBitmap != None) {
+ Tk_FreePixmap(graphPtr->display, bmPtr->destBitmap);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateBitmapProc --
+ *
+ * Allocate memory and initialize methods for the new bitmap marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the bitmap marker structure.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Marker *
+CreateBitmapProc(void)
+{
+ BitmapMarker *bmPtr;
+
+ bmPtr = Blt_AssertCalloc(1, sizeof(BitmapMarker));
+ bmPtr->classPtr = &bitmapMarkerClass;
+ return (Marker *)bmPtr;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureImageProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a image
+ * marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as image pixmap, colors, rotation,
+ * etc. get set for markerPtr; old resources get freed, if there were
+ * any. The marker is eventually redisplayed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+ConfigureImageProc(Marker *markerPtr)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ Blt_Painter painter;
+ GC newGC;
+
+ newGC = Tk_GetGC(graphPtr->tkwin, 0L, (XGCValues *)NULL);
+ if (imPtr->gc != NULL) {
+ Tk_FreeGC(graphPtr->display, imPtr->gc);
+ }
+ imPtr->gc = newGC;
+
+ painter = Blt_GetPainter(graphPtr->tkwin, 1.0);
+ if (imPtr->painter != NULL) {
+ Blt_FreePainter(painter);
+ }
+ imPtr->painter = painter;
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapImageProc --
+ *
+ * This procedure gets called each time the layout of the graph changes.
+ * The x, y window coordinates of the image marker are saved in the
+ * marker structure.
+ *
+ * In addition, if no background color was specified, the
+ * GCTileStipXOrigin and GCTileStipYOrigin attributes will not set in the
+ * private GC.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Window coordinates are saved and if no background color was set, the
+ * GC stipple origins are changed to calculated window coordinates.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapImageProc(Marker *markerPtr)
+{
+ Region2d extents;
+ Graph *graphPtr;
+ ImageMarker *imPtr;
+ Point2d anchorPt;
+ Point2d c1, c2;
+ int newWidth, newHeight;
+ int srcWidth, srcHeight;
+ int x, y, w, h;
+ int left, right, top, bottom;
+
+ imPtr = (ImageMarker *)markerPtr;
+ if (imPtr->picture == NULL) {
+ return;
+ }
+ if (imPtr->scaled != NULL) {
+ Blt_FreePicture(imPtr->scaled);
+ imPtr->scaled = NULL;
+ }
+ graphPtr = markerPtr->obj.graphPtr;
+ c1 = MapPoint(markerPtr->worldPts, &markerPtr->axes);
+
+ imPtr->width = srcWidth = Blt_PictureWidth(imPtr->picture);
+ imPtr->height = srcHeight = Blt_PictureHeight(imPtr->picture);
+
+ if ((srcWidth == 0) || (srcHeight == 0)) {
+ markerPtr->clipped = TRUE;
+ return; /* Empty image. */
+ }
+ if (markerPtr->nWorldPts > 1) {
+ double hold;
+
+ c2 = MapPoint(markerPtr->worldPts + 1, &markerPtr->axes);
+ /* Flip the corners if necessary */
+ if (c1.x > c2.x) {
+ hold = c1.x, c1.x = c2.x, c2.x = hold;
+ }
+ if (c1.y > c2.y) {
+ hold = c1.y, c1.y = c2.y, c2.y = hold;
+ }
+ } else {
+ c2.x = c1.x + srcWidth - 1;
+ c2.y = c1.y + srcHeight - 1;
+ }
+ newWidth = (int)(c2.x - c1.x) + 1;
+ newHeight = (int)(c2.y - c1.y) + 1;
+
+ if (markerPtr->nWorldPts == 1) {
+ anchorPt = Blt_AnchorPoint(c1.x, c1.y, (double)newWidth,
+ (double)newHeight, imPtr->anchor);
+ } else {
+ anchorPt = c1;
+ }
+ anchorPt.x += markerPtr->xOffset;
+ anchorPt.y += markerPtr->yOffset;
+
+ /* Check if the image sits at least partially in the plot area. */
+ extents.left = anchorPt.x;
+ extents.top = anchorPt.y;
+ extents.right = anchorPt.x + newWidth - 1;
+ extents.bottom = anchorPt.y + newHeight - 1;
+
+ markerPtr->clipped = BoxesDontOverlap(graphPtr, &extents);
+ if (markerPtr->clipped) {
+ return; /* Image is offscreen. Don't generate
+ * rotated or scaled images. */
+ }
+
+ /* Determine the extents of the subimage inside of the destination
+ * image. */
+ left = MAX((int)extents.left, graphPtr->left);
+ top = MAX((int)extents.top, graphPtr->top);
+ right = MIN((int)extents.right, graphPtr->right);
+ bottom = MIN((int)extents.bottom, graphPtr->bottom);
+
+ /* Reset image location and coordinates to that of the region */
+ anchorPt.x = left;
+ anchorPt.y = top;
+
+ x = y = 0;
+ if (graphPtr->left > (int)extents.left) {
+ x = graphPtr->left - (int)extents.left;
+ }
+ if (graphPtr->top > (int)extents.top) {
+ y = graphPtr->top - (int)extents.top;
+ }
+ w = (int)(right - left + 1);
+ h = (int)(bottom - top + 1);
+
+ if (markerPtr->nWorldPts > 1) {
+ Blt_Picture scaled;
+
+ scaled = Blt_ScalePictureArea(imPtr->picture, x, y, w, h,
+ newWidth, newHeight);
+ imPtr->scaled = scaled;
+ imPtr->pictX = 0;
+ imPtr->pictY = 0;
+ } else {
+ imPtr->pictX = x;
+ imPtr->pictY = y;
+ }
+ imPtr->width = newWidth;
+ imPtr->height = newHeight;
+ imPtr->anchorPt = anchorPt;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PointInWindowProc --
+ *
+ * Indicates if the given point is over the window marker. The area of
+ * the window is the rectangle.
+ *
+ * Results:
+ * Returns 1 is the point is over the window marker, 0 otherwise.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+PointInImageProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+ double left, right, top, bottom;
+
+ left = imPtr->anchorPt.x;
+ right = imPtr->anchorPt.x + imPtr->width;
+ top = imPtr->anchorPt.y;
+ bottom = imPtr->anchorPt.y + imPtr->height;
+
+ return ((samplePtr->x >= left) && (samplePtr->x < right) &&
+ (samplePtr->y >= top) && (samplePtr->y < bottom));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInImageProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInImageProc(Marker *markerPtr, Region2d *regPtr, int enclosed)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+
+ if (markerPtr->nWorldPts > 0) {
+ double left, right, top, bottom;
+
+ left = imPtr->anchorPt.x;
+ right = imPtr->anchorPt.x + imPtr->width;
+ top = imPtr->anchorPt.y;
+ bottom = imPtr->anchorPt.y + imPtr->height;
+ if (enclosed) {
+ return ((left >= regPtr->left) && (top >= regPtr->top) &&
+ (right <= regPtr->right) && (bottom <= regPtr->bottom));
+ }
+ return !((left >= regPtr->right) || (top >= regPtr->bottom) ||
+ (right <= regPtr->left) || (bottom <= regPtr->top));
+ }
+ return FALSE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DrawImageProc --
+ *
+ * This procedure is invoked to draw a image marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * GC stipple origins are changed to current window coordinates.
+ * Commands are output to X to draw the marker in its current mode.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+DrawImageProc(Marker *markerPtr, Drawable drawable)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+ Blt_Picture picture;
+
+ picture = (imPtr->scaled != NULL) ? imPtr->scaled : imPtr->picture;
+ if (picture != NULL) {
+ Blt_PaintPictureWithBlend(imPtr->painter, drawable, picture,
+ imPtr->pictX, imPtr->pictY, imPtr->width, imPtr->height,
+ (int)imPtr->anchorPt.x, (int)imPtr->anchorPt.y, 0, 0.4);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ImageToPostscriptProc --
+ *
+ * This procedure is invoked to print a image marker.
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+ImageToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+ Blt_Picture picture;
+
+ picture = (imPtr->scaled != NULL) ? imPtr->scaled : imPtr->picture;
+ if (picture != NULL) {
+ Blt_Ps_DrawPicture(ps, picture, imPtr->anchorPt.x, imPtr->anchorPt.y);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeImageProc --
+ *
+ * Destroys the structure containing the attributes of the image marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Image attributes (GCs, colors, image, etc) get destroyed. Memory is
+ * released, X resources are freed, and the graph is redrawn.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreeImageProc(Marker *markerPtr)
+{
+ ImageMarker *imPtr = (ImageMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (imPtr->painter != NULL) {
+ Blt_FreePainter(imPtr->painter);
+ }
+ if (imPtr->scaled != NULL) {
+ Blt_FreePicture(imPtr->scaled);
+ }
+ if (imPtr->gc != NULL) {
+ Tk_FreeGC(graphPtr->display, imPtr->gc);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateImageProc --
+ *
+ * Allocate memory and initialize methods for the new image marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the image marker structure.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Marker *
+CreateImageProc(void)
+{
+ ImageMarker *imPtr;
+
+ imPtr = Blt_AssertCalloc(1, sizeof(ImageMarker));
+ imPtr->classPtr = &imageMarkerClass;
+ return (Marker *)imPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureTextProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a text marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as text string, colors, font, etc. get
+ * set for markerPtr; old resources get freed, if there were any. The
+ * marker is eventually redisplayed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+ConfigureTextProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+ GC newGC;
+ XGCValues gcValues;
+ unsigned long gcMask;
+
+ tmPtr->style.angle = (float)FMOD(tmPtr->style.angle, 360.0);
+ if (tmPtr->style.angle < 0.0f) {
+ tmPtr->style.angle += 360.0f;
+ }
+ newGC = NULL;
+ if (tmPtr->fillColor != NULL) {
+ gcMask = GCForeground;
+ gcValues.foreground = tmPtr->fillColor->pixel;
+ newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
+ }
+ if (tmPtr->fillGC != NULL) {
+ Tk_FreeGC(graphPtr->display, tmPtr->fillGC);
+ }
+ tmPtr->fillGC = newGC;
+
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapTextProc --
+ *
+ * Calculate the layout position for a text marker. Positional information
+ * is saved in the marker. If the text is rotated, a bitmap containing the
+ * text is created.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If no background color has been specified, the GC stipple origins are
+ * changed to current window coordinates. For both rotated and
+ * non-rotated text, if any old bitmap is leftover, it is freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapTextProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+ Region2d extents;
+ Point2d anchorPt;
+ int i;
+ unsigned int w, h;
+ double rw, rh;
+
+ tmPtr->width = tmPtr->height = 0;
+ if (tmPtr->string == NULL) {
+ return;
+ }
+ Blt_Ts_GetExtents(&tmPtr->style, tmPtr->string, &w, &h);
+ Blt_GetBoundingBox(w, h, tmPtr->style.angle, &rw, &rh, tmPtr->outline);
+ tmPtr->width = ROUND(rw);
+ tmPtr->height = ROUND(rh);
+ for (i = 0; i < 4; i++) {
+ tmPtr->outline[i].x += ROUND(rw * 0.5);
+ tmPtr->outline[i].y += ROUND(rh * 0.5);
+ }
+ tmPtr->outline[4].x = tmPtr->outline[0].x;
+ tmPtr->outline[4].y = tmPtr->outline[0].y;
+ anchorPt = MapPoint(markerPtr->worldPts, &markerPtr->axes);
+ anchorPt = Blt_AnchorPoint(anchorPt.x, anchorPt.y, (double)(tmPtr->width),
+ (double)(tmPtr->height), tmPtr->anchor);
+ anchorPt.x += markerPtr->xOffset;
+ anchorPt.y += markerPtr->yOffset;
+ /*
+ * Determine the bounding box of the text and test to see if it is at
+ * least partially contained within the plotting area.
+ */
+ extents.left = anchorPt.x;
+ extents.top = anchorPt.y;
+ extents.right = anchorPt.x + tmPtr->width - 1;
+ extents.bottom = anchorPt.y + tmPtr->height - 1;
+ markerPtr->clipped = BoxesDontOverlap(graphPtr, &extents);
+ tmPtr->anchorPt = anchorPt;
+
+}
+
+static int
+PointInTextProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+
+ if (tmPtr->string == NULL) {
+ return 0;
+ }
+ if (tmPtr->style.angle != 0.0f) {
+ Point2d points[5];
+ int i;
+
+ /*
+ * Figure out the bounding polygon (isolateral) for the text and see
+ * if the point is inside of it.
+ */
+ for (i = 0; i < 5; i++) {
+ points[i].x = tmPtr->outline[i].x + tmPtr->anchorPt.x;
+ points[i].y = tmPtr->outline[i].y + tmPtr->anchorPt.y;
+ }
+ return Blt_PointInPolygon(samplePtr, points, 5);
+ }
+ return ((samplePtr->x >= tmPtr->anchorPt.x) &&
+ (samplePtr->x < (tmPtr->anchorPt.x + tmPtr->width)) &&
+ (samplePtr->y >= tmPtr->anchorPt.y) &&
+ (samplePtr->y < (tmPtr->anchorPt.y + tmPtr->height)));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInTextProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInTextProc(Marker *markerPtr, Region2d *extsPtr, int enclosed)
+{
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+
+ if (markerPtr->nWorldPts < 1) {
+ return FALSE;
+ }
+ if (tmPtr->style.angle != 0.0f) {
+ Point2d points[5];
+ int i;
+
+ /*
+ * Generate the bounding polygon (isolateral) for the bitmap and see
+ * if the point is inside of it.
+ */
+ for (i = 0; i < 4; i++) {
+ points[i].x = tmPtr->outline[i].x + tmPtr->anchorPt.x;
+ points[i].y = tmPtr->outline[i].y + tmPtr->anchorPt.y;
+ }
+ return Blt_RegionInPolygon(extsPtr, points, 4, enclosed);
+ }
+ if (enclosed) {
+ return ((tmPtr->anchorPt.x >= extsPtr->left) &&
+ (tmPtr->anchorPt.y >= extsPtr->top) &&
+ ((tmPtr->anchorPt.x + tmPtr->width) <= extsPtr->right) &&
+ ((tmPtr->anchorPt.y + tmPtr->height) <= extsPtr->bottom));
+ }
+ return !((tmPtr->anchorPt.x >= extsPtr->right) ||
+ (tmPtr->anchorPt.y >= extsPtr->bottom) ||
+ ((tmPtr->anchorPt.x + tmPtr->width) <= extsPtr->left) ||
+ ((tmPtr->anchorPt.y + tmPtr->height) <= extsPtr->top));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DrawTextProc --
+ *
+ * Draws the text marker on the graph.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Commands are output to X to draw the marker in its current mode.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+DrawTextProc(Marker *markerPtr, Drawable drawable)
+{
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (tmPtr->string == NULL) {
+ return;
+ }
+ if (tmPtr->fillGC != NULL) {
+ XPoint points[4];
+ int i;
+
+ /*
+ * Simulate the rotated background of the bitmap by filling a bounding
+ * polygon with the background color.
+ */
+ for (i = 0; i < 4; i++) {
+ points[i].x = (short int)(tmPtr->outline[i].x + tmPtr->anchorPt.x);
+ points[i].y = (short int)(tmPtr->outline[i].y + tmPtr->anchorPt.y);
+ }
+ XFillPolygon(graphPtr->display, drawable, tmPtr->fillGC, points, 4,
+ Convex, CoordModeOrigin);
+ }
+ if (tmPtr->style.color != NULL) {
+ Blt_Ts_DrawText(graphPtr->tkwin, drawable, tmPtr->string, -1,
+ &tmPtr->style, (int)tmPtr->anchorPt.x, (int)tmPtr->anchorPt.y);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TextToPostscriptProc --
+ *
+ * Outputs PostScript commands to draw a text marker at a given x,y
+ * coordinate, rotation, anchor, and font.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * PostScript font and color settings are changed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+TextToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+
+ if (tmPtr->string == NULL) {
+ return;
+ }
+ if (tmPtr->fillGC != NULL) {
+ Point2d points[4];
+ int i;
+
+ /*
+ * Simulate the rotated background of the bitmap by filling a bounding
+ * polygon with the background color.
+ */
+ for (i = 0; i < 4; i++) {
+ points[i].x = tmPtr->outline[i].x + tmPtr->anchorPt.x;
+ points[i].y = tmPtr->outline[i].y + tmPtr->anchorPt.y;
+ }
+ Blt_Ps_XSetBackground(ps, tmPtr->fillColor);
+ Blt_Ps_XFillPolygon(ps, points, 4);
+ }
+ Blt_Ps_DrawText(ps, tmPtr->string, &tmPtr->style, tmPtr->anchorPt.x,
+ tmPtr->anchorPt.y);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeTextProc --
+ *
+ * Destroys the structure containing the attributes of the text marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Text attributes (GCs, colors, stipple, font, etc) get destroyed.
+ * Memory is released, X resources are freed, and the graph is redrawn.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreeTextProc(Marker *markerPtr)
+{
+ TextMarker *tmPtr = (TextMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ Blt_Ts_FreeStyle(graphPtr->display, &tmPtr->style);
+}
+
+/*
+ *---------------------------------------------------------------------------
+
+ * CreateTextProc --
+ *
+ * Allocate memory and initialize methods for the new text marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the text marker structure.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Marker *
+CreateTextProc(void)
+{
+ TextMarker *tmPtr;
+
+ tmPtr = Blt_AssertCalloc(1, sizeof(TextMarker));
+ tmPtr->classPtr = &textMarkerClass;
+ Blt_Ts_InitStyle(tmPtr->style);
+ tmPtr->style.anchor = TK_ANCHOR_NW;
+ tmPtr->style.padLeft = tmPtr->style.padRight = 4;
+ tmPtr->style.padTop = tmPtr->style.padBottom = 4;
+ return (Marker *)tmPtr;
+}
+
+static Tk_EventProc ChildEventProc;
+static Tk_GeomRequestProc ChildGeometryProc;
+static Tk_GeomLostSlaveProc ChildCustodyProc;
+static Tk_GeomMgr winMarkerMgrInfo =
+{
+ (char *)"graph", /* Name of geometry manager used by
+ * winfo */
+ ChildGeometryProc, /* Procedure to for new geometry
+ * requests. */
+ ChildCustodyProc, /* Procedure when window is taken
+ * away. */
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureWindowProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a window
+ * marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as window pathname, placement,
+ * etc. get set for markerPtr; old resources get freed, if there were
+ * any. The marker is eventually redisplayed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+ConfigureWindowProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+ Tk_Window tkwin;
+
+ if (wmPtr->childName == NULL) {
+ return TCL_OK;
+ }
+ tkwin = Tk_NameToWindow(graphPtr->interp, wmPtr->childName,
+ graphPtr->tkwin);
+ if (tkwin == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tk_Parent(tkwin) != graphPtr->tkwin) {
+ Tcl_AppendResult(graphPtr->interp, "\"", wmPtr->childName,
+ "\" is not a child of \"", Tk_PathName(graphPtr->tkwin), "\"",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+ if (tkwin != wmPtr->child) {
+ if (wmPtr->child != NULL) {
+ Tk_DeleteEventHandler(wmPtr->child, StructureNotifyMask,
+ ChildEventProc, wmPtr);
+ Tk_ManageGeometry(wmPtr->child, (Tk_GeomMgr *) 0, (ClientData)0);
+ Tk_UnmapWindow(wmPtr->child);
+ }
+ Tk_CreateEventHandler(tkwin, StructureNotifyMask, ChildEventProc,
+ wmPtr);
+ Tk_ManageGeometry(tkwin, &winMarkerMgrInfo, wmPtr);
+ }
+ wmPtr->child = tkwin;
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapWindowProc --
+ *
+ * Calculate the layout position for a window marker. Positional
+ * information is saved in the marker.
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapWindowProc(Marker *markerPtr)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ Point2d anchorPt;
+ Region2d extents;
+ int width, height;
+
+ if (wmPtr->child == (Tk_Window)NULL) {
+ return;
+ }
+ anchorPt = MapPoint(markerPtr->worldPts, &markerPtr->axes);
+
+ width = Tk_ReqWidth(wmPtr->child);
+ height = Tk_ReqHeight(wmPtr->child);
+ if (wmPtr->reqWidth > 0) {
+ width = wmPtr->reqWidth;
+ }
+ if (wmPtr->reqHeight > 0) {
+ height = wmPtr->reqHeight;
+ }
+ wmPtr->anchorPt = Blt_AnchorPoint(anchorPt.x, anchorPt.y, (double)width,
+ (double)height, wmPtr->anchor);
+ wmPtr->anchorPt.x += markerPtr->xOffset;
+ wmPtr->anchorPt.y += markerPtr->yOffset;
+ wmPtr->width = width;
+ wmPtr->height = height;
+
+ /*
+ * Determine the bounding box of the window and test to see if it is at
+ * least partially contained within the plotting area.
+ */
+ extents.left = wmPtr->anchorPt.x;
+ extents.top = wmPtr->anchorPt.y;
+ extents.right = wmPtr->anchorPt.x + wmPtr->width - 1;
+ extents.bottom = wmPtr->anchorPt.y + wmPtr->height - 1;
+ markerPtr->clipped = BoxesDontOverlap(graphPtr, &extents);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * PointInWindowProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+PointInWindowProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+
+ return ((samplePtr->x >= wmPtr->anchorPt.x) &&
+ (samplePtr->x < (wmPtr->anchorPt.x + wmPtr->width)) &&
+ (samplePtr->y >= wmPtr->anchorPt.y) &&
+ (samplePtr->y < (wmPtr->anchorPt.y + wmPtr->height)));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInWindowProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInWindowProc(Marker *markerPtr, Region2d *extsPtr, int enclosed)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+
+ if (markerPtr->nWorldPts < 1) {
+ return FALSE;
+ }
+ if (enclosed) {
+ return ((wmPtr->anchorPt.x >= extsPtr->left) &&
+ (wmPtr->anchorPt.y >= extsPtr->top) &&
+ ((wmPtr->anchorPt.x + wmPtr->width) <= extsPtr->right) &&
+ ((wmPtr->anchorPt.y + wmPtr->height) <= extsPtr->bottom));
+ }
+ return !((wmPtr->anchorPt.x >= extsPtr->right) ||
+ (wmPtr->anchorPt.y >= extsPtr->bottom) ||
+ ((wmPtr->anchorPt.x + wmPtr->width) <= extsPtr->left) ||
+ ((wmPtr->anchorPt.y + wmPtr->height) <= extsPtr->top));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DrawWindowProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+DrawWindowProc(Marker *markerPtr, Drawable drawable)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+
+ if (wmPtr->child == NULL) {
+ return;
+ }
+ if ((wmPtr->height != Tk_Height(wmPtr->child)) ||
+ (wmPtr->width != Tk_Width(wmPtr->child)) ||
+ ((int)wmPtr->anchorPt.x != Tk_X(wmPtr->child)) ||
+ ((int)wmPtr->anchorPt.y != Tk_Y(wmPtr->child))) {
+ Tk_MoveResizeWindow(wmPtr->child, (int)wmPtr->anchorPt.x,
+ (int)wmPtr->anchorPt.y, wmPtr->width, wmPtr->height);
+ }
+ if (!Tk_IsMapped(wmPtr->child)) {
+ Tk_MapWindow(wmPtr->child);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * WindowToPostscriptProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+WindowToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+
+ if (wmPtr->child == NULL) {
+ return;
+ }
+ if (Tk_IsMapped(wmPtr->child)) {
+ Blt_Ps_XDrawWindow(ps, wmPtr->child, wmPtr->anchorPt.x,
+ wmPtr->anchorPt.y);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeWindowProc --
+ *
+ * Destroys the structure containing the attributes of the window *
+ * marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Window is destroyed and removed from the screen.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreeWindowProc(Marker *markerPtr)
+{
+ WindowMarker *wmPtr = (WindowMarker *)markerPtr;
+
+ if (wmPtr->child != NULL) {
+ Tk_DeleteEventHandler(wmPtr->child, StructureNotifyMask,
+ ChildEventProc, wmPtr);
+ Tk_ManageGeometry(wmPtr->child, (Tk_GeomMgr *) 0, (ClientData)0);
+ Tk_DestroyWindow(wmPtr->child);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateWindowProc --
+ *
+ * Allocate memory and initialize methods for the new window marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the window marker structure.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Marker *
+CreateWindowProc(void)
+{
+ WindowMarker *wmPtr;
+
+ wmPtr = Blt_AssertCalloc(1, sizeof(WindowMarker));
+ wmPtr->classPtr = &windowMarkerClass;
+ return (Marker *)wmPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ChildEventProc --
+ *
+ * This procedure is invoked whenever StructureNotify events occur for a
+ * window that's managed as part of a graph window marker. This
+ * procedure's only purpose is to clean up when windows are deleted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The window is disassociated from the window item when it is
+ * deleted.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+ChildEventProc(ClientData clientData, XEvent *eventPtr)
+{
+ WindowMarker *wmPtr = clientData;
+
+ if (eventPtr->type == DestroyNotify) {
+ wmPtr->child = NULL;
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ChildGeometryProc --
+ *
+ * This procedure is invoked whenever a window that's associated with a
+ * window item changes its requested dimensions.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The size and location on the window of the window may change,
+ * depending on the options specified for the window item.
+ *
+ *---------------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static void
+ChildGeometryProc(ClientData clientData, Tk_Window tkwin)
+{
+ WindowMarker *wmPtr = clientData;
+
+ if (wmPtr->reqWidth == 0) {
+ wmPtr->width = Tk_ReqWidth(tkwin);
+ }
+ if (wmPtr->reqHeight == 0) {
+ wmPtr->height = Tk_ReqHeight(tkwin);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ChildCustodyProc --
+ *
+ * This procedure is invoked when an embedded window has been stolen by
+ * another geometry manager. The information and memory associated with
+ * the widget is released.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Arranges for the graph to be redrawn without the embedded widget at
+ * the next idle point.
+ *
+ *---------------------------------------------------------------------------
+ */
+ /* ARGSUSED */
+static void
+ChildCustodyProc(ClientData clientData, Tk_Window tkwin)
+{
+ Marker *markerPtr = clientData;
+ Graph *graphPtr;
+
+ graphPtr = markerPtr->obj.graphPtr;
+ markerPtr->flags |= DELETE_PENDING;
+ Tcl_EventuallyFree(markerPtr, FreeMarker);
+ /*
+ * Not really needed. We should get an Expose event when the child window
+ * is unmapped.
+ */
+ Blt_EventuallyRedrawGraph(graphPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapLineProc --
+ *
+ * Calculate the layout position for a line marker. Positional
+ * information is saved in the marker. The line positions are stored in
+ * an array of points (malloc'ed).
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapLineProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+ Point2d *srcPtr, *pend;
+ Segment2d *segments, *segPtr;
+ Point2d p, q;
+ Region2d extents;
+
+ lmPtr->nSegments = 0;
+ if (lmPtr->segments != NULL) {
+ Blt_Free(lmPtr->segments);
+ }
+ if (markerPtr->nWorldPts < 2) {
+ return; /* Too few points */
+ }
+ Blt_GraphExtents(graphPtr, &extents);
+
+ /*
+ * Allow twice the number of world coordinates. The line will represented
+ * as series of line segments, not one continous polyline. This is
+ * because clipping against the plot area may chop the line into several
+ * disconnected segments.
+ */
+ segments = Blt_AssertMalloc(markerPtr->nWorldPts * sizeof(Segment2d));
+ srcPtr = markerPtr->worldPts;
+ p = MapPoint(srcPtr, &markerPtr->axes);
+ p.x += markerPtr->xOffset;
+ p.y += markerPtr->yOffset;
+
+ segPtr = segments;
+ for (srcPtr++, pend = markerPtr->worldPts + markerPtr->nWorldPts;
+ srcPtr < pend; srcPtr++) {
+ Point2d next;
+
+ next = MapPoint(srcPtr, &markerPtr->axes);
+ next.x += markerPtr->xOffset;
+ next.y += markerPtr->yOffset;
+ q = next;
+ if (Blt_LineRectClip(&extents, &p, &q)) {
+ segPtr->p = p;
+ segPtr->q = q;
+ segPtr++;
+ }
+ p = next;
+ }
+ lmPtr->nSegments = segPtr - segments;
+ lmPtr->segments = segments;
+ markerPtr->clipped = (lmPtr->nSegments == 0);
+}
+
+static int
+PointInLineProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+
+ return Blt_PointInSegments(samplePtr, lmPtr->segments, lmPtr->nSegments,
+ (double)markerPtr->obj.graphPtr->halo);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInLineProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInLineProc(Marker *markerPtr, Region2d *extsPtr, int enclosed)
+{
+ if (markerPtr->nWorldPts < 2) {
+ return FALSE;
+ }
+ if (enclosed) {
+ Point2d *pp, *pend;
+
+ for (pp = markerPtr->worldPts, pend = pp + markerPtr->nWorldPts;
+ pp < pend; pp++) {
+ Point2d p;
+
+ p = MapPoint(pp, &markerPtr->axes);
+ if ((p.x < extsPtr->left) && (p.x > extsPtr->right) &&
+ (p.y < extsPtr->top) && (p.y > extsPtr->bottom)) {
+ return FALSE;
+ }
+ }
+ return TRUE; /* All points inside bounding box. */
+ } else {
+ int count;
+ Point2d *pp, *pend;
+
+ count = 0;
+ for (pp = markerPtr->worldPts, pend = pp + (markerPtr->nWorldPts - 1);
+ pp < pend; pp++) {
+ Point2d p, q;
+
+ p = MapPoint(pp, &markerPtr->axes);
+ q = MapPoint(pp + 1, &markerPtr->axes);
+ if (Blt_LineRectClip(extsPtr, &p, &q)) {
+ count++;
+ }
+ }
+ return (count > 0); /* At least 1 segment passes through
+ * region. */
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DrawLineProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+DrawLineProc(Marker *markerPtr, Drawable drawable)
+{
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+
+ if (lmPtr->nSegments > 0) {
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ Blt_Draw2DSegments(graphPtr->display, drawable, lmPtr->gc,
+ lmPtr->segments, lmPtr->nSegments);
+ if (lmPtr->xor) { /* Toggle the drawing state */
+ lmPtr->xorState = (lmPtr->xorState == 0);
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureLineProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a line marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as line width, colors, dashes,
+ * etc. get set for markerPtr; old resources get freed, if there were
+ * any. The marker is eventually redisplayed.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ConfigureLineProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+ GC newGC;
+ XGCValues gcValues;
+ unsigned long gcMask;
+ Drawable drawable;
+
+ drawable = Tk_WindowId(graphPtr->tkwin);
+ gcMask = (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
+ if (lmPtr->outlineColor != NULL) {
+ gcMask |= GCForeground;
+ gcValues.foreground = lmPtr->outlineColor->pixel;
+ }
+ if (lmPtr->fillColor != NULL) {
+ gcMask |= GCBackground;
+ gcValues.background = lmPtr->fillColor->pixel;
+ }
+ gcValues.cap_style = lmPtr->capStyle;
+ gcValues.join_style = lmPtr->joinStyle;
+ gcValues.line_width = LineWidth(lmPtr->lineWidth);
+ gcValues.line_style = LineSolid;
+ if (LineIsDashed(lmPtr->dashes)) {
+ gcValues.line_style =
+ (gcMask & GCBackground) ? LineDoubleDash : LineOnOffDash;
+ }
+ if (lmPtr->xor) {
+ unsigned long pixel;
+ gcValues.function = GXxor;
+
+ gcMask |= GCFunction;
+ if (graphPtr->plotBg == NULL) {
+ pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin));
+ } else {
+ pixel = Blt_BackgroundBorderColor(graphPtr->plotBg)->pixel;
+ }
+ if (gcMask & GCBackground) {
+ gcValues.background ^= pixel;
+ }
+ gcValues.foreground ^= pixel;
+ if (drawable != None) {
+ DrawLineProc(markerPtr, drawable);
+ }
+ }
+ newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
+ if (lmPtr->gc != NULL) {
+ Blt_FreePrivateGC(graphPtr->display, lmPtr->gc);
+ }
+ if (LineIsDashed(lmPtr->dashes)) {
+ Blt_SetDashes(graphPtr->display, newGC, &lmPtr->dashes);
+ }
+ lmPtr->gc = newGC;
+ if (lmPtr->xor) {
+ if (drawable != None) {
+ MapLineProc(markerPtr);
+ DrawLineProc(markerPtr, drawable);
+ }
+ return TCL_OK;
+ }
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * LineToPostscriptProc --
+ *
+ * Prints postscript commands to display the connect line. Dashed lines
+ * need to be handled specially, especially if a background color is
+ * designated.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * PostScript output commands are saved in the interpreter
+ * (infoPtr->interp) result field.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+LineToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+
+ if (lmPtr->nSegments > 0) {
+ Blt_Ps_XSetLineAttributes(ps, lmPtr->outlineColor,
+ lmPtr->lineWidth, &lmPtr->dashes, lmPtr->capStyle,
+ lmPtr->joinStyle);
+ if ((LineIsDashed(lmPtr->dashes)) && (lmPtr->fillColor != NULL)) {
+ Blt_Ps_Append(ps, "/DashesProc {\n gsave\n ");
+ Blt_Ps_XSetBackground(ps, lmPtr->fillColor);
+ Blt_Ps_Append(ps, " ");
+ Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL);
+ Blt_Ps_VarAppend(ps,
+ "stroke\n",
+ " grestore\n",
+ "} def\n", (char *)NULL);
+ } else {
+ Blt_Ps_Append(ps, "/DashesProc {} def\n");
+ }
+ Blt_Ps_Draw2DSegments(ps, lmPtr->segments, lmPtr->nSegments);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeLineProc --
+ *
+ * Destroys the structure and attributes of a line marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Line attributes (GCs, colors, stipple, etc) get released. Memory is
+ * deallocated, X resources are freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreeLineProc(Marker *markerPtr)
+{
+ LineMarker *lmPtr = (LineMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (lmPtr->gc != NULL) {
+ Blt_FreePrivateGC(graphPtr->display, lmPtr->gc);
+ }
+ if (lmPtr->segments != NULL) {
+ Blt_Free(lmPtr->segments);
+ }
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateLineProc --
+ *
+ * Allocate memory and initialize methods for a new line marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the line marker structure.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Marker *
+CreateLineProc(void)
+{
+ LineMarker *lmPtr;
+
+ lmPtr = Blt_AssertCalloc(1, sizeof(LineMarker));
+ lmPtr->classPtr = &lineMarkerClass;
+ lmPtr->xor = FALSE;
+ lmPtr->capStyle = CapButt;
+ lmPtr->joinStyle = JoinMiter;
+ return (Marker *)lmPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * MapPolygonProc --
+ *
+ * Calculate the layout position for a polygon marker. Positional
+ * information is saved in the polygon in an array of points (malloc'ed).
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+MapPolygonProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+ Point2d *screenPts;
+ Region2d extents;
+ int nScreenPts;
+
+ if (pmPtr->outlinePts != NULL) {
+ Blt_Free(pmPtr->outlinePts);
+ pmPtr->outlinePts = NULL;
+ pmPtr->nOutlinePts = 0;
+ }
+ if (pmPtr->fillPts != NULL) {
+ Blt_Free(pmPtr->fillPts);
+ pmPtr->fillPts = NULL;
+ pmPtr->nFillPts = 0;
+ }
+ if (pmPtr->screenPts != NULL) {
+ Blt_Free(pmPtr->screenPts);
+ pmPtr->screenPts = NULL;
+ }
+ if (markerPtr->nWorldPts < 3) {
+ return; /* Too few points */
+ }
+
+ /*
+ * Allocate and fill a temporary array to hold the screen coordinates of
+ * the polygon.
+ */
+ nScreenPts = markerPtr->nWorldPts + 1;
+ screenPts = Blt_AssertMalloc((nScreenPts + 1) * sizeof(Point2d));
+ {
+ Point2d *sp, *dp, *send;
+
+ dp = screenPts;
+ for (sp = markerPtr->worldPts, send = sp + markerPtr->nWorldPts;
+ sp < send; sp++) {
+ *dp = MapPoint(sp, &markerPtr->axes);
+ dp->x += markerPtr->xOffset;
+ dp->y += markerPtr->yOffset;
+ dp++;
+ }
+ *dp = screenPts[0];
+ }
+ Blt_GraphExtents(graphPtr, &extents);
+ markerPtr->clipped = TRUE;
+ if (pmPtr->fill.fgColor != NULL) { /* Polygon fill required. */
+ Point2d *fillPts;
+ int n;
+
+ fillPts = Blt_AssertMalloc(sizeof(Point2d) * nScreenPts * 3);
+ n = Blt_PolyRectClip(&extents, screenPts, markerPtr->nWorldPts,fillPts);
+ if (n < 3) {
+ Blt_Free(fillPts);
+ } else {
+ pmPtr->nFillPts = n;
+ pmPtr->fillPts = fillPts;
+ markerPtr->clipped = FALSE;
+ }
+ }
+ if ((pmPtr->outline.fgColor != NULL) && (pmPtr->lineWidth > 0)) {
+ Segment2d *outlinePts;
+ Segment2d *segPtr;
+ Point2d *sp, *send;
+
+ /*
+ * Generate line segments representing the polygon outline. The
+ * resulting outline may or may not be closed from viewport clipping.
+ */
+ outlinePts = Blt_Malloc(nScreenPts * sizeof(Segment2d));
+ if (outlinePts == NULL) {
+ return; /* Can't allocate point array */
+ }
+ /*
+ * Note that this assumes that the point array contains an extra point
+ * that closes the polygon.
+ */
+ segPtr = outlinePts;
+ for (sp = screenPts, send = sp + (nScreenPts - 1); sp < send; sp++) {
+ segPtr->p = sp[0];
+ segPtr->q = sp[1];
+ if (Blt_LineRectClip(&extents, &segPtr->p, &segPtr->q)) {
+ segPtr++;
+ }
+ }
+ pmPtr->nOutlinePts = segPtr - outlinePts;
+ pmPtr->outlinePts = outlinePts;
+ if (pmPtr->nOutlinePts > 0) {
+ markerPtr->clipped = FALSE;
+ }
+ }
+ pmPtr->screenPts = screenPts;
+}
+
+static int
+PointInPolygonProc(Marker *markerPtr, Point2d *samplePtr)
+{
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+
+ if ((markerPtr->nWorldPts >= 3) && (pmPtr->screenPts != NULL)) {
+ return Blt_PointInPolygon(samplePtr, pmPtr->screenPts,
+ markerPtr->nWorldPts + 1);
+ }
+ return FALSE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RegionInPolygonProc --
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+RegionInPolygonProc(Marker *markerPtr, Region2d *extsPtr, int enclosed)
+{
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+
+ if ((markerPtr->nWorldPts >= 3) && (pmPtr->screenPts != NULL)) {
+ return Blt_RegionInPolygon(extsPtr, pmPtr->screenPts,
+ markerPtr->nWorldPts, enclosed);
+ }
+ return FALSE;
+}
+
+static void
+DrawPolygonProc(Marker *markerPtr, Drawable drawable)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+
+ /* Draw polygon fill region */
+ if ((pmPtr->nFillPts > 0) && (pmPtr->fill.fgColor != NULL)) {
+ XPoint *dp, *points;
+ Point2d *sp, *send;
+
+ points = Blt_Malloc(pmPtr->nFillPts * sizeof(XPoint));
+ if (points == NULL) {
+ return;
+ }
+ dp = points;
+ for (sp = pmPtr->fillPts, send = sp + pmPtr->nFillPts; sp < send;
+ sp++) {
+ dp->x = (short int)sp->x;
+ dp->y = (short int)sp->y;
+ dp++;
+ }
+
+ XFillPolygon(graphPtr->display, drawable, pmPtr->fillGC, points,
+ pmPtr->nFillPts, Complex, CoordModeOrigin);
+ Blt_Free(points);
+ }
+ /* and then the outline */
+ if ((pmPtr->nOutlinePts > 0) && (pmPtr->lineWidth > 0) &&
+ (pmPtr->outline.fgColor != NULL)) {
+ Blt_Draw2DSegments(graphPtr->display, drawable, pmPtr->outlineGC,
+ pmPtr->outlinePts, pmPtr->nOutlinePts);
+ }
+}
+
+
+static void
+PolygonToPostscriptProc(Marker *markerPtr, Blt_Ps ps)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+
+ if (pmPtr->fill.fgColor != NULL) {
+
+ /*
+ * Options: fg bg
+ * Draw outline only.
+ * x Draw solid or stipple.
+ * x x Draw solid or stipple.
+ */
+
+ /* Create a path to use for both the polygon and its outline. */
+ Blt_Ps_Polyline(ps, pmPtr->fillPts, pmPtr->nFillPts);
+
+ /* If the background fill color was specified, draw the polygon in a
+ * solid fashion with that color. */
+ if (pmPtr->fill.bgColor != NULL) {
+ /* Draw the solid background as the background layer of the opaque
+ * stipple */
+ Blt_Ps_XSetBackground(ps, pmPtr->fill.bgColor);
+ /* Retain the path. We'll need it for the foreground layer. */
+ Blt_Ps_Append(ps, "gsave fill grestore\n");
+ }
+ Blt_Ps_XSetForeground(ps, pmPtr->fill.fgColor);
+ if (pmPtr->stipple != None) {
+ /* Draw the stipple in the foreground color. */
+ Blt_Ps_XSetStipple(ps, graphPtr->display, pmPtr->stipple);
+ } else {
+ Blt_Ps_Append(ps, "fill\n");
+ }
+ }
+
+ /* Draw the outline in the foreground color. */
+ if ((pmPtr->lineWidth > 0) && (pmPtr->outline.fgColor != NULL)) {
+
+ /* Set up the line attributes. */
+ Blt_Ps_XSetLineAttributes(ps, pmPtr->outline.fgColor,
+ pmPtr->lineWidth, &pmPtr->dashes, pmPtr->capStyle,
+ pmPtr->joinStyle);
+
+ /*
+ * Define on-the-fly a PostScript macro "DashesProc" that will be
+ * executed for each call to the Polygon drawing routine. If the line
+ * isn't dashed, simply make this an empty definition.
+ */
+ if ((pmPtr->outline.bgColor != NULL) && (LineIsDashed(pmPtr->dashes))) {
+ Blt_Ps_Append(ps, "/DashesProc {\ngsave\n ");
+ Blt_Ps_XSetBackground(ps, pmPtr->outline.bgColor);
+ Blt_Ps_Append(ps, " ");
+ Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL);
+ Blt_Ps_Append(ps, "stroke\n grestore\n} def\n");
+ } else {
+ Blt_Ps_Append(ps, "/DashesProc {} def\n");
+ }
+ Blt_Ps_Draw2DSegments(ps, pmPtr->outlinePts, pmPtr->nOutlinePts);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigurePolygonProc --
+ *
+ * This procedure is called to process an objv/objc list, plus the Tk
+ * option database, in order to configure (or reconfigure) a polygon
+ * marker.
+ *
+ * Results:
+ * A standard TCL result. If TCL_ERROR is returned, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as polygon color, dashes, fillstyle,
+ * etc. get set for markerPtr; old resources get freed, if there were
+ * any. The marker is eventually redisplayed.
+ *
+ * --------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ConfigurePolygonProc(Marker *markerPtr)
+{
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+ GC newGC;
+ XGCValues gcValues;
+ unsigned long gcMask;
+ Drawable drawable;
+
+ drawable = Tk_WindowId(graphPtr->tkwin);
+ gcMask = (GCLineWidth | GCLineStyle);
+ if (pmPtr->outline.fgColor != NULL) {
+ gcMask |= GCForeground;
+ gcValues.foreground = pmPtr->outline.fgColor->pixel;
+ }
+ if (pmPtr->outline.bgColor != NULL) {
+ gcMask |= GCBackground;
+ gcValues.background = pmPtr->outline.bgColor->pixel;
+ }
+ gcMask |= (GCCapStyle | GCJoinStyle);
+ gcValues.cap_style = pmPtr->capStyle;
+ gcValues.join_style = pmPtr->joinStyle;
+ gcValues.line_style = LineSolid;
+ gcValues.dash_offset = 0;
+ gcValues.line_width = LineWidth(pmPtr->lineWidth);
+ if (LineIsDashed(pmPtr->dashes)) {
+ gcValues.line_style = (pmPtr->outline.bgColor == NULL)
+ ? LineOnOffDash : LineDoubleDash;
+ }
+ if (pmPtr->xor) {
+ unsigned long pixel;
+ gcValues.function = GXxor;
+
+ gcMask |= GCFunction;
+ if (graphPtr->plotBg == NULL) {
+ /* The graph's color option may not have been set yet */
+ pixel = WhitePixelOfScreen(Tk_Screen(graphPtr->tkwin));
+ } else {
+ pixel = Blt_BackgroundBorderColor(graphPtr->plotBg)->pixel;
+ }
+ if (gcMask & GCBackground) {
+ gcValues.background ^= pixel;
+ }
+ gcValues.foreground ^= pixel;
+ if (drawable != None) {
+ DrawPolygonProc(markerPtr, drawable);
+ }
+ }
+ newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
+ if (LineIsDashed(pmPtr->dashes)) {
+ Blt_SetDashes(graphPtr->display, newGC, &pmPtr->dashes);
+ }
+ if (pmPtr->outlineGC != NULL) {
+ Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC);
+ }
+ pmPtr->outlineGC = newGC;
+
+ gcMask = 0;
+ if (pmPtr->fill.fgColor != NULL) {
+ gcMask |= GCForeground;
+ gcValues.foreground = pmPtr->fill.fgColor->pixel;
+ }
+ if (pmPtr->fill.bgColor != NULL) {
+ gcMask |= GCBackground;
+ gcValues.background = pmPtr->fill.bgColor->pixel;
+ }
+ if (pmPtr->stipple != None) {
+ gcValues.stipple = pmPtr->stipple;
+ gcValues.fill_style = (pmPtr->fill.bgColor != NULL)
+ ? FillOpaqueStippled : FillStippled;
+ gcMask |= (GCStipple | GCFillStyle);
+ }
+ newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
+ if (pmPtr->fillGC != NULL) {
+ Tk_FreeGC(graphPtr->display, pmPtr->fillGC);
+ }
+ pmPtr->fillGC = newGC;
+
+ if ((gcMask == 0) && !(graphPtr->flags & RESET_AXES) && (pmPtr->xor)) {
+ if (drawable != None) {
+ MapPolygonProc(markerPtr);
+ DrawPolygonProc(markerPtr, drawable);
+ }
+ return TCL_OK;
+ }
+ markerPtr->flags |= MAP_ITEM;
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ graphPtr->flags |= RESET_WORLD;
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreePolygonProc --
+ *
+ * Release memory and resources allocated for the polygon element.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Everything associated with the polygon element is freed up.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+FreePolygonProc(Marker *markerPtr)
+{
+ PolygonMarker *pmPtr = (PolygonMarker *)markerPtr;
+ Graph *graphPtr = markerPtr->obj.graphPtr;
+
+ if (pmPtr->fillGC != NULL) {
+ Tk_FreeGC(graphPtr->display, pmPtr->fillGC);
+ }
+ if (pmPtr->outlineGC != NULL) {
+ Blt_FreePrivateGC(graphPtr->display, pmPtr->outlineGC);
+ }
+ if (pmPtr->fillPts != NULL) {
+ Blt_Free(pmPtr->fillPts);
+ }
+ if (pmPtr->outlinePts != NULL) {
+ Blt_Free(pmPtr->outlinePts);
+ }
+ if (pmPtr->screenPts != NULL) {
+ Blt_Free(pmPtr->screenPts);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreatePolygonProc --
+ *
+ * Allocate memory and initialize methods for the new polygon marker.
+ *
+ * Results:
+ * The pointer to the newly allocated marker structure is returned.
+ *
+ * Side effects:
+ * Memory is allocated for the polygon marker structure.
+ *
+ * --------------------------------------------------------------------------
+ */
+static Marker *
+CreatePolygonProc(void)
+{
+ PolygonMarker *pmPtr;
+
+ pmPtr = Blt_AssertCalloc(1, sizeof(PolygonMarker));
+ pmPtr->classPtr = &polygonMarkerClass;
+ pmPtr->capStyle = CapButt;
+ pmPtr->joinStyle = JoinMiter;
+ return (Marker *)pmPtr;
+}
+
+static int
+GetMarkerFromObj(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr,
+ Marker **markerPtrPtr)
+{
+ Blt_HashEntry *hPtr;
+ const char *string;
+
+ string = Tcl_GetString(objPtr);
+ hPtr = Blt_FindHashEntry(&graphPtr->markers.table, string);
+ if (hPtr != NULL) {
+ *markerPtrPtr = Blt_GetHashValue(hPtr);
+ return TCL_OK;
+ }
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't find marker \"", string,
+ "\" in \"", Tk_PathName(graphPtr->tkwin), (char *)NULL);
+ }
+ return TCL_ERROR;
+}
+
+
+static int
+RenameMarker(Graph *graphPtr, Marker *markerPtr, const char *oldName,
+ const char *newName)
+{
+ int isNew;
+ Blt_HashEntry *hPtr;
+
+ /* Rename the marker only if no marker already exists by that name */
+ hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, newName, &isNew);
+ if (!isNew) {
+ Tcl_AppendResult(graphPtr->interp, "can't rename marker: \"", newName,
+ "\" already exists", (char *)NULL);
+ return TCL_ERROR;
+ }
+ markerPtr->obj.name = Blt_AssertStrdup(newName);
+ markerPtr->hashPtr = hPtr;
+ Blt_SetHashValue(hPtr, (char *)markerPtr);
+
+ /* Delete the old hash entry */
+ hPtr = Blt_FindHashEntry(&graphPtr->markers.table, oldName);
+ Blt_DeleteHashEntry(&graphPtr->markers.table, hPtr);
+ if (oldName != NULL) {
+ Blt_Free(oldName);
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * NamesOp --
+ *
+ * Returns a list of marker identifiers in interp->result;
+ *
+ * Results:
+ * The return value is a standard TCL result.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+NamesOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Tcl_Obj *listObjPtr;
+
+ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ if (objc == 3) {
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(markerPtr->obj.name, -1));
+ }
+ } else {
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+ int i;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ for (i = 3; i < objc; i++) {
+ const char *pattern;
+
+ pattern = Tcl_GetString(objv[i]);
+ if (Tcl_StringMatch(markerPtr->obj.name, pattern)) {
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(markerPtr->obj.name, -1));
+ break;
+ }
+ }
+ }
+ }
+ Tcl_SetObjResult(interp, listObjPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * BindOp --
+ *
+ * .g element bind elemName sequence command
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+BindOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ if (objc == 3) {
+ Blt_HashEntry *hp;
+ Blt_HashSearch iter;
+ Tcl_Obj *listObjPtr;
+
+ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ for (hp = Blt_FirstHashEntry(&graphPtr->markers.tagTable, &iter);
+ hp != NULL; hp = Blt_NextHashEntry(&iter)) {
+ const char *tag;
+ Tcl_Obj *objPtr;
+
+ tag = Blt_GetHashKey(&graphPtr->markers.tagTable, hp);
+ objPtr = Tcl_NewStringObj(tag, -1);
+ Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+ }
+ Tcl_SetObjResult(interp, listObjPtr);
+ return TCL_OK;
+ }
+ return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable,
+ Blt_MakeMarkerTag(graphPtr, Tcl_GetString(objv[3])),
+ objc - 4, objv + 4);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CgetOp --
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+CgetOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Marker *markerPtr;
+
+ if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Blt_ConfigureValueFromObj(interp, graphPtr->tkwin,
+ markerPtr->classPtr->configSpecs, (char *)markerPtr, objv[4], 0)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureOp --
+ *
+ * Results:
+ * The return value is a standard TCL result.
+ *
+ * Side Effects:
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+ConfigureOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Marker *markerPtr;
+ Tcl_Obj *const *options;
+ const char *oldName;
+ const char *string;
+ int flags = BLT_CONFIG_OBJV_ONLY;
+ int nNames, nOpts;
+ int i;
+ int under;
+
+ markerPtr = NULL; /* Suppress compiler warning. */
+
+ /* Figure out where the option value pairs begin */
+ objc -= 3;
+ objv += 3;
+ for (i = 0; i < objc; i++) {
+ string = Tcl_GetString(objv[i]);
+ if (string[0] == '-') {
+ break;
+ }
+ if (GetMarkerFromObj(interp, graphPtr, objv[i], &markerPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ nNames = i; /* # of element names specified */
+ nOpts = objc - i; /* # of options specified */
+ options = objv + nNames; /* Start of options in objv */
+
+ for (i = 0; i < nNames; i++) {
+ GetMarkerFromObj(interp, graphPtr, objv[i], &markerPtr);
+ if (nOpts == 0) {
+ return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin,
+ markerPtr->classPtr->configSpecs, (char *)markerPtr,
+ (Tcl_Obj *)NULL, flags);
+ } else if (nOpts == 1) {
+ return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin,
+ markerPtr->classPtr->configSpecs, (char *)markerPtr,
+ options[0], flags);
+ }
+ /* Save the old marker name. */
+ oldName = markerPtr->obj.name;
+ under = markerPtr->drawUnder;
+ if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin,
+ markerPtr->classPtr->configSpecs, nOpts, options,
+ (char *)markerPtr, flags) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (oldName != markerPtr->obj.name) {
+ if (RenameMarker(graphPtr, markerPtr, oldName, markerPtr->obj.name)
+ != TCL_OK) {
+ markerPtr->obj.name = oldName;
+ return TCL_ERROR;
+ }
+ }
+ if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) {
+
+ return TCL_ERROR;
+ }
+ if (markerPtr->drawUnder != under) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateOp --
+ *
+ * This procedure creates and initializes a new marker.
+ *
+ * Results:
+ * The return value is a pointer to a structure describing the new
+ * element. If an error occurred, then the return value is NULL and an
+ * error message is left in interp->result.
+ *
+ * Side effects:
+ * Memory is allocated, etc.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+CreateOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Marker *markerPtr;
+ Blt_HashEntry *hPtr;
+ int isNew;
+ ClassId classId;
+ int i;
+ const char *name;
+ char ident[200];
+ const char *string;
+ char c;
+
+ string = Tcl_GetString(objv[3]);
+ c = string[0];
+ /* Create the new marker based upon the given type */
+ if ((c == 't') && (strcmp(string, "text") == 0)) {
+ classId = CID_MARKER_TEXT;
+ } else if ((c == 'l') && (strcmp(string, "line") == 0)) {
+ classId = CID_MARKER_LINE;
+ } else if ((c == 'p') && (strcmp(string, "polygon") == 0)) {
+ classId = CID_MARKER_POLYGON;
+ } else if ((c == 'i') && (strcmp(string, "image") == 0)) {
+ classId = CID_MARKER_IMAGE;
+ } else if ((c == 'b') && (strcmp(string, "bitmap") == 0)) {
+ classId = CID_MARKER_BITMAP;
+ } else if ((c == 'w') && (strcmp(string, "window") == 0)) {
+ classId = CID_MARKER_WINDOW;
+ } else {
+ Tcl_AppendResult(interp, "unknown marker type \"", string,
+ "\": should be \"text\", \"line\", \"polygon\", \"bitmap\", \"image\", or \
+\"window\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ /* Scan for "-name" option. We need it for the component name */
+ name = NULL;
+ for (i = 4; i < objc; i += 2) {
+ int length;
+
+ string = Tcl_GetStringFromObj(objv[i], &length);
+ if ((length > 1) && (strncmp(string, "-name", length) == 0)) {
+ name = Tcl_GetString(objv[i + 1]);
+ break;
+ }
+ }
+ /* If no name was given for the marker, make up one. */
+ if (name == NULL) {
+ sprintf_s(ident, 200, "marker%d", graphPtr->nextMarkerId++);
+ name = ident;
+ } else if (name[0] == '-') {
+ Tcl_AppendResult(interp, "name of marker \"", name,
+ "\" can't start with a '-'", (char *)NULL);
+ return TCL_ERROR;
+ }
+ markerPtr = CreateMarker(graphPtr, name, classId);
+ if (Blt_ConfigureComponentFromObj(interp, graphPtr->tkwin, name,
+ markerPtr->obj.className, markerPtr->classPtr->configSpecs,
+ objc - 4, objv + 4, (char *)markerPtr, 0) != TCL_OK) {
+ DestroyMarker(markerPtr);
+ return TCL_ERROR;
+ }
+ if ((*markerPtr->classPtr->configProc) (markerPtr) != TCL_OK) {
+ DestroyMarker(markerPtr);
+ return TCL_ERROR;
+ }
+ hPtr = Blt_CreateHashEntry(&graphPtr->markers.table, name, &isNew);
+ if (!isNew) {
+ Marker *oldPtr;
+ /*
+ * Marker by the same name already exists. Delete the old marker and
+ * it's list entry. But save the hash entry.
+ */
+ oldPtr = Blt_GetHashValue(hPtr);
+ oldPtr->hashPtr = NULL;
+ DestroyMarker(oldPtr);
+ }
+ Blt_SetHashValue(hPtr, markerPtr);
+ markerPtr->hashPtr = hPtr;
+ /* Unlike elements, new markers are drawn on top of old markers. */
+ markerPtr->link = Blt_Chain_Prepend(graphPtr->markers.displayList,markerPtr);
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DeleteOp --
+ *
+ * Deletes the marker given by markerId.
+ *
+ * Results:
+ * The return value is a standard TCL result.
+ *
+ * Side Effects:
+ * Graph will be redrawn to reflect the new display list.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+DeleteOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ int i;
+
+ for (i = 3; i < objc; i++) {
+ Marker *markerPtr;
+
+ if (GetMarkerFromObj(NULL, graphPtr, objv[i], &markerPtr) == TCL_OK) {
+ markerPtr->flags |= DELETE_PENDING;
+ Tcl_EventuallyFree(markerPtr, FreeMarker);
+ }
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetOp --
+ *
+ * Find the legend entry from the given argument. The argument can be
+ * either a screen position "@x,y" or the name of an element.
+ *
+ * I don't know how useful it is to test with the name of an element.
+ *
+ * Results:
+ * A standard TCL result.
+ *
+ * Side Effects:
+ * Graph will be redrawn to reflect the new legend attributes.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+GetOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Marker *markerPtr;
+ const char *string;
+
+ string = Tcl_GetString(objv[3]);
+ if ((string[0] == 'c') && (strcmp(string, "current") == 0)) {
+ markerPtr = (Marker *)Blt_GetCurrentItem(graphPtr->bindTable);
+ if (markerPtr == NULL) {
+ return TCL_OK; /* Report only on markers. */
+
+ }
+ if ((markerPtr->obj.classId >= CID_MARKER_BITMAP) &&
+ (markerPtr->obj.classId <= CID_MARKER_WINDOW)) {
+ Tcl_SetStringObj(Tcl_GetObjResult(interp),
+ markerPtr->obj.name, -1);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * RelinkOp --
+ *
+ * Reorders the marker (given by the first name) before/after the another
+ * marker (given by the second name) in the marker display list. If no
+ * second name is given, the marker is placed at the beginning/end of the
+ * list.
+ *
+ * Results:
+ * A standard TCL result.
+ *
+ * Side Effects:
+ * Graph will be redrawn to reflect the new display list.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+RelinkOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Blt_ChainLink link, place;
+ Marker *markerPtr;
+ const char *string;
+
+ /* Find the marker to be raised or lowered. */
+ if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ /* Right now it's assumed that all markers are always in the display
+ list. */
+ link = markerPtr->link;
+ Blt_Chain_UnlinkLink(graphPtr->markers.displayList, markerPtr->link);
+
+ place = NULL;
+ if (objc == 5) {
+ if (GetMarkerFromObj(interp, graphPtr, objv[4], &markerPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ place = markerPtr->link;
+ }
+
+ /* Link the marker at its new position. */
+ string = Tcl_GetString(objv[2]);
+ if (string[0] == 'l') {
+ Blt_Chain_LinkAfter(graphPtr->markers.displayList, link, place);
+ } else {
+ Blt_Chain_LinkBefore(graphPtr->markers.displayList, link, place);
+ }
+ if (markerPtr->drawUnder) {
+ graphPtr->flags |= CACHE_DIRTY;
+ }
+ Blt_EventuallyRedrawGraph(graphPtr);
+ return TCL_OK;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FindOp --
+ *
+ * Returns if marker by a given ID currently exists.
+ *
+ * Results:
+ * A standard TCL result.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+FindOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Blt_ChainLink link;
+ Region2d extents;
+ const char *string;
+ int enclosed;
+ int left, right, top, bottom;
+ int mode;
+
+#define FIND_ENCLOSED (1<<0)
+#define FIND_OVERLAPPING (1<<1)
+ string = Tcl_GetString(objv[3]);
+ if (strcmp(string, "enclosed") == 0) {
+ mode = FIND_ENCLOSED;
+ } else if (strcmp(string, "overlapping") == 0) {
+ mode = FIND_OVERLAPPING;
+ } else {
+ Tcl_AppendResult(interp, "bad search type \"", string,
+ ": should be \"enclosed\", or \"overlapping\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+
+ if ((Tcl_GetIntFromObj(interp, objv[4], &left) != TCL_OK) ||
+ (Tcl_GetIntFromObj(interp, objv[5], &top) != TCL_OK) ||
+ (Tcl_GetIntFromObj(interp, objv[6], &right) != TCL_OK) ||
+ (Tcl_GetIntFromObj(interp, objv[7], &bottom) != TCL_OK)) {
+ return TCL_ERROR;
+ }
+ if (left < right) {
+ extents.left = (double)left;
+ extents.right = (double)right;
+ } else {
+ extents.left = (double)right;
+ extents.right = (double)left;
+ }
+ if (top < bottom) {
+ extents.top = (double)top;
+ extents.bottom = (double)bottom;
+ } else {
+ extents.top = (double)bottom;
+ extents.bottom = (double)top;
+ }
+ enclosed = (mode == FIND_ENCLOSED);
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ if (markerPtr->flags & (HIDE|DELETE_PENDING)) {
+ continue;
+ }
+ if ((markerPtr->elemName != NULL) && (IsElementHidden(markerPtr))) {
+ continue;
+ }
+ if ((*markerPtr->classPtr->regionProc)(markerPtr, &extents, enclosed)) {
+ Tcl_Obj *objPtr;
+
+ objPtr = Tcl_GetObjResult(interp);
+ Tcl_SetStringObj(objPtr, markerPtr->obj.name, -1);
+ return TCL_OK;
+ }
+ }
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "", -1);
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ExistsOp --
+ *
+ * Returns if marker by a given ID currently exists.
+ *
+ * Results:
+ * A standard TCL result.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+ExistsOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Blt_HashEntry *hPtr;
+
+ hPtr = Blt_FindHashEntry(&graphPtr->markers.table, Tcl_GetString(objv[3]));
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL));
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TypeOp --
+ *
+ * Returns a symbolic name for the type of the marker whose ID is given.
+ *
+ * Results:
+ * A standard TCL result. interp->result will contain the symbolic type
+ * of the marker.
+ *
+ *---------------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static int
+TypeOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+ Marker *markerPtr;
+ const char *type;
+
+ if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ switch (markerPtr->obj.classId) {
+ case CID_MARKER_BITMAP: type = "bitmap"; break;
+ case CID_MARKER_IMAGE: type = "image"; break;
+ case CID_MARKER_LINE: type = "line"; break;
+ case CID_MARKER_POLYGON: type = "polygon"; break;
+ case CID_MARKER_TEXT: type = "text"; break;
+ case CID_MARKER_WINDOW: type = "window"; break;
+ default: type = "???"; break;
+ }
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), type, -1);
+ return TCL_OK;
+}
+
+/* Public routines */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_MarkerOp --
+ *
+ * This procedure is invoked to process the TCL command that corresponds
+ * to a widget managed by this module. See the user documentation for
+ * details on what it does.
+ *
+ * Results:
+ * A standard TCL result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static Blt_OpSpec markerOps[] =
+{
+ {"bind", 1, BindOp, 3, 6, "marker sequence command",},
+ {"cget", 2, CgetOp, 5, 5, "marker option",},
+ {"configure", 2, ConfigureOp, 4, 0,"marker ?marker?... ?option value?...",},
+ {"create", 2, CreateOp, 4, 0, "type ?option value?...",},
+ {"delete", 1, DeleteOp, 3, 0, "?marker?...",},
+ {"exists", 1, ExistsOp, 4, 4, "marker",},
+ {"find", 1, FindOp, 8, 8, "enclosed|overlapping x1 y1 x2 y2",},
+ {"get", 1, GetOp, 4, 4, "name",},
+ {"lower", 1, RelinkOp, 4, 5, "marker ?afterMarker?",},
+ {"names", 1, NamesOp, 3, 0, "?pattern?...",},
+ {"raise", 1, RelinkOp, 4, 5, "marker ?beforeMarker?",},
+ {"type", 1, TypeOp, 4, 4, "marker",},
+};
+static int nMarkerOps = sizeof(markerOps) / sizeof(Blt_OpSpec);
+
+/*ARGSUSED*/
+int
+Blt_MarkerOp(Graph *graphPtr, Tcl_Interp *interp, int objc,
+ Tcl_Obj *const *objv)
+{
+ GraphMarkerProc *proc;
+ int result;
+
+ proc = Blt_GetOpFromObj(interp, nMarkerOps, markerOps, BLT_OP_ARG2,
+ objc, objv,0);
+ if (proc == NULL) {
+ return TCL_ERROR;
+ }
+ result = (*proc) (graphPtr, interp, objc, objv);
+ return result;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_MarkersToPostScript --
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+Blt_MarkersToPostScript(Graph *graphPtr, Blt_Ps ps, int under)
+{
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_LastLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_PrevLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ if ((markerPtr->classPtr->postscriptProc == NULL) ||
+ (markerPtr->nWorldPts == 0)) {
+ continue;
+ }
+ if (markerPtr->drawUnder != under) {
+ continue;
+ }
+ if (markerPtr->flags & (HIDE|DELETE_PENDING)) {
+ continue;
+ }
+ if ((markerPtr->elemName != NULL) && (IsElementHidden(markerPtr))) {
+ continue;
+ }
+ Blt_Ps_VarAppend(ps, "\n% Marker \"", markerPtr->obj.name,
+ "\" is a ", markerPtr->obj.className, ".\n", (char *)NULL);
+ (*markerPtr->classPtr->postscriptProc) (markerPtr, ps);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_DrawMarkers --
+ *
+ * Calls the individual drawing routines (based on marker type) for each
+ * marker in the display list.
+ *
+ * A marker will not be drawn if
+ *
+ * 1) An element linked to the marker (indicated by elemName) is
+ * currently hidden.
+ *
+ * 2) No coordinates have been specified for the marker.
+ *
+ * 3) The marker is requesting to be drawn at a different level
+ * (above/below the elements) from the current mode.
+ *
+ * 4) The marker is configured as hidden (-hide option).
+ *
+ * 5) The marker isn't visible in the current viewport (i.e. clipped).
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Markers are drawn into the drawable (pixmap) which will eventually
+ * be displayed in the graph window.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+Blt_DrawMarkers(Graph *graphPtr, Drawable drawable, int under)
+{
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_LastLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_PrevLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+
+ if ((markerPtr->nWorldPts == 0) ||
+ (markerPtr->drawUnder != under) ||
+ (markerPtr->clipped) ||
+ (markerPtr->flags & (DELETE_PENDING|HIDE))) {
+ continue;
+ }
+ if ((markerPtr->elemName != NULL) && (IsElementHidden(markerPtr))) {
+ continue;
+ }
+ (*markerPtr->classPtr->drawProc) (markerPtr, drawable);
+ }
+}
+
+void
+Blt_ConfigureMarkers(Graph *graphPtr)
+{
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ (*markerPtr->classPtr->configProc) (markerPtr);
+ }
+}
+
+void
+Blt_MapMarkers(Graph *graphPtr)
+{
+ Blt_ChainLink link;
+
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ if (markerPtr->nWorldPts == 0) {
+ continue;
+ }
+ if (markerPtr->flags & (HIDE|DELETE_PENDING)) {
+ continue;
+ }
+ if ((graphPtr->flags & MAP_ALL) || (markerPtr->flags & MAP_ITEM)) {
+ (*markerPtr->classPtr->mapProc) (markerPtr);
+ markerPtr->flags &= ~MAP_ITEM;
+ }
+ }
+}
+
+void
+Blt_DestroyMarkers(Graph *graphPtr)
+{
+ Blt_HashEntry *hPtr;
+ Blt_HashSearch iter;
+
+ for (hPtr = Blt_FirstHashEntry(&graphPtr->markers.table, &iter);
+ hPtr != NULL; hPtr = Blt_NextHashEntry(&iter)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_GetHashValue(hPtr);
+ /*
+ * Dereferencing the pointer to the hash table prevents the hash table
+ * entry from being automatically deleted.
+ */
+ markerPtr->hashPtr = NULL;
+ DestroyMarker(markerPtr);
+ }
+ Blt_DeleteHashTable(&graphPtr->markers.table);
+ Blt_DeleteHashTable(&graphPtr->markers.tagTable);
+ Blt_Chain_Destroy(graphPtr->markers.displayList);
+}
+
+Marker *
+Blt_NearestMarker(
+ Graph *graphPtr,
+ int x, int y, /* Screen coordinates */
+ int under)
+{
+ Blt_ChainLink link;
+ Point2d point;
+
+ point.x = (double)x;
+ point.y = (double)y;
+ for (link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link != NULL; link = Blt_Chain_NextLink(link)) {
+ Marker *markerPtr;
+
+ markerPtr = Blt_Chain_GetValue(link);
+ if ((markerPtr->nWorldPts == 0) ||
+ (markerPtr->flags & (HIDE|DELETE_PENDING|MAP_ITEM))) {
+ continue; /* Don't consider markers that are
+ * pending to be mapped. Even if the
+ * marker has already been mapped, the
+ * coordinates could be invalid now.
+ * Better to pick no marker than the
+ * wrong marker. */
+
+ }
+ if ((markerPtr->elemName != NULL) && (IsElementHidden(markerPtr))) {
+ continue;
+ }
+ if ((markerPtr->drawUnder == under) &&
+ (markerPtr->state == STATE_NORMAL)) {
+ if ((*markerPtr->classPtr->pointProc) (markerPtr, &point)) {
+ return markerPtr;
+ }
+ }
+ }
+ return NULL;
+}
+
+ClientData
+Blt_MakeMarkerTag(Graph *graphPtr, const char *tagName)
+{
+ Blt_HashEntry *hPtr;
+ int isNew;
+
+ assert(tagName != NULL);
+ hPtr = Blt_CreateHashEntry(&graphPtr->markers.tagTable, tagName, &isNew);
+ return Blt_GetHashKey(&graphPtr->markers.tagTable, hPtr);
+}
+
+
+#ifdef notdef
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ConfigureArrows --
+ *
+ * If arrowheads have been requested for a line, this procedure makes
+ * arrangements for the arrowheads.
+ *
+ * Results:
+ * Always returns TCL_OK.
+ *
+ * Side effects:
+ * Information in linePtr is set up for one or two arrowheads. the
+ * firstArrowPtr and lastArrowPtr polygons are allocated and initialized,
+ * if need be, and the end points of the line are adjusted so that a
+ * thick line doesn't stick out past the arrowheads.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+ConfigureArrows(canvas, linePtr)
+ Tk_Canvas canvas; /* Canvas in which arrows will be
+ * displayed (interp and tkwin fields
+ * are needed). */
+ LineItem *linePtr; /* Item to configure for arrows. */
+{
+ double *poly, *coordPtr;
+ double dx, dy, length, sinTheta, cosTheta, temp;
+ double fracHeight; /* Line width as fraction of arrowhead
+ * width. */
+ double backup; /* Distance to backup end points so
+ * the line ends in the middle of the
+ * arrowhead. */
+ double vertX, vertY; /* Position of arrowhead vertex. */
+ double shapeA, shapeB, shapeC; /* Adjusted coordinates (see
+ * explanation below). */
+ double width;
+ Tk_State state = linePtr->header.state;
+
+ if (linePtr->numPoints <2) {
+ return TCL_OK;
+ }
+
+ if(state == TK_STATE_NULL) {
+ state = ((TkCanvas *)canvas)->canvas_state;
+ }
+
+ width = linePtr->outline.width;
+ if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) {
+ if (linePtr->outline.activeWidth>width) {
+ width = linePtr->outline.activeWidth;
+ }
+ } else if (state==TK_STATE_DISABLED) {
+ if (linePtr->outline.disabledWidth>0) {
+ width = linePtr->outline.disabledWidth;
+ }
+ }
+
+ /*
+ * The code below makes a tiny increase in the shape parameters for the
+ * line. This is a bit of a hack, but it seems to result in displays that
+ * more closely approximate the specified parameters. Without the
+ * adjustment, the arrows come out smaller than expected.
+ */
+
+ shapeA = linePtr->arrowShapeA + 0.001;
+ shapeB = linePtr->arrowShapeB + 0.001;
+ shapeC = linePtr->arrowShapeC + width/2.0 + 0.001;
+
+ /*
+ * If there's an arrowhead on the first point of the line, compute its
+ * polygon and adjust the first point of the line so that the line doesn't
+ * stick out past the leading edge of the arrowhead.
+ */
+
+ fracHeight = (width/2.0)/shapeC;
+ backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0;
+ if (linePtr->arrow != ARROWS_LAST) {
+ poly = linePtr->firstArrowPtr;
+ if (poly == NULL) {
+ poly = (double *) ckalloc((unsigned)
+ (2*PTS_IN_ARROW*sizeof(double)));
+ poly[0] = poly[10] = linePtr->coordPtr[0];
+ poly[1] = poly[11] = linePtr->coordPtr[1];
+ linePtr->firstArrowPtr = poly;
+ }
+ dx = poly[0] - linePtr->coordPtr[2];
+ dy = poly[1] - linePtr->coordPtr[3];
+ length = hypot(dx, dy);
+ if (length == 0) {
+ sinTheta = cosTheta = 0.0;
+ } else {
+ sinTheta = dy/length;
+ cosTheta = dx/length;
+ }
+ vertX = poly[0] - shapeA*cosTheta;
+ vertY = poly[1] - shapeA*sinTheta;
+ temp = shapeC*sinTheta;
+ poly[2] = poly[0] - shapeB*cosTheta + temp;
+ poly[8] = poly[2] - 2*temp;
+ temp = shapeC*cosTheta;
+ poly[3] = poly[1] - shapeB*sinTheta - temp;
+ poly[9] = poly[3] + 2*temp;
+ poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
+ poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
+ poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
+ poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
+
+ /*
+ * Polygon done. Now move the first point towards the second so that
+ * the corners at the end of the line are inside the arrowhead.
+ */
+
+ linePtr->coordPtr[0] = poly[0] - backup*cosTheta;
+ linePtr->coordPtr[1] = poly[1] - backup*sinTheta;
+ }
+
+ /*
+ * Similar arrowhead calculation for the last point of the line.
+ */
+
+ if (linePtr->arrow != ARROWS_FIRST) {
+ coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2);
+ poly = linePtr->lastArrowPtr;
+ if (poly == NULL) {
+ poly = (double *) ckalloc((unsigned)
+ (2*PTS_IN_ARROW*sizeof(double)));
+ poly[0] = poly[10] = coordPtr[2];
+ poly[1] = poly[11] = coordPtr[3];
+ linePtr->lastArrowPtr = poly;
+ }
+ dx = poly[0] - coordPtr[0];
+ dy = poly[1] - coordPtr[1];
+ length = hypot(dx, dy);
+ if (length == 0) {
+ sinTheta = cosTheta = 0.0;
+ } else {
+ sinTheta = dy/length;
+ cosTheta = dx/length;
+ }
+ vertX = poly[0] - shapeA*cosTheta;
+ vertY = poly[1] - shapeA*sinTheta;
+ temp = shapeC*sinTheta;
+ poly[2] = poly[0] - shapeB*cosTheta + temp;
+ poly[8] = poly[2] - 2*temp;
+ temp = shapeC*cosTheta;
+ poly[3] = poly[1] - shapeB*sinTheta - temp;
+ poly[9] = poly[3] + 2*temp;
+ poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight);
+ poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight);
+ poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight);
+ poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight);
+ coordPtr[2] = poly[0] - backup*cosTheta;
+ coordPtr[3] = poly[1] - backup*sinTheta;
+ }
+
+ return TCL_OK;
+}
+#endif