OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltGrAxis.c
diff --git a/util/src/TclTk/blt2.5/generic/bltGrAxis.c b/util/src/TclTk/blt2.5/generic/bltGrAxis.c
deleted file mode 100644 (file)
index d60970f..0000000
+++ /dev/null
@@ -1,4568 +0,0 @@
-
-/*
- * bltGrAxis.c --
- *
- *     This module implements coordinate axes for the BLT graph widget.
- *
- * Copyright 1993-1998 Lucent Technologies, Inc.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that the copyright notice and warranty
- * disclaimer appear in supporting documentation, and that the names
- * of Lucent Technologies any of their entities not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.
- *
- * Lucent Technologies disclaims all warranties with regard to this
- * software, including all implied warranties of merchantability and
- * fitness.  In no event shall Lucent Technologies be liable for any
- * special, indirect or consequential damages or any damages
- * whatsoever resulting from loss of use, data or profits, whether in
- * an action of contract, negligence or other tortuous action, arising
- * out of or in connection with the use or performance of this
- * software.
- */
-
-#include "bltGraph.h"
-#include "bltGrElem.h"
-#include <X11/Xutil.h>
-
-#define DEF_NUM_TICKS          4       /* Each minor tick is 20% */
-#define STATIC_TICK_SPACE      10
-
-#define TICK_LABEL_SIZE                200
-#define MAXTICKS               10001
-
-#define CLAMP(val,low,high)    \
-       (((val) < (low)) ? (low) : ((val) > (high)) ? (high) : (val))
-
-/*
- * Round x in terms of units
- */
-#define UROUND(x,u)            (Round((x)/(u))*(u))
-#define UCEIL(x,u)             (ceil((x)/(u))*(u))
-#define UFLOOR(x,u)            (floor((x)/(u))*(u))
-
-#define LENGTH_MAJOR_TICK      0.030   /* Length of a major tick */
-#define LENGTH_MINOR_TICK      0.015   /* Length of a minor (sub)tick */
-#define LENGTH_LABEL_TICK      0.040   /* Distance from graph to start of the
-                                        * label */
-#define NUMDIGITS              15      /* Specifies the number of
-                                        * digits of accuracy used when
-                                        * outputting axis tick labels. */
-#define AVG_TICK_NUM_CHARS     16      /* Assumed average tick label size */
-
-#define TICK_RANGE_TIGHT       0
-#define TICK_RANGE_LOOSE       1
-#define TICK_RANGE_ALWAYS_LOOSE        2
-
-#define AXIS_TITLE_PAD         2       /* Padding for axis title. */
-#define AXIS_LINE_PAD          1       /* Padding for axis line. */
-
-#define HORIZMARGIN(m) (!((m)->site & 0x1))    /* Even sites are horizontal */
-
-typedef enum AxisComponents {
-    MAJOR_TICK, MINOR_TICK, TICK_LABEL, AXIS_LINE
-} AxisComponent;
-
-
-typedef struct {
-    int axis;          /* Length of the axis.  */
-    int t1;            /* Length of a major tick (in pixels). */
-    int t2;            /* Length of a minor tick (in pixels). */
-    int label;         /* Distance from axis to tick label.  */
-} AxisInfo;
-
-extern Tk_CustomOption bltDistanceOption;
-extern Tk_CustomOption bltPositiveDistanceOption;
-extern Tk_CustomOption bltShadowOption;
-extern Tk_CustomOption bltListOption;
-
-static Tk_OptionParseProc StringToLimit;
-static Tk_OptionPrintProc LimitToString;
-static Tk_OptionParseProc StringToTicks;
-static Tk_OptionPrintProc TicksToString;
-static Tk_OptionParseProc StringToAxis;
-static Tk_OptionPrintProc AxisToString;
-static Tk_OptionParseProc StringToAnyAxis;
-static Tk_OptionParseProc StringToFormat;
-static Tk_OptionPrintProc FormatToString;
-static Tk_OptionParseProc StringToLoose;
-static Tk_OptionPrintProc LooseToString;
-
-static Tk_CustomOption limitOption =
-{
-    StringToLimit, LimitToString, (ClientData)0
-};
-
-static Tk_CustomOption majorTicksOption =
-{
-    StringToTicks, TicksToString, (ClientData)AXIS_CONFIG_MAJOR,
-};
-static Tk_CustomOption minorTicksOption =
-{
-    StringToTicks, TicksToString, (ClientData)AXIS_CONFIG_MINOR,
-};
-Tk_CustomOption bltXAxisOption =
-{
-    StringToAxis, AxisToString, (ClientData)&bltXAxisUid
-};
-Tk_CustomOption bltYAxisOption =
-{
-    StringToAxis, AxisToString, (ClientData)&bltYAxisUid
-};
-Tk_CustomOption bltAnyXAxisOption =
-{
-    StringToAnyAxis, AxisToString, (ClientData)&bltXAxisUid
-};
-Tk_CustomOption bltAnyYAxisOption =
-{
-    StringToAnyAxis, AxisToString, (ClientData)&bltYAxisUid
-};
-static Tk_CustomOption formatOption =
-{
-    StringToFormat, FormatToString, (ClientData)0,
-};
-static Tk_CustomOption looseOption =
-{
-    StringToLoose, LooseToString, (ClientData)0,
-};
-
-/* Axis flags: */
-
-#define DEF_AXIS_COMMAND               (char *)NULL
-#define DEF_AXIS_DESCENDING            "no"
-#define DEF_AXIS_FOREGROUND            RGB_BLACK
-#define DEF_AXIS_FG_MONO               RGB_BLACK
-#define DEF_AXIS_HIDE                  "no"
-#define DEF_AXIS_JUSTIFY               "center"
-#define DEF_AXIS_LIMITS_FORMAT         (char *)NULL
-#define DEF_AXIS_LINE_WIDTH            "1"
-#define DEF_AXIS_LOGSCALE              "no"
-#define DEF_AXIS_LOOSE                 "no"
-#define DEF_AXIS_RANGE                 "0.0"
-#define DEF_AXIS_ROTATE                        "0.0"
-#define DEF_AXIS_SCROLL_INCREMENT      "10"
-#define DEF_AXIS_SHIFTBY               "0.0"
-#define DEF_AXIS_SHOWTICKS             "yes"
-#define DEF_AXIS_STEP                  "0.0"
-#define DEF_AXIS_STEP                  "0.0"
-#define DEF_AXIS_SUBDIVISIONS          "2"
-#define DEF_AXIS_TAGS                  "all"
-#define DEF_AXIS_TICKS                 "0"
-#ifdef WIN32
-#define DEF_AXIS_TICK_FONT             "{Arial Narrow} 8"
-#else
-#define DEF_AXIS_TICK_FONT             "*-Helvetica-Medium-R-Normal-*-10-*"
-#endif
-#define DEF_AXIS_TICK_LENGTH           "8"
-#define DEF_AXIS_TITLE_ALTERNATE       "0"
-#define DEF_AXIS_TITLE_FG              RGB_BLACK
-#define DEF_AXIS_TITLE_FONT            STD_FONT
-#define DEF_AXIS_X_STEP_BARCHART       "1.0"
-#define DEF_AXIS_X_SUBDIVISIONS_BARCHART "0"
-#define DEF_AXIS_BACKGROUND            (char *)NULL
-#define DEF_AXIS_BORDERWIDTH           "0"
-#define DEF_AXIS_RELIEF                        "flat"
-
-static Tk_ConfigSpec configSpecs[] =
-{
-    {TK_CONFIG_DOUBLE, "-autorange", "autoRange", "AutoRange",
-       DEF_AXIS_RANGE, Tk_Offset(Axis, windowSize),
-        ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT}, 
-    {TK_CONFIG_BORDER, "-background", "background", "Background",
-       DEF_AXIS_BACKGROUND, Tk_Offset(Axis, border),
-       ALL_GRAPHS | TK_CONFIG_NULL_OK},
-    {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
-    {TK_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags",
-       DEF_AXIS_TAGS, Tk_Offset(Axis, tags),
-       ALL_GRAPHS | TK_CONFIG_NULL_OK, &bltListOption},
-    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, 
-        (char *)NULL, 0, ALL_GRAPHS},
-    {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth",
-       DEF_AXIS_BORDERWIDTH, Tk_Offset(Axis, borderWidth),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
-    {TK_CONFIG_COLOR, "-color", "color", "Color",
-       DEF_AXIS_FOREGROUND, Tk_Offset(Axis, tickTextStyle.color),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_COLOR, "-color", "color", "Color",
-       DEF_AXIS_FG_MONO, Tk_Offset(Axis, tickTextStyle.color),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_STRING, "-command", "command", "Command",
-       DEF_AXIS_COMMAND, Tk_Offset(Axis, formatCmd),
-       TK_CONFIG_NULL_OK | ALL_GRAPHS},
-    {TK_CONFIG_BOOLEAN, "-descending", "descending", "Descending",
-       DEF_AXIS_DESCENDING, Tk_Offset(Axis, descending),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
-       DEF_AXIS_HIDE, Tk_Offset(Axis, hidden),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
-       DEF_AXIS_JUSTIFY, Tk_Offset(Axis, titleTextStyle.justify),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_BOOLEAN, "-labeloffset", "labelOffset", "LabelOffset",
-        (char *)NULL, Tk_Offset(Axis, labelOffset), ALL_GRAPHS}, 
-    {TK_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color",
-       DEF_AXIS_FOREGROUND, Tk_Offset(Axis, limitsTextStyle.color),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color",
-       DEF_AXIS_FG_MONO, Tk_Offset(Axis, limitsTextStyle.color),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_FONT, "-limitsfont", "limitsFont", "Font",
-       DEF_AXIS_TICK_FONT, Tk_Offset(Axis, limitsTextStyle.font), ALL_GRAPHS},
-    {TK_CONFIG_CUSTOM, "-limitsformat", "limitsFormat", "LimitsFormat",
-        (char *)NULL, Tk_Offset(Axis, limitsFormats),
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &formatOption},
-    {TK_CONFIG_CUSTOM, "-limitsshadow", "limitsShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, limitsTextStyle.shadow),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_CUSTOM, "-limitsshadow", "limitsShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, limitsTextStyle.shadow),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "LineWidth",
-       DEF_AXIS_LINE_WIDTH, Tk_Offset(Axis, lineWidth),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltDistanceOption},
-    {TK_CONFIG_BOOLEAN, "-logscale", "logScale", "LogScale",
-       DEF_AXIS_LOGSCALE, Tk_Offset(Axis, logScale),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_CUSTOM, "-loose", "loose", "Loose",
-       DEF_AXIS_LOOSE, 0, ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT,
-       &looseOption},
-    {TK_CONFIG_CUSTOM, "-majorticks", "majorTicks", "MajorTicks",
-       (char *)NULL, Tk_Offset(Axis, t1Ptr),
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &majorTicksOption},
-    {TK_CONFIG_CUSTOM, "-max", "max", "Max",
-       (char *)NULL, Tk_Offset(Axis, reqMax), 
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption},
-    {TK_CONFIG_CUSTOM, "-min", "min", "Min",
-       (char *)NULL, Tk_Offset(Axis, reqMin), 
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption},
-    {TK_CONFIG_CUSTOM, "-minorticks", "minorTicks", "MinorTicks",
-       (char *)NULL, Tk_Offset(Axis, t2Ptr),
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &minorTicksOption},
-    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
-       DEF_AXIS_RELIEF, Tk_Offset(Axis, relief), 
-        ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate",
-       DEF_AXIS_ROTATE, Tk_Offset(Axis, tickTextStyle.theta),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_STRING, "-scrollcommand", "scrollCommand", "ScrollCommand",
-       (char *)NULL, Tk_Offset(Axis, scrollCmdPrefix),
-       ALL_GRAPHS | TK_CONFIG_NULL_OK},
-    {TK_CONFIG_CUSTOM, "-scrollincrement", "scrollIncrement", "ScrollIncrement",
-       DEF_AXIS_SCROLL_INCREMENT, Tk_Offset(Axis, scrollUnits),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT, &bltPositiveDistanceOption},
-    {TK_CONFIG_CUSTOM, "-scrollmax", "scrollMax", "ScrollMax",
-       (char *)NULL, Tk_Offset(Axis, scrollMax), 
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption},
-    {TK_CONFIG_CUSTOM, "-scrollmin", "scrollMin", "ScrollMin",
-       (char *)NULL, Tk_Offset(Axis, scrollMin), 
-       TK_CONFIG_NULL_OK | ALL_GRAPHS, &limitOption},
-    {TK_CONFIG_DOUBLE, "-shiftby", "shiftBy", "ShiftBy",
-       DEF_AXIS_SHIFTBY, Tk_Offset(Axis, shiftBy),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_BOOLEAN, "-showticks", "showTicks", "ShowTicks",
-       DEF_AXIS_SHOWTICKS, Tk_Offset(Axis, showTicks),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_DOUBLE, "-stepsize", "stepSize", "StepSize",
-       DEF_AXIS_STEP, Tk_Offset(Axis, reqStep),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_DOUBLE, "-tickdivider", "tickDivider", "TickDivider",
-       DEF_AXIS_STEP, Tk_Offset(Axis, tickZoom),
-       ALL_GRAPHS | TK_CONFIG_DONT_SET_DEFAULT},
-    {TK_CONFIG_INT, "-subdivisions", "subdivisions", "Subdivisions",
-       DEF_AXIS_SUBDIVISIONS, Tk_Offset(Axis, reqNumMinorTicks),
-       ALL_GRAPHS},
-    {TK_CONFIG_FONT, "-tickfont", "tickFont", "Font",
-       DEF_AXIS_TICK_FONT, Tk_Offset(Axis, tickTextStyle.font), ALL_GRAPHS},
-    {TK_CONFIG_PIXELS, "-ticklength", "tickLength", "TickLength",
-       DEF_AXIS_TICK_LENGTH, Tk_Offset(Axis, tickLength), ALL_GRAPHS},
-    {TK_CONFIG_CUSTOM, "-tickshadow", "tickShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, tickTextStyle.shadow),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_CUSTOM, "-tickshadow", "tickShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, tickTextStyle.shadow),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_STRING, "-title", "title", "Title",
-       (char *)NULL, Tk_Offset(Axis, title),
-       TK_CONFIG_DONT_SET_DEFAULT | TK_CONFIG_NULL_OK | ALL_GRAPHS},
-    {TK_CONFIG_BOOLEAN, "-titlealternate", "titleAlternate", "TitleAlternate",
-       DEF_AXIS_TITLE_ALTERNATE, Tk_Offset(Axis, titleAlternate),
-       TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS},
-    {TK_CONFIG_COLOR, "-titlecolor", "titleColor", "Color",
-       DEF_AXIS_FOREGROUND, Tk_Offset(Axis, titleTextStyle.color),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_COLOR, "-titlecolor", "titleColor", "TitleColor",
-       DEF_AXIS_FG_MONO, Tk_Offset(Axis, titleTextStyle.color),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS},
-    {TK_CONFIG_FONT, "-titlefont", "titleFont", "Font",
-       DEF_AXIS_TITLE_FONT, Tk_Offset(Axis, titleTextStyle.font), ALL_GRAPHS},
-    {TK_CONFIG_CUSTOM, "-titleshadow", "titleShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, titleTextStyle.shadow),
-       TK_CONFIG_COLOR_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_CUSTOM, "-titleshadow", "titleShadow", "Shadow",
-       (char *)NULL, Tk_Offset(Axis, titleTextStyle.shadow),
-       TK_CONFIG_MONO_ONLY | ALL_GRAPHS, &bltShadowOption},
-    {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
-};
-
-/* Forward declarations */
-static void DestroyAxis _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr));
-static int GetAxis _ANSI_ARGS_((Graph *graphPtr, char *name, Blt_Uid classUid,
-       Axis **axisPtrPtr));
-static void FreeAxis _ANSI_ARGS_((Graph *graphPtr, Axis *axisPtr));
-
-INLINE static int
-Round(register double x)
-{
-    return (int) (x + ((x < 0.0) ? -0.5 : 0.5));
-}
-
-static void
-SetAxisRange(AxisRange *rangePtr, double min, double max)
-{
-    rangePtr->min = min;
-    rangePtr->max = max;
-    rangePtr->range = max - min;
-    if (FABS(rangePtr->range) < DBL_EPSILON) {
-       rangePtr->range = 1.0;
-    }
-    rangePtr->scale = 1.0 / rangePtr->range;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InRange --
- *
- *     Determines if a value lies within a given range.
- *
- *     The value is normalized and compared against the interval
- *     [0..1], where 0.0 is the minimum and 1.0 is the maximum.
- *     DBL_EPSILON is the smallest number that can be represented
- *     on the host machine, such that (1.0 + epsilon) != 1.0.
- *
- *     Please note, *max* can't equal *min*.
- *
- * Results:
- *     If the value is within the interval [min..max], 1 is 
- *     returned; 0 otherwise.
- *
- * ----------------------------------------------------------------------
- */
-INLINE static int
-InRange(x, rangePtr)
-    register double x;
-    AxisRange *rangePtr;
-{
-    if (rangePtr->range < DBL_EPSILON) {
-#ifdef notdef
-       return (((rangePtr->max - x) >= (FABS(x) * DBL_EPSILON)) &&
-               ((x - rangePtr->min) >= (FABS(x) * DBL_EPSILON)));
-#endif
-       return (FABS(rangePtr->max - x) >= DBL_EPSILON);
-    } else {
-       double norm;
-
-       norm = (x - rangePtr->min) * rangePtr->scale;
-       return ((norm >= -DBL_EPSILON) && ((norm - 1.0) < DBL_EPSILON));
-    }
-}
-
-INLINE static int
-AxisIsHorizontal(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    return ((axisPtr->classUid == bltYAxisUid) == graphPtr->inverted);
-}
-
-\f
-/* ----------------------------------------------------------------------
- * Custom option parse and print procedures
- * ----------------------------------------------------------------------
- */
-
-/*
- *----------------------------------------------------------------------
- *
- * StringToAnyAxis --
- *
- *     Converts the name of an axis to a pointer to its axis structure.
- *
- * Results:
- *     The return value is a standard Tcl result.  The axis flags are
- *     written into the widget record.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToAnyAxis(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Class identifier of the type of 
-                                * axis we are looking for. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to. */
-    Tk_Window tkwin;           /* Used to look up pointer to graph. */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    Axis **axisPtrPtr = (Axis **)(widgRec + offset);
-    Blt_Uid classUid = *(Blt_Uid *)clientData;
-    Graph *graphPtr;
-    Axis *axisPtr;
-
-    graphPtr = Blt_GetGraphFromWindowData(tkwin);
-    if (*axisPtrPtr != NULL) {
-       FreeAxis(graphPtr, *axisPtrPtr);
-    }
-    if (string[0] == '\0') {
-       axisPtr = NULL;
-    } else if (GetAxis(graphPtr, string, classUid, &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    *axisPtrPtr = axisPtr;
-    return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * StringToAxis --
- *
- *     Converts the name of an axis to a pointer to its axis structure.
- *
- * Results:
- *     The return value is a standard Tcl result.  The axis flags are
- *     written into the widget record.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToAxis(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Class identifier of the type of 
-                                * axis we are looking for. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to. */
-    Tk_Window tkwin;           /* Used to look up pointer to graph. */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    Axis **axisPtrPtr = (Axis **)(widgRec + offset);
-    Blt_Uid classUid = *(Blt_Uid *)clientData;
-    Graph *graphPtr;
-
-    graphPtr = Blt_GetGraphFromWindowData(tkwin);
-    if (*axisPtrPtr != NULL) {
-       FreeAxis(graphPtr, *axisPtrPtr);
-    }
-    if (GetAxis(graphPtr, string, classUid, axisPtrPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * AxisToString --
- *
- *     Convert the window coordinates into a string.
- *
- * Results:
- *     The string representing the coordinate position is returned.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static char *
-AxisToString(clientData, tkwin, widgRec, offset, freeProcPtr)
-    ClientData clientData;     /* Not used. */
-    Tk_Window tkwin;           /* Not used. */
-    char *widgRec;             /* Pointer to structure record .*/
-    int offset;                        /* Offset of field in structure. */
-    Tcl_FreeProc **freeProcPtr;        /* Not used. */
-{
-    Axis *axisPtr = *(Axis **)(widgRec + offset);
-
-    if (axisPtr == NULL) {
-       return "";
-    }
-    return axisPtr->name;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * StringToFormat --
- *
- *     Convert the name of virtual axis to an pointer.
- *
- * Results:
- *     The return value is a standard Tcl result.  The axis flags are
- *     written into the widget record.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToFormat(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Not used. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to. */
-    Tk_Window tkwin;           /* Used to look up pointer to graph */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    Axis *axisPtr = (Axis *)(widgRec);
-    char **argv;
-    int argc;
-
-    if (axisPtr->limitsFormats != NULL) {
-       Blt_Free(axisPtr->limitsFormats);
-    }
-    axisPtr->limitsFormats = NULL;
-    axisPtr->nFormats = 0;
-
-    if ((string == NULL) || (*string == '\0')) {
-       return TCL_OK;
-    }
-    if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (argc > 2) {
-       Tcl_AppendResult(interp, "too many elements in limits format list \"",
-           string, "\"", (char *)NULL);
-       Blt_Free(argv);
-       return TCL_ERROR;
-    }
-    axisPtr->limitsFormats = argv;
-    axisPtr->nFormats = argc;
-    return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FormatToString --
- *
- *     Convert the window coordinates into a string.
- *
- * Results:
- *     The string representing the coordinate position is returned.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static char *
-FormatToString(clientData, tkwin, widgRec, offset, freeProcPtr)
-    ClientData clientData;     /* Not used. */
-    Tk_Window tkwin;           /* Not used. */
-    char *widgRec;             /* Widget record */
-    int offset;                        /* offset of limits field */
-    Tcl_FreeProc **freeProcPtr;        /* Not used. */
-{
-    Axis *axisPtr = (Axis *)(widgRec);
-    
-    if (axisPtr->nFormats == 0) {
-       return "";
-    }
-    *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
-    return Tcl_Merge(axisPtr->nFormats, axisPtr->limitsFormats); 
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * StringToLimit --
- *
- *     Convert the string representation of an axis limit into its numeric
- *     form.
- *
- * Results:
- *     The return value is a standard Tcl result.  The symbol type is
- *     written into the widget record.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToLimit(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Either AXIS_CONFIG_MIN or AXIS_CONFIG_MAX.
-                                * Indicates which axis limit to set. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to */
-    Tk_Window tkwin;           /* Not used. */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    double *limitPtr = (double *)(widgRec + offset);
-
-    if ((string == NULL) || (*string == '\0')) {
-       *limitPtr = VALUE_UNDEFINED;
-    } else if (Tcl_ExprDouble(interp, string, limitPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * LimitToString --
- *
- *     Convert the floating point axis limits into a string.
- *
- * Results:
- *     The string representation of the limits is returned.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static char *
-LimitToString(clientData, tkwin, widgRec, offset, freeProcPtr)
-    ClientData clientData;     /* Either LMIN or LMAX */
-    Tk_Window tkwin;           /* Not used. */
-    char *widgRec;             /* */
-    int offset;
-    Tcl_FreeProc **freeProcPtr;
-{
-    double limit = *(double *)(widgRec + offset);
-    char *result;
-
-    result = "";
-    if (DEFINED(limit)) {
-       char string[TCL_DOUBLE_SPACE + 1];
-       Graph *graphPtr;
-
-       graphPtr = Blt_GetGraphFromWindowData(tkwin);
-       Tcl_PrintDouble(graphPtr->interp, limit, string);
-       result = Blt_Strdup(string);
-       if (result == NULL) {
-           return "";
-       }
-       *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
-    }
-    return result;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * StringToTicks --
- *
- *
- * Results:
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToTicks(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Not used. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to */
-    Tk_Window tkwin;           /* Not used. */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    unsigned int mask = (unsigned int)clientData;
-    Axis *axisPtr = (Axis *)widgRec;
-    Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset);
-    int nTicks;
-    Ticks *ticksPtr;
-
-    nTicks = 0;
-    ticksPtr = NULL;
-    if ((string != NULL) && (*string != '\0')) {
-       int nExprs;
-       char **exprArr;
-
-       if (Tcl_SplitList(interp, string, &nExprs, &exprArr) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       if (nExprs > 0) {
-           register int i;
-           int result = TCL_ERROR;
-           double value;
-
-           ticksPtr = Blt_Malloc(sizeof(Ticks) + (nExprs * sizeof(double)));
-           assert(ticksPtr);
-           for (i = 0; i < nExprs; i++) {
-               result = Tcl_ExprDouble(interp, exprArr[i], &value);
-               if (result != TCL_OK) {
-                   break;
-               }
-               ticksPtr->values[i] = value;
-           }
-           Blt_Free(exprArr);
-           if (result != TCL_OK) {
-               Blt_Free(ticksPtr);
-               return TCL_ERROR;
-           }
-           nTicks = nExprs;
-       }
-    }
-    axisPtr->flags &= ~mask;
-    if (ticksPtr != NULL) {
-       axisPtr->flags |= mask;
-       ticksPtr->nTicks = nTicks;
-    }
-    if (*ticksPtrPtr != NULL) {
-       Blt_Free(*ticksPtrPtr);
-    }
-    *ticksPtrPtr = ticksPtr;
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TicksToString --
- *
- *     Convert array of tick coordinates to a list.
- *
- * Results:
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static char *
-TicksToString(clientData, tkwin, widgRec, offset, freeProcPtr)
-    ClientData clientData;     /* Not used. */
-    Tk_Window tkwin;           /* Not used. */
-    char *widgRec;             /* */
-    int offset;
-    Tcl_FreeProc **freeProcPtr;
-{
-    Ticks *ticksPtr = *(Ticks **) (widgRec + offset);
-    char string[TCL_DOUBLE_SPACE + 1];
-    register int i;
-    char *result;
-    Tcl_DString dString;
-    Graph *graphPtr;
-
-    if (ticksPtr == NULL) {
-       return "";
-    }
-    Tcl_DStringInit(&dString);
-    graphPtr = Blt_GetGraphFromWindowData(tkwin);
-    for (i = 0; i < ticksPtr->nTicks; i++) {
-       Tcl_PrintDouble(graphPtr->interp, ticksPtr->values[i], string);
-       Tcl_DStringAppendElement(&dString, string);
-    }
-    *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
-    result = Blt_Strdup(Tcl_DStringValue(&dString));
-    Tcl_DStringFree(&dString);
-    return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * StringToLoose --
- *
- *     Convert a string to one of three values.
- *             0 - false, no, off
- *             1 - true, yes, on
- *             2 - always
- * Results:
- *     If the string is successfully converted, TCL_OK is returned.
- *     Otherwise, TCL_ERROR is returned and an error message is left in
- *     interpreter's result field.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-StringToLoose(clientData, interp, tkwin, string, widgRec, offset)
-    ClientData clientData;     /* Not used. */
-    Tcl_Interp *interp;                /* Interpreter to send results back to */
-    Tk_Window tkwin;           /* Not used. */
-    char *string;              /* String representing new value. */
-    char *widgRec;             /* Pointer to structure record. */
-    int offset;                        /* Offset of field in structure. */
-{
-    Axis *axisPtr = (Axis *)(widgRec);
-    register int i;
-    int argc;
-    char **argv;
-    int values[2];
-
-    if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if ((argc < 1) || (argc > 2)) {
-       Tcl_AppendResult(interp, "wrong # elements in loose value \"",
-           string, "\"", (char *)NULL);
-       return TCL_ERROR;
-    }
-    for (i = 0; i < argc; i++) {
-       if ((argv[i][0] == 'a') && (strcmp(argv[i], "always") == 0)) {
-           values[i] = TICK_RANGE_ALWAYS_LOOSE;
-       } else {
-           int bool;
-
-           if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) {
-               Blt_Free(argv);
-               return TCL_ERROR;
-           }
-           values[i] = bool;
-       }
-    }
-    axisPtr->looseMin = axisPtr->looseMax = values[0];
-    if (argc > 1) {
-       axisPtr->looseMax = values[1];
-    }
-    Blt_Free(argv);
-    return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * LooseToString --
- *
- * Results:
- *     The string representation of the auto boolean is returned.
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static char *
-LooseToString(clientData, tkwin, widgRec, offset, freeProcPtr)
-    ClientData clientData;     /* Not used. */
-    Tk_Window tkwin;           /* Not used. */
-    char *widgRec;             /* Widget record */
-    int offset;                        /* offset of flags field in record */
-    Tcl_FreeProc **freeProcPtr;        /* Memory deallocation scheme to use */
-{
-    Axis *axisPtr = (Axis *)widgRec;
-    Tcl_DString dString;
-    char *result;
-
-    Tcl_DStringInit(&dString);
-    if (axisPtr->looseMin == TICK_RANGE_TIGHT) {
-       Tcl_DStringAppendElement(&dString, "0");
-    } else if (axisPtr->looseMin == TICK_RANGE_LOOSE) {
-       Tcl_DStringAppendElement(&dString, "1");
-    } else if (axisPtr->looseMin == TICK_RANGE_ALWAYS_LOOSE) {
-       Tcl_DStringAppendElement(&dString, "always");
-    }
-    if (axisPtr->looseMin != axisPtr->looseMax) {
-       if (axisPtr->looseMax == TICK_RANGE_TIGHT) {
-           Tcl_DStringAppendElement(&dString, "0");
-       } else if (axisPtr->looseMax == TICK_RANGE_LOOSE) {
-           Tcl_DStringAppendElement(&dString, "1");
-       } else if (axisPtr->looseMax == TICK_RANGE_ALWAYS_LOOSE) {
-           Tcl_DStringAppendElement(&dString, "always");
-       }
-    }
-    result = Blt_Strdup(Tcl_DStringValue(&dString));
-    Tcl_DStringFree(&dString);
-    *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
-    return result;
-}
-
-static void
-FreeLabels(chainPtr)
-    Blt_Chain *chainPtr;
-{
-    Blt_ChainLink *linkPtr;
-    TickLabel *labelPtr;
-
-    for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
-        linkPtr = Blt_ChainNextLink(linkPtr)) {
-       labelPtr = Blt_ChainGetValue(linkPtr);
-       Blt_Free(labelPtr);
-    }
-    Blt_ChainReset(chainPtr);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * MakeLabel --
- *
- *     Converts a floating point tick value to a string to be used as its
- *     label.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     Returns a new label in the string character buffer.  The formatted
- *     tick label will be displayed on the graph.
- *
- * ---------------------------------------------------------------------- 
- */
-static TickLabel *
-MakeLabel(graphPtr, axisPtr, value)
-    Graph *graphPtr;
-    Axis *axisPtr;             /* Axis structure */
-    double value;              /* Value to be convert to a decimal string */
-{
-    char string[TICK_LABEL_SIZE + 1];
-    TickLabel *labelPtr;
-
-    /* Generate a default tick label based upon the tick value.  */
-    if (axisPtr->logScale) {
-       sprintf(string, "1E%d", ROUND(value));
-    } else {
-       sprintf(string, "%.*g", NUMDIGITS, value);
-    }
-
-    if (axisPtr->formatCmd != NULL) {
-       Tcl_Interp *interp = graphPtr->interp;
-       Tk_Window tkwin = graphPtr->tkwin;
-
-       /*
-        * A Tcl proc was designated to format tick labels. Append the path
-        * name of the widget and the default tick label as arguments when
-        * invoking it. Copy and save the new label from interp->result.
-        */
-       Tcl_ResetResult(interp);
-       if (Tcl_VarEval(interp, axisPtr->formatCmd, " ", Tk_PathName(tkwin),
-               " ", string, (char *)NULL) != TCL_OK) {
-           Tcl_BackgroundError(interp);
-       } else {
-           /* 
-            * The proc could return a string of any length, so arbitrarily 
-            * limit it to what will fit in the return string. 
-            */
-           strncpy(string, Tcl_GetStringResult(interp), TICK_LABEL_SIZE);
-           string[TICK_LABEL_SIZE] = '\0';
-           
-           Tcl_ResetResult(interp); /* Clear the interpreter's result. */
-       }
-    }
-    labelPtr = Blt_Malloc(sizeof(TickLabel) + strlen(string));
-    assert(labelPtr);
-    strcpy(labelPtr->string, string);
-    labelPtr->anchorPos.x = labelPtr->anchorPos.y = DBL_MAX;
-    return labelPtr;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_InvHMap --
- *
- *     Maps the given screen coordinate back to a graph coordinate.
- *     Called by the graph locater routine.
- *
- * Results:
- *     Returns the graph coordinate value at the given window
- *     y-coordinate.
- *
- * ----------------------------------------------------------------------
- */
-double
-Blt_InvHMap(graphPtr, axisPtr, x)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double x;
-{
-    double value;
-
-    x = (double)(x - graphPtr->hOffset) * graphPtr->hScale;
-    if (axisPtr->descending) {
-       x = 1.0 - x;
-    }
-    value = (x * axisPtr->axisRange.range) + axisPtr->axisRange.min;
-    if (axisPtr->logScale) {
-       value = EXP10(value);
-    }
-    return value;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_InvVMap --
- *
- *     Maps the given window y-coordinate back to a graph coordinate
- *     value. Called by the graph locater routine.
- *
- * Results:
- *     Returns the graph coordinate value at the given window
- *     y-coordinate.
- *
- * ----------------------------------------------------------------------
- */
-double
-Blt_InvVMap(graphPtr, axisPtr, y)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double y;
-{
-    double value;
-
-    y = (double)(y - graphPtr->vOffset) * graphPtr->vScale;
-    if (axisPtr->descending) {
-       y = 1.0 - y;
-    }
-    value = ((1.0 - y) * axisPtr->axisRange.range) + axisPtr->axisRange.min;
-    if (axisPtr->logScale) {
-       value = EXP10(value);
-    }
-    return value;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_HMap --
- *
- *     Map the given graph coordinate value to its axis, returning a window
- *     position.
- *
- * Results:
- *     Returns a double precision number representing the window coordinate
- *     position on the given axis.
- *
- * ----------------------------------------------------------------------
- */
-double
-Blt_HMap(graphPtr, axisPtr, x)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double x;
-{
-    if ((axisPtr->logScale) && (x != 0.0)) {
-       x = log10(FABS(x));
-    }
-    /* Map graph coordinate to normalized coordinates [0..1] */
-    x = (x - axisPtr->axisRange.min) * axisPtr->axisRange.scale;
-    if (axisPtr->descending) {
-       x = 1.0 - x;
-    }
-    return (x * graphPtr->hRange + graphPtr->hOffset);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_VMap --
- *
- *     Map the given graph coordinate value to its axis, returning a window
- *     position.
- *
- * Results:
- *     Returns a double precision number representing the window coordinate
- *     position on the given axis.
- *
- * ----------------------------------------------------------------------
- */
-double
-Blt_VMap(graphPtr, axisPtr, y)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double y;
-{
-    if ((axisPtr->logScale) && (y != 0.0)) {
-       y = log10(FABS(y));
-    }
-    /* Map graph coordinate to normalized coordinates [0..1] */
-    y = (y - axisPtr->axisRange.min) * axisPtr->axisRange.scale;
-    if (axisPtr->descending) {
-       y = 1.0 - y;
-    }
-    return (((1.0 - y) * graphPtr->vRange) + graphPtr->vOffset);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_Map2D --
- *
- *     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.
- *
- * ----------------------------------------------------------------------
- */
-Point2D
-Blt_Map2D(graphPtr, x, y, axesPtr)
-    Graph *graphPtr;
-    double x, y;               /* Graph x and y coordinates */
-    Axis2D *axesPtr;           /* Specifies which axes to use */
-{
-    Point2D point;
-
-    if (graphPtr->inverted) {
-       point.x = Blt_HMap(graphPtr, axesPtr->y, y);
-       point.y = Blt_VMap(graphPtr, axesPtr->x, x);
-    } else {
-       point.x = Blt_HMap(graphPtr, axesPtr->x, x);
-       point.y = Blt_VMap(graphPtr, axesPtr->y, y);
-    }
-    return point;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_InvMap2D --
- *
- *     Maps the given window x,y coordinates to graph values.
- *
- * Results:
- *     Returns a structure containing the graph coordinates of
- *     the given window x,y coordinate.
- *
- * ----------------------------------------------------------------------
- */
-Point2D
-Blt_InvMap2D(graphPtr, x, y, axesPtr)
-    Graph *graphPtr;
-    double x, y;               /* Window x and y coordinates */
-    Axis2D *axesPtr;           /* Specifies which axes to use */
-{
-    Point2D point;
-
-    if (graphPtr->inverted) {
-       point.x = Blt_InvVMap(graphPtr, axesPtr->x, y);
-       point.y = Blt_InvHMap(graphPtr, axesPtr->y, x);
-    } else {
-       point.x = Blt_InvHMap(graphPtr, axesPtr->x, x);
-       point.y = Blt_InvVMap(graphPtr, axesPtr->y, y);
-    }
-    return point;
-}
-
-
-static void
-GetDataLimits(axisPtr, min, max)
-    Axis *axisPtr;
-    double min, max;
-{
-    if (axisPtr->valueRange.min > min) {
-       axisPtr->valueRange.min = min;
-    }
-    if (axisPtr->valueRange.max < max) {
-       axisPtr->valueRange.max = max;
-    }
-}
-
-static void
-FixAxisRange(axisPtr)
-    Axis *axisPtr;
-{
-    double min, max;
-    /*
-     * When auto-scaling, the axis limits are the bounds of the element
-     * data.  If no data exists, set arbitrary limits (wrt to log/linear
-     * scale).
-     */
-    min = axisPtr->valueRange.min;
-    max = axisPtr->valueRange.max;
-
-    if (min == DBL_MAX) {
-       if (DEFINED(axisPtr->reqMin)) {
-           min = axisPtr->reqMin;
-       } else {
-           min = (axisPtr->logScale) ? 0.001 : 0.0;
-       }
-    }
-    if (max == -DBL_MAX) {
-       if (DEFINED(axisPtr->reqMax)) {
-           max = axisPtr->reqMax;
-       } else {
-           max = 1.0;
-       }
-    }
-    if (min >= max) {
-       double value;
-
-       /*
-        * There is no range of data (i.e. min is not less than max), 
-        * so manufacture one.
-        */
-       value = min;
-       if (value == 0.0) {
-           min = -0.1, max = 0.1;
-       } else {
-           double x;
-
-           x = FABS(value) * 0.1;
-           min = value - x, max = value + x;
-       }
-    }
-    SetAxisRange(&axisPtr->valueRange, min, max);
-
-    /*   
-     * The axis limits are either the current data range or overridden
-     * by the values selected by the user with the -min or -max
-     * options.
-     */
-    axisPtr->min = min;
-    axisPtr->max = max;
-    if (DEFINED(axisPtr->reqMin)) {
-       axisPtr->min = axisPtr->reqMin;
-    }
-    if (DEFINED(axisPtr->reqMax)) { 
-       axisPtr->max = axisPtr->reqMax;
-    }
-
-    if (axisPtr->max < axisPtr->min) {
-
-       /*   
-        * If the limits still don't make sense, it's because one
-        * limit configuration option (-min or -max) was set and the
-        * other default (based upon the data) is too small or large.
-        * Remedy this by making up a new min or max from the
-        * user-defined limit.
-        */
-
-       if (!DEFINED(axisPtr->reqMin)) {
-           axisPtr->min = axisPtr->max - (FABS(axisPtr->max) * 0.1);
-       }
-       if (!DEFINED(axisPtr->reqMax)) {
-           axisPtr->max = axisPtr->min + (FABS(axisPtr->max) * 0.1);
-       }
-    }
-    /* 
-     * If a window size is defined, handle auto ranging by shifting
-     * the axis limits. 
-     */
-    if ((axisPtr->windowSize > 0.0) && 
-       (!DEFINED(axisPtr->reqMin)) && (!DEFINED(axisPtr->reqMax))) {
-       if (axisPtr->shiftBy < 0.0) {
-           axisPtr->shiftBy = 0.0;
-       }
-       max = axisPtr->min + axisPtr->windowSize;
-       if (axisPtr->max >= max) {
-           if (axisPtr->shiftBy > 0.0) {
-               max = UCEIL(axisPtr->max, axisPtr->shiftBy);
-           }
-           axisPtr->min = max - axisPtr->windowSize;
-       }
-       axisPtr->max = max;
-    }
-    if ((axisPtr->max != axisPtr->prevMax) ||
-       (axisPtr->min != axisPtr->prevMin)) {
-       /* Indicate if the axis limits have changed */
-       axisPtr->flags |= AXIS_DIRTY;
-       /* and save the previous minimum and maximum values */
-       axisPtr->prevMin = axisPtr->min;
-       axisPtr->prevMax = axisPtr->max;
-    }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * NiceNum --
- *
- *     Reference: Paul Heckbert, "Nice Numbers for Graph Labels",
- *                Graphics Gems, pp 61-63.  
- *
- *     Finds a "nice" number approximately equal to x.
- *
- * ----------------------------------------------------------------------
- */
-static double
-NiceNum(x, doround)
-    double x;
-    int doround;                       /* If non-zero, round. Otherwise take ceiling
-                                * of value. */
-{
-    double expt;               /* Exponent of x */
-    double frac;               /* Fractional part of x */
-    double fnice;              /* Nice, rounded fraction */
-
-    expt = floor(log10(x));
-    frac = x / EXP10(expt);    /* between 1 and 10 */
-    if (doround) {
-       if (frac < 1.5) {
-           fnice = 1.0;
-       } else if (frac < 3.0) {
-           fnice = 2.0;
-       } else if (frac < 7.0) {
-           fnice = 5.0;
-       } else {
-           fnice = 10.0;
-       }
-    } else {
-       if (frac <= 1.0) {
-           fnice = 1.0;
-       } else if (frac <= 2.0) {
-           fnice = 2.0;
-       } else if (frac <= 5.0) {
-           fnice = 5.0;
-       } else {
-           fnice = 10.0;
-       }
-    }
-    return fnice * EXP10(expt);
-}
-
-static Ticks *
-GenerateTicks(sweepPtr)
-    TickSweep *sweepPtr;
-{
-    Ticks *ticksPtr;
-    register int i;
-
-    ticksPtr = Blt_Malloc(sizeof(Ticks) + (sweepPtr->nSteps * sizeof(double)));
-    assert(ticksPtr);
-
-    if (sweepPtr->step == 0.0) { 
-       static double logTable[] = /* Precomputed log10 values [1..10] */
-       {
-           0.0, 
-           0.301029995663981, 0.477121254719662, 
-           0.602059991327962, 0.698970004336019, 
-           0.778151250383644, 0.845098040014257,
-           0.903089986991944, 0.954242509439325, 
-           1.0
-       };
-       /* Hack: A zero step indicates to use log values. */
-       for (i = 0; i < sweepPtr->nSteps; i++) {
-           ticksPtr->values[i] = logTable[i];
-       }
-    } else {
-       double value;
-
-       value = sweepPtr->initial; /* Start from smallest axis tick */
-       for (i = 0; i < sweepPtr->nSteps; i++) {
-           value = UROUND(value, sweepPtr->step);
-           ticksPtr->values[i] = value;
-           value += sweepPtr->step;
-       }
-    }
-    ticksPtr->nTicks = sweepPtr->nSteps;
-    return ticksPtr;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * LogScaleAxis --
- *
- *     Determine the range and units of a log scaled axis.
- *
- *     Unless the axis limits are specified, the axis is scaled
- *     automatically, where the smallest and largest major ticks encompass
- *     the range of actual data values.  When an axis limit is specified,
- *     that value represents the smallest(min)/largest(max) value in the
- *     displayed range of values.
- *
- *     Both manual and automatic scaling are affected by the step used.  By
- *     default, the step is the largest power of ten to divide the range in
- *     more than one piece.
- *
- *     Automatic scaling:
- *     Find the smallest number of units which contain the range of values.
- *     The minimum and maximum major tick values will be represent the
- *     range of values for the axis. This greatest number of major ticks
- *     possible is 10.
- *
- *     Manual scaling:
- *     Make the minimum and maximum data values the represent the range of
- *     the values for the axis.  The minimum and maximum major ticks will be
- *     inclusive of this range.  This provides the largest area for plotting
- *     and the expected results when the axis min and max values have be set
- *     by the user (.e.g zooming).  The maximum number of major ticks is 20.
- *
- *     For log scale, there's the possibility that the minimum and
- *     maximum data values are the same magnitude.  To represent the
- *     points properly, at least one full decade should be shown.
- *     However, if you zoom a log scale plot, the results should be
- *     predictable. Therefore, in that case, show only minor ticks.
- *     Lastly, there should be an appropriate way to handle numbers
- *     <=0.
- *
- *          maxY
- *            |    units = magnitude (of least significant digit)
- *            |    high  = largest unit tick < max axis value
- *      high _|    low   = smallest unit tick > min axis value
- *            |
- *            |    range = high - low
- *            |    # ticks = greatest factor of range/units
- *           _|
- *        U   |
- *        n   |
- *        i   |
- *        t  _|
- *            |
- *            |
- *            |
- *       low _|
- *            |
- *            |_minX________________maxX__
- *            |   |       |      |       |
- *     minY  low                        high
- *           minY
- *
- *
- *     numTicks = Number of ticks
- *     min = Minimum value of axis
- *     max = Maximum value of axis
- *     range    = Range of values (max - min)
- *
- *     If the number of decades is greater than ten, it is assumed
- *     that the full set of log-style ticks can't be drawn properly.
- *
- * Results:
- *     None
- *
- * ---------------------------------------------------------------------- */
-static void
-LogScaleAxis(axisPtr, min, max)
-    Axis *axisPtr;
-    double min, max;
-{
-    double range;
-    double tickMin, tickMax;
-    double majorStep, minorStep;
-    int nMajor, nMinor;
-
-    nMajor = nMinor = 0;
-    majorStep = minorStep = 0.0;
-    if (min < max) {
-       min = (min != 0.0) ? log10(FABS(min)) : 0.0;
-       max = (max != 0.0) ? log10(FABS(max)) : 1.0;
-       
-       tickMin = floor(min);
-       tickMax = ceil(max);
-       range = tickMax - tickMin;
-       
-       if (range > 10) {
-           /* There are too many decades to display a major tick at every
-            * decade.  Instead, treat the axis as a linear scale.  */
-           range = NiceNum(range, 0);
-           majorStep = NiceNum(range / DEF_NUM_TICKS, 1);
-           tickMin = UFLOOR(tickMin, majorStep);
-           tickMax = UCEIL(tickMax, majorStep);
-           nMajor = (int)((tickMax - tickMin) / majorStep) + 1;
-           minorStep = EXP10(floor(log10(majorStep)));
-           if (minorStep == majorStep) {
-               nMinor = 4, minorStep = 0.2;
-           } else {
-               nMinor = Round(majorStep / minorStep) - 1;
-           }
-       } else {
-           if (tickMin == tickMax) {
-               tickMax++;
-           }
-           majorStep = 1.0;
-           nMajor = (int)(tickMax - tickMin + 1); /* FIXME: Check this. */
-           
-           minorStep = 0.0;    /* This is a special hack to pass
-                                * information to the GenerateTicks
-                                * routine. An interval of 0.0 tells
-                                *      1) this is a minor sweep and 
-                                *      2) the axis is log scale.  
-                                */
-           nMinor = 10;
-       }
-       if ((axisPtr->looseMin == TICK_RANGE_TIGHT) ||
-           ((axisPtr->looseMin == TICK_RANGE_LOOSE) && 
-            (DEFINED(axisPtr->reqMin)))) {
-           tickMin = min;
-           nMajor++;
-       }
-       if ((axisPtr->looseMax == TICK_RANGE_TIGHT) ||
-           ((axisPtr->looseMax == TICK_RANGE_LOOSE) &&
-            (DEFINED(axisPtr->reqMax)))) {
-           tickMax = max;
-       }
-    }
-    axisPtr->majorSweep.step = majorStep;
-    axisPtr->majorSweep.initial = floor(tickMin);
-    axisPtr->majorSweep.nSteps = nMajor;
-    axisPtr->minorSweep.initial = axisPtr->minorSweep.step = minorStep;
-    axisPtr->minorSweep.nSteps = nMinor;
-    SetAxisRange(&axisPtr->axisRange, tickMin, tickMax);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * LinearScaleAxis --
- *
- *     Determine the units of a linear scaled axis.
- *
- *     The axis limits are either the range of the data values mapped
- *     to the axis (autoscaled), or the values specified by the -min
- *     and -max options (manual).
- *
- *     If autoscaled, the smallest and largest major ticks will
- *     encompass the range of data values.  If the -loose option is
- *     selected, the next outer ticks are choosen.  If tight, the
- *     ticks are at or inside of the data limits are used.
- *
- *     If manually set, the ticks are at or inside the data limits
- *     are used.  This makes sense for zooming.  You want the
- *     selected range to represent the next limit, not something a
- *     bit bigger.
- *
- *     Note: I added an "always" value to the -loose option to force
- *           the manually selected axes to be loose. It's probably
- *           not a good idea.
- *
- *          maxY
- *            |    units = magnitude (of least significant digit)
- *            |    high  = largest unit tick < max axis value
- *      high _|    low   = smallest unit tick > min axis value
- *            |
- *            |    range = high - low
- *            |    # ticks = greatest factor of range/units
- *           _|
- *        U   |
- *        n   |
- *        i   |
- *        t  _|
- *            |
- *            |
- *            |
- *       low _|
- *            |
- *            |_minX________________maxX__
- *            |   |       |      |       |
- *     minY  low                        high
- *           minY
- *
- *     numTicks = Number of ticks
- *     min = Minimum value of axis
- *     max = Maximum value of axis
- *     range    = Range of values (max - min)
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     The axis tick information is set.  The actual tick values will
- *     be generated later.
- *
- * ----------------------------------------------------------------------
- */
-static void
-LinearScaleAxis(axisPtr, min, max)
-    Axis *axisPtr;
-    double min, max;
-{
-    double range, step;
-    double tickMin, tickMax;
-    double axisMin, axisMax;
-    int nTicks;
-
-    nTicks = 0;
-    tickMin = tickMax = 0.0;
-    if (min < max) {
-       range = max - min;
-       
-       /* Calculate the major tick stepping. */
-       if (axisPtr->reqStep > 0.0) {
-           /* An interval was designated by the user.  Keep scaling it
-            * until it fits comfortably within the current range of the
-            * axis.  */
-           step = axisPtr->reqStep;
-           while ((2 * step) >= range) {
-               step *= 0.5;
-           }
-       } else {
-           range = NiceNum(range, 0);
-           step = NiceNum(range / DEF_NUM_TICKS, 1);
-       }
-       
-       /* Find the outer tick values. Add 0.0 to prevent getting -0.0. */
-       axisMin = tickMin = floor(min / step) * step + 0.0;
-       axisMax = tickMax = ceil(max / step) * step + 0.0;
-       
-       nTicks = Round((tickMax - tickMin) / step) + 1;
-    }
-    axisPtr->majorSweep.step = step;
-    axisPtr->majorSweep.initial = tickMin;
-    axisPtr->majorSweep.nSteps = nTicks;
-    
-    /*
-     * The limits of the axis are either the range of the data
-     * ("tight") or at the next outer tick interval ("loose").  The
-     * looseness or tightness has to do with how the axis fits the
-     * range of data values.  This option is overridden when
-     * the user sets an axis limit (by either -min or -max option).
-     * The axis limit is always at the selected limit (otherwise we
-     * assume that user would have picked a different number).
-     */
-    if ((axisPtr->looseMin == TICK_RANGE_TIGHT) ||
-       ((axisPtr->looseMin == TICK_RANGE_LOOSE) &&
-        (DEFINED(axisPtr->reqMin)))) {
-       axisMin = min;
-    }
-    if ((axisPtr->looseMax == TICK_RANGE_TIGHT) ||
-       ((axisPtr->looseMax == TICK_RANGE_LOOSE) &&
-        (DEFINED(axisPtr->reqMax)))) {
-       axisMax = max;
-    }
-    SetAxisRange(&axisPtr->axisRange, axisMin, axisMax);
-    
-    /* Now calculate the minor tick step and number. */
-    
-    if ((axisPtr->reqNumMinorTicks > 0) && 
-       ((axisPtr->flags & AXIS_CONFIG_MAJOR) == 0)) {
-       nTicks = axisPtr->reqNumMinorTicks - 1;
-       step = 1.0 / (nTicks + 1);
-    } else {
-       nTicks = 0;             /* No minor ticks. */
-       step = 0.5;             /* Don't set the minor tick interval
-                                * to 0.0. It makes the GenerateTicks
-                                * routine create minor log-scale tick
-                                * marks.  */
-    }
-    axisPtr->minorSweep.initial = axisPtr->minorSweep.step = step;
-    axisPtr->minorSweep.nSteps = nTicks;
-}
-
-static void
-SweepTicks(axisPtr)
-    Axis *axisPtr;
-{
-    if ((axisPtr->flags & AXIS_CONFIG_MAJOR) == 0) {
-       if (axisPtr->t1Ptr != NULL) {
-           Blt_Free(axisPtr->t1Ptr);
-       }
-       axisPtr->t1Ptr = GenerateTicks(&axisPtr->majorSweep);
-    }
-    if ((axisPtr->flags & AXIS_CONFIG_MINOR) == 0) {
-       if (axisPtr->t2Ptr != NULL) {
-           Blt_Free(axisPtr->t2Ptr);
-       }
-       axisPtr->t2Ptr = GenerateTicks(&axisPtr->minorSweep);
-    }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_ResetAxes --
- *
- * Results:
- *     None.
- *
- * ----------------------------------------------------------------------
- */
-void
-Blt_ResetAxes(graphPtr)
-    Graph *graphPtr;
-{
-    Blt_ChainLink *linkPtr;
-    Element *elemPtr;
-    Axis *axisPtr;
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Extents2D exts;
-    double min, max;
-
-    /* FIXME: This should be called whenever the display list of
-     *       elements change. Maybe yet another flag INIT_STACKS to
-     *       indicate that the element display list has changed.
-     *       Needs to be done before the axis limits are set.
-     */
-    Blt_InitFreqTable(graphPtr);
-    if ((graphPtr->mode == MODE_STACKED) && (graphPtr->nStacks > 0)) {
-       Blt_ComputeStacks(graphPtr);
-    }
-    /*
-     * Step 1:  Reset all axes. Initialize the data limits of the axis to
-     *         impossible values.
-     */
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       axisPtr->min = axisPtr->valueRange.min = DBL_MAX;
-       axisPtr->max = axisPtr->valueRange.max = -DBL_MAX;
-    }
-
-    /*
-     * Step 2:  For each element that's to be displayed, get the smallest
-     *         and largest data values mapped to each X and Y-axis.  This
-     *         will be the axis limits if the user doesn't override them 
-     *         with -min and -max options.
-     */
-    for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
-       linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
-       elemPtr = Blt_ChainGetValue(linkPtr);
-       if (!elemPtr->hidden) {
-           (*elemPtr->procsPtr->extentsProc) (elemPtr, &exts);
-           GetDataLimits(elemPtr->axes.x, exts.left, exts.right);
-           GetDataLimits(elemPtr->axes.y, exts.top, exts.bottom);
-       }
-    }
-    /*
-     * Step 3:  Now that we know the range of data values for each axis,
-     *         set axis limits and compute a sweep to generate tick values.
-     */
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       FixAxisRange(axisPtr);
-
-       /* Calculate min/max tick (major/minor) layouts */
-       min = axisPtr->min;
-       max = axisPtr->max;
-       if ((DEFINED(axisPtr->scrollMin)) && (min < axisPtr->scrollMin)) {
-           min = axisPtr->scrollMin;
-       }
-       if ((DEFINED(axisPtr->scrollMax)) && (max > axisPtr->scrollMax)) {
-           max = axisPtr->scrollMax;
-       }
-       if (axisPtr->logScale) {
-           LogScaleAxis(axisPtr, min, max);
-       } else {
-           LinearScaleAxis(axisPtr, min, max);
-       }
-
-       if ((axisPtr->flags & (AXIS_DIRTY | AXIS_ONSCREEN)) ==
-           (AXIS_DIRTY | AXIS_ONSCREEN)) {
-           graphPtr->flags |= REDRAW_BACKING_STORE;
-       }
-    }
-
-    graphPtr->flags &= ~RESET_AXES;
-
-    /*
-     * When any axis changes, we need to layout the entire graph.
-     */
-    graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | 
-                       MAP_ALL | REDRAW_WORLD);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * ResetTextStyles --
- *
- *     Configures axis attributes (font, line width, label, etc) and
- *     allocates a new (possibly shared) graphics context.  Line cap
- *     style is projecting.  This is for the problem of when a tick
- *     sits directly at the end point of the axis.
- *
- * Results:
- *     The return value is a standard Tcl result.
- *
- * Side Effects:
- *     Axis resources are allocated (GC, font). Axis layout is
- *     deferred until the height and width of the window are known.
- *
- * ----------------------------------------------------------------------
- */
-static void
-ResetTextStyles(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    GC newGC;
-    XGCValues gcValues;
-    unsigned long gcMask;
-
-    Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->titleTextStyle);
-    Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->tickTextStyle);
-    Blt_ResetTextStyle(graphPtr->tkwin, &axisPtr->limitsTextStyle);
-
-    gcMask = (GCForeground | GCLineWidth | GCCapStyle);
-    gcValues.foreground = axisPtr->tickTextStyle.color->pixel;
-    gcValues.line_width = LineWidth(axisPtr->lineWidth);
-    gcValues.cap_style = CapProjecting;
-
-    newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
-    if (axisPtr->tickGC != NULL) {
-       Tk_FreeGC(graphPtr->display, axisPtr->tickGC);
-    }
-    axisPtr->tickGC = newGC;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * DestroyAxis --
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Resources (font, color, gc, labels, etc.) associated with the
- *     axis are deallocated.
- *
- * ----------------------------------------------------------------------
- */
-static void
-DestroyAxis(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    int flags;
-
-    flags = Blt_GraphType(graphPtr);
-    Tk_FreeOptions(configSpecs, (char *)axisPtr, graphPtr->display, flags);
-    if (graphPtr->bindTable != NULL) {
-       Blt_DeleteBindings(graphPtr->bindTable, axisPtr);
-    }
-    if (axisPtr->linkPtr != NULL) {
-       Blt_ChainDeleteLink(axisPtr->chainPtr, axisPtr->linkPtr);
-    }
-    if (axisPtr->name != NULL) {
-       Blt_Free(axisPtr->name);
-    }
-    if (axisPtr->hashPtr != NULL) {
-       Blt_DeleteHashEntry(&graphPtr->axes.table, axisPtr->hashPtr);
-    }
-    Blt_FreeTextStyle(graphPtr->display, &axisPtr->titleTextStyle);
-    Blt_FreeTextStyle(graphPtr->display, &axisPtr->limitsTextStyle);
-    Blt_FreeTextStyle(graphPtr->display, &axisPtr->tickTextStyle);
-
-    if (axisPtr->tickGC != NULL) {
-       Tk_FreeGC(graphPtr->display, axisPtr->tickGC);
-    }
-    if (axisPtr->t1Ptr != NULL) {
-       Blt_Free(axisPtr->t1Ptr);
-    }
-    if (axisPtr->t2Ptr != NULL) {
-       Blt_Free(axisPtr->t2Ptr);
-    }
-    if (axisPtr->limitsFormats != NULL) {
-       Blt_Free(axisPtr->limitsFormats);
-    }
-    FreeLabels(axisPtr->tickLabels);
-    Blt_ChainDestroy(axisPtr->tickLabels);
-    if (axisPtr->segments != NULL) {
-       Blt_Free(axisPtr->segments);
-    }
-    if (axisPtr->tags != NULL) {
-       Blt_Free(axisPtr->tags);
-    }
-    Blt_Free(axisPtr);
-}
-
-static double titleRotate[4] = /* Rotation for each axis title */
-{
-    0.0, 90.0, 0.0, 270.0
-};
-
-/*
- * ----------------------------------------------------------------------
- *
- * AxisOffsets --
- *
- *     Determines the sites of the axis, major and minor ticks,
- *     and title of the axis.
- *
- * Results:
- *     None.
- *
- * ----------------------------------------------------------------------
- */
-static void
-AxisOffsets(graphPtr, axisPtr, margin, axisOffset, infoPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int margin;
-    int axisOffset;
-    AxisInfo *infoPtr;
-{
-    int pad;                   /* Offset of axis from interior region. This
-                                * includes a possible border and the axis
-                                * line width. */
-    int p;
-    int majorOffset, minorOffset, labelOffset;
-    int offset;
-    int x, y;
-
-    axisPtr->titleTextStyle.theta = titleRotate[margin];
-
-    majorOffset = minorOffset = 0;
-    labelOffset = AXIS_TITLE_PAD;
-    if (axisPtr->lineWidth > 0) {
-       majorOffset = ABS(axisPtr->tickLength);
-       minorOffset = 10 * majorOffset / 15;
-       labelOffset = majorOffset + AXIS_TITLE_PAD + axisPtr->lineWidth / 2;
-    }
-    /* Adjust offset for the interior border width and the line width */
-    pad = axisPtr->lineWidth + 1;
-    if (graphPtr->plotBorderWidth > 0) {
-       pad += graphPtr->plotBorderWidth + 1;
-    }
-    offset = axisOffset + 1 + pad;
-    if ((margin == MARGIN_LEFT) || (margin == MARGIN_TOP)) {
-       majorOffset = -majorOffset;
-       minorOffset = -minorOffset;
-       labelOffset = -labelOffset;
-    }
-    /*
-     * Pre-calculate the x-coordinate positions of the axis, tick labels, and
-     * the individual major and minor ticks.
-     */
-    p = 0;             /* Suppress compiler warning */
-    
-    switch (margin) {
-    case MARGIN_TOP:
-       p = graphPtr->top - axisOffset - pad;
-       if (axisPtr->titleAlternate) {
-           x = graphPtr->right + AXIS_TITLE_PAD;
-           y = graphPtr->top - axisOffset - (axisPtr->height  / 2);
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_W;
-       } else {
-           x = (graphPtr->right + graphPtr->left) / 2;
-           y = graphPtr->top - axisOffset - axisPtr->height - AXIS_TITLE_PAD;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_N;
-       }
-       axisPtr->tickTextStyle.anchor = TK_ANCHOR_S;
-       offset = axisPtr->borderWidth + axisPtr->lineWidth / 2;
-       axisPtr->region.left = graphPtr->hOffset - offset - 2;
-       axisPtr->region.right = graphPtr->hOffset + graphPtr->hRange + 
-           offset - 1;
-       axisPtr->region.top = p + labelOffset - 1;
-       axisPtr->region.bottom = p;
-       axisPtr->titlePos.x = x;
-       axisPtr->titlePos.y = y;
-       break;
-
-    case MARGIN_BOTTOM:
-       p = graphPtr->bottom + axisOffset + pad;
-       if (axisPtr->titleAlternate) {
-           x = graphPtr->right + AXIS_TITLE_PAD;
-           y = graphPtr->bottom + axisOffset + (axisPtr->height / 2);
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_W; 
-       } else {
-           x = (graphPtr->right + graphPtr->left) / 2;
-           y = graphPtr->bottom + axisOffset + axisPtr->height + 
-               AXIS_TITLE_PAD;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_S; 
-       }
-       axisPtr->tickTextStyle.anchor = TK_ANCHOR_N;
-       offset = axisPtr->borderWidth + axisPtr->lineWidth / 2;
-       axisPtr->region.left = graphPtr->hOffset - offset - 2;
-       axisPtr->region.right = graphPtr->hOffset + graphPtr->hRange + 
-           offset - 1;
-
-       axisPtr->region.top = graphPtr->bottom + axisOffset + 
-           axisPtr->lineWidth - axisPtr->lineWidth / 2;
-       axisPtr->region.bottom = graphPtr->bottom + axisOffset + 
-           axisPtr->lineWidth + labelOffset + 1;
-       axisPtr->titlePos.x = x;
-       axisPtr->titlePos.y = y;
-       break;
-
-    case MARGIN_LEFT:
-       p = graphPtr->left - axisOffset - pad;
-       if (axisPtr->titleAlternate) {
-           x = graphPtr->left - axisOffset - (axisPtr->width / 2);
-           y = graphPtr->top - AXIS_TITLE_PAD;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_SW; 
-       } else {
-           x = graphPtr->left - axisOffset - axisPtr->width -
-               graphPtr->plotBorderWidth;
-           y = (graphPtr->bottom + graphPtr->top) / 2;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_W; 
-       }
-       axisPtr->tickTextStyle.anchor = TK_ANCHOR_E;
-       axisPtr->region.left = graphPtr->left - offset + labelOffset - 1;
-       axisPtr->region.right = graphPtr->left - offset + 2;
-
-       offset = axisPtr->borderWidth + axisPtr->lineWidth / 2;
-       axisPtr->region.top = graphPtr->vOffset - offset - 2;
-       axisPtr->region.bottom = graphPtr->vOffset + graphPtr->vRange + 
-           offset - 1;
-       axisPtr->titlePos.x = x;
-       axisPtr->titlePos.y = y;
-       break;
-
-    case MARGIN_RIGHT:
-       p = graphPtr->right + axisOffset + pad;
-       if (axisPtr->titleAlternate) {
-           x = graphPtr->right + axisOffset + (axisPtr->width / 2);
-           y = graphPtr->top - AXIS_TITLE_PAD;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_SE; 
-       } else {
-           x = graphPtr->right + axisOffset + axisPtr->width + 
-               AXIS_TITLE_PAD;
-           y = (graphPtr->bottom + graphPtr->top) / 2;
-           axisPtr->titleTextStyle.anchor = TK_ANCHOR_E;
-       }
-       axisPtr->tickTextStyle.anchor = TK_ANCHOR_W;
-
-       axisPtr->region.left = graphPtr->right + axisOffset + 
-           axisPtr->lineWidth - axisPtr->lineWidth / 2;
-       axisPtr->region.right = graphPtr->right + axisOffset + 
-           labelOffset + axisPtr->lineWidth + 1;
-
-       offset = axisPtr->borderWidth + axisPtr->lineWidth / 2;
-       axisPtr->region.top = graphPtr->vOffset - offset - 2;
-       axisPtr->region.bottom = graphPtr->vOffset + graphPtr->vRange + 
-           offset - 1;
-       axisPtr->titlePos.x = x;
-       axisPtr->titlePos.y = y;
-       break;
-
-    case MARGIN_NONE:
-       break;
-    }
-    infoPtr->axis = p - (axisPtr->lineWidth / 2);
-    infoPtr->t1 = p + majorOffset;
-    infoPtr->t2 = p + minorOffset;
-    infoPtr->label = p + labelOffset;
-
-    if (axisPtr->tickLength < 0) {
-       int hold;
-       
-       hold = infoPtr->t1;
-       infoPtr->t1 = infoPtr->axis;
-       infoPtr->axis = hold;
-    }
-}
-
-static void
-MakeAxisLine(graphPtr, axisPtr, line, segPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;             /* Axis information */
-    int line;
-    Segment2D *segPtr;
-{
-    double min, max;
-
-    min = axisPtr->axisRange.min;
-    max = axisPtr->axisRange.max;
-    if (axisPtr->logScale) {
-       min = EXP10(min);
-       max = EXP10(max);
-    }
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       segPtr->p.x = Blt_HMap(graphPtr, axisPtr, min);
-       segPtr->q.x = Blt_HMap(graphPtr, axisPtr, max);
-       segPtr->p.y = segPtr->q.y = line;
-    } else {
-       segPtr->q.x = segPtr->p.x = line;
-       segPtr->p.y = Blt_VMap(graphPtr, axisPtr, min);
-       segPtr->q.y = Blt_VMap(graphPtr, axisPtr, max);
-    }
-}
-
-
-static void
-MakeTick(graphPtr, axisPtr, value, tick, line, segPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double value;
-    int tick, line;            /* Lengths of tick and axis line. */
-    Segment2D *segPtr;
-{
-    if (axisPtr->logScale) {
-       value = EXP10(value);
-    }
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       segPtr->p.x = segPtr->q.x = Blt_HMap(graphPtr, axisPtr, value);
-       segPtr->p.y = line;
-       segPtr->q.y = tick;
-    } else {
-       segPtr->p.x = line;
-       segPtr->p.y = segPtr->q.y = Blt_VMap(graphPtr, axisPtr, value);
-       segPtr->q.x = tick;
-    }
-}
-
-/*
- * -----------------------------------------------------------------
- *
- * MapAxis --
- *
- *     Pre-calculates positions of the axis, ticks, and labels (to be
- *     used later when displaying the axis).  Calculates the values
- *     for each major and minor tick and checks to see if they are in
- *     range (the outer ticks may be outside of the range of plotted
- *     values).
- *
- *     Line segments for the minor and major ticks are saved into one
- *     XSegment array so that they can be drawn by a single
- *     XDrawSegments call. The positions of the tick labels are also
- *     computed and saved.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     Line segments and tick labels are saved and used later to draw
- *     the axis.
- *
- * -----------------------------------------------------------------
- */
-static void
-MapAxis(graphPtr, axisPtr, offset, margin)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int offset;
-    int margin;
-{
-    int arraySize;
-    int nMajorTicks, nMinorTicks;
-    AxisInfo info;
-    Segment2D *segments;
-    Segment2D *segPtr;
-
-    AxisOffsets(graphPtr, axisPtr, margin, offset, &info);
-
-    /* Save all line coordinates in an array of line segments. */
-
-    if (axisPtr->segments != NULL) {
-       Blt_Free(axisPtr->segments);
-    }
-    nMajorTicks = nMinorTicks = 0;
-    if (axisPtr->t1Ptr != NULL) {
-       nMajorTicks = axisPtr->t1Ptr->nTicks;
-    }
-    if (axisPtr->t2Ptr != NULL) {
-       nMinorTicks = axisPtr->t2Ptr->nTicks;
-    }
-    arraySize = 1 + (nMajorTicks * (nMinorTicks + 1));
-    segments = Blt_Malloc(arraySize * sizeof(Segment2D));
-    assert(segments);
-
-    segPtr = segments;
-    if (axisPtr->lineWidth > 0) {
-       /* Axis baseline */
-       MakeAxisLine(graphPtr, axisPtr, info.axis, segPtr);
-       segPtr++;
-    }
-    if (axisPtr->showTicks) {
-       double t1, t2;
-       double labelPos;
-       register int i, j;
-       int isHoriz;
-       TickLabel *labelPtr;
-       Blt_ChainLink *linkPtr;
-       Segment2D seg;
-
-       isHoriz = AxisIsHorizontal(graphPtr, axisPtr);
-       for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) {
-           t1 = axisPtr->t1Ptr->values[i];
-           /* Minor ticks */
-           for (j = 0; j < axisPtr->t2Ptr->nTicks; j++) {
-               t2 = t1 +
-                   (axisPtr->majorSweep.step * axisPtr->t2Ptr->values[j]);
-               if (InRange(t2, &axisPtr->axisRange)) {
-                   MakeTick(graphPtr, axisPtr, t2, info.t2, info.axis, 
-                            segPtr);
-                   segPtr++;
-               }
-           }
-           if (!InRange(t1, &axisPtr->axisRange)) {
-               continue;
-           }
-           /* Major tick */
-           MakeTick(graphPtr, axisPtr, t1, info.t1, info.axis, segPtr);
-           segPtr++;
-       }
-
-       linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels);
-       labelPos = (double)info.label;
-
-       for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) {
-           t1 = axisPtr->t1Ptr->values[i];
-           if (axisPtr->labelOffset) {
-               t1 += axisPtr->majorSweep.step * 0.5;
-           }
-           if (!InRange(t1, &axisPtr->axisRange)) {
-               continue;
-           }
-           labelPtr = Blt_ChainGetValue(linkPtr);
-           linkPtr = Blt_ChainNextLink(linkPtr);
-           MakeTick(graphPtr, axisPtr, t1, info.t1, info.axis, &seg);
-           /* Save tick label X-Y position. */
-           if (isHoriz) {
-               labelPtr->anchorPos.x = seg.p.x;
-               labelPtr->anchorPos.y = labelPos;
-           } else {
-               labelPtr->anchorPos.x = labelPos;
-               labelPtr->anchorPos.y = seg.p.y;
-           }
-       }
-    }
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       axisPtr->width = graphPtr->right - graphPtr->left;
-    } else {
-       axisPtr->height = graphPtr->bottom - graphPtr->top;
-    }
-    axisPtr->segments = segments;
-    axisPtr->nSegments = segPtr - segments;
-    assert(axisPtr->nSegments <= arraySize);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * AdjustViewport --
- *
- *     Adjusts the offsets of the viewport according to the scroll mode.
- *     This is to accommodate both "listbox" and "canvas" style scrolling.
- *
- *     "canvas"        The viewport scrolls within the range of world
- *                     coordinates.  This way the viewport always displays
- *                     a full page of the world.  If the world is smaller
- *                     than the viewport, then (bizarrely) the world and
- *                     viewport are inverted so that the world moves up
- *                     and down within the viewport.
- *
- *     "listbox"       The viewport can scroll beyond the range of world
- *                     coordinates.  Every entry can be displayed at the
- *                     top of the viewport.  This also means that the
- *                     scrollbar thumb weirdly shrinks as the last entry
- *                     is scrolled upward.
- *
- * Results:
- *     The corrected offset is returned.
- *
- *----------------------------------------------------------------------
- */
-static double
-AdjustViewport(offset, windowSize)
-    double offset, windowSize;
-{
-    /*
-     * Canvas-style scrolling allows the world to be scrolled
-     * within the window.
-     */
-    if (windowSize > 1.0) {
-       if (windowSize < (1.0 - offset)) {
-           offset = 1.0 - windowSize;
-       }
-       if (offset > 0.0) {
-           offset = 0.0;
-       }
-    } else {
-       if ((offset + windowSize) > 1.0) {
-           offset = 1.0 - windowSize;
-       }
-       if (offset < 0.0) {
-           offset = 0.0;
-       }
-    }
-    return offset;
-}
-
-static int
-GetAxisScrollInfo(interp, argc, argv, offsetPtr, windowSize, scrollUnits)
-    Tcl_Interp *interp;
-    int argc;
-    char **argv;
-    double *offsetPtr;
-    double windowSize;
-    double scrollUnits;
-{
-    char c;
-    unsigned int length;
-    double offset;
-    int count;
-    double fract;
-
-    offset = *offsetPtr;
-    c = argv[0][0];
-    length = strlen(argv[0]);
-    if ((c == 's') && (strncmp(argv[0], "scroll", length) == 0)) {
-       /* assert(argc == 3); */
-         if (argc != 3) {
-             Tcl_AppendResult(interp, "expected arg", 0);
-             return TCL_ERROR;
-         }
-         /* scroll number unit/page */
-       if (Tcl_GetInt(interp, argv[1], &count) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       c = argv[2][0];
-       length = strlen(argv[2]);
-       if ((c == 'u') && (strncmp(argv[2], "units", length) == 0)) {
-           fract = (double)count * scrollUnits;
-       } else if ((c == 'p') && (strncmp(argv[2], "pages", length) == 0)) {
-           /* A page is 90% of the view-able window. */
-           fract = (double)count * windowSize * 0.9;
-       } else {
-           Tcl_AppendResult(interp, "unknown \"scroll\" units \"", argv[2],
-               "\"", (char *)NULL);
-           return TCL_ERROR;
-       }
-       offset += fract;
-    } else if ((c == 'm') && (strncmp(argv[0], "moveto", length) == 0)) {
-       /*assert(argc == 2);*/
-       if (argc != 2) {
-           Tcl_AppendResult(interp, "expected arg", 0);
-           return TCL_ERROR;
-       }
-       /* moveto fraction */
-       if (Tcl_GetDouble(interp, argv[1], &fract) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       offset = fract;
-    } else {
-       /* Treat like "scroll units" */
-       if (Tcl_GetInt(interp, argv[0], &count) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       fract = (double)count * scrollUnits;
-       offset += fract;
-       /* CHECK THIS: return TCL_OK; */
-    }
-    *offsetPtr = AdjustViewport(offset, windowSize);
-    return TCL_OK;
-}
-
-/*
- * -----------------------------------------------------------------
- *
- * DrawAxis --
- *
- *     Draws the axis, ticks, and labels onto the canvas.
- *
- *     Initializes and passes text attribute information through
- *     TextStyle structure.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     Axis gets drawn on window.
- *
- * -----------------------------------------------------------------
- */
-static void
-DrawAxis(graphPtr, drawable, axisPtr)
-    Graph *graphPtr;
-    Drawable drawable;
-    Axis *axisPtr;
-{
-    if (axisPtr->border != NULL) {
-       Blt_Fill3DRectangle(graphPtr->tkwin, drawable, axisPtr->border,
-               axisPtr->region.left + graphPtr->plotBorderWidth, 
-               axisPtr->region.top + graphPtr->plotBorderWidth, 
-               axisPtr->region.right - axisPtr->region.left, 
-               axisPtr->region.bottom - axisPtr->region.top, 
-               axisPtr->borderWidth, axisPtr->relief);
-    }
-    if (axisPtr->title != NULL) {
-       Blt_DrawText(graphPtr->tkwin, drawable, axisPtr->title,
-               &axisPtr->titleTextStyle, (int)axisPtr->titlePos.x, 
-               (int)axisPtr->titlePos.y);
-    }
-    if (axisPtr->scrollCmdPrefix != NULL) {
-       double viewWidth, viewMin, viewMax;
-       double worldWidth, worldMin, worldMax;
-       double fract;
-       int isHoriz;
-
-       worldMin = axisPtr->valueRange.min;
-       worldMax = axisPtr->valueRange.max;
-       if (DEFINED(axisPtr->scrollMin)) {
-           worldMin = axisPtr->scrollMin;
-       }
-       if (DEFINED(axisPtr->scrollMax)) {
-           worldMax = axisPtr->scrollMax;
-       }
-       viewMin = axisPtr->min;
-       viewMax = axisPtr->max;
-       if (viewMin < worldMin) {
-           viewMin = worldMin;
-       }
-       if (viewMax > worldMax) {
-           viewMax = worldMax;
-       }
-       if (axisPtr->logScale) {
-           worldMin = log10(worldMin);
-           worldMax = log10(worldMax);
-           viewMin = log10(viewMin);
-           viewMax = log10(viewMax);
-       }
-       worldWidth = worldMax - worldMin;       
-       viewWidth = viewMax - viewMin;
-       isHoriz = AxisIsHorizontal(graphPtr, axisPtr);
-
-       if (isHoriz != axisPtr->descending) {
-           fract = (viewMin - worldMin) / worldWidth;
-       } else {
-           fract = (worldMax - viewMax) / worldWidth;
-       }
-       fract = AdjustViewport(fract, viewWidth / worldWidth);
-
-       if (isHoriz != axisPtr->descending) {
-           viewMin = (fract * worldWidth);
-           axisPtr->min = viewMin + worldMin;
-           axisPtr->max = axisPtr->min + viewWidth;
-           viewMax = viewMin + viewWidth;
-           if (axisPtr->logScale) {
-               axisPtr->min = EXP10(axisPtr->min);
-               axisPtr->max = EXP10(axisPtr->max);
-           }
-           Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdPrefix,
-               (viewMin / worldWidth), (viewMax / worldWidth));
-       } else {
-           viewMax = (fract * worldWidth);
-           axisPtr->max = worldMax - viewMax;
-           axisPtr->min = axisPtr->max - viewWidth;
-           viewMin = viewMax + viewWidth;
-           if (axisPtr->logScale) {
-               axisPtr->min = EXP10(axisPtr->min);
-               axisPtr->max = EXP10(axisPtr->max);
-           }
-           Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdPrefix,
-               (viewMax / worldWidth), (viewMin / worldWidth));
-       }
-    }
-    if (axisPtr->showTicks) {
-       register Blt_ChainLink *linkPtr;
-       TickLabel *labelPtr;
-
-       for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); linkPtr != NULL;
-           linkPtr = Blt_ChainNextLink(linkPtr)) {     
-           /* Draw major tick labels */
-           labelPtr = Blt_ChainGetValue(linkPtr);
-           Blt_DrawText(graphPtr->tkwin, drawable, labelPtr->string,
-               &axisPtr->tickTextStyle, (int)labelPtr->anchorPos.x, 
-               (int)labelPtr->anchorPos.y);
-       }
-    }
-    if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) {        
-       /* Draw the tick marks and axis line. */
-       Blt_Draw2DSegments(graphPtr->display, drawable, axisPtr->tickGC,
-           axisPtr->segments, axisPtr->nSegments);
-    }
-}
-
-/*
- * -----------------------------------------------------------------
- *
- * AxisToPostScript --
- *
- *     Generates PostScript output to draw the axis, ticks, and
- *     labels.
- *
- *     Initializes and passes text attribute information through
- *     TextStyle structure.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     PostScript output is left in graphPtr->interp->result;
- *
- * -----------------------------------------------------------------
- */
-/* ARGSUSED */
-static void
-AxisToPostScript(psToken, axisPtr)
-    PsToken psToken;
-    Axis *axisPtr;
-{
-    if (axisPtr->title != NULL) {
-       Blt_TextToPostScript(psToken, axisPtr->title, &axisPtr->titleTextStyle, 
-               axisPtr->titlePos.x, axisPtr->titlePos.y);
-    }
-    if (axisPtr->showTicks) {
-       register Blt_ChainLink *linkPtr;
-       TickLabel *labelPtr;
-
-       for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); 
-            linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
-           labelPtr = Blt_ChainGetValue(linkPtr);
-           Blt_TextToPostScript(psToken, labelPtr->string, 
-               &axisPtr->tickTextStyle, labelPtr->anchorPos.x, 
-               labelPtr->anchorPos.y);
-       }
-    }
-    if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) {
-       Blt_LineAttributesToPostScript(psToken, axisPtr->tickTextStyle.color,
-           axisPtr->lineWidth, (Blt_Dashes *)NULL, CapButt, JoinMiter);
-       Blt_2DSegmentsToPostScript(psToken, axisPtr->segments, 
-          axisPtr->nSegments);
-    }
-}
-
-static void
-MakeGridLine(graphPtr, axisPtr, value, segPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    double value;
-    Segment2D *segPtr;
-{
-    if (axisPtr->logScale) {
-       value = EXP10(value);
-    }
-    /* Grid lines run orthogonally to the axis */
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       segPtr->p.y = graphPtr->top;
-       segPtr->q.y = graphPtr->bottom;
-       segPtr->p.x = segPtr->q.x = Blt_HMap(graphPtr, axisPtr, value);
-    } else {
-       segPtr->p.x = graphPtr->left;
-       segPtr->q.x = graphPtr->right;
-       segPtr->p.y = segPtr->q.y = Blt_VMap(graphPtr, axisPtr, value);
-    }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Blt_GetAxisSegments --
- *
- *     Assembles the grid lines associated with an axis. Generates
- *     tick positions if necessary (this happens when the axis is
- *     not a logical axis too).
- *
- * Results:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-void
-Blt_GetAxisSegments(graphPtr, axisPtr, segPtrPtr, nSegmentsPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    Segment2D **segPtrPtr;
-    int *nSegmentsPtr;
-{
-    int needed;
-    Ticks *t1Ptr, *t2Ptr;
-    register int i;
-    double value;
-    Segment2D *segments, *segPtr;
-
-    *nSegmentsPtr = 0;
-    *segPtrPtr = NULL;
-    if (axisPtr == NULL) {
-       return;
-    }
-    t1Ptr = axisPtr->t1Ptr;
-    if (t1Ptr == NULL) {
-       t1Ptr = GenerateTicks(&axisPtr->majorSweep);
-    }
-    t2Ptr = axisPtr->t2Ptr;
-    if (t2Ptr == NULL) {
-       t2Ptr = GenerateTicks(&axisPtr->minorSweep);
-    }
-
-    needed = t1Ptr->nTicks;
-    if (graphPtr->gridPtr->minorGrid) {
-       needed += (t1Ptr->nTicks * t2Ptr->nTicks);
-    }
-    if (needed == 0) {
-       return;                 
-    }
-    segments = Blt_Malloc(sizeof(Segment2D) * needed);
-    if (segments == NULL) {
-       return;                 /* Can't allocate memory for grid. */
-    }
-
-    segPtr = segments;
-    for (i = 0; i < t1Ptr->nTicks; i++) {
-       value = t1Ptr->values[i];
-       if (graphPtr->gridPtr->minorGrid) {
-           register int j;
-           double subValue;
-
-           for (j = 0; j < t2Ptr->nTicks; j++) {
-               subValue = value +
-                   (axisPtr->majorSweep.step * t2Ptr->values[j]);
-               if (InRange(subValue, &axisPtr->axisRange)) {
-                   MakeGridLine(graphPtr, axisPtr, subValue, segPtr);
-                   segPtr++;
-               }
-           }
-       }
-       if (InRange(value, &axisPtr->axisRange)) {
-           MakeGridLine(graphPtr, axisPtr, value, segPtr);
-           segPtr++;
-       }
-    }
-
-    if (t1Ptr != axisPtr->t1Ptr) {
-       Blt_Free(t1Ptr);        /* Free generated ticks. */
-    }
-    if (t2Ptr != axisPtr->t2Ptr) {
-       Blt_Free(t2Ptr);        /* Free generated ticks. */
-    }
-    *nSegmentsPtr = segPtr - segments;
-    assert(*nSegmentsPtr <= needed);
-    *segPtrPtr = segments;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * GetAxisGeometry --
- *
- * Results:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-static void
-GetAxisGeometry(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    int height;
-
-    FreeLabels(axisPtr->tickLabels);
-    height = 0;
-    if (axisPtr->lineWidth > 0) {
-       /* Leave room for axis baseline (and pad) */
-       height += axisPtr->lineWidth + 2;
-    }
-    if (axisPtr->showTicks) {
-       int pad;
-       register int i, nLabels;
-       int lw, lh;
-       double x, x2;
-       int maxWidth, maxHeight;
-       TickLabel *labelPtr;
-
-       SweepTicks(axisPtr);
-       
-       if (axisPtr->t1Ptr->nTicks < 0) {
-           fprintf(stderr, "%s major ticks can't be %d\n",
-                   axisPtr->name, axisPtr->t1Ptr->nTicks);
-           abort();
-       }
-       if (axisPtr->t1Ptr->nTicks > MAXTICKS) {
-           fprintf(stderr, "too big, %s major ticks can't be %d\n",
-                   axisPtr->name, axisPtr->t1Ptr->nTicks);
-           abort();
-       }
-       
-       maxHeight = maxWidth = 0;
-       nLabels = 0;
-       for (i = 0; i < axisPtr->t1Ptr->nTicks; i++) {
-           x2 = x = axisPtr->t1Ptr->values[i];
-           if (axisPtr->labelOffset) {
-               x2 += axisPtr->majorSweep.step * 0.5;
-           }
-           if (!InRange(x2, &axisPtr->axisRange)) {
-               continue;
-           }
-           labelPtr = MakeLabel(graphPtr, axisPtr, x);
-           Blt_ChainAppend(axisPtr->tickLabels, labelPtr);
-           nLabels++;
-           /* 
-            * Get the dimensions of each tick label.  
-            * Remember tick labels can be multi-lined and/or rotated. 
-            */
-           Blt_GetTextExtents(&axisPtr->tickTextStyle, labelPtr->string, 
-              &lw, &lh);
-           labelPtr->width = lw;
-           labelPtr->height = lh;
-
-           if (axisPtr->tickTextStyle.theta > 0.0) {
-               double rotWidth, rotHeight;
-
-               Blt_GetBoundingBox(lw, lh, axisPtr->tickTextStyle.theta, 
-                       &rotWidth, &rotHeight, (Point2D *)NULL);
-               lw = ROUND(rotWidth);
-               lh = ROUND(rotHeight);
-           }
-           if (maxWidth < lw) {
-               maxWidth = lw;
-           }
-           if (maxHeight < lh) {
-               maxHeight = lh;
-           }
-       }
-       assert(nLabels <= axisPtr->t1Ptr->nTicks);
-       
-       /* Because the axis cap style is "CapProjecting", we need to
-        * account for an extra 1.5 linewidth at the end of each
-        * line.  */
-
-       pad = ((axisPtr->lineWidth * 15) / 10);
-       
-       if (AxisIsHorizontal(graphPtr, axisPtr)) {
-           height += maxHeight + pad;
-       } else {
-           height += maxWidth + pad;
-       }
-       if (axisPtr->lineWidth > 0) {
-           /* Distance from axis line to tick label. */
-           height += AXIS_TITLE_PAD;
-           height += ABS(axisPtr->tickLength);
-       }
-    }
-
-    if (axisPtr->title != NULL) {
-       if (axisPtr->titleAlternate) {
-           if (height < axisPtr->titleHeight) {
-               height = axisPtr->titleHeight;
-           }
-       } else {
-           height += axisPtr->titleHeight + AXIS_TITLE_PAD;
-       }
-    }
-
-    /* Correct for orientation of the axis. */
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       axisPtr->height = height;
-    } else {
-       axisPtr->width = height;
-    }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * GetMarginGeometry --
- *
- *     Examines all the axes in the given margin and determines the 
- *     area required to display them.  
- *
- *     Note: For multiple axes, the titles are displayed in another
- *           margin. So we must keep track of the widest title.
- *     
- * Results:
- *     Returns the width or height of the margin, depending if it
- *     runs horizontally along the graph or vertically.
- *
- * Side Effects:
- *     The area width and height set in the margin.  Note again that
- *     this may be corrected later (mulitple axes) to adjust for
- *     the longest title in another margin.
- *
- *----------------------------------------------------------------------
- */
-static int
-GetMarginGeometry(graphPtr, marginPtr)
-    Graph *graphPtr;
-    Margin *marginPtr;
-{
-    Blt_ChainLink *linkPtr;
-    Axis *axisPtr;
-    int width, height;
-    int isHoriz;
-    int length, count;
-
-    isHoriz = HORIZMARGIN(marginPtr);
-    /* Count the number of visible axes. */
-    count = 0;
-    length = width = height = 0;
-    for (linkPtr = Blt_ChainFirstLink(marginPtr->axes); linkPtr != NULL;
-        linkPtr = Blt_ChainNextLink(linkPtr)) {
-       axisPtr = Blt_ChainGetValue(linkPtr);
-       if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) {
-           count++;
-           if (graphPtr->flags & GET_AXIS_GEOMETRY) {
-               GetAxisGeometry(graphPtr, axisPtr);
-           }
-           if ((axisPtr->titleAlternate) && (length < axisPtr->titleWidth)) {
-               length = axisPtr->titleWidth;
-           }
-           if (isHoriz) {
-               height += axisPtr->height;
-           } else {
-               width += axisPtr->width;
-           }
-       }
-    }
-    /* Enforce a minimum size for margins. */
-    if (width < 3) {
-       width = 3;
-    }
-    if (height < 3) {
-       height = 3;
-    }
-    marginPtr->nAxes = count;
-    marginPtr->axesTitleLength = length;
-    marginPtr->width = width;
-    marginPtr->height = height;
-    marginPtr->axesOffset = (HORIZMARGIN(marginPtr)) ? height : width;
-    return marginPtr->axesOffset;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ComputeMargins --
- *
- *     Computes the size of the margins and the plotting area.  We
- *     first compute the space needed for the axes in each margin.
- *     Then how much space the legend will occupy.  Finally, if the
- *     user has requested a margin size, we override the computed
- *     value.
- *
- * Results:
- *
- *---------------------------------------------------------------------- */
-static void
-ComputeMargins(graphPtr)
-    Graph *graphPtr;
-{
-    int left, right, top, bottom;
-    int width, height;
-    int insets;
-
-    /* 
-     * Step 1: Compute the amount of space needed to display the
-     *         axes (there many be 0 or more) associated with the
-     *         margin.
-     */
-    top = GetMarginGeometry(graphPtr, &graphPtr->topMargin);
-    bottom = GetMarginGeometry(graphPtr, &graphPtr->bottomMargin);
-    left = GetMarginGeometry(graphPtr, &graphPtr->leftMargin);
-    right = GetMarginGeometry(graphPtr, &graphPtr->rightMargin);
-
-    /* 
-     * Step 2:  Add the graph title height to the top margin. 
-     */
-    if (graphPtr->title != NULL) {
-       top += graphPtr->titleTextStyle.height;
-    }
-    insets = 2 * (graphPtr->inset + graphPtr->plotBorderWidth);
-
-    /* 
-     * Step 3:  Use the current estimate of the plot area to compute 
-     *         the legend size.  Add it to the proper margin.
-     */
-    width = graphPtr->width - (insets + left + right);
-    height = graphPtr->height - (insets + top + bottom);
-    Blt_MapLegend(graphPtr->legend, width, height);
-    if (!Blt_LegendIsHidden(graphPtr->legend)) {
-       switch (Blt_LegendSite(graphPtr->legend)) {
-       case LEGEND_RIGHT:
-           right += Blt_LegendWidth(graphPtr->legend) + 2;
-           break;
-       case LEGEND_LEFT:
-           left += Blt_LegendWidth(graphPtr->legend) + 2;
-           break;
-       case LEGEND_TOP:
-           top += Blt_LegendHeight(graphPtr->legend) + 2;
-           break;
-       case LEGEND_BOTTOM:
-           bottom += Blt_LegendHeight(graphPtr->legend) + 2;
-           break;
-       case LEGEND_XY:
-       case LEGEND_PLOT:
-       case LEGEND_WINDOW:
-           /* Do nothing. */
-           break;
-       }
-    }
-
-    /* 
-     * Recompute the plotarea, now accounting for the legend. 
-     */
-    width = graphPtr->width - (insets + left + right);
-    height = graphPtr->height - (insets + top + bottom);
-
-    /*
-     * Step 5: If necessary, correct for the requested plot area 
-     *         aspect ratio.
-     */
-    if (graphPtr->aspect > 0.0) {
-       double ratio;
-
-       /* 
-        * Shrink one dimension of the plotarea to fit the requested
-        * width/height aspect ratio.  
-        */
-       ratio = (double)width / (double)height;
-       if (ratio > graphPtr->aspect) {
-           int scaledWidth;
-
-           /* Shrink the width. */
-           scaledWidth = (int)(height * graphPtr->aspect);
-           if (scaledWidth < 1) {
-               scaledWidth = 1;
-           }
-           right += (width - scaledWidth); /* Add the difference to
-                                            * the right margin. */
-           /* CHECK THIS: width = scaledWidth; */
-       } else {
-           int scaledHeight;
-
-           /* Shrink the height. */
-           scaledHeight = (int)(width / graphPtr->aspect);
-           if (scaledHeight < 1) {
-               scaledHeight = 1;
-           }
-           top += (height - scaledHeight); /* Add the difference to
-                                           * the top margin. */
-           /* CHECK THIS: height = scaledHeight; */
-       }
-    }
-
-    /* 
-     * Step 6: If there's multiple axes in a margin, the axis 
-     *         titles will be displayed in the adjoining marging.
-     *         Make sure there's room for the longest axis titles. 
-     */
-
-    if (top < graphPtr->leftMargin.axesTitleLength) {
-       top = graphPtr->leftMargin.axesTitleLength;
-    }
-    if (right < graphPtr->bottomMargin.axesTitleLength) {
-       right = graphPtr->bottomMargin.axesTitleLength;
-    }
-    if (top < graphPtr->rightMargin.axesTitleLength) {
-       top = graphPtr->rightMargin.axesTitleLength;
-    }
-    if (right < graphPtr->topMargin.axesTitleLength) {
-       right = graphPtr->topMargin.axesTitleLength;
-    }
-
-    /* 
-     * Step 7:  Override calculated values with requested margin 
-     *         sizes. 
-     */
-
-    graphPtr->leftMargin.width = left;
-    graphPtr->rightMargin.width = right;
-    graphPtr->topMargin.height =  top;
-    graphPtr->bottomMargin.height = bottom;
-           
-    if (graphPtr->leftMargin.reqSize > 0) {
-       graphPtr->leftMargin.width = graphPtr->leftMargin.reqSize;
-    }
-    if (graphPtr->rightMargin.reqSize > 0) {
-       graphPtr->rightMargin.width = graphPtr->rightMargin.reqSize;
-    }
-    if (graphPtr->topMargin.reqSize > 0) {
-       graphPtr->topMargin.height = graphPtr->topMargin.reqSize;
-    }
-    if (graphPtr->bottomMargin.reqSize > 0) {
-       graphPtr->bottomMargin.height = graphPtr->bottomMargin.reqSize;
-    }
-}
-
-/*
- * -----------------------------------------------------------------
- *
- * Blt_LayoutMargins --
- *
- *     Calculate the layout of the graph.  Based upon the data,
- *     axis limits, X and Y titles, and title height, determine
- *     the cavity left which is the plotting surface.  The first
- *     step get the data and axis limits for calculating the space
- *     needed for the top, bottom, left, and right margins.
- *
- *     1) The LEFT margin is the area from the left border to the
- *        Y axis (not including ticks). It composes the border
- *        width, the width an optional Y axis label and its padding,
- *        and the tick numeric labels. The Y axis label is rotated
- *        90 degrees so that the width is the font height.
- *
- *     2) The RIGHT margin is the area from the end of the graph
- *        to the right window border. It composes the border width,
- *        some padding, the font height (this may be dubious. It
- *        appears to provide a more even border), the max of the
- *        legend width and 1/2 max X tick number. This last part is
- *        so that the last tick label is not clipped.
- *
- *           Window Width
- *      ___________________________________________________________
- *      |          |                               |               |
- *      |          |   TOP  height of title        |               |
- *      |          |                               |               |
- *      |          |           x2 title            |               |
- *      |          |                               |               |
- *      |          |        height of x2-axis      |               |
- *      |__________|_______________________________|_______________|  W
- *      |          | -plotpady                     |               |  i
- *      |__________|_______________________________|_______________|  n
- *      |          | top                   right   |               |  d
- *      |          |                               |               |  o
- *      |   LEFT   |                               |     RIGHT     |  w
- *      |          |                               |               |
- *      | y        |     Free area = 104%          |      y2       |  H
- *      |          |     Plotting surface = 100%   |               |  e
- *      | t        |     Tick length = 2 + 2%      |      t        |  i
- *      | i        |                               |      i        |  g
- *      | t        |                               |      t  legend|  h
- *      | l        |                               |      l   width|  t
- *      | e        |                               |      e        |
- *      |    height|                               |height         |
- *      |       of |                               | of            |
- *      |    y-axis|                               |y2-axis        |
- *      |          |                               |               |
- *      |          |origin 0,0                     |               |
- *      |__________|_left___________________bottom___|_______________|
- *      |          |-plotpady                      |               |
- *      |__________|_______________________________|_______________|
- *      |          | (xoffset, yoffset)            |               |
- *      |          |                               |               |
- *      |          |       height of x-axis        |               |
- *      |          |                               |               |
- *      |          |   BOTTOM   x title            |               |
- *      |__________|_______________________________|_______________|
- *
- * 3) The TOP margin is the area from the top window border to the top
- *    of the graph. It composes the border width, twice the height of
- *    the title font (if one is given) and some padding between the
- *    title.
- *
- * 4) The BOTTOM margin is area from the bottom window border to the
- *    X axis (not including ticks). It composes the border width, the height
- *    an optional X axis label and its padding, the height of the font
- *    of the tick labels.
- *
- * The plotting area is between the margins which includes the X and Y axes
- * including the ticks but not the tick numeric labels. The length of
- * the ticks and its padding is 5% of the entire plotting area.  Hence the
- * entire plotting area is scaled as 105% of the width and height of the
- * area.
- *
- * The axis labels, ticks labels, title, and legend may or may not be
- * displayed which must be taken into account.
- *
- *
- * -----------------------------------------------------------------
- */
-void
-Blt_LayoutMargins(graphPtr)
-    Graph *graphPtr;
-{
-    int width, height;
-    int titleY;
-    int left, right, top, bottom;
-
-    ComputeMargins(graphPtr);
-    left = graphPtr->leftMargin.width + graphPtr->inset + 
-       graphPtr->plotBorderWidth;
-    right = graphPtr->rightMargin.width + graphPtr->inset + 
-       graphPtr->plotBorderWidth;
-    top = graphPtr->topMargin.height + graphPtr->inset + 
-       graphPtr->plotBorderWidth;
-    bottom = graphPtr->bottomMargin.height + graphPtr->inset + 
-       graphPtr->plotBorderWidth;
-
-    /* Based upon the margins, calculate the space left for the graph. */
-    width = graphPtr->width - (left + right);
-    height = graphPtr->height - (top + bottom);
-    if (width < 1) {
-       width = 1;
-    }
-    if (height < 1) {
-       height = 1;
-    }
-    graphPtr->left = left;
-    graphPtr->right = left + width;
-    graphPtr->bottom = top + height;
-    graphPtr->top = top;
-
-    graphPtr->vOffset = top + graphPtr->padTop;
-    graphPtr->vRange = height - PADDING(graphPtr->padY);
-    graphPtr->hOffset = left + graphPtr->padLeft;
-    graphPtr->hRange = width - PADDING(graphPtr->padX);
-
-    if (graphPtr->vRange < 1) {
-       graphPtr->vRange = 1;
-    }
-    if (graphPtr->hRange < 1) {
-       graphPtr->hRange = 1;
-    }
-    graphPtr->hScale = 1.0 / (double)graphPtr->hRange;
-    graphPtr->vScale = 1.0 / (double)graphPtr->vRange;
-
-    /*
-     * Calculate the placement of the graph title so it is centered within the
-     * space provided for it in the top margin
-     */
-    titleY = graphPtr->titleTextStyle.height;
-    graphPtr->titleY = (titleY / 2) + graphPtr->inset;
-    graphPtr->titleX = (graphPtr->right + graphPtr->left) / 2;
-
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * ConfigureAxis --
- *
- *     Configures axis attributes (font, line width, label, etc).
- *
- * Results:
- *     The return value is a standard Tcl result.
- *
- * Side Effects:
- *     Axis layout is deferred until the height and width of the
- *     window are known.
- *
- * ----------------------------------------------------------------------
- */
-
-static int
-ConfigureAxis(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    char errMsg[200];
-
-    /* Check the requested axis limits. Can't allow -min to be greater
-     * than -max, or have undefined log scale limits.  */
-    if (((DEFINED(axisPtr->reqMin)) && (DEFINED(axisPtr->reqMax))) &&
-       (axisPtr->reqMin >= axisPtr->reqMax)) {
-       sprintf(errMsg, "impossible limits (min %g >= max %g) for axis \"%s\"",
-           axisPtr->reqMin, axisPtr->reqMax, axisPtr->name);
-       Tcl_AppendResult(graphPtr->interp, errMsg, (char *)NULL);
-       /* Bad values, turn on axis auto-scaling */
-       axisPtr->reqMin = axisPtr->reqMax = VALUE_UNDEFINED;
-       return TCL_ERROR;
-    }
-    if ((axisPtr->logScale) && (DEFINED(axisPtr->reqMin)) &&
-       (axisPtr->reqMin <= 0.0)) {
-       sprintf(errMsg, "bad logscale limits (min=%g,max=%g) for axis \"%s\"",
-           axisPtr->reqMin, axisPtr->reqMax, axisPtr->name);
-       Tcl_AppendResult(graphPtr->interp, errMsg, (char *)NULL);
-       /* Bad minimum value, turn on auto-scaling */
-       axisPtr->reqMin = VALUE_UNDEFINED;
-       return TCL_ERROR;
-    }
-    axisPtr->tickTextStyle.theta = FMOD(axisPtr->tickTextStyle.theta, 360.0);
-    if (axisPtr->tickTextStyle.theta < 0.0) {
-       axisPtr->tickTextStyle.theta += 360.0;
-    }
-    ResetTextStyles(graphPtr, axisPtr);
-
-    axisPtr->titleWidth = axisPtr->titleHeight = 0;
-    if (axisPtr->title != NULL) {
-       int w, h;
-
-       Blt_GetTextExtents(&axisPtr->titleTextStyle, axisPtr->title, &w, &h);
-       axisPtr->titleWidth = (short int)w;
-       axisPtr->titleHeight = (short int)h;
-    }
-
-    /* 
-     * Don't bother to check what configuration options have changed.
-     * Almost every option changes the size of the plotting area
-     * (except for -color and -titlecolor), requiring the graph and
-     * its contents to be completely redrawn.
-     *
-     * Recompute the scale and offset of the axis in case -min, -max
-     * options have changed.  
-     */
-    graphPtr->flags |= REDRAW_WORLD;
-    if (!Blt_ConfigModified(configSpecs, graphPtr->interp, "-*color", "-background", "-bg",
-                   (char *)NULL)) {
-       graphPtr->flags |= (MAP_WORLD | RESET_AXES);
-       axisPtr->flags |= AXIS_DIRTY;
-    }
-    Blt_EventuallyRedrawGraph(graphPtr);
-
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * CreateAxis --
- *
- *     Create and initialize a structure containing information to
- *     display a graph axis.
- *
- * Results:
- *     The return value is a standard Tcl result.
- *
- * ----------------------------------------------------------------------
- */
-static Axis *
-CreateAxis(graphPtr, name, margin)
-    Graph *graphPtr;
-    char *name;                        /* Identifier for axis. */
-    int margin;
-{
-    Axis *axisPtr;
-    Blt_HashEntry *hPtr;
-    int isNew;
-
-    if (name[0] == '-') {
-       Tcl_AppendResult(graphPtr->interp, "name of axis \"", name, 
-                        "\" can't start with a '-'", (char *)NULL);
-       return NULL;
-    }
-    hPtr = Blt_CreateHashEntry(&graphPtr->axes.table, name, &isNew);
-    if (!isNew) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       if (!axisPtr->deletePending) {
-           Tcl_AppendResult(graphPtr->interp, "axis \"", name,
-               "\" already exists in \"", Tk_PathName(graphPtr->tkwin), "\"",
-               (char *)NULL);
-           return NULL;
-       }
-       axisPtr->deletePending = FALSE;
-    } else {
-       axisPtr = Blt_Calloc(1, sizeof(Axis));
-       assert(axisPtr);
-
-       axisPtr->name = Blt_Strdup(name);
-       axisPtr->hashPtr = hPtr;
-       axisPtr->classUid = NULL;
-       axisPtr->looseMin = axisPtr->looseMax = TICK_RANGE_TIGHT;
-       axisPtr->reqNumMinorTicks = 2;
-       axisPtr->scrollUnits = 10;
-       axisPtr->showTicks = TRUE;
-       axisPtr->reqMin = axisPtr->reqMax = VALUE_UNDEFINED;
-       axisPtr->scrollMin = axisPtr->scrollMax = VALUE_UNDEFINED;
-
-       if ((graphPtr->classUid == bltBarElementUid) && 
-           ((margin == MARGIN_TOP) || (margin == MARGIN_BOTTOM))) {
-           axisPtr->reqStep = 1.0;
-           axisPtr->reqNumMinorTicks = 0;
-       } 
-       if ((margin == MARGIN_RIGHT) || (margin == MARGIN_TOP)) {
-           axisPtr->hidden = TRUE;
-       }
-       Blt_InitTextStyle(&axisPtr->titleTextStyle);
-       Blt_InitTextStyle(&axisPtr->limitsTextStyle);
-       Blt_InitTextStyle(&axisPtr->tickTextStyle);
-       axisPtr->tickLabels = Blt_ChainCreate();
-       axisPtr->lineWidth = 1;
-       axisPtr->tickTextStyle.padX.side1 = 2;
-       axisPtr->tickTextStyle.padX.side2 = 2;
-       Blt_SetHashValue(hPtr, axisPtr);
-    }
-    return axisPtr;
-}
-
-static int
-NameToAxis(graphPtr, name, axisPtrPtr)
-    Graph *graphPtr;           /* Graph widget record. */
-    char *name;                        /* Name of the axis to be searched for. */
-    Axis **axisPtrPtr;         /* (out) Pointer to found axis structure. */
-{
-    Blt_HashEntry *hPtr;
-
-    hPtr = Blt_FindHashEntry(&graphPtr->axes.table, name);
-    if (hPtr != NULL) {
-       Axis *axisPtr;
-
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       if (!axisPtr->deletePending) {
-           *axisPtrPtr = axisPtr;
-           return TCL_OK;
-       }
-    }
-    Tcl_AppendResult(graphPtr->interp, "can't find axis \"", name,
-           "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL);
-    *axisPtrPtr = NULL;
-    return TCL_ERROR;
-}
-
-static int
-GetAxis(graphPtr, axisName, classUid, axisPtrPtr)
-    Graph *graphPtr;
-    char *axisName;
-    Blt_Uid classUid;
-    Axis **axisPtrPtr;
-{
-    Axis *axisPtr;
-
-    if (NameToAxis(graphPtr, axisName, &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (classUid != NULL) {
-       if ((axisPtr->refCount == 0) || (axisPtr->classUid == NULL)) {
-           /* Set the axis type on the first use of it. */
-           axisPtr->classUid = classUid;
-       } else if (axisPtr->classUid != classUid) {
-           Tcl_AppendResult(graphPtr->interp, "axis \"", axisName,
-               "\" is already in use on an opposite ", axisPtr->classUid,
-               "-axis", (char *)NULL);
-           return TCL_ERROR;
-       }
-       axisPtr->refCount++;
-    }
-    *axisPtrPtr = axisPtr;
-    return TCL_OK;
-}
-
-static void
-FreeAxis(graphPtr, axisPtr)
-    Graph *graphPtr;
-    Axis *axisPtr;
-{
-    axisPtr->refCount--;
-    if ((axisPtr->deletePending) && (axisPtr->refCount == 0)) {
-       DestroyAxis(graphPtr, axisPtr);
-    }
-}
-
-
-void
-Blt_DestroyAxes(graphPtr)
-    Graph *graphPtr;
-{
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Axis *axisPtr;
-    int i;
-
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       axisPtr->hashPtr = NULL;
-       DestroyAxis(graphPtr, axisPtr);
-    }
-    Blt_DeleteHashTable(&graphPtr->axes.table);
-    for (i = 0; i < 4; i++) {
-       Blt_ChainDestroy(graphPtr->axisChain[i]);
-    }
-    Blt_DeleteHashTable(&graphPtr->axes.tagTable);
-    Blt_ChainDestroy(graphPtr->axes.displayList);
-}
-
-int Blt_ConfigureAxes(graphPtr)
-    Graph *graphPtr;
-{
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Axis *axisPtr;
-    
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-    hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-        axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-        ConfigureAxis(graphPtr, axisPtr);
-    }
-    return TCL_OK;
-}
-
-int
-Blt_DefaultAxes(graphPtr)
-    Graph *graphPtr;
-{
-    register int i;
-    Axis *axisPtr;
-    Blt_Chain *chainPtr;
-    static char *axisNames[4] = { "x", "y", "x2", "y2" } ;
-    int flags;
-
-    flags = Blt_GraphType(graphPtr);
-    for (i = 0; i < 4; i++) {
-       chainPtr = Blt_ChainCreate();
-       graphPtr->axisChain[i] = chainPtr;
-
-       /* Create a default axis for each chain. */
-       axisPtr = CreateAxis(graphPtr, axisNames[i], i);
-       if (axisPtr == NULL) {
-           return TCL_ERROR;
-       }
-       axisPtr->refCount = 1;  /* Default axes are assumed in use. */
-       axisPtr->classUid = (i & 1) ? bltYAxisUid : bltXAxisUid;
-       axisPtr->flags |= AXIS_ONSCREEN;
-
-       /*
-        * Blt_ConfigureWidgetComponent creates a temporary child window 
-        * by the name of the axis.  It's used so that the Tk routines
-        * that access the X resource database can describe a single 
-        * component and not the entire graph.
-        */
-       if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin,
-               axisPtr->name, "Axis", configSpecs, 0, (char **)NULL,
-               (char *)axisPtr, flags) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       axisPtr->linkPtr = Blt_ChainAppend(chainPtr, axisPtr);
-       axisPtr->chainPtr = chainPtr;
-    }
-    return TCL_OK;
-}
-
-
-/*----------------------------------------------------------------------
- *
- * BindOp --
- *
- *    .g axis bind axisName sequence command
- *
- *----------------------------------------------------------------------
- */
-static int
-BindOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int argc;
-    char **argv;
-{
-    Tcl_Interp *interp = graphPtr->interp;
-
-    return Blt_ConfigureBindings(interp, graphPtr->bindTable,
-          Blt_MakeAxisTag(graphPtr, axisPtr->name), argc, argv);
-}
-          
-/*
- * ----------------------------------------------------------------------
- *
- * CgetOp --
- *
- *     Queries axis attributes (font, line width, label, etc).
- *
- * Results:
- *     Return value is a standard Tcl result.  If querying configuration
- *     values, interp->result will contain the results.
- *
- * ----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static int
-CgetOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int argc;                  /* Not used. */
-    char *argv[];
-{
-    return Tk_ConfigureValue(graphPtr->interp, graphPtr->tkwin, configSpecs,
-       (char *)axisPtr, argv[0], Blt_GraphType(graphPtr));
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * ConfigureOp --
- *
- *     Queries or resets axis attributes (font, line width, label, etc).
- *
- * Results:
- *     Return value is a standard Tcl result.  If querying configuration
- *     values, interp->result will contain the results.
- *
- * Side Effects:
- *     Axis resources are possibly allocated (GC, font). Axis layout is
- *     deferred until the height and width of the window are known.
- *
- * ----------------------------------------------------------------------
- */
-static int
-ConfigureOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int argc;
-    char *argv[];
-{
-    int flags;
-
-    flags = TK_CONFIG_ARGV_ONLY | Blt_GraphType(graphPtr);
-    if (argc == 0) {
-       return Tk_ConfigureInfo(graphPtr->interp, graphPtr->tkwin, configSpecs,
-           (char *)axisPtr, (char *)NULL, flags);
-    } else if (argc == 1) {
-       return Tk_ConfigureInfo(graphPtr->interp, graphPtr->tkwin, configSpecs,
-           (char *)axisPtr, argv[0], flags);
-    }
-    if (Tk_ConfigureWidget(graphPtr->interp, graphPtr->tkwin, configSpecs,
-           argc, argv, (char *)axisPtr, flags) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (axisPtr->flags & AXIS_ONSCREEN) {
-       if (!Blt_ConfigModified(configSpecs, graphPtr->interp, "-*color", "-background", "-bg",
-                               (char *)NULL)) {
-           graphPtr->flags |= REDRAW_BACKING_STORE;
-       }
-       graphPtr->flags |= DRAW_MARGINS;
-       Blt_EventuallyRedrawGraph(graphPtr);
-    }
-    return TCL_OK;
-}
-
-
-/*
- * ----------------------------------------------------------------------
- *
- * GetOp --
- *
- *    Returns the name of the picked axis (using the axis
- *    bind operation).  Right now, the only name accepted is
- *    "current".
- *
- * Results:
- *    A standard Tcl result.  The interpreter result will contain
- *    the name of the axis.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-GetOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;                 /* Not used. */
-    char *argv[];
-{
-    Tcl_Interp *interp = graphPtr->interp;
-    register Axis *axisPtr;
-
-    axisPtr = (Axis *)Blt_GetCurrentItem(graphPtr->bindTable);
-    /* Report only on axes. */
-    if ((axisPtr != NULL) && 
-       ((axisPtr->classUid == bltXAxisUid) ||
-        (axisPtr->classUid == bltYAxisUid) || 
-        (axisPtr->classUid == NULL))) {
-       char c;
-       
-       c = argv[3][0];
-       if ((c == 'c') && (strcmp(argv[3], "current") == 0)) {
-           Tcl_SetResult(interp, axisPtr->name, TCL_VOLATILE);
-       } else if ((c == 'd') && (strcmp(argv[3], "detail") == 0)) {
-           Tcl_SetResult(interp, axisPtr->detail, TCL_VOLATILE);
-       }
-    }
-    return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * LimitsOp --
- *
- *     This procedure returns a string representing the axis limits
- *     of the graph.  The format of the string is { left top right bottom}.
- *
- * Results:
- *     Always returns TCL_OK.  The interp->result field is
- *     a list of the graph axis limits.
- *
- *--------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-LimitsOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int argc;                  /* Not used. */
-    char **argv;               /* Not used. */
-
-{
-    Tcl_Interp *interp = graphPtr->interp;
-    double min, max;
-
-    if (graphPtr->flags & RESET_AXES) {
-       Blt_ResetAxes(graphPtr);
-    }
-    if (axisPtr->logScale) {
-       min = EXP10(axisPtr->axisRange.min);
-       max = EXP10(axisPtr->axisRange.max);
-    } else {
-       min = axisPtr->axisRange.min;
-       max = axisPtr->axisRange.max;
-    }
-    Tcl_AppendElement(interp, Blt_Dtoa(interp, min));
-    Tcl_AppendElement(interp, Blt_Dtoa(interp, max));
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InvTransformOp --
- *
- *     Maps the given window coordinate into an axis-value.
- *
- * Results:
- *     Returns a standard Tcl result.  interp->result contains
- *     the axis value. If an error occurred, TCL_ERROR is returned
- *     and interp->result will contain an error message.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-InvTransformOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;
-    int argc;                  /* Not used. */
-    char **argv;
-{
-    int x;                     /* Integer window coordinate*/
-    double y;                  /* Real graph coordinate */
-
-    if (graphPtr->flags & RESET_AXES) {
-       Blt_ResetAxes(graphPtr);
-    }
-    if (Tcl_GetInt(graphPtr->interp, argv[0], &x) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    /*
-     * Is the axis vertical or horizontal?
-     *
-     * Check the site where the axis was positioned.  If the axis is
-     * virtual, all we have to go on is how it was mapped to an
-     * element (using either -mapx or -mapy options).  
-     */
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       y = Blt_InvHMap(graphPtr, axisPtr, (double)x);
-    } else {
-       y = Blt_InvVMap(graphPtr, axisPtr, (double)x);
-    }
-    Tcl_AppendElement(graphPtr->interp, Blt_Dtoa(graphPtr->interp, y));
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TransformOp --
- *
- *     Maps the given axis-value to a window coordinate.
- *
- * Results:
- *     Returns a standard Tcl result.  interp->result contains
- *     the window coordinate. If an error occurred, TCL_ERROR
- *     is returned and interp->result will contain an error
- *     message.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-TransformOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;             /* Axis */
-    int argc;                  /* Not used. */
-    char **argv;
-{
-    double x;
-
-    if (graphPtr->flags & RESET_AXES) {
-       Blt_ResetAxes(graphPtr);
-    }
-    if (Tcl_ExprDouble(graphPtr->interp, argv[0], &x) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (AxisIsHorizontal(graphPtr, axisPtr)) {
-       x = Blt_HMap(graphPtr, axisPtr, x);
-    } else {
-       x = Blt_VMap(graphPtr, axisPtr, x);
-    }
-    Tcl_SetResult(graphPtr->interp, Blt_Itoa((int)x), TCL_VOLATILE);
-    return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * UseOp --
- *
- *     Changes the virtual axis used by the logical axis.
- *
- * Results:
- *     A standard Tcl result.  If the named axis doesn't exist
- *     an error message is put in interp->result.
- *
- * .g xaxis use "abc def gah"
- * .g xaxis use [lappend abc [.g axis use]]
- *
- *--------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-UseOp(graphPtr, axisPtr, argc, argv)
-    Graph *graphPtr;
-    Axis *axisPtr;             /* Not used. */
-    int argc;
-    char **argv;
-{
-    Blt_Chain *chainPtr;
-    int nNames;
-    char **names;
-    Blt_ChainLink *linkPtr;
-    int i;
-    Blt_Uid classUid;
-    int margin;
-
-    /* TODO: fix bug where "$g xaxis x2" leaves x unavailable. */
-    margin = (int)argv[-1];
-    chainPtr = graphPtr->margins[margin].axes;
-    if (argc == 0) {
-       for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr!= NULL;
-            linkPtr = Blt_ChainNextLink(linkPtr)) {
-           axisPtr = Blt_ChainGetValue(linkPtr);
-           Tcl_AppendElement(graphPtr->interp, axisPtr->name);
-       }
-       return TCL_OK;
-    }
-    if ((margin == MARGIN_BOTTOM) || (margin == MARGIN_TOP)) {
-       classUid = (graphPtr->inverted) ? bltYAxisUid : bltXAxisUid;
-    } else {
-       classUid = (graphPtr->inverted) ? bltXAxisUid : bltYAxisUid;
-    }
-    if (Tcl_SplitList(graphPtr->interp, argv[0], &nNames, &names) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr!= NULL;
-        linkPtr = Blt_ChainNextLink(linkPtr)) {
-       axisPtr = Blt_ChainGetValue(linkPtr);
-       axisPtr->linkPtr = NULL;
-       axisPtr->flags &= ~AXIS_ONSCREEN;
-       /* Clear the axis type if it's not currently used.*/
-       if (axisPtr->refCount == 0) {
-           axisPtr->classUid = NULL; 
-       }
-    }
-    Blt_ChainReset(chainPtr);
-    for (i = 0; i < nNames; i++) {
-       if (NameToAxis(graphPtr, names[i], &axisPtr) != TCL_OK) {
-           Blt_Free(names);
-           return TCL_ERROR;
-       }
-       if (axisPtr->classUid == NULL) {
-           axisPtr->classUid = classUid; 
-       } else if (axisPtr->classUid != classUid) {
-           Tcl_AppendResult(graphPtr->interp, "wrong type axis \"", 
-                    axisPtr->name, "\": can't use ", classUid, " type axis.", 
-                    (char *)NULL);                          
-           Blt_Free(names);
-           return TCL_ERROR;
-       }
-       if (axisPtr->linkPtr != NULL) {
-           /* Move the axis from the old margin's "use" list to the new. */
-           Blt_ChainUnlinkLink(axisPtr->chainPtr, axisPtr->linkPtr);
-           Blt_ChainAppendLink(chainPtr, axisPtr->linkPtr);
-       } else {
-           axisPtr->linkPtr = Blt_ChainAppend(chainPtr, axisPtr);
-       }
-       axisPtr->chainPtr = chainPtr;
-       axisPtr->flags |= AXIS_ONSCREEN;
-    }
-    graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | RESET_AXES);
-    /* When any axis changes, we need to layout the entire graph.  */
-    graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD);
-    Blt_EventuallyRedrawGraph(graphPtr);
-    
-    Blt_Free(names);
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * CreateVirtualOp --
- *
- *     Creates a new axis.
- *
- * Results:
- *     Returns a standard Tcl result.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-CreateVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char **argv;
-{
-    Axis *axisPtr;
-    int flags;
-
-    axisPtr = CreateAxis(graphPtr, argv[3], MARGIN_NONE);
-    if (axisPtr == NULL) {
-       return TCL_ERROR;
-    }
-    flags = Blt_GraphType(graphPtr);
-    if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin,
-           axisPtr->name, "Axis", configSpecs, argc - 4, argv + 4,
-           (char *)axisPtr, flags) != TCL_OK) {
-       goto error;
-    }
-    if (ConfigureAxis(graphPtr, axisPtr) != TCL_OK) {
-       goto error;
-    }
-    Tcl_SetResult(graphPtr->interp, axisPtr->name, TCL_VOLATILE);
-    return TCL_OK;
-  error:
-    DestroyAxis(graphPtr, axisPtr);
-    return TCL_ERROR;
-}
-
-/*----------------------------------------------------------------------
- *
- * BindVirtualOp --
- *
- *    .g axis bind axisName sequence command
- *
- *----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-BindVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char **argv;
-{
-    Tcl_Interp *interp = graphPtr->interp;
-
-    if (argc == 3) {
-       Blt_HashEntry *hPtr;
-       Blt_HashSearch cursor;
-       char *tagName;
-
-       for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.tagTable, &cursor);
-            hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-           tagName = Blt_GetHashKey(&graphPtr->axes.tagTable, hPtr);
-           Tcl_AppendElement(interp, tagName);
-       }
-       return TCL_OK;
-    }
-    return Blt_ConfigureBindings(interp, graphPtr->bindTable, 
-        Blt_MakeAxisTag(graphPtr, argv[3]), argc - 4, argv + 4);
-}
-
-
-/*
- * ----------------------------------------------------------------------
- *
- * CgetVirtualOp --
- *
- *     Queries axis attributes (font, line width, label, etc).
- *
- * Results:
- *     Return value is a standard Tcl result.  If querying configuration
- *     values, interp->result will contain the results.
- *
- * ----------------------------------------------------------------------
- */
-/* ARGSUSED */
-static int
-CgetVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char *argv[];
-{
-    Axis *axisPtr;
-
-    if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return CgetOp(graphPtr, axisPtr, argc - 4, argv + 4);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * ConfigureVirtualOp --
- *
- *     Queries or resets axis attributes (font, line width, label, etc).
- *
- * Results:
- *     Return value is a standard Tcl result.  If querying configuration
- *     values, interp->result will contain the results.
- *
- * Side Effects:
- *     Axis resources are possibly allocated (GC, font). Axis layout is
- *     deferred until the height and width of the window are known.
- *
- * ----------------------------------------------------------------------
- */
-static int
-ConfigureVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char *argv[];
-{
-    Axis *axisPtr;
-    int nNames, nOpts;
-    char **options;
-    register int i;
-
-    /* Figure out where the option value pairs begin */
-    argc -= 3;
-    argv += 3;
-    for (i = 0; i < argc; i++) {
-       if (argv[i][0] == '-') {
-           break;
-       }
-       if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) {
-           return TCL_ERROR;
-       }
-    }
-    nNames = i;                        /* Number of pen names specified */
-    nOpts = argc - i;          /* Number of options specified */
-    options = argv + i;                /* Start of options in argv  */
-
-    for (i = 0; i < nNames; i++) {
-       if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       if (ConfigureOp(graphPtr, axisPtr, nOpts, options) != TCL_OK) {
-           break;
-       }
-    }
-    if (i < nNames) {
-       return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * DeleteVirtualOp --
- *
- *     Deletes one or more axes.  The actual removal may be deferred
- *     until the axis is no longer used by any element. The axis
- *     can't be referenced by its name any longer and it may be
- *     recreated.
- *
- * Results:
- *     Returns a standard Tcl result.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-DeleteVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char **argv;
-{
-    register int i;
-    Axis *axisPtr;
-
-    for (i = 3; i < argc; i++) {
-       if (NameToAxis(graphPtr, argv[i], &axisPtr) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       axisPtr->deletePending = TRUE;
-       if (axisPtr->refCount == 0) {
-           DestroyAxis(graphPtr, axisPtr);
-       }
-    }
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InvTransformVirtualOp --
- *
- *     Maps the given window coordinate into an axis-value.
- *
- * Results:
- *     Returns a standard Tcl result.  interp->result contains
- *     the axis value. If an error occurred, TCL_ERROR is returned
- *     and interp->result will contain an error message.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-InvTransformVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;                  /* Not used. */
-    char **argv;
-{
-    Axis *axisPtr;
-
-    if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return InvTransformOp(graphPtr, axisPtr, argc - 4, argv + 4);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * LimitsVirtualOp --
- *
- *     This procedure returns a string representing the axis limits
- *     of the graph.  The format of the string is { left top right bottom}.
- *
- * Results:
- *     Always returns TCL_OK.  The interp->result field is
- *     a list of the graph axis limits.
- *
- *--------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-LimitsVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;                  /* Not used. */
-    char **argv;               /* Not used. */
-
-{
-    Axis *axisPtr;
-
-    if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return LimitsOp(graphPtr, axisPtr, argc - 4, argv + 4);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * NamesVirtualOp --
- *
- *     Return a list of the names of all the axes.
- *
- * Results:
- *     Returns a standard Tcl result.
- *
- * ----------------------------------------------------------------------
- */
-
-/*ARGSUSED*/
-static int
-NamesVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;                  /* Not used. */
-    char **argv;               /* Not used. */
-{
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Axis *axisPtr;
-    register int i;
-
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       if (axisPtr->deletePending) {
-           continue;
-       }
-       if (argc == 3) {
-           Tcl_AppendElement(graphPtr->interp, axisPtr->name);
-           continue;
-       }
-       for (i = 3; i < argc; i++) {
-           if (Tcl_StringMatch(axisPtr->name, argv[i])) {
-               Tcl_AppendElement(graphPtr->interp, axisPtr->name);
-               break;
-           }
-       }
-    }
-    return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TransformVirtualOp --
- *
- *     Maps the given axis-value to a window coordinate.
- *
- * Results:
- *     Returns a standard Tcl result.  interp->result contains
- *     the window coordinate. If an error occurred, TCL_ERROR
- *     is returned and interp->result will contain an error
- *     message.
- *
- * ----------------------------------------------------------------------
- */
-/*ARGSUSED*/
-static int
-TransformVirtualOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;                  /* Not used. */
-    char **argv;
-{
-    Axis *axisPtr;
-
-    if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    return TransformOp(graphPtr, axisPtr, argc - 4, argv + 4);
-}
-
-static int
-ViewOp(graphPtr, argc, argv)
-    Graph *graphPtr;
-    int argc;
-    char **argv;
-{
-    Axis *axisPtr;
-    Tcl_Interp *interp = graphPtr->interp;
-    double axisOffset, scrollUnits;
-    double fract;
-    double viewMin, viewMax, worldMin, worldMax;
-    double viewWidth, worldWidth;
-
-    if (NameToAxis(graphPtr, argv[3], &axisPtr) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    worldMin = axisPtr->valueRange.min;
-    worldMax = axisPtr->valueRange.max;
-    /* Override data dimensions with user-selected limits. */
-    if (DEFINED(axisPtr->scrollMin)) {
-       worldMin = axisPtr->scrollMin;
-    }
-    if (DEFINED(axisPtr->scrollMax)) {
-       worldMax = axisPtr->scrollMax;
-    }
-    viewMin = axisPtr->min;
-    viewMax = axisPtr->max;
-    /* Bound the view within scroll region. */ 
-    if (viewMin < worldMin) {
-       viewMin = worldMin;
-    } 
-    if (viewMax > worldMax) {
-       viewMax = worldMax;
-    }
-    if (axisPtr->logScale) {
-       worldMin = log10(worldMin);
-       worldMax = log10(worldMax);
-       viewMin = log10(viewMin);
-       viewMax = log10(viewMax);
-    }
-    worldWidth = worldMax - worldMin;
-    viewWidth = viewMax - viewMin;
-
-    /* Unlike horizontal axes, vertical axis values run opposite of
-     * the scrollbar first/last values.  So instead of pushing the
-     * axis minimum around, we move the maximum instead. */
-
-    if (AxisIsHorizontal(graphPtr, axisPtr) != axisPtr->descending) {
-       axisOffset = viewMin - worldMin;
-       scrollUnits = (double)axisPtr->scrollUnits * graphPtr->hScale;
-    } else {
-       axisOffset = worldMax - viewMax;
-       scrollUnits = (double)axisPtr->scrollUnits * graphPtr->vScale;
-    }
-    if (argc == 4) {
-       /* Note: Bound the fractions between 0.0 and 1.0 to support
-        * "canvas"-style scrolling. */
-       fract = axisOffset / worldWidth;
-       Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0)));
-       fract = (axisOffset + viewWidth) / worldWidth;
-       Tcl_AppendElement(interp, Blt_Dtoa(interp, CLAMP(fract, 0.0, 1.0)));
-       return TCL_OK;
-    }
-    fract = axisOffset / worldWidth;
-    if (GetAxisScrollInfo(interp, argc - 4, argv + 4, &fract, 
-               viewWidth / worldWidth, scrollUnits) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (AxisIsHorizontal(graphPtr, axisPtr) != axisPtr->descending) {
-       axisPtr->reqMin = (fract * worldWidth) + worldMin;
-       axisPtr->reqMax = axisPtr->reqMin + viewWidth;
-    } else {
-       axisPtr->reqMax = worldMax - (fract * worldWidth);
-       axisPtr->reqMin = axisPtr->reqMax - viewWidth;
-    }
-    if (axisPtr->logScale) {
-       axisPtr->reqMin = EXP10(axisPtr->reqMin);
-       axisPtr->reqMax = EXP10(axisPtr->reqMax);
-    }
-    graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | RESET_AXES);
-    Blt_EventuallyRedrawGraph(graphPtr);
-    return TCL_OK;
-}
-
-int
-Blt_VirtualAxisOp(graphPtr, interp, argc, argv)
-    Graph *graphPtr;
-    Tcl_Interp *interp;
-    int argc;
-    char **argv;
-{
-    Blt_Op proc;
-    int result;
-    static Blt_OpSpec axisOps[] =
-    {
-       {"bind", 1, (Blt_Op)BindVirtualOp, 3, 6, 
-            "axisName sequence command",},
-       {"cget", 2, (Blt_Op)CgetVirtualOp, 5, 5, "axisName option",},
-       {"configure", 2, (Blt_Op)ConfigureVirtualOp, 4, 0,
-           "axisName ?axisName?... ?option value?...",},
-       {"create", 2, (Blt_Op)CreateVirtualOp, 4, 0,
-           "axisName ?option value?...",},
-       {"delete", 1, (Blt_Op)DeleteVirtualOp, 3, 0, "?axisName?...",},
-       {"get", 1, (Blt_Op)GetOp, 4, 4, "name",},
-       {"invtransform", 1, (Blt_Op)InvTransformVirtualOp, 5, 5,
-           "axisName value",},
-       {"limits", 1, (Blt_Op)LimitsVirtualOp, 4, 4, "axisName",},
-       {"names", 1, (Blt_Op)NamesVirtualOp, 3, 0, "?pattern?...",},
-       {"transform", 1, (Blt_Op)TransformVirtualOp, 5, 5, "axisName value",},
-       {"view", 1, (Blt_Op)ViewOp, 4, 7,
-           "axisName ?moveto fract? ?scroll number what?",},
-    };
-    static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec);
-
-    proc = Blt_GetOp(interp, nAxisOps, axisOps, BLT_OP_ARG2, argc, argv, 0);
-    if (proc == NULL) {
-       return TCL_ERROR;
-    }
-    result = (*proc) (graphPtr, argc, argv);
-    return result;
-}
-
-int
-Blt_AxisOp(graphPtr, margin, argc, argv)
-    Graph *graphPtr;
-    int margin;
-    int argc;
-    char **argv;
-{
-    int result;
-    Blt_Op proc;
-    Axis *axisPtr;
-    static Blt_OpSpec axisOps[] =
-    {
-       {"bind", 1, (Blt_Op)BindOp, 2, 5, "sequence command",},
-       {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",},
-       {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?option value?...",},
-       {"invtransform", 1, (Blt_Op)InvTransformOp, 4, 4, "value",},
-       {"limits", 1, (Blt_Op)LimitsOp, 3, 3, "",},
-       {"transform", 1, (Blt_Op)TransformOp, 4, 4, "value",},
-       {"use", 1, (Blt_Op)UseOp, 3, 4, "?axisName?",},
-    };
-    static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec);
-
-    proc = Blt_GetOp(graphPtr->interp, nAxisOps, axisOps, BLT_OP_ARG2, 
-       argc, argv, 0);
-    if (proc == NULL) {
-       return TCL_ERROR;
-    }
-    if (proc == UseOp) {
-       argv[2] = (char *)margin; /* Hack. Slide a reference to the margin in 
-                                  * the argument list. Needed only for UseOp.
-                                  */
-       result = (*proc)(graphPtr, NULL, argc - 3, argv +3);
-     } else {
-       axisPtr = Blt_GetFirstAxis(graphPtr->margins[margin].axes);
-       if (axisPtr == NULL) {
-           Tcl_AppendResult(graphPtr->interp, "bad axis", (char *)NULL);
-           return TCL_ERROR;
-       }
-       result = (*proc)(graphPtr, axisPtr, argc - 3, argv + 3);
-    }
-    return result;
-}
-
-void
-Blt_MapAxes(graphPtr)
-    Graph *graphPtr;
-{
-    Axis *axisPtr;
-    Blt_Chain *chainPtr;
-    Blt_ChainLink *linkPtr;
-    register int margin;
-    int offset;
-    
-    for (margin = 0; margin < 4; margin++) {
-       chainPtr = graphPtr->margins[margin].axes;
-       offset = 0;
-       for (linkPtr = Blt_ChainFirstLink(chainPtr); linkPtr != NULL;
-            linkPtr = Blt_ChainNextLink(linkPtr)) {
-           axisPtr = Blt_ChainGetValue(linkPtr);
-           if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) {
-               MapAxis(graphPtr, axisPtr, offset, margin);
-               if (AxisIsHorizontal(graphPtr, axisPtr)) {
-                   offset += axisPtr->height;
-               } else {
-                   offset += axisPtr->width;
-               }
-           }
-       }
-    }
-}
-
-void
-Blt_DrawAxes(graphPtr, drawable)
-    Graph *graphPtr;
-    Drawable drawable;
-{
-    Axis *axisPtr;
-    Blt_ChainLink *linkPtr;
-    register int i;
-
-    for (i = 0; i < 4; i++) {
-       for (linkPtr = Blt_ChainFirstLink(graphPtr->margins[i].axes); 
-            linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
-           axisPtr = Blt_ChainGetValue(linkPtr);
-           if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) {
-               DrawAxis(graphPtr, drawable, axisPtr);
-           }
-       }
-    }
-}
-
-void
-Blt_AxesToPostScript(graphPtr, psToken)
-    Graph *graphPtr;
-    PsToken psToken;
-{
-    Axis *axisPtr;
-    Blt_ChainLink *linkPtr;
-    register int i;
-
-    for (i = 0; i < 4; i++) {
-       for (linkPtr = Blt_ChainFirstLink(graphPtr->margins[i].axes); 
-            linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
-           axisPtr = Blt_ChainGetValue(linkPtr);
-           if ((!axisPtr->hidden) && (axisPtr->flags & AXIS_ONSCREEN)) {
-               AxisToPostScript(psToken, axisPtr);
-           }
-       }
-    }
-}
-
-
-/*
- * ----------------------------------------------------------------------
- *
- * Blt_DrawAxisLimits --
- *
- *     Draws the min/max values of the axis in the plotting area. 
- *     The text strings are formatted according to the "sprintf"
- *     format descriptors in the limitsFormats array.
- *
- * Results:
- *     None.
- *
- * Side Effects:
- *     Draws the numeric values of the axis limits into the outer
- *     regions of the plotting area.
- *
- * ----------------------------------------------------------------------
- */
-void
-Blt_DrawAxisLimits(graphPtr, drawable)
-    Graph *graphPtr;
-    Drawable drawable;
-{
-    Axis *axisPtr;
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Dim2D textDim;
-    int isHoriz;
-    char *minPtr, *maxPtr;
-    char *minFormat, *maxFormat;
-    char minString[200], maxString[200];
-    int vMin, hMin, vMax, hMax;
-
-#define SPACING 8
-    vMin = vMax = graphPtr->left + graphPtr->padLeft + 2;
-    hMin = hMax = graphPtr->bottom - graphPtr->padBottom - 2;  /* Offsets */
-
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-
-       if (axisPtr->nFormats == 0) {
-           continue;
-       }
-       isHoriz = AxisIsHorizontal(graphPtr, axisPtr);
-       minPtr = maxPtr = NULL;
-       minFormat = maxFormat = axisPtr->limitsFormats[0];
-       if (axisPtr->nFormats > 1) {
-           maxFormat = axisPtr->limitsFormats[1];
-       }
-       if (minFormat[0] != '\0') {
-           minPtr = minString;
-           sprintf(minString, minFormat, axisPtr->axisRange.min);
-       }
-       if (maxFormat[0] != '\0') {
-           maxPtr = maxString;
-           sprintf(maxString, maxFormat, axisPtr->axisRange.max);
-       }
-       if (axisPtr->descending) {
-           char *tmp;
-
-           tmp = minPtr, minPtr = maxPtr, maxPtr = tmp;
-       }
-       if (maxPtr != NULL) {
-           if (isHoriz) {
-               axisPtr->limitsTextStyle.theta = 90.0;
-               axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SE;
-               Blt_DrawText2(graphPtr->tkwin, drawable, maxPtr,
-                   &axisPtr->limitsTextStyle, graphPtr->right, hMax, &textDim);
-               hMax -= (textDim.height + SPACING);
-           } else {
-               axisPtr->limitsTextStyle.theta = 0.0;
-               axisPtr->limitsTextStyle.anchor = TK_ANCHOR_NW;
-               Blt_DrawText2(graphPtr->tkwin, drawable, maxPtr,
-                   &axisPtr->limitsTextStyle, vMax, graphPtr->top, &textDim);
-               vMax += (textDim.width + SPACING);
-           }
-       }
-       if (minPtr != NULL) {
-           axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SW;
-           if (isHoriz) {
-               axisPtr->limitsTextStyle.theta = 90.0;
-               Blt_DrawText2(graphPtr->tkwin, drawable, minPtr,
-                   &axisPtr->limitsTextStyle, graphPtr->left, hMin, &textDim);
-               hMin -= (textDim.height + SPACING);
-           } else {
-               axisPtr->limitsTextStyle.theta = 0.0;
-               Blt_DrawText2(graphPtr->tkwin, drawable, minPtr,
-                   &axisPtr->limitsTextStyle, vMin, graphPtr->bottom, &textDim);
-               vMin += (textDim.width + SPACING);
-           }
-       }
-    }                          /* Loop on axes */
-}
-
-void
-Blt_AxisLimitsToPostScript(graphPtr, psToken)
-    Graph *graphPtr;
-    PsToken psToken;
-{
-    Axis *axisPtr;
-    Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    double vMin, hMin, vMax, hMax;
-    char string[200];
-    int textWidth, textHeight;
-    char *minFmt, *maxFmt;
-
-#define SPACING 8
-    vMin = vMax = graphPtr->left + graphPtr->padLeft + 2;
-    hMin = hMax = graphPtr->bottom - graphPtr->padBottom - 2;  /* Offsets */
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-       hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-
-       if (axisPtr->nFormats == 0) {
-           continue;
-       }
-       minFmt = maxFmt = axisPtr->limitsFormats[0];
-       if (axisPtr->nFormats > 1) {
-           maxFmt = axisPtr->limitsFormats[1];
-       }
-       if (*maxFmt != '\0') {
-           sprintf(string, maxFmt, axisPtr->axisRange.max);
-           Blt_GetTextExtents(&axisPtr->tickTextStyle, string, &textWidth,
-               &textHeight);
-           if ((textWidth > 0) && (textHeight > 0)) {
-               if (axisPtr->classUid == bltXAxisUid) {
-                   axisPtr->limitsTextStyle.theta = 90.0;
-                   axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SE;
-                   Blt_TextToPostScript(psToken, string, 
-                                        &axisPtr->limitsTextStyle, 
-                                        (double)graphPtr->right, hMax);
-                   hMax -= (textWidth + SPACING);
-               } else {
-                   axisPtr->limitsTextStyle.theta = 0.0;
-                   axisPtr->limitsTextStyle.anchor = TK_ANCHOR_NW;
-                   Blt_TextToPostScript(psToken, string, 
-                        &axisPtr->limitsTextStyle, vMax, (double)graphPtr->top);
-                   vMax += (textWidth + SPACING);
-               }
-           }
-       }
-       if (*minFmt != '\0') {
-           sprintf(string, minFmt, axisPtr->axisRange.min);
-           Blt_GetTextExtents(&axisPtr->tickTextStyle, string, &textWidth,
-               &textHeight);
-           if ((textWidth > 0) && (textHeight > 0)) {
-               axisPtr->limitsTextStyle.anchor = TK_ANCHOR_SW;
-               if (axisPtr->classUid == bltXAxisUid) {
-                   axisPtr->limitsTextStyle.theta = 90.0;
-                   Blt_TextToPostScript(psToken, string, 
-                                        &axisPtr->limitsTextStyle, 
-                                        (double)graphPtr->left, hMin);
-                   hMin -= (textWidth + SPACING);
-               } else {
-                   axisPtr->limitsTextStyle.theta = 0.0;
-                   Blt_TextToPostScript(psToken, string, 
-                                        &axisPtr->limitsTextStyle, 
-                                        vMin, (double)graphPtr->bottom);
-                   vMin += (textWidth + SPACING);
-               }
-           }
-       }
-    }
-}
-
-Axis *
-Blt_GetFirstAxis(chainPtr)
-    Blt_Chain *chainPtr;
-{
-    Blt_ChainLink *linkPtr;
-
-    linkPtr = Blt_ChainFirstLink(chainPtr);
-    if (linkPtr == NULL) {
-       return NULL;
-    }
-    return Blt_ChainGetValue(linkPtr);
-}
-
-Axis *
-Blt_NearestAxis(graphPtr, x, y)
-    Graph *graphPtr;
-    int x, y;                 /* Point to be tested */
-{
-    register Blt_HashEntry *hPtr;
-    Blt_HashSearch cursor;
-    Axis *axisPtr;
-    int width, height;
-    double rotWidth, rotHeight;
-    Point2D bbox[5];
-    
-    for (hPtr = Blt_FirstHashEntry(&graphPtr->axes.table, &cursor);
-        hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
-       axisPtr = (Axis *)Blt_GetHashValue(hPtr);
-       if ((axisPtr->hidden) || (!(axisPtr->flags & AXIS_ONSCREEN))) {
-           continue;           /* Don't check hidden axes or axes
-                                * that are virtual. */
-       }
-       if (axisPtr->showTicks) {
-           register Blt_ChainLink *linkPtr;
-           TickLabel *labelPtr;
-           Point2D t;
-
-           for (linkPtr = Blt_ChainFirstLink(axisPtr->tickLabels); 
-                linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {       
-               labelPtr = Blt_ChainGetValue(linkPtr);
-               Blt_GetBoundingBox(labelPtr->width, labelPtr->height, 
-                   axisPtr->tickTextStyle.theta, &rotWidth, &rotHeight, bbox);
-               width = ROUND(rotWidth);
-               height = ROUND(rotHeight);
-               t = Blt_TranslatePoint(&labelPtr->anchorPos, width, height, 
-                       axisPtr->tickTextStyle.anchor);
-               t.x = x - t.x - (width * 0.5);
-               t.y = y - t.y - (height * 0.5);
-
-               bbox[4] = bbox[0];
-               if (Blt_PointInPolygon(&t, bbox, 5)) {
-                   axisPtr->detail = "label";
-                   return axisPtr;
-               }
-           }
-       }
-       if (axisPtr->title != NULL) { /* and then the title string. */
-           Point2D t;
-
-           Blt_GetTextExtents(&axisPtr->titleTextStyle, axisPtr->title,&width,
-                &height);
-           Blt_GetBoundingBox(width, height, axisPtr->titleTextStyle.theta, 
-               &rotWidth, &rotHeight, bbox);
-           width = ROUND(rotWidth);
-           height = ROUND(rotHeight);
-           t = Blt_TranslatePoint(&axisPtr->titlePos, width, height, 
-               axisPtr->titleTextStyle.anchor);
-           /* Translate the point so that the 0,0 is the upper left 
-            * corner of the bounding box.  */
-           t.x = x - t.x - (width / 2);
-           t.y = y - t.y - (height / 2);
-           
-           bbox[4] = bbox[0];
-           if (Blt_PointInPolygon(&t, bbox, 5)) {
-               axisPtr->detail = "title";
-               return axisPtr;
-           }
-       }
-       if (axisPtr->lineWidth > 0) { /* Check for the axis region */
-           if (PointInRegion(&axisPtr->region, x, y)) {
-               axisPtr->detail = "line";
-               return axisPtr;
-           }
-       }
-    }
-    return NULL;
-}
-ClientData
-Blt_MakeAxisTag(graphPtr, tagName)
-    Graph *graphPtr;
-    char *tagName;
-{
-    Blt_HashEntry *hPtr;
-    int isNew;
-
-    hPtr = Blt_CreateHashEntry(&graphPtr->axes.tagTable, tagName, &isNew);
-    assert(hPtr);
-    return Blt_GetHashKey(&graphPtr->axes.tagTable, hPtr);
-}