From 46712b55900a85512f51c9e915fe2b32b9ce7ae5 Mon Sep 17 00:00:00 2001 From: joye Date: Mon, 3 Mar 2014 20:04:47 +0000 Subject: *** empty log message *** --- src/bltGrAxis.C | 6296 ++++++++++++++++++++++++++--------------------------- src/bltGrAxis.h | 1 + src/bltGrBind.C | 2 +- src/bltGrElemOp.C | 65 +- src/bltGrHairs.C | 37 +- src/bltGrLegd.C | 77 +- src/bltGrLegd.h | 2 +- src/bltGrMarker.C | 28 +- src/bltGrPenOp.C | 54 +- src/bltGraph.C | 53 +- src/bltGraph.h | 20 +- src/bltOp.h | 2 +- src/bltSwitch.C | 2 +- src/bltVecCmd.C | 66 +- src/bltVector.C | 14 +- 15 files changed, 3331 insertions(+), 3388 deletions(-) diff --git a/src/bltGrAxis.C b/src/bltGrAxis.C index d4cd041..c601d98 100644 --- a/src/bltGrAxis.C +++ b/src/bltGrAxis.C @@ -95,6 +95,17 @@ static int nAxisNames = sizeof(axisNames) / sizeof(AxisName); // Defs +static int GetAxisScrollInfo(Tcl_Interp* interp, int objc, Tcl_Obj* const objv[], + double *offsetPtr, double windowSize, + double scrollUnits, double scale); +static double Clamp(double x); +static int GetAxisFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, + Axis **axisPtrPtr); +static int AxisIsHorizontal(Axis *axisPtr); +static void FreeTickLabels(Blt_Chain chain); +static int ConfigureAxis(Axis *axisPtr); +static Blt_ConfigSpec configSpecs[]; +static Axis *NewAxis(Graph* graphPtr, const char *name, int margin); static void FreeTicksProc(ClientData clientData, Display *display, char *widgRec, int offset); static void ReleaseAxis(Axis *axisPtr); @@ -105,10 +116,10 @@ static Tcl_FreeProc FreeAxis; static void TimeScaleAxis(Axis *axisPtr, double min, double max); static int lastMargin; -typedef int (GraphAxisProc)(Tcl_Interp* interp, Axis *axisPtr, int objc, - Tcl_Obj *const *objv); -typedef int (GraphVirtualAxisProc)(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv); +typedef int (GraphDefAxisProc)(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]); +typedef int (GraphAxisProc)(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]); // OptionSpecs @@ -509,3712 +520,3437 @@ static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_END, NULL, NULL, NULL, NULL, -1, 0, 0, NULL, 0} }; -static Blt_OptionParseProc ObjToLimitProc; -static Blt_OptionPrintProc LimitToObjProc; -static Blt_CustomOption limitOption = { - ObjToLimitProc, LimitToObjProc, NULL, (ClientData)0 -}; +// Create -static Blt_OptionFreeProc FreeTicksProc; -static Blt_OptionParseProc ObjToTicksProc; -static Blt_OptionPrintProc TicksToObjProc; -static Blt_CustomOption majorTicksOption = { - ObjToTicksProc, TicksToObjProc, FreeTicksProc, (ClientData)AXIS_AUTO_MAJOR, -}; -static Blt_CustomOption minorTicksOption = { - ObjToTicksProc, TicksToObjProc, FreeTicksProc, (ClientData)AXIS_AUTO_MINOR, -}; -static Blt_OptionFreeProc FreeAxisProc; -static Blt_OptionPrintProc AxisToObjProc; -static Blt_OptionParseProc ObjToAxisProc; -Blt_CustomOption bltXAxisOption = { - ObjToAxisProc, AxisToObjProc, FreeAxisProc, (ClientData)CID_AXIS_X -}; -Blt_CustomOption bltYAxisOption = { - ObjToAxisProc, AxisToObjProc, FreeAxisProc, (ClientData)CID_AXIS_Y -}; +int Blt_CreateAxes(Graph* graphPtr) +{ + int flags = Blt_GraphType(graphPtr); + for (int ii = 0; ii < 4; ii++) { + Blt_Chain chain = Blt_Chain_Create(); + graphPtr->axisChain[ii] = chain; -static Blt_OptionFreeProc FreeFormatProc; -static Blt_OptionParseProc ObjToFormatProc; -static Blt_OptionPrintProc FormatToObjProc; -static Blt_CustomOption formatOption = { - ObjToFormatProc, FormatToObjProc, FreeFormatProc, (ClientData)0, -}; -static Blt_OptionParseProc ObjToLooseProc; -static Blt_OptionPrintProc LooseToObjProc; -static Blt_CustomOption looseOption = { - ObjToLooseProc, LooseToObjProc, NULL, (ClientData)0, -}; + Axis* axisPtr = NewAxis(graphPtr, axisNames[ii].name, ii); + if (!axisPtr) + return TCL_ERROR; -static Blt_OptionParseProc ObjToUseProc; -static Blt_OptionPrintProc UseToObjProc; -static Blt_CustomOption useOption = { - ObjToUseProc, UseToObjProc, NULL, (ClientData)0 -}; + axisPtr->refCount = 1; /* Default axes are assumed in use. */ + axisPtr->margin = ii; + axisPtr->flags |= AXIS_USE; + Blt_GraphSetObjectClass(&axisPtr->obj, axisNames[ii].classId); + /* + * Blt_ConfigureComponentFromObj 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_ConfigureComponentFromObj(graphPtr->interp, graphPtr->tkwin, + axisPtr->obj.name, "Axis", + configSpecs, 0, (Tcl_Obj **)NULL, + (char*)axisPtr, flags) != TCL_OK) { + return TCL_ERROR; + } + if (ConfigureAxis(axisPtr) != TCL_OK) + return TCL_ERROR; -Blt_CustomOption bitmaskGrAxisCheckLimitsOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_CHECK_LIMITS - }; + axisPtr->link = Blt_Chain_Append(chain, axisPtr); + axisPtr->chain = chain; + } + return TCL_OK; +} -Blt_CustomOption bitmaskGrAxisExteriorOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_EXTERIOR - }; +static int CreateAxis(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) +{ + char *string = Tcl_GetString(objv[3]); + if (string[0] == '-') { + Tcl_AppendResult(graphPtr->interp, "name of axis \"", string, + "\" can't start with a '-'", NULL); + return TCL_ERROR; + } -Blt_CustomOption bitmaskGrAxisGridOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_GRID - }; + int isNew; + Tcl_HashEntry* hPtr = + Tcl_CreateHashEntry(&graphPtr->axes.table, string, &isNew); + if (!isNew) { + Tcl_AppendResult(graphPtr->interp, "axis \"", string, + "\" already exists in \"", Tcl_GetString(objv[0]), + "\"", NULL); + return TCL_ERROR; + } -Blt_CustomOption bitmaskGrAxisGridMinorOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_GRID_MINOR - }; + Axis* axisPtr = NewAxis(graphPtr, Tcl_GetString(objv[3]), MARGIN_NONE); + if (axisPtr == NULL) + return TCL_ERROR; -Blt_CustomOption bitmaskGrAxisHideOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)HIDE - }; + if ((Tk_InitOptions(graphPtr->interp, (char*)axisPtr, axisPtr->optionTable, graphPtr->tkwin) != TCL_OK) || (AxisObjConfigure(interp, graphPtr, axisPtr, objc-4, objv+4) != TCL_OK)) { + DestroyAxis(axisPtr); + return TCL_ERROR; + } -Blt_CustomOption bitmaskGrAxisShowTicksOption = - { - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_SHOWTICKS - }; + axisPtr->hashPtr = hPtr; + Tcl_SetHashValue(hPtr, axisPtr); -static Blt_ConfigSpec configSpecs[] = { - {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", - "ActiveForeground", STD_ACTIVE_FOREGROUND, - Tk_Offset(Axis, activeFgColor), ALL_GRAPHS}, - {BLT_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", - "flat", Tk_Offset(Axis, activeRelief), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_DOUBLE, "-autorange", "autoRange", "AutoRange", - "0.0", Tk_Offset(Axis, windowSize), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_BORDER, "-background", "background", "Background", - NULL, Tk_Offset(Axis, normalBg), - ALL_GRAPHS | BLT_CONFIG_NULL_OK}, - {BLT_CONFIG_SYNONYM, "-bg", "background", NULL, NULL, 0, 0}, - {BLT_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", "all", - Tk_Offset(Axis, obj.tags), ALL_GRAPHS | BLT_CONFIG_NULL_OK, - &listOption}, - {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", NULL, NULL, - 0, ALL_GRAPHS}, - {BLT_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - "0", Tk_Offset(Axis, borderWidth), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-checklimits", "checkLimits", "CheckLimits", - "0", Tk_Offset(Axis, flags), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrAxisCheckLimitsOption}, - {BLT_CONFIG_COLOR, "-color", "color", "Color", - STD_NORMAL_FOREGROUND, Tk_Offset(Axis, tickColor), ALL_GRAPHS}, - {BLT_CONFIG_STRING, "-command", "command", "Command", - NULL, Tk_Offset(Axis, formatCmd), - BLT_CONFIG_NULL_OK | ALL_GRAPHS}, - {BLT_CONFIG_BOOLEAN, "-descending", "descending", "Descending", - "0", Tk_Offset(Axis, descending), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-exterior", "exterior", "exterior", "1", - Tk_Offset(Axis, flags), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrAxisExteriorOption}, - {BLT_CONFIG_SYNONYM, "-fg", "color", NULL, - NULL, 0, ALL_GRAPHS}, - {BLT_CONFIG_SYNONYM, "-foreground", "color", NULL, - NULL, 0, ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-grid", "grid", "Grid", "1", - Tk_Offset(Axis, flags), BARCHART, - &bitmaskGrAxisGridOption}, - {BLT_CONFIG_CUSTOM, "-grid", "grid", "Grid", "1", - Tk_Offset(Axis, flags), GRAPH | STRIPCHART, - &bitmaskGrAxisGridOption}, - {BLT_CONFIG_COLOR, "-gridcolor", "gridColor", "GridColor", - "gray64", Tk_Offset(Axis, major.color), ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-griddashes", "gridDashes", "GridDashes", - "dot", Tk_Offset(Axis, major.dashes), - BLT_CONFIG_NULL_OK | ALL_GRAPHS, &dashesOption}, - {BLT_CONFIG_PIXELS, "-gridlinewidth", "gridLineWidth", - "GridLineWidth", "0", - Tk_Offset(Axis, major.lineWidth), - BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-gridminor", "gridMinor", "GridMinor", - "1", Tk_Offset(Axis, flags), - BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS, - &bitmaskGrAxisGridMinorOption}, - {BLT_CONFIG_COLOR, "-gridminorcolor", "gridMinorColor", "GridColor", - "gray64", Tk_Offset(Axis, minor.color), ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-gridminordashes", "gridMinorDashes", "GridDashes", - "dot", Tk_Offset(Axis, minor.dashes), - BLT_CONFIG_NULL_OK | ALL_GRAPHS, &dashesOption}, - {BLT_CONFIG_PIXELS, "-gridminorlinewidth", "gridMinorLineWidth", - "GridLineWidth", "0", - Tk_Offset(Axis, minor.lineWidth), - BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-hide", "hide", "Hide", "0", - Tk_Offset(Axis, flags), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrAxisHideOption}, - {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - "c", Tk_Offset(Axis, titleJustify), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_BOOLEAN, "-labeloffset", "labelOffset", "LabelOffset", - "no", Tk_Offset(Axis, labelOffset), ALL_GRAPHS}, - {BLT_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color", - STD_NORMAL_FOREGROUND, Tk_Offset(Axis, limitsTextStyle.color), - ALL_GRAPHS}, - {BLT_CONFIG_FONT, "-limitsfont", "limitsFont", "Font", STD_FONT_SMALL, - Tk_Offset(Axis, limitsTextStyle.font), ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-limitsformat", "limitsFormat", "LimitsFormat", - NULL, Tk_Offset(Axis, limitsFormats), - BLT_CONFIG_NULL_OK | ALL_GRAPHS, &formatOption}, - {BLT_CONFIG_PIXELS, "-linewidth", "lineWidth", "LineWidth", - "1", Tk_Offset(Axis, lineWidth), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_BOOLEAN, "-logscale", "logScale", "LogScale", - "0", Tk_Offset(Axis, logScale), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-loose", "loose", "Loose", "0", 0, - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, &looseOption}, - {BLT_CONFIG_CUSTOM, "-majorticks", "majorTicks", "MajorTicks", - NULL, Tk_Offset(Axis, t1Ptr), - BLT_CONFIG_NULL_OK | ALL_GRAPHS, &majorTicksOption}, - {BLT_CONFIG_CUSTOM, "-max", "max", "Max", NULL, - Tk_Offset(Axis, reqMax), ALL_GRAPHS, &limitOption}, - {BLT_CONFIG_CUSTOM, "-min", "min", "Min", NULL, - Tk_Offset(Axis, reqMin), ALL_GRAPHS, &limitOption}, - {BLT_CONFIG_CUSTOM, "-minorticks", "minorTicks", "MinorTicks", - NULL, Tk_Offset(Axis, t2Ptr), - BLT_CONFIG_NULL_OK | ALL_GRAPHS, &minorTicksOption}, - {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", - "flat", Tk_Offset(Axis, relief), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", "0", - Tk_Offset(Axis, tickAngle), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-scrollcommand", "scrollCommand", "ScrollCommand", - NULL, Tk_Offset(Axis, scrollCmdObjPtr), - ALL_GRAPHS | BLT_CONFIG_NULL_OK, - &objectOption}, - {BLT_CONFIG_PIXELS, "-scrollincrement", "scrollIncrement", - "ScrollIncrement", "10", - Tk_Offset(Axis, scrollUnits), ALL_GRAPHS|BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-scrollmax", "scrollMax", "ScrollMax", NULL, - Tk_Offset(Axis, reqScrollMax), ALL_GRAPHS, &limitOption}, - {BLT_CONFIG_CUSTOM, "-scrollmin", "scrollMin", "ScrollMin", NULL, - Tk_Offset(Axis, reqScrollMin), ALL_GRAPHS, &limitOption}, - {BLT_CONFIG_DOUBLE, "-shiftby", "shiftBy", "ShiftBy", - "0.0", Tk_Offset(Axis, shiftBy), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-showticks", "showTicks", "ShowTicks", - "1", Tk_Offset(Axis, flags), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrAxisShowTicksOption}, - {BLT_CONFIG_DOUBLE, "-stepsize", "stepSize", "StepSize", - "0.0", Tk_Offset(Axis, reqStep), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_INT, "-subdivisions", "subdivisions", "Subdivisions", - "2", Tk_Offset(Axis, reqNumMinorTicks), ALL_GRAPHS}, - {BLT_CONFIG_ANCHOR, "-tickanchor", "tickAnchor", "Anchor", - "c", Tk_Offset(Axis, reqTickAnchor), ALL_GRAPHS}, - {BLT_CONFIG_FONT, "-tickfont", "tickFont", "Font", - STD_FONT_SMALL, Tk_Offset(Axis, tickFont), - GRAPH | STRIPCHART}, - {BLT_CONFIG_FONT, "-tickfont", "tickFont", "Font", - STD_FONT_SMALL, Tk_Offset(Axis, tickFont), BARCHART}, - {BLT_CONFIG_PIXELS, "-ticklength", "tickLength", "TickLength", - "4", Tk_Offset(Axis, tickLength), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_INT, "-tickdefault", "tickDefault", "TickDefault", - "10", Tk_Offset(Axis, reqNumMajorTicks), - ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_STRING, "-title", "title", "Title", - NULL, Tk_Offset(Axis, title), - BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK | ALL_GRAPHS}, - {BLT_CONFIG_BOOLEAN, "-titlealternate", "titleAlternate", "TitleAlternate", - "0", Tk_Offset(Axis, titleAlternate), - BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, - {BLT_CONFIG_COLOR, "-titlecolor", "titleColor", "Color", - STD_NORMAL_FOREGROUND, Tk_Offset(Axis, titleColor), - ALL_GRAPHS}, - {BLT_CONFIG_FONT, "-titlefont", "titleFont", "Font", STD_FONT_NORMAL, - Tk_Offset(Axis, titleFont), ALL_GRAPHS}, - {BLT_CONFIG_CUSTOM, "-use", "use", "Use", NULL, 0, ALL_GRAPHS, - &useOption}, - {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} -}; + graphPtr->flags |= CACHE_DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); -static double Clamp(double x) -{ - return (x < 0.0) ? 0.0 : (x > 1.0) ? 1.0 : x; + return TCL_OK; } -static int Round(double x) +static Axis *NewAxis(Graph* graphPtr, const char *name, int margin) { - return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); -} + Axis *axisPtr = calloc(1, sizeof(Axis)); + axisPtr->obj.name = Blt_Strdup(name); + Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); + axisPtr->obj.graphPtr = graphPtr; + axisPtr->looseMin = AXIS_TIGHT; + axisPtr->looseMax = AXIS_TIGHT; + axisPtr->reqNumMinorTicks = 2; + axisPtr->reqNumMajorTicks = 4; + axisPtr->margin = margin; + axisPtr->tickLength = 8; + axisPtr->scrollUnits = 10; + axisPtr->reqMin = NAN; + axisPtr->reqMax = NAN; + axisPtr->reqScrollMin = NAN; + axisPtr->reqScrollMax = NAN; + axisPtr->flags = (AXIS_AUTO_MAJOR|AXIS_AUTO_MINOR); + axisPtr->exterior =1; + axisPtr->hide =0; + axisPtr->showTicks =1; + axisPtr->showGridMinor =1; + axisPtr->showGrid =1; + axisPtr->checkLimits =0; + + if ((graphPtr->classId == CID_ELEM_BAR) && + ((margin == MARGIN_TOP) || (margin == MARGIN_BOTTOM))) { + axisPtr->reqStep = 1.0; + axisPtr->reqNumMinorTicks = 0; + } + if ((margin == MARGIN_RIGHT) || (margin == MARGIN_TOP)) + axisPtr->hide = 1; -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; + Blt_Ts_InitStyle(axisPtr->limitsTextStyle); + axisPtr->tickLabels = Blt_Chain_Create(); + axisPtr->lineWidth = 1; + + axisPtr->optionTable = + Tk_CreateOptionTable(graphPtr->interp, axisOptionSpecs); + return axisPtr; } -static int InRange(double x, AxisRange *rangePtr) +static void DestroyAxis(Axis *axisPtr) { - if (rangePtr->range < DBL_EPSILON) { - return (fabs(rangePtr->max - x) >= DBL_EPSILON); - } else { - double norm; + Graph* graphPtr = axisPtr->obj.graphPtr; - norm = (x - rangePtr->min) * rangePtr->scale; - return ((norm >= -DBL_EPSILON) && ((norm - 1.0) < DBL_EPSILON)); - } + if (graphPtr->bindTable) + Blt_DeleteBindings(graphPtr->bindTable, axisPtr); + + if (axisPtr->link) + Blt_Chain_DeleteLink(axisPtr->chain, axisPtr->link); + + if (axisPtr->obj.name) + free((void*)(axisPtr->obj.name)); + + if (axisPtr->hashPtr) + Tcl_DeleteHashEntry(axisPtr->hashPtr); + + Blt_Ts_FreeStyle(graphPtr->display, &axisPtr->limitsTextStyle); + + if (axisPtr->tickGC) + Tk_FreeGC(graphPtr->display, axisPtr->tickGC); + + if (axisPtr->activeTickGC) + Tk_FreeGC(graphPtr->display, axisPtr->activeTickGC); + + if (axisPtr->major.gc) + Blt_FreePrivateGC(graphPtr->display, axisPtr->major.gc); + + if (axisPtr->minor.gc) + Blt_FreePrivateGC(graphPtr->display, axisPtr->minor.gc); + + FreeTickLabels(axisPtr->tickLabels); + + Blt_Chain_Destroy(axisPtr->tickLabels); + + if (axisPtr->segments) + free(axisPtr->segments); + + Tk_FreeConfigOptions((char*)axisPtr, axisPtr->optionTable, graphPtr->tkwin); + free(axisPtr); } -static int AxisIsHorizontal(Axis *axisPtr) +// Configure + +static int CgetOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = axisPtr->obj.graphPtr; - return ((axisPtr->obj.classId == CID_AXIS_Y) == graphPtr->inverted); + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, (char*)axisPtr, + axisPtr->optionTable, + objv[3], graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; } -static void ReleaseAxis(Axis *axisPtr) +static int AxisCgetOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - if (axisPtr != NULL) { - axisPtr->refCount--; - assert(axisPtr->refCount >= 0); - if (axisPtr->refCount == 0) { - axisPtr->flags |= DELETE_PENDING; - Tcl_EventuallyFree(axisPtr, FreeAxis); - } - } + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return CgetOp(interp, axisPtr, objc-1, objv+1); } -static void FreeAxisProc(ClientData clientData, Display *display, - char *widgRec, int offset) +static int ConfigureOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis **axisPtrPtr = (Axis **)(widgRec + offset); + Graph* graphPtr = axisPtr->obj.graphPtr; - if (*axisPtrPtr != NULL) { - ReleaseAxis(*axisPtrPtr); - *axisPtrPtr = NULL; - } + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(graphPtr->interp, (char*)axisPtr, + axisPtr->optionTable, + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return AxisObjConfigure(interp, graphPtr, axisPtr, objc-3, objv+3); } -static int ObjToAxisProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, - char *widgRec, int offset, int flags) +static int AxisConfigureOp(Tcl_Interp* interp, Graph* graphPtr, int objc, + Tcl_Obj* const objv[]) { - ClassId classId = (ClassId)clientData; - Axis **axisPtrPtr = (Axis **)(widgRec + offset); Axis *axisPtr; - Graph* graphPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - if (flags & BLT_CONFIG_NULL_OK) { - const char *string; + return ConfigureOp(interp, axisPtr, objc-1, objv+1); +} - string = Tcl_GetString(objPtr); - if (string[0] == '\0') { - ReleaseAxis(*axisPtrPtr); - *axisPtrPtr = NULL; - return TCL_OK; +static int AxisObjConfigure(Tcl_Interp* interp, Graph* graphPtr, Axis* axis, + int objc, Tcl_Obj* const objv[]) +{ + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)axisPtr, axisPtr->optionTable, + objc, objv, graphPtr->tkwin, &savedOptions, &mask) + != TCL_OK) + continue; } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + graphPtr->flags |= mask; + graphPtr->flags |= CACHE_DIRTY; + ConfigureAxis(graphPtr, axisPtr); + Blt_EventuallyRedrawGraph(graphPtr); + + break; } - graphPtr = Blt_GetGraphFromWindowData(tkwin); - assert(graphPtr); - if (GetAxisByClass(interp, graphPtr, objPtr, classId, &axisPtr) - != TCL_OK) { + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); return TCL_ERROR; } - ReleaseAxis(*axisPtrPtr); - *axisPtrPtr = axisPtr; - return TCL_OK; } -static Tcl_Obj *AxisToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +// Ops + +static int ActivateOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = *(Axis **)(widgRec + offset); - const char *name; + Graph* graphPtr = axisPtr->obj.graphPtr; + const char *string; - name = (axisPtr == NULL) ? "" : axisPtr->obj.name; - return Tcl_NewStringObj(name, -1); + string = Tcl_GetString(objv[2]); + if (string[0] == 'a') + axisPtr->flags |= ACTIVE; + else + axisPtr->flags &= ~ACTIVE; + + if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { + graphPtr->flags |= DRAW_MARGINS | CACHE_DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); + } + + return TCL_OK; } -static void FreeFormatProc(ClientData clientData, Display *display, - char *widgRec, int offset) +static int BindOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); + Graph* graphPtr = axisPtr->obj.graphPtr; - if (axisPtr->limitsFormats != NULL) { - free(axisPtr->limitsFormats); - axisPtr->limitsFormats = NULL; - } - axisPtr->nFormats = 0; + return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, Blt_MakeAxisTag(graphPtr, axisPtr->obj.name), objc-3, objv+3); } - -static int ObjToFormatProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, - int offset, int flags) + +static int InvTransformOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); - const char **argv; - int argc; + Graph* graphPtr = axisPtr->obj.graphPtr; - if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc, &argv) != TCL_OK) { - return TCL_ERROR; - } - if (argc > 2) { - Tcl_AppendResult(interp, "too many elements in limits format list \"", - Tcl_GetString(objPtr), "\"", NULL); - free(argv); + if (graphPtr->flags & RESET_AXES) + Blt_ResetAxes(graphPtr); + + int sy; + if (Tcl_GetIntFromObj(interp, objv[3], &sy) != TCL_OK) return TCL_ERROR; - } - if (axisPtr->limitsFormats != NULL) { - free(axisPtr->limitsFormats); - } - axisPtr->limitsFormats = argv; - axisPtr->nFormats = argc; + + /* + * 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). + */ + double y; + if (AxisIsHorizontal(axisPtr)) + y = Blt_InvHMap(axisPtr, (double)sy); + else + y = Blt_InvVMap(axisPtr, (double)sy); + + Tcl_SetDoubleObj(Tcl_GetObjResult(interp), y); return TCL_OK; } -static Tcl_Obj *FormatToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +static int LimitsOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); - Tcl_Obj *objPtr; + Graph* graphPtr = axisPtr->obj.graphPtr; - if (axisPtr->nFormats == 0) { - objPtr = Tcl_NewStringObj("", -1); - } else { - char *string; + if (graphPtr->flags & RESET_AXES) + Blt_ResetAxes(graphPtr); - string = Tcl_Merge(axisPtr->nFormats, axisPtr->limitsFormats); - objPtr = Tcl_NewStringObj(string, -1); - free(string); + double min, max; + if (axisPtr->logScale) { + min = EXP10(axisPtr->axisRange.min); + max = EXP10(axisPtr->axisRange.max); + } + else { + min = axisPtr->axisRange.min; + max = axisPtr->axisRange.max; } - return objPtr; + + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(min)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(max)); + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } -static int ObjToLimitProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, - int offset, int flags) +static int MarginOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - double *limitPtr = (double *)(widgRec + offset); - const char *string; + const char *marginName = ""; + if (axisPtr->flags & AXIS_USE) + marginName = axisNames[axisPtr->margin].name; - string = Tcl_GetString(objPtr); - if (string[0] == '\0') { - *limitPtr = NAN; - } else if (Blt_ExprDoubleFromObj(interp, objPtr, limitPtr) != TCL_OK) { - return TCL_ERROR; - } + Tcl_SetStringObj(Tcl_GetObjResult(interp), marginName, -1); return TCL_OK; } -static Tcl_Obj *LimitToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +static int TransformOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - double limit = *(double *)(widgRec + offset); - Tcl_Obj *objPtr; + Graph* graphPtr = axisPtr->obj.graphPtr; - if (!isnan(limit)) - objPtr = Tcl_NewDoubleObj(limit); + if (graphPtr->flags & RESET_AXES) + Blt_ResetAxes(graphPtr); + + double x; + if (Blt_ExprDoubleFromObj(interp, objv[3], &x) != TCL_OK) + return TCL_ERROR; + + if (AxisIsHorizontal(axisPtr)) + x = Blt_HMap(axisPtr, x); else - objPtr = Tcl_NewStringObj("", -1); + x = Blt_VMap(axisPtr, x); - return objPtr; + Tcl_SetIntObj(Tcl_GetObjResult(interp), (int)x); + return TCL_OK; } -static int ObjToUseProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, - int offset, int flags) +static int TypeOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); - AxisName *p, *pend; - Blt_Chain chain; - Graph* graphPtr; - const char *string; - int margin; + const char *typeName; - graphPtr = axisPtr->obj.graphPtr; - if (axisPtr->refCount == 0) { - /* Clear the axis class if it's not currently used by an element.*/ - Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); - } - /* Remove the axis from the margin's use list and clear its use flag. */ - if (axisPtr->link != NULL) { - Blt_Chain_UnlinkLink(axisPtr->chain, axisPtr->link); - } - axisPtr->flags &= ~AXIS_USE; - string = Tcl_GetString(objPtr); - if ((string == NULL) || (string[0] == '\0')) { - goto done; - } - for (p = axisNames, pend = axisNames + nAxisNames; p < pend; p++) { - if (strcmp(p->name, string) == 0) { - break; /* Found the axis name. */ + typeName = ""; + if (axisPtr->flags & AXIS_USE) + if (axisNames[axisPtr->margin].classId == CID_AXIS_X) + typeName = "x"; + else if (axisNames[axisPtr->margin].classId == CID_AXIS_Y) + typeName = "y"; + + Tcl_SetStringObj(Tcl_GetObjResult(interp), typeName, -1); + return TCL_OK; +} + +static int UseOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = (Graph *)axisPtr; + + Blt_Chain chain = graphPtr->margins[lastMargin].axes; + if (objc == 0) { + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (Blt_ChainLink link = Blt_Chain_FirstLink(chain); link != NULL; + link = Blt_Chain_NextLink(link)) { + Axis *axisPtr = Blt_Chain_GetValue(link); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(axisPtr->obj.name, -1)); } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } - if (p == pend) { - Tcl_AppendResult(interp, "unknown axis type \"", string, "\": " - "should be x, y, x1, y2, or \"\".", NULL); - return TCL_ERROR; + ClassId classId; + if ((lastMargin == MARGIN_BOTTOM) || (lastMargin == MARGIN_TOP)) { + classId = (graphPtr->inverted) ? CID_AXIS_Y : CID_AXIS_X; + } else { + classId = (graphPtr->inverted) ? CID_AXIS_X : CID_AXIS_Y; } - /* Check the axis class. Can't use the axis if it's already being used as - * another type. */ - if (axisPtr->obj.classId == CID_NONE) { - Blt_GraphSetObjectClass(&axisPtr->obj, p->classId); - } else if (axisPtr->obj.classId != p->classId) { - Tcl_AppendResult(interp, "wrong type for axis \"", - axisPtr->obj.name, "\": can't use ", - axisPtr->obj.className, " type axis.", NULL); + int axisObjc; + Tcl_Obj **axisObjv; + if (Tcl_ListObjGetElements(interp, objv[3], &axisObjc, &axisObjv) + != TCL_OK) { return TCL_ERROR; } - margin = (graphPtr->inverted) ? p->invertMargin : p->margin; - chain = graphPtr->margins[margin].axes; - if (axisPtr->link != NULL) { - /* Move the axis from the old margin's "use" list to the new. */ - Blt_Chain_AppendLink(chain, axisPtr->link); - } else { - axisPtr->link = Blt_Chain_Append(chain, axisPtr); + for (link = Blt_Chain_FirstLink(chain); link!= NULL; + link = Blt_Chain_NextLink(link)) { + Axis *axisPtr; + + axisPtr = Blt_Chain_GetValue(link); + axisPtr->link = NULL; + axisPtr->flags &= ~AXIS_USE; + /* Clear the axis type if it's not currently used.*/ + if (axisPtr->refCount == 0) { + Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); + } + } + Blt_Chain_Reset(chain); + for (int i=0; iobj.classId == CID_NONE) + Blt_GraphSetObjectClass(&axisPtr->obj, classId); + else if (axisPtr->obj.classId != classId) { + Tcl_AppendResult(interp, "wrong type axis \"", + axisPtr->obj.name, "\": can't use ", + axisPtr->obj.className, " type axis.", NULL); + return TCL_ERROR; + } + if (axisPtr->link != NULL) { + /* Move the axis from the old margin's "use" list to the new. */ + Blt_Chain_UnlinkLink(axisPtr->chain, axisPtr->link); + Blt_Chain_AppendLink(chain, axisPtr->link); + } else { + axisPtr->link = Blt_Chain_Append(chain, axisPtr); + } + axisPtr->chain = chain; + axisPtr->flags |= AXIS_USE; } - axisPtr->chain = chain; - axisPtr->flags |= AXIS_USE; - axisPtr->margin = margin; - done: 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); + return TCL_OK; } -static Tcl_Obj *UseToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +static int ViewOp(Tcl_Interp* interp, Axis *axisPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); - - if (axisPtr->margin == MARGIN_NONE) { - return Tcl_NewStringObj("", -1); + Graph* graphPtr = axisPtr->obj.graphPtr; + double worldMin = axisPtr->valueRange.min; + double worldMax = axisPtr->valueRange.max; + /* Override data dimensions with user-selected limits. */ + if (!isnan(axisPtr->scrollMin)) + worldMin = axisPtr->scrollMin; + + if (!isnan(axisPtr->scrollMax)) + worldMax = axisPtr->scrollMax; + + double viewMin = axisPtr->min; + double 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); } - return Tcl_NewStringObj(axisNames[axisPtr->margin].name, -1); -} + double worldWidth = worldMax - worldMin; + double viewWidth = viewMax - viewMin; -static void FreeTicksProc(ClientData clientData, Display *display, - char *widgRec, int offset) -{ - Axis *axisPtr = (Axis *)widgRec; - Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset); - unsigned long mask = (unsigned long)clientData; + /* 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. */ + double axisOffset; + double axisScale; + if (AxisIsHorizontal(axisPtr) != axisPtr->descending) { + axisOffset = viewMin - worldMin; + axisScale = graphPtr->hScale; + } else { + axisOffset = worldMax - viewMax; + axisScale = graphPtr->vScale; + } + if (objc == 4) { + double first = Clamp(axisOffset / worldWidth); + double last = Clamp((axisOffset + viewWidth) / worldWidth); + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(first)); + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(last)); + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + double fract = axisOffset / worldWidth; + if (GetAxisScrollInfo(interp, objc, objv, &fract, viewWidth / worldWidth, axisPtr->scrollUnits, axisScale) != TCL_OK) + return TCL_ERROR; - axisPtr->flags |= mask; - if (*ticksPtrPtr != NULL) { - free(*ticksPtrPtr); + if (AxisIsHorizontal(axisPtr) != axisPtr->descending) { + axisPtr->reqMin = (fract * worldWidth) + worldMin; + axisPtr->reqMax = axisPtr->reqMin + viewWidth; } - *ticksPtrPtr = NULL; + 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; } -static int ObjToTicksProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, - int offset, int flags) -{ - Axis *axisPtr = (Axis *)widgRec; - Tcl_Obj **objv; - Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset); - Ticks *ticksPtr; - int objc; - unsigned long mask = (unsigned long)clientData; +static Blt_OpSpec defAxisOps[] = { + {"activate", 1, ActivateOp, 3, 3, "",}, + {"bind", 1, BindOp, 2, 5, "sequence command",}, + {"cget", 2, CgetOp, 4, 4, "option",}, + {"configure", 2, ConfigureOp, 3, 0, "?option value?...",}, + {"deactivate", 1, ActivateOp, 3, 3, "",}, + {"invtransform", 1, InvTransformOp, 4, 4, "value",}, + {"limits", 1, LimitsOp, 3, 3, "",}, + {"transform", 1, TransformOp, 4, 4, "value",}, + {"use", 1, UseOp, 3, 4, "?axisName?",}, + {"view", 1, ViewOp, 3, 6, "?moveto fract? ",}, +}; - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - axisPtr->flags |= mask; - ticksPtr = NULL; - if (objc > 0) { - int i; +static int nDefAxisOps = sizeof(defAxisOps) / sizeof(Blt_OpSpec); - ticksPtr = malloc(sizeof(Ticks) + (objc*sizeof(double))); - for (i = 0; i < objc; i++) { - double value; +int Blt_DefAxisOp(Tcl_Interp* interp, Graph* graphPtr, int margin, + int objc, Tcl_Obj* const objv[]) +{ + GraphDefAxisProc* proc = Blt_GetOpFromObj(interp, nDefAxisOps, axisOps, + BLT_OP_ARG2, objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; - if (Blt_ExprDoubleFromObj(interp, objv[i], &value) != TCL_OK) { - free(ticksPtr); - return TCL_ERROR; - } - ticksPtr->values[i] = value; - } - ticksPtr->nTicks = objc; - axisPtr->flags &= ~mask; + if (proc == UseOp) { + // Set global variable to the margin in the argument list + lastMargin = margin; + return (*proc)(interp, (Axis*)graphPtr, objc, objv); + } + else { + Axis* axisPtr = Blt_GetFirstAxis(graphPtr->margins[margin].axes); + if (axisPtr == NULL) + return TCL_OK; + return (*proc)(interp, axisPtr, objc, objv); } - FreeTicksProc(clientData, Tk_Display(tkwin), widgRec, offset); - *ticksPtrPtr = ticksPtr; - return TCL_OK; } -static Tcl_Obj *TicksToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +static int AxisActivateOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { Axis *axisPtr; - Tcl_Obj *listObjPtr; - Ticks *ticksPtr; - unsigned long mask; - - axisPtr = (Axis *)widgRec; - ticksPtr = *(Ticks **) (widgRec + offset); - mask = (unsigned long)clientData; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - if ((ticksPtr != NULL) && ((axisPtr->flags & mask) == 0)) { - unsigned int i; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - for (i = 0; i < ticksPtr->nTicks; i++) { - Tcl_Obj *objPtr; + return ActivateOp(interp, axisPtr, objc, objv); +} - objPtr = Tcl_NewDoubleObj(ticksPtr->values[i]); +static int AxisBindOp(Tcl_Interp* interp, Graph* graphPtr, int objc, + Tcl_Obj* const objv[]) +{ + if (objc == 3) { + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->axes.tagTable, &cursor); hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + const char *tagName = Tcl_GetHashKey(&graphPtr->axes.tagTable, hPtr); + Tcl_Obj *objPtr = Tcl_NewStringObj(tagName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } - return listObjPtr; + else + return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, Blt_MakeAxisTag(graphPtr, Tcl_GetString(objv[3])), objc-4, objv+4); } -static int ObjToLooseProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, - int offset, int flags) +static int AxisCreateOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)(widgRec); - Tcl_Obj **objv; - int i; - int objc; - int values[2]; - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - if ((objc < 1) || (objc > 2)) { - Tcl_AppendResult(interp, "wrong # elements in loose value \"", - Tcl_GetString(objPtr), "\"", NULL); + if (CreateAxis(graphPtr, interp, Tcl_GetString(objv[3]), graphPtr->classId, objc, objv) != TCL_OK) return TCL_ERROR; - } - for (i = 0; i < objc; i++) { - const char *string; - - string = Tcl_GetString(objv[i]); - if ((string[0] == 'a') && (strcmp(string, "always") == 0)) { - values[i] = AXIS_ALWAYS_LOOSE; - } else { - int bool; - - if (Tcl_GetBooleanFromObj(interp, objv[i], &bool) != TCL_OK) { - return TCL_ERROR; - } - values[i] = bool; - } - } - axisPtr->looseMin = axisPtr->looseMax = values[0]; - if (objc > 1) { - axisPtr->looseMax = values[1]; - } + Tcl_SetObjResult(interp, objv[3]); return TCL_OK; } -static Tcl_Obj *LooseToObjProc(ClientData clientData, Tcl_Interp* interp, - Tk_Window tkwin, char *widgRec, - int offset, int flags) +static int AxisDeleteOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Axis *axisPtr = (Axis *)widgRec; - Tcl_Obj *listObjPtr; + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - if (axisPtr->looseMin == AXIS_TIGHT) { - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewBooleanObj(FALSE)); - } else if (axisPtr->looseMin == AXIS_LOOSE) { - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewBooleanObj(TRUE)); - } else if (axisPtr->looseMin == AXIS_ALWAYS_LOOSE) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("always", 6)); - } - if (axisPtr->looseMin != axisPtr->looseMax) { - if (axisPtr->looseMax == AXIS_TIGHT) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewBooleanObj(FALSE)); - } else if (axisPtr->looseMax == AXIS_LOOSE) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewBooleanObj(TRUE)); - } else if (axisPtr->looseMax == AXIS_ALWAYS_LOOSE) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("always", 6)); - } - } - return listObjPtr; + axisPtr->flags |= DELETE_PENDING; + if (axisPtr->refCount == 0) + Tcl_EventuallyFree(axisPtr, FreeAxis); + + return TCL_OK; } -static void FreeTickLabels(Blt_Chain chain) +static int AxisFocusOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Blt_ChainLink link; + if (objc > 3) { + Axis *axisPtr = NULL; + const char *string = Tcl_GetString(objv[3]); + if ((string[0] != '\0') && + (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK)) + return TCL_ERROR; - for (link = Blt_Chain_FirstLink(chain); link != NULL; - link = Blt_Chain_NextLink(link)) { - TickLabel *labelPtr; + graphPtr->focusPtr = NULL; + if (axisPtr && !axisPtr->hide && (axisPtr->flags & AXIS_USE)) + graphPtr->focusPtr = axisPtr; - labelPtr = Blt_Chain_GetValue(link); - free(labelPtr); + Blt_SetFocusItem(graphPtr->bindTable, graphPtr->focusPtr, NULL); } - Blt_Chain_Reset(chain); + /* Return the name of the axis that has focus. */ + if (graphPtr->focusPtr != NULL) + Tcl_SetStringObj(Tcl_GetObjResult(interp), graphPtr->focusPtr->obj.name,-1); + + return TCL_OK; } -static TickLabel *MakeLabel(Axis *axisPtr, double value) +static int AxisGetOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { -#define TICK_LABEL_SIZE 200 - char string[TICK_LABEL_SIZE + 1]; - TickLabel *labelPtr; - - /* Generate a default tick label based upon the tick value. */ - if (axisPtr->logScale) { - sprintf_s(string, TICK_LABEL_SIZE, "1E%d", ROUND(value)); - } else { - sprintf_s(string, TICK_LABEL_SIZE, "%.*G", NUMDIGITS, value); + Axis *axisPtr = Blt_GetCurrentItem(graphPtr->bindTable); + /* Report only on axes. */ + if ((axisPtr != NULL) && + ((axisPtr->obj.classId == CID_AXIS_X) || + (axisPtr->obj.classId == CID_AXIS_Y) || + (axisPtr->obj.classId == CID_NONE))) { + char *string = Tcl_GetString(objv[3]); + char c = string[0]; + if ((c == 'c') && (strcmp(string, "current") == 0)) + Tcl_SetStringObj(Tcl_GetObjResult(interp), axisPtr->obj.name,-1); + else if ((c == 'd') && (strcmp(string, "detail") == 0)) + Tcl_SetStringObj(Tcl_GetObjResult(interp), axisPtr->detail, -1); } - if (axisPtr->formatCmd != NULL) { - Graph* graphPtr; - Tcl_Interp* interp; - Tk_Window tkwin; - - graphPtr = axisPtr->obj.graphPtr; - interp = graphPtr->interp; - 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, 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 = malloc(sizeof(TickLabel) + strlen(string)); - strcpy(labelPtr->string, string); - labelPtr->anchorPos.x = DBL_MAX; - labelPtr->anchorPos.y = DBL_MAX; - return labelPtr; + return TCL_OK; } -double Blt_InvHMap(Axis *axisPtr, double x) +static int AxisInvTransformOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - double value; + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - x = (double)(x - axisPtr->screenMin) * axisPtr->screenScale; - if (axisPtr->descending) { - x = 1.0 - x; - } - value = (x * axisPtr->axisRange.range) + axisPtr->axisRange.min; - if (axisPtr->logScale) { - value = EXP10(value); - } - return value; + return InvTransformOp(interp, axisPtr, objc-1, objv+1); } -double Blt_InvVMap(Axis *axisPtr, double y) /* Screen coordinate */ +static int AxisLimitsOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - double value; + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - y = (double)(y - axisPtr->screenMin) * axisPtr->screenScale; - 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; + return LimitsOp(interp, axisPtr, objc-1, objv+1); } -double Blt_HMap(Axis *axisPtr, double x) +static int AxisMarginOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - 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 * axisPtr->screenRange + axisPtr->screenMin); + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return MarginOp(interp, axisPtr, objc-1, objv+1); } -double Blt_VMap(Axis *axisPtr, double y) +static int AxisNamesOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - 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; + Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc == 3) { + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = Tcl_GetHashValue(hPtr); + if (axisPtr->flags & DELETE_PENDING) + continue; + + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(axisPtr->obj.name, -1)); + } + } + else { + Tcl_HashSearch cursor; + for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr = Tcl_GetHashValue(hPtr); + for (int ii=3; iiobj.name, pattern)) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(axisPtr->obj.name, -1)); + break; + } + } + } } - return ((1.0 - y) * axisPtr->screenRange + axisPtr->screenMin); + Tcl_SetObjResult(interp, listObjPtr); + + return TCL_OK; } -Point2d Blt_Map2D(Graph* graphPtr, double x, double y, Axis2d *axesPtr) +static int AxisTransformOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Point2d point; + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - if (graphPtr->inverted) { - point.x = Blt_HMap(axesPtr->y, y); - point.y = Blt_VMap(axesPtr->x, x); - } else { - point.x = Blt_HMap(axesPtr->x, x); - point.y = Blt_VMap(axesPtr->y, y); - } - return point; + return TransformOp(interp, axisPtr, objc-1, objv+1); } -Point2d Blt_InvMap2D(Graph* graphPtr, double x, double y, Axis2d *axesPtr) +static int AxisTypeOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Point2d point; + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; - if (graphPtr->inverted) { - point.x = Blt_InvVMap(axesPtr->x, y); - point.y = Blt_InvHMap(axesPtr->y, x); - } else { - point.x = Blt_InvHMap(axesPtr->x, x); - point.y = Blt_InvVMap(axesPtr->y, y); - } - return point; + return TypeOp(interp, axisPtr, objc-1, objv+1); } -static void GetDataLimits(Axis *axisPtr, double min, double max) +static int AxisViewOp(Tcl_Interp* interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - if (axisPtr->valueRange.min > min) { - axisPtr->valueRange.min = min; - } - if (axisPtr->valueRange.max < max) { - axisPtr->valueRange.max = max; - } + Axis *axisPtr; + if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) + return TCL_ERROR; + + return ViewOp(interp, axisPtr, objc-1, objv+1); } -static void FixAxisRange(Axis *axisPtr) +static Blt_OpSpec axisOps[] = { + {"activate", 1, AxisActivateOp, 4, 4, "axisName"}, + {"bind", 1, AxisBindOp, 3, 6, "axisName sequence command"}, + {"cget", 2, AxisCgetOp, 5, 5, "axisName option"}, + {"configure", 2, AxisConfigureOp, 4, 0, "axisName ?axisName?... " + "?option value?..."}, + {"create", 2, AxisCreateOp, 4, 0, "axisName ?option value?..."}, + {"deactivate", 3, AxisActivateOp, 4, 4, "axisName"}, + {"delete", 3, AxisDeleteOp, 3, 0, "?axisName?..."}, + {"focus", 1, AxisFocusOp, 3, 4, "?axisName?"}, + {"get", 1, AxisGetOp, 4, 4, "name"}, + {"invtransform", 1, AxisInvTransformOp, 5, 5, "axisName value"}, + {"limits", 1, AxisLimitsOp, 4, 4, "axisName"}, + {"margin", 1, AxisMarginOp, 4, 4, "axisName"}, + {"names", 1, AxisNamesOp, 3, 0, "?pattern?..."}, + {"transform", 2, AxisTransformOp, 5, 5, "axisName value"}, + {"type", 2, AxisTypeOp, 4, 4, "axisName"}, + {"view", 1, AxisViewOp, 4, 7, "axisName ?moveto fract? " + "?scroll number what?"}, +}; +static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec); + +int Blt_AxisOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) { - double min, max; + GraphAxisProc* proc = + Blt_GetOpFromObj(interp, nAxisOps, axisOps, BLT_OP_ARG2, objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; - /* - * 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; + return (*proc)(interp, graphPtr, objc, objv); +} - /* Check the requested axis limits. Can't allow -min to be greater - * than -max, or have undefined log scale limits. */ - if (((!isnan(axisPtr->reqMin)) && (!isnan(axisPtr->reqMax))) && - (axisPtr->reqMin >= axisPtr->reqMax)) { - axisPtr->reqMin = axisPtr->reqMax = NAN; - } - if (axisPtr->logScale) { - if ((!isnan(axisPtr->reqMin)) && (axisPtr->reqMin <= 0.0)) { - axisPtr->reqMin = NAN; - } - if ((!isnan(axisPtr->reqMax)) && (axisPtr->reqMax <= 0.0)) { - axisPtr->reqMax = NAN; - } - } +// Support - if (min == DBL_MAX) { - if (!isnan(axisPtr->reqMin)) { - min = axisPtr->reqMin; - } else { - min = (axisPtr->logScale) ? 0.001 : 0.0; - } - } - if (max == -DBL_MAX) { - if (!isnan(axisPtr->reqMax)) { - max = axisPtr->reqMax; - } else { - max = 1.0; - } - } - if (min >= max) { - /* - * There is no range of data (i.e. min is not less than max), so - * manufacture one. - */ - if (min == 0.0) { - min = 0.0, max = 1.0; - } else { - max = min + (fabs(min) * 0.1); - } - } - SetAxisRange(&axisPtr->valueRange, min, max); +static double Clamp(double x) +{ + return (x < 0.0) ? 0.0 : (x > 1.0) ? 1.0 : x; +} - /* - * 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 (!isnan(axisPtr->reqMin)) { - axisPtr->min = axisPtr->reqMin; - } - if (!isnan(axisPtr->reqMax)) { - axisPtr->max = axisPtr->reqMax; +static int Round(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; } - 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 (isnan(axisPtr->reqMin)) { - axisPtr->min = axisPtr->max - (fabs(axisPtr->max) * 0.1); - } - if (isnan(axisPtr->reqMax)) { - axisPtr->max = axisPtr->min + (fabs(axisPtr->max) * 0.1); - } + rangePtr->scale = 1.0 / rangePtr->range; +} + +static int InRange(double x, AxisRange *rangePtr) +{ + if (rangePtr->range < DBL_EPSILON) { + 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)); } - /* - * If a window size is defined, handle auto ranging by shifting the axis - * limits. - */ - if ((axisPtr->windowSize > 0.0) && - (isnan(axisPtr->reqMin)) && (isnan(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; +} + +static int AxisIsHorizontal(Axis *axisPtr) +{ + Graph* graphPtr = axisPtr->obj.graphPtr; + + return ((axisPtr->obj.classId == CID_AXIS_Y) == graphPtr->inverted); +} + +static void ReleaseAxis(Axis *axisPtr) +{ + if (axisPtr != NULL) { + axisPtr->refCount--; + assert(axisPtr->refCount >= 0); + if (axisPtr->refCount == 0) { + axisPtr->flags |= DELETE_PENDING; + Tcl_EventuallyFree(axisPtr, FreeAxis); } - axisPtr->max = max; - } - if ((axisPtr->max != axisPtr->prevMax) || - (axisPtr->min != axisPtr->prevMin)) { - /* Indicate if the axis limits have changed */ - axisPtr->flags |= DIRTY; - /* and save the previous minimum and maximum values */ - axisPtr->prevMin = axisPtr->min; - axisPtr->prevMax = axisPtr->max; } } -// Reference: Paul Heckbert, "Nice Numbers for Graph Labels", -// Graphics Gems, pp 61-63. -double NiceNum(double x, int round) +static void FreeAxisProc(ClientData clientData, Display *display, + char *widgRec, int offset) { - double expt; /* Exponent of x */ - double frac; /* Fractional part of x */ - double nice; /* Nice, rounded fraction */ + Axis **axisPtrPtr = (Axis **)(widgRec + offset); - expt = floor(log10(x)); - frac = x / EXP10(expt); /* between 1 and 10 */ - if (round) { - if (frac < 1.5) { - nice = 1.0; - } else if (frac < 3.0) { - nice = 2.0; - } else if (frac < 7.0) { - nice = 5.0; - } else { - nice = 10.0; - } - } else { - if (frac <= 1.0) { - nice = 1.0; - } else if (frac <= 2.0) { - nice = 2.0; - } else if (frac <= 5.0) { - nice = 5.0; - } else { - nice = 10.0; - } + if (*axisPtrPtr != NULL) { + ReleaseAxis(*axisPtrPtr); + *axisPtrPtr = NULL; } - return nice * EXP10(expt); } -static Ticks *GenerateTicks(TickSweep *sweepPtr) +static int ObjToAxisProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, + char *widgRec, int offset, int flags) { - Ticks *ticksPtr; + ClassId classId = (ClassId)clientData; + Axis **axisPtrPtr = (Axis **)(widgRec + offset); + Axis *axisPtr; + Graph* graphPtr; - ticksPtr = malloc(sizeof(Ticks) + - (sweepPtr->nSteps * sizeof(double))); - ticksPtr->nTicks = 0; + if (flags & BLT_CONFIG_NULL_OK) { + const char *string; - if (sweepPtr->step == 0.0) { - /* Hack: A zero step indicates to use log values. */ - int i; - /* Precomputed log10 values [1..10] */ - static double logTable[] = { - 0.0, - 0.301029995663981, - 0.477121254719662, - 0.602059991327962, - 0.698970004336019, - 0.778151250383644, - 0.845098040014257, - 0.903089986991944, - 0.954242509439325, - 1.0 - }; - for (i = 0; i < sweepPtr->nSteps; i++) { - ticksPtr->values[i] = logTable[i]; - } - } else { - double value; - int i; - - 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; + string = Tcl_GetString(objPtr); + if (string[0] == '\0') { + ReleaseAxis(*axisPtrPtr); + *axisPtrPtr = NULL; + return TCL_OK; } } - ticksPtr->nTicks = sweepPtr->nSteps; - return ticksPtr; + graphPtr = Blt_GetGraphFromWindowData(tkwin); + assert(graphPtr); + if (GetAxisByClass(interp, graphPtr, objPtr, classId, &axisPtr) + != TCL_OK) { + return TCL_ERROR; + } + ReleaseAxis(*axisPtrPtr); + *axisPtrPtr = axisPtr; + return TCL_OK; } -static void LogScaleAxis(Axis *axisPtr, double min, double max) +static Tcl_Obj *AxisToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) { - double range; - double tickMin, tickMax; - double majorStep, minorStep; - int nMajor, nMinor; + Axis *axisPtr = *(Axis **)(widgRec + offset); + const char *name; - nMajor = nMinor = 0; - /* Suppress compiler warnings. */ - majorStep = minorStep = 0.0; - tickMin = tickMax = NAN; - if (min < max) { - min = (min != 0.0) ? log10(fabs(min)) : 0.0; - max = (max != 0.0) ? log10(fabs(max)) : 1.0; + name = (axisPtr == NULL) ? "" : axisPtr->obj.name; + return Tcl_NewStringObj(name, -1); +} - 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 / axisPtr->reqNumMajorTicks, 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 == AXIS_TIGHT) || - ((axisPtr->looseMin == AXIS_LOOSE) && - (!isnan(axisPtr->reqMin)))) { - tickMin = min; - nMajor++; - } - if ((axisPtr->looseMax == AXIS_TIGHT) || - ((axisPtr->looseMax == AXIS_LOOSE) && - (!isnan(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; +static void FreeFormatProc(ClientData clientData, Display *display, + char *widgRec, int offset) +{ + Axis *axisPtr = (Axis *)(widgRec); - SetAxisRange(&axisPtr->axisRange, tickMin, tickMax); + if (axisPtr->limitsFormats != NULL) { + free(axisPtr->limitsFormats); + axisPtr->limitsFormats = NULL; + } + axisPtr->nFormats = 0; } -static void LinearScaleAxis(Axis *axisPtr, double min, double max) +static int ObjToFormatProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - double step; - double tickMin, tickMax; - double axisMin, axisMax; - unsigned int nTicks; - - nTicks = 0; - step = 1.0; - /* Suppress compiler warning. */ - axisMin = axisMax = tickMin = tickMax = NAN; - if (min < max) { - double range; - - 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 / axisPtr->reqNumMajorTicks, 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; + Axis *axisPtr = (Axis *)(widgRec); + const char **argv; + int argc; - /* - * 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 == AXIS_TIGHT) || - ((axisPtr->looseMin == AXIS_LOOSE) && - (!isnan(axisPtr->reqMin)))) { - axisMin = min; + if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc, &argv) != TCL_OK) { + return TCL_ERROR; } - if ((axisPtr->looseMax == AXIS_TIGHT) || - ((axisPtr->looseMax == AXIS_LOOSE) && - (!isnan(axisPtr->reqMax)))) { - axisMax = max; + if (argc > 2) { + Tcl_AppendResult(interp, "too many elements in limits format list \"", + Tcl_GetString(objPtr), "\"", NULL); + free(argv); + return TCL_ERROR; } - SetAxisRange(&axisPtr->axisRange, axisMin, axisMax); + if (axisPtr->limitsFormats != NULL) { + free(axisPtr->limitsFormats); + } + axisPtr->limitsFormats = argv; + axisPtr->nFormats = argc; + return TCL_OK; +} - /* Now calculate the minor tick step and number. */ +static Tcl_Obj *FormatToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) +{ + Axis *axisPtr = (Axis *)(widgRec); + Tcl_Obj *objPtr; - if ((axisPtr->reqNumMinorTicks > 0) && (axisPtr->flags & AXIS_AUTO_MAJOR)) { - nTicks = axisPtr->reqNumMinorTicks - 1; - step = 1.0 / (nTicks + 1); + if (axisPtr->nFormats == 0) { + objPtr = Tcl_NewStringObj("", -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. */ + char *string; + + string = Tcl_Merge(axisPtr->nFormats, axisPtr->limitsFormats); + objPtr = Tcl_NewStringObj(string, -1); + free(string); } - axisPtr->minorSweep.initial = axisPtr->minorSweep.step = step; - axisPtr->minorSweep.nSteps = nTicks; + return objPtr; } -static void SweepTicks(Axis *axisPtr) +static int ObjToLimitProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - if (axisPtr->flags & AXIS_AUTO_MAJOR) { - if (axisPtr->t1Ptr != NULL) { - free(axisPtr->t1Ptr); - } - axisPtr->t1Ptr = GenerateTicks(&axisPtr->majorSweep); - } - if (axisPtr->flags & AXIS_AUTO_MINOR) { - if (axisPtr->t2Ptr != NULL) { - free(axisPtr->t2Ptr); - } - axisPtr->t2Ptr = GenerateTicks(&axisPtr->minorSweep); + double *limitPtr = (double *)(widgRec + offset); + const char *string; + + string = Tcl_GetString(objPtr); + if (string[0] == '\0') { + *limitPtr = NAN; + } else if (Blt_ExprDoubleFromObj(interp, objPtr, limitPtr) != TCL_OK) { + return TCL_ERROR; } + return TCL_OK; } -void Blt_ResetAxes(Graph* graphPtr) +static Tcl_Obj *LimitToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) { - Blt_ChainLink link; - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - - /* 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_InitBarSetTable(graphPtr); - if ((graphPtr->barMode == BARS_STACKED) && (graphPtr->nBarGroups > 0)) - Blt_ComputeBarStacks(graphPtr); + double limit = *(double *)(widgRec + offset); + Tcl_Obj *objPtr; - /* - * Step 1: Reset all axes. Initialize the data limits of the axis to - * impossible values. - */ - for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { - Axis *axisPtr; + if (!isnan(limit)) + objPtr = Tcl_NewDoubleObj(limit); + else + objPtr = Tcl_NewStringObj("", -1); - axisPtr = Tcl_GetHashValue(hPtr); - axisPtr->min = axisPtr->valueRange.min = DBL_MAX; - axisPtr->max = axisPtr->valueRange.max = -DBL_MAX; - } + return objPtr; +} - /* - * 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 (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element* elemPtr; - Region2d exts; +static int ObjToUseProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) +{ + Axis *axisPtr = (Axis *)(widgRec); + AxisName *p, *pend; + Blt_Chain chain; + Graph* graphPtr; + const char *string; + int margin; - elemPtr = Blt_Chain_GetValue(link); - (*elemPtr->procsPtr->extentsProc) (elemPtr, &exts); - GetDataLimits(elemPtr->axes.x, exts.left, exts.right); - GetDataLimits(elemPtr->axes.y, exts.top, exts.bottom); + graphPtr = axisPtr->obj.graphPtr; + if (axisPtr->refCount == 0) { + /* Clear the axis class if it's not currently used by an element.*/ + Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); } - /* - * 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 = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { - Axis *axisPtr; - double min, max; - - axisPtr = Tcl_GetHashValue(hPtr); - FixAxisRange(axisPtr); - - /* Calculate min/max tick (major/minor) layouts */ - min = axisPtr->min; - max = axisPtr->max; - if ((!isnan(axisPtr->scrollMin)) && (min < axisPtr->scrollMin)) { - min = axisPtr->scrollMin; - } - if ((!isnan(axisPtr->scrollMax)) && (max > axisPtr->scrollMax)) { - max = axisPtr->scrollMax; - } - if (axisPtr->logScale) { - LogScaleAxis(axisPtr, min, max); - } else if (axisPtr->timeScale) { - TimeScaleAxis(axisPtr, min, max); - } else { - LinearScaleAxis(axisPtr, min, max); + /* Remove the axis from the margin's use list and clear its use flag. */ + if (axisPtr->link != NULL) { + Blt_Chain_UnlinkLink(axisPtr->chain, axisPtr->link); + } + axisPtr->flags &= ~AXIS_USE; + string = Tcl_GetString(objPtr); + if ((string == NULL) || (string[0] == '\0')) { + goto done; + } + for (p = axisNames, pend = axisNames + nAxisNames; p < pend; p++) { + if (strcmp(p->name, string) == 0) { + break; /* Found the axis name. */ } + } + if (p == pend) { + Tcl_AppendResult(interp, "unknown axis type \"", string, "\": " + "should be x, y, x1, y2, or \"\".", NULL); + return TCL_ERROR; + } + /* Check the axis class. Can't use the axis if it's already being used as + * another type. */ + if (axisPtr->obj.classId == CID_NONE) { + Blt_GraphSetObjectClass(&axisPtr->obj, p->classId); + } else if (axisPtr->obj.classId != p->classId) { + Tcl_AppendResult(interp, "wrong type for axis \"", + axisPtr->obj.name, "\": can't use ", + axisPtr->obj.className, " type axis.", NULL); + return TCL_ERROR; + } + margin = (graphPtr->inverted) ? p->invertMargin : p->margin; + chain = graphPtr->margins[margin].axes; + if (axisPtr->link != NULL) { + /* Move the axis from the old margin's "use" list to the new. */ + Blt_Chain_AppendLink(chain, axisPtr->link); + } else { + axisPtr->link = Blt_Chain_Append(chain, axisPtr); + } + axisPtr->chain = chain; + axisPtr->flags |= AXIS_USE; + axisPtr->margin = margin; + done: + 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); + return TCL_OK; +} - if ((axisPtr->flags & (DIRTY|AXIS_USE)) == (DIRTY|AXIS_USE)) { - graphPtr->flags |= CACHE_DIRTY; - } +static Tcl_Obj *UseToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) +{ + Axis *axisPtr = (Axis *)(widgRec); + + if (axisPtr->margin == MARGIN_NONE) { + return Tcl_NewStringObj("", -1); } + return Tcl_NewStringObj(axisNames[axisPtr->margin].name, -1); +} - graphPtr->flags &= ~RESET_AXES; +static void FreeTicksProc(ClientData clientData, Display *display, + char *widgRec, int offset) +{ + Axis *axisPtr = (Axis *)widgRec; + Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset); + unsigned long mask = (unsigned long)clientData; - /* - * When any axis changes, we need to layout the entire graph. - */ - graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | MAP_ALL | - REDRAW_WORLD); + axisPtr->flags |= mask; + if (*ticksPtrPtr != NULL) { + free(*ticksPtrPtr); + } + *ticksPtrPtr = NULL; } -static void ResetTextStyles(Axis *axisPtr) +static int ObjToTicksProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - Graph* graphPtr = axisPtr->obj.graphPtr; - GC newGC; - XGCValues gcValues; - unsigned long gcMask; + Axis *axisPtr = (Axis *)widgRec; + Tcl_Obj **objv; + Ticks **ticksPtrPtr = (Ticks **) (widgRec + offset); + Ticks *ticksPtr; + int objc; + unsigned long mask = (unsigned long)clientData; - Blt_Ts_ResetStyle(graphPtr->tkwin, &axisPtr->limitsTextStyle); + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + axisPtr->flags |= mask; + ticksPtr = NULL; + if (objc > 0) { + int i; - gcMask = (GCForeground | GCLineWidth | GCCapStyle); - gcValues.foreground = axisPtr->tickColor->pixel; - gcValues.font = Tk_FontId(axisPtr->tickFont); - gcValues.line_width = LineWidth(axisPtr->lineWidth); - gcValues.cap_style = CapProjecting; + ticksPtr = malloc(sizeof(Ticks) + (objc*sizeof(double))); + for (i = 0; i < objc; i++) { + double value; - newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - if (axisPtr->tickGC != NULL) { - Tk_FreeGC(graphPtr->display, axisPtr->tickGC); + if (Blt_ExprDoubleFromObj(interp, objv[i], &value) != TCL_OK) { + free(ticksPtr); + return TCL_ERROR; + } + ticksPtr->values[i] = value; + } + ticksPtr->nTicks = objc; + axisPtr->flags &= ~mask; } - axisPtr->tickGC = newGC; + FreeTicksProc(clientData, Tk_Display(tkwin), widgRec, offset); + *ticksPtrPtr = ticksPtr; + return TCL_OK; +} - /* Assuming settings from above GC */ - gcValues.foreground = axisPtr->activeFgColor->pixel; - newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - if (axisPtr->activeTickGC != NULL) { - Tk_FreeGC(graphPtr->display, axisPtr->activeTickGC); - } - axisPtr->activeTickGC = newGC; +static Tcl_Obj *TicksToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) +{ + Axis *axisPtr; + Tcl_Obj *listObjPtr; + Ticks *ticksPtr; + unsigned long mask; - gcValues.background = gcValues.foreground = axisPtr->major.color->pixel; - gcValues.line_width = LineWidth(axisPtr->major.lineWidth); - gcMask = (GCForeground | GCBackground | GCLineWidth); - if (LineIsDashed(axisPtr->major.dashes)) { - gcValues.line_style = LineOnOffDash; - gcMask |= GCLineStyle; - } - newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); - if (LineIsDashed(axisPtr->major.dashes)) { - Blt_SetDashes(graphPtr->display, newGC, &axisPtr->major.dashes); - } - if (axisPtr->major.gc != NULL) { - Blt_FreePrivateGC(graphPtr->display, axisPtr->major.gc); - } - axisPtr->major.gc = newGC; + axisPtr = (Axis *)widgRec; + ticksPtr = *(Ticks **) (widgRec + offset); + mask = (unsigned long)clientData; + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if ((ticksPtr != NULL) && ((axisPtr->flags & mask) == 0)) { + unsigned int i; - gcValues.background = gcValues.foreground = axisPtr->minor.color->pixel; - gcValues.line_width = LineWidth(axisPtr->minor.lineWidth); - gcMask = (GCForeground | GCBackground | GCLineWidth); - if (LineIsDashed(axisPtr->minor.dashes)) { - gcValues.line_style = LineOnOffDash; - gcMask |= GCLineStyle; - } - newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); - if (LineIsDashed(axisPtr->minor.dashes)) { - Blt_SetDashes(graphPtr->display, newGC, &axisPtr->minor.dashes); - } - if (axisPtr->minor.gc != NULL) { - Blt_FreePrivateGC(graphPtr->display, axisPtr->minor.gc); + for (i = 0; i < ticksPtr->nTicks; i++) { + Tcl_Obj *objPtr; + + objPtr = Tcl_NewDoubleObj(ticksPtr->values[i]); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } } - axisPtr->minor.gc = newGC; + return listObjPtr; } -static void DestroyAxis(Axis *axisPtr) +static int ObjToLooseProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - Graph* graphPtr = axisPtr->obj.graphPtr; - int flags; + Axis *axisPtr = (Axis *)(widgRec); + Tcl_Obj **objv; + int i; + int objc; + int values[2]; - flags = Blt_GraphType(graphPtr); - Blt_FreeOptions(configSpecs, (char*)axisPtr, graphPtr->display, flags); - if (graphPtr->bindTable != NULL) { - Blt_DeleteBindings(graphPtr->bindTable, axisPtr); - } - if (axisPtr->link != NULL) { - Blt_Chain_DeleteLink(axisPtr->chain, axisPtr->link); - } - if (axisPtr->obj.name != NULL) { - free((void*)(axisPtr->obj.name)); + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; } - if (axisPtr->hashPtr != NULL) { - Tcl_DeleteHashEntry(axisPtr->hashPtr); + if ((objc < 1) || (objc > 2)) { + Tcl_AppendResult(interp, "wrong # elements in loose value \"", + Tcl_GetString(objPtr), "\"", NULL); + return TCL_ERROR; } - Blt_Ts_FreeStyle(graphPtr->display, &axisPtr->limitsTextStyle); + for (i = 0; i < objc; i++) { + const char *string; - if (axisPtr->tickGC != NULL) { - Tk_FreeGC(graphPtr->display, axisPtr->tickGC); - } - if (axisPtr->activeTickGC != NULL) { - Tk_FreeGC(graphPtr->display, axisPtr->activeTickGC); - } - if (axisPtr->major.gc != NULL) { - Blt_FreePrivateGC(graphPtr->display, axisPtr->major.gc); - } - if (axisPtr->minor.gc != NULL) { - Blt_FreePrivateGC(graphPtr->display, axisPtr->minor.gc); + string = Tcl_GetString(objv[i]); + if ((string[0] == 'a') && (strcmp(string, "always") == 0)) { + values[i] = AXIS_ALWAYS_LOOSE; + } else { + int bool; + + if (Tcl_GetBooleanFromObj(interp, objv[i], &bool) != TCL_OK) { + return TCL_ERROR; + } + values[i] = bool; + } } - FreeTickLabels(axisPtr->tickLabels); - Blt_Chain_Destroy(axisPtr->tickLabels); - if (axisPtr->segments != NULL) { - free(axisPtr->segments); + axisPtr->looseMin = axisPtr->looseMax = values[0]; + if (objc > 1) { + axisPtr->looseMax = values[1]; } - free(axisPtr); - axisPtr = NULL; + return TCL_OK; } -static void FreeAxis(char* data) +static Tcl_Obj *LooseToObjProc(ClientData clientData, Tcl_Interp* interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) { - Axis *axisPtr = (Axis *)data; - DestroyAxis(axisPtr); -} + Axis *axisPtr = (Axis *)widgRec; + Tcl_Obj *listObjPtr; -static float titleAngle[4] = /* Rotation for each axis title */ - { - 0.0, 90.0, 0.0, 270.0 - }; + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (axisPtr->looseMin == AXIS_TIGHT) { + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewBooleanObj(FALSE)); + } else if (axisPtr->looseMin == AXIS_LOOSE) { + Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewBooleanObj(TRUE)); + } else if (axisPtr->looseMin == AXIS_ALWAYS_LOOSE) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("always", 6)); + } + if (axisPtr->looseMin != axisPtr->looseMax) { + if (axisPtr->looseMax == AXIS_TIGHT) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewBooleanObj(FALSE)); + } else if (axisPtr->looseMax == AXIS_LOOSE) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewBooleanObj(TRUE)); + } else if (axisPtr->looseMax == AXIS_ALWAYS_LOOSE) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("always", 6)); + } + } + return listObjPtr; +} -static void AxisOffsets(Axis *axisPtr, int margin, int offset, - AxisInfo *infoPtr) +static void FreeTickLabels(Blt_Chain chain) { - Graph* graphPtr = axisPtr->obj.graphPtr; - Margin *marginPtr; - int pad; /* Offset of axis from interior - * region. This includes a possible - * border and the axis line width. */ - int axisLine; - int t1, t2, labelOffset; - int tickLabel, axisPad; - int inset, mark; - int x, y; - float fangle; + Blt_ChainLink link; - axisPtr->titleAngle = titleAngle[margin]; - marginPtr = graphPtr->margins + margin; + for (link = Blt_Chain_FirstLink(chain); link != NULL; + link = Blt_Chain_NextLink(link)) { + TickLabel *labelPtr; - tickLabel = axisLine = t1 = t2 = 0; - labelOffset = AXIS_PAD_TITLE; - if (axisPtr->lineWidth > 0) { - if (axisPtr->showTicks) { - t1 = axisPtr->tickLength; - t2 = (t1 * 10) / 15; - } - labelOffset = t1 + AXIS_PAD_TITLE; - if (axisPtr->exterior) - labelOffset += axisPtr->lineWidth; - } - axisPad = 0; - if (graphPtr->plotRelief != TK_RELIEF_SOLID) { - axisPad = 0; + labelPtr = Blt_Chain_GetValue(link); + free(labelPtr); } - /* Adjust offset for the interior border width and the line width */ - pad = 1; - if (graphPtr->plotBW > 0) { - pad += graphPtr->plotBW + 1; + Blt_Chain_Reset(chain); +} + +static TickLabel *MakeLabel(Axis *axisPtr, double value) +{ +#define TICK_LABEL_SIZE 200 + char string[TICK_LABEL_SIZE + 1]; + TickLabel *labelPtr; + + /* Generate a default tick label based upon the tick value. */ + if (axisPtr->logScale) { + sprintf_s(string, TICK_LABEL_SIZE, "1E%d", ROUND(value)); + } else { + sprintf_s(string, TICK_LABEL_SIZE, "%.*G", NUMDIGITS, value); } - pad = 0; /* FIXME: test */ - /* - * Pre-calculate the x-coordinate positions of the axis, tick labels, and - * the individual major and minor ticks. - */ - inset = pad + axisPtr->lineWidth / 2; - switch (margin) { - case MARGIN_TOP: - axisLine = graphPtr->top; - if (axisPtr->exterior) { - axisLine -= graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; - tickLabel = axisLine - 2; - if (axisPtr->lineWidth > 0) { - tickLabel -= axisPtr->tickLength; - } - } else { - if (graphPtr->plotRelief == TK_RELIEF_SOLID) { - axisLine--; - } - axisLine -= axisPad + axisPtr->lineWidth / 2; - tickLabel = graphPtr->top - graphPtr->plotBW - 2; - } - mark = graphPtr->top - offset - pad; - axisPtr->tickAnchor = TK_ANCHOR_S; - axisPtr->left = axisPtr->screenMin - inset - 2; - axisPtr->right = axisPtr->screenMin + axisPtr->screenRange + inset - 1; - if (graphPtr->stackAxes) { - axisPtr->top = mark - marginPtr->axesOffset; - } else { - axisPtr->top = mark - axisPtr->height; - } - axisPtr->bottom = mark; - if (axisPtr->titleAlternate) { - x = graphPtr->right + AXIS_PAD_TITLE; - y = mark - (axisPtr->height / 2); - axisPtr->titleAnchor = TK_ANCHOR_W; - } else { - x = (axisPtr->right + axisPtr->left) / 2; - if (graphPtr->stackAxes) { - y = mark - marginPtr->axesOffset + AXIS_PAD_TITLE; - } else { - y = mark - axisPtr->height + AXIS_PAD_TITLE; - } - axisPtr->titleAnchor = TK_ANCHOR_N; - } - axisPtr->titlePos.x = x; - axisPtr->titlePos.y = y; - break; - case MARGIN_BOTTOM: + if (axisPtr->formatCmd != NULL) { + Graph* graphPtr; + Tcl_Interp* interp; + Tk_Window tkwin; + + graphPtr = axisPtr->obj.graphPtr; + interp = graphPtr->interp; + tkwin = graphPtr->tkwin; /* - * ----------- bottom + plot borderwidth - * mark -------------------------------------------- - * ===================== axisLine (linewidth) - * tick - * title - * - * ===================== axisLine (linewidth) - * ----------- bottom + plot borderwidth - * mark -------------------------------------------- - * tick - * title + * 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. */ - axisLine = graphPtr->bottom; - if (graphPtr->plotRelief == TK_RELIEF_SOLID) { - axisLine++; - } - if (axisPtr->exterior) { - axisLine += graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; - tickLabel = axisLine + 2; - if (axisPtr->lineWidth > 0) { - tickLabel += axisPtr->tickLength; - } + Tcl_ResetResult(interp); + if (Tcl_VarEval(interp, axisPtr->formatCmd, " ", Tk_PathName(tkwin), + " ", string, NULL) != TCL_OK) { + Tcl_BackgroundError(interp); } else { - axisLine -= axisPad + axisPtr->lineWidth / 2; - tickLabel = graphPtr->bottom + graphPtr->plotBW + 2; + /* + * 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. */ } - mark = graphPtr->bottom + offset; - fangle = fmod(axisPtr->tickAngle, 90.0); - if (fangle == 0.0) { - axisPtr->tickAnchor = TK_ANCHOR_N; - } else { - int quadrant; + } + labelPtr = malloc(sizeof(TickLabel) + strlen(string)); + strcpy(labelPtr->string, string); + labelPtr->anchorPos.x = DBL_MAX; + labelPtr->anchorPos.y = DBL_MAX; + return labelPtr; +} - quadrant = (int)(axisPtr->tickAngle / 90.0); - if ((quadrant == 0) || (quadrant == 2)) { - axisPtr->tickAnchor = TK_ANCHOR_NE; - } else { - axisPtr->tickAnchor = TK_ANCHOR_NW; - } - } - axisPtr->left = axisPtr->screenMin - inset - 2; - axisPtr->right = axisPtr->screenMin + axisPtr->screenRange + inset - 1; - axisPtr->top = graphPtr->bottom + labelOffset - t1; - if (graphPtr->stackAxes) { - axisPtr->bottom = mark + marginPtr->axesOffset - 1; - } else { - axisPtr->bottom = mark + axisPtr->height - 1; - } - if (axisPtr->titleAlternate) { - x = graphPtr->right + AXIS_PAD_TITLE; - y = mark + (axisPtr->height / 2); - axisPtr->titleAnchor = TK_ANCHOR_W; - } else { - x = (axisPtr->right + axisPtr->left) / 2; - if (graphPtr->stackAxes) { - y = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; - } else { - y = mark + axisPtr->height - AXIS_PAD_TITLE; - } - axisPtr->titleAnchor = TK_ANCHOR_S; - } - axisPtr->titlePos.x = x; - axisPtr->titlePos.y = y; - break; +double Blt_InvHMap(Axis *axisPtr, double x) +{ + double value; - case MARGIN_LEFT: - /* - * mark - * | : - * | : - * | : - * | : - * | : - * axisLine - */ - /* - * Exterior axis - * + plotarea right - * |A|B|C|D|E|F|G|H - * |right - * A = plot pad - * B = plot border width - * C = axis pad - * D = axis line - * E = tick length - * F = tick label - * G = graph border width - * H = highlight thickness - */ - /* - * Interior axis - * + plotarea right - * |A|B|C|D|E|F|G|H - * |right - * A = plot pad - * B = tick length - * C = axis line width - * D = axis pad - * E = plot border width - * F = tick label - * G = graph border width - * H = highlight thickness - */ - axisLine = graphPtr->left; - if (axisPtr->exterior) { - axisLine -= graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; - tickLabel = axisLine - 2; - if (axisPtr->lineWidth > 0) { - tickLabel -= axisPtr->tickLength; - } - } else { - if (graphPtr->plotRelief == TK_RELIEF_SOLID) { - axisLine--; - } - axisLine += axisPad + axisPtr->lineWidth / 2; - tickLabel = graphPtr->left - graphPtr->plotBW - 2; - } - mark = graphPtr->left - offset; - axisPtr->tickAnchor = TK_ANCHOR_E; - if (graphPtr->stackAxes) { - axisPtr->left = mark - marginPtr->axesOffset; - } else { - axisPtr->left = mark - axisPtr->width; - } - axisPtr->right = mark - 3; - axisPtr->top = axisPtr->screenMin - inset - 2; - axisPtr->bottom = axisPtr->screenMin + axisPtr->screenRange + inset - 1; - if (axisPtr->titleAlternate) { - x = mark - (axisPtr->width / 2); - y = graphPtr->top - AXIS_PAD_TITLE; - axisPtr->titleAnchor = TK_ANCHOR_SW; - } else { - if (graphPtr->stackAxes) { - x = mark - marginPtr->axesOffset; - } else { - x = mark - axisPtr->width + AXIS_PAD_TITLE; - } - y = (axisPtr->bottom + axisPtr->top) / 2; - axisPtr->titleAnchor = TK_ANCHOR_W; - } - axisPtr->titlePos.x = x; - axisPtr->titlePos.y = y; - break; + x = (double)(x - axisPtr->screenMin) * axisPtr->screenScale; + if (axisPtr->descending) { + x = 1.0 - x; + } + value = (x * axisPtr->axisRange.range) + axisPtr->axisRange.min; + if (axisPtr->logScale) { + value = EXP10(value); + } + return value; +} - case MARGIN_RIGHT: - axisLine = graphPtr->right; - if (graphPtr->plotRelief == TK_RELIEF_SOLID) { - axisLine++; /* Draw axis line within solid plot - * border. */ - } - if (axisPtr->exterior) { - axisLine += graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; - tickLabel = axisLine + 2; - if (axisPtr->lineWidth > 0) { - tickLabel += axisPtr->tickLength; - } - } else { - axisLine -= axisPad + axisPtr->lineWidth / 2; - tickLabel = graphPtr->right + graphPtr->plotBW + 2; - } - mark = graphPtr->right + offset + pad; - axisPtr->tickAnchor = TK_ANCHOR_W; - axisPtr->left = mark; - if (graphPtr->stackAxes) { - axisPtr->right = mark + marginPtr->axesOffset - 1; - } else { - axisPtr->right = mark + axisPtr->width - 1; - } - axisPtr->top = axisPtr->screenMin - inset - 2; - axisPtr->bottom = axisPtr->screenMin + axisPtr->screenRange + inset -1; - if (axisPtr->titleAlternate) { - x = mark + (axisPtr->width / 2); - y = graphPtr->top - AXIS_PAD_TITLE; - axisPtr->titleAnchor = TK_ANCHOR_SE; - } else { - if (graphPtr->stackAxes) { - x = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; - } else { - x = mark + axisPtr->width - AXIS_PAD_TITLE; - } - y = (axisPtr->bottom + axisPtr->top) / 2; - axisPtr->titleAnchor = TK_ANCHOR_E; - } - axisPtr->titlePos.x = x; - axisPtr->titlePos.y = y; - break; +double Blt_InvVMap(Axis *axisPtr, double y) /* Screen coordinate */ +{ + double value; - case MARGIN_NONE: - axisLine = 0; - break; + y = (double)(y - axisPtr->screenMin) * axisPtr->screenScale; + 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; +} + +double Blt_HMap(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 * axisPtr->screenRange + axisPtr->screenMin); +} + +double Blt_VMap(Axis *axisPtr, double y) +{ + if ((axisPtr->logScale) && (y != 0.0)) { + y = log10(fabs(y)); } - if ((margin == MARGIN_LEFT) || (margin == MARGIN_TOP)) { - t1 = -t1, t2 = -t2; - labelOffset = -labelOffset; + /* Map graph coordinate to normalized coordinates [0..1] */ + y = (y - axisPtr->axisRange.min) * axisPtr->axisRange.scale; + if (axisPtr->descending) { + y = 1.0 - y; } - infoPtr->axis = axisLine; - infoPtr->t1 = axisLine + t1; - infoPtr->t2 = axisLine + t2; - if (tickLabel > 0) { - infoPtr->label = tickLabel; + return ((1.0 - y) * axisPtr->screenRange + axisPtr->screenMin); +} + +Point2d Blt_Map2D(Graph* graphPtr, double x, double y, Axis2d *axesPtr) +{ + Point2d point; + + if (graphPtr->inverted) { + point.x = Blt_HMap(axesPtr->y, y); + point.y = Blt_VMap(axesPtr->x, x); } else { - infoPtr->label = axisLine + labelOffset; + point.x = Blt_HMap(axesPtr->x, x); + point.y = Blt_VMap(axesPtr->y, y); } - if (!axisPtr->exterior) { - /*infoPtr->label = axisLine + labelOffset - t1; */ - infoPtr->t1 = axisLine - t1; - infoPtr->t2 = axisLine - t2; - } + return point; } -static void MakeAxisLine(Axis *axisPtr, int line, Segment2d *sp) +Point2d Blt_InvMap2D(Graph* graphPtr, double x, double y, Axis2d *axesPtr) { - double min, max; + Point2d point; - min = axisPtr->axisRange.min; - max = axisPtr->axisRange.max; - if (axisPtr->logScale) { - min = EXP10(min); - max = EXP10(max); - } - if (AxisIsHorizontal(axisPtr)) { - sp->p.x = Blt_HMap(axisPtr, min); - sp->q.x = Blt_HMap(axisPtr, max); - sp->p.y = sp->q.y = line; + if (graphPtr->inverted) { + point.x = Blt_InvVMap(axesPtr->x, y); + point.y = Blt_InvHMap(axesPtr->y, x); } else { - sp->q.x = sp->p.x = line; - sp->p.y = Blt_VMap(axisPtr, min); - sp->q.y = Blt_VMap(axisPtr, max); + point.x = Blt_InvHMap(axesPtr->x, x); + point.y = Blt_InvVMap(axesPtr->y, y); } + return point; } -static void MakeTick(Axis *axisPtr, double value, int tick, int line, - Segment2d *sp) +static void GetDataLimits(Axis *axisPtr, double min, double max) { - if (axisPtr->logScale) - value = EXP10(value); - - if (AxisIsHorizontal(axisPtr)) { - sp->p.x = sp->q.x = Blt_HMap(axisPtr, value); - sp->p.y = line; - sp->q.y = tick; + if (axisPtr->valueRange.min > min) { + axisPtr->valueRange.min = min; } - else { - sp->p.x = line; - sp->p.y = sp->q.y = Blt_VMap(axisPtr, value); - sp->q.x = tick; + if (axisPtr->valueRange.max < max) { + axisPtr->valueRange.max = max; } } -static void MakeSegments(Axis *axisPtr, AxisInfo *infoPtr) +static void FixAxisRange(Axis *axisPtr) { - int arraySize; - int nMajorTicks, nMinorTicks; - Segment2d *segments; - Segment2d *sp; - - if (axisPtr->segments) { - free(axisPtr->segments); - axisPtr->segments = NULL; - } - nMajorTicks = nMinorTicks = 0; - if (axisPtr->t1Ptr) - nMajorTicks = axisPtr->t1Ptr->nTicks; + double min, max; - if (axisPtr->t2Ptr) - nMinorTicks = axisPtr->t2Ptr->nTicks; + /* + * 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; - arraySize = 1 + (nMajorTicks * (nMinorTicks + 1)); - segments = malloc(arraySize * sizeof(Segment2d)); - sp = segments; - if (axisPtr->lineWidth > 0) { - /* Axis baseline */ - MakeAxisLine(axisPtr, infoPtr->axis, sp); - sp++; + /* Check the requested axis limits. Can't allow -min to be greater + * than -max, or have undefined log scale limits. */ + if (((!isnan(axisPtr->reqMin)) && (!isnan(axisPtr->reqMax))) && + (axisPtr->reqMin >= axisPtr->reqMax)) { + axisPtr->reqMin = axisPtr->reqMax = NAN; + } + if (axisPtr->logScale) { + if ((!isnan(axisPtr->reqMin)) && (axisPtr->reqMin <= 0.0)) { + axisPtr->reqMin = NAN; + } + if ((!isnan(axisPtr->reqMax)) && (axisPtr->reqMax <= 0.0)) { + axisPtr->reqMax = NAN; + } } - if (axisPtr->showTicks) { - Blt_ChainLink link; - double labelPos; - int i; - int isHoriz; - isHoriz = AxisIsHorizontal(axisPtr); - for (i = 0; i < nMajorTicks; i++) { - double t1, t2; - int j; + if (min == DBL_MAX) { + if (!isnan(axisPtr->reqMin)) { + min = axisPtr->reqMin; + } else { + min = (axisPtr->logScale) ? 0.001 : 0.0; + } + } + if (max == -DBL_MAX) { + if (!isnan(axisPtr->reqMax)) { + max = axisPtr->reqMax; + } else { + max = 1.0; + } + } + if (min >= max) { + /* + * There is no range of data (i.e. min is not less than max), so + * manufacture one. + */ + if (min == 0.0) { + min = 0.0, max = 1.0; + } else { + max = min + (fabs(min) * 0.1); + } + } + SetAxisRange(&axisPtr->valueRange, min, max); - t1 = axisPtr->t1Ptr->values[i]; - /* Minor ticks */ - for (j = 0; j < nMinorTicks; j++) { - t2 = t1 + (axisPtr->majorSweep.step * - axisPtr->t2Ptr->values[j]); - if (InRange(t2, &axisPtr->axisRange)) { - MakeTick(axisPtr, t2, infoPtr->t2, infoPtr->axis, sp); - sp++; - } - } - if (!InRange(t1, &axisPtr->axisRange)) { - continue; + /* + * 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 (!isnan(axisPtr->reqMin)) { + axisPtr->min = axisPtr->reqMin; + } + if (!isnan(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 (isnan(axisPtr->reqMin)) { + axisPtr->min = axisPtr->max - (fabs(axisPtr->max) * 0.1); + } + if (isnan(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) && + (isnan(axisPtr->reqMin)) && (isnan(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); } - /* Major tick */ - MakeTick(axisPtr, t1, infoPtr->t1, infoPtr->axis, sp); - sp++; + 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 |= DIRTY; + /* and save the previous minimum and maximum values */ + axisPtr->prevMin = axisPtr->min; + axisPtr->prevMax = axisPtr->max; + } +} - link = Blt_Chain_FirstLink(axisPtr->tickLabels); - labelPos = (double)infoPtr->label; - - for (i = 0; i < nMajorTicks; i++) { - double t1; - TickLabel *labelPtr; - Segment2d seg; +// Reference: Paul Heckbert, "Nice Numbers for Graph Labels", +// Graphics Gems, pp 61-63. +double NiceNum(double x, int round) +{ + double expt; /* Exponent of x */ + double frac; /* Fractional part of x */ + double nice; /* Nice, rounded fraction */ - t1 = axisPtr->t1Ptr->values[i]; - if (axisPtr->labelOffset) { - t1 += axisPtr->majorSweep.step * 0.5; - } - if (!InRange(t1, &axisPtr->axisRange)) { - continue; - } - labelPtr = Blt_Chain_GetValue(link); - link = Blt_Chain_NextLink(link); - MakeTick(axisPtr, t1, infoPtr->t1, infoPtr->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; - } + expt = floor(log10(x)); + frac = x / EXP10(expt); /* between 1 and 10 */ + if (round) { + if (frac < 1.5) { + nice = 1.0; + } else if (frac < 3.0) { + nice = 2.0; + } else if (frac < 7.0) { + nice = 5.0; + } else { + nice = 10.0; + } + } else { + if (frac <= 1.0) { + nice = 1.0; + } else if (frac <= 2.0) { + nice = 2.0; + } else if (frac <= 5.0) { + nice = 5.0; + } else { + nice = 10.0; } } - axisPtr->segments = segments; - axisPtr->nSegments = sp - segments; - assert(axisPtr->nSegments <= arraySize); + return nice * EXP10(expt); } -static void MapAxis(Axis *axisPtr, int offset, int margin) +static Ticks *GenerateTicks(TickSweep *sweepPtr) { - AxisInfo info; - Graph* graphPtr = axisPtr->obj.graphPtr; + Ticks *ticksPtr; - if (AxisIsHorizontal(axisPtr)) { - axisPtr->screenMin = graphPtr->hOffset; - axisPtr->width = graphPtr->right - graphPtr->left; - axisPtr->screenRange = graphPtr->hRange; + ticksPtr = malloc(sizeof(Ticks) + + (sweepPtr->nSteps * sizeof(double))); + ticksPtr->nTicks = 0; + + if (sweepPtr->step == 0.0) { + /* Hack: A zero step indicates to use log values. */ + int i; + /* Precomputed log10 values [1..10] */ + static double logTable[] = { + 0.0, + 0.301029995663981, + 0.477121254719662, + 0.602059991327962, + 0.698970004336019, + 0.778151250383644, + 0.845098040014257, + 0.903089986991944, + 0.954242509439325, + 1.0 + }; + for (i = 0; i < sweepPtr->nSteps; i++) { + ticksPtr->values[i] = logTable[i]; + } } else { - axisPtr->screenMin = graphPtr->vOffset; - axisPtr->height = graphPtr->bottom - graphPtr->top; - axisPtr->screenRange = graphPtr->vRange; + double value; + int i; + + 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; + } } - axisPtr->screenScale = 1.0 / axisPtr->screenRange; - AxisOffsets(axisPtr, margin, offset, &info); - MakeSegments(axisPtr, &info); + ticksPtr->nTicks = sweepPtr->nSteps; + return ticksPtr; } -static void MapStackedAxis(Axis *axisPtr, int count, int margin) +static void LogScaleAxis(Axis *axisPtr, double min, double max) { - AxisInfo info; - Graph* graphPtr = axisPtr->obj.graphPtr; - unsigned int slice, w, h; + double range; + double tickMin, tickMax; + double majorStep, minorStep; + int nMajor, nMinor; - if ((graphPtr->margins[axisPtr->margin].axes->nLinks > 1) || - (axisPtr->reqNumMajorTicks <= 0)) { - axisPtr->reqNumMajorTicks = 4; - } - if (AxisIsHorizontal(axisPtr)) { - slice = graphPtr->hRange / graphPtr->margins[margin].axes->nLinks; - axisPtr->screenMin = graphPtr->hOffset; - axisPtr->width = slice; - } else { - slice = graphPtr->vRange / graphPtr->margins[margin].axes->nLinks; - axisPtr->screenMin = graphPtr->vOffset; - axisPtr->height = slice; - } -#define AXIS_PAD 2 - Blt_GetTextExtents(axisPtr->tickFont, 0, "0", 1, &w, &h); - axisPtr->screenMin += (slice * count) + AXIS_PAD + h / 2; - axisPtr->screenRange = slice - 2 * AXIS_PAD - h; - axisPtr->screenScale = 1.0f / axisPtr->screenRange; - AxisOffsets(axisPtr, margin, 0, &info); - MakeSegments(axisPtr, &info); -} + nMajor = nMinor = 0; + /* Suppress compiler warnings. */ + majorStep = minorStep = 0.0; + tickMin = tickMax = NAN; + if (min < max) { + min = (min != 0.0) ? log10(fabs(min)) : 0.0; + max = (max != 0.0) ? log10(fabs(max)) : 1.0; -static double AdjustViewport(double offset, double 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; + 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 / axisPtr->reqNumMajorTicks, 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; } - } else { - if ((offset + windowSize) > 1.0) { - offset = 1.0 - windowSize; + if ((axisPtr->looseMin == AXIS_TIGHT) || + ((axisPtr->looseMin == AXIS_LOOSE) && + (!isnan(axisPtr->reqMin)))) { + tickMin = min; + nMajor++; } - if (offset < 0.0) { - offset = 0.0; + if ((axisPtr->looseMax == AXIS_TIGHT) || + ((axisPtr->looseMax == AXIS_LOOSE) && + (!isnan(axisPtr->reqMax)))) { + tickMax = max; } } - return offset; + 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); } -static int GetAxisScrollInfo(Tcl_Interp* interp, int objc, Tcl_Obj *const *objv, - double *offsetPtr, double windowSize, - double scrollUnits, double scale) +static void LinearScaleAxis(Axis *axisPtr, double min, double max) { - const char *string; - char c; - double offset; - int length; + double step; + double tickMin, tickMax; + double axisMin, axisMax; + unsigned int nTicks; - offset = *offsetPtr; - string = Tcl_GetStringFromObj(objv[0], &length); - c = string[0]; - scrollUnits *= scale; - if ((c == 's') && (strncmp(string, "scroll", length) == 0)) { - int count; - double fract; + nTicks = 0; + step = 1.0; + /* Suppress compiler warning. */ + axisMin = axisMax = tickMin = tickMax = NAN; + if (min < max) { + double range; - assert(objc == 3); - /* Scroll number unit/page */ - if (Tcl_GetIntFromObj(interp, objv[1], &count) != TCL_OK) { - return TCL_ERROR; - } - string = Tcl_GetStringFromObj(objv[2], &length); - c = string[0]; - if ((c == 'u') && (strncmp(string, "units", length) == 0)) { - fract = count * scrollUnits; - } else if ((c == 'p') && (strncmp(string, "pages", length) == 0)) { - /* A page is 90% of the view-able window. */ - fract = (int)(count * windowSize * 0.9 + 0.5); - } else if ((c == 'p') && (strncmp(string, "pixels", length) == 0)) { - fract = count * scale; + 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 { - Tcl_AppendResult(interp, "unknown \"scroll\" units \"", string, - "\"", NULL); - return TCL_ERROR; + range = NiceNum(range, 0); + step = NiceNum(range / axisPtr->reqNumMajorTicks, 1); } - offset += fract; - } else if ((c == 'm') && (strncmp(string, "moveto", length) == 0)) { - double fract; + + /* 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 == AXIS_TIGHT) || + ((axisPtr->looseMin == AXIS_LOOSE) && + (!isnan(axisPtr->reqMin)))) { + axisMin = min; + } + if ((axisPtr->looseMax == AXIS_TIGHT) || + ((axisPtr->looseMax == AXIS_LOOSE) && + (!isnan(axisPtr->reqMax)))) { + axisMax = max; + } + SetAxisRange(&axisPtr->axisRange, axisMin, axisMax); + + /* Now calculate the minor tick step and number. */ - assert(objc == 2); - /* moveto fraction */ - if (Tcl_GetDoubleFromObj(interp, objv[1], &fract) != TCL_OK) { - return TCL_ERROR; - } - offset = fract; + if ((axisPtr->reqNumMinorTicks > 0) && (axisPtr->flags & AXIS_AUTO_MAJOR)) { + nTicks = axisPtr->reqNumMinorTicks - 1; + step = 1.0 / (nTicks + 1); } else { - int count; - double fract; + 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; +} - /* Treat like "scroll units" */ - if (Tcl_GetIntFromObj(interp, objv[0], &count) != TCL_OK) { - return TCL_ERROR; +static void SweepTicks(Axis *axisPtr) +{ + if (axisPtr->flags & AXIS_AUTO_MAJOR) { + if (axisPtr->t1Ptr != NULL) { + free(axisPtr->t1Ptr); } - fract = (double)count * scrollUnits; - offset += fract; - /* CHECK THIS: return TCL_OK; */ + axisPtr->t1Ptr = GenerateTicks(&axisPtr->majorSweep); + } + if (axisPtr->flags & AXIS_AUTO_MINOR) { + if (axisPtr->t2Ptr != NULL) { + free(axisPtr->t2Ptr); + } + axisPtr->t2Ptr = GenerateTicks(&axisPtr->minorSweep); } - *offsetPtr = AdjustViewport(offset, windowSize); - return TCL_OK; } -static void DrawAxis(Axis *axisPtr, Drawable drawable) +void Blt_ResetAxes(Graph* graphPtr) { - Graph* graphPtr = axisPtr->obj.graphPtr; + Blt_ChainLink link; + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; - if (axisPtr->normalBg != NULL) { - Tk_Fill3DRectangle(graphPtr->tkwin, drawable, - axisPtr->normalBg, - axisPtr->left, axisPtr->top, - axisPtr->right - axisPtr->left, - axisPtr->bottom - axisPtr->top, - axisPtr->borderWidth, - axisPtr->relief); - } - if (axisPtr->title != NULL) { - TextStyle ts; + /* 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_InitBarSetTable(graphPtr); + if ((graphPtr->barMode == BARS_STACKED) && (graphPtr->nBarGroups > 0)) + Blt_ComputeBarStacks(graphPtr); - Blt_Ts_InitStyle(ts); - Blt_Ts_SetAngle(ts, axisPtr->titleAngle); - Blt_Ts_SetFont(ts, axisPtr->titleFont); - Blt_Ts_SetPadding(ts, 1, 0); - Blt_Ts_SetAnchor(ts, axisPtr->titleAnchor); - Blt_Ts_SetJustify(ts, axisPtr->titleJustify); - if (axisPtr->flags & ACTIVE) - Blt_Ts_SetForeground(ts, axisPtr->activeFgColor); - else - Blt_Ts_SetForeground(ts, axisPtr->titleColor); + /* + * Step 1: Reset all axes. Initialize the data limits of the axis to + * impossible values. + */ + for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr; - Blt_Ts_SetForeground(ts, axisPtr->titleColor); - if ((axisPtr->titleAngle == 90.0) || (axisPtr->titleAngle == 270.0)) - Blt_Ts_SetMaxLength(ts, axisPtr->height); - else - Blt_Ts_SetMaxLength(ts, axisPtr->width); + axisPtr = Tcl_GetHashValue(hPtr); + axisPtr->min = axisPtr->valueRange.min = DBL_MAX; + axisPtr->max = axisPtr->valueRange.max = -DBL_MAX; + } - Blt_Ts_DrawText(graphPtr->tkwin, drawable, axisPtr->title, -1, &ts, - (int)axisPtr->titlePos.x, (int)axisPtr->titlePos.y); + /* + * 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 (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element* elemPtr; + Region2d exts; + + elemPtr = Blt_Chain_GetValue(link); + (*elemPtr->procsPtr->extentsProc) (elemPtr, &exts); + GetDataLimits(elemPtr->axes.x, exts.left, exts.right); + GetDataLimits(elemPtr->axes.y, exts.top, exts.bottom); } - if (axisPtr->scrollCmdObjPtr != NULL) { - double viewWidth, viewMin, viewMax; - double worldWidth, worldMin, worldMax; - double fract; - int isHoriz; + /* + * 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 = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + Axis *axisPtr; + double min, max; - worldMin = axisPtr->valueRange.min; - worldMax = axisPtr->valueRange.max; - if (!isnan(axisPtr->scrollMin)) { - worldMin = axisPtr->scrollMin; - } - if (!isnan(axisPtr->scrollMax)) { - worldMax = axisPtr->scrollMax; - } - viewMin = axisPtr->min; - viewMax = axisPtr->max; - if (viewMin < worldMin) { - viewMin = worldMin; + axisPtr = Tcl_GetHashValue(hPtr); + FixAxisRange(axisPtr); + + /* Calculate min/max tick (major/minor) layouts */ + min = axisPtr->min; + max = axisPtr->max; + if ((!isnan(axisPtr->scrollMin)) && (min < axisPtr->scrollMin)) { + min = axisPtr->scrollMin; } - if (viewMax > worldMax) { - viewMax = worldMax; + if ((!isnan(axisPtr->scrollMax)) && (max > axisPtr->scrollMax)) { + max = axisPtr->scrollMax; } if (axisPtr->logScale) { - worldMin = log10(worldMin); - worldMax = log10(worldMax); - viewMin = log10(viewMin); - viewMax = log10(viewMax); - } - worldWidth = worldMax - worldMin; - viewWidth = viewMax - viewMin; - isHoriz = AxisIsHorizontal(axisPtr); - - if (isHoriz != axisPtr->descending) { - fract = (viewMin - worldMin) / worldWidth; + LogScaleAxis(axisPtr, min, max); + } else if (axisPtr->timeScale) { + TimeScaleAxis(axisPtr, min, max); } else { - fract = (worldMax - viewMax) / worldWidth; + LinearScaleAxis(axisPtr, min, max); } - 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->scrollCmdObjPtr, - viewMin, 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->scrollCmdObjPtr, - viewMax, viewMin, worldWidth); + if ((axisPtr->flags & (DIRTY|AXIS_USE)) == (DIRTY|AXIS_USE)) { + graphPtr->flags |= CACHE_DIRTY; } } - if (axisPtr->showTicks) { - Blt_ChainLink link; - TextStyle ts; - - Blt_Ts_InitStyle(ts); - Blt_Ts_SetAngle(ts, axisPtr->tickAngle); - Blt_Ts_SetFont(ts, axisPtr->tickFont); - Blt_Ts_SetPadding(ts, 2, 0); - Blt_Ts_SetAnchor(ts, axisPtr->tickAnchor); - if (axisPtr->flags & ACTIVE) - Blt_Ts_SetForeground(ts, axisPtr->activeFgColor); - else - Blt_Ts_SetForeground(ts, axisPtr->tickColor); - for (link = Blt_Chain_FirstLink(axisPtr->tickLabels); link != NULL; - link = Blt_Chain_NextLink(link)) { - TickLabel *labelPtr; - - labelPtr = Blt_Chain_GetValue(link); - /* Draw major tick labels */ - Blt_DrawText(graphPtr->tkwin, drawable, labelPtr->string, &ts, - (int)labelPtr->anchorPos.x, (int)labelPtr->anchorPos.y); - } - } - if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { - GC gc; + graphPtr->flags &= ~RESET_AXES; - if (axisPtr->flags & ACTIVE) { - gc = axisPtr->activeTickGC; - } else { - gc = axisPtr->tickGC; - } - /* Draw the tick marks and axis line. */ - Blt_Draw2DSegments(graphPtr->display, drawable, gc, axisPtr->segments, - axisPtr->nSegments); - } + /* + * When any axis changes, we need to layout the entire graph. + */ + graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | MAP_ALL | + REDRAW_WORLD); } -static void AxisToPostScript(Blt_Ps ps, Axis *axisPtr) +static void ResetTextStyles(Axis *axisPtr) { - Blt_Ps_Format(ps, "%% Axis \"%s\"\n", axisPtr->obj.name); - if (axisPtr->normalBg != NULL) { - Blt_Ps_Fill3DRectangle(ps, axisPtr->normalBg, - (double)axisPtr->left, (double)axisPtr->top, - axisPtr->right - axisPtr->left, - axisPtr->bottom - axisPtr->top, - axisPtr->borderWidth, axisPtr->relief); - } - if (axisPtr->title != NULL) { - TextStyle ts; - - Blt_Ts_InitStyle(ts); - Blt_Ts_SetAngle(ts, axisPtr->titleAngle); - Blt_Ts_SetFont(ts, axisPtr->titleFont); - Blt_Ts_SetPadding(ts, 1, 0); - Blt_Ts_SetAnchor(ts, axisPtr->titleAnchor); - Blt_Ts_SetJustify(ts, axisPtr->titleJustify); - Blt_Ts_SetForeground(ts, axisPtr->titleColor); - Blt_Ps_DrawText(ps, axisPtr->title, &ts, axisPtr->titlePos.x, - axisPtr->titlePos.y); - } - if (axisPtr->showTicks) { - Blt_ChainLink link; - TextStyle ts; + Graph* graphPtr = axisPtr->obj.graphPtr; + GC newGC; + XGCValues gcValues; + unsigned long gcMask; - Blt_Ts_InitStyle(ts); - Blt_Ts_SetAngle(ts, axisPtr->tickAngle); - Blt_Ts_SetFont(ts, axisPtr->tickFont); - Blt_Ts_SetPadding(ts, 2, 0); - Blt_Ts_SetAnchor(ts, axisPtr->tickAnchor); - Blt_Ts_SetForeground(ts, axisPtr->tickColor); + Blt_Ts_ResetStyle(graphPtr->tkwin, &axisPtr->limitsTextStyle); - for (link = Blt_Chain_FirstLink(axisPtr->tickLabels); link != NULL; - link = Blt_Chain_NextLink(link)) { - TickLabel *labelPtr; + gcMask = (GCForeground | GCLineWidth | GCCapStyle); + gcValues.foreground = axisPtr->tickColor->pixel; + gcValues.font = Tk_FontId(axisPtr->tickFont); + gcValues.line_width = LineWidth(axisPtr->lineWidth); + gcValues.cap_style = CapProjecting; - labelPtr = Blt_Chain_GetValue(link); - Blt_Ps_DrawText(ps, labelPtr->string, &ts, labelPtr->anchorPos.x, - labelPtr->anchorPos.y); - } + newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); + if (axisPtr->tickGC != NULL) { + Tk_FreeGC(graphPtr->display, axisPtr->tickGC); } - if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { - Blt_Ps_XSetLineAttributes(ps, axisPtr->tickColor, axisPtr->lineWidth, - (Blt_Dashes *)NULL, CapButt, JoinMiter); - Blt_Ps_Draw2DSegments(ps, axisPtr->segments, axisPtr->nSegments); + axisPtr->tickGC = newGC; + + /* Assuming settings from above GC */ + gcValues.foreground = axisPtr->activeFgColor->pixel; + newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); + if (axisPtr->activeTickGC != NULL) { + Tk_FreeGC(graphPtr->display, axisPtr->activeTickGC); } -} + axisPtr->activeTickGC = newGC; -static void MakeGridLine(Axis *axisPtr, double value, Segment2d *sp) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; + gcValues.background = gcValues.foreground = axisPtr->major.color->pixel; + gcValues.line_width = LineWidth(axisPtr->major.lineWidth); + gcMask = (GCForeground | GCBackground | GCLineWidth); + if (LineIsDashed(axisPtr->major.dashes)) { + gcValues.line_style = LineOnOffDash; + gcMask |= GCLineStyle; + } + newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); + if (LineIsDashed(axisPtr->major.dashes)) { + Blt_SetDashes(graphPtr->display, newGC, &axisPtr->major.dashes); + } + if (axisPtr->major.gc != NULL) { + Blt_FreePrivateGC(graphPtr->display, axisPtr->major.gc); + } + axisPtr->major.gc = newGC; - if (axisPtr->logScale) { - value = EXP10(value); + gcValues.background = gcValues.foreground = axisPtr->minor.color->pixel; + gcValues.line_width = LineWidth(axisPtr->minor.lineWidth); + gcMask = (GCForeground | GCBackground | GCLineWidth); + if (LineIsDashed(axisPtr->minor.dashes)) { + gcValues.line_style = LineOnOffDash; + gcMask |= GCLineStyle; } - /* Grid lines run orthogonally to the axis */ - if (AxisIsHorizontal(axisPtr)) { - sp->p.y = graphPtr->top; - sp->q.y = graphPtr->bottom; - sp->p.x = sp->q.x = Blt_HMap(axisPtr, value); - } else { - sp->p.x = graphPtr->left; - sp->q.x = graphPtr->right; - sp->p.y = sp->q.y = Blt_VMap(axisPtr, value); + newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); + if (LineIsDashed(axisPtr->minor.dashes)) { + Blt_SetDashes(graphPtr->display, newGC, &axisPtr->minor.dashes); + } + if (axisPtr->minor.gc != NULL) { + Blt_FreePrivateGC(graphPtr->display, axisPtr->minor.gc); } + axisPtr->minor.gc = newGC; } -static void MapGridlines(Axis *axisPtr) +static void FreeAxis(char* data) { - Segment2d *s1, *s2; - Ticks *t1Ptr, *t2Ptr; - int needed; - int i; + Axis *axisPtr = (Axis *)data; + DestroyAxis(axisPtr); +} - if (axisPtr == NULL) { - return; - } - t1Ptr = axisPtr->t1Ptr; - if (t1Ptr == NULL) { - t1Ptr = GenerateTicks(&axisPtr->majorSweep); +static float titleAngle[4] = /* Rotation for each axis title */ + { + 0.0, 90.0, 0.0, 270.0 + }; + +static void AxisOffsets(Axis *axisPtr, int margin, int offset, + AxisInfo *infoPtr) +{ + Graph* graphPtr = axisPtr->obj.graphPtr; + Margin *marginPtr; + int pad; /* Offset of axis from interior + * region. This includes a possible + * border and the axis line width. */ + int axisLine; + int t1, t2, labelOffset; + int tickLabel, axisPad; + int inset, mark; + int x, y; + float fangle; + + axisPtr->titleAngle = titleAngle[margin]; + marginPtr = graphPtr->margins + margin; + + tickLabel = axisLine = t1 = t2 = 0; + labelOffset = AXIS_PAD_TITLE; + if (axisPtr->lineWidth > 0) { + if (axisPtr->showTicks) { + t1 = axisPtr->tickLength; + t2 = (t1 * 10) / 15; + } + labelOffset = t1 + AXIS_PAD_TITLE; + if (axisPtr->exterior) + labelOffset += axisPtr->lineWidth; } - t2Ptr = axisPtr->t2Ptr; - if (t2Ptr == NULL) { - t2Ptr = GenerateTicks(&axisPtr->minorSweep); + axisPad = 0; + if (graphPtr->plotRelief != TK_RELIEF_SOLID) { + axisPad = 0; } - needed = t1Ptr->nTicks; - if (axisPtr->showGridMinor) - needed += (t1Ptr->nTicks * t2Ptr->nTicks); - - if (needed == 0) { - return; + /* Adjust offset for the interior border width and the line width */ + pad = 1; + if (graphPtr->plotBW > 0) { + pad += graphPtr->plotBW + 1; } - needed = t1Ptr->nTicks; - if (needed != axisPtr->major.nAllocated) { - if (axisPtr->major.segments != NULL) { - free(axisPtr->major.segments); - axisPtr->major.segments = NULL; + pad = 0; /* FIXME: test */ + /* + * Pre-calculate the x-coordinate positions of the axis, tick labels, and + * the individual major and minor ticks. + */ + inset = pad + axisPtr->lineWidth / 2; + switch (margin) { + case MARGIN_TOP: + axisLine = graphPtr->top; + if (axisPtr->exterior) { + axisLine -= graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; + tickLabel = axisLine - 2; + if (axisPtr->lineWidth > 0) { + tickLabel -= axisPtr->tickLength; + } + } else { + if (graphPtr->plotRelief == TK_RELIEF_SOLID) { + axisLine--; + } + axisLine -= axisPad + axisPtr->lineWidth / 2; + tickLabel = graphPtr->top - graphPtr->plotBW - 2; } - axisPtr->major.segments = malloc(sizeof(Segment2d) * needed); - axisPtr->major.nAllocated = needed; - } - needed = (t1Ptr->nTicks * t2Ptr->nTicks); - if (needed != axisPtr->minor.nAllocated) { - if (axisPtr->minor.segments != NULL) { - free(axisPtr->minor.segments); - axisPtr->minor.segments = NULL; + mark = graphPtr->top - offset - pad; + axisPtr->tickAnchor = TK_ANCHOR_S; + axisPtr->left = axisPtr->screenMin - inset - 2; + axisPtr->right = axisPtr->screenMin + axisPtr->screenRange + inset - 1; + if (graphPtr->stackAxes) { + axisPtr->top = mark - marginPtr->axesOffset; + } else { + axisPtr->top = mark - axisPtr->height; } - axisPtr->minor.segments = malloc(sizeof(Segment2d) * needed); - axisPtr->minor.nAllocated = needed; - } - s1 = axisPtr->major.segments, s2 = axisPtr->minor.segments; - for (i = 0; i < t1Ptr->nTicks; i++) { - double value; - - value = t1Ptr->values[i]; - if (axisPtr->showGridMinor) { - int j; + axisPtr->bottom = mark; + if (axisPtr->titleAlternate) { + x = graphPtr->right + AXIS_PAD_TITLE; + y = mark - (axisPtr->height / 2); + axisPtr->titleAnchor = TK_ANCHOR_W; + } else { + x = (axisPtr->right + axisPtr->left) / 2; + if (graphPtr->stackAxes) { + y = mark - marginPtr->axesOffset + AXIS_PAD_TITLE; + } else { + y = mark - axisPtr->height + AXIS_PAD_TITLE; + } + axisPtr->titleAnchor = TK_ANCHOR_N; + } + axisPtr->titlePos.x = x; + axisPtr->titlePos.y = y; + break; - for (j = 0; j < t2Ptr->nTicks; j++) { - double subValue; + case MARGIN_BOTTOM: + /* + * ----------- bottom + plot borderwidth + * mark -------------------------------------------- + * ===================== axisLine (linewidth) + * tick + * title + * + * ===================== axisLine (linewidth) + * ----------- bottom + plot borderwidth + * mark -------------------------------------------- + * tick + * title + */ + axisLine = graphPtr->bottom; + if (graphPtr->plotRelief == TK_RELIEF_SOLID) { + axisLine++; + } + if (axisPtr->exterior) { + axisLine += graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; + tickLabel = axisLine + 2; + if (axisPtr->lineWidth > 0) { + tickLabel += axisPtr->tickLength; + } + } else { + axisLine -= axisPad + axisPtr->lineWidth / 2; + tickLabel = graphPtr->bottom + graphPtr->plotBW + 2; + } + mark = graphPtr->bottom + offset; + fangle = fmod(axisPtr->tickAngle, 90.0); + if (fangle == 0.0) { + axisPtr->tickAnchor = TK_ANCHOR_N; + } else { + int quadrant; - subValue = value + (axisPtr->majorSweep.step * - t2Ptr->values[j]); - if (InRange(subValue, &axisPtr->axisRange)) { - MakeGridLine(axisPtr, subValue, s2); - s2++; - } + quadrant = (int)(axisPtr->tickAngle / 90.0); + if ((quadrant == 0) || (quadrant == 2)) { + axisPtr->tickAnchor = TK_ANCHOR_NE; + } else { + axisPtr->tickAnchor = TK_ANCHOR_NW; } } - if (InRange(value, &axisPtr->axisRange)) { - MakeGridLine(axisPtr, value, s1); - s1++; + axisPtr->left = axisPtr->screenMin - inset - 2; + axisPtr->right = axisPtr->screenMin + axisPtr->screenRange + inset - 1; + axisPtr->top = graphPtr->bottom + labelOffset - t1; + if (graphPtr->stackAxes) { + axisPtr->bottom = mark + marginPtr->axesOffset - 1; + } else { + axisPtr->bottom = mark + axisPtr->height - 1; } - } - if (t1Ptr != axisPtr->t1Ptr) { - free(t1Ptr); /* Free generated ticks. */ - } - if (t2Ptr != axisPtr->t2Ptr) { - free(t2Ptr); /* Free generated ticks. */ - } - axisPtr->major.nUsed = s1 - axisPtr->major.segments; - axisPtr->minor.nUsed = s2 - axisPtr->minor.segments; -} - -static void GetAxisGeometry(Graph* graphPtr, Axis *axisPtr) -{ - unsigned int y; - - FreeTickLabels(axisPtr->tickLabels); - y = 0; - - // Leave room for axis baseline and padding - if (axisPtr->exterior && (graphPtr->plotRelief != TK_RELIEF_SOLID)) - y += axisPtr->lineWidth + 2; - - axisPtr->maxTickHeight = axisPtr->maxTickWidth = 0; - if (axisPtr->showTicks) { - unsigned int pad; - unsigned int i, nLabels, nTicks; - - SweepTicks(axisPtr); - - nTicks = 0; - if (axisPtr->t1Ptr != NULL) { - nTicks = axisPtr->t1Ptr->nTicks; + if (axisPtr->titleAlternate) { + x = graphPtr->right + AXIS_PAD_TITLE; + y = mark + (axisPtr->height / 2); + axisPtr->titleAnchor = TK_ANCHOR_W; + } else { + x = (axisPtr->right + axisPtr->left) / 2; + if (graphPtr->stackAxes) { + y = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; + } else { + y = mark + axisPtr->height - AXIS_PAD_TITLE; + } + axisPtr->titleAnchor = TK_ANCHOR_S; } - assert(nTicks <= MAXTICKS); - - nLabels = 0; - for (i = 0; i < nTicks; i++) { - TickLabel *labelPtr; - double x, x2; - unsigned int lw, lh; /* Label width and height. */ + axisPtr->titlePos.x = x; + axisPtr->titlePos.y = y; + break; - x2 = x = axisPtr->t1Ptr->values[i]; - if (axisPtr->labelOffset) { - x2 += axisPtr->majorSweep.step * 0.5; + case MARGIN_LEFT: + /* + * mark + * | : + * | : + * | : + * | : + * | : + * axisLine + */ + /* + * Exterior axis + * + plotarea right + * |A|B|C|D|E|F|G|H + * |right + * A = plot pad + * B = plot border width + * C = axis pad + * D = axis line + * E = tick length + * F = tick label + * G = graph border width + * H = highlight thickness + */ + /* + * Interior axis + * + plotarea right + * |A|B|C|D|E|F|G|H + * |right + * A = plot pad + * B = tick length + * C = axis line width + * D = axis pad + * E = plot border width + * F = tick label + * G = graph border width + * H = highlight thickness + */ + axisLine = graphPtr->left; + if (axisPtr->exterior) { + axisLine -= graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; + tickLabel = axisLine - 2; + if (axisPtr->lineWidth > 0) { + tickLabel -= axisPtr->tickLength; } - if (!InRange(x2, &axisPtr->axisRange)) { - continue; + } else { + if (graphPtr->plotRelief == TK_RELIEF_SOLID) { + axisLine--; + } + axisLine += axisPad + axisPtr->lineWidth / 2; + tickLabel = graphPtr->left - graphPtr->plotBW - 2; + } + mark = graphPtr->left - offset; + axisPtr->tickAnchor = TK_ANCHOR_E; + if (graphPtr->stackAxes) { + axisPtr->left = mark - marginPtr->axesOffset; + } else { + axisPtr->left = mark - axisPtr->width; + } + axisPtr->right = mark - 3; + axisPtr->top = axisPtr->screenMin - inset - 2; + axisPtr->bottom = axisPtr->screenMin + axisPtr->screenRange + inset - 1; + if (axisPtr->titleAlternate) { + x = mark - (axisPtr->width / 2); + y = graphPtr->top - AXIS_PAD_TITLE; + axisPtr->titleAnchor = TK_ANCHOR_SW; + } else { + if (graphPtr->stackAxes) { + x = mark - marginPtr->axesOffset; + } else { + x = mark - axisPtr->width + AXIS_PAD_TITLE; } - labelPtr = MakeLabel(axisPtr, x); - Blt_Chain_Append(axisPtr->tickLabels, labelPtr); - nLabels++; - /* - * Get the dimensions of each tick label. Remember tick labels - * can be multi-lined and/or rotated. - */ - Blt_GetTextExtents(axisPtr->tickFont, 0, labelPtr->string, -1, - &lw, &lh); - labelPtr->width = lw; - labelPtr->height = lh; + y = (axisPtr->bottom + axisPtr->top) / 2; + axisPtr->titleAnchor = TK_ANCHOR_W; + } + axisPtr->titlePos.x = x; + axisPtr->titlePos.y = y; + break; - if (axisPtr->tickAngle != 0.0f) { - double rlw, rlh; /* Rotated label width and height. */ - Blt_GetBoundingBox(lw, lh, axisPtr->tickAngle, &rlw, &rlh,NULL); - lw = ROUND(rlw), lh = ROUND(rlh); - } - if (axisPtr->maxTickWidth < lw) { - axisPtr->maxTickWidth = lw; - } - if (axisPtr->maxTickHeight < lh) { - axisPtr->maxTickHeight = lh; - } - } - assert(nLabels <= nTicks); - - pad = 0; + case MARGIN_RIGHT: + axisLine = graphPtr->right; + if (graphPtr->plotRelief == TK_RELIEF_SOLID) { + axisLine++; /* Draw axis line within solid plot + * border. */ + } if (axisPtr->exterior) { - /* 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 * 12) / 8); + axisLine += graphPtr->plotBW + axisPad + axisPtr->lineWidth / 2; + tickLabel = axisLine + 2; + if (axisPtr->lineWidth > 0) { + tickLabel += axisPtr->tickLength; + } + } else { + axisLine -= axisPad + axisPtr->lineWidth / 2; + tickLabel = graphPtr->right + graphPtr->plotBW + 2; } - if (AxisIsHorizontal(axisPtr)) { - y += axisPtr->maxTickHeight + pad; + mark = graphPtr->right + offset + pad; + axisPtr->tickAnchor = TK_ANCHOR_W; + axisPtr->left = mark; + if (graphPtr->stackAxes) { + axisPtr->right = mark + marginPtr->axesOffset - 1; } else { - y += axisPtr->maxTickWidth + pad; - if (axisPtr->maxTickWidth > 0) { - y += 5; /* Pad either size of label. */ - } + axisPtr->right = mark + axisPtr->width - 1; } - y += 2 * AXIS_PAD_TITLE; - if ((axisPtr->lineWidth > 0) && axisPtr->exterior) { - /* Distance from axis line to tick label. */ - y += axisPtr->tickLength; + axisPtr->top = axisPtr->screenMin - inset - 2; + axisPtr->bottom = axisPtr->screenMin + axisPtr->screenRange + inset -1; + if (axisPtr->titleAlternate) { + x = mark + (axisPtr->width / 2); + y = graphPtr->top - AXIS_PAD_TITLE; + axisPtr->titleAnchor = TK_ANCHOR_SE; + } else { + if (graphPtr->stackAxes) { + x = mark + marginPtr->axesOffset - AXIS_PAD_TITLE; + } else { + x = mark + axisPtr->width - AXIS_PAD_TITLE; + } + y = (axisPtr->bottom + axisPtr->top) / 2; + axisPtr->titleAnchor = TK_ANCHOR_E; } + axisPtr->titlePos.x = x; + axisPtr->titlePos.y = y; + break; + + case MARGIN_NONE: + axisLine = 0; + break; + } + if ((margin == MARGIN_LEFT) || (margin == MARGIN_TOP)) { + t1 = -t1, t2 = -t2; + labelOffset = -labelOffset; + } + infoPtr->axis = axisLine; + infoPtr->t1 = axisLine + t1; + infoPtr->t2 = axisLine + t2; + if (tickLabel > 0) { + infoPtr->label = tickLabel; + } else { + infoPtr->label = axisLine + labelOffset; + } + if (!axisPtr->exterior) { + /*infoPtr->label = axisLine + labelOffset - t1; */ + infoPtr->t1 = axisLine - t1; + infoPtr->t2 = axisLine - t2; + } +} + +static void MakeAxisLine(Axis *axisPtr, int line, Segment2d *sp) +{ + double min, max; + + min = axisPtr->axisRange.min; + max = axisPtr->axisRange.max; + if (axisPtr->logScale) { + min = EXP10(min); + max = EXP10(max); } - - if (axisPtr->title != NULL) { - if (axisPtr->titleAlternate) { - if (y < axisPtr->titleHeight) { - y = axisPtr->titleHeight; - } - } else { - y += axisPtr->titleHeight + AXIS_PAD_TITLE; - } + if (AxisIsHorizontal(axisPtr)) { + sp->p.x = Blt_HMap(axisPtr, min); + sp->q.x = Blt_HMap(axisPtr, max); + sp->p.y = sp->q.y = line; + } else { + sp->q.x = sp->p.x = line; + sp->p.y = Blt_VMap(axisPtr, min); + sp->q.y = Blt_VMap(axisPtr, max); } +} + +static void MakeTick(Axis *axisPtr, double value, int tick, int line, + Segment2d *sp) +{ + if (axisPtr->logScale) + value = EXP10(value); - /* Correct for orientation of the axis. */ if (AxisIsHorizontal(axisPtr)) { - axisPtr->height = y; - } else { - axisPtr->width = y; + sp->p.x = sp->q.x = Blt_HMap(axisPtr, value); + sp->p.y = line; + sp->q.y = tick; + } + else { + sp->p.x = line; + sp->p.y = sp->q.y = Blt_VMap(axisPtr, value); + sp->q.x = tick; } } -static int GetMarginGeometry(Graph* graphPtr, Margin *marginPtr) +static void MakeSegments(Axis *axisPtr, AxisInfo *infoPtr) { - Blt_ChainLink link; - unsigned int l, w, h; /* Length, width, and height. */ - int isHoriz; - unsigned int nVisible; + int arraySize; + int nMajorTicks, nMinorTicks; + Segment2d *segments; + Segment2d *sp; - isHoriz = HORIZMARGIN(marginPtr); + if (axisPtr->segments) { + free(axisPtr->segments); + axisPtr->segments = NULL; + } + nMajorTicks = nMinorTicks = 0; + if (axisPtr->t1Ptr) + nMajorTicks = axisPtr->t1Ptr->nTicks; - /* Count the visible axes. */ - nVisible = 0; - l = w = h = 0; - marginPtr->maxTickWidth = marginPtr->maxTickHeight = 0; - if (graphPtr->stackAxes) { - for (link = Blt_Chain_FirstLink(marginPtr->axes); link != NULL; - link = Blt_Chain_NextLink(link)) { - Axis *axisPtr; - - axisPtr = Blt_Chain_GetValue(link); - if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { - nVisible++; - if (graphPtr->flags & GET_AXIS_GEOMETRY) { - GetAxisGeometry(graphPtr, axisPtr); - } - if (isHoriz) { - if (h < axisPtr->height) { - h = axisPtr->height; - } - } else { - if (w < axisPtr->width) { - w = axisPtr->width; - } - } - if (axisPtr->maxTickWidth > marginPtr->maxTickWidth) { - marginPtr->maxTickWidth = axisPtr->maxTickWidth; - } - if (axisPtr->maxTickHeight > marginPtr->maxTickHeight) { - marginPtr->maxTickHeight = axisPtr->maxTickHeight; + if (axisPtr->t2Ptr) + nMinorTicks = axisPtr->t2Ptr->nTicks; + + arraySize = 1 + (nMajorTicks * (nMinorTicks + 1)); + segments = malloc(arraySize * sizeof(Segment2d)); + sp = segments; + if (axisPtr->lineWidth > 0) { + /* Axis baseline */ + MakeAxisLine(axisPtr, infoPtr->axis, sp); + sp++; + } + if (axisPtr->showTicks) { + Blt_ChainLink link; + double labelPos; + int i; + int isHoriz; + + isHoriz = AxisIsHorizontal(axisPtr); + for (i = 0; i < nMajorTicks; i++) { + double t1, t2; + int j; + + t1 = axisPtr->t1Ptr->values[i]; + /* Minor ticks */ + for (j = 0; j < nMinorTicks; j++) { + t2 = t1 + (axisPtr->majorSweep.step * + axisPtr->t2Ptr->values[j]); + if (InRange(t2, &axisPtr->axisRange)) { + MakeTick(axisPtr, t2, infoPtr->t2, infoPtr->axis, sp); + sp++; } } - } - } else { - for (link = Blt_Chain_FirstLink(marginPtr->axes); link != NULL; - link = Blt_Chain_NextLink(link)) { - Axis *axisPtr; - - axisPtr = Blt_Chain_GetValue(link); - if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { - nVisible++; - if (graphPtr->flags & GET_AXIS_GEOMETRY) { - GetAxisGeometry(graphPtr, axisPtr); - } - if ((axisPtr->titleAlternate) && (l < axisPtr->titleWidth)) { - l = axisPtr->titleWidth; - } - if (isHoriz) { - h += axisPtr->height; - } else { - w += axisPtr->width; - } - if (axisPtr->maxTickWidth > marginPtr->maxTickWidth) { - marginPtr->maxTickWidth = axisPtr->maxTickWidth; - } - if (axisPtr->maxTickHeight > marginPtr->maxTickHeight) { - marginPtr->maxTickHeight = axisPtr->maxTickHeight; - } + if (!InRange(t1, &axisPtr->axisRange)) { + continue; } + /* Major tick */ + MakeTick(axisPtr, t1, infoPtr->t1, infoPtr->axis, sp); + sp++; } - } - /* Enforce a minimum size for margins. */ - if (w < 3) { - w = 3; - } - if (h < 3) { - h = 3; - } - marginPtr->nAxes = nVisible; - marginPtr->axesTitleLength = l; - marginPtr->width = w; - marginPtr->height = h; - marginPtr->axesOffset = (isHoriz) ? h : w; - return marginPtr->axesOffset; -} -/* - *--------------------------------------------------------------------------- - * - * Blt_LayoutGraph -- - * - * 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. - * - * if reqWidth > 0 : set outer size - * if reqPlotWidth > 0 : set plot size - *--------------------------------------------------------------------------- - */ + link = Blt_Chain_FirstLink(axisPtr->tickLabels); + labelPos = (double)infoPtr->label; -void Blt_LayoutGraph(Graph* graphPtr) -{ - unsigned int titleY; - unsigned int left, right, top, bottom; - unsigned int plotWidth, plotHeight; - unsigned int inset, inset2; - int width, height; - int pad; + for (i = 0; i < nMajorTicks; i++) { + double t1; + TickLabel *labelPtr; + Segment2d seg; - width = graphPtr->width; - height = graphPtr->height; + t1 = axisPtr->t1Ptr->values[i]; + if (axisPtr->labelOffset) { + t1 += axisPtr->majorSweep.step * 0.5; + } + if (!InRange(t1, &axisPtr->axisRange)) { + continue; + } + labelPtr = Blt_Chain_GetValue(link); + link = Blt_Chain_NextLink(link); + MakeTick(axisPtr, t1, infoPtr->t1, infoPtr->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; + } + } + } + axisPtr->segments = segments; + axisPtr->nSegments = sp - segments; + assert(axisPtr->nSegments <= arraySize); +} - /* - * Step 1: Compute the amount of space needed to display the axes - * associated with each margin. They can be overridden by - * -leftmargin, -rightmargin, -bottommargin, and -topmargin - * graph options, respectively. - */ - left = GetMarginGeometry(graphPtr, &graphPtr->leftMargin); - right = GetMarginGeometry(graphPtr, &graphPtr->rightMargin); - top = GetMarginGeometry(graphPtr, &graphPtr->topMargin); - bottom = GetMarginGeometry(graphPtr, &graphPtr->bottomMargin); +static void MapAxis(Axis *axisPtr, int offset, int margin) +{ + AxisInfo info; + Graph* graphPtr = axisPtr->obj.graphPtr; - pad = graphPtr->bottomMargin.maxTickWidth; - if (pad < graphPtr->topMargin.maxTickWidth) - pad = graphPtr->topMargin.maxTickWidth; + if (AxisIsHorizontal(axisPtr)) { + axisPtr->screenMin = graphPtr->hOffset; + axisPtr->width = graphPtr->right - graphPtr->left; + axisPtr->screenRange = graphPtr->hRange; + } else { + axisPtr->screenMin = graphPtr->vOffset; + axisPtr->height = graphPtr->bottom - graphPtr->top; + axisPtr->screenRange = graphPtr->vRange; + } + axisPtr->screenScale = 1.0 / axisPtr->screenRange; + AxisOffsets(axisPtr, margin, offset, &info); + MakeSegments(axisPtr, &info); +} - pad = pad / 2 + 3; - if (right < pad) - right = pad; +static void MapStackedAxis(Axis *axisPtr, int count, int margin) +{ + AxisInfo info; + Graph* graphPtr = axisPtr->obj.graphPtr; + unsigned int slice, w, h; - if (left < pad) - left = pad; + if ((graphPtr->margins[axisPtr->margin].axes->nLinks > 1) || + (axisPtr->reqNumMajorTicks <= 0)) { + axisPtr->reqNumMajorTicks = 4; + } + if (AxisIsHorizontal(axisPtr)) { + slice = graphPtr->hRange / graphPtr->margins[margin].axes->nLinks; + axisPtr->screenMin = graphPtr->hOffset; + axisPtr->width = slice; + } else { + slice = graphPtr->vRange / graphPtr->margins[margin].axes->nLinks; + axisPtr->screenMin = graphPtr->vOffset; + axisPtr->height = slice; + } +#define AXIS_PAD 2 + Blt_GetTextExtents(axisPtr->tickFont, 0, "0", 1, &w, &h); + axisPtr->screenMin += (slice * count) + AXIS_PAD + h / 2; + axisPtr->screenRange = slice - 2 * AXIS_PAD - h; + axisPtr->screenScale = 1.0f / axisPtr->screenRange; + AxisOffsets(axisPtr, margin, 0, &info); + MakeSegments(axisPtr, &info); +} - pad = graphPtr->leftMargin.maxTickHeight; - if (pad < graphPtr->rightMargin.maxTickHeight) - pad = graphPtr->rightMargin.maxTickHeight; +static double AdjustViewport(double offset, double 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; +} - pad = pad / 2; - if (top < pad) - top = pad; +static int GetAxisScrollInfo(Tcl_Interp* interp, int objc, Tcl_Obj* const objv[], + double *offsetPtr, double windowSize, + double scrollUnits, double scale) +{ + const char *string; + char c; + double offset; + int length; - if (bottom < pad) - bottom = pad; + offset = *offsetPtr; + string = Tcl_GetStringFromObj(objv[0], &length); + c = string[0]; + scrollUnits *= scale; + if ((c == 's') && (strncmp(string, "scroll", length) == 0)) { + int count; + double fract; - if (graphPtr->leftMargin.reqSize > 0) - left = graphPtr->leftMargin.reqSize; + assert(objc == 3); + /* Scroll number unit/page */ + if (Tcl_GetIntFromObj(interp, objv[1], &count) != TCL_OK) { + return TCL_ERROR; + } + string = Tcl_GetStringFromObj(objv[2], &length); + c = string[0]; + if ((c == 'u') && (strncmp(string, "units", length) == 0)) { + fract = count * scrollUnits; + } else if ((c == 'p') && (strncmp(string, "pages", length) == 0)) { + /* A page is 90% of the view-able window. */ + fract = (int)(count * windowSize * 0.9 + 0.5); + } else if ((c == 'p') && (strncmp(string, "pixels", length) == 0)) { + fract = count * scale; + } else { + Tcl_AppendResult(interp, "unknown \"scroll\" units \"", string, + "\"", NULL); + return TCL_ERROR; + } + offset += fract; + } else if ((c == 'm') && (strncmp(string, "moveto", length) == 0)) { + double fract; - if (graphPtr->rightMargin.reqSize > 0) - right = graphPtr->rightMargin.reqSize; + assert(objc == 2); + /* moveto fraction */ + if (Tcl_GetDoubleFromObj(interp, objv[1], &fract) != TCL_OK) { + return TCL_ERROR; + } + offset = fract; + } else { + int count; + double fract; - if (graphPtr->topMargin.reqSize > 0) - top = graphPtr->topMargin.reqSize; + /* Treat like "scroll units" */ + if (Tcl_GetIntFromObj(interp, objv[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; +} - if (graphPtr->bottomMargin.reqSize > 0) - bottom = graphPtr->bottomMargin.reqSize; +static void DrawAxis(Axis *axisPtr, Drawable drawable) +{ + Graph* graphPtr = axisPtr->obj.graphPtr; - /* - * Step 2: Add the graph title height to the top margin. - */ - if (graphPtr->title != NULL) { - top += graphPtr->titleHeight + 6; + if (axisPtr->normalBg != NULL) { + Tk_Fill3DRectangle(graphPtr->tkwin, drawable, + axisPtr->normalBg, + axisPtr->left, axisPtr->top, + axisPtr->right - axisPtr->left, + axisPtr->bottom - axisPtr->top, + axisPtr->borderWidth, + axisPtr->relief); } - inset = (graphPtr->inset + graphPtr->plotBW); - inset2 = 2 * inset; + if (axisPtr->title != NULL) { + TextStyle ts; - /* - * Step 3: Estimate the size of the plot area from the remaining - * space. This may be overridden by the -plotwidth and - * -plotheight graph options. We use this to compute the - * size of the legend. - */ - if (width == 0) { - width = 400; - } - if (height == 0) { - height = 400; - } - plotWidth = (graphPtr->reqPlotWidth > 0) ? graphPtr->reqPlotWidth : - width - (inset2 + left + right); /* Plot width. */ - plotHeight = (graphPtr->reqPlotHeight > 0) ? graphPtr->reqPlotHeight : - height - (inset2 + top + bottom); /* Plot height. */ - Blt_MapLegend(graphPtr, plotWidth, plotHeight); + Blt_Ts_InitStyle(ts); + Blt_Ts_SetAngle(ts, axisPtr->titleAngle); + Blt_Ts_SetFont(ts, axisPtr->titleFont); + Blt_Ts_SetPadding(ts, 1, 0); + Blt_Ts_SetAnchor(ts, axisPtr->titleAnchor); + Blt_Ts_SetJustify(ts, axisPtr->titleJustify); + if (axisPtr->flags & ACTIVE) + Blt_Ts_SetForeground(ts, axisPtr->activeFgColor); + else + Blt_Ts_SetForeground(ts, axisPtr->titleColor); - /* - * Step 2: Add the legend to the appropiate margin. - */ - if (!Blt_Legend_IsHidden(graphPtr)) { - switch (Blt_Legend_Site(graphPtr)) { - case LEGEND_RIGHT: - right += Blt_Legend_Width(graphPtr) + 2; - break; - case LEGEND_LEFT: - left += Blt_Legend_Width(graphPtr) + 2; - break; - case LEGEND_TOP: - top += Blt_Legend_Height(graphPtr) + 2; - break; - case LEGEND_BOTTOM: - bottom += Blt_Legend_Height(graphPtr) + 2; - break; - case LEGEND_XY: - case LEGEND_PLOT: - case LEGEND_WINDOW: - /* Do nothing. */ - break; - } + Blt_Ts_SetForeground(ts, axisPtr->titleColor); + if ((axisPtr->titleAngle == 90.0) || (axisPtr->titleAngle == 270.0)) + Blt_Ts_SetMaxLength(ts, axisPtr->height); + else + Blt_Ts_SetMaxLength(ts, axisPtr->width); + + Blt_Ts_DrawText(graphPtr->tkwin, drawable, axisPtr->title, -1, &ts, + (int)axisPtr->titlePos.x, (int)axisPtr->titlePos.y); } + if (axisPtr->scrollCmdObjPtr != NULL) { + double viewWidth, viewMin, viewMax; + double worldWidth, worldMin, worldMax; + double fract; + int isHoriz; - /* - * Recompute the plotarea or graph size, now accounting for the legend. - */ - if (graphPtr->reqPlotWidth == 0) { - plotWidth = width - (inset2 + left + right); - if (plotWidth < 1) { - plotWidth = 1; + worldMin = axisPtr->valueRange.min; + worldMax = axisPtr->valueRange.max; + if (!isnan(axisPtr->scrollMin)) { + worldMin = axisPtr->scrollMin; } - } - if (graphPtr->reqPlotHeight == 0) { - plotHeight = height - (inset2 + top + bottom); - if (plotHeight < 1) { - plotHeight = 1; + if (!isnan(axisPtr->scrollMax)) { + worldMax = axisPtr->scrollMax; } - } - - /* - * Step 5: If necessary, correct for the requested plot area aspect - * ratio. - */ - if ((graphPtr->reqPlotWidth == 0) && (graphPtr->reqPlotHeight == 0) && - (graphPtr->aspect > 0.0f)) { - float ratio; + 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(axisPtr); - /* - * Shrink one dimension of the plotarea to fit the requested - * width/height aspect ratio. - */ - ratio = (float)plotWidth / (float)plotHeight; - if (ratio > graphPtr->aspect) { - int scaledWidth; + if (isHoriz != axisPtr->descending) { + fract = (viewMin - worldMin) / worldWidth; + } else { + fract = (worldMax - viewMax) / worldWidth; + } + fract = AdjustViewport(fract, viewWidth / worldWidth); - /* Shrink the width. */ - scaledWidth = (int)(plotHeight * graphPtr->aspect); - if (scaledWidth < 1) { - scaledWidth = 1; + 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); } - /* Add the difference to the right margin. */ - /* CHECK THIS: w = scaledWidth; */ - right += (plotWidth - scaledWidth); + Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdObjPtr, + viewMin, viewMax, worldWidth); } else { - int scaledHeight; - - /* Shrink the height. */ - scaledHeight = (int)(plotWidth / graphPtr->aspect); - if (scaledHeight < 1) { - scaledHeight = 1; + 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); } - /* Add the difference to the top margin. */ - /* CHECK THIS: h = scaledHeight; */ - top += (plotHeight - scaledHeight); + Blt_UpdateScrollbar(graphPtr->interp, axisPtr->scrollCmdObjPtr, + viewMax, viewMin, worldWidth); } } + if (axisPtr->showTicks) { + Blt_ChainLink link; + TextStyle ts; - /* - * Step 6: If there's multiple axes in a margin, the axis titles will be - * displayed in the adjoining margins. Make sure there's room - * for the longest axis titles. - */ + Blt_Ts_InitStyle(ts); + Blt_Ts_SetAngle(ts, axisPtr->tickAngle); + Blt_Ts_SetFont(ts, axisPtr->tickFont); + Blt_Ts_SetPadding(ts, 2, 0); + Blt_Ts_SetAnchor(ts, axisPtr->tickAnchor); + if (axisPtr->flags & ACTIVE) + Blt_Ts_SetForeground(ts, axisPtr->activeFgColor); + else + Blt_Ts_SetForeground(ts, axisPtr->tickColor); - 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; - } + for (link = Blt_Chain_FirstLink(axisPtr->tickLabels); link != NULL; + link = Blt_Chain_NextLink(link)) { + TickLabel *labelPtr; - /* - * Step 7: Override calculated values with requested margin sizes. - */ - if (graphPtr->leftMargin.reqSize > 0) { - left = graphPtr->leftMargin.reqSize; - } - if (graphPtr->rightMargin.reqSize > 0) { - right = graphPtr->rightMargin.reqSize; - } - if (graphPtr->topMargin.reqSize > 0) { - top = graphPtr->topMargin.reqSize; - } - if (graphPtr->bottomMargin.reqSize > 0) { - bottom = graphPtr->bottomMargin.reqSize; + labelPtr = Blt_Chain_GetValue(link); + /* Draw major tick labels */ + Blt_DrawText(graphPtr->tkwin, drawable, labelPtr->string, &ts, + (int)labelPtr->anchorPos.x, (int)labelPtr->anchorPos.y); + } } - if (graphPtr->reqPlotWidth > 0) { - int w; - - /* - * Width of plotarea is constained. If there's extra space, add it to - * th left and/or right margins. If there's too little, grow the - * graph width to accomodate it. - */ - w = plotWidth + inset2 + left + right; - if (width > w) { /* Extra space in window. */ - int extra; + if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { + GC gc; - extra = (width - w) / 2; - if (graphPtr->leftMargin.reqSize == 0) { - left += extra; - if (graphPtr->rightMargin.reqSize == 0) { - right += extra; - } else { - left += extra; - } - } else if (graphPtr->rightMargin.reqSize == 0) { - right += extra + extra; - } - } else if (width < w) { - width = w; + if (axisPtr->flags & ACTIVE) { + gc = axisPtr->activeTickGC; + } else { + gc = axisPtr->tickGC; } - } - if (graphPtr->reqPlotHeight > 0) { /* Constrain the plotarea height. */ - int h; + /* Draw the tick marks and axis line. */ + Blt_Draw2DSegments(graphPtr->display, drawable, gc, axisPtr->segments, + axisPtr->nSegments); + } +} - /* - * Height of plotarea is constained. If there's extra space, - * add it to th top and/or bottom margins. If there's too little, - * grow the graph height to accomodate it. - */ - h = plotHeight + inset2 + top + bottom; - if (height > h) { /* Extra space in window. */ - int extra; +static void AxisToPostScript(Blt_Ps ps, Axis *axisPtr) +{ + Blt_Ps_Format(ps, "%% Axis \"%s\"\n", axisPtr->obj.name); + if (axisPtr->normalBg != NULL) { + Blt_Ps_Fill3DRectangle(ps, axisPtr->normalBg, + (double)axisPtr->left, (double)axisPtr->top, + axisPtr->right - axisPtr->left, + axisPtr->bottom - axisPtr->top, + axisPtr->borderWidth, axisPtr->relief); + } + if (axisPtr->title != NULL) { + TextStyle ts; - extra = (height - h) / 2; - if (graphPtr->topMargin.reqSize == 0) { - top += extra; - if (graphPtr->bottomMargin.reqSize == 0) { - bottom += extra; - } else { - top += extra; - } - } else if (graphPtr->bottomMargin.reqSize == 0) { - bottom += extra + extra; - } - } else if (height < h) { - height = h; - } - } - graphPtr->width = width; - graphPtr->height = height; - graphPtr->left = left + inset; - graphPtr->top = top + inset; - graphPtr->right = width - right - inset; - graphPtr->bottom = height - bottom - inset; + Blt_Ts_InitStyle(ts); + Blt_Ts_SetAngle(ts, axisPtr->titleAngle); + Blt_Ts_SetFont(ts, axisPtr->titleFont); + Blt_Ts_SetPadding(ts, 1, 0); + Blt_Ts_SetAnchor(ts, axisPtr->titleAnchor); + Blt_Ts_SetJustify(ts, axisPtr->titleJustify); + Blt_Ts_SetForeground(ts, axisPtr->titleColor); + Blt_Ps_DrawText(ps, axisPtr->title, &ts, axisPtr->titlePos.x, + axisPtr->titlePos.y); + } + if (axisPtr->showTicks) { + Blt_ChainLink link; + TextStyle ts; - graphPtr->leftMargin.width = left + graphPtr->inset; - graphPtr->rightMargin.width = right + graphPtr->inset; - graphPtr->topMargin.height = top + graphPtr->inset; - graphPtr->bottomMargin.height = bottom + graphPtr->inset; - - graphPtr->vOffset = graphPtr->top + graphPtr->yPad; - graphPtr->vRange = plotHeight - 2*graphPtr->yPad; - graphPtr->hOffset = graphPtr->left + graphPtr->xPad; - graphPtr->hRange = plotWidth - 2*graphPtr->xPad; + Blt_Ts_InitStyle(ts); + Blt_Ts_SetAngle(ts, axisPtr->tickAngle); + Blt_Ts_SetFont(ts, axisPtr->tickFont); + Blt_Ts_SetPadding(ts, 2, 0); + Blt_Ts_SetAnchor(ts, axisPtr->tickAnchor); + Blt_Ts_SetForeground(ts, axisPtr->tickColor); - if (graphPtr->vRange < 1) { - graphPtr->vRange = 1; + for (link = Blt_Chain_FirstLink(axisPtr->tickLabels); link != NULL; + link = Blt_Chain_NextLink(link)) { + TickLabel *labelPtr; + + labelPtr = Blt_Chain_GetValue(link); + Blt_Ps_DrawText(ps, labelPtr->string, &ts, labelPtr->anchorPos.x, + labelPtr->anchorPos.y); + } } - if (graphPtr->hRange < 1) { - graphPtr->hRange = 1; + if ((axisPtr->nSegments > 0) && (axisPtr->lineWidth > 0)) { + Blt_Ps_XSetLineAttributes(ps, axisPtr->tickColor, axisPtr->lineWidth, + (Blt_Dashes *)NULL, CapButt, JoinMiter); + Blt_Ps_Draw2DSegments(ps, axisPtr->segments, axisPtr->nSegments); } - graphPtr->hScale = 1.0f / (float)graphPtr->hRange; - graphPtr->vScale = 1.0f / (float)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->titleHeight; - graphPtr->titleY = 3 + graphPtr->inset; - graphPtr->titleX = (graphPtr->right + graphPtr->left) / 2; +static void MakeGridLine(Axis *axisPtr, double value, Segment2d *sp) +{ + Graph* graphPtr = axisPtr->obj.graphPtr; + if (axisPtr->logScale) { + value = EXP10(value); + } + /* Grid lines run orthogonally to the axis */ + if (AxisIsHorizontal(axisPtr)) { + sp->p.y = graphPtr->top; + sp->q.y = graphPtr->bottom; + sp->p.x = sp->q.x = Blt_HMap(axisPtr, value); + } else { + sp->p.x = graphPtr->left; + sp->q.x = graphPtr->right; + sp->p.y = sp->q.y = Blt_VMap(axisPtr, value); + } } -static int ConfigureAxis(Axis *axisPtr) +static void MapGridlines(Axis *axisPtr) { - Graph* graphPtr = axisPtr->obj.graphPtr; - float angle; + Segment2d *s1, *s2; + Ticks *t1Ptr, *t2Ptr; + int needed; + int i; - /* Check the requested axis limits. Can't allow -min to be greater than - * -max. Do this regardless of -checklimits option. We want to always - * detect when the user has zoomed in beyond the precision of the data.*/ - if (((!isnan(axisPtr->reqMin)) && (!isnan(axisPtr->reqMax))) && - (axisPtr->reqMin >= axisPtr->reqMax)) { - char msg[200]; - sprintf_s(msg, 200, - "impossible axis limits (-min %g >= -max %g) for \"%s\"", - axisPtr->reqMin, axisPtr->reqMax, axisPtr->obj.name); - Tcl_AppendResult(graphPtr->interp, msg, NULL); - return TCL_ERROR; + if (axisPtr == NULL) { + return; } - axisPtr->scrollMin = axisPtr->reqScrollMin; - axisPtr->scrollMax = axisPtr->reqScrollMax; - if (axisPtr->logScale) { - if (axisPtr->checkLimits) { - /* Check that the logscale limits are positive. */ - if ((!isnan(axisPtr->reqMin)) && (axisPtr->reqMin <= 0.0)) { - Tcl_AppendResult(graphPtr->interp,"bad logscale -min limit \"", - Blt_Dtoa(graphPtr->interp, axisPtr->reqMin), - "\" for axis \"", axisPtr->obj.name, "\"", - NULL); - return TCL_ERROR; - } - } - if ((!isnan(axisPtr->scrollMin)) && (axisPtr->scrollMin <= 0.0)) { - axisPtr->scrollMin = NAN; - } - if ((!isnan(axisPtr->scrollMax)) && (axisPtr->scrollMax <= 0.0)) { - axisPtr->scrollMax = NAN; + t1Ptr = axisPtr->t1Ptr; + if (t1Ptr == NULL) { + t1Ptr = GenerateTicks(&axisPtr->majorSweep); + } + t2Ptr = axisPtr->t2Ptr; + if (t2Ptr == NULL) { + t2Ptr = GenerateTicks(&axisPtr->minorSweep); + } + needed = t1Ptr->nTicks; + if (axisPtr->showGridMinor) + needed += (t1Ptr->nTicks * t2Ptr->nTicks); + + if (needed == 0) { + return; + } + needed = t1Ptr->nTicks; + if (needed != axisPtr->major.nAllocated) { + if (axisPtr->major.segments != NULL) { + free(axisPtr->major.segments); + axisPtr->major.segments = NULL; } + axisPtr->major.segments = malloc(sizeof(Segment2d) * needed); + axisPtr->major.nAllocated = needed; } - angle = fmod(axisPtr->tickAngle, 360.0); - if (angle < 0.0f) { - angle += 360.0f; + needed = (t1Ptr->nTicks * t2Ptr->nTicks); + if (needed != axisPtr->minor.nAllocated) { + if (axisPtr->minor.segments != NULL) { + free(axisPtr->minor.segments); + axisPtr->minor.segments = NULL; + } + axisPtr->minor.segments = malloc(sizeof(Segment2d) * needed); + axisPtr->minor.nAllocated = needed; } - axisPtr->tickAngle = angle; - ResetTextStyles(axisPtr); + s1 = axisPtr->major.segments, s2 = axisPtr->minor.segments; + for (i = 0; i < t1Ptr->nTicks; i++) { + double value; - axisPtr->titleWidth = axisPtr->titleHeight = 0; - if (axisPtr->title != NULL) { - unsigned int w, h; + value = t1Ptr->values[i]; + if (axisPtr->showGridMinor) { + int j; - Blt_GetTextExtents(axisPtr->titleFont, 0, axisPtr->title, -1, &w, &h); - axisPtr->titleWidth = (unsigned short int)w; - axisPtr->titleHeight = (unsigned short int)h; - } + for (j = 0; j < t2Ptr->nTicks; j++) { + double subValue; - /* - * 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; - graphPtr->flags |= MAP_WORLD | RESET_AXES | CACHE_DIRTY; - axisPtr->flags |= DIRTY; - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; + subValue = value + (axisPtr->majorSweep.step * + t2Ptr->values[j]); + if (InRange(subValue, &axisPtr->axisRange)) { + MakeGridLine(axisPtr, subValue, s2); + s2++; + } + } + } + if (InRange(value, &axisPtr->axisRange)) { + MakeGridLine(axisPtr, value, s1); + s1++; + } + } + if (t1Ptr != axisPtr->t1Ptr) { + free(t1Ptr); /* Free generated ticks. */ + } + if (t2Ptr != axisPtr->t2Ptr) { + free(t2Ptr); /* Free generated ticks. */ + } + axisPtr->major.nUsed = s1 - axisPtr->major.segments; + axisPtr->minor.nUsed = s2 - axisPtr->minor.segments; } -static Axis *NewAxis(Graph* graphPtr, const char *name, int margin) +static void GetAxisGeometry(Graph* graphPtr, Axis *axisPtr) { - Axis *axisPtr; - Tcl_HashEntry *hPtr; - int isNew; + unsigned int y; - if (name[0] == '-') { - Tcl_AppendResult(graphPtr->interp, "name of axis \"", name, - "\" can't start with a '-'", NULL); - return NULL; - } - hPtr = Tcl_CreateHashEntry(&graphPtr->axes.table, name, &isNew); - if (!isNew) { - axisPtr = Tcl_GetHashValue(hPtr); - if ((axisPtr->flags & DELETE_PENDING) == 0) { - Tcl_AppendResult(graphPtr->interp, "axis \"", name, - "\" already exists in \"", - Tk_PathName(graphPtr->tkwin), "\"", - NULL); - return NULL; + FreeTickLabels(axisPtr->tickLabels); + y = 0; + + // Leave room for axis baseline and padding + if (axisPtr->exterior && (graphPtr->plotRelief != TK_RELIEF_SOLID)) + y += axisPtr->lineWidth + 2; + + axisPtr->maxTickHeight = axisPtr->maxTickWidth = 0; + if (axisPtr->showTicks) { + unsigned int pad; + unsigned int i, nLabels, nTicks; + + SweepTicks(axisPtr); + + nTicks = 0; + if (axisPtr->t1Ptr != NULL) { + nTicks = axisPtr->t1Ptr->nTicks; } - axisPtr->flags &= ~DELETE_PENDING; - } - else { - axisPtr = calloc(1, sizeof(Axis)); - axisPtr->obj.name = Blt_Strdup(name); - axisPtr->hashPtr = hPtr; - Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); - axisPtr->obj.graphPtr = graphPtr; - axisPtr->looseMin = AXIS_TIGHT; - axisPtr->looseMax = AXIS_TIGHT; - axisPtr->reqNumMinorTicks = 2; - axisPtr->reqNumMajorTicks = 4 /*10*/; - axisPtr->margin = MARGIN_NONE; - axisPtr->tickLength = 8; - axisPtr->scrollUnits = 10; - axisPtr->reqMin = NAN; - axisPtr->reqMax = NAN; - axisPtr->reqScrollMin = NAN; - axisPtr->reqScrollMax = NAN; - axisPtr->flags = (AXIS_AUTO_MAJOR|AXIS_AUTO_MINOR); - axisPtr->exterior =1; - axisPtr->hide =0; - axisPtr->showTicks =1; - axisPtr->showGridMinor =1; - axisPtr->showGrid =1; - axisPtr->checkLimits =0; - - if ((graphPtr->classId == CID_ELEM_BAR) && - ((margin == MARGIN_TOP) || (margin == MARGIN_BOTTOM))) { - axisPtr->reqStep = 1.0; - axisPtr->reqNumMinorTicks = 0; - } - if ((margin == MARGIN_RIGHT) || (margin == MARGIN_TOP)) - axisPtr->hide = 1; + assert(nTicks <= MAXTICKS); + + nLabels = 0; + for (i = 0; i < nTicks; i++) { + TickLabel *labelPtr; + double x, x2; + unsigned int lw, lh; /* Label width and height. */ + + x2 = x = axisPtr->t1Ptr->values[i]; + if (axisPtr->labelOffset) { + x2 += axisPtr->majorSweep.step * 0.5; + } + if (!InRange(x2, &axisPtr->axisRange)) { + continue; + } + labelPtr = MakeLabel(axisPtr, x); + Blt_Chain_Append(axisPtr->tickLabels, labelPtr); + nLabels++; + /* + * Get the dimensions of each tick label. Remember tick labels + * can be multi-lined and/or rotated. + */ + Blt_GetTextExtents(axisPtr->tickFont, 0, labelPtr->string, -1, + &lw, &lh); + labelPtr->width = lw; + labelPtr->height = lh; - Blt_Ts_InitStyle(axisPtr->limitsTextStyle); - axisPtr->tickLabels = Blt_Chain_Create(); - axisPtr->lineWidth = 1; - Tcl_SetHashValue(hPtr, axisPtr); + if (axisPtr->tickAngle != 0.0f) { + double rlw, rlh; /* Rotated label width and height. */ + Blt_GetBoundingBox(lw, lh, axisPtr->tickAngle, &rlw, &rlh,NULL); + lw = ROUND(rlw), lh = ROUND(rlh); + } + if (axisPtr->maxTickWidth < lw) { + axisPtr->maxTickWidth = lw; + } + if (axisPtr->maxTickHeight < lh) { + axisPtr->maxTickHeight = lh; + } + } + assert(nLabels <= nTicks); + + pad = 0; + if (axisPtr->exterior) { + /* 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 * 12) / 8); + } + if (AxisIsHorizontal(axisPtr)) { + y += axisPtr->maxTickHeight + pad; + } else { + y += axisPtr->maxTickWidth + pad; + if (axisPtr->maxTickWidth > 0) { + y += 5; /* Pad either size of label. */ + } + } + y += 2 * AXIS_PAD_TITLE; + if ((axisPtr->lineWidth > 0) && axisPtr->exterior) { + /* Distance from axis line to tick label. */ + y += axisPtr->tickLength; + } } - return axisPtr; -} - -static int GetAxisFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, - Axis **axisPtrPtr) -{ - Tcl_HashEntry *hPtr; - const char *name; - - *axisPtrPtr = NULL; - name = Tcl_GetString(objPtr); - hPtr = Tcl_FindHashEntry(&graphPtr->axes.table, name); - if (hPtr != NULL) { - Axis *axisPtr; - axisPtr = Tcl_GetHashValue(hPtr); - if ((axisPtr->flags & DELETE_PENDING) == 0) { - *axisPtrPtr = axisPtr; - return TCL_OK; + if (axisPtr->title != NULL) { + if (axisPtr->titleAlternate) { + if (y < axisPtr->titleHeight) { + y = axisPtr->titleHeight; + } + } else { + y += axisPtr->titleHeight + AXIS_PAD_TITLE; } } - if (interp != NULL) { - Tcl_AppendResult(interp, "can't find axis \"", name, "\" in \"", - Tk_PathName(graphPtr->tkwin), "\"", NULL); + + /* Correct for orientation of the axis. */ + if (AxisIsHorizontal(axisPtr)) { + axisPtr->height = y; + } else { + axisPtr->width = y; } - return TCL_ERROR; } -static int GetAxisByClass(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, - ClassId classId, Axis **axisPtrPtr) +static int GetMarginGeometry(Graph* graphPtr, Margin *marginPtr) { - Axis *axisPtr; + Blt_ChainLink link; + unsigned int l, w, h; /* Length, width, and height. */ + int isHoriz; + unsigned int nVisible; - if (GetAxisFromObj(interp, graphPtr, objPtr, &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - if (classId != CID_NONE) { - if ((axisPtr->refCount == 0) || (axisPtr->obj.classId == CID_NONE)) { - /* Set the axis type on the first use of it. */ - Blt_GraphSetObjectClass(&axisPtr->obj, classId); - } else if (axisPtr->obj.classId != classId) { - if (interp != NULL) { - Tcl_AppendResult(interp, "axis \"", Tcl_GetString(objPtr), - "\" is already in use on an opposite ", - axisPtr->obj.className, "-axis", - NULL); + isHoriz = HORIZMARGIN(marginPtr); + + /* Count the visible axes. */ + nVisible = 0; + l = w = h = 0; + marginPtr->maxTickWidth = marginPtr->maxTickHeight = 0; + if (graphPtr->stackAxes) { + for (link = Blt_Chain_FirstLink(marginPtr->axes); link != NULL; + link = Blt_Chain_NextLink(link)) { + Axis *axisPtr; + + axisPtr = Blt_Chain_GetValue(link); + if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { + nVisible++; + if (graphPtr->flags & GET_AXIS_GEOMETRY) { + GetAxisGeometry(graphPtr, axisPtr); + } + if (isHoriz) { + if (h < axisPtr->height) { + h = axisPtr->height; + } + } else { + if (w < axisPtr->width) { + w = axisPtr->width; + } + } + if (axisPtr->maxTickWidth > marginPtr->maxTickWidth) { + marginPtr->maxTickWidth = axisPtr->maxTickWidth; + } + if (axisPtr->maxTickHeight > marginPtr->maxTickHeight) { + marginPtr->maxTickHeight = axisPtr->maxTickHeight; + } } - return TCL_ERROR; } - axisPtr->refCount++; - } - *axisPtrPtr = axisPtr; - return TCL_OK; -} - -void Blt_DestroyAxes(Graph* graphPtr) -{ - { - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - - for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { + } else { + for (link = Blt_Chain_FirstLink(marginPtr->axes); link != NULL; + link = Blt_Chain_NextLink(link)) { Axis *axisPtr; - axisPtr = Tcl_GetHashValue(hPtr); - axisPtr->hashPtr = NULL; - DestroyAxis(axisPtr); + axisPtr = Blt_Chain_GetValue(link); + if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { + nVisible++; + if (graphPtr->flags & GET_AXIS_GEOMETRY) { + GetAxisGeometry(graphPtr, axisPtr); + } + if ((axisPtr->titleAlternate) && (l < axisPtr->titleWidth)) { + l = axisPtr->titleWidth; + } + if (isHoriz) { + h += axisPtr->height; + } else { + w += axisPtr->width; + } + if (axisPtr->maxTickWidth > marginPtr->maxTickWidth) { + marginPtr->maxTickWidth = axisPtr->maxTickWidth; + } + if (axisPtr->maxTickHeight > marginPtr->maxTickHeight) { + marginPtr->maxTickHeight = axisPtr->maxTickHeight; + } + } } } - Tcl_DeleteHashTable(&graphPtr->axes.table); - { - int i; - - for (i = 0; i < 4; i++) { - Blt_Chain_Destroy(graphPtr->axisChain[i]); - } + /* Enforce a minimum size for margins. */ + if (w < 3) { + w = 3; } - Tcl_DeleteHashTable(&graphPtr->axes.tagTable); - Blt_Chain_Destroy(graphPtr->axes.displayList); -} - -void Blt_ConfigureAxes(Graph* graphPtr) -{ - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - - for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { - Axis *axisPtr; - - axisPtr = Tcl_GetHashValue(hPtr); - ConfigureAxis(axisPtr); + if (h < 3) { + h = 3; } + marginPtr->nAxes = nVisible; + marginPtr->axesTitleLength = l; + marginPtr->width = w; + marginPtr->height = h; + marginPtr->axesOffset = (isHoriz) ? h : w; + return marginPtr->axesOffset; } -int Blt_DefaultAxes(Graph* graphPtr) -{ - int i; - int flags; - - flags = Blt_GraphType(graphPtr); - for (i = 0; i < 4; i++) { - Blt_Chain chain; - Axis *axisPtr; - - chain = Blt_Chain_Create(); - graphPtr->axisChain[i] = chain; - - /* Create a default axis for each chain. */ - axisPtr = NewAxis(graphPtr, axisNames[i].name, i); - if (axisPtr == NULL) { - return TCL_ERROR; - } - axisPtr->refCount = 1; /* Default axes are assumed in use. */ - axisPtr->margin = i; - axisPtr->flags |= AXIS_USE; - Blt_GraphSetObjectClass(&axisPtr->obj, axisNames[i].classId); - /* - * Blt_ConfigureComponentFromObj 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_ConfigureComponentFromObj(graphPtr->interp, graphPtr->tkwin, - axisPtr->obj.name, "Axis", configSpecs, 0, (Tcl_Obj **)NULL, - (char*)axisPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - if (ConfigureAxis(axisPtr) != TCL_OK) { - return TCL_ERROR; - } - axisPtr->link = Blt_Chain_Append(chain, axisPtr); - axisPtr->chain = chain; - } - return TCL_OK; -} +/* + *--------------------------------------------------------------------------- + * + * Blt_LayoutGraph -- + * + * 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. + * + * if reqWidth > 0 : set outer size + * if reqPlotWidth > 0 : set plot size + *--------------------------------------------------------------------------- + */ -static int ActivateOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) +void Blt_LayoutGraph(Graph* graphPtr) { - Graph* graphPtr = axisPtr->obj.graphPtr; - const char *string; - - string = Tcl_GetString(objv[2]); - if (string[0] == 'a') { - axisPtr->flags |= ACTIVE; - } else { - axisPtr->flags &= ~ACTIVE; - } - if (!axisPtr->hide && (axisPtr->flags & AXIS_USE)) { - graphPtr->flags |= DRAW_MARGINS | CACHE_DIRTY; - Blt_EventuallyRedrawGraph(graphPtr); - } - return TCL_OK; -} + unsigned int titleY; + unsigned int left, right, top, bottom; + unsigned int plotWidth, plotHeight; + unsigned int inset, inset2; + int width, height; + int pad; -static int BindOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; + width = graphPtr->width; + height = graphPtr->height; - return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, - Blt_MakeAxisTag(graphPtr, axisPtr->obj.name), objc, objv); -} - -static int CgetOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; + /* + * Step 1: Compute the amount of space needed to display the axes + * associated with each margin. They can be overridden by + * -leftmargin, -rightmargin, -bottommargin, and -topmargin + * graph options, respectively. + */ + left = GetMarginGeometry(graphPtr, &graphPtr->leftMargin); + right = GetMarginGeometry(graphPtr, &graphPtr->rightMargin); + top = GetMarginGeometry(graphPtr, &graphPtr->topMargin); + bottom = GetMarginGeometry(graphPtr, &graphPtr->bottomMargin); - return Blt_ConfigureValueFromObj(interp, graphPtr->tkwin, configSpecs, - (char*)axisPtr, objv[0], Blt_GraphType(graphPtr)); -} + pad = graphPtr->bottomMargin.maxTickWidth; + if (pad < graphPtr->topMargin.maxTickWidth) + pad = graphPtr->topMargin.maxTickWidth; -static int ConfigureOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; - int flags; + pad = pad / 2 + 3; + if (right < pad) + right = pad; - flags = BLT_CONFIG_OBJV_ONLY | Blt_GraphType(graphPtr); - if (objc == 0) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, configSpecs, - (char*)axisPtr, (Tcl_Obj *)NULL, flags); - } else if (objc == 1) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, configSpecs, - (char*)axisPtr, objv[0], flags); - } - if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin, configSpecs, - objc, objv, (char*)axisPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - if (ConfigureAxis(axisPtr) != TCL_OK) { - return TCL_ERROR; - } - if (axisPtr->flags & AXIS_USE) { - if (!Blt_ConfigModified(configSpecs, "-*color", "-background", "-bg", - NULL)) { - graphPtr->flags |= CACHE_DIRTY; - } - Blt_EventuallyRedrawGraph(graphPtr); - } - return TCL_OK; -} + if (left < pad) + left = pad; -static int LimitsOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; - Tcl_Obj *listObjPtr; - double min, max; + pad = graphPtr->leftMargin.maxTickHeight; + if (pad < graphPtr->rightMargin.maxTickHeight) + pad = graphPtr->rightMargin.maxTickHeight; - 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; - } - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(min)); - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(max)); - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; -} + pad = pad / 2; + if (top < pad) + top = pad; -static int InvTransformOp(Tcl_Interp* interp, Axis *axisPtr, int objc, - Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; - double y; /* Real graph coordinate */ - int sy; /* Integer window coordinate*/ + if (bottom < pad) + bottom = pad; - if (graphPtr->flags & RESET_AXES) { - Blt_ResetAxes(graphPtr); - } - if (Tcl_GetIntFromObj(interp, objv[0], &sy) != 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(axisPtr)) { - y = Blt_InvHMap(axisPtr, (double)sy); - } else { - y = Blt_InvVMap(axisPtr, (double)sy); - } - Tcl_SetDoubleObj(Tcl_GetObjResult(interp), y); - return TCL_OK; -} + if (graphPtr->leftMargin.reqSize > 0) + left = graphPtr->leftMargin.reqSize; -static int MarginOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - const char *marginName; + if (graphPtr->rightMargin.reqSize > 0) + right = graphPtr->rightMargin.reqSize; - marginName = ""; - if (axisPtr->flags & AXIS_USE) { - marginName = axisNames[axisPtr->margin].name; - } - Tcl_SetStringObj(Tcl_GetObjResult(interp), marginName, -1); - return TCL_OK; -} + if (graphPtr->topMargin.reqSize > 0) + top = graphPtr->topMargin.reqSize; -static int TransformOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = axisPtr->obj.graphPtr; - double x; + if (graphPtr->bottomMargin.reqSize > 0) + bottom = graphPtr->bottomMargin.reqSize; - if (graphPtr->flags & RESET_AXES) { - Blt_ResetAxes(graphPtr); - } - if (Blt_ExprDoubleFromObj(interp, objv[0], &x) != TCL_OK) { - return TCL_ERROR; - } - if (AxisIsHorizontal(axisPtr)) { - x = Blt_HMap(axisPtr, x); - } else { - x = Blt_VMap(axisPtr, x); + /* + * Step 2: Add the graph title height to the top margin. + */ + if (graphPtr->title != NULL) { + top += graphPtr->titleHeight + 6; } - Tcl_SetIntObj(Tcl_GetObjResult(interp), (int)x); - return TCL_OK; -} - -static int TypeOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - const char *typeName; + inset = (graphPtr->inset + graphPtr->plotBW); + inset2 = 2 * inset; - typeName = ""; - if (axisPtr->flags & AXIS_USE) { - if (axisNames[axisPtr->margin].classId == CID_AXIS_X) { - typeName = "x"; - } else if (axisNames[axisPtr->margin].classId == CID_AXIS_Y) { - typeName = "y"; - } + /* + * Step 3: Estimate the size of the plot area from the remaining + * space. This may be overridden by the -plotwidth and + * -plotheight graph options. We use this to compute the + * size of the legend. + */ + if (width == 0) { + width = 400; } - Tcl_SetStringObj(Tcl_GetObjResult(interp), typeName, -1); - return TCL_OK; -} - -static int UseOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr = (Graph *)axisPtr; - Blt_Chain chain; - Blt_ChainLink link; - Tcl_Obj **axisObjv; - ClassId classId; - int axisObjc; - int i; - - chain = graphPtr->margins[lastMargin].axes; - if (objc == 0) { - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (link = Blt_Chain_FirstLink(chain); link != NULL; - link = Blt_Chain_NextLink(link)) { - Axis *axisPtr; + if (height == 0) { + height = 400; + } + plotWidth = (graphPtr->reqPlotWidth > 0) ? graphPtr->reqPlotWidth : + width - (inset2 + left + right); /* Plot width. */ + plotHeight = (graphPtr->reqPlotHeight > 0) ? graphPtr->reqPlotHeight : + height - (inset2 + top + bottom); /* Plot height. */ + Blt_MapLegend(graphPtr, plotWidth, plotHeight); - axisPtr = Blt_Chain_GetValue(link); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(axisPtr->obj.name, -1)); + /* + * Step 2: Add the legend to the appropiate margin. + */ + if (!Blt_Legend_IsHidden(graphPtr)) { + switch (Blt_Legend_Site(graphPtr)) { + case LEGEND_RIGHT: + right += Blt_Legend_Width(graphPtr) + 2; + break; + case LEGEND_LEFT: + left += Blt_Legend_Width(graphPtr) + 2; + break; + case LEGEND_TOP: + top += Blt_Legend_Height(graphPtr) + 2; + break; + case LEGEND_BOTTOM: + bottom += Blt_Legend_Height(graphPtr) + 2; + break; + case LEGEND_XY: + case LEGEND_PLOT: + case LEGEND_WINDOW: + /* Do nothing. */ + break; } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; - } - if ((lastMargin == MARGIN_BOTTOM) || (lastMargin == MARGIN_TOP)) { - classId = (graphPtr->inverted) ? CID_AXIS_Y : CID_AXIS_X; - } else { - classId = (graphPtr->inverted) ? CID_AXIS_X : CID_AXIS_Y; } - if (Tcl_ListObjGetElements(interp, objv[0], &axisObjc, &axisObjv) - != TCL_OK) { - return TCL_ERROR; - } - for (link = Blt_Chain_FirstLink(chain); link!= NULL; - link = Blt_Chain_NextLink(link)) { - Axis *axisPtr; - axisPtr = Blt_Chain_GetValue(link); - axisPtr->link = NULL; - axisPtr->flags &= ~AXIS_USE; - /* Clear the axis type if it's not currently used.*/ - if (axisPtr->refCount == 0) { - Blt_GraphSetObjectClass(&axisPtr->obj, CID_NONE); + /* + * Recompute the plotarea or graph size, now accounting for the legend. + */ + if (graphPtr->reqPlotWidth == 0) { + plotWidth = width - (inset2 + left + right); + if (plotWidth < 1) { + plotWidth = 1; } } - Blt_Chain_Reset(chain); - for (i = 0; i < axisObjc; i++) { - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, axisObjv[i], &axisPtr) != TCL_OK){ - return TCL_ERROR; - } - if (axisPtr->obj.classId == CID_NONE) { - Blt_GraphSetObjectClass(&axisPtr->obj, classId); - } else if (axisPtr->obj.classId != classId) { - Tcl_AppendResult(interp, "wrong type axis \"", - axisPtr->obj.name, "\": can't use ", - axisPtr->obj.className, " type axis.", NULL); - return TCL_ERROR; + if (graphPtr->reqPlotHeight == 0) { + plotHeight = height - (inset2 + top + bottom); + if (plotHeight < 1) { + plotHeight = 1; } - if (axisPtr->link != NULL) { - /* Move the axis from the old margin's "use" list to the new. */ - Blt_Chain_UnlinkLink(axisPtr->chain, axisPtr->link); - Blt_Chain_AppendLink(chain, axisPtr->link); + } + + /* + * Step 5: If necessary, correct for the requested plot area aspect + * ratio. + */ + if ((graphPtr->reqPlotWidth == 0) && (graphPtr->reqPlotHeight == 0) && + (graphPtr->aspect > 0.0f)) { + float ratio; + + /* + * Shrink one dimension of the plotarea to fit the requested + * width/height aspect ratio. + */ + ratio = (float)plotWidth / (float)plotHeight; + if (ratio > graphPtr->aspect) { + int scaledWidth; + + /* Shrink the width. */ + scaledWidth = (int)(plotHeight * graphPtr->aspect); + if (scaledWidth < 1) { + scaledWidth = 1; + } + /* Add the difference to the right margin. */ + /* CHECK THIS: w = scaledWidth; */ + right += (plotWidth - scaledWidth); } else { - axisPtr->link = Blt_Chain_Append(chain, axisPtr); + int scaledHeight; + + /* Shrink the height. */ + scaledHeight = (int)(plotWidth / graphPtr->aspect); + if (scaledHeight < 1) { + scaledHeight = 1; + } + /* Add the difference to the top margin. */ + /* CHECK THIS: h = scaledHeight; */ + top += (plotHeight - scaledHeight); } - axisPtr->chain = chain; - axisPtr->flags |= AXIS_USE; } - 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); - return TCL_OK; -} -static int ViewOp(Tcl_Interp* interp, Axis *axisPtr, int objc, Tcl_Obj *const *objv) -{ - Graph* graphPtr; - double axisOffset, axisScale; - double fract; - double viewMin, viewMax, worldMin, worldMax; - double viewWidth, worldWidth; + /* + * Step 6: If there's multiple axes in a margin, the axis titles will be + * displayed in the adjoining margins. Make sure there's room + * for the longest axis titles. + */ - graphPtr = axisPtr->obj.graphPtr; - worldMin = axisPtr->valueRange.min; - worldMax = axisPtr->valueRange.max; - /* Override data dimensions with user-selected limits. */ - if (!isnan(axisPtr->scrollMin)) { - worldMin = axisPtr->scrollMin; - } - if (!isnan(axisPtr->scrollMax)) { - worldMax = axisPtr->scrollMax; + if (top < graphPtr->leftMargin.axesTitleLength) { + top = graphPtr->leftMargin.axesTitleLength; } - viewMin = axisPtr->min; - viewMax = axisPtr->max; - /* Bound the view within scroll region. */ - if (viewMin < worldMin) { - viewMin = worldMin; - } - if (viewMax > worldMax) { - viewMax = worldMax; + if (right < graphPtr->bottomMargin.axesTitleLength) { + right = graphPtr->bottomMargin.axesTitleLength; } - if (axisPtr->logScale) { - worldMin = log10(worldMin); - worldMax = log10(worldMax); - viewMin = log10(viewMin); - viewMax = log10(viewMax); + if (top < graphPtr->rightMargin.axesTitleLength) { + top = graphPtr->rightMargin.axesTitleLength; } - 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(axisPtr) != axisPtr->descending) { - axisOffset = viewMin - worldMin; - axisScale = graphPtr->hScale; - } else { - axisOffset = worldMax - viewMax; - axisScale = graphPtr->vScale; + if (right < graphPtr->topMargin.axesTitleLength) { + right = graphPtr->topMargin.axesTitleLength; } - if (objc == 4) { - Tcl_Obj *listObjPtr; - double first, last; - first = Clamp(axisOffset / worldWidth); - last = Clamp((axisOffset + viewWidth) / worldWidth); - listObjPtr = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(first)); - Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(last)); - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; - } - fract = axisOffset / worldWidth; - if (GetAxisScrollInfo(interp, objc, objv, &fract, - viewWidth / worldWidth, axisPtr->scrollUnits, axisScale) != TCL_OK) { - return TCL_ERROR; - } - if (AxisIsHorizontal(axisPtr) != axisPtr->descending) { - axisPtr->reqMin = (fract * worldWidth) + worldMin; - axisPtr->reqMax = axisPtr->reqMin + viewWidth; - } else { - axisPtr->reqMax = worldMax - (fract * worldWidth); - axisPtr->reqMin = axisPtr->reqMax - viewWidth; + /* + * Step 7: Override calculated values with requested margin sizes. + */ + if (graphPtr->leftMargin.reqSize > 0) { + left = graphPtr->leftMargin.reqSize; } - if (axisPtr->logScale) { - axisPtr->reqMin = EXP10(axisPtr->reqMin); - axisPtr->reqMax = EXP10(axisPtr->reqMax); + if (graphPtr->rightMargin.reqSize > 0) { + right = graphPtr->rightMargin.reqSize; } - graphPtr->flags |= (GET_AXIS_GEOMETRY | LAYOUT_NEEDED | RESET_AXES); - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -static int AxisCreateOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; - int flags; - - axisPtr = NewAxis(graphPtr, Tcl_GetString(objv[3]), MARGIN_NONE); - if (axisPtr == NULL) { - return TCL_ERROR; + if (graphPtr->topMargin.reqSize > 0) { + top = graphPtr->topMargin.reqSize; } - flags = Blt_GraphType(graphPtr); - if ((Blt_ConfigureComponentFromObj(interp, graphPtr->tkwin, - axisPtr->obj.name, "Axis", configSpecs, objc - 4, objv + 4, - (char*)axisPtr, flags) != TCL_OK) || - (ConfigureAxis(axisPtr) != TCL_OK)) { - DestroyAxis(axisPtr); - return TCL_ERROR; + if (graphPtr->bottomMargin.reqSize > 0) { + bottom = graphPtr->bottomMargin.reqSize; } - Tcl_SetStringObj(Tcl_GetObjResult(interp), axisPtr->obj.name, -1); - return TCL_OK; -} - -static int AxisActivateOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; + if (graphPtr->reqPlotWidth > 0) { + int w; - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - return ActivateOp(interp, axisPtr, objc, objv); -} + /* + * Width of plotarea is constained. If there's extra space, add it to + * th left and/or right margins. If there's too little, grow the + * graph width to accomodate it. + */ + w = plotWidth + inset2 + left + right; + if (width > w) { /* Extra space in window. */ + int extra; -static int AxisBindOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - Tcl_Obj *listObjPtr; + extra = (width - w) / 2; + if (graphPtr->leftMargin.reqSize == 0) { + left += extra; + if (graphPtr->rightMargin.reqSize == 0) { + right += extra; + } else { + left += extra; + } + } else if (graphPtr->rightMargin.reqSize == 0) { + right += extra + extra; + } + } else if (width < w) { + width = w; + } + } + if (graphPtr->reqPlotHeight > 0) { /* Constrain the plotarea height. */ + int h; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.tagTable, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { - const char *tagName; - Tcl_Obj *objPtr; + /* + * Height of plotarea is constained. If there's extra space, + * add it to th top and/or bottom margins. If there's too little, + * grow the graph height to accomodate it. + */ + h = plotHeight + inset2 + top + bottom; + if (height > h) { /* Extra space in window. */ + int extra; - tagName = Tcl_GetHashKey(&graphPtr->axes.tagTable, hPtr); - objPtr = Tcl_NewStringObj(tagName, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + extra = (height - h) / 2; + if (graphPtr->topMargin.reqSize == 0) { + top += extra; + if (graphPtr->bottomMargin.reqSize == 0) { + bottom += extra; + } else { + top += extra; + } + } else if (graphPtr->bottomMargin.reqSize == 0) { + bottom += extra + extra; + } + } else if (height < h) { + height = h; } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; - } - return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, - Blt_MakeAxisTag(graphPtr, Tcl_GetString(objv[3])), objc - 4, objv + 4); -} + } + graphPtr->width = width; + graphPtr->height = height; + graphPtr->left = left + inset; + graphPtr->top = top + inset; + graphPtr->right = width - right - inset; + graphPtr->bottom = height - bottom - inset; -static int AxisCgetOp(Tcl_Interp* interp, Graph* graphPtr, int objc, Tcl_Obj *const *objv) -{ - Axis *axisPtr; + graphPtr->leftMargin.width = left + graphPtr->inset; + graphPtr->rightMargin.width = right + graphPtr->inset; + graphPtr->topMargin.height = top + graphPtr->inset; + graphPtr->bottomMargin.height = bottom + graphPtr->inset; + + graphPtr->vOffset = graphPtr->top + graphPtr->yPad; + graphPtr->vRange = plotHeight - 2*graphPtr->yPad; + graphPtr->hOffset = graphPtr->left + graphPtr->xPad; + graphPtr->hRange = plotWidth - 2*graphPtr->xPad; - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; + if (graphPtr->vRange < 1) { + graphPtr->vRange = 1; } - return CgetOp(interp, axisPtr, objc - 4, objv + 4); -} - -static int AxisConfigureOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Tcl_Obj *const *options; - int i; - int nNames, nOpts; - - /* Figure out where the option value pairs begin */ - objc -= 3; - objv += 3; - for (i = 0; i < objc; i++) { - Axis *axisPtr; - const char *string; - - string = Tcl_GetString(objv[i]); - if (string[0] == '-') { - break; - } - if (GetAxisFromObj(interp, graphPtr, objv[i], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } + if (graphPtr->hRange < 1) { + graphPtr->hRange = 1; } - nNames = i; /* Number of pen names specified */ - nOpts = objc - i; /* Number of options specified */ - options = objv + i; /* Start of options in objv */ + graphPtr->hScale = 1.0f / (float)graphPtr->hRange; + graphPtr->vScale = 1.0f / (float)graphPtr->vRange; - for (i = 0; i < nNames; i++) { - Axis *axisPtr; + /* + * Calculate the placement of the graph title so it is centered within the + * space provided for it in the top margin + */ + titleY = graphPtr->titleHeight; + graphPtr->titleY = 3 + graphPtr->inset; + graphPtr->titleX = (graphPtr->right + graphPtr->left) / 2; - if (GetAxisFromObj(interp, graphPtr, objv[i], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - if (ConfigureOp(interp, axisPtr, nOpts, options) != TCL_OK) { - break; - } - } - if (i < nNames) { - return TCL_ERROR; - } - return TCL_OK; } -static int AxisDeleteOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) +static int ConfigureAxis(Axis *axisPtr) { - int i; - - for (i = 3; i < objc; i++) { - Axis *axisPtr; + Graph* graphPtr = axisPtr->obj.graphPtr; + float angle; - if (GetAxisFromObj(interp, graphPtr, objv[i], &axisPtr) != TCL_OK) { - return TCL_ERROR; + /* Check the requested axis limits. Can't allow -min to be greater than + * -max. Do this regardless of -checklimits option. We want to always + * detect when the user has zoomed in beyond the precision of the data.*/ + if (((!isnan(axisPtr->reqMin)) && (!isnan(axisPtr->reqMax))) && + (axisPtr->reqMin >= axisPtr->reqMax)) { + char msg[200]; + sprintf_s(msg, 200, + "impossible axis limits (-min %g >= -max %g) for \"%s\"", + axisPtr->reqMin, axisPtr->reqMax, axisPtr->obj.name); + Tcl_AppendResult(graphPtr->interp, msg, NULL); + return TCL_ERROR; + } + axisPtr->scrollMin = axisPtr->reqScrollMin; + axisPtr->scrollMax = axisPtr->reqScrollMax; + if (axisPtr->logScale) { + if (axisPtr->checkLimits) { + /* Check that the logscale limits are positive. */ + if ((!isnan(axisPtr->reqMin)) && (axisPtr->reqMin <= 0.0)) { + Tcl_AppendResult(graphPtr->interp,"bad logscale -min limit \"", + Blt_Dtoa(graphPtr->interp, axisPtr->reqMin), + "\" for axis \"", axisPtr->obj.name, "\"", + NULL); + return TCL_ERROR; + } } - axisPtr->flags |= DELETE_PENDING; - if (axisPtr->refCount == 0) { - Tcl_EventuallyFree(axisPtr, FreeAxis); + if ((!isnan(axisPtr->scrollMin)) && (axisPtr->scrollMin <= 0.0)) { + axisPtr->scrollMin = NAN; + } + if ((!isnan(axisPtr->scrollMax)) && (axisPtr->scrollMax <= 0.0)) { + axisPtr->scrollMax = NAN; } } - return TCL_OK; -} - -static int AxisFocusOp(Tcl_Interp* interp, Graph* graphPtr, int objc, Tcl_Obj *const *objv) -{ - if (objc > 3) { - Axis *axisPtr; - const char *string; + angle = fmod(axisPtr->tickAngle, 360.0); + if (angle < 0.0f) { + angle += 360.0f; + } + axisPtr->tickAngle = angle; + ResetTextStyles(axisPtr); - axisPtr = NULL; - string = Tcl_GetString(objv[3]); - if ((string[0] != '\0') && - (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK)) { - return TCL_ERROR; - } - graphPtr->focusPtr = NULL; - if (axisPtr && !axisPtr->hide && (axisPtr->flags & AXIS_USE)) - graphPtr->focusPtr = axisPtr; + axisPtr->titleWidth = axisPtr->titleHeight = 0; + if (axisPtr->title != NULL) { + unsigned int w, h; - Blt_SetFocusItem(graphPtr->bindTable, graphPtr->focusPtr, NULL); - } - /* Return the name of the axis that has focus. */ - if (graphPtr->focusPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - graphPtr->focusPtr->obj.name, -1); + Blt_GetTextExtents(axisPtr->titleFont, 0, axisPtr->title, -1, &w, &h); + axisPtr->titleWidth = (unsigned short int)w; + axisPtr->titleHeight = (unsigned 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; + graphPtr->flags |= MAP_WORLD | RESET_AXES | CACHE_DIRTY; + axisPtr->flags |= DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } -static int AxisGetOp(Tcl_Interp* interp, Graph* graphPtr, int objc, Tcl_Obj *const *objv) +static int GetAxisFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, + Axis **axisPtrPtr) { - Axis *axisPtr; + Tcl_HashEntry *hPtr; + const char *name; - axisPtr = Blt_GetCurrentItem(graphPtr->bindTable); - /* Report only on axes. */ - if ((axisPtr != NULL) && - ((axisPtr->obj.classId == CID_AXIS_X) || - (axisPtr->obj.classId == CID_AXIS_Y) || - (axisPtr->obj.classId == CID_NONE))) { - char c; - char *string; + *axisPtrPtr = NULL; + name = Tcl_GetString(objPtr); + hPtr = Tcl_FindHashEntry(&graphPtr->axes.table, name); + if (hPtr != NULL) { + Axis *axisPtr; - string = Tcl_GetString(objv[3]); - c = string[0]; - if ((c == 'c') && (strcmp(string, "current") == 0)) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), axisPtr->obj.name,-1); - } else if ((c == 'd') && (strcmp(string, "detail") == 0)) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), axisPtr->detail, -1); + axisPtr = Tcl_GetHashValue(hPtr); + if ((axisPtr->flags & DELETE_PENDING) == 0) { + *axisPtrPtr = axisPtr; + return TCL_OK; } } - return TCL_OK; -} - -static int AxisInvTransformOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't find axis \"", name, "\" in \"", + Tk_PathName(graphPtr->tkwin), "\"", NULL); } - return InvTransformOp(interp, axisPtr, objc - 4, objv + 4); + return TCL_ERROR; } -static int AxisLimitsOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) +static int GetAxisByClass(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, + ClassId classId, Axis **axisPtrPtr) { Axis *axisPtr; - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { + if (GetAxisFromObj(interp, graphPtr, objPtr, &axisPtr) != TCL_OK) { return TCL_ERROR; } - return LimitsOp(interp, axisPtr, objc - 4, objv + 4); -} - -static int AxisMarginOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; + if (classId != CID_NONE) { + if ((axisPtr->refCount == 0) || (axisPtr->obj.classId == CID_NONE)) { + /* Set the axis type on the first use of it. */ + Blt_GraphSetObjectClass(&axisPtr->obj, classId); + } else if (axisPtr->obj.classId != classId) { + if (interp != NULL) { + Tcl_AppendResult(interp, "axis \"", Tcl_GetString(objPtr), + "\" is already in use on an opposite ", + axisPtr->obj.className, "-axis", + NULL); + } + return TCL_ERROR; + } + axisPtr->refCount++; } - return MarginOp(interp, axisPtr, objc - 4, objv + 4); + *axisPtrPtr = axisPtr; + return TCL_OK; } -static int AxisNamesOp(Tcl_Interp* interp, Graph* graphPtr, int objc, Tcl_Obj *const *objv) +void Blt_DestroyAxes(Graph* graphPtr) { - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch cursor; - - for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { - Axis *axisPtr; - - axisPtr = Tcl_GetHashValue(hPtr); - if (axisPtr->flags & DELETE_PENDING) { - continue; - } - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(axisPtr->obj.name, -1)); - } - } else { + { Tcl_HashEntry *hPtr; Tcl_HashSearch cursor; for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { Axis *axisPtr; - int i; - + axisPtr = Tcl_GetHashValue(hPtr); - for (i = 3; i < objc; i++) { - const char *pattern; - - pattern = Tcl_GetString(objv[i]); - if (Tcl_StringMatch(axisPtr->obj.name, pattern)) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(axisPtr->obj.name, -1)); - break; - } - } + axisPtr->hashPtr = NULL; + DestroyAxis(axisPtr); } } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; -} - -static int AxisTransformOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - return TransformOp(interp, axisPtr, objc - 4, objv + 4); -} - -static int AxisTypeOp(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv) -{ - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - return TypeOp(interp, axisPtr, objc - 4, objv + 4); -} - -static int -AxisViewOp(Tcl_Interp* interp, Graph* graphPtr, int objc, Tcl_Obj *const *objv) -{ - Axis *axisPtr; - - if (GetAxisFromObj(interp, graphPtr, objv[3], &axisPtr) != TCL_OK) { - return TCL_ERROR; - } - return ViewOp(interp, axisPtr, objc - 4, objv + 4); -} - -static Blt_OpSpec virtAxisOps[] = { - {"activate", 1, AxisActivateOp, 4, 4, "axisName"}, - {"bind", 1, AxisBindOp, 3, 6, "axisName sequence command"}, - {"cget", 2, AxisCgetOp, 5, 5, "axisName option"}, - {"configure", 2, AxisConfigureOp, 4, 0, "axisName ?axisName?... " - "?option value?..."}, - {"create", 2, AxisCreateOp, 4, 0, "axisName ?option value?..."}, - {"deactivate", 3, AxisActivateOp, 4, 4, "axisName"}, - {"delete", 3, AxisDeleteOp, 3, 0, "?axisName?..."}, - {"focus", 1, AxisFocusOp, 3, 4, "?axisName?"}, - {"get", 1, AxisGetOp, 4, 4, "name"}, - {"invtransform", 1, AxisInvTransformOp, 5, 5, "axisName value"}, - {"limits", 1, AxisLimitsOp, 4, 4, "axisName"}, - {"margin", 1, AxisMarginOp, 4, 4, "axisName"}, - {"names", 1, AxisNamesOp, 3, 0, "?pattern?..."}, - {"transform", 2, AxisTransformOp, 5, 5, "axisName value"}, - {"type", 2, AxisTypeOp, 4, 4, "axisName"}, - {"view", 1, AxisViewOp, 4, 7, "axisName ?moveto fract? " - "?scroll number what?"}, -}; -static int nVirtAxisOps = sizeof(virtAxisOps) / sizeof(Blt_OpSpec); - -int -Blt_VirtualAxisOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) -{ - GraphVirtualAxisProc *proc; - int result; - - proc = Blt_GetOpFromObj(interp, nVirtAxisOps, virtAxisOps, BLT_OP_ARG2, - objc, objv, 0); - if (proc == NULL) { - return TCL_ERROR; - } - result = (*proc) (interp, graphPtr, objc, objv); - return result; -} - -static Blt_OpSpec axisOps[] = { - {"activate", 1, ActivateOp, 3, 3, "",}, - {"bind", 1, BindOp, 2, 5, "sequence command",}, - {"cget", 2, CgetOp, 4, 4, "option",}, - {"configure", 2, ConfigureOp, 3, 0, "?option value?...",}, - {"deactivate", 1, ActivateOp, 3, 3, "",}, - {"invtransform", 1, InvTransformOp, 4, 4, "value",}, - {"limits", 1, LimitsOp, 3, 3, "",}, - {"transform", 1, TransformOp, 4, 4, "value",}, - {"use", 1, UseOp, 3, 4, "?axisName?",}, - {"view", 1, ViewOp, 3, 6, "?moveto fract? ",}, -}; - -static int nAxisOps = sizeof(axisOps) / sizeof(Blt_OpSpec); + Tcl_DeleteHashTable(&graphPtr->axes.table); + { + int i; + + for (i = 0; i < 4; i++) { + Blt_Chain_Destroy(graphPtr->axisChain[i]); + } + } + Tcl_DeleteHashTable(&graphPtr->axes.tagTable); + Blt_Chain_Destroy(graphPtr->axes.displayList); +} -int -Blt_AxisOp(Tcl_Interp* interp, Graph* graphPtr, int margin, int objc, - Tcl_Obj *const *objv) +void Blt_ConfigureAxes(Graph* graphPtr) { - int result; - GraphAxisProc *proc; - - proc = Blt_GetOpFromObj(interp, nAxisOps, axisOps, BLT_OP_ARG2, - objc, objv, 0); - if (proc == NULL) { - return TCL_ERROR; - } - if (proc == UseOp) { - lastMargin = margin; /* Set global variable to the margin - * in the argument list. Needed only - * for UseOp. */ - result = (*proc)(interp, (Axis *)graphPtr, objc - 3, objv + 3); - } else { + Tcl_HashEntry *hPtr; + Tcl_HashSearch cursor; + + for (hPtr = Tcl_FirstHashEntry(&graphPtr->axes.table, &cursor); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&cursor)) { Axis *axisPtr; - - axisPtr = Blt_GetFirstAxis(graphPtr->margins[margin].axes); - if (axisPtr == NULL) { - return TCL_OK; - } - result = (*proc)(interp, axisPtr, objc - 3, objv + 3); + + axisPtr = Tcl_GetHashValue(hPtr); + ConfigureAxis(axisPtr); } - return result; } void @@ -4609,3 +4345,235 @@ static void TimeScaleAxis(Axis *axisPtr, double min, double max) } +static Blt_OptionParseProc ObjToLimitProc; +static Blt_OptionPrintProc LimitToObjProc; +static Blt_CustomOption limitOption = { + ObjToLimitProc, LimitToObjProc, NULL, (ClientData)0 +}; + +static Blt_OptionFreeProc FreeTicksProc; +static Blt_OptionParseProc ObjToTicksProc; +static Blt_OptionPrintProc TicksToObjProc; +static Blt_CustomOption majorTicksOption = { + ObjToTicksProc, TicksToObjProc, FreeTicksProc, (ClientData)AXIS_AUTO_MAJOR, +}; +static Blt_CustomOption minorTicksOption = { + ObjToTicksProc, TicksToObjProc, FreeTicksProc, (ClientData)AXIS_AUTO_MINOR, +}; +static Blt_OptionFreeProc FreeAxisProc; +static Blt_OptionPrintProc AxisToObjProc; +static Blt_OptionParseProc ObjToAxisProc; +Blt_CustomOption bltXAxisOption = { + ObjToAxisProc, AxisToObjProc, FreeAxisProc, (ClientData)CID_AXIS_X +}; +Blt_CustomOption bltYAxisOption = { + ObjToAxisProc, AxisToObjProc, FreeAxisProc, (ClientData)CID_AXIS_Y +}; + +static Blt_OptionFreeProc FreeFormatProc; +static Blt_OptionParseProc ObjToFormatProc; +static Blt_OptionPrintProc FormatToObjProc; +static Blt_CustomOption formatOption = { + ObjToFormatProc, FormatToObjProc, FreeFormatProc, (ClientData)0, +}; +static Blt_OptionParseProc ObjToLooseProc; +static Blt_OptionPrintProc LooseToObjProc; +static Blt_CustomOption looseOption = { + ObjToLooseProc, LooseToObjProc, NULL, (ClientData)0, +}; + +static Blt_OptionParseProc ObjToUseProc; +static Blt_OptionPrintProc UseToObjProc; +static Blt_CustomOption useOption = { + ObjToUseProc, UseToObjProc, NULL, (ClientData)0 +}; + +Blt_CustomOption bitmaskGrAxisCheckLimitsOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_CHECK_LIMITS + }; + +Blt_CustomOption bitmaskGrAxisExteriorOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_EXTERIOR + }; + +Blt_CustomOption bitmaskGrAxisGridOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_GRID + }; + +Blt_CustomOption bitmaskGrAxisGridMinorOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_GRID_MINOR + }; + +Blt_CustomOption bitmaskGrAxisHideOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)HIDE + }; + +Blt_CustomOption bitmaskGrAxisShowTicksOption = + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)AXIS_SHOWTICKS + }; + +static Blt_ConfigSpec configSpecs[] = { + {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", + "ActiveForeground", STD_ACTIVE_FOREGROUND, + Tk_Offset(Axis, activeFgColor), ALL_GRAPHS}, + {BLT_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", + "flat", Tk_Offset(Axis, activeRelief), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_DOUBLE, "-autorange", "autoRange", "AutoRange", + "0.0", Tk_Offset(Axis, windowSize), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_BORDER, "-background", "background", "Background", + NULL, Tk_Offset(Axis, normalBg), + ALL_GRAPHS | BLT_CONFIG_NULL_OK}, + {BLT_CONFIG_SYNONYM, "-bg", "background", NULL, NULL, 0, 0}, + {BLT_CONFIG_CUSTOM, "-bindtags", "bindTags", "BindTags", "all", + Tk_Offset(Axis, obj.tags), ALL_GRAPHS | BLT_CONFIG_NULL_OK, + &listOption}, + {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", NULL, NULL, + 0, ALL_GRAPHS}, + {BLT_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + "0", Tk_Offset(Axis, borderWidth), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-checklimits", "checkLimits", "CheckLimits", + "0", Tk_Offset(Axis, flags), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, + &bitmaskGrAxisCheckLimitsOption}, + {BLT_CONFIG_COLOR, "-color", "color", "Color", + STD_NORMAL_FOREGROUND, Tk_Offset(Axis, tickColor), ALL_GRAPHS}, + {BLT_CONFIG_STRING, "-command", "command", "Command", + NULL, Tk_Offset(Axis, formatCmd), + BLT_CONFIG_NULL_OK | ALL_GRAPHS}, + {BLT_CONFIG_BOOLEAN, "-descending", "descending", "Descending", + "0", Tk_Offset(Axis, descending), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-exterior", "exterior", "exterior", "1", + Tk_Offset(Axis, flags), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, + &bitmaskGrAxisExteriorOption}, + {BLT_CONFIG_SYNONYM, "-fg", "color", NULL, + NULL, 0, ALL_GRAPHS}, + {BLT_CONFIG_SYNONYM, "-foreground", "color", NULL, + NULL, 0, ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-grid", "grid", "Grid", "1", + Tk_Offset(Axis, flags), BARCHART, + &bitmaskGrAxisGridOption}, + {BLT_CONFIG_CUSTOM, "-grid", "grid", "Grid", "1", + Tk_Offset(Axis, flags), GRAPH | STRIPCHART, + &bitmaskGrAxisGridOption}, + {BLT_CONFIG_COLOR, "-gridcolor", "gridColor", "GridColor", + "gray64", Tk_Offset(Axis, major.color), ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-griddashes", "gridDashes", "GridDashes", + "dot", Tk_Offset(Axis, major.dashes), + BLT_CONFIG_NULL_OK | ALL_GRAPHS, &dashesOption}, + {BLT_CONFIG_PIXELS, "-gridlinewidth", "gridLineWidth", + "GridLineWidth", "0", + Tk_Offset(Axis, major.lineWidth), + BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-gridminor", "gridMinor", "GridMinor", + "1", Tk_Offset(Axis, flags), + BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS, + &bitmaskGrAxisGridMinorOption}, + {BLT_CONFIG_COLOR, "-gridminorcolor", "gridMinorColor", "GridColor", + "gray64", Tk_Offset(Axis, minor.color), ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-gridminordashes", "gridMinorDashes", "GridDashes", + "dot", Tk_Offset(Axis, minor.dashes), + BLT_CONFIG_NULL_OK | ALL_GRAPHS, &dashesOption}, + {BLT_CONFIG_PIXELS, "-gridminorlinewidth", "gridMinorLineWidth", + "GridLineWidth", "0", + Tk_Offset(Axis, minor.lineWidth), + BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-hide", "hide", "Hide", "0", + Tk_Offset(Axis, flags), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, + &bitmaskGrAxisHideOption}, + {BLT_CONFIG_JUSTIFY, "-justify", "justify", "Justify", + "c", Tk_Offset(Axis, titleJustify), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_BOOLEAN, "-labeloffset", "labelOffset", "LabelOffset", + "no", Tk_Offset(Axis, labelOffset), ALL_GRAPHS}, + {BLT_CONFIG_COLOR, "-limitscolor", "limitsColor", "Color", + STD_NORMAL_FOREGROUND, Tk_Offset(Axis, limitsTextStyle.color), + ALL_GRAPHS}, + {BLT_CONFIG_FONT, "-limitsfont", "limitsFont", "Font", STD_FONT_SMALL, + Tk_Offset(Axis, limitsTextStyle.font), ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-limitsformat", "limitsFormat", "LimitsFormat", + NULL, Tk_Offset(Axis, limitsFormats), + BLT_CONFIG_NULL_OK | ALL_GRAPHS, &formatOption}, + {BLT_CONFIG_PIXELS, "-linewidth", "lineWidth", "LineWidth", + "1", Tk_Offset(Axis, lineWidth), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_BOOLEAN, "-logscale", "logScale", "LogScale", + "0", Tk_Offset(Axis, logScale), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-loose", "loose", "Loose", "0", 0, + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, &looseOption}, + {BLT_CONFIG_CUSTOM, "-majorticks", "majorTicks", "MajorTicks", + NULL, Tk_Offset(Axis, t1Ptr), + BLT_CONFIG_NULL_OK | ALL_GRAPHS, &majorTicksOption}, + {BLT_CONFIG_CUSTOM, "-max", "max", "Max", NULL, + Tk_Offset(Axis, reqMax), ALL_GRAPHS, &limitOption}, + {BLT_CONFIG_CUSTOM, "-min", "min", "Min", NULL, + Tk_Offset(Axis, reqMin), ALL_GRAPHS, &limitOption}, + {BLT_CONFIG_CUSTOM, "-minorticks", "minorTicks", "MinorTicks", + NULL, Tk_Offset(Axis, t2Ptr), + BLT_CONFIG_NULL_OK | ALL_GRAPHS, &minorTicksOption}, + {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", + "flat", Tk_Offset(Axis, relief), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_DOUBLE, "-rotate", "rotate", "Rotate", "0", + Tk_Offset(Axis, tickAngle), ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-scrollcommand", "scrollCommand", "ScrollCommand", + NULL, Tk_Offset(Axis, scrollCmdObjPtr), + ALL_GRAPHS | BLT_CONFIG_NULL_OK, + &objectOption}, + {BLT_CONFIG_PIXELS, "-scrollincrement", "scrollIncrement", + "ScrollIncrement", "10", + Tk_Offset(Axis, scrollUnits), ALL_GRAPHS|BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-scrollmax", "scrollMax", "ScrollMax", NULL, + Tk_Offset(Axis, reqScrollMax), ALL_GRAPHS, &limitOption}, + {BLT_CONFIG_CUSTOM, "-scrollmin", "scrollMin", "ScrollMin", NULL, + Tk_Offset(Axis, reqScrollMin), ALL_GRAPHS, &limitOption}, + {BLT_CONFIG_DOUBLE, "-shiftby", "shiftBy", "ShiftBy", + "0.0", Tk_Offset(Axis, shiftBy), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_CUSTOM, "-showticks", "showTicks", "ShowTicks", + "1", Tk_Offset(Axis, flags), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT, + &bitmaskGrAxisShowTicksOption}, + {BLT_CONFIG_DOUBLE, "-stepsize", "stepSize", "StepSize", + "0.0", Tk_Offset(Axis, reqStep), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_INT, "-subdivisions", "subdivisions", "Subdivisions", + "2", Tk_Offset(Axis, reqNumMinorTicks), ALL_GRAPHS}, + {BLT_CONFIG_ANCHOR, "-tickanchor", "tickAnchor", "Anchor", + "c", Tk_Offset(Axis, reqTickAnchor), ALL_GRAPHS}, + {BLT_CONFIG_FONT, "-tickfont", "tickFont", "Font", + STD_FONT_SMALL, Tk_Offset(Axis, tickFont), + GRAPH | STRIPCHART}, + {BLT_CONFIG_FONT, "-tickfont", "tickFont", "Font", + STD_FONT_SMALL, Tk_Offset(Axis, tickFont), BARCHART}, + {BLT_CONFIG_PIXELS, "-ticklength", "tickLength", "TickLength", + "4", Tk_Offset(Axis, tickLength), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_INT, "-tickdefault", "tickDefault", "TickDefault", + "10", Tk_Offset(Axis, reqNumMajorTicks), + ALL_GRAPHS | BLT_CONFIG_DONT_SET_DEFAULT}, + {BLT_CONFIG_STRING, "-title", "title", "Title", + NULL, Tk_Offset(Axis, title), + BLT_CONFIG_DONT_SET_DEFAULT | BLT_CONFIG_NULL_OK | ALL_GRAPHS}, + {BLT_CONFIG_BOOLEAN, "-titlealternate", "titleAlternate", "TitleAlternate", + "0", Tk_Offset(Axis, titleAlternate), + BLT_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS}, + {BLT_CONFIG_COLOR, "-titlecolor", "titleColor", "Color", + STD_NORMAL_FOREGROUND, Tk_Offset(Axis, titleColor), + ALL_GRAPHS}, + {BLT_CONFIG_FONT, "-titlefont", "titleFont", "Font", STD_FONT_NORMAL, + Tk_Offset(Axis, titleFont), ALL_GRAPHS}, + {BLT_CONFIG_CUSTOM, "-use", "use", "Use", NULL, 0, ALL_GRAPHS, + &useOption}, + {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} +}; diff --git a/src/bltGrAxis.h b/src/bltGrAxis.h index 3d458b0..4ff5139 100644 --- a/src/bltGrAxis.h +++ b/src/bltGrAxis.h @@ -83,6 +83,7 @@ typedef struct { int checkLimits; unsigned int flags; + Tk_OptionTable optionTable; /* Configuration specifications */ Tcl_HashEntry *hashPtr; /* Fields specific to axes. */ diff --git a/src/bltGrBind.C b/src/bltGrBind.C index 0c876ce..ed1e5b3 100644 --- a/src/bltGrBind.C +++ b/src/bltGrBind.C @@ -523,7 +523,7 @@ Blt_ConfigureBindingsFromObj( BindTable *bindPtr, ClientData item, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { const char *command; unsigned long mask; diff --git a/src/bltGrElemOp.C b/src/bltGrElemOp.C index 8682f8b..adbfc3e 100644 --- a/src/bltGrElemOp.C +++ b/src/bltGrElemOp.C @@ -290,7 +290,7 @@ static int CreateElement(Graph* graphPtr, Tcl_Interp* interp, int objc, char *string = Tcl_GetString(objv[3]); if (string[0] == '-') { Tcl_AppendResult(graphPtr->interp, "name of element \"", string, - "\" can't start with a '-'", (char *)NULL); + "\" can't start with a '-'", NULL); return TCL_ERROR; } @@ -415,6 +415,15 @@ static int ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, return ElementObjConfigure(interp, graphPtr, elemPtr, objc-4, objv+4); } +static int CreateOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[], ClassId classId) +{ + if (CreateElement(graphPtr, interp, objc, objv, classId) != TCL_OK) + return TCL_ERROR; + Tcl_SetObjResult(interp, objv[3]); + return TCL_OK; +} + static int ElementObjConfigure(Tcl_Interp* interp, Graph* graphPtr, Element* elemPtr, int objc, Tcl_Obj* const objv[]) @@ -460,7 +469,7 @@ static int ElementObjConfigure(Tcl_Interp* interp, Graph* graphPtr, // Ops static int ActivateOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Element* elemPtr; int i; @@ -514,7 +523,7 @@ static int ActivateOp(Graph* graphPtr, Tcl_Interp* interp, } static int BindOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { if (objc == 3) { Tcl_HashEntry *hPtr; @@ -536,15 +545,6 @@ static int BindOp(Graph* graphPtr, Tcl_Interp* interp, return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, Blt_MakeElementTag(graphPtr, Tcl_GetString(objv[3])), objc - 4, objv + 4); } -static int CreateOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj* const objv[], ClassId classId) -{ - if (CreateElement(graphPtr, interp, objc, objv, classId) != TCL_OK) - return TCL_ERROR; - Tcl_SetObjResult(interp, objv[3]); - return TCL_OK; -} - static Blt_OptionParseProc ObjToAlong; static Blt_OptionPrintProc AlongToObj; static Blt_CustomOption alongOption = @@ -610,7 +610,7 @@ static Blt_ConfigSpec closestSpecs[] = { }; static int ClosestOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Element* elemPtr; ClosestSearch search; @@ -721,7 +721,7 @@ static int ClosestOp(Graph* graphPtr, Tcl_Interp* interp, } static int DeactivateOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { int i; @@ -743,7 +743,7 @@ static int DeactivateOp(Graph* graphPtr, Tcl_Interp* interp, } static int DeleteOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { int i; @@ -761,7 +761,7 @@ static int DeleteOp(Graph* graphPtr, Tcl_Interp* interp, } static int ExistsOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Tcl_HashEntry *hPtr; @@ -771,7 +771,7 @@ static int ExistsOp(Graph* graphPtr, Tcl_Interp* interp, } static int GetOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { char *string; @@ -841,7 +841,7 @@ static int LowerOp(Graph* graphPtr, Tcl_Interp* interp, } static int NamesOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Tcl_Obj *listObjPtr; @@ -885,7 +885,7 @@ static int NamesOp(Graph* graphPtr, Tcl_Interp* interp, } static int RaiseOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Blt_Chain chain; Blt_ChainLink link, prev; @@ -917,7 +917,7 @@ static int RaiseOp(Graph* graphPtr, Tcl_Interp* interp, } static int ShowOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { if (objc == 4) { Blt_Chain chain; @@ -1006,24 +1006,19 @@ static int numElemOps = sizeof(elemOps) / sizeof(Blt_OpSpec); int Blt_ElementOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[], ClassId classId) { - void *ptr; - int result; - - ptr = Blt_GetOpFromObj(interp, numElemOps, elemOps, BLT_OP_ARG2, - objc, objv, 0); - if (ptr == NULL) { + void *ptr = Blt_GetOpFromObj(interp, numElemOps, elemOps, BLT_OP_ARG2, + objc, objv, 0); + if (ptr == NULL) return TCL_ERROR; + + if (ptr == CreateOp) + retur CreateOp(graphPtr, interp, objc, objv, classId); + else { + GraphElementProc* proc = ptr; + return (*proc)(graphPtr, interp, objc, objv); } - if (ptr == CreateOp) { - result = CreateOp(graphPtr, interp, objc, objv, classId); - } else { - GraphElementProc *proc; - - proc = ptr; - result = (*proc) (graphPtr, interp, objc, objv); - } - return result; } + // Support static void FreeElement(char* data) diff --git a/src/bltGrHairs.C b/src/bltGrHairs.C index 48b2657..d792619 100644 --- a/src/bltGrHairs.C +++ b/src/bltGrHairs.C @@ -67,6 +67,8 @@ static int CrosshairsObjConfigure(Tcl_Interp* interp, Graph* graphPtr, static void ConfigureCrosshairs(Graph* graphPtr); static void TurnOffHairs(Tk_Window tkwin, Crosshairs *chPtr); static void TurnOnHairs(Graph* graphPtr, Crosshairs *chPtr); +typedef int (GraphCrosshairProc)(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); // OptionSpecs @@ -244,26 +246,8 @@ static void ConfigureCrosshairs(Graph* graphPtr) // Ops -static Blt_OpSpec xhairOps[]; -static int nXhairOps; -typedef int (GraphCrosshairProc)(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj* const objv[]); - -int Blt_CrosshairsOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj* const objv[]) -{ - GraphCrosshairProc* proc = Blt_GetOpFromObj(interp, nXhairOps, xhairOps, - BLT_OP_ARG2, objc, objv, 0); - if (proc == NULL) - return TCL_ERROR; - - return (*proc)(graphPtr, interp, objc, objv); -} - -// Widget commands - static int OnOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Crosshairs *chPtr = graphPtr->crosshairs; @@ -275,7 +259,7 @@ static int OnOp(Graph* graphPtr, Tcl_Interp* interp, } static int OffOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Crosshairs *chPtr = graphPtr->crosshairs; @@ -287,7 +271,7 @@ static int OffOp(Graph* graphPtr, Tcl_Interp* interp, } static int ToggleOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Crosshairs *chPtr = graphPtr->crosshairs; @@ -310,6 +294,17 @@ static Blt_OpSpec xhairOps[] = }; static int nXhairOps = sizeof(xhairOps) / sizeof(Blt_OpSpec); +int Blt_CrosshairsOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + GraphCrosshairProc* proc = Blt_GetOpFromObj(interp, nXhairOps, xhairOps, + BLT_OP_ARG2, objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; + + return (*proc)(graphPtr, interp, objc, objv); +} + // Support static void TurnOffHairs(Tk_Window tkwin, Crosshairs *chPtr) diff --git a/src/bltGrLegd.C b/src/bltGrLegd.C index 8a60683..6566905 100644 --- a/src/bltGrLegd.C +++ b/src/bltGrLegd.C @@ -650,22 +650,8 @@ static void ConfigureLegend(Graph* graphPtr) // Ops -static Blt_OpSpec legendOps[]; -static int nLegendOps; - -int Blt_LegendOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj* const objv[]) -{ - GraphLegendProc *proc = Blt_GetOpFromObj(interp, nLegendOps, legendOps, - BLT_OP_ARG2, objc, objv,0); - if (proc == NULL) - return TCL_ERROR; - - return (*proc) (graphPtr, interp, objc, objv); -} - static int ActivateOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; unsigned int active, redraw; @@ -745,7 +731,7 @@ static int ActivateOp(Graph* graphPtr, Tcl_Interp* interp, } static int BindOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { if (objc == 3) { Tcl_HashEntry *hPtr; @@ -769,7 +755,7 @@ static int BindOp(Graph* graphPtr, Tcl_Interp* interp, } static int CurselectionOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; Tcl_Obj *listObjPtr; @@ -810,7 +796,7 @@ static int CurselectionOp(Graph* graphPtr, Tcl_Interp* interp, } static int FocusOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; @@ -837,7 +823,7 @@ static int FocusOp(Graph* graphPtr, Tcl_Interp* interp, } static int GetOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; @@ -854,24 +840,6 @@ static int GetOp(Graph* graphPtr, Tcl_Interp* interp, return TCL_OK; } -static Blt_OpSpec selectionOps[]; -static int nSelectionOps; - -static int SelectionOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) -{ - GraphLegendProc *proc; - int result; - - proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG3, - objc, objv, 0); - if (proc == NULL) { - return TCL_ERROR; - } - result = (*proc) (graphPtr, interp, objc, objv); - return result; -} - static Blt_OpSpec legendOps[] = { {"activate", 1, ActivateOp, 3, 0, "?pattern?...",}, @@ -886,10 +854,21 @@ static Blt_OpSpec legendOps[] = }; static int nLegendOps = sizeof(legendOps) / sizeof(Blt_OpSpec); +int Blt_LegendOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + GraphLegendProc *proc = Blt_GetOpFromObj(interp, nLegendOps, legendOps, + BLT_OP_ARG2, objc, objv,0); + if (proc == NULL) + return TCL_ERROR; + + return (*proc)(graphPtr, interp, objc, objv); +} + // Selection Widget Ops static int SelectionAnchorOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; Element* elemPtr; @@ -909,7 +888,7 @@ static int SelectionAnchorOp(Graph* graphPtr, Tcl_Interp* interp, } static int SelectionClearallOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; @@ -918,7 +897,7 @@ static int SelectionClearallOp(Graph* graphPtr, Tcl_Interp* interp, } static int SelectionIncludesOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; Element* elemPtr; @@ -933,7 +912,7 @@ static int SelectionIncludesOp(Graph* graphPtr, Tcl_Interp* interp, } static int SelectionMarkOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; Element* elemPtr; @@ -976,7 +955,7 @@ static int SelectionMarkOp(Graph* graphPtr, Tcl_Interp* interp, } static int SelectionPresentOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; int bool; @@ -987,7 +966,7 @@ static int SelectionPresentOp(Graph* graphPtr, Tcl_Interp* interp, } static int SelectionSetOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Legend *legendPtr = graphPtr->legend; Element *firstPtr, *lastPtr; @@ -1059,6 +1038,18 @@ static Blt_OpSpec selectionOps[] = }; static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec); +static int SelectionOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + GraphLegendProc* proc = Blt_GetOpFromObj(interp, nSelectionOps, + selectionOps, BLT_OP_ARG3, + objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; + + return (*proc)(graphPtr, interp, objc, objv); +} + // Support static void DisplayLegend(ClientData clientData) diff --git a/src/bltGrLegd.h b/src/bltGrLegd.h index 500320b..425aaee 100644 --- a/src/bltGrLegd.h +++ b/src/bltGrLegd.h @@ -55,7 +55,7 @@ extern void Blt_DestroyLegend(Graph *graphPtr); extern void Blt_DrawLegend(Graph *graphPtr, Drawable drawable); extern void Blt_MapLegend(Graph *graphPtr, int width, int height); extern int Blt_LegendOp(Graph *graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); extern int Blt_Legend_Site(Graph *graphPtr); extern int Blt_Legend_Width(Graph *graphPtr); extern int Blt_Legend_Height(Graph *graphPtr); diff --git a/src/bltGrMarker.C b/src/bltGrMarker.C index 9a7cb61..edbaf7d 100644 --- a/src/bltGrMarker.C +++ b/src/bltGrMarker.C @@ -42,7 +42,7 @@ #include "bltConfig.h" typedef int (GraphMarkerProc)(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); #define GETBITMAP(b) \ (((b)->destBitmap == None) ? (b)->srcBitmap : (b)->destBitmap) @@ -976,7 +976,7 @@ ParseCoordinates( Tcl_Interp* interp, Marker *markerPtr, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { int nWorldPts; int minArgs, maxArgs; @@ -3528,7 +3528,7 @@ RenameMarker(Graph* graphPtr, Marker *markerPtr, const char* oldName, *--------------------------------------------------------------------------- */ static int -NamesOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +NamesOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_Obj *listObjPtr; @@ -3580,7 +3580,7 @@ NamesOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -BindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +BindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (objc == 3) { Tcl_HashEntry *hp; @@ -3614,7 +3614,7 @@ BindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -CgetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +CgetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker *markerPtr; @@ -3642,7 +3642,7 @@ CgetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker *markerPtr; Tcl_Obj *const *options; @@ -3726,7 +3726,7 @@ ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -CreateOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +CreateOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker *markerPtr; Tcl_HashEntry *hPtr; @@ -3830,7 +3830,7 @@ CreateOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -DeleteOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +DeleteOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; @@ -3866,7 +3866,7 @@ DeleteOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -GetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +GetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker *markerPtr; const char* string; @@ -3907,7 +3907,7 @@ GetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -RelinkOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +RelinkOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Blt_ChainLink link, place; Marker *markerPtr; @@ -3959,7 +3959,7 @@ RelinkOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -FindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +FindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Blt_ChainLink link; Region2d extents; @@ -4039,7 +4039,7 @@ FindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -ExistsOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +ExistsOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_HashEntry *hPtr; @@ -4063,7 +4063,7 @@ ExistsOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -TypeOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +TypeOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker *markerPtr; const char* type; @@ -4124,7 +4124,7 @@ static int nMarkerOps = sizeof(markerOps) / sizeof(Blt_OpSpec); /*ARGSUSED*/ int Blt_MarkerOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { GraphMarkerProc *proc; int result; diff --git a/src/bltGrPenOp.C b/src/bltGrPenOp.C index 916e140..b6c468f 100644 --- a/src/bltGrPenOp.C +++ b/src/bltGrPenOp.C @@ -49,7 +49,7 @@ static int GetPenFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, static int PenObjConfigure(Tcl_Interp* interp, Graph* graphPtr, Pen* penPtr, int objc, Tcl_Obj* const objv[]); typedef int (GraphPenProc)(Tcl_Interp* interp, Graph* graphPtr, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); // OptionSpecs @@ -191,7 +191,7 @@ static int CgetOp(Tcl_Interp* interp, Graph* graphPtr, } static int ConfigureOp(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Pen* penPtr; if (GetPenFromObj(interp, graphPtr, objv[3], &penPtr) != TCL_OK) @@ -256,7 +256,7 @@ static int PenObjConfigure(Tcl_Interp* interp, Graph* graphPtr, Pen* penPtr, // Ops static int CreateOp(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { if (Blt_CreatePen(graphPtr, interp, Tcl_GetString(objv[3]), graphPtr->classId, objc, objv) != TCL_OK) return TCL_ERROR; @@ -265,32 +265,27 @@ static int CreateOp(Tcl_Interp* interp, Graph* graphPtr, } static int DeleteOp(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { - int i; - - for (i = 3; i < objc; i++) { - Pen* penPtr; + Pen* penPtr; + if (GetPenFromObj(interp, graphPtr, objv[3], &penPtr) != TCL_OK) + return TCL_ERROR; - if (GetPenFromObj(interp, graphPtr, objv[i], &penPtr) != TCL_OK) { - return TCL_ERROR; - } - if (penPtr->flags & DELETE_PENDING) { - Tcl_AppendResult(interp, "can't find pen \"", - Tcl_GetString(objv[i]), "\" in \"", - Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); - return TCL_ERROR; - } - penPtr->flags |= DELETE_PENDING; - if (penPtr->refCount == 0) { - DestroyPen(penPtr); - } + if (penPtr->flags & DELETE_PENDING) { + Tcl_AppendResult(interp, "can't find pen \"", + Tcl_GetString(objv[i]), "\" in \"", + Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); + return TCL_ERROR; } + penPtr->flags |= DELETE_PENDING; + if (penPtr->refCount == 0) + DestroyPen(penPtr); + return TCL_OK; } static int NamesOp(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Tcl_Obj *listObjPtr; @@ -339,10 +334,9 @@ static int NamesOp(Tcl_Interp* interp, Graph* graphPtr, } static int TypeOp(Tcl_Interp* interp, Graph* graphPtr, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { Pen* penPtr; - if (GetPenFromObj(interp, graphPtr, objv[3], &penPtr) != TCL_OK) return TCL_ERROR; @@ -362,19 +356,19 @@ static Blt_OpSpec penOps[] = }; static int nPenOps = sizeof(penOps) / sizeof(Blt_OpSpec); -// Extern - int Blt_PenOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv) + int objc, Tcl_Obj* const objv[]) { GraphPenProc *proc = Blt_GetOpFromObj(interp, nPenOps, penOps, BLT_OP_ARG2, objc, objv, 0); - if (proc == NULL) { + if (proc == NULL) return TCL_ERROR; - } - return (*proc) (interp, graphPtr, objc, objv); + + return (*proc)(interp, graphPtr, objc, objv); } +// Support + void Blt_DestroyPens(Graph* graphPtr) { Tcl_HashEntry *hPtr; diff --git a/src/bltGraph.C b/src/bltGraph.C index 122901f..a56a6da 100644 --- a/src/bltGraph.C +++ b/src/bltGraph.C @@ -81,6 +81,9 @@ static void ConfigureGraph(Graph* graphPtr); static void DrawPlot(Graph* graphPtr, Drawable drawable); static void UpdateMarginTraces(Graph* graphPtr); +typedef int (GraphCmdProc)(Graph* graphPtr, Tcl_Interp* interp, int objc, + Tcl_Obj* const objv[]); + // OptionSpecs static char* barmodeObjOption[] = @@ -300,6 +303,8 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, if (Blt_CreatePen(graphPtr, interp, "activeBar", CID_ELEM_BAR, 0, NULL) != TCL_OK) goto error; + if (Blt_CreateAxes(graphPtr) != TCL_OK) + goto error; if (Blt_CreatePageSetup(graphPtr) != TCL_OK) goto error; @@ -322,8 +327,7 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, if (Blt_ConfigurePageSetup(graphPtr) != TCL_OK) goto error; - if (Blt_DefaultAxes(graphPtr) != TCL_OK) - goto error; + AdjustAxisPointers(graphPtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), @@ -335,26 +339,6 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, return TCL_ERROR; } -static Blt_OpSpec graphOps[]; -static int nGraphOps; -typedef int (GraphCmdProc)(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj* const objv[]); - -int Blt_GraphInstCmdProc(ClientData clientData, Tcl_Interp* interp, - int objc, Tcl_Obj* const objv[]) -{ - Graph* graphPtr = clientData; - GraphCmdProc* proc = Blt_GetOpFromObj(interp, nGraphOps, graphOps, - BLT_OP_ARG1, objc, objv, 0); - if (proc == NULL) - return TCL_ERROR; - - Tcl_Preserve(graphPtr); - int result = (*proc)(graphPtr, interp, objc, objv); - Tcl_Release(graphPtr); - return result; -} - // called by Tcl_DeleteCommand static void GraphInstCmdDeleteProc(ClientData clientData) { @@ -663,28 +647,28 @@ static int XAxisOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int margin = (graphPtr->inverted) ? MARGIN_LEFT : MARGIN_BOTTOM; - return Blt_AxisOp(interp, graphPtr, margin, objc, objv); + return Blt_DefAxisOp(interp, graphPtr, margin, objc, objv); } static int X2AxisOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int margin = (graphPtr->inverted) ? MARGIN_RIGHT : MARGIN_TOP; - return Blt_AxisOp(interp, graphPtr, margin, objc, objv); + return Blt_DefAxisOp(interp, graphPtr, margin, objc, objv); } static int YAxisOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int margin = (graphPtr->inverted) ? MARGIN_BOTTOM : MARGIN_LEFT; - return Blt_AxisOp(interp, graphPtr, margin, objc, objv); + return Blt_DefAxisOp(interp, graphPtr, margin, objc, objv); } static int Y2AxisOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int margin = (graphPtr->inverted) ? MARGIN_TOP : MARGIN_RIGHT; - return Blt_AxisOp(interp, graphPtr, margin, objc, objv); + return Blt_DefAxisOp(interp, graphPtr, margin, objc, objv); } static int BarOp(Graph* graphPtr, Tcl_Interp* interp, int objc, @@ -878,7 +862,7 @@ static int TransformOp(Graph* graphPtr, Tcl_Interp* interp, int objc, static Blt_OpSpec graphOps[] = { - {"axis", 1, Blt_VirtualAxisOp, 2, 0, "oper ?args?",}, + {"axis", 1, Blt_AxisOp, 2, 0, "oper ?args?",}, {"bar", 2, BarOp, 2, 0, "oper ?args?",}, {"cget", 2, CgetOp, 3, 3, "option",}, {"configure", 2, ConfigureOp, 2, 0, "?option value?...",}, @@ -900,6 +884,21 @@ static Blt_OpSpec graphOps[] = }; static int nGraphOps = sizeof(graphOps) / sizeof(Blt_OpSpec); +int Blt_GraphInstCmdProc(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + Graph* graphPtr = clientData; + GraphCmdProc* proc = Blt_GetOpFromObj(interp, nGraphOps, graphOps, + BLT_OP_ARG1, objc, objv, 0); + if (proc == NULL) + return TCL_ERROR; + + Tcl_Preserve(graphPtr); + int result = (*proc)(graphPtr, interp, objc, objv); + Tcl_Release(graphPtr); + return result; +} + // Support void Blt_EventuallyRedrawGraph(Graph* graphPtr) diff --git a/src/bltGraph.h b/src/bltGraph.h index 138473d..eb06e73 100644 --- a/src/bltGraph.h +++ b/src/bltGraph.h @@ -568,23 +568,23 @@ extern int Blt_InitBarPens(Graph* graphPtr); extern void Blt_FreePen(Pen* penPtr); -extern int Blt_VirtualAxisOp(Graph* graphPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv); +extern int Blt_AxisOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); -extern int Blt_AxisOp(Tcl_Interp* interp, Graph* graphPtr, int margin, - int objc, Tcl_Obj *const *objv); +extern int Blt_DefAxisOp(Tcl_Interp* interp, Graph* graphPtr, int margin, + int objc, Tcl_Obj* const objv[]); extern int Blt_ElementOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv, ClassId classId); + Tcl_Obj* const objv[], ClassId classId); extern int Blt_CrosshairsOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); extern int Blt_MarkerOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); extern int Blt_PenOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); extern int Blt_PointInPolygon(Point2d *samplePtr, Point2d *screenPts, int nScreenPts); @@ -596,11 +596,11 @@ extern int Blt_PointInSegments(Point2d *samplePtr, Segment2d *segments, int nSegments, double halo); extern int Blt_PostScriptOp(Graph* graphPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); extern int Blt_GraphUpdateNeeded(Graph* graphPtr); -extern int Blt_DefaultAxes(Graph* graphPtr); +extern int Blt_CreateAxes(Graph* graphPtr); extern Axis *Blt_GetFirstAxis(Blt_Chain chain); diff --git a/src/bltOp.h b/src/bltOp.h index 4722303..25db5c4 100644 --- a/src/bltOp.h +++ b/src/bltOp.h @@ -37,6 +37,6 @@ typedef enum { #define BLT_OP_LINEAR_SEARCH 1 extern void *Blt_GetOpFromObj(Tcl_Interp* interp, int nSpecs, - Blt_OpSpec *specs, int operPos, int objc, Tcl_Obj *const *objv, + Blt_OpSpec *specs, int operPos, int objc, Tcl_Obj* const objv[], int flags); diff --git a/src/bltSwitch.C b/src/bltSwitch.C index 753c765..891a47f 100644 --- a/src/bltSwitch.C +++ b/src/bltSwitch.C @@ -325,7 +325,7 @@ Blt_ParseSwitches( Tcl_Interp* interp, /* Interpreter for error reporting. */ Blt_SwitchSpec *specs, /* Describes legal switches. */ int objc, /* Number of elements in argv. */ - Tcl_Obj *const *objv, /* Command-line switches. */ + Tcl_Obj* const objv[], /* Command-line switches. */ void *record, /* Record whose fields are to be modified. * Values must be properly initialized. */ int flags) /* Used to specify additional flags that must diff --git a/src/bltVecCmd.C b/src/bltVecCmd.C index 12ad4e8..44cb1bf 100644 --- a/src/bltVecCmd.C +++ b/src/bltVecCmd.C @@ -61,7 +61,7 @@ #include "bltSwitch.h" typedef int (VectorCmdProc)(Vector *vPtr, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj* const objv[]); static Blt_SwitchParseProc ObjToFFTVector; static Blt_SwitchCustom fftVectorSwitch = { @@ -236,7 +236,7 @@ ReplicateValue(Vector *vPtr, int first, int last, double value) } static int -CopyList(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +CopyList(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; @@ -274,7 +274,7 @@ AppendVector(Vector *destPtr, Vector *srcPtr) } static int -AppendList(Vector *vPtr, int objc, Tcl_Obj *const *objv) +AppendList(Vector *vPtr, int objc, Tcl_Obj* const objv[]) { Tcl_Interp* interp = vPtr->interp; int count; @@ -319,7 +319,7 @@ AppendList(Vector *vPtr, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -AppendOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +AppendOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; int result; @@ -372,7 +372,7 @@ AppendOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -ClearOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +ClearOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Blt_Vec_FlushCache(vPtr); return TCL_OK; @@ -398,7 +398,7 @@ ClearOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -DeleteOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +DeleteOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { unsigned char *unsetArr; int i, j; @@ -467,7 +467,7 @@ DeleteOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -DupOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +DupOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; @@ -503,7 +503,7 @@ DupOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) /* fft implementation */ /*ARGSUSED*/ static int -FFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +FFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Vector *v2Ptr = NULL; int isNew; @@ -556,7 +556,7 @@ FFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) /*ARGSUSED*/ static int -InverseFFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +InverseFFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int isNew; char *name; @@ -606,7 +606,7 @@ InverseFFTOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -IndexOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +IndexOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int first, last; char *string; @@ -671,7 +671,7 @@ IndexOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -LengthOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +LengthOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (objc == 3) { int nElem; @@ -714,7 +714,7 @@ LengthOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -MapOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +MapOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (objc > 2) { if (Blt_Vec_MapVariable(interp, vPtr, Tcl_GetString(objv[2])) @@ -742,7 +742,7 @@ MapOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -MaxOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +MaxOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_SetDoubleObj(Tcl_GetObjResult(interp), Blt_Vec_Max(vPtr)); return TCL_OK; @@ -764,7 +764,7 @@ MaxOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -MergeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +MergeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Vector **vecArr; int refSize, nElem; @@ -839,7 +839,7 @@ MergeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -MinOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +MinOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_SetDoubleObj(Tcl_GetObjResult(interp), Blt_Vec_Min(vPtr)); return TCL_OK; @@ -860,7 +860,7 @@ MinOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -NormalizeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +NormalizeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; double range; @@ -928,7 +928,7 @@ NormalizeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -NotifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +NotifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int option; int bool; @@ -990,7 +990,7 @@ NotifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -PopulateOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +PopulateOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Vector *v2Ptr; int size, density; @@ -1059,7 +1059,7 @@ PopulateOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -ValuesOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +ValuesOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { PrintSwitches switches; @@ -1122,7 +1122,7 @@ ValuesOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -RangeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +RangeOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_Obj *listObjPtr; int first, last; @@ -1389,7 +1389,7 @@ CopyValues(Vector *vPtr, char *byteArr, enum NativeFormats fmt, int size, */ /*ARGSUSED*/ static int -BinreadOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +BinreadOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_Channel channel; char *byteArr; @@ -1537,7 +1537,7 @@ BinreadOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -SearchOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SearchOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { double min, max; int i; @@ -1605,7 +1605,7 @@ SearchOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -OffsetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +OffsetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (objc == 3) { int newOffset; @@ -1633,7 +1633,7 @@ OffsetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -RandomOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +RandomOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int i; @@ -1661,7 +1661,7 @@ RandomOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -SeqOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SeqOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int n; double start, stop; @@ -1715,7 +1715,7 @@ SeqOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -SetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int result; Vector *v2Ptr; @@ -1783,7 +1783,7 @@ SetOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -SimplifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SimplifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { size_t i, n; int length, nPoints; @@ -1828,7 +1828,7 @@ SimplifyOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -SplitOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SplitOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int nVectors; @@ -1936,7 +1936,7 @@ Blt_Vec_SortMap(Vector **vectors, int nVectors) } static size_t * -SortVectors(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SortVectors(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Vector **vectors, *v2Ptr; size_t *map; @@ -1985,7 +1985,7 @@ SortVectors(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) *--------------------------------------------------------------------------- */ static int -SortOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +SortOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Vector *v2Ptr; double *copy; @@ -2091,7 +2091,7 @@ SortOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -InstExprOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +InstExprOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (Blt_ExprVector(interp, Tcl_GetString(objv[2]), (Blt_Vector *)vPtr) @@ -2123,7 +2123,7 @@ InstExprOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) */ /*ARGSUSED*/ static int -ArithOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj *const *objv) +ArithOp(Vector *vPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { double value; int i; @@ -2276,7 +2276,7 @@ static int nInstOps = sizeof(vectorInstOps) / sizeof(Blt_OpSpec); int Blt_Vec_InstCmd(ClientData clientData, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { VectorCmdProc *proc; Vector *vPtr = clientData; diff --git a/src/bltVector.C b/src/bltVector.C index f149b35..bf69143 100644 --- a/src/bltVector.C +++ b/src/bltVector.C @@ -118,7 +118,7 @@ static Blt_SwitchSpec createSwitches[] = }; typedef int (VectorCmdProc)(Vector *vecObjPtr, Tcl_Interp* interp, - int objc, Tcl_Obj *const *objv); + int objc, Tcl_Obj* const objv[]); static Vector * FindVectorInNamespace( @@ -1385,7 +1385,7 @@ VectorNamesOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { VectorInterpData *dataPtr = clientData; Tcl_Obj *listObjPtr; @@ -1457,7 +1457,7 @@ VectorCreate2( Tcl_Interp* interp, int argStart, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { VectorInterpData *dataPtr = clientData; Vector *vPtr; @@ -1621,7 +1621,7 @@ VectorCreateOp( ClientData clientData, Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { return VectorCreate2(clientData, interp, 2, objc, objv); } @@ -1648,7 +1648,7 @@ VectorDestroyOp( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp* interp, /* Not used. */ int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { VectorInterpData *dataPtr = clientData; Vector *vPtr; @@ -1683,7 +1683,7 @@ VectorExprOp( ClientData clientData, /* Not Used. */ Tcl_Interp* interp, int objc, /* Not used. */ - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { return Blt_ExprVector(interp, Tcl_GetString(objv[2]), (Blt_Vector *)NULL); } @@ -1706,7 +1706,7 @@ VectorCmd( ClientData clientData, /* Interpreter-specific data. */ Tcl_Interp* interp, int objc, - Tcl_Obj *const *objv) + Tcl_Obj* const objv[]) { VectorCmdProc *proc; /* -- cgit v0.12