From 81d64674f0c91ca6714b2ff4d67ab362bf1d467a Mon Sep 17 00:00:00 2001 From: joye Date: Fri, 21 Feb 2014 21:11:20 +0000 Subject: *** empty log message *** --- src/bltGrElemBar.C | 61 +- src/bltGrElemLine.C | 6891 +++++++++++++++++++++++---------------------------- src/bltGrElemOp.C | 3195 ++++++++++-------------- src/bltGrElemOp.h | 2 +- src/bltGrHairs.C | 3 + src/bltGrLegd.C | 8 +- src/bltGrPenOp.C | 180 +- src/bltGraph.C | 7 +- src/bltGraph.h | 8 +- 9 files changed, 4550 insertions(+), 5805 deletions(-) diff --git a/src/bltGrElemBar.C b/src/bltGrElemBar.C index 20e2431..be28d14 100644 --- a/src/bltGrElemBar.C +++ b/src/bltGrElemBar.C @@ -61,7 +61,7 @@ typedef struct { int refCount; /* Reference count for elements using * this pen. */ Tcl_HashEntry *hashPtr; - Blt_ConfigSpec *configSpecs; /* Configuration specifications */ + Tk_OptionTable optionTable; /* Configuration specifications */ PenConfigureProc *configProc; PenDestroyProc *destroyProc; Graph *graphPtr; /* Graph that the pen is associated @@ -140,7 +140,7 @@ typedef struct { * then all data * points are drawn * active. */ ElementProcs *procsPtr; - Blt_ConfigSpec *configSpecs; /* Configuration specifications. */ + Tk_OptionTable optionTable; /* Configuration specifications. */ BarPen *activePenPtr; /* Standard Pens */ BarPen *normalPenPtr; BarPen *builtinPenPtr; @@ -623,8 +623,11 @@ static int ConfigureBarPen(Graph *graphPtr, BarPen *penPtr) return TCL_OK; } -static void DestroyBarPen(Graph *graphPtr, BarPen *penPtr) +static void DestroyBarPen(Graph* graphPtr, BarPen* penPtr) { + Tk_FreeConfigOptions((char*)penPtr, penPtr->optionTable, graphPtr->tkwin); + Tk_DeleteOptionTable(penPtr->optionTable); + Blt_Ts_FreeStyle(graphPtr->display, &penPtr->valueStyle); if (penPtr->outlineGC != NULL) { Tk_FreeGC(graphPtr->display, penPtr->outlineGC); @@ -647,13 +650,14 @@ static void DestroyBarPenProc(Graph *graphPtr, Pen *basePtr) DestroyBarPen(graphPtr, (BarPen *)basePtr); } -static void InitializeBarPen(BarPen *penPtr) +static void InitBarPen(Graph* graphPtr, BarPen* penPtr) { /* Generic fields common to all pen types. */ penPtr->configProc = ConfigureBarPenProc; penPtr->destroyProc = DestroyBarPenProc; penPtr->flags = NORMAL_PEN; - penPtr->configSpecs = barPenConfigSpecs; + penPtr->optionTable = + Tk_CreateOptionTable(graphPtr->interp, barPenOptionSpecs); /* Initialize fields specific to bar pens. */ Blt_Ts_InitStyle(penPtr->valueStyle); @@ -663,12 +667,10 @@ static void InitializeBarPen(BarPen *penPtr) penPtr->errorBarShow = SHOW_BOTH; } -Pen* Blt_BarPen(const char *penName) +Pen* Blt_BarPen(Graph* graphPtr, const char *penName) { - BarPen *penPtr; - - penPtr = calloc(1, sizeof(BarPen)); - InitializeBarPen(penPtr); + BarPen *penPtr = calloc(1, sizeof(BarPen)); + InitBarPen(graphPtr, penPtr); penPtr->name = Blt_Strdup(penName); if (strcmp(penName, "activeBar") == 0) { penPtr->flags = ACTIVE_PEN; @@ -762,10 +764,12 @@ static int ConfigureBarProc(Graph *graphPtr, Element *basePtr) stylePtr = Blt_Chain_GetValue(link); stylePtr->penPtr = NORMALPEN(elemPtr); + /* if (Blt_ConfigModified(elemPtr->configSpecs, "-barwidth", "-*data", "-map*", "-label", "-hide", "-x", "-y", (char *)NULL)) { elemPtr->flags |= MAP_ITEM; } + */ return TCL_OK; } @@ -2200,31 +2204,18 @@ static void NormalBarToPostScriptProc(Graph *graphPtr, Blt_Ps ps, } if (penPtr->valueShow != SHOW_NONE) { BarValuesToPostScript(graphPtr, ps, elemPtr, penPtr, - stylePtr->bars, stylePtr->nBars, elemPtr->barToData + count); + stylePtr->bars, stylePtr->nBars, + elemPtr->barToData + count); } count += stylePtr->nBars; } } -/* - *--------------------------------------------------------------------------- - * - * DestroyBar -- - * - * Release memory and resources allocated for the bar element. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the bar element is freed up. - * - *--------------------------------------------------------------------------- - */ - -static void DestroyBarProc(Graph *graphPtr, Element *basePtr) +static void DestroyBarProc(Graph* graphPtr, Element* basePtr) { - BarElement *elemPtr = (BarElement *)basePtr; + BarElement* elemPtr = (BarElement*)basePtr; + Tk_FreeConfigOptions((char*)elemPtr, elemPtr->optionTable, graphPtr->tkwin); + Tk_DeleteOptionTable(elemPtr->optionTable); DestroyBarPen(graphPtr, elemPtr->builtinPenPtr); if (elemPtr->activePenPtr != NULL) { @@ -2270,13 +2261,12 @@ static ElementProcs barProcs = { MapBarProc, }; -Element* Blt_BarElement(Graph *graphPtr, const char *name, ClassId classId) +Element* Blt_BarElement(Graph* graphPtr, const char* name, ClassId classId) { - BarElement *elemPtr; - - elemPtr = calloc(1, sizeof(BarElement)); + BarElement *elemPtr = calloc(1, sizeof(BarElement)); elemPtr->procsPtr = &barProcs; - elemPtr->configSpecs = barElemConfigSpecs; + elemPtr->optionTable = + Tk_CreateOptionTable(graphPtr->interp, barElemOptionSpecs); elemPtr->legendRelief = TK_RELIEF_FLAT; Blt_GraphSetObjectClass(&elemPtr->obj, classId); elemPtr->obj.name = Blt_Strdup(name); @@ -2284,9 +2274,10 @@ Element* Blt_BarElement(Graph *graphPtr, const char *name, ClassId classId) /* By default, an element's name and label are the same. */ elemPtr->label = Blt_Strdup(name); elemPtr->builtinPenPtr = &elemPtr->builtinPen; - InitializeBarPen(elemPtr->builtinPenPtr); + InitBarPen(graphPtr, elemPtr->builtinPenPtr); elemPtr->stylePalette = Blt_Chain_Create(); bltBarStylesOption.clientData = (ClientData)sizeof(BarStyle); + return (Element *)elemPtr; } diff --git a/src/bltGrElemLine.C b/src/bltGrElemLine.C index a410984..9fc4dbe 100644 --- a/src/bltGrElemLine.C +++ b/src/bltGrElemLine.C @@ -45,9 +45,7 @@ #include "bltBitmap.h" #include "bltConfig.h" -#define PointInRegion(e,x,y) \ - (((x) <= (e)->right) && ((x) >= (e)->left) && \ - ((y) <= (e)->bottom) && ((y) >= (e)->top)) +#define PointInRegion(e,x,y) (((x) <= (e)->right) && ((x) >= (e)->left) && ((y) <= (e)->bottom) && ((y) >= (e)->top)) #define COLOR_DEFAULT (XColor *)1 #define PATTERN_SOLID ((Pixmap)1) @@ -65,316 +63,314 @@ /* Lines will be drawn between points regardless of the ordering of the * abscissas */ -#define BROKEN_TRACE(dir,last,next) \ - (((((dir) & PEN_DECREASING) == 0) && ((next) < (last))) || \ - ((((dir) & PEN_INCREASING) == 0) && ((next) > (last)))) +#define BROKEN_TRACE(dir,last,next) \ + (((((dir) & PEN_DECREASING) == 0) && ((next) < (last))) || \ + ((((dir) & PEN_INCREASING) == 0) && ((next) > (last)))) -#define DRAW_SYMBOL(linePtr) \ - (((linePtr)->symbolCounter % (linePtr)->symbolInterval) == 0) +#define DRAW_SYMBOL(linePtr) \ + (((linePtr)->symbolCounter % (linePtr)->symbolInterval) == 0) typedef enum { - PEN_SMOOTH_LINEAR, /* Line segments */ - PEN_SMOOTH_STEP, /* Step-and-hold */ - PEN_SMOOTH_NATURAL, /* Natural cubic spline */ - PEN_SMOOTH_QUADRATIC, /* Quadratic spline */ - PEN_SMOOTH_CATROM, /* Catrom parametric spline */ - PEN_SMOOTH_LAST /* Sentinel */ + PEN_SMOOTH_LINEAR, /* Line segments */ + PEN_SMOOTH_STEP, /* Step-and-hold */ + PEN_SMOOTH_NATURAL, /* Natural cubic spline */ + PEN_SMOOTH_QUADRATIC, /* Quadratic spline */ + PEN_SMOOTH_CATROM, /* Catrom parametric spline */ + PEN_SMOOTH_LAST /* Sentinel */ } Smoothing; typedef struct { - const char *name; - Smoothing value; + const char *name; + Smoothing value; } SmoothingInfo; static SmoothingInfo smoothingInfo[] = { - { "none", PEN_SMOOTH_LINEAR }, - { "linear", PEN_SMOOTH_LINEAR }, - { "step", PEN_SMOOTH_STEP }, - { "natural", PEN_SMOOTH_NATURAL }, - { "cubic", PEN_SMOOTH_NATURAL }, - { "quadratic", PEN_SMOOTH_QUADRATIC }, - { "catrom", PEN_SMOOTH_CATROM }, - { (char *)NULL, PEN_SMOOTH_LAST } + { "none", PEN_SMOOTH_LINEAR }, + { "linear", PEN_SMOOTH_LINEAR }, + { "step", PEN_SMOOTH_STEP }, + { "natural", PEN_SMOOTH_NATURAL }, + { "cubic", PEN_SMOOTH_NATURAL }, + { "quadratic", PEN_SMOOTH_QUADRATIC }, + { "catrom", PEN_SMOOTH_CATROM }, + { (char *)NULL, PEN_SMOOTH_LAST } }; typedef struct { - Point2d *screenPts; /* Array of transformed coordinates */ - int nScreenPts; /* Number of coordinates */ - int *styleMap; /* Index of pen styles */ - int *map; /* Maps segments/traces to data + Point2d *screenPts; /* Array of transformed coordinates */ + int nScreenPts; /* Number of coordinates */ + int *styleMap; /* Index of pen styles */ + int *map; /* Maps segments/traces to data * points */ } MapInfo; /* Symbol types for line elements */ typedef enum { - SYMBOL_NONE, - SYMBOL_SQUARE, - SYMBOL_CIRCLE, - SYMBOL_DIAMOND, - SYMBOL_PLUS, - SYMBOL_CROSS, - SYMBOL_SPLUS, - SYMBOL_SCROSS, - SYMBOL_TRIANGLE, - SYMBOL_ARROW, - SYMBOL_BITMAP, - SYMBOL_IMAGE + SYMBOL_NONE, + SYMBOL_SQUARE, + SYMBOL_CIRCLE, + SYMBOL_DIAMOND, + SYMBOL_PLUS, + SYMBOL_CROSS, + SYMBOL_SPLUS, + SYMBOL_SCROSS, + SYMBOL_TRIANGLE, + SYMBOL_ARROW, + SYMBOL_BITMAP, + SYMBOL_IMAGE } SymbolType; typedef struct { - const char *name; - unsigned int minChars; - SymbolType type; + const char *name; + unsigned int minChars; + SymbolType type; } GraphSymbolType; static GraphSymbolType graphSymbols[] = { - { "arrow", 1, SYMBOL_ARROW, }, - { "circle", 2, SYMBOL_CIRCLE, }, - { "cross", 2, SYMBOL_CROSS, }, - { "diamond", 1, SYMBOL_DIAMOND, }, - { "none", 1, SYMBOL_NONE, }, - { "plus", 1, SYMBOL_PLUS, }, - { "scross", 2, SYMBOL_SCROSS, }, - { "splus", 2, SYMBOL_SPLUS, }, - { "square", 2, SYMBOL_SQUARE, }, - { "triangle", 1, SYMBOL_TRIANGLE, }, - { NULL, 0, 0 }, + { "arrow", 1, SYMBOL_ARROW, }, + { "circle", 2, SYMBOL_CIRCLE, }, + { "cross", 2, SYMBOL_CROSS, }, + { "diamond", 1, SYMBOL_DIAMOND, }, + { "none", 1, SYMBOL_NONE, }, + { "plus", 1, SYMBOL_PLUS, }, + { "scross", 2, SYMBOL_SCROSS, }, + { "splus", 2, SYMBOL_SPLUS, }, + { "square", 2, SYMBOL_SQUARE, }, + { "triangle", 1, SYMBOL_TRIANGLE, }, + { NULL, 0, 0 }, }; typedef struct { - SymbolType type; /* Type of symbol to be drawn/printed */ + SymbolType type; /* Type of symbol to be drawn/printed */ - int size; /* Requested size of symbol in pixels */ + int size; /* Requested size of symbol in pixels */ - XColor *outlineColor; /* Outline color */ + XColor *outlineColor; /* Outline color */ - int outlineWidth; /* Width of the outline */ + int outlineWidth; /* Width of the outline */ - GC outlineGC; /* Outline graphics context */ + GC outlineGC; /* Outline graphics context */ - XColor *fillColor; /* Normal fill color */ + XColor *fillColor; /* Normal fill color */ - GC fillGC; /* Fill graphics context */ + GC fillGC; /* Fill graphics context */ - Tk_Image image; /* This is used of image symbols. */ + Tk_Image image; /* This is used of image symbols. */ - /* The last two fields are used only for bitmap symbols. */ + /* The last two fields are used only for bitmap symbols. */ - Pixmap bitmap; /* Bitmap to determine - * foreground/background pixels of the - * symbol */ - Pixmap mask; /* Bitmap representing the transparent - * pixels of the symbol */ + Pixmap bitmap; /* Bitmap to determine + * foreground/background pixels of the + * symbol */ + Pixmap mask; /* Bitmap representing the transparent + * pixels of the symbol */ } Symbol; typedef struct { - int start; /* Index into the X-Y coordinate arrays + int start; /* Index into the X-Y coordinate arrays * indicating where trace starts. */ - GraphPoints screenPts; /* Array of screen coordinates + GraphPoints screenPts; /* Array of screen coordinates * (malloc-ed) representing the * trace. */ } bltTrace; typedef struct { - const char *name; /* Pen style identifier. If NULL pen + const char *name; /* Pen style identifier. If NULL pen * was statically allocated. */ - ClassId classId; /* Type of pen */ - const char *typeId; /* String token identifying the type of + ClassId classId; /* Type of pen */ + const char *typeId; /* String token identifying the type of * pen */ - unsigned int flags; /* Indicates if the pen element is + unsigned int flags; /* Indicates if the pen element is * active or normal */ - int refCount; /* Reference count for elements using - * this pen. */ - Tcl_HashEntry *hashPtr; - - Blt_ConfigSpec *configSpecs; /* Configuration specifications */ - - PenConfigureProc *configProc; - PenDestroyProc *destroyProc; - Graph *graphPtr; /* Graph that the pen is associated + int refCount; /* Reference count for elements using + * this pen. */ + Tcl_HashEntry *hashPtr; + Tk_OptionTable optionTable; /* Configuration specifications */ + PenConfigureProc *configProc; + PenDestroyProc *destroyProc; + Graph *graphPtr; /* Graph that the pen is associated * with. */ - /* Symbol attributes. */ - Symbol symbol; /* Element symbol type */ + /* Symbol attributes. */ + Symbol symbol; /* Element symbol type */ - /* Trace attributes. */ - int traceWidth; /* Width of the line segments. If + /* Trace attributes. */ + int traceWidth; /* Width of the line segments. If * lineWidth is 0, no line will be * drawn, only symbols. */ - Blt_Dashes traceDashes; /* Dash on-off list value */ + Blt_Dashes traceDashes; /* Dash on-off list value */ - XColor *traceColor; /* Line segment color */ + XColor *traceColor; /* Line segment color */ - XColor *traceOffColor; /* Line segment dash gap color */ + XColor *traceOffColor; /* Line segment dash gap color */ - GC traceGC; /* Line segment graphics context */ + GC traceGC; /* Line segment graphics context */ - /* Error bar attributes. */ - int errorBarShow; /* Describes which error bars to display: + /* Error bar attributes. */ + int errorBarShow; /* Describes which error bars to display: * none, x, y, or * both. */ - int errorBarLineWidth; /* Width of the error bar segments. */ + int errorBarLineWidth; /* Width of the error bar segments. */ - int errorBarCapWidth; /* Width of the cap on error bars. */ + int errorBarCapWidth; /* Width of the cap on error bars. */ - XColor *errorBarColor; /* Color of the error bar. */ + XColor *errorBarColor; /* Color of the error bar. */ - GC errorBarGC; /* Error bar graphics context. */ + GC errorBarGC; /* Error bar graphics context. */ - /* Show value attributes. */ - int valueShow; /* Indicates whether to display data + /* Show value attributes. */ + int valueShow; /* Indicates whether to display data * value. Values are x, y, both, or * none. */ - const char *valueFormat; /* A printf format string. */ + const char *valueFormat; /* A printf format string. */ - TextStyle valueStyle; /* Text attributes (color, font, - * rotation, etc.) of the value. */ + TextStyle valueStyle; /* Text attributes (color, font, + * rotation, etc.) of the value. */ } LinePen; typedef struct { - Weight weight; /* Weight range where this pen is + Weight weight; /* Weight range where this pen is * valid. */ - LinePen *penPtr; /* Pen to use. */ - GraphPoints symbolPts; + LinePen *penPtr; /* Pen to use. */ + GraphPoints symbolPts; - GraphSegments lines; /* Points to start of the line segments - * for this pen. */ - GraphSegments xeb, yeb; /* X and Y axis error bars. */ + GraphSegments lines; /* Points to start of the line segments + * for this pen. */ + GraphSegments xeb, yeb; /* X and Y axis error bars. */ - int symbolSize; /* Size of the pen's symbol scaled to + int symbolSize; /* Size of the pen's symbol scaled to * the current graph size. */ - int errorBarCapWidth; /* Length of the cap ends on each error - * bar. */ + int errorBarCapWidth; /* Length of the cap ends on each error + * bar. */ } LineStyle; typedef struct { - GraphObj obj; /* Must be first field in element. */ - unsigned int flags; - Tcl_HashEntry *hashPtr; + GraphObj obj; /* Must be first field in element. */ + unsigned int flags; + Tcl_HashEntry *hashPtr; - /* Fields specific to elements. */ - const char *label; /* Label displayed in legend */ - unsigned short row, col; /* Position of the entry in the + /* Fields specific to elements. */ + const char *label; /* Label displayed in legend */ + unsigned short row, col; /* Position of the entry in the * legend. */ - int legendRelief; /* Relief of label in legend. */ - Axis2d axes; /* X-axis and Y-axis mapping the - * element */ - ElemValues x, y, w; /* Contains array of floating point + int legendRelief; /* Relief of label in legend. */ + Axis2d axes; /* X-axis and Y-axis mapping the + * element */ + ElemValues x, y, w; /* Contains array of floating point * graph coordinate values. Also holds * min/max * and the number of * coordinates */ - int *activeIndices; /* Array of indices (malloc-ed) which + int *activeIndices; /* Array of indices (malloc-ed) which * indicate which data points are active * (drawn * with "active" colors). */ - int nActiveIndices; /* Number of active data points. + int nActiveIndices; /* Number of active data points. * Special case: if nActiveIndices < 0 * and the * active bit is set in * "flags", then all data points are * drawn active. */ - ElementProcs *procsPtr; - Blt_ConfigSpec *configSpecs; /* Configuration specifications. */ - LinePen *activePenPtr; /* Standard Pens */ - LinePen *normalPenPtr; - LinePen *builtinPenPtr; - Blt_Chain styles; /* Palette of pens. */ - - /* Symbol scaling */ - int scaleSymbols; /* If non-zero, the symbols will scale + ElementProcs *procsPtr; + Tk_OptionTable optionTable; /* Configuration specifications. */ + LinePen *activePenPtr; /* Standard Pens */ + LinePen *normalPenPtr; + LinePen *builtinPenPtr; + Blt_Chain stylesPalette; /* Palette of pens. */ + + /* Symbol scaling */ + int scaleSymbols; /* If non-zero, the symbols will scale * in size as the graph is zoomed * in/out. */ - double xRange, yRange; /* Initial X-axis and Y-axis ranges: + double xRange, yRange; /* Initial X-axis and Y-axis ranges: * used to scale the size of element's * symbol. */ - int state; - Blt_ChainLink link; /* Element's link in display list. */ + int state; + Blt_ChainLink link; /* Element's link in display list. */ - /* The line element specific fields start here. */ + /* The line element specific fields start here. */ - ElemValues xError; /* Relative/symmetric X error values. */ - ElemValues yError; /* Relative/symmetric Y error values. */ - ElemValues xHigh, xLow; /* Absolute/asymmetric X-coordinate + ElemValues xError; /* Relative/symmetric X error values. */ + ElemValues yError; /* Relative/symmetric Y error values. */ + ElemValues xHigh, xLow; /* Absolute/asymmetric X-coordinate * high/low error values. */ - ElemValues yHigh, yLow; /* Absolute/asymmetric Y-coordinate + ElemValues yHigh, yLow; /* Absolute/asymmetric Y-coordinate * high/low error values. */ - LinePen builtinPen; - int errorBarCapWidth; /* Length of cap on error bars */ - - /* Line smoothing */ - Smoothing reqSmooth; /* Requested smoothing function to use - * for connecting the data points */ - Smoothing smooth; /* Smoothing function used. */ - double rTolerance; /* Tolerance to reduce the number of + LinePen builtinPen; + int errorBarCapWidth; /* Length of cap on error bars */ + + /* Line smoothing */ + Smoothing reqSmooth; /* Requested smoothing function to use + * for connecting the data points */ + Smoothing smooth; /* Smoothing function used. */ + double rTolerance; /* Tolerance to reduce the number of * points displayed. */ - /* Drawing-related data structures. */ + /* Drawing-related data structures. */ - /* Area-under-curve fill attributes. */ - XColor *fillFgColor; - XColor *fillBgColor; - GC fillGC; + /* Area-under-curve fill attributes. */ + XColor *fillFgColor; + XColor *fillBgColor; + GC fillGC; - Tk_3DBorder fillBg; /* Background for fill area. */ + Tk_3DBorder fillBg; /* Background for fill area. */ - Point2d *fillPts; /* Array of points used to draw polygon + Point2d *fillPts; /* Array of points used to draw polygon * to fill area under the curve */ - int nFillPts; + int nFillPts; - /* Symbol points */ - GraphPoints symbolPts; + /* Symbol points */ + GraphPoints symbolPts; - /* Active symbol points */ - GraphPoints activePts; - GraphSegments xeb, yeb; /* Point to start of this pen's X-error + /* Active symbol points */ + GraphPoints activePts; + GraphSegments xeb, yeb; /* Point to start of this pen's X-error * bar segments in the element's * array. */ - int reqMaxSymbols; - int symbolInterval; - int symbolCounter; + int reqMaxSymbols; + int symbolInterval; + int symbolCounter; - /* X-Y graph-specific fields */ + /* X-Y graph-specific fields */ - int penDir; /* Indicates if a change in the pen + int penDir; /* Indicates if a change in the pen * direction should be considered a * retrace (line segment is not * drawn). */ - Blt_Chain traces; /* List of traces (a trace is a series + Blt_Chain traces; /* List of traces (a trace is a series * of contiguous line segments). New * traces are generated when either * the next segment changes the pen * direction, or the end point is * clipped by the plotting area. */ - /* Stripchart-specific fields */ + /* Stripchart-specific fields */ - GraphSegments lines; /* Holds the the line segments of the - * element trace. The segments are - * grouped by pen style. */ + GraphSegments lines; /* Holds the the line segments of the + * element trace. The segments are + * grouped by pen style. */ } LineElement; static Blt_OptionParseProc ObjToSmoothProc; static Blt_OptionPrintProc SmoothToObjProc; static Blt_CustomOption smoothOption = -{ + { ObjToSmoothProc, SmoothToObjProc, NULL, (ClientData)0 -}; + }; static Blt_OptionParseProc ObjToPenDirProc; static Blt_OptionPrintProc PenDirToObjProc; static Blt_CustomOption penDirOption = -{ + { ObjToPenDirProc, PenDirToObjProc, NULL, (ClientData)0 -}; + }; static Blt_OptionFreeProc FreeSymbolProc; static Blt_OptionParseProc ObjToSymbolProc; static Blt_OptionPrintProc SymbolToObjProc; static Blt_CustomOption symbolOption = -{ + { ObjToSymbolProc, SymbolToObjProc, FreeSymbolProc, (ClientData)0 -}; + }; extern Blt_CustomOption bltLineStylesOption; extern Blt_CustomOption bltColorOption; @@ -499,9 +495,9 @@ static Tk_OptionSpec lineElemOptionSpecs[] = { }; Blt_CustomOption bitmaskLineElemHideOption = -{ - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)HIDE -}; + { + ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)HIDE + }; static Blt_ConfigSpec lineElemConfigSpecs[] = { {BLT_CONFIG_CUSTOM, "-activepen", "activePen", "ActivePen", @@ -591,7 +587,7 @@ static Blt_ConfigSpec lineElemConfigSpecs[] = { {BLT_CONFIG_CUSTOM, "-state", "state", "State", DEF_LINE_STATE, Tk_Offset(LineElement, state), BLT_CONFIG_DONT_SET_DEFAULT, &stateOption}, {BLT_CONFIG_CUSTOM, "-styles", "styles", "Styles", DEF_LINE_STYLES, - Tk_Offset(LineElement, styles), 0, &bltLineStylesOption}, + Tk_Offset(LineElement, stylesPalette), 0, &bltLineStylesOption}, {BLT_CONFIG_CUSTOM, "-symbol", "symbol", "Symbol", DEF_LINE_SYMBOL, Tk_Offset(LineElement, builtinPen.symbol), BLT_CONFIG_DONT_SET_DEFAULT, &symbolOption}, @@ -758,10 +754,9 @@ static DistanceProc DistanceToYProc; static DistanceProc DistanceToXProc; static DistanceProc DistanceToLineProc; -INLINE static int -Round(double x) +INLINE static int Round(double x) { - return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); + return (int) (x + ((x < 0.0) ? -0.5 : 0.5)); } /* @@ -770,63 +765,43 @@ Round(double x) *--------------------------------------------------------------------------- */ -static void -DestroySymbol(Display *display, Symbol *symbolPtr) +static void DestroySymbol(Display *display, Symbol *symbolPtr) { - if (symbolPtr->image != NULL) { - Tk_FreeImage(symbolPtr->image); - symbolPtr->image = NULL; - } - if (symbolPtr->bitmap != None) { - Tk_FreeBitmap(display, symbolPtr->bitmap); - symbolPtr->bitmap = None; - } - if (symbolPtr->mask != None) { - Tk_FreeBitmap(display, symbolPtr->mask); - symbolPtr->mask = None; - } - symbolPtr->type = SYMBOL_NONE; + if (symbolPtr->image != NULL) { + Tk_FreeImage(symbolPtr->image); + symbolPtr->image = NULL; + } + if (symbolPtr->bitmap != None) { + Tk_FreeBitmap(display, symbolPtr->bitmap); + symbolPtr->bitmap = None; + } + if (symbolPtr->mask != None) { + Tk_FreeBitmap(display, symbolPtr->mask); + symbolPtr->mask = None; + } + symbolPtr->type = SYMBOL_NONE; } -/* - *--------------------------------------------------------------------------- - * - * ImageChangedProc - * - * - * Results: - * None. - * - *--------------------------------------------------------------------------- - */ -/* ARGSUSED */ -static void -ImageChangedProc( - ClientData clientData, - int x, int y, int w, int h, /* Not used. */ - int imageWidth, int imageHeight) /* Not used. */ +static void ImageChangedProc(ClientData clientData, + int x, int y, int w, int h, + int imageWidth, int imageHeight) { - Element *elemPtr; - Graph *graphPtr; - - elemPtr = clientData; - elemPtr->flags |= MAP_ITEM; - graphPtr = elemPtr->obj.graphPtr; - graphPtr->flags |= CACHE_DIRTY; - Blt_EventuallyRedrawGraph(graphPtr); + Element *elemPtr; + Graph *graphPtr; + + elemPtr = clientData; + elemPtr->flags |= MAP_ITEM; + graphPtr = elemPtr->obj.graphPtr; + graphPtr->flags |= CACHE_DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); } -/*ARGSUSED*/ -static void -FreeSymbolProc( - ClientData clientData, /* Not used. */ - Display *display, /* Not used. */ - char *widgRec, - int offset) +static void FreeSymbolProc(ClientData clientData, Display *display, + char *widgRec, int offset) { - Symbol *symbolPtr = (Symbol *)(widgRec + offset); + Symbol *symbolPtr = (Symbol *)(widgRec + offset); - DestroySymbol(display, symbolPtr); + DestroySymbol(display, symbolPtr); } /* @@ -843,340 +818,209 @@ FreeSymbolProc( * *--------------------------------------------------------------------------- */ -/*ARGSUSED*/ -static int -ObjToSymbolProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back - * to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* String representing symbol type */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ + +static int ObjToSymbolProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - Symbol *symbolPtr = (Symbol *)(widgRec + offset); - const char *string; + Symbol *symbolPtr = (Symbol *)(widgRec + offset); + const char *string; - { - int length; - GraphSymbolType *p; - char c; - - string = Tcl_GetStringFromObj(objPtr, &length); - if (length == 0) { - DestroySymbol(Tk_Display(tkwin), symbolPtr); - symbolPtr->type = SYMBOL_NONE; - return TCL_OK; - } - c = string[0]; - for (p = graphSymbols; p->name != NULL; p++) { - if (length < p->minChars) { - continue; - } - if ((c == p->name[0]) && (strncmp(string, p->name, length) == 0)) { - DestroySymbol(Tk_Display(tkwin), symbolPtr); - symbolPtr->type = p->type; - return TCL_OK; - } - } - } - { - Tk_Image tkImage; - Element *elemPtr = (Element *)widgRec; - - tkImage = Tk_GetImage(interp, tkwin, string, ImageChangedProc, elemPtr); - if (tkImage != NULL) { - DestroySymbol(Tk_Display(tkwin), symbolPtr); - symbolPtr->image = tkImage; - symbolPtr->type = SYMBOL_IMAGE; - return TCL_OK; - } - } - { - Pixmap bitmap, mask; - Tcl_Obj **objv; - int objc; + { + int length; + GraphSymbolType *p; + char c; - if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) || - (objc > 2)) { - goto error; - } - bitmap = mask = None; - if (objc > 0) { - bitmap = Tk_AllocBitmapFromObj((Tcl_Interp *)NULL, tkwin, objv[0]); - if (bitmap == None) { - goto error; - } - } - if (objc > 1) { - mask = Tk_AllocBitmapFromObj((Tcl_Interp *)NULL, tkwin, objv[1]); - if (mask == None) { - goto error; - } - } + string = Tcl_GetStringFromObj(objPtr, &length); + if (length == 0) { + DestroySymbol(Tk_Display(tkwin), symbolPtr); + symbolPtr->type = SYMBOL_NONE; + return TCL_OK; + } + c = string[0]; + for (p = graphSymbols; p->name != NULL; p++) { + if (length < p->minChars) { + continue; + } + if ((c == p->name[0]) && (strncmp(string, p->name, length) == 0)) { DestroySymbol(Tk_Display(tkwin), symbolPtr); - symbolPtr->bitmap = bitmap; - symbolPtr->mask = mask; - symbolPtr->type = SYMBOL_BITMAP; + symbolPtr->type = p->type; return TCL_OK; - } + } + } + } + { + Tk_Image tkImage; + Element *elemPtr = (Element *)widgRec; + + tkImage = Tk_GetImage(interp, tkwin, string, ImageChangedProc, elemPtr); + if (tkImage != NULL) { + DestroySymbol(Tk_Display(tkwin), symbolPtr); + symbolPtr->image = tkImage; + symbolPtr->type = SYMBOL_IMAGE; + return TCL_OK; + } + } + { + Pixmap bitmap, mask; + Tcl_Obj **objv; + int objc; + + if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) || + (objc > 2)) { + goto error; + } + bitmap = mask = None; + if (objc > 0) { + bitmap = Tk_AllocBitmapFromObj((Tcl_Interp *)NULL, tkwin, objv[0]); + if (bitmap == None) { + goto error; + } + } + if (objc > 1) { + mask = Tk_AllocBitmapFromObj((Tcl_Interp *)NULL, tkwin, objv[1]); + if (mask == None) { + goto error; + } + } + DestroySymbol(Tk_Display(tkwin), symbolPtr); + symbolPtr->bitmap = bitmap; + symbolPtr->mask = mask; + symbolPtr->type = SYMBOL_BITMAP; + return TCL_OK; + } error: - Tcl_AppendResult(interp, "bad symbol \"", string, - "\": should be \"none\", \"circle\", \"square\", \"diamond\", " - "\"plus\", \"cross\", \"splus\", \"scross\", \"triangle\", " - "\"arrow\" or the name of a bitmap", (char *)NULL); - return TCL_ERROR; + Tcl_AppendResult(interp, "bad symbol \"", string, + "\": should be \"none\", \"circle\", \"square\", \"diamond\", " + "\"plus\", \"cross\", \"splus\", \"scross\", \"triangle\", " + "\"arrow\" or the name of a bitmap", (char *)NULL); + return TCL_ERROR; } -/* - *--------------------------------------------------------------------------- - * - * SymbolToObj -- - * - * Convert the symbol value into a string. - * - * Results: - * The string representing the symbol type or line style is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -SymbolToObjProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, - Tk_Window tkwin, - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static Tcl_Obj* SymbolToObjProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) { - Symbol *symbolPtr = (Symbol *)(widgRec + offset); - - if (symbolPtr->type == SYMBOL_BITMAP) { - Tcl_Obj *listObjPtr, *objPtr; - const char *name; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - name = Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->bitmap); - objPtr = Tcl_NewStringObj(name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - if (symbolPtr->mask == None) { - objPtr = Tcl_NewStringObj("", -1); - } else { - name = Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->mask); - objPtr = Tcl_NewStringObj(name, -1); - } - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - return listObjPtr; + Symbol *symbolPtr = (Symbol *)(widgRec + offset); + + if (symbolPtr->type == SYMBOL_BITMAP) { + Tcl_Obj *listObjPtr, *objPtr; + const char *name; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + name = Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->bitmap); + objPtr = Tcl_NewStringObj(name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + if (symbolPtr->mask == None) { + objPtr = Tcl_NewStringObj("", -1); } else { - GraphSymbolType *p; + name = Tk_NameOfBitmap(Tk_Display(tkwin), symbolPtr->mask); + objPtr = Tcl_NewStringObj(name, -1); + } + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + return listObjPtr; + } else { + GraphSymbolType *p; - for (p = graphSymbols; p->name != NULL; p++) { - if (p->type == symbolPtr->type) { - return Tcl_NewStringObj(p->name, -1); - } - } - return Tcl_NewStringObj("?unknown symbol type?", -1); + for (p = graphSymbols; p->name != NULL; p++) { + if (p->type == symbolPtr->type) { + return Tcl_NewStringObj(p->name, -1); + } } + return Tcl_NewStringObj("?unknown symbol type?", -1); + } } -/* - *--------------------------------------------------------------------------- - * - * NameOfSmooth -- - * - * Converts the smooth value into its string representation. - * - * Results: - * The static string representing the smooth type is returned. - * - *--------------------------------------------------------------------------- - */ -static const char * -NameOfSmooth(Smoothing value) +static const char* NameOfSmooth(Smoothing value) { - SmoothingInfo *siPtr; + SmoothingInfo *siPtr; - for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) { - if (siPtr->value == value) { - return siPtr->name; - } + for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) { + if (siPtr->value == value) { + return siPtr->name; } - return "unknown smooth value"; + } + return "unknown smooth value"; } -/* - *--------------------------------------------------------------------------- - * - * ObjToSmooth -- - * - * Convert the string representation of a line style or smooth name - * into its numeric form. - * - * Results: - * The return value is a standard TCL result. The smooth type is - * written into the widget record. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToSmoothProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back - * to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* String representing smooth type */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static int ObjToSmoothProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - Smoothing *valuePtr = (Smoothing *)(widgRec + offset); - SmoothingInfo *siPtr; - const char *string; - char c; - - string = Tcl_GetString(objPtr); - c = string[0]; - for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) { - if ((c == siPtr->name[0]) && (strcmp(string, siPtr->name) == 0)) { - *valuePtr = siPtr->value; - return TCL_OK; - } - } - Tcl_AppendResult(interp, "bad smooth value \"", string, "\": should be \ + Smoothing *valuePtr = (Smoothing *)(widgRec + offset); + SmoothingInfo *siPtr; + const char *string; + char c; + + string = Tcl_GetString(objPtr); + c = string[0]; + for (siPtr = smoothingInfo; siPtr->name != NULL; siPtr++) { + if ((c == siPtr->name[0]) && (strcmp(string, siPtr->name) == 0)) { + *valuePtr = siPtr->value; + return TCL_OK; + } + } + Tcl_AppendResult(interp, "bad smooth value \"", string, "\": should be \ linear, step, natural, or quadratic", (char *)NULL); - return TCL_ERROR; + return TCL_ERROR; } -/* - *--------------------------------------------------------------------------- - * - * SmoothToObj -- - * - * Convert the smooth value into a string. - * - * Results: - * The string representing the smooth type or line style is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -SmoothToObjProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Not used. */ - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static Tcl_Obj* SmoothToObjProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) { - int smooth = *(int *)(widgRec + offset); + int smooth = *(int *)(widgRec + offset); - return Tcl_NewStringObj(NameOfSmooth(smooth), -1); + return Tcl_NewStringObj(NameOfSmooth(smooth), -1); } -/* - *--------------------------------------------------------------------------- - * - * ObjToPenDir -- - * - * Convert the string representation of a line style or symbol name - * into its numeric form. - * - * Results: - * The return value is a standard TCL result. The symbol type is - * written into the widget record. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToPenDirProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back - * to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* String representing pen direction */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static int ObjToPenDirProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - int *penDirPtr = (int *)(widgRec + offset); - int length; - char c; - char *string; - - string = Tcl_GetStringFromObj(objPtr, &length); - c = string[0]; - if ((c == 'i') && (strncmp(string, "increasing", length) == 0)) { - *penDirPtr = PEN_INCREASING; - } else if ((c == 'd') && (strncmp(string, "decreasing", length) == 0)) { - *penDirPtr = PEN_DECREASING; - } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { - *penDirPtr = PEN_BOTH_DIRECTIONS; - } else { - Tcl_AppendResult(interp, "bad trace value \"", string, - "\" : should be \"increasing\", \"decreasing\", or \"both\"", - (char *)NULL); - return TCL_ERROR; - } - return TCL_OK; + int *penDirPtr = (int *)(widgRec + offset); + int length; + char c; + char *string; + + string = Tcl_GetStringFromObj(objPtr, &length); + c = string[0]; + if ((c == 'i') && (strncmp(string, "increasing", length) == 0)) { + *penDirPtr = PEN_INCREASING; + } else if ((c == 'd') && (strncmp(string, "decreasing", length) == 0)) { + *penDirPtr = PEN_DECREASING; + } else if ((c == 'b') && (strncmp(string, "both", length) == 0)) { + *penDirPtr = PEN_BOTH_DIRECTIONS; + } else { + Tcl_AppendResult(interp, "bad trace value \"", string, + "\" : should be \"increasing\", \"decreasing\", or \"both\"", + (char *)NULL); + return TCL_ERROR; + } + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * NameOfPenDir -- - * - * Convert the pen direction into a string. - * - * Results: - * The static string representing the pen direction is returned. - * - *--------------------------------------------------------------------------- - */ -static const char * -NameOfPenDir(int penDir) +static const char* NameOfPenDir(int penDir) { - switch (penDir) { - case PEN_INCREASING: - return "increasing"; - case PEN_DECREASING: - return "decreasing"; - case PEN_BOTH_DIRECTIONS: - return "both"; - default: - return "unknown trace direction"; - } + switch (penDir) { + case PEN_INCREASING: + return "increasing"; + case PEN_DECREASING: + return "decreasing"; + case PEN_BOTH_DIRECTIONS: + return "both"; + default: + return "unknown trace direction"; + } } -/* - *--------------------------------------------------------------------------- - * - * PenDirToObj -- - * - * Convert the pen direction into a string. - * - * Results: - * The string representing the pen drawing direction is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -PenDirToObjProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Not used. */ - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static Tcl_Obj* PenDirToObjProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) { - int penDir = *(int *)(widgRec + offset); + int penDir = *(int *)(widgRec + offset); - return Tcl_NewStringObj(NameOfPenDir(penDir), -1); + return Tcl_NewStringObj(NameOfPenDir(penDir), -1); } @@ -1184,234 +1028,194 @@ PenDirToObjProc( * Reset the number of points and segments, in case there are no segments or * points */ -static void -ResetStylePalette(Blt_Chain styles) +static void ResetStylePalette(Blt_Chain styles) { - Blt_ChainLink link; + Blt_ChainLink link; - for (link = Blt_Chain_FirstLink(styles); link != NULL; - link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; + for (link = Blt_Chain_FirstLink(styles); link != NULL; + link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; - stylePtr = Blt_Chain_GetValue(link); - stylePtr->lines.length = stylePtr->symbolPts.length = 0; - stylePtr->xeb.length = stylePtr->yeb.length = 0; - } + stylePtr = Blt_Chain_GetValue(link); + stylePtr->lines.length = stylePtr->symbolPts.length = 0; + stylePtr->xeb.length = stylePtr->yeb.length = 0; + } } -/* - *--------------------------------------------------------------------------- - * - * ConfigurePenProc -- - * - * Sets up the appropriate configuration parameters in the GC. It is - * assumed the parameters have been previously set by a call to - * Blt_ConfigureWidget. - * - * Results: - * The return value is a standard TCL result. If TCL_ERROR is returned, - * then interp->result contains an error message. - * - * Side effects: - * Configuration information such as line width, line style, color - * etc. get set in a new GC. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ConfigurePenProc(Graph *graphPtr, Pen *penPtr) +static int ConfigurePenProc(Graph* graphPtr, Pen* penPtr) { - LinePen *lpPtr = (LinePen *)penPtr; - unsigned long gcMask; - GC newGC; - XGCValues gcValues; - XColor *colorPtr; - - /* - * Set the outline GC for this pen: GCForeground is outline color. - * GCBackground is the fill color (only used for bitmap symbols). - */ - gcMask = (GCLineWidth | GCForeground); - colorPtr = lpPtr->symbol.outlineColor; - if (colorPtr == COLOR_DEFAULT) { - colorPtr = lpPtr->traceColor; - } - gcValues.foreground = colorPtr->pixel; - if (lpPtr->symbol.type == SYMBOL_BITMAP) { - colorPtr = lpPtr->symbol.fillColor; - if (colorPtr == COLOR_DEFAULT) { - colorPtr = lpPtr->traceColor; - } - /* - * Set a clip mask if either - * 1) no background color was designated or - * 2) a masking bitmap was specified. - * - * These aren't necessarily the bitmaps we'll be using for clipping. But - * this makes it unlikely that anyone else will be sharing this GC when - * we set the clip origin (at the time the bitmap is drawn). - */ - if (colorPtr != NULL) { - gcValues.background = colorPtr->pixel; - gcMask |= GCBackground; - if (lpPtr->symbol.mask != None) { - gcValues.clip_mask = lpPtr->symbol.mask; - gcMask |= GCClipMask; - } - } else { - gcValues.clip_mask = lpPtr->symbol.bitmap; - gcMask |= GCClipMask; - } - } - gcValues.line_width = LineWidth(lpPtr->symbol.outlineWidth); - newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - if (lpPtr->symbol.outlineGC != NULL) { - Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC); - } - lpPtr->symbol.outlineGC = newGC; - - /* Fill GC for symbols: GCForeground is fill color */ - - gcMask = (GCLineWidth | GCForeground); + LinePen* lpPtr = (LinePen*)penPtr; + unsigned long gcMask; + GC newGC; + XGCValues gcValues; + XColor *colorPtr; + + /* + * Set the outline GC for this pen: GCForeground is outline color. + * GCBackground is the fill color (only used for bitmap symbols). + */ + gcMask = (GCLineWidth | GCForeground); + colorPtr = lpPtr->symbol.outlineColor; + if (colorPtr == COLOR_DEFAULT) { + colorPtr = lpPtr->traceColor; + } + gcValues.foreground = colorPtr->pixel; + if (lpPtr->symbol.type == SYMBOL_BITMAP) { colorPtr = lpPtr->symbol.fillColor; if (colorPtr == COLOR_DEFAULT) { - colorPtr = lpPtr->traceColor; - } - newGC = NULL; - if (colorPtr != NULL) { - gcValues.foreground = colorPtr->pixel; - newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - } - if (lpPtr->symbol.fillGC != NULL) { - Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC); - } - lpPtr->symbol.fillGC = newGC; - - /* Line segments */ - - gcMask = (GCLineWidth | GCForeground | GCLineStyle | GCCapStyle | - GCJoinStyle); - gcValues.cap_style = CapButt; - gcValues.join_style = JoinRound; - gcValues.line_style = LineSolid; - gcValues.line_width = LineWidth(lpPtr->traceWidth); - - colorPtr = lpPtr->traceOffColor; - if (colorPtr == COLOR_DEFAULT) { - colorPtr = lpPtr->traceColor; + colorPtr = lpPtr->traceColor; } + /* + * Set a clip mask if either + * 1) no background color was designated or + * 2) a masking bitmap was specified. + * + * These aren't necessarily the bitmaps we'll be using for clipping. But + * this makes it unlikely that anyone else will be sharing this GC when + * we set the clip origin (at the time the bitmap is drawn). + */ if (colorPtr != NULL) { - gcMask |= GCBackground; - gcValues.background = colorPtr->pixel; - } - gcValues.foreground = lpPtr->traceColor->pixel; - if (LineIsDashed(lpPtr->traceDashes)) { - gcValues.line_width = lpPtr->traceWidth; - gcValues.line_style = - (colorPtr == NULL) ? LineOnOffDash : LineDoubleDash; - } - newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); - if (lpPtr->traceGC != NULL) { - Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC); - } - if (LineIsDashed(lpPtr->traceDashes)) { - lpPtr->traceDashes.offset = lpPtr->traceDashes.values[0] / 2; - Blt_SetDashes(graphPtr->display, newGC, &lpPtr->traceDashes); - } - lpPtr->traceGC = newGC; - - gcMask = (GCLineWidth | GCForeground); - colorPtr = lpPtr->errorBarColor; - if (colorPtr == COLOR_DEFAULT) { - colorPtr = lpPtr->traceColor; - } - gcValues.line_width = LineWidth(lpPtr->errorBarLineWidth); + gcValues.background = colorPtr->pixel; + gcMask |= GCBackground; + if (lpPtr->symbol.mask != None) { + gcValues.clip_mask = lpPtr->symbol.mask; + gcMask |= GCClipMask; + } + } else { + gcValues.clip_mask = lpPtr->symbol.bitmap; + gcMask |= GCClipMask; + } + } + gcValues.line_width = LineWidth(lpPtr->symbol.outlineWidth); + newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); + if (lpPtr->symbol.outlineGC != NULL) { + Tk_FreeGC(graphPtr->display, lpPtr->symbol.outlineGC); + } + lpPtr->symbol.outlineGC = newGC; + + /* Fill GC for symbols: GCForeground is fill color */ + + gcMask = (GCLineWidth | GCForeground); + colorPtr = lpPtr->symbol.fillColor; + if (colorPtr == COLOR_DEFAULT) { + colorPtr = lpPtr->traceColor; + } + newGC = NULL; + if (colorPtr != NULL) { gcValues.foreground = colorPtr->pixel; newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - if (lpPtr->errorBarGC != NULL) { - Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC); - } - lpPtr->errorBarGC = newGC; - - return TCL_OK; + } + if (lpPtr->symbol.fillGC != NULL) { + Tk_FreeGC(graphPtr->display, lpPtr->symbol.fillGC); + } + lpPtr->symbol.fillGC = newGC; + + /* Line segments */ + + gcMask = (GCLineWidth | GCForeground | GCLineStyle | GCCapStyle | + GCJoinStyle); + gcValues.cap_style = CapButt; + gcValues.join_style = JoinRound; + gcValues.line_style = LineSolid; + gcValues.line_width = LineWidth(lpPtr->traceWidth); + + colorPtr = lpPtr->traceOffColor; + if (colorPtr == COLOR_DEFAULT) { + colorPtr = lpPtr->traceColor; + } + if (colorPtr != NULL) { + gcMask |= GCBackground; + gcValues.background = colorPtr->pixel; + } + gcValues.foreground = lpPtr->traceColor->pixel; + if (LineIsDashed(lpPtr->traceDashes)) { + gcValues.line_width = lpPtr->traceWidth; + gcValues.line_style = + (colorPtr == NULL) ? LineOnOffDash : LineDoubleDash; + } + newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues); + if (lpPtr->traceGC != NULL) { + Blt_FreePrivateGC(graphPtr->display, lpPtr->traceGC); + } + if (LineIsDashed(lpPtr->traceDashes)) { + lpPtr->traceDashes.offset = lpPtr->traceDashes.values[0] / 2; + Blt_SetDashes(graphPtr->display, newGC, &lpPtr->traceDashes); + } + lpPtr->traceGC = newGC; + + gcMask = (GCLineWidth | GCForeground); + colorPtr = lpPtr->errorBarColor; + if (colorPtr == COLOR_DEFAULT) { + colorPtr = lpPtr->traceColor; + } + gcValues.line_width = LineWidth(lpPtr->errorBarLineWidth); + gcValues.foreground = colorPtr->pixel; + newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); + if (lpPtr->errorBarGC != NULL) { + Tk_FreeGC(graphPtr->display, lpPtr->errorBarGC); + } + lpPtr->errorBarGC = newGC; + + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * DestroyPenProc -- - * - * Release memory and resources allocated for the style. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the pen style is freed up. - * - *--------------------------------------------------------------------------- - */ -static void -DestroyPenProc(Graph *graphPtr, Pen *basePtr) +static void DestroyPenProc(Graph* graphPtr, Pen* basePtr) { - LinePen *penPtr = (LinePen *)basePtr; - - Blt_Ts_FreeStyle(graphPtr->display, &penPtr->valueStyle); - if (penPtr->symbol.outlineGC != NULL) { - Tk_FreeGC(graphPtr->display, penPtr->symbol.outlineGC); - } - if (penPtr->symbol.fillGC != NULL) { - Tk_FreeGC(graphPtr->display, penPtr->symbol.fillGC); - } - if (penPtr->errorBarGC != NULL) { - Tk_FreeGC(graphPtr->display, penPtr->errorBarGC); - } - if (penPtr->traceGC != NULL) { - Blt_FreePrivateGC(graphPtr->display, penPtr->traceGC); - } - if (penPtr->symbol.bitmap != None) { - Tk_FreeBitmap(graphPtr->display, penPtr->symbol.bitmap); - penPtr->symbol.bitmap = None; - } - if (penPtr->symbol.mask != None) { - Tk_FreeBitmap(graphPtr->display, penPtr->symbol.mask); - penPtr->symbol.mask = None; - } + LinePen* penPtr = (LinePen*)basePtr; + Tk_FreeConfigOptions((char*)penPtr, penPtr->optionTable, graphPtr->tkwin); + Tk_DeleteOptionTable(penPtr->optionTable); + + Blt_Ts_FreeStyle(graphPtr->display, &penPtr->valueStyle); + if (penPtr->symbol.outlineGC != NULL) { + Tk_FreeGC(graphPtr->display, penPtr->symbol.outlineGC); + } + if (penPtr->symbol.fillGC != NULL) { + Tk_FreeGC(graphPtr->display, penPtr->symbol.fillGC); + } + if (penPtr->errorBarGC != NULL) { + Tk_FreeGC(graphPtr->display, penPtr->errorBarGC); + } + if (penPtr->traceGC != NULL) { + Blt_FreePrivateGC(graphPtr->display, penPtr->traceGC); + } + if (penPtr->symbol.bitmap != None) { + Tk_FreeBitmap(graphPtr->display, penPtr->symbol.bitmap); + penPtr->symbol.bitmap = None; + } + if (penPtr->symbol.mask != None) { + Tk_FreeBitmap(graphPtr->display, penPtr->symbol.mask); + penPtr->symbol.mask = None; + } } - -static void -InitLinePen(LinePen *penPtr) +static void InitLinePen(Graph* graphPtr, LinePen* penPtr) { - Blt_Ts_InitStyle(penPtr->valueStyle); - penPtr->errorBarLineWidth = 1; - penPtr->errorBarShow = SHOW_BOTH; - penPtr->configProc = ConfigurePenProc; - penPtr->configSpecs = linePenConfigSpecs; - penPtr->destroyProc = DestroyPenProc; - penPtr->flags = NORMAL_PEN; - penPtr->name = ""; - penPtr->symbol.bitmap = penPtr->symbol.mask = None; - penPtr->symbol.outlineColor = penPtr->symbol.fillColor = COLOR_DEFAULT; - penPtr->symbol.outlineWidth = penPtr->traceWidth = 1; - penPtr->symbol.type = SYMBOL_NONE; - penPtr->valueShow = SHOW_NONE; + Blt_Ts_InitStyle(penPtr->valueStyle); + penPtr->errorBarLineWidth = 1; + penPtr->errorBarShow = SHOW_BOTH; + penPtr->configProc = ConfigurePenProc; + penPtr->optionTable = + Tk_CreateOptionTable(graphPtr->interp, linePenOptionSpecs); + penPtr->destroyProc = DestroyPenProc; + penPtr->flags = NORMAL_PEN; + penPtr->name = ""; + penPtr->symbol.bitmap = penPtr->symbol.mask = None; + penPtr->symbol.outlineColor = penPtr->symbol.fillColor = COLOR_DEFAULT; + penPtr->symbol.outlineWidth = penPtr->traceWidth = 1; + penPtr->symbol.type = SYMBOL_NONE; + penPtr->valueShow = SHOW_NONE; } -Pen * -Blt_LinePen(const char *penName) +Pen* Blt_LinePen(Graph* graphPtr, const char* penName) { - LinePen *penPtr; - - penPtr = calloc(1, sizeof(LinePen)); - InitLinePen(penPtr); - penPtr->name = Blt_Strdup(penName); - penPtr->classId = CID_ELEM_LINE; - if (strcmp(penName, "activeLine") == 0) { - penPtr->flags = ACTIVE_PEN; - } - return (Pen *)penPtr; + LinePen *penPtr = calloc(1, sizeof(LinePen)); + InitLinePen(graphPtr, penPtr); + penPtr->name = Blt_Strdup(penName); + penPtr->classId = CID_ELEM_LINE; + if (strcmp(penName, "activeLine") == 0) { + penPtr->flags = ACTIVE_PEN; + } + return (Pen *)penPtr; } /* @@ -1441,48 +1245,47 @@ Blt_LinePen(const char *penName) * *--------------------------------------------------------------------------- */ -static int -ScaleSymbol(LineElement *elemPtr, int normalSize) +static int ScaleSymbol(LineElement *elemPtr, int normalSize) { - int maxSize; - double scale; - int newSize; - - scale = 1.0; - if (elemPtr->scaleSymbols) { - double xRange, yRange; - - xRange = (elemPtr->axes.x->max - elemPtr->axes.x->min); - yRange = (elemPtr->axes.y->max - elemPtr->axes.y->min); - if (elemPtr->flags & SCALE_SYMBOL) { - /* Save the ranges as a baseline for future scaling. */ - elemPtr->xRange = xRange; - elemPtr->yRange = yRange; - elemPtr->flags &= ~SCALE_SYMBOL; - } else { - double xScale, yScale; - - /* Scale the symbol by the smallest change in the X or Y axes */ - xScale = elemPtr->xRange / xRange; - yScale = elemPtr->yRange / yRange; - scale = MIN(xScale, yScale); - } - } - newSize = Round(normalSize * scale); - - /* - * Don't let the size of symbols go unbounded. Both X and Win32 drawing - * routines assume coordinates to be a signed short int. - */ - maxSize = (int)MIN(elemPtr->obj.graphPtr->hRange, - elemPtr->obj.graphPtr->vRange); - if (newSize > maxSize) { - newSize = maxSize; - } - - /* Make the symbol size odd so that its center is a single pixel. */ - newSize |= 0x01; - return newSize; + int maxSize; + double scale; + int newSize; + + scale = 1.0; + if (elemPtr->scaleSymbols) { + double xRange, yRange; + + xRange = (elemPtr->axes.x->max - elemPtr->axes.x->min); + yRange = (elemPtr->axes.y->max - elemPtr->axes.y->min); + if (elemPtr->flags & SCALE_SYMBOL) { + /* Save the ranges as a baseline for future scaling. */ + elemPtr->xRange = xRange; + elemPtr->yRange = yRange; + elemPtr->flags &= ~SCALE_SYMBOL; + } else { + double xScale, yScale; + + /* Scale the symbol by the smallest change in the X or Y axes */ + xScale = elemPtr->xRange / xRange; + yScale = elemPtr->yRange / yRange; + scale = MIN(xScale, yScale); + } + } + newSize = Round(normalSize * scale); + + /* + * Don't let the size of symbols go unbounded. Both X and Win32 drawing + * routines assume coordinates to be a signed short int. + */ + maxSize = (int)MIN(elemPtr->obj.graphPtr->hRange, + elemPtr->obj.graphPtr->vRange); + if (newSize > maxSize) { + newSize = maxSize; + } + + /* Make the symbol size odd so that its center is a single pixel. */ + newSize |= 0x01; + return newSize; } /* @@ -1507,44 +1310,44 @@ ScaleSymbol(LineElement *elemPtr, int normalSize) * *--------------------------------------------------------------------------- */ -static void -GetScreenPoints(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void GetScreenPoints(Graph *graphPtr, LineElement *elemPtr, + MapInfo *mapPtr) { - double *x, *y; - int i, np; - int count; - Point2d *points; - int *map; - - np = NUMBEROFPOINTS(elemPtr); - x = elemPtr->x.values; - y = elemPtr->y.values; - points = malloc(sizeof(Point2d) * np); - map = malloc(sizeof(int) * np); - - count = 0; /* Count the valid screen coordinates */ - if (graphPtr->inverted) { - for (i = 0; i < np; i++) { - if ((isfinite(x[i])) && (isfinite(y[i]))) { - points[count].x = Blt_HMap(elemPtr->axes.y, y[i]); - points[count].y = Blt_VMap(elemPtr->axes.x, x[i]); - map[count] = i; - count++; - } - } - } else { - for (i = 0; i < np; i++) { - if ((isfinite(x[i])) && (isfinite(y[i]))) { - points[count].x = Blt_HMap(elemPtr->axes.x, x[i]); - points[count].y = Blt_VMap(elemPtr->axes.y, y[i]); - map[count] = i; - count++; - } - } + double *x, *y; + int i, np; + int count; + Point2d *points; + int *map; + + np = NUMBEROFPOINTS(elemPtr); + x = elemPtr->x.values; + y = elemPtr->y.values; + points = malloc(sizeof(Point2d) * np); + map = malloc(sizeof(int) * np); + + count = 0; /* Count the valid screen coordinates */ + if (graphPtr->inverted) { + for (i = 0; i < np; i++) { + if ((isfinite(x[i])) && (isfinite(y[i]))) { + points[count].x = Blt_HMap(elemPtr->axes.y, y[i]); + points[count].y = Blt_VMap(elemPtr->axes.x, x[i]); + map[count] = i; + count++; + } } - mapPtr->screenPts = points; - mapPtr->nScreenPts = count; - mapPtr->map = map; + } else { + for (i = 0; i < np; i++) { + if ((isfinite(x[i])) && (isfinite(y[i]))) { + points[count].x = Blt_HMap(elemPtr->axes.x, x[i]); + points[count].y = Blt_VMap(elemPtr->axes.y, y[i]); + map[count] = i; + count++; + } + } + } + mapPtr->screenPts = points; + mapPtr->nScreenPts = count; + mapPtr->map = map; } /* @@ -1563,31 +1366,30 @@ GetScreenPoints(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) * *--------------------------------------------------------------------------- */ -static void -ReducePoints(MapInfo *mapPtr, double tolerance) +static void ReducePoints(MapInfo *mapPtr, double tolerance) { - int i, np; - Point2d *screenPts; - int *map, *simple; - - simple = malloc(mapPtr->nScreenPts * sizeof(int)); - map = malloc(mapPtr->nScreenPts * sizeof(int)); - screenPts = malloc(mapPtr->nScreenPts * sizeof(Point2d)); - np = Blt_SimplifyLine(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1, - tolerance, simple); - for (i = 0; i < np; i++) { - int k; - - k = simple[i]; - screenPts[i] = mapPtr->screenPts[k]; - map[i] = mapPtr->map[k]; - } - free(mapPtr->screenPts); - free(mapPtr->map); - free(simple); - mapPtr->screenPts = screenPts; - mapPtr->map = map; - mapPtr->nScreenPts = np; + int i, np; + Point2d *screenPts; + int *map, *simple; + + simple = malloc(mapPtr->nScreenPts * sizeof(int)); + map = malloc(mapPtr->nScreenPts * sizeof(int)); + screenPts = malloc(mapPtr->nScreenPts * sizeof(Point2d)); + np = Blt_SimplifyLine(mapPtr->screenPts, 0, mapPtr->nScreenPts - 1, + tolerance, simple); + for (i = 0; i < np; i++) { + int k; + + k = simple[i]; + screenPts[i] = mapPtr->screenPts[k]; + map[i] = mapPtr->map[k]; + } + free(mapPtr->screenPts); + free(mapPtr->map); + free(simple); + mapPtr->screenPts = screenPts; + mapPtr->map = map; + mapPtr->nScreenPts = np; } /* @@ -1607,38 +1409,37 @@ ReducePoints(MapInfo *mapPtr, double tolerance) * *--------------------------------------------------------------------------- */ -static void -GenerateSteps(MapInfo *mapPtr) +static void GenerateSteps(MapInfo *mapPtr) { - int newSize; - int i, count; - Point2d *screenPts; - int *map; - - newSize = ((mapPtr->nScreenPts - 1) * 2) + 1; - screenPts = malloc(newSize * sizeof(Point2d)); - map = malloc(sizeof(int) * newSize); - screenPts[0] = mapPtr->screenPts[0]; - map[0] = 0; - - count = 1; - for (i = 1; i < mapPtr->nScreenPts; i++) { - screenPts[count + 1] = mapPtr->screenPts[i]; - - /* Hold last y-coordinate, use new x-coordinate */ - screenPts[count].x = screenPts[count + 1].x; - screenPts[count].y = screenPts[count - 1].y; - - /* Use the same style for both the hold and the step points */ - map[count] = map[count + 1] = mapPtr->map[i]; - count += 2; - } - free(mapPtr->screenPts); - free(mapPtr->map); - mapPtr->map = map; - mapPtr->screenPts = screenPts; - mapPtr->nScreenPts = newSize; -} + int newSize; + int i, count; + Point2d *screenPts; + int *map; + + newSize = ((mapPtr->nScreenPts - 1) * 2) + 1; + screenPts = malloc(newSize * sizeof(Point2d)); + map = malloc(sizeof(int) * newSize); + screenPts[0] = mapPtr->screenPts[0]; + map[0] = 0; + + count = 1; + for (i = 1; i < mapPtr->nScreenPts; i++) { + screenPts[count + 1] = mapPtr->screenPts[i]; + + /* Hold last y-coordinate, use new x-coordinate */ + screenPts[count].x = screenPts[count + 1].x; + screenPts[count].y = screenPts[count - 1].y; + + /* Use the same style for both the hold and the step points */ + map[count] = map[count + 1] = mapPtr->map[i]; + count += 2; + } + free(mapPtr->screenPts); + free(mapPtr->map); + mapPtr->map = map; + mapPtr->screenPts = screenPts; + mapPtr->nScreenPts = newSize; +} /* *--------------------------------------------------------------------------- @@ -1661,107 +1462,106 @@ GenerateSteps(MapInfo *mapPtr) * *--------------------------------------------------------------------------- */ -static void -GenerateSpline(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void GenerateSpline(Graph *graphPtr, LineElement *elemPtr, + MapInfo *mapPtr) { - Point2d *origPts, *iPts; - int *map; - int extra; - int niPts, nOrigPts; - int result; - int i, j, count; - - nOrigPts = mapPtr->nScreenPts; - origPts = mapPtr->screenPts; - assert(mapPtr->nScreenPts > 0); - for (i = 0, j = 1; j < nOrigPts; i++, j++) { - if (origPts[j].x <= origPts[i].x) { - return; /* Points are not monotonically - * increasing */ - } - } - if (((origPts[0].x > (double)graphPtr->right)) || - ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr->left))) { - return; /* All points are clipped */ - } - - /* - * The spline is computed in screen coordinates instead of data points so - * that we can select the abscissas of the interpolated points from each - * pixel horizontally across the plotting area. - */ - extra = (graphPtr->right - graphPtr->left) + 1; - if (extra < 1) { - return; - } - niPts = nOrigPts + extra + 1; - iPts = malloc(niPts * sizeof(Point2d)); - map = malloc(sizeof(int) * niPts); - /* Populate the x2 array with both the original X-coordinates and extra - * X-coordinates for each horizontal pixel that the line segment - * contains. */ - count = 0; - for (i = 0, j = 1; j < nOrigPts; i++, j++) { - - /* Add the original x-coordinate */ - iPts[count].x = origPts[i].x; + Point2d *origPts, *iPts; + int *map; + int extra; + int niPts, nOrigPts; + int result; + int i, j, count; + + nOrigPts = mapPtr->nScreenPts; + origPts = mapPtr->screenPts; + assert(mapPtr->nScreenPts > 0); + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + if (origPts[j].x <= origPts[i].x) { + return; /* Points are not monotonically + * increasing */ + } + } + if (((origPts[0].x > (double)graphPtr->right)) || + ((origPts[mapPtr->nScreenPts - 1].x < (double)graphPtr->left))) { + return; /* All points are clipped */ + } + + /* + * The spline is computed in screen coordinates instead of data points so + * that we can select the abscissas of the interpolated points from each + * pixel horizontally across the plotting area. + */ + extra = (graphPtr->right - graphPtr->left) + 1; + if (extra < 1) { + return; + } + niPts = nOrigPts + extra + 1; + iPts = malloc(niPts * sizeof(Point2d)); + map = malloc(sizeof(int) * niPts); + /* Populate the x2 array with both the original X-coordinates and extra + * X-coordinates for each horizontal pixel that the line segment + * contains. */ + count = 0; + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + + /* Add the original x-coordinate */ + iPts[count].x = origPts[i].x; + + /* Include the starting offset of the point in the offset array */ + map[count] = mapPtr->map[i]; + count++; - /* Include the starting offset of the point in the offset array */ + /* Is any part of the interval (line segment) in the plotting area? */ + if ((origPts[j].x >= (double)graphPtr->left) || + (origPts[i].x <= (double)graphPtr->right)) { + double x, last; + + x = origPts[i].x + 1.0; + + /* + * Since the line segment may be partially clipped on the left or + * right side, the points to interpolate are always interior to + * the plotting area. + * + * left right + * x1----|---------------------------|---x2 + * + * Pick the max of the starting X-coordinate and the left edge and + * the min of the last X-coordinate and the right edge. + */ + x = MAX(x, (double)graphPtr->left); + last = MIN(origPts[j].x, (double)graphPtr->right); + + /* Add the extra x-coordinates to the interval. */ + while (x < last) { map[count] = mapPtr->map[i]; - count++; - - /* Is any part of the interval (line segment) in the plotting area? */ - if ((origPts[j].x >= (double)graphPtr->left) || - (origPts[i].x <= (double)graphPtr->right)) { - double x, last; - - x = origPts[i].x + 1.0; - - /* - * Since the line segment may be partially clipped on the left or - * right side, the points to interpolate are always interior to - * the plotting area. - * - * left right - * x1----|---------------------------|---x2 - * - * Pick the max of the starting X-coordinate and the left edge and - * the min of the last X-coordinate and the right edge. - */ - x = MAX(x, (double)graphPtr->left); - last = MIN(origPts[j].x, (double)graphPtr->right); - - /* Add the extra x-coordinates to the interval. */ - while (x < last) { - map[count] = mapPtr->map[i]; - iPts[count++].x = x; - x++; - } - } - } - niPts = count; - result = FALSE; - if (elemPtr->smooth == PEN_SMOOTH_NATURAL) { - result = Blt_NaturalSpline(origPts, nOrigPts, iPts, niPts); - } else if (elemPtr->smooth == PEN_SMOOTH_QUADRATIC) { - result = Blt_QuadraticSpline(origPts, nOrigPts, iPts, niPts); - } - if (!result) { - /* The spline interpolation failed. We'll fallback to the current - * coordinates and do no smoothing (standard line segments). */ - elemPtr->smooth = PEN_SMOOTH_LINEAR; - free(iPts); - free(map); - } else { - free(mapPtr->screenPts); - free(mapPtr->map); - mapPtr->map = map; - mapPtr->screenPts = iPts; - mapPtr->nScreenPts = niPts; - } + iPts[count++].x = x; + x++; + } + } + } + niPts = count; + result = FALSE; + if (elemPtr->smooth == PEN_SMOOTH_NATURAL) { + result = Blt_NaturalSpline(origPts, nOrigPts, iPts, niPts); + } else if (elemPtr->smooth == PEN_SMOOTH_QUADRATIC) { + result = Blt_QuadraticSpline(origPts, nOrigPts, iPts, niPts); + } + if (!result) { + /* The spline interpolation failed. We'll fallback to the current + * coordinates and do no smoothing (standard line segments). */ + elemPtr->smooth = PEN_SMOOTH_LINEAR; + free(iPts); + free(map); + } else { + free(mapPtr->screenPts); + free(mapPtr->map); + mapPtr->map = map; + mapPtr->screenPts = iPts; + mapPtr->nScreenPts = niPts; + } } - /* *--------------------------------------------------------------------------- * @@ -1783,116 +1583,115 @@ GenerateSpline(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) * *--------------------------------------------------------------------------- */ -static void -GenerateParametricSpline(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void GenerateParametricSpline(Graph *graphPtr, LineElement *elemPtr, + MapInfo *mapPtr) { - Region2d exts; - Point2d *origPts, *iPts; - int *map; - int niPts, nOrigPts; - int result; - int i, j, count; - - nOrigPts = mapPtr->nScreenPts; - origPts = mapPtr->screenPts; - assert(mapPtr->nScreenPts > 0); - - Blt_GraphExtents(graphPtr, &exts); - - /* - * Populate the x2 array with both the original X-coordinates and extra - * X-coordinates for each horizontal pixel that the line segment contains. - */ - count = 1; - for (i = 0, j = 1; j < nOrigPts; i++, j++) { - Point2d p, q; + Region2d exts; + Point2d *origPts, *iPts; + int *map; + int niPts, nOrigPts; + int result; + int i, j, count; + + nOrigPts = mapPtr->nScreenPts; + origPts = mapPtr->screenPts; + assert(mapPtr->nScreenPts > 0); + + Blt_GraphExtents(graphPtr, &exts); + + /* + * Populate the x2 array with both the original X-coordinates and extra + * X-coordinates for each horizontal pixel that the line segment contains. + */ + count = 1; + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + Point2d p, q; + + p = origPts[i]; + q = origPts[j]; + count++; + if (Blt_LineRectClip(&exts, &p, &q)) { + count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5); + } + } + niPts = count; + iPts = malloc(niPts * sizeof(Point2d)); + map = malloc(sizeof(int) * niPts); + + /* + * FIXME: This is just plain wrong. The spline should be computed + * and evaluated in separate steps. This will mean breaking + * up this routine since the catrom coefficients can be + * independently computed for original data point. This + * also handles the problem of allocating enough points + * since evaluation is independent of the number of points + * to be evalualted. The interpolated + * line segments should be clipped, not the original segments. + */ + count = 0; + for (i = 0, j = 1; j < nOrigPts; i++, j++) { + Point2d p, q; + double d; - p = origPts[i]; - q = origPts[j]; - count++; - if (Blt_LineRectClip(&exts, &p, &q)) { - count += (int)(hypot(q.x - p.x, q.y - p.y) * 0.5); - } - } - niPts = count; - iPts = malloc(niPts * sizeof(Point2d)); - map = malloc(sizeof(int) * niPts); + p = origPts[i]; + q = origPts[j]; - /* - * FIXME: This is just plain wrong. The spline should be computed - * and evaluated in separate steps. This will mean breaking - * up this routine since the catrom coefficients can be - * independently computed for original data point. This - * also handles the problem of allocating enough points - * since evaluation is independent of the number of points - * to be evalualted. The interpolated - * line segments should be clipped, not the original segments. - */ - count = 0; - for (i = 0, j = 1; j < nOrigPts; i++, j++) { - Point2d p, q; - double d; - - p = origPts[i]; - q = origPts[j]; - - d = hypot(q.x - p.x, q.y - p.y); - /* Add the original x-coordinate */ - iPts[count].x = (double)i; - iPts[count].y = 0.0; - - /* Include the starting offset of the point in the offset array */ - map[count] = mapPtr->map[i]; - count++; - - /* Is any part of the interval (line segment) in the plotting - * area? */ - - if (Blt_LineRectClip(&exts, &p, &q)) { - double dp, dq; - - /* Distance of original point to p. */ - dp = hypot(p.x - origPts[i].x, p.y - origPts[i].y); - /* Distance of original point to q. */ - dq = hypot(q.x - origPts[i].x, q.y - origPts[i].y); - dp += 2.0; - while(dp <= dq) { - /* Point is indicated by its interval and parameter t. */ - iPts[count].x = (double)i; - iPts[count].y = dp / d; - map[count] = mapPtr->map[i]; - count++; - dp += 2.0; - } - } - } + d = hypot(q.x - p.x, q.y - p.y); + /* Add the original x-coordinate */ iPts[count].x = (double)i; iPts[count].y = 0.0; + + /* Include the starting offset of the point in the offset array */ map[count] = mapPtr->map[i]; count++; - niPts = count; - result = FALSE; - if (elemPtr->smooth == PEN_SMOOTH_NATURAL) { - result = Blt_NaturalParametricSpline(origPts, nOrigPts, &exts, FALSE, - iPts, niPts); - } else if (elemPtr->smooth == PEN_SMOOTH_CATROM) { - result = Blt_CatromParametricSpline(origPts, nOrigPts, iPts, niPts); - } - if (!result) { - /* The spline interpolation failed. We will fall back to the current - * coordinates and do no smoothing (standard line segments). */ - elemPtr->smooth = PEN_SMOOTH_LINEAR; - free(iPts); - free(map); - } else { - free(mapPtr->screenPts); - free(mapPtr->map); - mapPtr->map = map; - mapPtr->screenPts = iPts; - mapPtr->nScreenPts = niPts; - } -} + /* Is any part of the interval (line segment) in the plotting + * area? */ + + if (Blt_LineRectClip(&exts, &p, &q)) { + double dp, dq; + + /* Distance of original point to p. */ + dp = hypot(p.x - origPts[i].x, p.y - origPts[i].y); + /* Distance of original point to q. */ + dq = hypot(q.x - origPts[i].x, q.y - origPts[i].y); + dp += 2.0; + while(dp <= dq) { + /* Point is indicated by its interval and parameter t. */ + iPts[count].x = (double)i; + iPts[count].y = dp / d; + map[count] = mapPtr->map[i]; + count++; + dp += 2.0; + } + } + } + iPts[count].x = (double)i; + iPts[count].y = 0.0; + map[count] = mapPtr->map[i]; + count++; + niPts = count; + result = FALSE; + if (elemPtr->smooth == PEN_SMOOTH_NATURAL) { + result = Blt_NaturalParametricSpline(origPts, nOrigPts, &exts, FALSE, + iPts, niPts); + } else if (elemPtr->smooth == PEN_SMOOTH_CATROM) { + result = Blt_CatromParametricSpline(origPts, nOrigPts, iPts, niPts); + } + if (!result) { + /* The spline interpolation failed. We will fall back to the current + * coordinates and do no smoothing (standard line segments). */ + elemPtr->smooth = PEN_SMOOTH_LINEAR; + free(iPts); + free(map); + } else { + free(mapPtr->screenPts); + free(mapPtr->map); + mapPtr->map = map; + mapPtr->screenPts = iPts; + mapPtr->nScreenPts = niPts; + } +} /* *--------------------------------------------------------------------------- @@ -1910,31 +1709,30 @@ GenerateParametricSpline(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) * *--------------------------------------------------------------------------- */ -static void -MapSymbols(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void MapSymbols(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) { - Region2d exts; - Point2d *pp, *points; - int *map; - int i, count; - - points = malloc(sizeof(Point2d) * mapPtr->nScreenPts); - map = malloc(sizeof(int) * mapPtr->nScreenPts); - - Blt_GraphExtents(graphPtr, &exts); - count = 0; /* Count the number of visible points */ - - for (pp = mapPtr->screenPts, i = 0; i < mapPtr->nScreenPts; i++, pp++) { - if (PointInRegion(&exts, pp->x, pp->y)) { - points[count].x = pp->x; - points[count].y = pp->y; - map[count] = mapPtr->map[i]; - count++; - } - } - elemPtr->symbolPts.points = points; - elemPtr->symbolPts.length = count; - elemPtr->symbolPts.map = map; + Region2d exts; + Point2d *pp, *points; + int *map; + int i, count; + + points = malloc(sizeof(Point2d) * mapPtr->nScreenPts); + map = malloc(sizeof(int) * mapPtr->nScreenPts); + + Blt_GraphExtents(graphPtr, &exts); + count = 0; /* Count the number of visible points */ + + for (pp = mapPtr->screenPts, i = 0; i < mapPtr->nScreenPts; i++, pp++) { + if (PointInRegion(&exts, pp->x, pp->y)) { + points[count].x = pp->x; + points[count].y = pp->y; + map[count] = mapPtr->map[i]; + count++; + } + } + elemPtr->symbolPts.points = points; + elemPtr->symbolPts.length = count; + elemPtr->symbolPts.map = map; } /* @@ -1952,53 +1750,52 @@ MapSymbols(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) * *--------------------------------------------------------------------------- */ -static void -MapActiveSymbols(Graph *graphPtr, LineElement *elemPtr) +static void MapActiveSymbols(Graph *graphPtr, LineElement *elemPtr) { - Point2d *points; - Region2d exts; - int *map; - int count, i, np; - - if (elemPtr->activePts.points != NULL) { - free(elemPtr->activePts.points); - elemPtr->activePts.points = NULL; - } - if (elemPtr->activePts.map != NULL) { - free(elemPtr->activePts.map); - elemPtr->activePts.map = NULL; - } - Blt_GraphExtents(graphPtr, &exts); - points = malloc(sizeof(Point2d) * elemPtr->nActiveIndices); - map = malloc(sizeof(int) * elemPtr->nActiveIndices); - np = NUMBEROFPOINTS(elemPtr); - count = 0; /* Count the visible active points */ - for (i = 0; i < elemPtr->nActiveIndices; i++) { - double x, y; - int iPoint; - - iPoint = elemPtr->activeIndices[i]; - if (iPoint >= np) { - continue; /* Index not available */ - } - x = elemPtr->x.values[iPoint]; - y = elemPtr->y.values[iPoint]; - points[count] = Blt_Map2D(graphPtr, x, y, &elemPtr->axes); - map[count] = iPoint; - if (PointInRegion(&exts, points[count].x, points[count].y)) { - count++; - } - } - if (count > 0) { - elemPtr->activePts.points = points; - elemPtr->activePts.map = map; - } else { - /* No active points were visible. */ - free(points); - free(map); - } - elemPtr->activePts.length = count; - elemPtr->flags &= ~ACTIVE_PENDING; + Point2d *points; + Region2d exts; + int *map; + int count, i, np; + + if (elemPtr->activePts.points != NULL) { + free(elemPtr->activePts.points); + elemPtr->activePts.points = NULL; + } + if (elemPtr->activePts.map != NULL) { + free(elemPtr->activePts.map); + elemPtr->activePts.map = NULL; + } + Blt_GraphExtents(graphPtr, &exts); + points = malloc(sizeof(Point2d) * elemPtr->nActiveIndices); + map = malloc(sizeof(int) * elemPtr->nActiveIndices); + np = NUMBEROFPOINTS(elemPtr); + count = 0; /* Count the visible active points */ + for (i = 0; i < elemPtr->nActiveIndices; i++) { + double x, y; + int iPoint; + + iPoint = elemPtr->activeIndices[i]; + if (iPoint >= np) { + continue; /* Index not available */ + } + x = elemPtr->x.values[iPoint]; + y = elemPtr->y.values[iPoint]; + points[count] = Blt_Map2D(graphPtr, x, y, &elemPtr->axes); + map[count] = iPoint; + if (PointInRegion(&exts, points[count].x, points[count].y)) { + count++; + } + } + if (count > 0) { + elemPtr->activePts.points = points; + elemPtr->activePts.map = map; + } else { + /* No active points were visible. */ + free(points); + free(map); + } + elemPtr->activePts.length = count; + elemPtr->flags &= ~ACTIVE_PENDING; } /* @@ -2017,155 +1814,154 @@ MapActiveSymbols(Graph *graphPtr, LineElement *elemPtr) * *--------------------------------------------------------------------------- */ -static void -MergePens(LineElement *elemPtr, LineStyle **styleMap) +static void MergePens(LineElement *elemPtr, LineStyle **styleMap) { - if (Blt_Chain_GetLength(elemPtr->styles) < 2) { - Blt_ChainLink link; - LineStyle *stylePtr; - - link = Blt_Chain_FirstLink(elemPtr->styles); - stylePtr = Blt_Chain_GetValue(link); - stylePtr->errorBarCapWidth = elemPtr->errorBarCapWidth; - stylePtr->lines.length = elemPtr->lines.length; - stylePtr->lines.segments = elemPtr->lines.segments; - stylePtr->symbolPts.length = elemPtr->symbolPts.length; - stylePtr->symbolPts.points = elemPtr->symbolPts.points; - stylePtr->xeb.length = elemPtr->xeb.length; - stylePtr->xeb.segments = elemPtr->xeb.segments; - stylePtr->yeb.length = elemPtr->yeb.length; - stylePtr->yeb.segments = elemPtr->yeb.segments; - return; - } - - /* We have more than one style. Group line segments and points of like pen - * styles. */ - if (elemPtr->lines.length > 0) { - Blt_ChainLink link; - Segment2d *sp, *segments; - int *ip; - int *map; - - segments = malloc(elemPtr->lines.length * sizeof(Segment2d)); - map = malloc(elemPtr->lines.length * sizeof(int)); - sp = segments, ip = map; - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - int i; + if (Blt_Chain_GetLength(elemPtr->stylesPalette) < 2) { + Blt_ChainLink link; + LineStyle *stylePtr; - stylePtr = Blt_Chain_GetValue(link); - stylePtr->lines.segments = sp; - for (i = 0; i < elemPtr->lines.length; i++) { - int iData; + link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + stylePtr = Blt_Chain_GetValue(link); + stylePtr->errorBarCapWidth = elemPtr->errorBarCapWidth; + stylePtr->lines.length = elemPtr->lines.length; + stylePtr->lines.segments = elemPtr->lines.segments; + stylePtr->symbolPts.length = elemPtr->symbolPts.length; + stylePtr->symbolPts.points = elemPtr->symbolPts.points; + stylePtr->xeb.length = elemPtr->xeb.length; + stylePtr->xeb.segments = elemPtr->xeb.segments; + stylePtr->yeb.length = elemPtr->yeb.length; + stylePtr->yeb.segments = elemPtr->yeb.segments; + return; + } + + /* We have more than one style. Group line segments and points of like pen + * styles. */ + if (elemPtr->lines.length > 0) { + Blt_ChainLink link; + Segment2d *sp, *segments; + int *ip; + int *map; - iData = elemPtr->lines.map[i]; - if (styleMap[iData] == stylePtr) { - *sp++ = elemPtr->lines.segments[i]; - *ip++ = iData; - } - } - stylePtr->lines.length = sp - stylePtr->lines.segments; + segments = malloc(elemPtr->lines.length * sizeof(Segment2d)); + map = malloc(elemPtr->lines.length * sizeof(int)); + sp = segments, ip = map; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + int i; + + stylePtr = Blt_Chain_GetValue(link); + stylePtr->lines.segments = sp; + for (i = 0; i < elemPtr->lines.length; i++) { + int iData; + + iData = elemPtr->lines.map[i]; + if (styleMap[iData] == stylePtr) { + *sp++ = elemPtr->lines.segments[i]; + *ip++ = iData; } - free(elemPtr->lines.segments); - elemPtr->lines.segments = segments; - free(elemPtr->lines.map); - elemPtr->lines.map = map; - } - if (elemPtr->symbolPts.length > 0) { - Blt_ChainLink link; - int *ip; - Point2d *points, *pp; - int *map; - - points = malloc(elemPtr->symbolPts.length * sizeof(Point2d)); - map = malloc(elemPtr->symbolPts.length * sizeof(int)); - pp = points, ip = map; - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - int i; - - stylePtr = Blt_Chain_GetValue(link); - stylePtr->symbolPts.points = pp; - for (i = 0; i < elemPtr->symbolPts.length; i++) { - int iData; + } + stylePtr->lines.length = sp - stylePtr->lines.segments; + } + free(elemPtr->lines.segments); + elemPtr->lines.segments = segments; + free(elemPtr->lines.map); + elemPtr->lines.map = map; + } + if (elemPtr->symbolPts.length > 0) { + Blt_ChainLink link; + int *ip; + Point2d *points, *pp; + int *map; - iData = elemPtr->symbolPts.map[i]; - if (styleMap[iData] == stylePtr) { - *pp++ = elemPtr->symbolPts.points[i]; - *ip++ = iData; - } - } - stylePtr->symbolPts.length = pp - stylePtr->symbolPts.points; + points = malloc(elemPtr->symbolPts.length * sizeof(Point2d)); + map = malloc(elemPtr->symbolPts.length * sizeof(int)); + pp = points, ip = map; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + int i; + + stylePtr = Blt_Chain_GetValue(link); + stylePtr->symbolPts.points = pp; + for (i = 0; i < elemPtr->symbolPts.length; i++) { + int iData; + + iData = elemPtr->symbolPts.map[i]; + if (styleMap[iData] == stylePtr) { + *pp++ = elemPtr->symbolPts.points[i]; + *ip++ = iData; } - free(elemPtr->symbolPts.points); - free(elemPtr->symbolPts.map); - elemPtr->symbolPts.points = points; - elemPtr->symbolPts.map = map; + } + stylePtr->symbolPts.length = pp - stylePtr->symbolPts.points; } - if (elemPtr->xeb.length > 0) { - Segment2d *segments, *sp; - int *map, *ip; - Blt_ChainLink link; - - segments = malloc(elemPtr->xeb.length * sizeof(Segment2d)); - map = malloc(elemPtr->xeb.length * sizeof(int)); - sp = segments, ip = map; - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - int i; - - stylePtr = Blt_Chain_GetValue(link); - stylePtr->xeb.segments = sp; - for (i = 0; i < elemPtr->xeb.length; i++) { - int iData; + free(elemPtr->symbolPts.points); + free(elemPtr->symbolPts.map); + elemPtr->symbolPts.points = points; + elemPtr->symbolPts.map = map; + } + if (elemPtr->xeb.length > 0) { + Segment2d *segments, *sp; + int *map, *ip; + Blt_ChainLink link; - iData = elemPtr->xeb.map[i]; - if (styleMap[iData] == stylePtr) { - *sp++ = elemPtr->xeb.segments[i]; - *ip++ = iData; - } - } - stylePtr->xeb.length = sp - stylePtr->xeb.segments; + segments = malloc(elemPtr->xeb.length * sizeof(Segment2d)); + map = malloc(elemPtr->xeb.length * sizeof(int)); + sp = segments, ip = map; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + int i; + + stylePtr = Blt_Chain_GetValue(link); + stylePtr->xeb.segments = sp; + for (i = 0; i < elemPtr->xeb.length; i++) { + int iData; + + iData = elemPtr->xeb.map[i]; + if (styleMap[iData] == stylePtr) { + *sp++ = elemPtr->xeb.segments[i]; + *ip++ = iData; } - free(elemPtr->xeb.segments); - free(elemPtr->xeb.map); - elemPtr->xeb.segments = segments; - elemPtr->xeb.map = map; - } - if (elemPtr->yeb.length > 0) { - Segment2d *segments, *sp; - int *map, *ip; - Blt_ChainLink link; - - segments = malloc(elemPtr->yeb.length * sizeof(Segment2d)); - map = malloc(elemPtr->yeb.length * sizeof(int)); - sp = segments, ip = map; - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - int i; - - stylePtr = Blt_Chain_GetValue(link); - stylePtr->yeb.segments = sp; - for (i = 0; i < elemPtr->yeb.length; i++) { - int iData; + } + stylePtr->xeb.length = sp - stylePtr->xeb.segments; + } + free(elemPtr->xeb.segments); + free(elemPtr->xeb.map); + elemPtr->xeb.segments = segments; + elemPtr->xeb.map = map; + } + if (elemPtr->yeb.length > 0) { + Segment2d *segments, *sp; + int *map, *ip; + Blt_ChainLink link; - iData = elemPtr->yeb.map[i]; - if (styleMap[iData] == stylePtr) { - *sp++ = elemPtr->yeb.segments[i]; - *ip++ = iData; - } - } - stylePtr->yeb.length = sp - stylePtr->yeb.segments; + segments = malloc(elemPtr->yeb.length * sizeof(Segment2d)); + map = malloc(elemPtr->yeb.length * sizeof(int)); + sp = segments, ip = map; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + int i; + + stylePtr = Blt_Chain_GetValue(link); + stylePtr->yeb.segments = sp; + for (i = 0; i < elemPtr->yeb.length; i++) { + int iData; + + iData = elemPtr->yeb.map[i]; + if (styleMap[iData] == stylePtr) { + *sp++ = elemPtr->yeb.segments[i]; + *ip++ = iData; } - free(elemPtr->yeb.segments); - elemPtr->yeb.segments = segments; - free(elemPtr->yeb.map); - elemPtr->yeb.map = map; - } + } + stylePtr->yeb.length = sp - stylePtr->yeb.segments; + } + free(elemPtr->yeb.segments); + elemPtr->yeb.segments = segments; + free(elemPtr->yeb.map); + elemPtr->yeb.map = map; + } } #define CLIP_TOP (1<<0) @@ -2173,1137 +1969,943 @@ MergePens(LineElement *elemPtr, LineStyle **styleMap) #define CLIP_RIGHT (1<<2) #define CLIP_LEFT (1<<3) -INLINE static int -OutCode(Region2d *extsPtr, Point2d *p) +INLINE static int OutCode(Region2d *extsPtr, Point2d *p) { - int code; - - code = 0; - if (p->x > extsPtr->right) { - code |= CLIP_RIGHT; - } else if (p->x < extsPtr->left) { - code |= CLIP_LEFT; - } - if (p->y > extsPtr->bottom) { - code |= CLIP_BOTTOM; - } else if (p->y < extsPtr->top) { - code |= CLIP_TOP; - } - return code; + int code; + + code = 0; + if (p->x > extsPtr->right) { + code |= CLIP_RIGHT; + } else if (p->x < extsPtr->left) { + code |= CLIP_LEFT; + } + if (p->y > extsPtr->bottom) { + code |= CLIP_BOTTOM; + } else if (p->y < extsPtr->top) { + code |= CLIP_TOP; + } + return code; } -static int -ClipSegment( - Region2d *extsPtr, - int code1, int code2, - Point2d *p, Point2d *q) +static int ClipSegment(Region2d *extsPtr, int code1, int code2, + Point2d *p, Point2d *q) { - int inside, outside; + int inside, outside; + + inside = ((code1 | code2) == 0); + outside = ((code1 & code2) != 0); + + /* + * In the worst case, we'll clip the line segment against each of the four + * sides of the bounding rectangle. + */ + while ((!outside) && (!inside)) { + if (code1 == 0) { + Point2d *tmp; + int code; + + /* Swap pointers and out codes */ + tmp = p, p = q, q = tmp; + code = code1, code1 = code2, code2 = code; + } + if (code1 & CLIP_LEFT) { + p->y += (q->y - p->y) * + (extsPtr->left - p->x) / (q->x - p->x); + p->x = extsPtr->left; + } else if (code1 & CLIP_RIGHT) { + p->y += (q->y - p->y) * + (extsPtr->right - p->x) / (q->x - p->x); + p->x = extsPtr->right; + } else if (code1 & CLIP_BOTTOM) { + p->x += (q->x - p->x) * + (extsPtr->bottom - p->y) / (q->y - p->y); + p->y = extsPtr->bottom; + } else if (code1 & CLIP_TOP) { + p->x += (q->x - p->x) * + (extsPtr->top - p->y) / (q->y - p->y); + p->y = extsPtr->top; + } + code1 = OutCode(extsPtr, p); inside = ((code1 | code2) == 0); outside = ((code1 & code2) != 0); + } + return (!inside); +} - /* - * In the worst case, we'll clip the line segment against each of the four - * sides of the bounding rectangle. - */ - while ((!outside) && (!inside)) { - if (code1 == 0) { - Point2d *tmp; - int code; - - /* Swap pointers and out codes */ - tmp = p, p = q, q = tmp; - code = code1, code1 = code2, code2 = code; - } - if (code1 & CLIP_LEFT) { - p->y += (q->y - p->y) * - (extsPtr->left - p->x) / (q->x - p->x); - p->x = extsPtr->left; - } else if (code1 & CLIP_RIGHT) { - p->y += (q->y - p->y) * - (extsPtr->right - p->x) / (q->x - p->x); - p->x = extsPtr->right; - } else if (code1 & CLIP_BOTTOM) { - p->x += (q->x - p->x) * - (extsPtr->bottom - p->y) / (q->y - p->y); - p->y = extsPtr->bottom; - } else if (code1 & CLIP_TOP) { - p->x += (q->x - p->x) * - (extsPtr->top - p->y) / (q->y - p->y); - p->y = extsPtr->top; - } - code1 = OutCode(extsPtr, p); - - inside = ((code1 | code2) == 0); - outside = ((code1 & code2) != 0); - } - return (!inside); +static void SaveTrace(LineElement *elemPtr, int start, int length, + MapInfo *mapPtr) +{ + bltTrace *tracePtr; + Point2d *screenPts; + int *map; + int i, j; + + tracePtr = malloc(sizeof(bltTrace)); + screenPts = malloc(sizeof(Point2d) * length); + map = malloc(sizeof(int) * length); + + /* Copy the screen coordinates of the trace into the point array */ + + if (mapPtr->map != NULL) { + for (i = 0, j = start; i < length; i++, j++) { + screenPts[i].x = mapPtr->screenPts[j].x; + screenPts[i].y = mapPtr->screenPts[j].y; + map[i] = mapPtr->map[j]; + } + } else { + for (i = 0, j = start; i < length; i++, j++) { + screenPts[i].x = mapPtr->screenPts[j].x; + screenPts[i].y = mapPtr->screenPts[j].y; + map[i] = j; + } + } + tracePtr->screenPts.length = length; + tracePtr->screenPts.points = screenPts; + tracePtr->screenPts.map = map; + tracePtr->start = start; + if (elemPtr->traces == NULL) { + elemPtr->traces = Blt_Chain_Create(); + } + Blt_Chain_Append(elemPtr->traces, tracePtr); } -/* - *--------------------------------------------------------------------------- - * - * SaveTrace -- - * - * Creates a new trace and inserts it into the line's list of traces. - * - * Results: - * None. - * - *--------------------------------------------------------------------------- - */ -static void -SaveTrace( - LineElement *elemPtr, - int start, /* Starting index of the trace in data point - * array. Used to figure out closest point */ - int length, /* Number of points forming the trace */ - MapInfo *mapPtr) +static void FreeTraces(LineElement *elemPtr) { - bltTrace *tracePtr; - Point2d *screenPts; - int *map; - int i, j; + Blt_ChainLink link; - tracePtr = malloc(sizeof(bltTrace)); - screenPts = malloc(sizeof(Point2d) * length); - map = malloc(sizeof(int) * length); + for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; + link = Blt_Chain_NextLink(link)) { + bltTrace *tracePtr; - /* Copy the screen coordinates of the trace into the point array */ + tracePtr = Blt_Chain_GetValue(link); + free(tracePtr->screenPts.map); + free(tracePtr->screenPts.points); + free(tracePtr); + } + Blt_Chain_Destroy(elemPtr->traces); + elemPtr->traces = NULL; +} - if (mapPtr->map != NULL) { - for (i = 0, j = start; i < length; i++, j++) { - screenPts[i].x = mapPtr->screenPts[j].x; - screenPts[i].y = mapPtr->screenPts[j].y; - map[i] = mapPtr->map[j]; - } +static void MapTraces(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +{ + Point2d *p, *q; + Region2d exts; + int code1; + int i; + int start, count; + + Blt_GraphExtents(graphPtr, &exts); + count = 1; + code1 = OutCode(&exts, mapPtr->screenPts); + p = mapPtr->screenPts; + q = p + 1; + for (i = 1; i < mapPtr->nScreenPts; i++, p++, q++) { + Point2d s; + int code2; + int broken, offscreen; + + s.x = s.y = 0; + code2 = OutCode(&exts, q); + if (code2 != 0) { + /* Save the coordinates of the last point, before clipping */ + s = *q; + } + broken = BROKEN_TRACE(elemPtr->penDir, p->x, q->x); + offscreen = ClipSegment(&exts, code1, code2, p, q); + if (broken || offscreen) { + + /* + * The last line segment is either totally clipped by the plotting + * area or the x-direction is wrong, breaking the trace. Either + * way, save information about the last trace (if one exists), + * discarding the current line segment + */ + + if (count > 1) { + start = i - count; + SaveTrace(elemPtr, start, count, mapPtr); + count = 1; + } } else { - for (i = 0, j = start; i < length; i++, j++) { - screenPts[i].x = mapPtr->screenPts[j].x; - screenPts[i].y = mapPtr->screenPts[j].y; - map[i] = j; - } - } - tracePtr->screenPts.length = length; - tracePtr->screenPts.points = screenPts; - tracePtr->screenPts.map = map; - tracePtr->start = start; - if (elemPtr->traces == NULL) { - elemPtr->traces = Blt_Chain_Create(); - } - Blt_Chain_Append(elemPtr->traces, tracePtr); + count++; /* Add the point to the trace. */ + if (code2 != 0) { + + /* + * If the last point is clipped, this means that the trace is + * broken after this point. Restore the original coordinate + * (before clipping) after saving the trace. + */ + + start = i - (count - 1); + SaveTrace(elemPtr, start, count, mapPtr); + mapPtr->screenPts[i] = s; + count = 1; + } + } + code1 = code2; + } + if (count > 1) { + start = i - count; + SaveTrace(elemPtr, start, count, mapPtr); + } } -/* - *--------------------------------------------------------------------------- - * - * FreeTraces -- - * - * Deletes all the traces for the line. - * - * Results: - * None. - * - *--------------------------------------------------------------------------- - */ -static void -FreeTraces(LineElement *elemPtr) +static void MapFillArea(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) { - Blt_ChainLink link; + Point2d *origPts, *clipPts; + Region2d exts; + int np; + + if (elemPtr->fillPts != NULL) { + free(elemPtr->fillPts); + elemPtr->fillPts = NULL; + elemPtr->nFillPts = 0; + } + if (mapPtr->nScreenPts < 3) { + return; + } + np = mapPtr->nScreenPts + 3; + Blt_GraphExtents(graphPtr, &exts); + + origPts = malloc(sizeof(Point2d) * np); + if (graphPtr->inverted) { + double minX; + int i; - for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; - link = Blt_Chain_NextLink(link)) { - bltTrace *tracePtr; + minX = (double)elemPtr->axes.y->screenMin; + for (i = 0; i < mapPtr->nScreenPts; i++) { + origPts[i].x = mapPtr->screenPts[i].x + 1; + origPts[i].y = mapPtr->screenPts[i].y; + if (origPts[i].x < minX) { + minX = origPts[i].x; + } + } + /* Add edges to make (if necessary) the polygon fill to the bottom of + * plotting window */ + origPts[i].x = minX; + origPts[i].y = origPts[i - 1].y; + i++; + origPts[i].x = minX; + origPts[i].y = origPts[0].y; + i++; + origPts[i] = origPts[0]; + } else { + double maxY; + int i; - tracePtr = Blt_Chain_GetValue(link); - free(tracePtr->screenPts.map); - free(tracePtr->screenPts.points); - free(tracePtr); - } - Blt_Chain_Destroy(elemPtr->traces); - elemPtr->traces = NULL; + maxY = (double)elemPtr->axes.y->bottom; + for (i = 0; i < mapPtr->nScreenPts; i++) { + origPts[i].x = mapPtr->screenPts[i].x + 1; + origPts[i].y = mapPtr->screenPts[i].y; + if (origPts[i].y > maxY) { + maxY = origPts[i].y; + } + } + /* Add edges to extend the fill polygon to the bottom of plotting + * window */ + origPts[i].x = origPts[i - 1].x; + origPts[i].y = maxY; + i++; + origPts[i].x = origPts[0].x; + origPts[i].y = maxY; + i++; + origPts[i] = origPts[0]; + } + + clipPts = malloc(sizeof(Point2d) * np * 3); + np = Blt_PolyRectClip(&exts, origPts, np - 1, clipPts); + + free(origPts); + if (np < 3) { + free(clipPts); + } else { + elemPtr->fillPts = clipPts; + elemPtr->nFillPts = np; + } } -/* - *--------------------------------------------------------------------------- - * - * MapTraces -- - * - * Creates an array of line segments of the graph coordinates. - * - * Results: - * None. - * - * Side effects: - * Memory is allocated for the line segment array. - * - *--------------------------------------------------------------------------- - */ -static void -MapTraces(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void ResetLine(LineElement *elemPtr) { - Point2d *p, *q; - Region2d exts; - int code1; + FreeTraces(elemPtr); + ResetStylePalette(elemPtr->stylesPalette); + if (elemPtr->symbolPts.points != NULL) { + free(elemPtr->symbolPts.points); + } + if (elemPtr->symbolPts.map != NULL) { + free(elemPtr->symbolPts.map); + } + if (elemPtr->lines.segments != NULL) { + free(elemPtr->lines.segments); + } + if (elemPtr->lines.map != NULL) { + free(elemPtr->lines.map); + } + if (elemPtr->activePts.points != NULL) { + free(elemPtr->activePts.points); + } + if (elemPtr->activePts.map != NULL) { + free(elemPtr->activePts.map); + } + if (elemPtr->xeb.segments != NULL) { + free(elemPtr->xeb.segments); + } + if (elemPtr->xeb.map != NULL) { + free(elemPtr->xeb.map); + } + if (elemPtr->yeb.segments != NULL) { + free(elemPtr->yeb.segments); + } + if (elemPtr->yeb.map != NULL) { + free(elemPtr->yeb.map); + } + elemPtr->xeb.segments = elemPtr->yeb.segments = elemPtr->lines.segments = NULL; + elemPtr->symbolPts.points = elemPtr->activePts.points = NULL; + elemPtr->lines.map = elemPtr->symbolPts.map = elemPtr->xeb.map = + elemPtr->yeb.map = elemPtr->activePts.map = NULL; + elemPtr->activePts.length = elemPtr->symbolPts.length = + elemPtr->lines.length = elemPtr->xeb.length = elemPtr->yeb.length = 0; +} + +static void MapErrorBars(Graph *graphPtr, LineElement *elemPtr, + LineStyle **styleMap) +{ + int n, np; + Region2d exts; + + Blt_GraphExtents(graphPtr, &exts); + np = NUMBEROFPOINTS(elemPtr); + if (elemPtr->xError.nValues > 0) { + n = MIN(elemPtr->xError.nValues, np); + } else { + n = MIN3(elemPtr->xHigh.nValues, elemPtr->xLow.nValues, np); + } + if (n > 0) { + Segment2d *errorBars; + Segment2d *segPtr; + int *errorToData; + int *indexPtr; int i; - int start, count; - - Blt_GraphExtents(graphPtr, &exts); - count = 1; - code1 = OutCode(&exts, mapPtr->screenPts); - p = mapPtr->screenPts; - q = p + 1; - for (i = 1; i < mapPtr->nScreenPts; i++, p++, q++) { - Point2d s; - int code2; - int broken, offscreen; - - s.x = s.y = 0; - code2 = OutCode(&exts, q); - if (code2 != 0) { - /* Save the coordinates of the last point, before clipping */ - s = *q; + + segPtr = errorBars = malloc(n * 3 * sizeof(Segment2d)); + indexPtr = errorToData = malloc(n * 3 * sizeof(int)); + for (i = 0; i < n; i++) { + double x, y; + double high, low; + LineStyle *stylePtr; + + x = elemPtr->x.values[i]; + y = elemPtr->y.values[i]; + stylePtr = styleMap[i]; + if ((isfinite(x)) && (isfinite(y))) { + if (elemPtr->xError.nValues > 0) { + high = x + elemPtr->xError.values[i]; + low = x - elemPtr->xError.values[i]; + } else { + high = elemPtr->xHigh.values[i]; + low = elemPtr->xLow.values[i]; } - broken = BROKEN_TRACE(elemPtr->penDir, p->x, q->x); - offscreen = ClipSegment(&exts, code1, code2, p, q); - if (broken || offscreen) { - - /* - * The last line segment is either totally clipped by the plotting - * area or the x-direction is wrong, breaking the trace. Either - * way, save information about the last trace (if one exists), - * discarding the current line segment - */ - - if (count > 1) { - start = i - count; - SaveTrace(elemPtr, start, count, mapPtr); - count = 1; - } + if ((isfinite(high)) && (isfinite(low))) { + Point2d p, q; + + p = Blt_Map2D(graphPtr, high, y, &elemPtr->axes); + q = Blt_Map2D(graphPtr, low, y, &elemPtr->axes); + segPtr->p = p; + segPtr->q = q; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + /* Left cap */ + segPtr->p.x = segPtr->q.x = p.x; + segPtr->p.y = p.y - stylePtr->errorBarCapWidth; + segPtr->q.y = p.y + stylePtr->errorBarCapWidth; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + /* Right cap */ + segPtr->p.x = segPtr->q.x = q.x; + segPtr->p.y = q.y - stylePtr->errorBarCapWidth; + segPtr->q.y = q.y + stylePtr->errorBarCapWidth; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + } + } + } + elemPtr->xeb.segments = errorBars; + elemPtr->xeb.length = segPtr - errorBars; + elemPtr->xeb.map = errorToData; + } + if (elemPtr->yError.nValues > 0) { + n = MIN(elemPtr->yError.nValues, np); + } else { + n = MIN3(elemPtr->yHigh.nValues, elemPtr->yLow.nValues, np); + } + if (n > 0) { + Segment2d *errorBars; + Segment2d *segPtr; + int *errorToData; + int *indexPtr; + int i; + + segPtr = errorBars = malloc(n * 3 * sizeof(Segment2d)); + indexPtr = errorToData = malloc(n * 3 * sizeof(int)); + for (i = 0; i < n; i++) { + double x, y; + double high, low; + LineStyle *stylePtr; + + x = elemPtr->x.values[i]; + y = elemPtr->y.values[i]; + stylePtr = styleMap[i]; + if ((isfinite(x)) && (isfinite(y))) { + if (elemPtr->yError.nValues > 0) { + high = y + elemPtr->yError.values[i]; + low = y - elemPtr->yError.values[i]; } else { - count++; /* Add the point to the trace. */ - if (code2 != 0) { - - /* - * If the last point is clipped, this means that the trace is - * broken after this point. Restore the original coordinate - * (before clipping) after saving the trace. - */ - - start = i - (count - 1); - SaveTrace(elemPtr, start, count, mapPtr); - mapPtr->screenPts[i] = s; - count = 1; - } + high = elemPtr->yHigh.values[i]; + low = elemPtr->yLow.values[i]; } - code1 = code2; - } - if (count > 1) { - start = i - count; - SaveTrace(elemPtr, start, count, mapPtr); + if ((isfinite(high)) && (isfinite(low))) { + Point2d p, q; + + p = Blt_Map2D(graphPtr, x, high, &elemPtr->axes); + q = Blt_Map2D(graphPtr, x, low, &elemPtr->axes); + segPtr->p = p; + segPtr->q = q; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + /* Top cap. */ + segPtr->p.y = segPtr->q.y = p.y; + segPtr->p.x = p.x - stylePtr->errorBarCapWidth; + segPtr->q.x = p.x + stylePtr->errorBarCapWidth; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + /* Bottom cap. */ + segPtr->p.y = segPtr->q.y = q.y; + segPtr->p.x = q.x - stylePtr->errorBarCapWidth; + segPtr->q.x = q.x + stylePtr->errorBarCapWidth; + if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { + segPtr++; + *indexPtr++ = i; + } + } + } } + elemPtr->yeb.segments = errorBars; + elemPtr->yeb.length = segPtr - errorBars; + elemPtr->yeb.map = errorToData; + } } -/* - *--------------------------------------------------------------------------- - * - * MapFillArea -- - * - * Creates an array of points that represent a polygon that fills - * the area under the element. - * - * Results: - * None. - * - * Side effects: - * Memory is allocated for the polygon point array. - * - *--------------------------------------------------------------------------- - */ -static void -MapFillArea(Graph *graphPtr, LineElement *elemPtr, MapInfo *mapPtr) +static void MapLineProc(Graph *graphPtr, Element *basePtr) { - Point2d *origPts, *clipPts; - Region2d exts; - int np; - - if (elemPtr->fillPts != NULL) { - free(elemPtr->fillPts); - elemPtr->fillPts = NULL; - elemPtr->nFillPts = 0; + LineElement *elemPtr = (LineElement *)basePtr; + MapInfo mi; + int size, np; + LineStyle **styleMap; + Blt_ChainLink link; + + ResetLine(elemPtr); + np = NUMBEROFPOINTS(elemPtr); + if (np < 1) { + return; /* No data points */ + } + GetScreenPoints(graphPtr, elemPtr, &mi); + MapSymbols(graphPtr, elemPtr, &mi); + + if ((elemPtr->flags & ACTIVE_PENDING) && (elemPtr->nActiveIndices > 0)) { + MapActiveSymbols(graphPtr, elemPtr); + } + /* + * Map connecting line segments if they are to be displayed. + */ + elemPtr->smooth = elemPtr->reqSmooth; + if ((np > 1) && (elemPtr->builtinPen.traceWidth > 0)) { + /* + * Do smoothing if necessary. This can extend the coordinate array, + * so both mi.points and mi.nPoints may change. + */ + switch (elemPtr->smooth) { + case PEN_SMOOTH_STEP: + GenerateSteps(&mi); + break; + + case PEN_SMOOTH_NATURAL: + case PEN_SMOOTH_QUADRATIC: + if (mi.nScreenPts < 3) { + /* Can't interpolate with less than three points. */ + elemPtr->smooth = PEN_SMOOTH_LINEAR; + } else { + GenerateSpline(graphPtr, elemPtr, &mi); + } + break; + + case PEN_SMOOTH_CATROM: + if (mi.nScreenPts < 3) { + /* Can't interpolate with less than three points. */ + elemPtr->smooth = PEN_SMOOTH_LINEAR; + } else { + GenerateParametricSpline(graphPtr, elemPtr, &mi); + } + break; + + default: + break; } - if (mapPtr->nScreenPts < 3) { - return; + if (elemPtr->rTolerance > 0.0) { + ReducePoints(&mi, elemPtr->rTolerance); } - np = mapPtr->nScreenPts + 3; - Blt_GraphExtents(graphPtr, &exts); - - origPts = malloc(sizeof(Point2d) * np); - if (graphPtr->inverted) { - double minX; - int i; - - minX = (double)elemPtr->axes.y->screenMin; - for (i = 0; i < mapPtr->nScreenPts; i++) { - origPts[i].x = mapPtr->screenPts[i].x + 1; - origPts[i].y = mapPtr->screenPts[i].y; - if (origPts[i].x < minX) { - minX = origPts[i].x; - } - } - /* Add edges to make (if necessary) the polygon fill to the bottom of - * plotting window */ - origPts[i].x = minX; - origPts[i].y = origPts[i - 1].y; - i++; - origPts[i].x = minX; - origPts[i].y = origPts[0].y; - i++; - origPts[i] = origPts[0]; - } else { - double maxY; - int i; - - maxY = (double)elemPtr->axes.y->bottom; - for (i = 0; i < mapPtr->nScreenPts; i++) { - origPts[i].x = mapPtr->screenPts[i].x + 1; - origPts[i].y = mapPtr->screenPts[i].y; - if (origPts[i].y > maxY) { - maxY = origPts[i].y; - } - } - /* Add edges to extend the fill polygon to the bottom of plotting - * window */ - origPts[i].x = origPts[i - 1].x; - origPts[i].y = maxY; - i++; - origPts[i].x = origPts[0].x; - origPts[i].y = maxY; - i++; - origPts[i] = origPts[0]; + if (elemPtr->fillBg != NULL) { + MapFillArea(graphPtr, elemPtr, &mi); } + MapTraces(graphPtr, elemPtr, &mi); + } + free(mi.screenPts); + free(mi.map); - clipPts = malloc(sizeof(Point2d) * np * 3); - np = Blt_PolyRectClip(&exts, origPts, np - 1, clipPts); + /* Set the symbol size of all the pen styles. */ + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); link != NULL; + link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + LinePen *penPtr; - free(origPts); - if (np < 3) { - free(clipPts); - } else { - elemPtr->fillPts = clipPts; - elemPtr->nFillPts = np; - } + stylePtr = Blt_Chain_GetValue(link); + penPtr = (LinePen *)stylePtr->penPtr; + size = ScaleSymbol(elemPtr, penPtr->symbol.size); + stylePtr->symbolSize = size; + stylePtr->errorBarCapWidth = (penPtr->errorBarCapWidth > 0) + ? penPtr->errorBarCapWidth : Round(size * 0.6666666); + stylePtr->errorBarCapWidth /= 2; + } + styleMap = (LineStyle **)Blt_StyleMap((Element *)elemPtr); + if (((elemPtr->yHigh.nValues > 0) && (elemPtr->yLow.nValues > 0)) || + ((elemPtr->xHigh.nValues > 0) && (elemPtr->xLow.nValues > 0)) || + (elemPtr->xError.nValues > 0) || (elemPtr->yError.nValues > 0)) { + MapErrorBars(graphPtr, elemPtr, styleMap); + } + MergePens(elemPtr, styleMap); + free(styleMap); } -static void -ResetLine(LineElement *elemPtr) +static double DistanceToLineProc(int x, int y, Point2d *p, Point2d *q, + Point2d *t) { - FreeTraces(elemPtr); - ResetStylePalette(elemPtr->styles); - if (elemPtr->symbolPts.points != NULL) { - free(elemPtr->symbolPts.points); - } - if (elemPtr->symbolPts.map != NULL) { - free(elemPtr->symbolPts.map); - } - if (elemPtr->lines.segments != NULL) { - free(elemPtr->lines.segments); - } - if (elemPtr->lines.map != NULL) { - free(elemPtr->lines.map); - } - if (elemPtr->activePts.points != NULL) { - free(elemPtr->activePts.points); - } - if (elemPtr->activePts.map != NULL) { - free(elemPtr->activePts.map); - } - if (elemPtr->xeb.segments != NULL) { - free(elemPtr->xeb.segments); - } - if (elemPtr->xeb.map != NULL) { - free(elemPtr->xeb.map); - } - if (elemPtr->yeb.segments != NULL) { - free(elemPtr->yeb.segments); - } - if (elemPtr->yeb.map != NULL) { - free(elemPtr->yeb.map); - } - elemPtr->xeb.segments = elemPtr->yeb.segments = elemPtr->lines.segments = NULL; - elemPtr->symbolPts.points = elemPtr->activePts.points = NULL; - elemPtr->lines.map = elemPtr->symbolPts.map = elemPtr->xeb.map = - elemPtr->yeb.map = elemPtr->activePts.map = NULL; - elemPtr->activePts.length = elemPtr->symbolPts.length = - elemPtr->lines.length = elemPtr->xeb.length = elemPtr->yeb.length = 0; + double right, left, top, bottom; + + *t = Blt_GetProjection(x, y, p, q); + if (p->x > q->x) { + right = p->x, left = q->x; + } else { + left = p->x, right = q->x; + } + if (p->y > q->y) { + bottom = p->y, top = q->y; + } else { + top = p->y, bottom = q->y; + } + if (t->x > right) { + t->x = right; + } else if (t->x < left) { + t->x = left; + } + if (t->y > bottom) { + t->y = bottom; + } else if (t->y < top) { + t->y = top; + } + return hypot((t->x - x), (t->y - y)); } -/* - *--------------------------------------------------------------------------- - * - * MapErrorBars -- - * - * Creates two arrays of points and pen indices, filled with the screen - * coordinates of the visible - * - * Results: - * None. - * - * Side effects: - * Memory is freed and allocated for the index array. - * - *--------------------------------------------------------------------------- - */ -static void -MapErrorBars(Graph *graphPtr, LineElement *elemPtr, LineStyle **styleMap) +static double DistanceToXProc(int x, int y, Point2d *p, Point2d *q, + Point2d *t) { - int n, np; - Region2d exts; - - Blt_GraphExtents(graphPtr, &exts); - np = NUMBEROFPOINTS(elemPtr); - if (elemPtr->xError.nValues > 0) { - n = MIN(elemPtr->xError.nValues, np); + double dx, dy; + double d; + + if (p->x > q->x) { + if ((x > p->x) || (x < q->x)) { + return DBL_MAX; /* X-coordinate outside line segment. */ + } + } else { + if ((x > q->x) || (x < p->x)) { + return DBL_MAX; /* X-coordinate outside line segment. */ + } + } + dx = p->x - q->x; + dy = p->y - q->y; + t->x = (double)x; + if (fabs(dx) < DBL_EPSILON) { + double d1, d2; + /* + * Same X-coordinate indicates a vertical line. Pick the closest end + * point. + */ + d1 = p->y - y; + d2 = q->y - y; + if (fabs(d1) < fabs(d2)) { + t->y = p->y, d = d1; } else { - n = MIN3(elemPtr->xHigh.nValues, elemPtr->xLow.nValues, np); + t->y = q->y, d = d2; } - if (n > 0) { - Segment2d *errorBars; - Segment2d *segPtr; - int *errorToData; - int *indexPtr; - int i; + } else if (fabs(dy) < DBL_EPSILON) { + /* Horizontal line. */ + t->y = p->y, d = p->y - y; + } else { + double m, b; - segPtr = errorBars = malloc(n * 3 * sizeof(Segment2d)); - indexPtr = errorToData = malloc(n * 3 * sizeof(int)); - for (i = 0; i < n; i++) { - double x, y; - double high, low; - LineStyle *stylePtr; - - x = elemPtr->x.values[i]; - y = elemPtr->y.values[i]; - stylePtr = styleMap[i]; - if ((isfinite(x)) && (isfinite(y))) { - if (elemPtr->xError.nValues > 0) { - high = x + elemPtr->xError.values[i]; - low = x - elemPtr->xError.values[i]; - } else { - high = elemPtr->xHigh.values[i]; - low = elemPtr->xLow.values[i]; - } - if ((isfinite(high)) && (isfinite(low))) { - Point2d p, q; - - p = Blt_Map2D(graphPtr, high, y, &elemPtr->axes); - q = Blt_Map2D(graphPtr, low, y, &elemPtr->axes); - segPtr->p = p; - segPtr->q = q; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - /* Left cap */ - segPtr->p.x = segPtr->q.x = p.x; - segPtr->p.y = p.y - stylePtr->errorBarCapWidth; - segPtr->q.y = p.y + stylePtr->errorBarCapWidth; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - /* Right cap */ - segPtr->p.x = segPtr->q.x = q.x; - segPtr->p.y = q.y - stylePtr->errorBarCapWidth; - segPtr->q.y = q.y + stylePtr->errorBarCapWidth; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - } - } - } - elemPtr->xeb.segments = errorBars; - elemPtr->xeb.length = segPtr - errorBars; - elemPtr->xeb.map = errorToData; - } - if (elemPtr->yError.nValues > 0) { - n = MIN(elemPtr->yError.nValues, np); + m = dy / dx; + b = p->y - (m * p->x); + t->y = (x * m) + b; + d = y - t->y; + } + return fabs(d); +} + +static double DistanceToYProc(int x, int y, Point2d *p, Point2d *q, Point2d *t) +{ + double dx, dy; + double d; + + if (p->y > q->y) { + if ((y > p->y) || (y < q->y)) { + return DBL_MAX; + } + } else { + if ((y > q->y) || (y < p->y)) { + return DBL_MAX; + } + } + dx = p->x - q->x; + dy = p->y - q->y; + t->y = y; + if (fabs(dy) < DBL_EPSILON) { + double d1, d2; + + /* Save Y-coordinate indicates an horizontal line. Pick the closest end + * point. */ + d1 = p->x - x; + d2 = q->x - x; + if (fabs(d1) < fabs(d2)) { + t->x = p->x, d = d1; } else { - n = MIN3(elemPtr->yHigh.nValues, elemPtr->yLow.nValues, np); - } - if (n > 0) { - Segment2d *errorBars; - Segment2d *segPtr; - int *errorToData; - int *indexPtr; - int i; - - segPtr = errorBars = malloc(n * 3 * sizeof(Segment2d)); - indexPtr = errorToData = malloc(n * 3 * sizeof(int)); - for (i = 0; i < n; i++) { - double x, y; - double high, low; - LineStyle *stylePtr; - - x = elemPtr->x.values[i]; - y = elemPtr->y.values[i]; - stylePtr = styleMap[i]; - if ((isfinite(x)) && (isfinite(y))) { - if (elemPtr->yError.nValues > 0) { - high = y + elemPtr->yError.values[i]; - low = y - elemPtr->yError.values[i]; - } else { - high = elemPtr->yHigh.values[i]; - low = elemPtr->yLow.values[i]; - } - if ((isfinite(high)) && (isfinite(low))) { - Point2d p, q; - - p = Blt_Map2D(graphPtr, x, high, &elemPtr->axes); - q = Blt_Map2D(graphPtr, x, low, &elemPtr->axes); - segPtr->p = p; - segPtr->q = q; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - /* Top cap. */ - segPtr->p.y = segPtr->q.y = p.y; - segPtr->p.x = p.x - stylePtr->errorBarCapWidth; - segPtr->q.x = p.x + stylePtr->errorBarCapWidth; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - /* Bottom cap. */ - segPtr->p.y = segPtr->q.y = q.y; - segPtr->p.x = q.x - stylePtr->errorBarCapWidth; - segPtr->q.x = q.x + stylePtr->errorBarCapWidth; - if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) { - segPtr++; - *indexPtr++ = i; - } - } - } - } - elemPtr->yeb.segments = errorBars; - elemPtr->yeb.length = segPtr - errorBars; - elemPtr->yeb.map = errorToData; + t->x = q->x, d = d2; } + } else if (fabs(dx) < DBL_EPSILON) { + /* Vertical line. */ + t->x = p->x, d = p->x - x; + } else { + double m, b; + + m = dy / dx; + b = p->y - (m * p->x); + t->x = (y - b) / m; + d = x - t->x; + } + return fabs(d); } -/* - *--------------------------------------------------------------------------- - * - * MapLineProc -- - * - * Calculates the actual window coordinates of the line element. The - * window coordinates are saved in an allocated point array. - * - * Results: - * None. - * - * Side effects: - * Memory is (re)allocated for the point array. - * - *--------------------------------------------------------------------------- - */ -static void -MapLineProc(Graph *graphPtr, Element *basePtr) -{ - LineElement *elemPtr = (LineElement *)basePtr; - MapInfo mi; - int size, np; - LineStyle **styleMap; - Blt_ChainLink link; - - ResetLine(elemPtr); - np = NUMBEROFPOINTS(elemPtr); - if (np < 1) { - return; /* No data points */ - } - GetScreenPoints(graphPtr, elemPtr, &mi); - MapSymbols(graphPtr, elemPtr, &mi); - - if ((elemPtr->flags & ACTIVE_PENDING) && (elemPtr->nActiveIndices > 0)) { - MapActiveSymbols(graphPtr, elemPtr); - } - /* - * Map connecting line segments if they are to be displayed. - */ - elemPtr->smooth = elemPtr->reqSmooth; - if ((np > 1) && (elemPtr->builtinPen.traceWidth > 0)) { - /* - * Do smoothing if necessary. This can extend the coordinate array, - * so both mi.points and mi.nPoints may change. - */ - switch (elemPtr->smooth) { - case PEN_SMOOTH_STEP: - GenerateSteps(&mi); - break; - - case PEN_SMOOTH_NATURAL: - case PEN_SMOOTH_QUADRATIC: - if (mi.nScreenPts < 3) { - /* Can't interpolate with less than three points. */ - elemPtr->smooth = PEN_SMOOTH_LINEAR; - } else { - GenerateSpline(graphPtr, elemPtr, &mi); - } - break; - - case PEN_SMOOTH_CATROM: - if (mi.nScreenPts < 3) { - /* Can't interpolate with less than three points. */ - elemPtr->smooth = PEN_SMOOTH_LINEAR; - } else { - GenerateParametricSpline(graphPtr, elemPtr, &mi); - } - break; - - default: - break; - } - if (elemPtr->rTolerance > 0.0) { - ReducePoints(&mi, elemPtr->rTolerance); - } - if (elemPtr->fillBg != NULL) { - MapFillArea(graphPtr, elemPtr, &mi); - } - MapTraces(graphPtr, elemPtr, &mi); - } - free(mi.screenPts); - free(mi.map); - - /* Set the symbol size of all the pen styles. */ - for (link = Blt_Chain_FirstLink(elemPtr->styles); link != NULL; - link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - LinePen *penPtr; - - stylePtr = Blt_Chain_GetValue(link); - penPtr = (LinePen *)stylePtr->penPtr; - size = ScaleSymbol(elemPtr, penPtr->symbol.size); - stylePtr->symbolSize = size; - stylePtr->errorBarCapWidth = (penPtr->errorBarCapWidth > 0) - ? penPtr->errorBarCapWidth : Round(size * 0.6666666); - stylePtr->errorBarCapWidth /= 2; - } - styleMap = (LineStyle **)Blt_StyleMap((Element *)elemPtr); - if (((elemPtr->yHigh.nValues > 0) && (elemPtr->yLow.nValues > 0)) || - ((elemPtr->xHigh.nValues > 0) && (elemPtr->xLow.nValues > 0)) || - (elemPtr->xError.nValues > 0) || (elemPtr->yError.nValues > 0)) { - MapErrorBars(graphPtr, elemPtr, styleMap); - } - MergePens(elemPtr, styleMap); - free(styleMap); -} - -static double -DistanceToLineProc( - int x, int y, /* Sample X-Y coordinate. */ - Point2d *p, Point2d *q, /* End points of the line segment. */ - Point2d *t) /* (out) Point on line segment. */ +static int ClosestTrace(Graph *graphPtr, LineElement *elemPtr, + ClosestSearch *searchPtr, DistanceProc *distProc) { - double right, left, top, bottom; - - *t = Blt_GetProjection(x, y, p, q); - if (p->x > q->x) { - right = p->x, left = q->x; - } else { - left = p->x, right = q->x; - } - if (p->y > q->y) { - bottom = p->y, top = q->y; - } else { - top = p->y, bottom = q->y; - } - if (t->x > right) { - t->x = right; - } else if (t->x < left) { - t->x = left; - } - if (t->y > bottom) { - t->y = bottom; - } else if (t->y < top) { - t->y = top; - } - return hypot((t->x - x), (t->y - y)); + Blt_ChainLink link; + Point2d closest; + double dMin; + int iClose; + + iClose = -1; /* Suppress compiler warning. */ + dMin = searchPtr->dist; + closest.x = closest.y = 0; /* Suppress compiler warning. */ + for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; + link = Blt_Chain_NextLink(link)) { + bltTrace *tracePtr; + Point2d *p, *pend; + + tracePtr = Blt_Chain_GetValue(link); + for (p = tracePtr->screenPts.points, + pend = p + (tracePtr->screenPts.length - 1); p < pend; p++) { + Point2d b; + double d; + + d = (*distProc)(searchPtr->x, searchPtr->y, p, p + 1, &b); + if (d < dMin) { + closest = b; + iClose = tracePtr->screenPts.map[p-tracePtr->screenPts.points]; + dMin = d; + } + } + } + if (dMin < searchPtr->dist) { + searchPtr->dist = dMin; + searchPtr->elemPtr = (Element *)elemPtr; + searchPtr->index = iClose; + searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y, + &elemPtr->axes); + return TRUE; + } + return FALSE; } -static double -DistanceToXProc( - int x, int y, /* Search X-Y coordinate. */ - Point2d *p, - Point2d *q, /* End points of the line segment. */ - Point2d *t) /* (out) Point on line segment. */ +static void ClosestPoint(LineElement *elemPtr, ClosestSearch *searchPtr) { + double dMin; + int count, iClose; + Point2d *pp; + + dMin = searchPtr->dist; + iClose = 0; + + /* + * Instead of testing each data point in graph coordinates, look at the + * array of mapped screen coordinates. The advantages are + * 1) only examine points that are visible (unclipped), and + * 2) the computed distance is already in screen coordinates. + */ + for (pp = elemPtr->symbolPts.points, count = 0; + count < elemPtr->symbolPts.length; count++, pp++) { double dx, dy; double d; - if (p->x > q->x) { - if ((x > p->x) || (x < q->x)) { - return DBL_MAX; /* X-coordinate outside line segment. */ - } - } else { - if ((x > q->x) || (x < p->x)) { - return DBL_MAX; /* X-coordinate outside line segment. */ - } - } - dx = p->x - q->x; - dy = p->y - q->y; - t->x = (double)x; - if (fabs(dx) < DBL_EPSILON) { - double d1, d2; - /* - * Same X-coordinate indicates a vertical line. Pick the closest end - * point. - */ - d1 = p->y - y; - d2 = q->y - y; - if (fabs(d1) < fabs(d2)) { - t->y = p->y, d = d1; - } else { - t->y = q->y, d = d2; - } - } else if (fabs(dy) < DBL_EPSILON) { - /* Horizontal line. */ - t->y = p->y, d = p->y - y; + dx = (double)(searchPtr->x - pp->x); + dy = (double)(searchPtr->y - pp->y); + if (searchPtr->along == SEARCH_BOTH) { + d = hypot(dx, dy); + } else if (searchPtr->along == SEARCH_X) { + d = dx; + } else if (searchPtr->along == SEARCH_Y) { + d = dy; } else { - double m, b; - - m = dy / dx; - b = p->y - (m * p->x); - t->y = (x * m) + b; - d = y - t->y; - } - return fabs(d); + /* This can't happen */ + continue; + } + if (d < dMin) { + iClose = elemPtr->symbolPts.map[count]; + dMin = d; + } + } + if (dMin < searchPtr->dist) { + searchPtr->elemPtr = (Element *)elemPtr; + searchPtr->dist = dMin; + searchPtr->index = iClose; + searchPtr->point.x = elemPtr->x.values[iClose]; + searchPtr->point.y = elemPtr->y.values[iClose]; + } } -static double -DistanceToYProc( - int x, int y, /* Search X-Y coordinate. */ - Point2d *p, Point2d *q, /* End points of the line segment. */ - Point2d *t) /* (out) Point on line segment. */ +static void GetLineExtentsProc(Element *basePtr, Region2d *extsPtr) { - double dx, dy; - double d; - - if (p->y > q->y) { - if ((y > p->y) || (y < q->y)) { - return DBL_MAX; - } - } else { - if ((y > q->y) || (y < p->y)) { - return DBL_MAX; - } - } - dx = p->x - q->x; - dy = p->y - q->y; - t->y = y; - if (fabs(dy) < DBL_EPSILON) { - double d1, d2; - - /* Save Y-coordinate indicates an horizontal line. Pick the closest end - * point. */ - d1 = p->x - x; - d2 = q->x - x; - if (fabs(d1) < fabs(d2)) { - t->x = p->x, d = d1; - } else { - t->x = q->x, d = d2; - } - } else if (fabs(dx) < DBL_EPSILON) { - /* Vertical line. */ - t->x = p->x, d = p->x - x; - } else { - double m, b; + LineElement *elemPtr = (LineElement *)basePtr; + int np; + + extsPtr->top = extsPtr->left = DBL_MAX; + extsPtr->bottom = extsPtr->right = -DBL_MAX; + + np = NUMBEROFPOINTS(elemPtr); + if (np < 1) { + return; + } + extsPtr->right = elemPtr->x.max; + if ((elemPtr->x.min <= 0.0) && (elemPtr->axes.x->logScale)) { + extsPtr->left = Blt_FindElemValuesMinimum(&elemPtr->x, DBL_MIN); + } else { + extsPtr->left = elemPtr->x.min; + } + extsPtr->bottom = elemPtr->y.max; + if ((elemPtr->y.min <= 0.0) && (elemPtr->axes.y->logScale)) { + extsPtr->top = Blt_FindElemValuesMinimum(&elemPtr->y, DBL_MIN); + } else { + extsPtr->top = elemPtr->y.min; + } + + /* Correct the data limits for error bars */ + + if (elemPtr->xError.nValues > 0) { + int i; - m = dy / dx; - b = p->y - (m * p->x); - t->x = (y - b) / m; - d = x - t->x; - } - return fabs(d); -} - -/* - *--------------------------------------------------------------------------- - * - * ClosestTrace -- - * - * Find the line segment closest to the given window coordinate in the - * element. - * - * Results: - * If a new minimum distance is found, the information regarding it is - * returned via searchPtr. - * - *--------------------------------------------------------------------------- - */ -static int -ClosestTrace( - Graph *graphPtr, /* Graph widget record */ - LineElement *elemPtr, - ClosestSearch *searchPtr, /* Info about closest point in - * element */ - DistanceProc *distProc) -{ - Blt_ChainLink link; - Point2d closest; - double dMin; - int iClose; - - iClose = -1; /* Suppress compiler warning. */ - dMin = searchPtr->dist; - closest.x = closest.y = 0; /* Suppress compiler warning. */ - for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; - link = Blt_Chain_NextLink(link)) { - bltTrace *tracePtr; - Point2d *p, *pend; - - tracePtr = Blt_Chain_GetValue(link); - for (p = tracePtr->screenPts.points, - pend = p + (tracePtr->screenPts.length - 1); p < pend; p++) { - Point2d b; - double d; - - d = (*distProc)(searchPtr->x, searchPtr->y, p, p + 1, &b); - if (d < dMin) { - closest = b; - iClose = tracePtr->screenPts.map[p-tracePtr->screenPts.points]; - dMin = d; - } - } - } - if (dMin < searchPtr->dist) { - searchPtr->dist = dMin; - searchPtr->elemPtr = (Element *)elemPtr; - searchPtr->index = iClose; - searchPtr->point = Blt_InvMap2D(graphPtr, closest.x, closest.y, - &elemPtr->axes); - return TRUE; - } - return FALSE; -} - -/* - *--------------------------------------------------------------------------- - * - * ClosestPoint -- - * - * Find the element whose data point is closest to the given screen - * coordinate. - * - * Results: - * If a new minimum distance is found, the information regarding - * it is returned via searchPtr. - * - *--------------------------------------------------------------------------- - */ -static void -ClosestPoint( - LineElement *elemPtr, /* Line element to be searched. */ - ClosestSearch *searchPtr) /* Assorted information related to - * searching for the closest point */ -{ - double dMin; - int count, iClose; - Point2d *pp; - - dMin = searchPtr->dist; - iClose = 0; - - /* - * Instead of testing each data point in graph coordinates, look at the - * array of mapped screen coordinates. The advantages are - * 1) only examine points that are visible (unclipped), and - * 2) the computed distance is already in screen coordinates. - */ - for (pp = elemPtr->symbolPts.points, count = 0; - count < elemPtr->symbolPts.length; count++, pp++) { - double dx, dy; - double d; - - dx = (double)(searchPtr->x - pp->x); - dy = (double)(searchPtr->y - pp->y); - if (searchPtr->along == SEARCH_BOTH) { - d = hypot(dx, dy); - } else if (searchPtr->along == SEARCH_X) { - d = dx; - } else if (searchPtr->along == SEARCH_Y) { - d = dy; - } else { - /* This can't happen */ - continue; - } - if (d < dMin) { - iClose = elemPtr->symbolPts.map[count]; - dMin = d; + np = MIN(elemPtr->xError.nValues, np); + for (i = 0; i < np; i++) { + double x; + + x = elemPtr->x.values[i] + elemPtr->xError.values[i]; + if (x > extsPtr->right) { + extsPtr->right = x; + } + x = elemPtr->x.values[i] - elemPtr->xError.values[i]; + if (elemPtr->axes.x->logScale) { + if (x < 0.0) { + x = -x; /* Mirror negative values, instead of + * ignoring them. */ } - } - if (dMin < searchPtr->dist) { - searchPtr->elemPtr = (Element *)elemPtr; - searchPtr->dist = dMin; - searchPtr->index = iClose; - searchPtr->point.x = elemPtr->x.values[iClose]; - searchPtr->point.y = elemPtr->y.values[iClose]; - } -} - -/* - *--------------------------------------------------------------------------- - * - * GetLineExtentsProc -- - * - * Retrieves the range of the line element - * - * Results: - * Returns the number of data points in the element. - * - *--------------------------------------------------------------------------- - */ -static void -GetLineExtentsProc(Element *basePtr, Region2d *extsPtr) -{ - LineElement *elemPtr = (LineElement *)basePtr; - int np; - - extsPtr->top = extsPtr->left = DBL_MAX; - extsPtr->bottom = extsPtr->right = -DBL_MAX; - - np = NUMBEROFPOINTS(elemPtr); - if (np < 1) { - return; - } - extsPtr->right = elemPtr->x.max; - if ((elemPtr->x.min <= 0.0) && (elemPtr->axes.x->logScale)) { - extsPtr->left = Blt_FindElemValuesMinimum(&elemPtr->x, DBL_MIN); - } else { - extsPtr->left = elemPtr->x.min; - } - extsPtr->bottom = elemPtr->y.max; - if ((elemPtr->y.min <= 0.0) && (elemPtr->axes.y->logScale)) { - extsPtr->top = Blt_FindElemValuesMinimum(&elemPtr->y, DBL_MIN); - } else { - extsPtr->top = elemPtr->y.min; - } - - /* Correct the data limits for error bars */ - - if (elemPtr->xError.nValues > 0) { - int i; - - np = MIN(elemPtr->xError.nValues, np); - for (i = 0; i < np; i++) { - double x; - - x = elemPtr->x.values[i] + elemPtr->xError.values[i]; - if (x > extsPtr->right) { - extsPtr->right = x; - } - x = elemPtr->x.values[i] - elemPtr->xError.values[i]; - if (elemPtr->axes.x->logScale) { - if (x < 0.0) { - x = -x; /* Mirror negative values, instead of - * ignoring them. */ - } - if ((x > DBL_MIN) && (x < extsPtr->left)) { - extsPtr->left = x; - } - } else if (x < extsPtr->left) { - extsPtr->left = x; - } - } - } else { - if ((elemPtr->xHigh.nValues > 0) && - (elemPtr->xHigh.max > extsPtr->right)) { - extsPtr->right = elemPtr->xHigh.max; + if ((x > DBL_MIN) && (x < extsPtr->left)) { + extsPtr->left = x; } - if (elemPtr->xLow.nValues > 0) { - double left; + } else if (x < extsPtr->left) { + extsPtr->left = x; + } + } + } else { + if ((elemPtr->xHigh.nValues > 0) && + (elemPtr->xHigh.max > extsPtr->right)) { + extsPtr->right = elemPtr->xHigh.max; + } + if (elemPtr->xLow.nValues > 0) { + double left; - if ((elemPtr->xLow.min <= 0.0) && - (elemPtr->axes.x->logScale)) { - left = Blt_FindElemValuesMinimum(&elemPtr->xLow, DBL_MIN); - } else { - left = elemPtr->xLow.min; - } - if (left < extsPtr->left) { - extsPtr->left = left; - } - } - } + if ((elemPtr->xLow.min <= 0.0) && + (elemPtr->axes.x->logScale)) { + left = Blt_FindElemValuesMinimum(&elemPtr->xLow, DBL_MIN); + } else { + left = elemPtr->xLow.min; + } + if (left < extsPtr->left) { + extsPtr->left = left; + } + } + } - if (elemPtr->yError.nValues > 0) { - int i; + if (elemPtr->yError.nValues > 0) { + int i; - np = MIN(elemPtr->yError.nValues, np); - for (i = 0; i < np; i++) { - double y; - - y = elemPtr->y.values[i] + elemPtr->yError.values[i]; - if (y > extsPtr->bottom) { - extsPtr->bottom = y; - } - y = elemPtr->y.values[i] - elemPtr->yError.values[i]; - if (elemPtr->axes.y->logScale) { - if (y < 0.0) { - y = -y; /* Mirror negative values, instead of - * ignoring them. */ - } - if ((y > DBL_MIN) && (y < extsPtr->left)) { - extsPtr->top = y; - } - } else if (y < extsPtr->top) { - extsPtr->top = y; - } - } - } else { - if ((elemPtr->yHigh.nValues > 0) && - (elemPtr->yHigh.max > extsPtr->bottom)) { - extsPtr->bottom = elemPtr->yHigh.max; + np = MIN(elemPtr->yError.nValues, np); + for (i = 0; i < np; i++) { + double y; + + y = elemPtr->y.values[i] + elemPtr->yError.values[i]; + if (y > extsPtr->bottom) { + extsPtr->bottom = y; + } + y = elemPtr->y.values[i] - elemPtr->yError.values[i]; + if (elemPtr->axes.y->logScale) { + if (y < 0.0) { + y = -y; /* Mirror negative values, instead of + * ignoring them. */ } - if (elemPtr->yLow.nValues > 0) { - double top; - - if ((elemPtr->yLow.min <= 0.0) && - (elemPtr->axes.y->logScale)) { - top = Blt_FindElemValuesMinimum(&elemPtr->yLow, DBL_MIN); - } else { - top = elemPtr->yLow.min; - } - if (top < extsPtr->top) { - extsPtr->top = top; - } + if ((y > DBL_MIN) && (y < extsPtr->left)) { + extsPtr->top = y; } - } + } else if (y < extsPtr->top) { + extsPtr->top = y; + } + } + } else { + if ((elemPtr->yHigh.nValues > 0) && + (elemPtr->yHigh.max > extsPtr->bottom)) { + extsPtr->bottom = elemPtr->yHigh.max; + } + if (elemPtr->yLow.nValues > 0) { + double top; + + if ((elemPtr->yLow.min <= 0.0) && + (elemPtr->axes.y->logScale)) { + top = Blt_FindElemValuesMinimum(&elemPtr->yLow, DBL_MIN); + } else { + top = elemPtr->yLow.min; + } + if (top < extsPtr->top) { + extsPtr->top = top; + } + } + } } -/* - *--------------------------------------------------------------------------- - * - * ConfigureLineProc -- - * - * Sets up the appropriate configuration parameters in the GC. It is - * assumed the parameters have been previously set by a call to - * Blt_ConfigureWidget. - * - * Results: - * The return value is a standard TCL result. If TCL_ERROR is returned, - * then interp->result contains an error message. - * - * Side effects: - * Configuration information such as line width, line style, color - * etc. get set in a new GC. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ConfigureLineProc(Graph *graphPtr, Element *basePtr) +static int ConfigureLineProc(Graph *graphPtr, Element *basePtr) { - LineElement *elemPtr = (LineElement *)basePtr; - unsigned long gcMask; - XGCValues gcValues; - GC newGC; - Blt_ChainLink link; - LineStyle *stylePtr; - - if (ConfigurePenProc(graphPtr, (Pen *)&elemPtr->builtinPen) != TCL_OK) { - return TCL_ERROR; - } - /* - * Point to the static normal/active pens if no external pens have been - * selected. - */ - link = Blt_Chain_FirstLink(elemPtr->styles); - if (link == NULL) { - link = Blt_Chain_AllocLink(sizeof(LineStyle)); - Blt_Chain_LinkAfter(elemPtr->styles, link, NULL); - } - stylePtr = Blt_Chain_GetValue(link); - stylePtr->penPtr = NORMALPEN(elemPtr); - - /* - * Set the outline GC for this pen: GCForeground is outline color. - * GCBackground is the fill color (only used for bitmap symbols). - */ - gcMask = 0; - if (elemPtr->fillFgColor != NULL) { - gcMask |= GCForeground; - gcValues.foreground = elemPtr->fillFgColor->pixel; - } - if (elemPtr->fillBgColor != NULL) { - gcMask |= GCBackground; - gcValues.background = elemPtr->fillBgColor->pixel; - } - newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); - if (elemPtr->fillGC != NULL) { - Tk_FreeGC(graphPtr->display, elemPtr->fillGC); - } - elemPtr->fillGC = newGC; - + LineElement *elemPtr = (LineElement *)basePtr; + unsigned long gcMask; + XGCValues gcValues; + GC newGC; + Blt_ChainLink link; + LineStyle *stylePtr; + + if (ConfigurePenProc(graphPtr, (Pen *)&elemPtr->builtinPen) != TCL_OK) { + return TCL_ERROR; + } + /* + * Point to the static normal/active pens if no external pens have been + * selected. + */ + link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + if (link == NULL) { + link = Blt_Chain_AllocLink(sizeof(LineStyle)); + Blt_Chain_LinkAfter(elemPtr->stylesPalette, link, NULL); + } + stylePtr = Blt_Chain_GetValue(link); + stylePtr->penPtr = NORMALPEN(elemPtr); + + /* + * Set the outline GC for this pen: GCForeground is outline color. + * GCBackground is the fill color (only used for bitmap symbols). + */ + gcMask = 0; + if (elemPtr->fillFgColor != NULL) { + gcMask |= GCForeground; + gcValues.foreground = elemPtr->fillFgColor->pixel; + } + if (elemPtr->fillBgColor != NULL) { + gcMask |= GCBackground; + gcValues.background = elemPtr->fillBgColor->pixel; + } + newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues); + if (elemPtr->fillGC != NULL) { + Tk_FreeGC(graphPtr->display, elemPtr->fillGC); + } + elemPtr->fillGC = newGC; + + /* if (Blt_ConfigModified(elemPtr->configSpecs, "-scalesymbols", - (char *)NULL)) { - elemPtr->flags |= (MAP_ITEM | SCALE_SYMBOL); + (char *)NULL)) { + elemPtr->flags |= (MAP_ITEM | SCALE_SYMBOL); } if (Blt_ConfigModified(elemPtr->configSpecs, "-pixels", "-trace", - "-*data", "-smooth", "-map*", "-label", "-hide", "-x", "-y", - "-areabackground", (char *)NULL)) { - elemPtr->flags |= MAP_ITEM; + "-*data", "-smooth", "-map*", "-label", "-hide", "-x", "-y", + "-areabackground", (char *)NULL)) { + elemPtr->flags |= MAP_ITEM; } - return TCL_OK; + */ + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * ClosestLineProc -- - * - * Find the closest point or line segment (if interpolated) to the given - * window coordinate in the line element. - * - * Results: - * Returns the distance of the closest point among other information. - * - *--------------------------------------------------------------------------- - */ -static void -ClosestLineProc(Graph *graphPtr, Element *basePtr, ClosestSearch *searchPtr) +static void ClosestLineProc(Graph *graphPtr, Element *basePtr, + ClosestSearch *searchPtr) { - LineElement *elemPtr = (LineElement *)basePtr; - int mode; + LineElement *elemPtr = (LineElement *)basePtr; + int mode; - mode = searchPtr->mode; - if (mode == SEARCH_AUTO) { - LinePen *penPtr; + mode = searchPtr->mode; + if (mode == SEARCH_AUTO) { + LinePen *penPtr; - penPtr = NORMALPEN(elemPtr); - mode = SEARCH_POINTS; - if ((NUMBEROFPOINTS(elemPtr) > 1) && (penPtr->traceWidth > 0)) { - mode = SEARCH_TRACES; - } - } - if (mode == SEARCH_POINTS) { - ClosestPoint(elemPtr, searchPtr); + penPtr = NORMALPEN(elemPtr); + mode = SEARCH_POINTS; + if ((NUMBEROFPOINTS(elemPtr) > 1) && (penPtr->traceWidth > 0)) { + mode = SEARCH_TRACES; + } + } + if (mode == SEARCH_POINTS) { + ClosestPoint(elemPtr, searchPtr); + } else { + DistanceProc *distProc; + int found; + + if (searchPtr->along == SEARCH_X) { + distProc = DistanceToXProc; + } else if (searchPtr->along == SEARCH_Y) { + distProc = DistanceToYProc; } else { - DistanceProc *distProc; - int found; - - if (searchPtr->along == SEARCH_X) { - distProc = DistanceToXProc; - } else if (searchPtr->along == SEARCH_Y) { - distProc = DistanceToYProc; - } else { - distProc = DistanceToLineProc; - } - found = ClosestTrace(graphPtr, elemPtr, searchPtr, distProc); - if ((!found) && (searchPtr->along != SEARCH_BOTH)) { - ClosestPoint(elemPtr, searchPtr); - } + distProc = DistanceToLineProc; + } + found = ClosestTrace(graphPtr, elemPtr, searchPtr, distProc); + if ((!found) && (searchPtr->along != SEARCH_BOTH)) { + ClosestPoint(elemPtr, searchPtr); } + } } /* @@ -3321,1534 +2923,1331 @@ ClosestLineProc(Graph *graphPtr, Element *basePtr, ClosestSearch *searchPtr) #define MAX_DRAWRECTANGLES(d) Blt_MaxRequestSize(d, sizeof(XRectangle)) #define MAX_DRAWARCS(d) Blt_MaxRequestSize(d, sizeof(XArc)) -static void -DrawCircles(Display *display, Drawable drawable, LineElement *elemPtr, - LinePen *penPtr, int nSymbolPts, Point2d *symbolPts, int radius) +static void DrawCircles(Display *display, Drawable drawable, + LineElement *elemPtr, LinePen *penPtr, + int nSymbolPts, Point2d *symbolPts, int radius) { - int i; - XArc *arcs; /* Array of arcs (circle) */ - int reqSize; - int s; - int count; + int i; + XArc *arcs; /* Array of arcs (circle) */ + int reqSize; + int s; + int count; - s = radius + radius; - arcs = malloc(nSymbolPts * sizeof(XArc)); + s = radius + radius; + arcs = malloc(nSymbolPts * sizeof(XArc)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *pend; - XArc *ap; + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *pend; + XArc *ap; - ap = arcs; - count = 0; - for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - ap->x = Round(pp->x) - radius; - ap->y = Round(pp->y) - radius; - ap->width = ap->height = (unsigned short)s; - ap->angle1 = 0; - ap->angle2 = 23040; - ap++, count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *pend; - XArc *ap; - - ap = arcs; - for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { - ap->x = Round(pp->x) - radius; - ap->y = Round(pp->y) - radius; - ap->width = ap->height = (unsigned short)s; - ap->angle1 = 0; - ap->angle2 = 23040; - ap++; - } - count = nSymbolPts; + ap = arcs; + count = 0; + for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + ap->x = Round(pp->x) - radius; + ap->y = Round(pp->y) - radius; + ap->width = ap->height = (unsigned short)s; + ap->angle1 = 0; + ap->angle2 = 23040; + ap++, count++; + } + elemPtr->symbolCounter++; + } + } else { + Point2d *pp, *pend; + XArc *ap; + + ap = arcs; + for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { + ap->x = Round(pp->x) - radius; + ap->y = Round(pp->y) - radius; + ap->width = ap->height = (unsigned short)s; + ap->angle1 = 0; + ap->angle2 = 23040; + ap++; + } + count = nSymbolPts; + } + reqSize = MAX_DRAWARCS(display); + for (i = 0; i < count; i += reqSize) { + int n; + + n = ((i + reqSize) > count) ? (count - i) : reqSize; + if (penPtr->symbol.fillGC != NULL) { + XFillArcs(display, drawable, penPtr->symbol.fillGC, arcs + i, n); } - reqSize = MAX_DRAWARCS(display); - for (i = 0; i < count; i += reqSize) { - int n; - - n = ((i + reqSize) > count) ? (count - i) : reqSize; - if (penPtr->symbol.fillGC != NULL) { - XFillArcs(display, drawable, penPtr->symbol.fillGC, arcs + i, n); - } - if (penPtr->symbol.outlineWidth > 0) { - XDrawArcs(display, drawable, penPtr->symbol.outlineGC, arcs + i, n); - } + if (penPtr->symbol.outlineWidth > 0) { + XDrawArcs(display, drawable, penPtr->symbol.outlineGC, arcs + i, n); } - free(arcs); + } + free(arcs); } -static void -DrawSquares(Display *display, Drawable drawable, LineElement *elemPtr, - LinePen *penPtr, int nSymbolPts, Point2d *symbolPts, int r) +static void DrawSquares(Display *display, Drawable drawable, + LineElement *elemPtr, LinePen *penPtr, + int nSymbolPts, Point2d *symbolPts, int r) { - XRectangle *rectangles; - XRectangle *rp, *rend; - int reqSize; - int s, count; + XRectangle *rectangles; + XRectangle *rp, *rend; + int reqSize; + int s, count; - s = r + r; - rectangles = malloc(nSymbolPts * sizeof(XRectangle)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *pend; - XRectangle *rp; + s = r + r; + rectangles = malloc(nSymbolPts * sizeof(XRectangle)); + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *pend; + XRectangle *rp; - count = 0; - rp = rectangles; - for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - rp->x = Round(pp->x) - r; - rp->y = Round(pp->y) - r; - rp->width = rp->height = (unsigned short)s; - rp++, count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *pend; - XRectangle *rp; - - rp = rectangles; - for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { - rp->x = Round(pp->x) - r; - rp->y = Round(pp->y) - r; - rp->width = rp->height = (unsigned short)s; - rp++; - } - count = nSymbolPts; + count = 0; + rp = rectangles; + for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + rp->x = Round(pp->x) - r; + rp->y = Round(pp->y) - r; + rp->width = rp->height = (unsigned short)s; + rp++, count++; + } + elemPtr->symbolCounter++; + } + } else { + Point2d *pp, *pend; + XRectangle *rp; + + rp = rectangles; + for (pp = symbolPts, pend = pp + nSymbolPts; pp < pend; pp++) { + rp->x = Round(pp->x) - r; + rp->y = Round(pp->y) - r; + rp->width = rp->height = (unsigned short)s; + rp++; + } + count = nSymbolPts; + } + reqSize = MAX_DRAWRECTANGLES(display) - 3; + for (rp = rectangles, rend = rp + count; rp < rend; rp += reqSize) { + int n; + + n = rend - rp; + if (n > reqSize) { + n = reqSize; } - reqSize = MAX_DRAWRECTANGLES(display) - 3; - for (rp = rectangles, rend = rp + count; rp < rend; rp += reqSize) { - int n; - - n = rend - rp; - if (n > reqSize) { - n = reqSize; - } - if (penPtr->symbol.fillGC != NULL) { - XFillRectangles(display, drawable, penPtr->symbol.fillGC, rp, n); - } - if (penPtr->symbol.outlineWidth > 0) { - XDrawRectangles(display, drawable, penPtr->symbol.outlineGC, rp, n); - } + if (penPtr->symbol.fillGC != NULL) { + XFillRectangles(display, drawable, penPtr->symbol.fillGC, rp, n); + } + if (penPtr->symbol.outlineWidth > 0) { + XDrawRectangles(display, drawable, penPtr->symbol.outlineGC, rp, n); } - free(rectangles); + } + free(rectangles); } -/* - *--------------------------------------------------------------------------- - * - * DrawSymbols -- - * - * Draw the symbols centered at the each given x,y coordinate in the array - * of points. - * - * Results: - * None. - * - * Side Effects: - * Draws a symbol at each coordinate given. If active, only those - * coordinates which are currently active are drawn. - * - *--------------------------------------------------------------------------- - */ -static void -DrawSymbols( - Graph *graphPtr, /* Graph widget record */ - Drawable drawable, /* Pixmap or window to draw into */ - LineElement *elemPtr, - LinePen *penPtr, - int size, /* Size of element */ - int nSymbolPts, /* Number of coordinates in array */ - Point2d *symbolPts) /* Array of x,y coordinates for line */ +static void DrawSymbols(Graph *graphPtr, Drawable drawable, + LineElement *elemPtr, LinePen *penPtr, + int size, int nSymbolPts, Point2d *symbolPts) { - XPoint pattern[13]; /* Template for polygon symbols */ - int r1, r2; - int count; + XPoint pattern[13]; /* Template for polygon symbols */ + int r1, r2; + int count; #define SQRT_PI 1.77245385090552 #define S_RATIO 0.886226925452758 - if (size < 3) { - if (penPtr->symbol.fillGC != NULL) { - Point2d *pp, *endp; - XPoint *points, *xpp; + if (size < 3) { + if (penPtr->symbol.fillGC != NULL) { + Point2d *pp, *endp; + XPoint *points, *xpp; - xpp = points = malloc(nSymbolPts * sizeof(XPoint)); - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - xpp->x = Round(pp->x); - xpp->y = Round(pp->y); - xpp++; - } - XDrawPoints(graphPtr->display, drawable, penPtr->symbol.fillGC, - points, nSymbolPts, CoordModeOrigin); - free(points); - } - return; - } - r1 = (int)ceil(size * 0.5); - r2 = (int)ceil(size * S_RATIO * 0.5); - - switch (penPtr->symbol.type) { - case SYMBOL_NONE: - break; - - case SYMBOL_SQUARE: - DrawSquares(graphPtr->display, drawable, elemPtr, penPtr, nSymbolPts, - symbolPts, r2); - break; - - case SYMBOL_CIRCLE: - DrawCircles(graphPtr->display, drawable, elemPtr, penPtr, nSymbolPts, - symbolPts, r1); - break; - - case SYMBOL_SPLUS: - case SYMBOL_SCROSS: - { - XSegment *segments; /* Array of line segments (splus, + xpp = points = malloc(nSymbolPts * sizeof(XPoint)); + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + xpp->x = Round(pp->x); + xpp->y = Round(pp->y); + xpp++; + } + XDrawPoints(graphPtr->display, drawable, penPtr->symbol.fillGC, + points, nSymbolPts, CoordModeOrigin); + free(points); + } + return; + } + r1 = (int)ceil(size * 0.5); + r2 = (int)ceil(size * S_RATIO * 0.5); + + switch (penPtr->symbol.type) { + case SYMBOL_NONE: + break; + + case SYMBOL_SQUARE: + DrawSquares(graphPtr->display, drawable, elemPtr, penPtr, nSymbolPts, + symbolPts, r2); + break; + + case SYMBOL_CIRCLE: + DrawCircles(graphPtr->display, drawable, elemPtr, penPtr, nSymbolPts, + symbolPts, r1); + break; + + case SYMBOL_SPLUS: + case SYMBOL_SCROSS: + { + XSegment *segments; /* Array of line segments (splus, * scross) */ - int i; - int reqSize, nSegs; - - if (penPtr->symbol.type == SYMBOL_SCROSS) { - r2 = Round((double)r2 * M_SQRT1_2); - pattern[3].y = pattern[2].x = pattern[0].x = pattern[0].y = -r2; - pattern[3].x = pattern[2].y = pattern[1].y = pattern[1].x = r2; - } else { - pattern[0].y = pattern[1].y = pattern[2].x = pattern[3].x = 0; - pattern[0].x = pattern[2].y = -r2; - pattern[1].x = pattern[3].y = r2; - } - segments = malloc(nSymbolPts * 2 * sizeof(XSegment)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; - XSegment *sp; - - sp = segments; - count = 0; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - int rndx, rndy; - rndx = Round(pp->x), rndy = Round(pp->y); - sp->x1 = pattern[0].x + rndx; - sp->y1 = pattern[0].y + rndy; - sp->x2 = pattern[1].x + rndx; - sp->y2 = pattern[1].y + rndy; - sp++; - sp->x1 = pattern[2].x + rndx; - sp->y1 = pattern[2].y + rndy; - sp->x2 = pattern[3].x + rndx; - sp->y2 = pattern[3].y + rndy; - sp++; - count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - XSegment *sp; - - sp = segments; - count = nSymbolPts; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int rndx, rndy; - rndx = Round(pp->x), rndy = Round(pp->y); - sp->x1 = pattern[0].x + rndx; - sp->y1 = pattern[0].y + rndy; - sp->x2 = pattern[1].x + rndx; - sp->y2 = pattern[1].y + rndy; - sp++; - sp->x1 = pattern[2].x + rndx; - sp->y1 = pattern[2].y + rndy; - sp->x2 = pattern[3].x + rndx; - sp->y2 = pattern[3].y + rndy; - sp++; - } - } - nSegs = count * 2; - /* Always draw skinny symbols regardless of the outline width */ - reqSize = MAX_DRAWSEGMENTS(graphPtr->display); - for (i = 0; i < nSegs; i += reqSize) { - int chunk; - - chunk = ((i + reqSize) > nSegs) ? (nSegs - i) : reqSize; - XDrawSegments(graphPtr->display, drawable, - penPtr->symbol.outlineGC, segments + i, chunk); - } - free(segments); - } - break; - - case SYMBOL_PLUS: - case SYMBOL_CROSS: - { - XPoint *polygon; - int d; /* Small delta for cross/plus - * thickness */ - - d = (r2 / 3); - - /* - * - * 2 3 The plus/cross symbol is a closed polygon - * of 12 points. The diagram to the left - * 0,12 1 4 5 represents the positions of the points - * x,y which are computed below. The extra - * 11 10 7 6 (thirteenth) point connects the first and - * last points. - * 9 8 - */ - - pattern[0].x = pattern[11].x = pattern[12].x = -r2; - pattern[2].x = pattern[1].x = pattern[10].x = pattern[9].x = -d; - pattern[3].x = pattern[4].x = pattern[7].x = pattern[8].x = d; - pattern[5].x = pattern[6].x = r2; - pattern[2].y = pattern[3].y = -r2; - pattern[0].y = pattern[1].y = pattern[4].y = pattern[5].y = - pattern[12].y = -d; - pattern[11].y = pattern[10].y = pattern[7].y = pattern[6].y = d; - pattern[9].y = pattern[8].y = r2; - - if (penPtr->symbol.type == SYMBOL_CROSS) { - int i; - - /* For the cross symbol, rotate the points by 45 degrees. */ - for (i = 0; i < 12; i++) { - double dx, dy; - - dx = (double)pattern[i].x * M_SQRT1_2; - dy = (double)pattern[i].y * M_SQRT1_2; - pattern[i].x = Round(dx - dy); - pattern[i].y = Round(dx + dy); - } - pattern[12] = pattern[0]; - } - polygon = malloc(nSymbolPts * 13 * sizeof(XPoint)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; - XPoint *xpp; - - count = 0; - xpp = polygon; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - int i; - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 13; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - XPoint *xpp; - - xpp = polygon; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int i; - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 13; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - } - count = nSymbolPts; - } - if (penPtr->symbol.fillGC != NULL) { - int i; - XPoint *xpp; - - for (xpp = polygon, i = 0; i < count; i++, xpp += 13) { - XFillPolygon(graphPtr->display, drawable, - penPtr->symbol.fillGC, xpp, 13, Complex, - CoordModeOrigin); - } - } - if (penPtr->symbol.outlineWidth > 0) { - int i; - XPoint *xpp; - - for (xpp = polygon, i = 0; i < count; i++, xpp += 13) { - XDrawLines(graphPtr->display, drawable, - penPtr->symbol.outlineGC, xpp, 13, CoordModeOrigin); - } - } - free(polygon); - } - break; - - case SYMBOL_DIAMOND: - { - XPoint *polygon; - - /* - * - * The plus symbol is a closed polygon - * 1 of 4 points. The diagram to the left - * represents the positions of the points - * 0,4 x,y 2 which are computed below. The extra - * (fifth) point connects the first and - * 3 last points. - * - */ - pattern[1].y = pattern[0].x = -r1; - pattern[2].y = pattern[3].x = pattern[0].y = pattern[1].x = 0; - pattern[3].y = pattern[2].x = r1; - pattern[4] = pattern[0]; - - polygon = malloc(nSymbolPts * 5 * sizeof(XPoint)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; - XPoint *xpp; - - xpp = polygon; - count = 0; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int i; - - if (DRAW_SYMBOL(elemPtr)) { - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 5; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - XPoint *xpp; - - xpp = polygon; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int i; - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 5; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - } - count = nSymbolPts; - } - if (penPtr->symbol.fillGC != NULL) { - XPoint *xpp; - int i; - - for (xpp = polygon, i = 0; i < count; i++, xpp += 5) { - XFillPolygon(graphPtr->display, drawable, - penPtr->symbol.fillGC, xpp, 5, Convex, CoordModeOrigin); + int i; + int reqSize, nSegs; + + if (penPtr->symbol.type == SYMBOL_SCROSS) { + r2 = Round((double)r2 * M_SQRT1_2); + pattern[3].y = pattern[2].x = pattern[0].x = pattern[0].y = -r2; + pattern[3].x = pattern[2].y = pattern[1].y = pattern[1].x = r2; + } else { + pattern[0].y = pattern[1].y = pattern[2].x = pattern[3].x = 0; + pattern[0].x = pattern[2].y = -r2; + pattern[1].x = pattern[3].y = r2; + } + segments = malloc(nSymbolPts * 2 * sizeof(XSegment)); + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; + XSegment *sp; - } - } - if (penPtr->symbol.outlineWidth > 0) { - XPoint *xpp; - int i; - - for (xpp = polygon, i = 0; i < count; i++, xpp += 5) { - XDrawLines(graphPtr->display, drawable, - penPtr->symbol.outlineGC, xpp, 5, CoordModeOrigin); - } - } - free(polygon); + sp = segments; + count = 0; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + int rndx, rndy; + rndx = Round(pp->x), rndy = Round(pp->y); + sp->x1 = pattern[0].x + rndx; + sp->y1 = pattern[0].y + rndy; + sp->x2 = pattern[1].x + rndx; + sp->y2 = pattern[1].y + rndy; + sp++; + sp->x1 = pattern[2].x + rndx; + sp->y1 = pattern[2].y + rndy; + sp->x2 = pattern[3].x + rndx; + sp->y2 = pattern[3].y + rndy; + sp++; + count++; + } + elemPtr->symbolCounter++; } - break; - - case SYMBOL_TRIANGLE: - case SYMBOL_ARROW: - { - XPoint *polygon; - double b; - int b2, h1, h2; -#define H_RATIO 1.1663402261671607 -#define B_RATIO 1.3467736870885982 -#define TAN30 0.57735026918962573 -#define COS30 0.86602540378443871 + } else { + Point2d *pp, *endp; + XSegment *sp; - b = Round(size * B_RATIO * 0.7); - b2 = Round(b * 0.5); - h2 = Round(TAN30 * b2); - h1 = Round(b2 / COS30); - /* - * - * The triangle symbol is a closed polygon - * 0,3 of 3 points. The diagram to the left - * represents the positions of the points - * x,y which are computed below. The extra - * (fourth) point connects the first and - * 2 1 last points. - * - */ - - if (penPtr->symbol.type == SYMBOL_ARROW) { - pattern[3].x = pattern[0].x = 0; - pattern[3].y = pattern[0].y = h1; - pattern[1].x = b2; - pattern[2].y = pattern[1].y = -h2; - pattern[2].x = -b2; - } else { - pattern[3].x = pattern[0].x = 0; - pattern[3].y = pattern[0].y = -h1; - pattern[1].x = b2; - pattern[2].y = pattern[1].y = h2; - pattern[2].x = -b2; - } - polygon = malloc(nSymbolPts * 4 * sizeof(XPoint)); - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; - XPoint *xpp; - - xpp = polygon; - count = 0; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int i; - - if (DRAW_SYMBOL(elemPtr)) { - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 4; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - count++; - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - XPoint *xpp; - - xpp = polygon; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int i; - int rndx, rndy; - - rndx = Round(pp->x), rndy = Round(pp->y); - for (i = 0; i < 4; i++) { - xpp->x = pattern[i].x + rndx; - xpp->y = pattern[i].y + rndy; - xpp++; - } - } - count = nSymbolPts; - } - if (penPtr->symbol.fillGC != NULL) { - XPoint *xpp; - int i; - - xpp = polygon; - for (xpp = polygon, i = 0; i < count; i++, xpp += 4) { - XFillPolygon(graphPtr->display, drawable, - penPtr->symbol.fillGC, xpp, 4, Convex, CoordModeOrigin); - } - } - if (penPtr->symbol.outlineWidth > 0) { - XPoint *xpp; - int i; - - xpp = polygon; - for (xpp = polygon, i = 0; i < count; i++, xpp += 4) { - XDrawLines(graphPtr->display, drawable, - penPtr->symbol.outlineGC, xpp, 4, CoordModeOrigin); - } - } - free(polygon); + sp = segments; + count = nSymbolPts; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int rndx, rndy; + rndx = Round(pp->x), rndy = Round(pp->y); + sp->x1 = pattern[0].x + rndx; + sp->y1 = pattern[0].y + rndy; + sp->x2 = pattern[1].x + rndx; + sp->y2 = pattern[1].y + rndy; + sp++; + sp->x1 = pattern[2].x + rndx; + sp->y1 = pattern[2].y + rndy; + sp->x2 = pattern[3].x + rndx; + sp->y2 = pattern[3].y + rndy; + sp++; } - break; + } + nSegs = count * 2; + /* Always draw skinny symbols regardless of the outline width */ + reqSize = MAX_DRAWSEGMENTS(graphPtr->display); + for (i = 0; i < nSegs; i += reqSize) { + int chunk; + + chunk = ((i + reqSize) > nSegs) ? (nSegs - i) : reqSize; + XDrawSegments(graphPtr->display, drawable, + penPtr->symbol.outlineGC, segments + i, chunk); + } + free(segments); + } + break; + + case SYMBOL_PLUS: + case SYMBOL_CROSS: + { + XPoint *polygon; + int d; /* Small delta for cross/plus + * thickness */ + + d = (r2 / 3); + + /* + * + * 2 3 The plus/cross symbol is a closed polygon + * of 12 points. The diagram to the left + * 0,12 1 4 5 represents the positions of the points + * x,y which are computed below. The extra + * 11 10 7 6 (thirteenth) point connects the first and + * last points. + * 9 8 + */ + + pattern[0].x = pattern[11].x = pattern[12].x = -r2; + pattern[2].x = pattern[1].x = pattern[10].x = pattern[9].x = -d; + pattern[3].x = pattern[4].x = pattern[7].x = pattern[8].x = d; + pattern[5].x = pattern[6].x = r2; + pattern[2].y = pattern[3].y = -r2; + pattern[0].y = pattern[1].y = pattern[4].y = pattern[5].y = + pattern[12].y = -d; + pattern[11].y = pattern[10].y = pattern[7].y = pattern[6].y = d; + pattern[9].y = pattern[8].y = r2; + + if (penPtr->symbol.type == SYMBOL_CROSS) { + int i; - case SYMBOL_IMAGE: - { - int w, h; - int dx, dy; + /* For the cross symbol, rotate the points by 45 degrees. */ + for (i = 0; i < 12; i++) { + double dx, dy; - Tk_SizeOfImage(penPtr->symbol.image, &w, &h); + dx = (double)pattern[i].x * M_SQRT1_2; + dy = (double)pattern[i].y * M_SQRT1_2; + pattern[i].x = Round(dx - dy); + pattern[i].y = Round(dx + dy); + } + pattern[12] = pattern[0]; + } + polygon = malloc(nSymbolPts * 13 * sizeof(XPoint)); + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; + XPoint *xpp; - dx = w / 2; - dy = h / 2; - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; + count = 0; + xpp = polygon; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + int i; + int rndx, rndy; - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - int x, y; - - x = Round(pp->x) - dx; - y = Round(pp->y) - dy; - Tk_RedrawImage(penPtr->symbol.image, 0, 0, w, h, - drawable, x, y); - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int x, y; - - x = Round(pp->x) - dx; - y = Round(pp->y) - dy; - Tk_RedrawImage(penPtr->symbol.image, 0, 0, w, h, - drawable, x, y); - } - } - } - break; - - case SYMBOL_BITMAP: - { - Pixmap bitmap, mask; - int w, h, bw, bh; - double scale, sx, sy; - int dx, dy; - - Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &w, &h); - mask = None; - - /* - * Compute the size of the scaled bitmap. Stretch the bitmap to fit - * a nxn bounding box. - */ - sx = (double)size / (double)w; - sy = (double)size / (double)h; - scale = MIN(sx, sy); - bw = (int)(w * scale); - bh = (int)(h * scale); - - XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, None); - if (penPtr->symbol.mask != None) { - mask = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.mask, - w, h, bw, bh); - XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, mask); - } - bitmap = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.bitmap, - w, h, bw, bh); - if (penPtr->symbol.fillGC == NULL) { - XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, - bitmap); - } - dx = bw / 2; - dy = bh / 2; - if (elemPtr->symbolInterval > 0) { - Point2d *pp, *endp; - - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - if (DRAW_SYMBOL(elemPtr)) { - int x, y; - - x = Round(pp->x) - dx; - y = Round(pp->y) - dy; - if ((penPtr->symbol.fillGC == NULL) || (mask !=None)) { - XSetClipOrigin(graphPtr->display, - penPtr->symbol.outlineGC, x, y); - } - XCopyPlane(graphPtr->display, bitmap, drawable, - penPtr->symbol.outlineGC, 0, 0, bw, bh, x, y, 1); - } - elemPtr->symbolCounter++; - } - } else { - Point2d *pp, *endp; - - for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { - int x, y; - - x = Round(pp->x) - dx; - y = Round(pp->y) - dy; - if ((penPtr->symbol.fillGC == NULL) || (mask != None)) { - XSetClipOrigin(graphPtr->display, - penPtr->symbol.outlineGC, x, y); - } - XCopyPlane(graphPtr->display, bitmap, drawable, - penPtr->symbol.outlineGC, 0, 0, bw, bh, x, y, 1); - } - } - Tk_FreePixmap(graphPtr->display, bitmap); - if (mask != None) { - Tk_FreePixmap(graphPtr->display, mask); + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 13; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; } + count++; + } + elemPtr->symbolCounter++; } - break; - } -} - -/* - *--------------------------------------------------------------------------- - * - * DrawSymbolProc -- - * - * Draw the symbol centered at the each given x,y coordinate. - * - * Results: - * None. - * - * Side Effects: - * Draws a symbol at the coordinate given. - * - *--------------------------------------------------------------------------- - */ -static void -DrawSymbolProc( - Graph *graphPtr, /* Graph widget record */ - Drawable drawable, /* Pixmap or window to draw into */ - Element *basePtr, /* Line element information */ - int x, int y, /* Center position of symbol */ - int size) /* Size of symbol. */ -{ - LineElement *elemPtr = (LineElement *)basePtr; - LinePen *penPtr; - - penPtr = NORMALPEN(elemPtr); - if (penPtr->traceWidth > 0) { - /* - * Draw an extra line offset by one pixel from the previous to give a - * thicker appearance. This is only for the legend entry. This routine - * is never called for drawing the actual line segments. - */ - XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size, y, - x + size, y); - XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size, y + 1, - x + size, y + 1); - } - if (penPtr->symbol.type != SYMBOL_NONE) { - Point2d point; - - point.x = x, point.y = y; - DrawSymbols(graphPtr, drawable, elemPtr, penPtr, size, 1, &point); - } -} - -static void -DrawTraces(Graph *graphPtr, Drawable drawable, LineElement *elemPtr, - LinePen *penPtr) -{ - Blt_ChainLink link; - XPoint *points; - int np; - - np = Blt_MaxRequestSize(graphPtr->display, sizeof(XPoint)) - 1; - points = malloc((np + 1) * sizeof(XPoint)); - - for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; - link = Blt_Chain_NextLink(link)) { + } else { + Point2d *pp, *endp; XPoint *xpp; - bltTrace *tracePtr; - int remaining, count; - int n; - - tracePtr = Blt_Chain_GetValue(link); - - /* - * If the trace has to be split into separate XDrawLines calls, then the - * end point of the current trace is also the starting point of the new - * split. - */ - /* Step 1. Convert and draw the first section of the trace. - * It may contain the entire trace. */ - n = MIN(np, tracePtr->screenPts.length); - for (xpp = points, count = 0; count < n; count++, xpp++) { - xpp->x = Round(tracePtr->screenPts.points[count].x); - xpp->y = Round(tracePtr->screenPts.points[count].y); + xpp = polygon; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int i; + int rndx, rndy; + + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 13; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; + } } - XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, - count, CoordModeOrigin); - - /* Step 2. Next handle any full-size chunks left. */ - - while ((count + np) < tracePtr->screenPts.length) { - int j; + count = nSymbolPts; + } + if (penPtr->symbol.fillGC != NULL) { + int i; + XPoint *xpp; - /* Start with the last point of the previous trace. */ - points[0].x = points[np - 1].x; - points[0].y = points[np - 1].y; - - for (xpp = points + 1, j = 0; j < np; j++, count++, xpp++) { - xpp->x = Round(tracePtr->screenPts.points[count].x); - xpp->y = Round(tracePtr->screenPts.points[count].y); - } - XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, - np + 1, CoordModeOrigin); + for (xpp = polygon, i = 0; i < count; i++, xpp += 13) { + XFillPolygon(graphPtr->display, drawable, + penPtr->symbol.fillGC, xpp, 13, Complex, + CoordModeOrigin); } - - /* Step 3. Convert and draw the remaining points. */ - - remaining = tracePtr->screenPts.length - count; - if (remaining > 0) { - /* Start with the last point of the previous trace. */ - points[0].x = points[np - 1].x; - points[0].y = points[np - 1].y; - for (xpp = points + 1; count < tracePtr->screenPts.length; count++, - xpp++) { - xpp->x = Round(tracePtr->screenPts.points[count].x); - xpp->y = Round(tracePtr->screenPts.points[count].y); - } - XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, - remaining + 1, CoordModeOrigin); + } + if (penPtr->symbol.outlineWidth > 0) { + int i; + XPoint *xpp; + + for (xpp = polygon, i = 0; i < count; i++, xpp += 13) { + XDrawLines(graphPtr->display, drawable, + penPtr->symbol.outlineGC, xpp, 13, CoordModeOrigin); } + } + free(polygon); } - free(points); -} + break; -static void -DrawValues(Graph *graphPtr, Drawable drawable, LineElement *elemPtr, - LinePen *penPtr, int length, Point2d *points, int *map) -{ - Point2d *pp, *endp; - double *xval, *yval; - const char *fmt; - char string[TCL_DOUBLE_SPACE * 2 + 2]; - int count; - - fmt = penPtr->valueFormat; - if (fmt == NULL) { - fmt = "%g"; - } - count = 0; - xval = elemPtr->x.values, yval = elemPtr->y.values; + case SYMBOL_DIAMOND: + { + XPoint *polygon; + + /* + * + * The plus symbol is a closed polygon + * 1 of 4 points. The diagram to the left + * represents the positions of the points + * 0,4 x,y 2 which are computed below. The extra + * (fifth) point connects the first and + * 3 last points. + * + */ + pattern[1].y = pattern[0].x = -r1; + pattern[2].y = pattern[3].x = pattern[0].y = pattern[1].x = 0; + pattern[3].y = pattern[2].x = r1; + pattern[4] = pattern[0]; + + polygon = malloc(nSymbolPts * 5 * sizeof(XPoint)); + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; + XPoint *xpp; - // be sure to update style->gc, things might have changed - penPtr->valueStyle.flags |= UPDATE_GC; - for (pp = points, endp = points + length; pp < endp; pp++) { - double x, y; + xpp = polygon; + count = 0; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int i; - x = xval[map[count]]; - y = yval[map[count]]; - count++; - if (penPtr->valueShow == SHOW_X) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); - } else if (penPtr->valueShow == SHOW_Y) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, y); - } else if (penPtr->valueShow == SHOW_BOTH) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); - strcat(string, ","); - sprintf_s(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + if (DRAW_SYMBOL(elemPtr)) { + int rndx, rndy; + + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 5; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; + } + count++; + } + elemPtr->symbolCounter++; } - Blt_DrawText(graphPtr->tkwin, drawable, string, &penPtr->valueStyle, - Round(pp->x), Round(pp->y)); - } -} + } else { + Point2d *pp, *endp; + XPoint *xpp; -/* - *--------------------------------------------------------------------------- - * - * DrawActiveLineProc -- - * - * Draws the connected line(s) representing the element. If the line is - * made up of non-line symbols and the line width parameter has been set - * (linewidth > 0), the element will also be drawn as a line (with the - * linewidth requested). The line may consist of separate line segments. - * - * Results: - * None. - * - * Side effects: - * X drawing commands are output. - * - *--------------------------------------------------------------------------- - */ -static void -DrawActiveLineProc(Graph *graphPtr, Drawable drawable, Element *basePtr) -{ - LineElement *elemPtr = (LineElement *)basePtr; - LinePen *penPtr = (LinePen *)elemPtr->activePenPtr; - int symbolSize; + xpp = polygon; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int i; + int rndx, rndy; + + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 5; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; + } + } + count = nSymbolPts; + } + if (penPtr->symbol.fillGC != NULL) { + XPoint *xpp; + int i; - if (penPtr == NULL) { - return; - } - symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size); + for (xpp = polygon, i = 0; i < count; i++, xpp += 5) { + XFillPolygon(graphPtr->display, drawable, + penPtr->symbol.fillGC, xpp, 5, Convex, CoordModeOrigin); - /* - * nActiveIndices - * > 0 Some points are active. Uses activeArr. - * < 0 All points are active. - * == 0 No points are active. - */ - if (elemPtr->nActiveIndices > 0) { - if (elemPtr->flags & ACTIVE_PENDING) { - MapActiveSymbols(graphPtr, elemPtr); } - if (penPtr->symbol.type != SYMBOL_NONE) { - DrawSymbols(graphPtr, drawable, elemPtr, penPtr, symbolSize, - elemPtr->activePts.length, elemPtr->activePts.points); - } - if (penPtr->valueShow != SHOW_NONE) { - DrawValues(graphPtr, drawable, elemPtr, penPtr, - elemPtr->activePts.length, - elemPtr->activePts.points, - elemPtr->activePts.map); - } - } else if (elemPtr->nActiveIndices < 0) { - if (penPtr->traceWidth > 0) { - if (elemPtr->lines.length > 0) { - Blt_Draw2DSegments(graphPtr->display, drawable, - penPtr->traceGC, elemPtr->lines.segments, - elemPtr->lines.length); - } else if (Blt_Chain_GetLength(elemPtr->traces) > 0) { - DrawTraces(graphPtr, drawable, elemPtr, penPtr); - } - } - if (penPtr->symbol.type != SYMBOL_NONE) { - DrawSymbols(graphPtr, drawable, elemPtr, penPtr, symbolSize, - elemPtr->symbolPts.length, elemPtr->symbolPts.points); - } - if (penPtr->valueShow != SHOW_NONE) { - DrawValues(graphPtr, drawable, elemPtr, penPtr, - elemPtr->symbolPts.length, elemPtr->symbolPts.points, - elemPtr->symbolPts.map); + } + if (penPtr->symbol.outlineWidth > 0) { + XPoint *xpp; + int i; + + for (xpp = polygon, i = 0; i < count; i++, xpp += 5) { + XDrawLines(graphPtr->display, drawable, + penPtr->symbol.outlineGC, xpp, 5, CoordModeOrigin); } + } + free(polygon); } -} + break; -/* - *--------------------------------------------------------------------------- - * - * DrawNormalLine -- - * - * Draws the connected line(s) representing the element. If the line is - * made up of non-line symbols and the line width parameter has been set - * (linewidth > 0), the element will also be drawn as a line (with the - * linewidth requested). The line may consist of separate line segments. - * - * Results: - * None. - * - * Side effects: - * X drawing commands are output. - * - *--------------------------------------------------------------------------- - */ -static void -DrawNormalLineProc(Graph *graphPtr, Drawable drawable, Element *basePtr) -{ - LineElement *elemPtr = (LineElement *)basePtr; - Blt_ChainLink link; - unsigned int count; + case SYMBOL_TRIANGLE: + case SYMBOL_ARROW: + { + XPoint *polygon; + double b; + int b2, h1, h2; +#define H_RATIO 1.1663402261671607 +#define B_RATIO 1.3467736870885982 +#define TAN30 0.57735026918962573 +#define COS30 0.86602540378443871 - /* Fill area under the curve */ - if (elemPtr->fillPts != NULL) { - XPoint *points; - Point2d *endp, *pp; + b = Round(size * B_RATIO * 0.7); + b2 = Round(b * 0.5); + h2 = Round(TAN30 * b2); + h1 = Round(b2 / COS30); + /* + * + * The triangle symbol is a closed polygon + * 0,3 of 3 points. The diagram to the left + * represents the positions of the points + * x,y which are computed below. The extra + * (fourth) point connects the first and + * 2 1 last points. + * + */ + + if (penPtr->symbol.type == SYMBOL_ARROW) { + pattern[3].x = pattern[0].x = 0; + pattern[3].y = pattern[0].y = h1; + pattern[1].x = b2; + pattern[2].y = pattern[1].y = -h2; + pattern[2].x = -b2; + } else { + pattern[3].x = pattern[0].x = 0; + pattern[3].y = pattern[0].y = -h1; + pattern[1].x = b2; + pattern[2].y = pattern[1].y = h2; + pattern[2].x = -b2; + } + polygon = malloc(nSymbolPts * 4 * sizeof(XPoint)); + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; + XPoint *xpp; - points = malloc(sizeof(XPoint) * elemPtr->nFillPts); + xpp = polygon; count = 0; - for (pp = elemPtr->fillPts, endp = pp + elemPtr->nFillPts; - pp < endp; pp++) { - points[count].x = Round(pp->x); - points[count].y = Round(pp->y); + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int i; + + if (DRAW_SYMBOL(elemPtr)) { + int rndx, rndy; + + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 4; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; + } count++; + } + elemPtr->symbolCounter++; } - if (elemPtr->fillBg != NULL) { - Tk_Fill3DPolygon(graphPtr->tkwin, drawable, - elemPtr->fillBg, points, - elemPtr->nFillPts, 0, TK_RELIEF_FLAT); + } else { + Point2d *pp, *endp; + XPoint *xpp; + + xpp = polygon; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int i; + int rndx, rndy; + + rndx = Round(pp->x), rndy = Round(pp->y); + for (i = 0; i < 4; i++) { + xpp->x = pattern[i].x + rndx; + xpp->y = pattern[i].y + rndy; + xpp++; + } } - free(points); - } + count = nSymbolPts; + } + if (penPtr->symbol.fillGC != NULL) { + XPoint *xpp; + int i; - /* Lines: stripchart segments or graph traces. */ - if (elemPtr->lines.length > 0) { - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - LinePen *penPtr; - - stylePtr = Blt_Chain_GetValue(link); - penPtr = (LinePen *)stylePtr->penPtr; - if ((stylePtr->lines.length > 0) && - (penPtr->errorBarLineWidth > 0)) { - Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->traceGC, - stylePtr->lines.segments, stylePtr->lines.length); - } + xpp = polygon; + for (xpp = polygon, i = 0; i < count; i++, xpp += 4) { + XFillPolygon(graphPtr->display, drawable, + penPtr->symbol.fillGC, xpp, 4, Convex, CoordModeOrigin); } - } else { - LinePen *penPtr; + } + if (penPtr->symbol.outlineWidth > 0) { + XPoint *xpp; + int i; - penPtr = NORMALPEN(elemPtr); - if ((Blt_Chain_GetLength(elemPtr->traces) > 0) && - (penPtr->traceWidth > 0)) { - DrawTraces(graphPtr, drawable, elemPtr, penPtr); + xpp = polygon; + for (xpp = polygon, i = 0; i < count; i++, xpp += 4) { + XDrawLines(graphPtr->display, drawable, + penPtr->symbol.outlineGC, xpp, 4, CoordModeOrigin); } + } + free(polygon); } + break; - if (elemPtr->reqMaxSymbols > 0) { - int total; + case SYMBOL_IMAGE: + { + int w, h; + int dx, dy; + + Tk_SizeOfImage(penPtr->symbol.image, &w, &h); - total = 0; - for (link = Blt_Chain_FirstLink(elemPtr->styles); - link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; + dx = w / 2; + dy = h / 2; + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; - stylePtr = Blt_Chain_GetValue(link); - total += stylePtr->symbolPts.length; + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + int x, y; + + x = Round(pp->x) - dx; + y = Round(pp->y) - dy; + Tk_RedrawImage(penPtr->symbol.image, 0, 0, w, h, + drawable, x, y); + } + elemPtr->symbolCounter++; } - elemPtr->symbolInterval = total / elemPtr->reqMaxSymbols; - elemPtr->symbolCounter = 0; - } + } else { + Point2d *pp, *endp; - /* Symbols, error bars, values. */ + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int x, y; - count = 0; - for (link = Blt_Chain_FirstLink(elemPtr->styles); link != NULL; - link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - LinePen *penPtr; - - stylePtr = Blt_Chain_GetValue(link); - penPtr = (LinePen *)stylePtr->penPtr; - if ((stylePtr->xeb.length > 0) && (penPtr->errorBarShow & SHOW_X)) { - Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, - stylePtr->xeb.segments, stylePtr->xeb.length); + x = Round(pp->x) - dx; + y = Round(pp->y) - dy; + Tk_RedrawImage(penPtr->symbol.image, 0, 0, w, h, + drawable, x, y); } - if ((stylePtr->yeb.length > 0) && (penPtr->errorBarShow & SHOW_Y)) { - Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, - stylePtr->yeb.segments, stylePtr->yeb.length); - } - if ((stylePtr->symbolPts.length > 0) && - (penPtr->symbol.type != SYMBOL_NONE)) { - DrawSymbols(graphPtr, drawable, elemPtr, penPtr, - stylePtr->symbolSize, stylePtr->symbolPts.length, - stylePtr->symbolPts.points); + } + } + break; + + case SYMBOL_BITMAP: + { + Pixmap bitmap, mask; + int w, h, bw, bh; + double scale, sx, sy; + int dx, dy; + + Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &w, &h); + mask = None; + + /* + * Compute the size of the scaled bitmap. Stretch the bitmap to fit + * a nxn bounding box. + */ + sx = (double)size / (double)w; + sy = (double)size / (double)h; + scale = MIN(sx, sy); + bw = (int)(w * scale); + bh = (int)(h * scale); + + XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, None); + if (penPtr->symbol.mask != None) { + mask = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.mask, + w, h, bw, bh); + XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, mask); + } + bitmap = Blt_ScaleBitmap(graphPtr->tkwin, penPtr->symbol.bitmap, + w, h, bw, bh); + if (penPtr->symbol.fillGC == NULL) { + XSetClipMask(graphPtr->display, penPtr->symbol.outlineGC, + bitmap); + } + dx = bw / 2; + dy = bh / 2; + if (elemPtr->symbolInterval > 0) { + Point2d *pp, *endp; + + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + if (DRAW_SYMBOL(elemPtr)) { + int x, y; + + x = Round(pp->x) - dx; + y = Round(pp->y) - dy; + if ((penPtr->symbol.fillGC == NULL) || (mask !=None)) { + XSetClipOrigin(graphPtr->display, + penPtr->symbol.outlineGC, x, y); + } + XCopyPlane(graphPtr->display, bitmap, drawable, + penPtr->symbol.outlineGC, 0, 0, bw, bh, x, y, 1); + } + elemPtr->symbolCounter++; } - if (penPtr->valueShow != SHOW_NONE) { - DrawValues(graphPtr, drawable, elemPtr, penPtr, - stylePtr->symbolPts.length, stylePtr->symbolPts.points, - elemPtr->symbolPts.map + count); + } else { + Point2d *pp, *endp; + + for (pp = symbolPts, endp = pp + nSymbolPts; pp < endp; pp++) { + int x, y; + + x = Round(pp->x) - dx; + y = Round(pp->y) - dy; + if ((penPtr->symbol.fillGC == NULL) || (mask != None)) { + XSetClipOrigin(graphPtr->display, + penPtr->symbol.outlineGC, x, y); + } + XCopyPlane(graphPtr->display, bitmap, drawable, + penPtr->symbol.outlineGC, 0, 0, bw, bh, x, y, 1); } - count += stylePtr->symbolPts.length; - } - elemPtr->symbolInterval = 0; + } + Tk_FreePixmap(graphPtr->display, bitmap); + if (mask != None) { + Tk_FreePixmap(graphPtr->display, mask); + } + } + break; + } } -/* - *--------------------------------------------------------------------------- - * - * GetSymbolPostScriptInfo -- - * - * Set up the PostScript environment with the macros and attributes needed - * to draw the symbols of the element. - * - * Results: - * None. - * - *--------------------------------------------------------------------------- - */ -static void -GetSymbolPostScriptInfo( - Graph *graphPtr, - Blt_Ps ps, - LinePen *penPtr, - int size) +static void DrawSymbolProc(Graph *graphPtr, Drawable drawable, + Element *basePtr, int x, int y, int size) { - XColor *outlineColor, *fillColor, *defaultColor; + LineElement *elemPtr = (LineElement *)basePtr; + LinePen *penPtr; + + penPtr = NORMALPEN(elemPtr); + if (penPtr->traceWidth > 0) { + /* + * Draw an extra line offset by one pixel from the previous to give a + * thicker appearance. This is only for the legend entry. This routine + * is never called for drawing the actual line segments. + */ + XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size, y, + x + size, y); + XDrawLine(graphPtr->display, drawable, penPtr->traceGC, x - size, y + 1, + x + size, y + 1); + } + if (penPtr->symbol.type != SYMBOL_NONE) { + Point2d point; + + point.x = x, point.y = y; + DrawSymbols(graphPtr, drawable, elemPtr, penPtr, size, 1, &point); + } +} - /* Set line and foreground attributes */ - outlineColor = penPtr->symbol.outlineColor; - fillColor = penPtr->symbol.fillColor; - defaultColor = penPtr->traceColor; +static void DrawTraces(Graph *graphPtr, Drawable drawable, + LineElement *elemPtr, LinePen *penPtr) +{ + Blt_ChainLink link; + XPoint *points; + int np; - if (fillColor == COLOR_DEFAULT) { - fillColor = defaultColor; - } - if (outlineColor == COLOR_DEFAULT) { - outlineColor = defaultColor; - } - if (penPtr->symbol.type == SYMBOL_NONE) { - Blt_Ps_XSetLineAttributes(ps, defaultColor, penPtr->traceWidth + 2, - &penPtr->traceDashes, CapButt, JoinMiter); - } else { - Blt_Ps_XSetLineWidth(ps, penPtr->symbol.outlineWidth); - Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL); - } + np = Blt_MaxRequestSize(graphPtr->display, sizeof(XPoint)) - 1; + points = malloc((np + 1) * sizeof(XPoint)); + + for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; + link = Blt_Chain_NextLink(link)) { + XPoint *xpp; + bltTrace *tracePtr; + int remaining, count; + int n; + + tracePtr = Blt_Chain_GetValue(link); /* - * Build a PostScript procedure to draw the symbols. For bitmaps, paint - * both the bitmap and its mask. Otherwise fill and stroke the path formed - * already. + * If the trace has to be split into separate XDrawLines calls, then the + * end point of the current trace is also the starting point of the new + * split. */ - Blt_Ps_Append(ps, "\n/DrawSymbolProc {\n"); - switch (penPtr->symbol.type) { - case SYMBOL_NONE: - break; /* Do nothing */ - case SYMBOL_BITMAP: - { - int w, h; - double sx, sy, scale; - - /* - * Compute how much to scale the bitmap. Don't let the scaled - * bitmap exceed the bounding square for the symbol. - */ - Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &w, &h); - sx = (double)size / (double)w; - sy = (double)size / (double)h; - scale = MIN(sx, sy); - - if ((penPtr->symbol.mask != None) && (fillColor != NULL)) { - Blt_Ps_VarAppend(ps, "\n % Bitmap mask is \"", - Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.mask), - "\"\n\n ", (char *)NULL); - Blt_Ps_XSetBackground(ps, fillColor); - Blt_Ps_DrawBitmap(ps, graphPtr->display, penPtr->symbol.mask, - scale, scale); - } - Blt_Ps_VarAppend(ps, "\n % Bitmap symbol is \"", - Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.bitmap), - "\"\n\n ", (char *)NULL); - Blt_Ps_XSetForeground(ps, outlineColor); - Blt_Ps_DrawBitmap(ps, graphPtr->display, penPtr->symbol.bitmap, - scale, scale); - } - break; - default: - if (fillColor != NULL) { - Blt_Ps_Append(ps, " "); - Blt_Ps_XSetBackground(ps, fillColor); - Blt_Ps_Append(ps, " gsave fill grestore\n"); - } - if ((outlineColor != NULL) && (penPtr->symbol.outlineWidth > 0)) { - Blt_Ps_Append(ps, " "); - Blt_Ps_XSetForeground(ps, outlineColor); - Blt_Ps_Append(ps, " stroke\n"); - } - break; + /* Step 1. Convert and draw the first section of the trace. + * It may contain the entire trace. */ + + n = MIN(np, tracePtr->screenPts.length); + for (xpp = points, count = 0; count < n; count++, xpp++) { + xpp->x = Round(tracePtr->screenPts.points[count].x); + xpp->y = Round(tracePtr->screenPts.points[count].y); } - Blt_Ps_Append(ps, "} def\n\n"); + XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, + count, CoordModeOrigin); + + /* Step 2. Next handle any full-size chunks left. */ + + while ((count + np) < tracePtr->screenPts.length) { + int j; + + /* Start with the last point of the previous trace. */ + points[0].x = points[np - 1].x; + points[0].y = points[np - 1].y; + + for (xpp = points + 1, j = 0; j < np; j++, count++, xpp++) { + xpp->x = Round(tracePtr->screenPts.points[count].x); + xpp->y = Round(tracePtr->screenPts.points[count].y); + } + XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, + np + 1, CoordModeOrigin); + } + + /* Step 3. Convert and draw the remaining points. */ + + remaining = tracePtr->screenPts.length - count; + if (remaining > 0) { + /* Start with the last point of the previous trace. */ + points[0].x = points[np - 1].x; + points[0].y = points[np - 1].y; + for (xpp = points + 1; count < tracePtr->screenPts.length; count++, + xpp++) { + xpp->x = Round(tracePtr->screenPts.points[count].x); + xpp->y = Round(tracePtr->screenPts.points[count].y); + } + XDrawLines(graphPtr->display, drawable, penPtr->traceGC, points, + remaining + 1, CoordModeOrigin); + } + } + free(points); } -/* - *--------------------------------------------------------------------------- - * - * SymbolsToPostScript -- - * - * Draw a symbol centered at the given x,y window coordinate based upon the - * element symbol type and size. - * - * Results: - * None. - * - * Problems: - * Most notable is the round-off errors generated when calculating the - * centered position of the symbol. - * - *--------------------------------------------------------------------------- - */ -static void -SymbolsToPostScript( - Graph *graphPtr, - Blt_Ps ps, - LinePen *penPtr, - int size, - int nSymbolPts, - Point2d *symbolPts) +static void DrawValues(Graph *graphPtr, Drawable drawable, + LineElement *elemPtr, LinePen *penPtr, + int length, Point2d *points, int *map) { - double symbolSize; - static const char *symbolMacros[] = - { - "Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm", - (char *)NULL, - }; - GetSymbolPostScriptInfo(graphPtr, ps, penPtr, size); - - symbolSize = (double)size; - switch (penPtr->symbol.type) { - case SYMBOL_SQUARE: - case SYMBOL_CROSS: - case SYMBOL_PLUS: - case SYMBOL_SCROSS: - case SYMBOL_SPLUS: - symbolSize = (double)Round(size * S_RATIO); - break; - case SYMBOL_TRIANGLE: - case SYMBOL_ARROW: - symbolSize = (double)Round(size * 0.7); - break; - case SYMBOL_DIAMOND: - symbolSize = (double)Round(size * M_SQRT1_2); - break; + Point2d *pp, *endp; + double *xval, *yval; + const char *fmt; + char string[TCL_DOUBLE_SPACE * 2 + 2]; + int count; + + fmt = penPtr->valueFormat; + if (fmt == NULL) { + fmt = "%g"; + } + count = 0; + xval = elemPtr->x.values, yval = elemPtr->y.values; + + // be sure to update style->gc, things might have changed + penPtr->valueStyle.flags |= UPDATE_GC; + for (pp = points, endp = points + length; pp < endp; pp++) { + double x, y; + + x = xval[map[count]]; + y = yval[map[count]]; + count++; + if (penPtr->valueShow == SHOW_X) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); + } else if (penPtr->valueShow == SHOW_Y) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, y); + } else if (penPtr->valueShow == SHOW_BOTH) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + sprintf_s(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + Blt_DrawText(graphPtr->tkwin, drawable, string, &penPtr->valueStyle, + Round(pp->x), Round(pp->y)); + } +} - default: - break; +static void DrawActiveLineProc(Graph *graphPtr, Drawable drawable, + Element *basePtr) +{ + LineElement *elemPtr = (LineElement *)basePtr; + LinePen *penPtr = (LinePen *)elemPtr->activePenPtr; + int symbolSize; + + if (penPtr == NULL) { + return; + } + symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size); + + /* + * nActiveIndices + * > 0 Some points are active. Uses activeArr. + * < 0 All points are active. + * == 0 No points are active. + */ + if (elemPtr->nActiveIndices > 0) { + if (elemPtr->flags & ACTIVE_PENDING) { + MapActiveSymbols(graphPtr, elemPtr); } - { - Point2d *pp, *endp; - - for (pp = symbolPts, endp = symbolPts + nSymbolPts; pp < endp; pp++) { - Blt_Ps_Format(ps, "%g %g %g %s\n", pp->x, pp->y, - symbolSize, symbolMacros[penPtr->symbol.type]); - } + if (penPtr->symbol.type != SYMBOL_NONE) { + DrawSymbols(graphPtr, drawable, elemPtr, penPtr, symbolSize, + elemPtr->activePts.length, elemPtr->activePts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + DrawValues(graphPtr, drawable, elemPtr, penPtr, + elemPtr->activePts.length, + elemPtr->activePts.points, + elemPtr->activePts.map); + } + } else if (elemPtr->nActiveIndices < 0) { + if (penPtr->traceWidth > 0) { + if (elemPtr->lines.length > 0) { + Blt_Draw2DSegments(graphPtr->display, drawable, + penPtr->traceGC, elemPtr->lines.segments, + elemPtr->lines.length); + } else if (Blt_Chain_GetLength(elemPtr->traces) > 0) { + DrawTraces(graphPtr, drawable, elemPtr, penPtr); + } } + if (penPtr->symbol.type != SYMBOL_NONE) { + DrawSymbols(graphPtr, drawable, elemPtr, penPtr, symbolSize, + elemPtr->symbolPts.length, elemPtr->symbolPts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + DrawValues(graphPtr, drawable, elemPtr, penPtr, + elemPtr->symbolPts.length, elemPtr->symbolPts.points, + elemPtr->symbolPts.map); + } + } } -/* - *--------------------------------------------------------------------------- - * - * SymbolToPostScriptProc -- - * - * Draw the symbol centered at the each given x,y coordinate. - * - * Results: - * None. - * - * Side Effects: - * Draws a symbol at the coordinate given. - * - *--------------------------------------------------------------------------- - */ -static void -SymbolToPostScriptProc( - Graph *graphPtr, /* Graph widget record */ - Blt_Ps ps, - Element *basePtr, /* Line element information */ - double x, double y, /* Center position of symbol */ - int size) /* Size of element */ +static void DrawNormalLineProc(Graph *graphPtr, Drawable drawable, + Element *basePtr) { - LineElement *elemPtr = (LineElement *)basePtr; + LineElement *elemPtr = (LineElement *)basePtr; + Blt_ChainLink link; + unsigned int count; + + /* Fill area under the curve */ + if (elemPtr->fillPts != NULL) { + XPoint *points; + Point2d *endp, *pp; + + points = malloc(sizeof(XPoint) * elemPtr->nFillPts); + count = 0; + for (pp = elemPtr->fillPts, endp = pp + elemPtr->nFillPts; + pp < endp; pp++) { + points[count].x = Round(pp->x); + points[count].y = Round(pp->y); + count++; + } + if (elemPtr->fillBg != NULL) { + Tk_Fill3DPolygon(graphPtr->tkwin, drawable, + elemPtr->fillBg, points, + elemPtr->nFillPts, 0, TK_RELIEF_FLAT); + } + free(points); + } + + /* Lines: stripchart segments or graph traces. */ + if (elemPtr->lines.length > 0) { + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + LinePen *penPtr; + + stylePtr = Blt_Chain_GetValue(link); + penPtr = (LinePen *)stylePtr->penPtr; + if ((stylePtr->lines.length > 0) && + (penPtr->errorBarLineWidth > 0)) { + Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->traceGC, + stylePtr->lines.segments, stylePtr->lines.length); + } + } + } else { LinePen *penPtr; penPtr = NORMALPEN(elemPtr); - if (penPtr->traceWidth > 0) { - /* - * Draw an extra line offset by one pixel from the previous to give a - * thicker appearance. This is only for the legend entry. This routine - * is never called for drawing the actual line segments. - */ - Blt_Ps_XSetLineAttributes(ps, penPtr->traceColor, - penPtr->traceWidth, &penPtr->traceDashes, CapButt, JoinMiter); - Blt_Ps_Format(ps, "%g %g %d Li\n", x, y, size + size); + if ((Blt_Chain_GetLength(elemPtr->traces) > 0) && + (penPtr->traceWidth > 0)) { + DrawTraces(graphPtr, drawable, elemPtr, penPtr); } - if (penPtr->symbol.type != SYMBOL_NONE) { - Point2d point; + } + + if (elemPtr->reqMaxSymbols > 0) { + int total; + + total = 0; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); + link != NULL; link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; - point.x = x, point.y = y; - SymbolsToPostScript(graphPtr, ps, penPtr, size, 1, &point); + stylePtr = Blt_Chain_GetValue(link); + total += stylePtr->symbolPts.length; } + elemPtr->symbolInterval = total / elemPtr->reqMaxSymbols; + elemPtr->symbolCounter = 0; + } + + /* Symbols, error bars, values. */ + + count = 0; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); link != NULL; + link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + LinePen *penPtr; + + stylePtr = Blt_Chain_GetValue(link); + penPtr = (LinePen *)stylePtr->penPtr; + if ((stylePtr->xeb.length > 0) && (penPtr->errorBarShow & SHOW_X)) { + Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, + stylePtr->xeb.segments, stylePtr->xeb.length); + } + if ((stylePtr->yeb.length > 0) && (penPtr->errorBarShow & SHOW_Y)) { + Blt_Draw2DSegments(graphPtr->display, drawable, penPtr->errorBarGC, + stylePtr->yeb.segments, stylePtr->yeb.length); + } + if ((stylePtr->symbolPts.length > 0) && + (penPtr->symbol.type != SYMBOL_NONE)) { + DrawSymbols(graphPtr, drawable, elemPtr, penPtr, + stylePtr->symbolSize, stylePtr->symbolPts.length, + stylePtr->symbolPts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + DrawValues(graphPtr, drawable, elemPtr, penPtr, + stylePtr->symbolPts.length, stylePtr->symbolPts.points, + elemPtr->symbolPts.map + count); + } + count += stylePtr->symbolPts.length; + } + elemPtr->symbolInterval = 0; } -static void -SetLineAttributes(Blt_Ps ps, LinePen *penPtr) +static void GetSymbolPostScriptInfo(Graph *graphPtr, Blt_Ps ps, + LinePen *penPtr, int size) { - /* Set the attributes of the line (color, dashes, linewidth) */ - Blt_Ps_XSetLineAttributes(ps, penPtr->traceColor, - penPtr->traceWidth, &penPtr->traceDashes, CapButt, JoinMiter); - if ((LineIsDashed(penPtr->traceDashes)) && - (penPtr->traceOffColor != NULL)) { - Blt_Ps_Append(ps, "/DashesProc {\n gsave\n "); - Blt_Ps_XSetBackground(ps, penPtr->traceOffColor); - Blt_Ps_Append(ps, " "); - Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL); - Blt_Ps_Append(ps, "stroke\n grestore\n} def\n"); - } else { - Blt_Ps_Append(ps, "/DashesProc {} def\n"); + XColor *outlineColor, *fillColor, *defaultColor; + + /* Set line and foreground attributes */ + outlineColor = penPtr->symbol.outlineColor; + fillColor = penPtr->symbol.fillColor; + defaultColor = penPtr->traceColor; + + if (fillColor == COLOR_DEFAULT) { + fillColor = defaultColor; + } + if (outlineColor == COLOR_DEFAULT) { + outlineColor = defaultColor; + } + if (penPtr->symbol.type == SYMBOL_NONE) { + Blt_Ps_XSetLineAttributes(ps, defaultColor, penPtr->traceWidth + 2, + &penPtr->traceDashes, CapButt, JoinMiter); + } else { + Blt_Ps_XSetLineWidth(ps, penPtr->symbol.outlineWidth); + Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL); + } + + /* + * Build a PostScript procedure to draw the symbols. For bitmaps, paint + * both the bitmap and its mask. Otherwise fill and stroke the path formed + * already. + */ + Blt_Ps_Append(ps, "\n/DrawSymbolProc {\n"); + switch (penPtr->symbol.type) { + case SYMBOL_NONE: + break; /* Do nothing */ + case SYMBOL_BITMAP: + { + int w, h; + double sx, sy, scale; + + /* + * Compute how much to scale the bitmap. Don't let the scaled + * bitmap exceed the bounding square for the symbol. + */ + Tk_SizeOfBitmap(graphPtr->display, penPtr->symbol.bitmap, &w, &h); + sx = (double)size / (double)w; + sy = (double)size / (double)h; + scale = MIN(sx, sy); + + if ((penPtr->symbol.mask != None) && (fillColor != NULL)) { + Blt_Ps_VarAppend(ps, "\n % Bitmap mask is \"", + Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.mask), + "\"\n\n ", (char *)NULL); + Blt_Ps_XSetBackground(ps, fillColor); + Blt_Ps_DrawBitmap(ps, graphPtr->display, penPtr->symbol.mask, + scale, scale); + } + Blt_Ps_VarAppend(ps, "\n % Bitmap symbol is \"", + Tk_NameOfBitmap(graphPtr->display, penPtr->symbol.bitmap), + "\"\n\n ", (char *)NULL); + Blt_Ps_XSetForeground(ps, outlineColor); + Blt_Ps_DrawBitmap(ps, graphPtr->display, penPtr->symbol.bitmap, + scale, scale); } + break; + default: + if (fillColor != NULL) { + Blt_Ps_Append(ps, " "); + Blt_Ps_XSetBackground(ps, fillColor); + Blt_Ps_Append(ps, " gsave fill grestore\n"); + } + if ((outlineColor != NULL) && (penPtr->symbol.outlineWidth > 0)) { + Blt_Ps_Append(ps, " "); + Blt_Ps_XSetForeground(ps, outlineColor); + Blt_Ps_Append(ps, " stroke\n"); + } + break; + } + Blt_Ps_Append(ps, "} def\n\n"); } -static void -TracesToPostScript(Blt_Ps ps, LineElement *elemPtr, LinePen *penPtr) +static void SymbolsToPostScript(Graph *graphPtr, Blt_Ps ps, LinePen *penPtr, + int size, int nSymbolPts, Point2d *symbolPts) { - Blt_ChainLink link; + double symbolSize; + static const char *symbolMacros[] = + { + "Li", "Sq", "Ci", "Di", "Pl", "Cr", "Sp", "Sc", "Tr", "Ar", "Bm", + (char *)NULL, + }; + GetSymbolPostScriptInfo(graphPtr, ps, penPtr, size); + + symbolSize = (double)size; + switch (penPtr->symbol.type) { + case SYMBOL_SQUARE: + case SYMBOL_CROSS: + case SYMBOL_PLUS: + case SYMBOL_SCROSS: + case SYMBOL_SPLUS: + symbolSize = (double)Round(size * S_RATIO); + break; + case SYMBOL_TRIANGLE: + case SYMBOL_ARROW: + symbolSize = (double)Round(size * 0.7); + break; + case SYMBOL_DIAMOND: + symbolSize = (double)Round(size * M_SQRT1_2); + break; + + default: + break; + } + { + Point2d *pp, *endp; - SetLineAttributes(ps, penPtr); - for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; - link = Blt_Chain_NextLink(link)) { - bltTrace *tracePtr; - - tracePtr = Blt_Chain_GetValue(link); - if (tracePtr->screenPts.length > 0) { - Blt_Ps_Append(ps, "% start trace\n"); - Blt_Ps_DrawPolyline(ps, tracePtr->screenPts.points, - tracePtr->screenPts.length); - Blt_Ps_Append(ps, "% end trace\n"); - } + for (pp = symbolPts, endp = symbolPts + nSymbolPts; pp < endp; pp++) { + Blt_Ps_Format(ps, "%g %g %g %s\n", pp->x, pp->y, + symbolSize, symbolMacros[penPtr->symbol.type]); + } + } +} + +static void SymbolToPostScriptProc(Graph *graphPtr, Blt_Ps ps, + Element *basePtr, double x, double y, + int size) +{ + LineElement *elemPtr = (LineElement *)basePtr; + LinePen *penPtr; + + penPtr = NORMALPEN(elemPtr); + if (penPtr->traceWidth > 0) { + /* + * Draw an extra line offset by one pixel from the previous to give a + * thicker appearance. This is only for the legend entry. This routine + * is never called for drawing the actual line segments. + */ + Blt_Ps_XSetLineAttributes(ps, penPtr->traceColor, penPtr->traceWidth, + &penPtr->traceDashes, CapButt, JoinMiter); + Blt_Ps_Format(ps, "%g %g %d Li\n", x, y, size + size); + } + if (penPtr->symbol.type != SYMBOL_NONE) { + Point2d point; + + point.x = x, point.y = y; + SymbolsToPostScript(graphPtr, ps, penPtr, size, 1, &point); + } +} + +static void SetLineAttributes(Blt_Ps ps, LinePen *penPtr) +{ + /* Set the attributes of the line (color, dashes, linewidth) */ + Blt_Ps_XSetLineAttributes(ps, penPtr->traceColor, penPtr->traceWidth, + &penPtr->traceDashes, CapButt, JoinMiter); + if ((LineIsDashed(penPtr->traceDashes)) && + (penPtr->traceOffColor != NULL)) { + Blt_Ps_Append(ps, "/DashesProc {\n gsave\n "); + Blt_Ps_XSetBackground(ps, penPtr->traceOffColor); + Blt_Ps_Append(ps, " "); + Blt_Ps_XSetDashes(ps, (Blt_Dashes *)NULL); + Blt_Ps_Append(ps, "stroke\n grestore\n} def\n"); + } else { + Blt_Ps_Append(ps, "/DashesProc {} def\n"); + } +} + +static void TracesToPostScript(Blt_Ps ps, LineElement *elemPtr, LinePen *penPtr) +{ + Blt_ChainLink link; + + SetLineAttributes(ps, penPtr); + for (link = Blt_Chain_FirstLink(elemPtr->traces); link != NULL; + link = Blt_Chain_NextLink(link)) { + bltTrace *tracePtr; + + tracePtr = Blt_Chain_GetValue(link); + if (tracePtr->screenPts.length > 0) { + Blt_Ps_Append(ps, "% start trace\n"); + Blt_Ps_DrawPolyline(ps, tracePtr->screenPts.points, + tracePtr->screenPts.length); + Blt_Ps_Append(ps, "% end trace\n"); } + } } static void ValuesToPostScript(Blt_Ps ps, LineElement *elemPtr, LinePen *penPtr, int nSymbolPts, Point2d *symbolPts, int *pointToData) { - Point2d *pp, *endp; - int count; - char string[TCL_DOUBLE_SPACE * 2 + 2]; - const char *fmt; + Point2d *pp, *endp; + int count; + char string[TCL_DOUBLE_SPACE * 2 + 2]; + const char *fmt; - fmt = penPtr->valueFormat; - if (fmt == NULL) { - fmt = "%g"; - } - count = 0; - for (pp = symbolPts, endp = symbolPts + nSymbolPts; pp < endp; pp++) { - double x, y; - - x = elemPtr->x.values[pointToData[count]]; - y = elemPtr->y.values[pointToData[count]]; - count++; - if (penPtr->valueShow == SHOW_X) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); - } else if (penPtr->valueShow == SHOW_Y) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, y); - } else if (penPtr->valueShow == SHOW_BOTH) { - sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); - strcat(string, ","); - sprintf_s(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); - } - Blt_Ps_DrawText(ps, string, &penPtr->valueStyle, pp->x, pp->y); - } + fmt = penPtr->valueFormat; + if (fmt == NULL) { + fmt = "%g"; + } + count = 0; + for (pp = symbolPts, endp = symbolPts + nSymbolPts; pp < endp; pp++) { + double x, y; + + x = elemPtr->x.values[pointToData[count]]; + y = elemPtr->y.values[pointToData[count]]; + count++; + if (penPtr->valueShow == SHOW_X) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); + } else if (penPtr->valueShow == SHOW_Y) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, y); + } else if (penPtr->valueShow == SHOW_BOTH) { + sprintf_s(string, TCL_DOUBLE_SPACE, fmt, x); + strcat(string, ","); + sprintf_s(string + strlen(string), TCL_DOUBLE_SPACE, fmt, y); + } + Blt_Ps_DrawText(ps, string, &penPtr->valueStyle, pp->x, pp->y); + } } - -/* - *--------------------------------------------------------------------------- - * - * ActiveLineToPostScript -- - * - * Generates PostScript commands to draw as "active" the points (symbols) - * and or line segments (trace) representing the element. - * - * Results: - * None. - * - * Side effects: - * PostScript pen width, dashes, and color settings are changed. - * - *--------------------------------------------------------------------------- - */ -static void -ActiveLineToPostScriptProc(Graph *graphPtr, Blt_Ps ps, Element *basePtr) +static void ActiveLineToPostScriptProc(Graph *graphPtr, Blt_Ps ps, + Element *basePtr) { - LineElement *elemPtr = (LineElement *)basePtr; - LinePen *penPtr = (LinePen *)elemPtr->activePenPtr; - int symbolSize; - - if (penPtr == NULL) { - return; + LineElement *elemPtr = (LineElement *)basePtr; + LinePen *penPtr = (LinePen *)elemPtr->activePenPtr; + int symbolSize; + + if (penPtr == NULL) { + return; + } + symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size); + if (elemPtr->nActiveIndices > 0) { + if (elemPtr->flags & ACTIVE_PENDING) { + MapActiveSymbols(graphPtr, elemPtr); } - symbolSize = ScaleSymbol(elemPtr, penPtr->symbol.size); - if (elemPtr->nActiveIndices > 0) { - if (elemPtr->flags & ACTIVE_PENDING) { - MapActiveSymbols(graphPtr, elemPtr); - } - if (penPtr->symbol.type != SYMBOL_NONE) { - SymbolsToPostScript(graphPtr, ps, penPtr, symbolSize, - elemPtr->activePts.length, elemPtr->activePts.points); - } - if (penPtr->valueShow != SHOW_NONE) { - ValuesToPostScript(ps, elemPtr, penPtr, elemPtr->activePts.length, - elemPtr->activePts.points, elemPtr->activePts.map); - } - } else if (elemPtr->nActiveIndices < 0) { - if (penPtr->traceWidth > 0) { - if (elemPtr->lines.length > 0) { - SetLineAttributes(ps, penPtr); - Blt_Ps_Draw2DSegments(ps, elemPtr->lines.segments, - elemPtr->lines.length); - } - if (Blt_Chain_GetLength(elemPtr->traces) > 0) { - TracesToPostScript(ps, elemPtr, (LinePen *)penPtr); - } - } - if (penPtr->symbol.type != SYMBOL_NONE) { - SymbolsToPostScript(graphPtr, ps, penPtr, symbolSize, - elemPtr->symbolPts.length, elemPtr->symbolPts.points); - } - if (penPtr->valueShow != SHOW_NONE) { - ValuesToPostScript(ps, elemPtr, penPtr, elemPtr->symbolPts.length, - elemPtr->symbolPts.points, elemPtr->symbolPts.map); - } + if (penPtr->symbol.type != SYMBOL_NONE) { + SymbolsToPostScript(graphPtr, ps, penPtr, symbolSize, + elemPtr->activePts.length, elemPtr->activePts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + ValuesToPostScript(ps, elemPtr, penPtr, elemPtr->activePts.length, + elemPtr->activePts.points, elemPtr->activePts.map); + } + } else if (elemPtr->nActiveIndices < 0) { + if (penPtr->traceWidth > 0) { + if (elemPtr->lines.length > 0) { + SetLineAttributes(ps, penPtr); + Blt_Ps_Draw2DSegments(ps, elemPtr->lines.segments, + elemPtr->lines.length); + } + if (Blt_Chain_GetLength(elemPtr->traces) > 0) { + TracesToPostScript(ps, elemPtr, (LinePen *)penPtr); + } + } + if (penPtr->symbol.type != SYMBOL_NONE) { + SymbolsToPostScript(graphPtr, ps, penPtr, symbolSize, + elemPtr->symbolPts.length, elemPtr->symbolPts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + ValuesToPostScript(ps, elemPtr, penPtr, elemPtr->symbolPts.length, + elemPtr->symbolPts.points, elemPtr->symbolPts.map); } + } } -/* - *--------------------------------------------------------------------------- - * - * NormalLineToPostScriptProc -- - * - * Similar to the DrawLine procedure, prints PostScript related commands to - * form the connected line(s) representing the element. - * - * Results: - * None. - * - * Side effects: - * PostScript pen width, dashes, and color settings are changed. - * - *--------------------------------------------------------------------------- - */ -static void -NormalLineToPostScriptProc(Graph *graphPtr, Blt_Ps ps, Element *basePtr) +static void NormalLineToPostScriptProc(Graph *graphPtr, Blt_Ps ps, + Element *basePtr) { - LineElement *elemPtr = (LineElement *)basePtr; - Blt_ChainLink link; - unsigned int count; - - /* Draw fill area */ - if (elemPtr->fillPts != NULL) { - /* Create a path to use for both the polygon and its outline. */ - Blt_Ps_Append(ps, "% start fill area\n"); - Blt_Ps_Polyline(ps, elemPtr->fillPts, elemPtr->nFillPts); - - /* If the background fill color was specified, draw the polygon in a - * solid fashion with that color. */ - if (elemPtr->fillBgColor != NULL) { - Blt_Ps_XSetBackground(ps, elemPtr->fillBgColor); - Blt_Ps_Append(ps, "gsave fill grestore\n"); - } - Blt_Ps_XSetForeground(ps, elemPtr->fillFgColor); - if (elemPtr->fillBg != NULL) { - Blt_Ps_Append(ps, "gsave fill grestore\n"); - /* TBA: Transparent tiling is the hard part. */ - } else { - Blt_Ps_Append(ps, "gsave fill grestore\n"); - } - Blt_Ps_Append(ps, "% end fill area\n"); + LineElement *elemPtr = (LineElement *)basePtr; + Blt_ChainLink link; + unsigned int count; + + /* Draw fill area */ + if (elemPtr->fillPts != NULL) { + /* Create a path to use for both the polygon and its outline. */ + Blt_Ps_Append(ps, "% start fill area\n"); + Blt_Ps_Polyline(ps, elemPtr->fillPts, elemPtr->nFillPts); + + /* If the background fill color was specified, draw the polygon in a + * solid fashion with that color. */ + if (elemPtr->fillBgColor != NULL) { + Blt_Ps_XSetBackground(ps, elemPtr->fillBgColor); + Blt_Ps_Append(ps, "gsave fill grestore\n"); } - - /* Draw lines (strip chart) or traces (xy graph) */ - if (elemPtr->lines.length > 0) { - for (link = Blt_Chain_FirstLink(elemPtr->styles); link != NULL; - link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - LinePen *penPtr; - - stylePtr = Blt_Chain_GetValue(link); - penPtr = (LinePen *)stylePtr->penPtr; - if ((stylePtr->lines.length > 0) && (penPtr->traceWidth > 0)) { - SetLineAttributes(ps, penPtr); - Blt_Ps_Append(ps, "% start segments\n"); - Blt_Ps_Draw2DSegments(ps, stylePtr->lines.segments, - stylePtr->lines.length); - Blt_Ps_Append(ps, "% end segments\n"); - } - } + Blt_Ps_XSetForeground(ps, elemPtr->fillFgColor); + if (elemPtr->fillBg != NULL) { + Blt_Ps_Append(ps, "gsave fill grestore\n"); + /* TBA: Transparent tiling is the hard part. */ } else { - LinePen *penPtr; - - penPtr = NORMALPEN(elemPtr); - if ((Blt_Chain_GetLength(elemPtr->traces) > 0) && - (penPtr->traceWidth > 0)) { - TracesToPostScript(ps, elemPtr, penPtr); - } + Blt_Ps_Append(ps, "gsave fill grestore\n"); } + Blt_Ps_Append(ps, "% end fill area\n"); + } - /* Draw symbols, error bars, values. */ - - count = 0; - for (link = Blt_Chain_FirstLink(elemPtr->styles); link != NULL; + /* Draw lines (strip chart) or traces (xy graph) */ + if (elemPtr->lines.length > 0) { + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); link != NULL; link = Blt_Chain_NextLink(link)) { - LineStyle *stylePtr; - LinePen *penPtr; - XColor *colorPtr; - - stylePtr = Blt_Chain_GetValue(link); - penPtr = (LinePen *)stylePtr->penPtr; - colorPtr = penPtr->errorBarColor; - if (colorPtr == COLOR_DEFAULT) { - colorPtr = penPtr->traceColor; - } - if ((stylePtr->xeb.length > 0) && (penPtr->errorBarShow & SHOW_X)) { - Blt_Ps_XSetLineAttributes(ps, colorPtr, penPtr->errorBarLineWidth, - NULL, CapButt, JoinMiter); - Blt_Ps_Draw2DSegments(ps, stylePtr->xeb.segments, - stylePtr->xeb.length); - } - if ((stylePtr->yeb.length > 0) && (penPtr->errorBarShow & SHOW_Y)) { - Blt_Ps_XSetLineAttributes(ps, colorPtr, penPtr->errorBarLineWidth, - NULL, CapButt, JoinMiter); - Blt_Ps_Draw2DSegments(ps, stylePtr->yeb.segments, - stylePtr->yeb.length); - } - if ((stylePtr->symbolPts.length > 0) && - (penPtr->symbol.type != SYMBOL_NONE)) { - SymbolsToPostScript(graphPtr, ps, penPtr, stylePtr->symbolSize, - stylePtr->symbolPts.length, stylePtr->symbolPts.points); - } - if (penPtr->valueShow != SHOW_NONE) { - ValuesToPostScript(ps, elemPtr, penPtr, stylePtr->symbolPts.length, - stylePtr->symbolPts.points, elemPtr->symbolPts.map + count); - } - count += stylePtr->symbolPts.length; + LineStyle *stylePtr; + LinePen *penPtr; + + stylePtr = Blt_Chain_GetValue(link); + penPtr = (LinePen *)stylePtr->penPtr; + if ((stylePtr->lines.length > 0) && (penPtr->traceWidth > 0)) { + SetLineAttributes(ps, penPtr); + Blt_Ps_Append(ps, "% start segments\n"); + Blt_Ps_Draw2DSegments(ps, stylePtr->lines.segments, + stylePtr->lines.length); + Blt_Ps_Append(ps, "% end segments\n"); + } + } + } else { + LinePen *penPtr; + + penPtr = NORMALPEN(elemPtr); + if ((Blt_Chain_GetLength(elemPtr->traces) > 0) && + (penPtr->traceWidth > 0)) { + TracesToPostScript(ps, elemPtr, penPtr); } -} + } -/* - *--------------------------------------------------------------------------- - * - * DestroyLineProc -- - * - * Release memory and resources allocated for the line element. - * - * Results: - * None. - * - * Side effects: - * Everything associated with the line element is freed up. - * - *--------------------------------------------------------------------------- - */ + /* Draw symbols, error bars, values. */ -static void -DestroyLineProc(Graph *graphPtr, Element *basePtr) -{ - LineElement *elemPtr = (LineElement *)basePtr; + count = 0; + for (link = Blt_Chain_FirstLink(elemPtr->stylesPalette); link != NULL; + link = Blt_Chain_NextLink(link)) { + LineStyle *stylePtr; + LinePen *penPtr; + XColor *colorPtr; - DestroyPenProc(graphPtr, (Pen *)&elemPtr->builtinPen); - if (elemPtr->activePenPtr != NULL) { - Blt_FreePen((Pen *)elemPtr->activePenPtr); - } - ResetLine(elemPtr); - if (elemPtr->styles != NULL) { - Blt_FreeStylePalette(elemPtr->styles); - Blt_Chain_Destroy(elemPtr->styles); - } - if (elemPtr->activeIndices != NULL) { - free(elemPtr->activeIndices); - } - if (elemPtr->fillPts != NULL) { - free(elemPtr->fillPts); - } - if (elemPtr->fillGC != NULL) { - Tk_FreeGC(graphPtr->display, elemPtr->fillGC); - } + stylePtr = Blt_Chain_GetValue(link); + penPtr = (LinePen *)stylePtr->penPtr; + colorPtr = penPtr->errorBarColor; + if (colorPtr == COLOR_DEFAULT) { + colorPtr = penPtr->traceColor; + } + if ((stylePtr->xeb.length > 0) && (penPtr->errorBarShow & SHOW_X)) { + Blt_Ps_XSetLineAttributes(ps, colorPtr, penPtr->errorBarLineWidth, + NULL, CapButt, JoinMiter); + Blt_Ps_Draw2DSegments(ps, stylePtr->xeb.segments, + stylePtr->xeb.length); + } + if ((stylePtr->yeb.length > 0) && (penPtr->errorBarShow & SHOW_Y)) { + Blt_Ps_XSetLineAttributes(ps, colorPtr, penPtr->errorBarLineWidth, + NULL, CapButt, JoinMiter); + Blt_Ps_Draw2DSegments(ps, stylePtr->yeb.segments, + stylePtr->yeb.length); + } + if ((stylePtr->symbolPts.length > 0) && + (penPtr->symbol.type != SYMBOL_NONE)) { + SymbolsToPostScript(graphPtr, ps, penPtr, stylePtr->symbolSize, + stylePtr->symbolPts.length, + stylePtr->symbolPts.points); + } + if (penPtr->valueShow != SHOW_NONE) { + ValuesToPostScript(ps, elemPtr, penPtr, stylePtr->symbolPts.length, + stylePtr->symbolPts.points, + elemPtr->symbolPts.map + count); + } + count += stylePtr->symbolPts.length; + } } -/* - *--------------------------------------------------------------------------- - * - * Blt_LineElement -- - * - * Allocate memory and initialize methods for the new line element. - * - * Results: - * The pointer to the newly allocated element structure is returned. - * - * Side effects: - * Memory is allocated for the line element structure. - * - *--------------------------------------------------------------------------- - */ +static void DestroyLineProc(Graph* graphPtr, Element* basePtr) +{ + LineElement* elemPtr = (LineElement*)basePtr; + Tk_FreeConfigOptions((char*)elemPtr, elemPtr->optionTable, graphPtr->tkwin); + Tk_DeleteOptionTable(elemPtr->optionTable); + + DestroyPenProc(graphPtr, (Pen *)&elemPtr->builtinPen); + if (elemPtr->activePenPtr != NULL) { + Blt_FreePen((Pen *)elemPtr->activePenPtr); + } + ResetLine(elemPtr); + if (elemPtr->stylesPalette != NULL) { + Blt_FreeStylePalette(elemPtr->stylesPalette); + Blt_Chain_Destroy(elemPtr->stylesPalette); + } + if (elemPtr->activeIndices != NULL) { + free(elemPtr->activeIndices); + } + if (elemPtr->fillPts != NULL) { + free(elemPtr->fillPts); + } + if (elemPtr->fillGC != NULL) { + Tk_FreeGC(graphPtr->display, elemPtr->fillGC); + } +} static ElementProcs lineProcs = -{ + { ClosestLineProc, /* Finds the closest element/data * point */ ConfigureLineProc, /* Configures the element. */ @@ -4863,29 +4262,27 @@ static ElementProcs lineProcs = SymbolToPostScriptProc, /* Prints the line's symbol. */ MapLineProc /* Compute element's screen * coordinates. */ -}; + }; -Element * -Blt_LineElement(Graph *graphPtr, const char *name, ClassId classId) +Element * Blt_LineElement(Graph *graphPtr, const char *name, ClassId classId) { - LineElement *elemPtr; - - elemPtr = calloc(1, sizeof(LineElement)); - elemPtr->procsPtr = &lineProcs; - elemPtr->configSpecs = lineElemConfigSpecs; - elemPtr->obj.name = Blt_Strdup(name); - Blt_GraphSetObjectClass(&elemPtr->obj, classId); - elemPtr->flags = SCALE_SYMBOL; - elemPtr->obj.graphPtr = graphPtr; - /* By default an element's name and label are the same. */ - elemPtr->label = Blt_Strdup(name); - elemPtr->legendRelief = TK_RELIEF_FLAT; - elemPtr->penDir = PEN_BOTH_DIRECTIONS; - elemPtr->styles = Blt_Chain_Create(); - elemPtr->builtinPenPtr = &elemPtr->builtinPen; - elemPtr->reqSmooth = PEN_SMOOTH_LINEAR; - InitLinePen(elemPtr->builtinPenPtr); - bltLineStylesOption.clientData = (ClientData)sizeof(LineStyle); - return (Element *)elemPtr; + LineElement *elemPtr = calloc(1, sizeof(LineElement)); + elemPtr->procsPtr = &lineProcs; + elemPtr->optionTable = + Tk_CreateOptionTable(graphPtr->interp, lineElemOptionSpecs); + elemPtr->obj.name = Blt_Strdup(name); + Blt_GraphSetObjectClass(&elemPtr->obj, classId); + elemPtr->flags = SCALE_SYMBOL; + elemPtr->obj.graphPtr = graphPtr; + /* By default an element's name and label are the same. */ + elemPtr->label = Blt_Strdup(name); + elemPtr->legendRelief = TK_RELIEF_FLAT; + elemPtr->penDir = PEN_BOTH_DIRECTIONS; + elemPtr->stylesPalette = Blt_Chain_Create(); + elemPtr->builtinPenPtr = &elemPtr->builtinPen; + elemPtr->reqSmooth = PEN_SMOOTH_LINEAR; + InitLinePen(graphPtr, elemPtr->builtinPenPtr); + bltLineStylesOption.clientData = (ClientData)sizeof(LineStyle); + + return (Element *)elemPtr; } - diff --git a/src/bltGrElemOp.C b/src/bltGrElemOp.C index fe1fd6c..d6383da 100644 --- a/src/bltGrElemOp.C +++ b/src/bltGrElemOp.C @@ -49,36 +49,36 @@ static Blt_OptionParseProc ObjToAlong; static Blt_OptionPrintProc AlongToObj; static Blt_CustomOption alongOption = -{ + { ObjToAlong, AlongToObj, NULL, (ClientData)0 -}; + }; static Blt_OptionFreeProc FreeValues; static Blt_OptionParseProc ObjToValues; static Blt_OptionPrintProc ValuesToObj; Blt_CustomOption bltValuesOption = -{ + { ObjToValues, ValuesToObj, FreeValues, (ClientData)0 -}; + }; static Blt_OptionFreeProc FreeValuePairs; static Blt_OptionParseProc ObjToValuePairs; static Blt_OptionPrintProc ValuePairsToObj; Blt_CustomOption bltValuePairsOption = -{ + { ObjToValuePairs, ValuePairsToObj, FreeValuePairs, (ClientData)0 -}; + }; static Blt_OptionFreeProc FreeStyles; static Blt_OptionParseProc ObjToStyles; static Blt_OptionPrintProc StylesToObj; Blt_CustomOption bltLineStylesOption = -{ + { ObjToStyles, StylesToObj, FreeStyles, (ClientData)0, -}; + }; Blt_CustomOption bltBarStylesOption = -{ + { ObjToStyles, StylesToObj, FreeStyles, (ClientData)0, -}; + }; #include "bltGrElem.h" @@ -88,2134 +88,1491 @@ static void FindRange(ElemValues *valuesPtr); static void FreeDataValues(ElemValues *valuesPtr); static Tcl_FreeProc FreeElement; +static int ElementObjConfigure(Tcl_Interp *interp, Graph* graphPtr, + Element* elemPtr, + int objc, Tcl_Obj* const objv[]); typedef int (GraphElementProc)(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv); + Tcl_Obj *const *objv); -/* - *--------------------------------------------------------------------------- - * Custom option parse and print procedures - *--------------------------------------------------------------------------- - */ -static int -GetPenStyleFromObj( - Tcl_Interp *interp, - Graph *graphPtr, - Tcl_Obj *objPtr, - ClassId classId, - PenStyle *stylePtr) +static int GetPenStyleFromObj(Tcl_Interp *interp, Graph *graphPtr, + Tcl_Obj *objPtr, ClassId classId, + PenStyle *stylePtr) { - Pen *penPtr; - Tcl_Obj **objv; - int objc; - - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - if ((objc != 1) && (objc != 3)) { - if (interp != NULL) { - Tcl_AppendResult(interp, "bad style entry \"", - Tcl_GetString(objPtr), - "\": should be \"penName\" or \"penName min max\"", - (char *)NULL); - } - return TCL_ERROR; - } - if (Blt_GetPenFromObj(interp, graphPtr, objv[0], classId, &penPtr) - != TCL_OK) { - return TCL_ERROR; - } - if (objc == 3) { - double min, max; + Pen *penPtr; + Tcl_Obj **objv; + int objc; + + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + if ((objc != 1) && (objc != 3)) { + if (interp != NULL) { + Tcl_AppendResult(interp, "bad style entry \"", + Tcl_GetString(objPtr), + "\": should be \"penName\" or \"penName min max\"", + (char *)NULL); + } + return TCL_ERROR; + } + if (Blt_GetPenFromObj(interp, graphPtr, objv[0], classId, &penPtr) + != TCL_OK) { + return TCL_ERROR; + } + if (objc == 3) { + double min, max; - if ((Tcl_GetDoubleFromObj(interp, objv[1], &min) != TCL_OK) || - (Tcl_GetDoubleFromObj(interp, objv[2], &max) != TCL_OK)) { - return TCL_ERROR; - } - SetWeight(stylePtr->weight, min, max); + if ((Tcl_GetDoubleFromObj(interp, objv[1], &min) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[2], &max) != TCL_OK)) { + return TCL_ERROR; } - stylePtr->penPtr = penPtr; - return TCL_OK; + SetWeight(stylePtr->weight, min, max); + } + stylePtr->penPtr = penPtr; + return TCL_OK; } -static void -FreeVectorSource(ElemValues *valuesPtr) +static void FreeVectorSource(ElemValues *valuesPtr) { - if (valuesPtr->vectorSource.vector != NULL) { - Blt_SetVectorChangedProc(valuesPtr->vectorSource.vector, NULL, NULL); - Blt_FreeVectorId(valuesPtr->vectorSource.vector); - valuesPtr->vectorSource.vector = NULL; - } + if (valuesPtr->vectorSource.vector != NULL) { + Blt_SetVectorChangedProc(valuesPtr->vectorSource.vector, NULL, NULL); + Blt_FreeVectorId(valuesPtr->vectorSource.vector); + valuesPtr->vectorSource.vector = NULL; + } } -static int -FetchVectorValues(Tcl_Interp *interp, ElemValues *valuesPtr, Blt_Vector *vector) +static int FetchVectorValues(Tcl_Interp *interp, ElemValues *valuesPtr, + Blt_Vector *vector) { - double *array; + double *array; - if (valuesPtr->values == NULL) { - array = malloc(Blt_VecLength(vector) * sizeof(double)); - } else { - array = realloc(valuesPtr->values, - Blt_VecLength(vector) * sizeof(double)); - } - if (array == NULL) { - if (interp != NULL) { - Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL); - } - return TCL_ERROR; - } - memcpy(array, Blt_VecData(vector), sizeof(double) * Blt_VecLength(vector)); - valuesPtr->min = Blt_VecMin(vector); - valuesPtr->max = Blt_VecMax(vector); - valuesPtr->values = array; - valuesPtr->nValues = Blt_VecLength(vector); - /* FindRange(valuesPtr); */ - return TCL_OK; + if (valuesPtr->values == NULL) { + array = malloc(Blt_VecLength(vector) * sizeof(double)); + } else { + array = realloc(valuesPtr->values, + Blt_VecLength(vector) * sizeof(double)); + } + if (array == NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL); + } + return TCL_ERROR; + } + memcpy(array, Blt_VecData(vector), sizeof(double) * Blt_VecLength(vector)); + valuesPtr->min = Blt_VecMin(vector); + valuesPtr->max = Blt_VecMax(vector); + valuesPtr->values = array; + valuesPtr->nValues = Blt_VecLength(vector); + /* FindRange(valuesPtr); */ + return TCL_OK; } - -/* - *--------------------------------------------------------------------------- - * - * VectorChangedProc -- - * - * Results: - * None. - * - * Side Effects: - * Graph is redrawn. - * - *--------------------------------------------------------------------------- - */ -static void -VectorChangedProc( - Tcl_Interp *interp, - ClientData clientData, - Blt_VectorNotify notify) +static void VectorChangedProc(Tcl_Interp *interp, ClientData clientData, + Blt_VectorNotify notify) { - ElemValues *valuesPtr = clientData; + ElemValues *valuesPtr = clientData; - if (notify == BLT_VECTOR_NOTIFY_DESTROY) { - FreeDataValues(valuesPtr); - } else { - Blt_Vector *vector; + if (notify == BLT_VECTOR_NOTIFY_DESTROY) { + FreeDataValues(valuesPtr); + } else { + Blt_Vector *vector; - Blt_GetVectorById(interp, valuesPtr->vectorSource.vector, &vector); - if (FetchVectorValues(NULL, valuesPtr, vector) != TCL_OK) { - return; - } - } - { - Element *elemPtr = valuesPtr->elemPtr; - Graph *graphPtr; + Blt_GetVectorById(interp, valuesPtr->vectorSource.vector, &vector); + if (FetchVectorValues(NULL, valuesPtr, vector) != TCL_OK) { + return; + } + } + { + Element *elemPtr = valuesPtr->elemPtr; + Graph *graphPtr; - graphPtr = elemPtr->obj.graphPtr; - graphPtr->flags |= RESET_AXES; - elemPtr->flags |= MAP_ITEM; - if (!IGNORE_ELEMENT(elemPtr)) { - graphPtr->flags |= CACHE_DIRTY; - Blt_EventuallyRedrawGraph(graphPtr); - } + graphPtr = elemPtr->obj.graphPtr; + graphPtr->flags |= RESET_AXES; + elemPtr->flags |= MAP_ITEM; + if (!IGNORE_ELEMENT(elemPtr)) { + graphPtr->flags |= CACHE_DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); } + } } -static int -GetVectorData(Tcl_Interp *interp, ElemValues *valuesPtr, const char *vecName) +static int GetVectorData(Tcl_Interp *interp, ElemValues *valuesPtr, + const char *vecName) { - Blt_Vector *vecPtr; - VectorDataSource *srcPtr; + Blt_Vector *vecPtr; + VectorDataSource *srcPtr; + + srcPtr = &valuesPtr->vectorSource; + srcPtr->vector = Blt_AllocVectorId(interp, vecName); + if (Blt_GetVectorById(interp, srcPtr->vector, &vecPtr) != TCL_OK) { + return TCL_ERROR; + } + if (FetchVectorValues(interp, valuesPtr, vecPtr) != TCL_OK) { + FreeVectorSource(valuesPtr); + return TCL_ERROR; + } + Blt_SetVectorChangedProc(srcPtr->vector, VectorChangedProc, valuesPtr); + valuesPtr->type = ELEM_SOURCE_VECTOR; + return TCL_OK; +} - srcPtr = &valuesPtr->vectorSource; - srcPtr->vector = Blt_AllocVectorId(interp, vecName); - if (Blt_GetVectorById(interp, srcPtr->vector, &vecPtr) != TCL_OK) { - return TCL_ERROR; +static int ParseValues(Tcl_Interp *interp, Tcl_Obj *objPtr, int *nValuesPtr, + double **arrayPtr) +{ + int objc; + Tcl_Obj **objv; + + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + *arrayPtr = NULL; + *nValuesPtr = 0; + if (objc > 0) { + double *array; + double *p; + int i; + + array = malloc(sizeof(double) * objc); + if (array == NULL) { + Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL); + return TCL_ERROR; } - if (FetchVectorValues(interp, valuesPtr, vecPtr) != TCL_OK) { - FreeVectorSource(valuesPtr); + for (p = array, i = 0; i < objc; i++, p++) { + if (Blt_ExprDoubleFromObj(interp, objv[i], p) != TCL_OK) { + free(array); return TCL_ERROR; + } } - Blt_SetVectorChangedProc(srcPtr->vector, VectorChangedProc, valuesPtr); - valuesPtr->type = ELEM_SOURCE_VECTOR; - return TCL_OK; + *arrayPtr = array; + *nValuesPtr = objc; + } + return TCL_OK; } -static int -ParseValues(Tcl_Interp *interp, Tcl_Obj *objPtr, int *nValuesPtr, - double **arrayPtr) +static void FreeDataValues(ElemValues *valuesPtr) { - int objc; - Tcl_Obj **objv; + switch (valuesPtr->type) { + case ELEM_SOURCE_VECTOR: + FreeVectorSource(valuesPtr); break; + case ELEM_SOURCE_VALUES: + break; + } + if (valuesPtr->values != NULL) { + free(valuesPtr->values); + } + valuesPtr->values = NULL; + valuesPtr->nValues = 0; + valuesPtr->type = ELEM_SOURCE_VALUES; +} - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - *arrayPtr = NULL; - *nValuesPtr = 0; - if (objc > 0) { - double *array; - double *p; - int i; - - array = malloc(sizeof(double) * objc); - if (array == NULL) { - Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL); - return TCL_ERROR; - } - for (p = array, i = 0; i < objc; i++, p++) { - if (Blt_ExprDoubleFromObj(interp, objv[i], p) != TCL_OK) { - free(array); - return TCL_ERROR; - } - } - *arrayPtr = array; - *nValuesPtr = objc; - } - return TCL_OK; +static void FindRange(ElemValues *valuesPtr) +{ + int i; + double *x; + double min, max; + + if ((valuesPtr->nValues < 1) || (valuesPtr->values == NULL)) { + return; /* This shouldn't ever happen. */ + } + x = valuesPtr->values; + + min = DBL_MAX, max = -DBL_MAX; + for(i = 0; i < valuesPtr->nValues; i++) { + if (isfinite(x[i])) { + min = max = x[i]; + break; + } + } + /* Initialize values to track the vector range */ + for (/* empty */; i < valuesPtr->nValues; i++) { + if (isfinite(x[i])) { + if (x[i] < min) { + min = x[i]; + } else if (x[i] > max) { + max = x[i]; + } + } + } + valuesPtr->min = min, valuesPtr->max = max; +} + +double Blt_FindElemValuesMinimum(ElemValues *valuesPtr, double minLimit) +{ + int i; + double min; + + min = DBL_MAX; + for (i = 0; i < valuesPtr->nValues; i++) { + double x; + + x = valuesPtr->values[i]; + if (x < 0.0) { + /* What do you do about negative values when using log + * scale values seems like a grey area. Mirror. */ + x = -x; + } + if ((x > minLimit) && (min > x)) { + min = x; + } + } + if (min == DBL_MAX) { + min = minLimit; + } + return min; +} + +static void FreeValues(ClientData clientData, Display *display, char *widgRec, + int offset) +{ + ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); + + FreeDataValues(valuesPtr); } -static void -FreeDataValues(ElemValues *valuesPtr) +static int ObjToValues(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - switch (valuesPtr->type) { - case ELEM_SOURCE_VECTOR: - FreeVectorSource(valuesPtr); break; - case ELEM_SOURCE_VALUES: - break; + ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); + Element *elemPtr = (Element *)widgRec; + Tcl_Obj **objv; + int objc; + int result; + const char *string; + + valuesPtr->elemPtr = elemPtr; + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + elemPtr->flags |= MAP_ITEM; + + /* Release the current data sources. */ + FreeDataValues(valuesPtr); + if (objc == 0) { + return TCL_OK; /* Empty list of values. */ + } + string = Tcl_GetString(objv[0]); + if ((objc == 1) && (Blt_VectorExists2(interp, string))) { + result = GetVectorData(interp, valuesPtr, string); + } else { + double *values; + int nValues; + + result = ParseValues(interp, objPtr, &nValues, &values); + if (result != TCL_OK) { + return TCL_ERROR; /* Can't parse the values as numbers. */ } - if (valuesPtr->values != NULL) { - free(valuesPtr->values); + FreeDataValues(valuesPtr); + if (nValues > 0) { + valuesPtr->values = values; } - valuesPtr->values = NULL; - valuesPtr->nValues = 0; + valuesPtr->nValues = nValues; + FindRange(valuesPtr); valuesPtr->type = ELEM_SOURCE_VALUES; + } + return result; } -/* - *--------------------------------------------------------------------------- - * - * FindRange -- - * - * Find the minimum, positive minimum, and maximum values in a given - * vector and store the results in the vector structure. - * - * Results: - * None. - * - * Side Effects: - * Minimum, positive minimum, and maximum values are stored in the - * vector. - * - *--------------------------------------------------------------------------- - */ -static void -FindRange(ElemValues *valuesPtr) +static Tcl_Obj *ValuesToObj(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) { - int i; - double *x; - double min, max; + ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); - if ((valuesPtr->nValues < 1) || (valuesPtr->values == NULL)) { - return; /* This shouldn't ever happen. */ + switch (valuesPtr->type) { + case ELEM_SOURCE_VECTOR: + { + const char *vecName; + + vecName = Blt_NameOfVectorId(valuesPtr->vectorSource.vector); + return Tcl_NewStringObj(vecName, -1); } - x = valuesPtr->values; + case ELEM_SOURCE_VALUES: + { + Tcl_Obj *listObjPtr; + double *vp, *vend; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (vp = valuesPtr->values, vend = vp + valuesPtr->nValues; + vp < vend; vp++) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(*vp)); + } + return listObjPtr; + } + default: + abort(); + } + return Tcl_NewStringObj("", 0); +} - min = DBL_MAX, max = -DBL_MAX; - for(i = 0; i < valuesPtr->nValues; i++) { - if (isfinite(x[i])) { - min = max = x[i]; - break; - } - } - /* Initialize values to track the vector range */ - for (/* empty */; i < valuesPtr->nValues; i++) { - if (isfinite(x[i])) { - if (x[i] < min) { - min = x[i]; - } else if (x[i] > max) { - max = x[i]; - } - } - } - valuesPtr->min = min, valuesPtr->max = max; +static void FreeValuePairs(ClientData clientData, Display *display, + char *widgRec, int offset) +{ + Element *elemPtr = (Element *)widgRec; + + FreeDataValues(&elemPtr->x); + FreeDataValues(&elemPtr->y); } -/* - *--------------------------------------------------------------------------- - * - * Blt_FindElemValuesMinimum -- - * - * Find the minimum, positive minimum, and maximum values in a given - * vector and store the results in the vector structure. - * - * Results: - * None. - * - * Side Effects: - * Minimum, positive minimum, and maximum values are stored in the - * vector. - * - *--------------------------------------------------------------------------- - */ -double -Blt_FindElemValuesMinimum(ElemValues *valuesPtr, double minLimit) +static int ObjToValuePairs(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { + Element *elemPtr = (Element *)widgRec; + double *values; + int nValues; + size_t newSize; + + if (ParseValues(interp, objPtr, &nValues, &values) != TCL_OK) { + return TCL_ERROR; + } + if (nValues & 1) { + Tcl_AppendResult(interp, "odd number of data points", (char *)NULL); + free(values); + return TCL_ERROR; + } + nValues /= 2; + newSize = nValues * sizeof(double); + FreeDataValues(&elemPtr->x); /* Release the current data sources. */ + FreeDataValues(&elemPtr->y); + if (newSize > 0) { + double *p; int i; - double min; - min = DBL_MAX; - for (i = 0; i < valuesPtr->nValues; i++) { - double x; + elemPtr->x.values = malloc(newSize); + elemPtr->y.values = malloc(newSize); + elemPtr->x.nValues = elemPtr->y.nValues = nValues; + for (p = values, i = 0; i < nValues; i++) { + elemPtr->x.values[i] = *p++; + elemPtr->y.values[i] = *p++; + } + free(values); + FindRange(&elemPtr->x); + FindRange(&elemPtr->y); + } + return TCL_OK; +} - x = valuesPtr->values[i]; - if (x < 0.0) { - /* What do you do about negative values when using log - * scale values seems like a grey area. Mirror. */ - x = -x; - } - if ((x > minLimit) && (min > x)) { - min = x; - } - } - if (min == DBL_MAX) { - min = minLimit; - } - return min; +static Tcl_Obj *ValuePairsToObj(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) +{ + Element *elemPtr = (Element *)widgRec; + Tcl_Obj *listObjPtr; + int i; + int length; + + length = NUMBEROFPOINTS(elemPtr); + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (i = 0; i < length; i++) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(elemPtr->x.values[i])); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(elemPtr->y.values[i])); + } + return listObjPtr; } -/*ARGSUSED*/ -static void -FreeValues( - ClientData clientData, /* Not used. */ - Display *display, /* Not used. */ - char *widgRec, - int offset) +static int ObjToAlong(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr, char *widgRec, + int offset, int flags) { - ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); + int *intPtr = (int *)(widgRec + offset); + char *string; + + string = Tcl_GetString(objPtr); + if ((string[0] == 'x') && (string[1] == '\0')) { + *intPtr = SEARCH_X; + } else if ((string[0] == 'y') && (string[1] == '\0')) { + *intPtr = SEARCH_Y; + } else if ((string[0] == 'b') && (strcmp(string, "both") == 0)) { + *intPtr = SEARCH_BOTH; + } else { + Tcl_AppendResult(interp, "bad along value \"", string, "\"", + (char *)NULL); + return TCL_ERROR; + } + return TCL_OK; +} - FreeDataValues(valuesPtr); +static Tcl_Obj *AlongToObj(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, int offset, + int flags) +{ + int along = *(int *)(widgRec + offset); + Tcl_Obj *objPtr; + + switch (along) { + case SEARCH_X: + objPtr = Tcl_NewStringObj("x", 1); + break; + case SEARCH_Y: + objPtr = Tcl_NewStringObj("y", 1); + break; + case SEARCH_BOTH: + objPtr = Tcl_NewStringObj("both", 4); + break; + default: + objPtr = Tcl_NewStringObj("unknown along value", 4); + break; + } + return objPtr; } -/* - *--------------------------------------------------------------------------- - * - * ObjToValues -- - * - * Given a TCL list of numeric expression representing the element - * values, convert into an array of double precision values. In addition, - * the minimum and maximum values are saved. Since elastic values are - * allow (values which translate to the min/max of the graph), we must - * try to get the non-elastic minimum and maximum. - * - * Results: - * The return value is a standard TCL result. The vector is passed - * back via the valuesPtr. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToValues( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* TCL list of expressions */ - char *widgRec, /* Element record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +void Blt_FreeStylePalette(Blt_Chain stylePalette) { - ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); - Element *elemPtr = (Element *)widgRec; - Tcl_Obj **objv; - int objc; - int result; - const char *string; - - valuesPtr->elemPtr = elemPtr; - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - elemPtr->flags |= MAP_ITEM; + Blt_ChainLink link; - /* Release the current data sources. */ - FreeDataValues(valuesPtr); - if (objc == 0) { - return TCL_OK; /* Empty list of values. */ - } - string = Tcl_GetString(objv[0]); - if ((objc == 1) && (Blt_VectorExists2(interp, string))) { - result = GetVectorData(interp, valuesPtr, string); - } else { - double *values; - int nValues; - - result = ParseValues(interp, objPtr, &nValues, &values); - if (result != TCL_OK) { - return TCL_ERROR; /* Can't parse the values as numbers. */ - } - FreeDataValues(valuesPtr); - if (nValues > 0) { - valuesPtr->values = values; - } - valuesPtr->nValues = nValues; - FindRange(valuesPtr); - valuesPtr->type = ELEM_SOURCE_VALUES; + /* Skip the first slot. It contains the built-in "normal" pen of + * the element. */ + link = Blt_Chain_FirstLink(stylePalette); + if (link != NULL) { + Blt_ChainLink next; + + for (link = Blt_Chain_NextLink(link); link != NULL; link = next) { + PenStyle *stylePtr; + + next = Blt_Chain_NextLink(link); + stylePtr = Blt_Chain_GetValue(link); + Blt_FreePen(stylePtr->penPtr); + Blt_Chain_DeleteLink(stylePalette, link); } - return result; + } } -/* - *--------------------------------------------------------------------------- - * - * ValuesToObj -- - * - * Convert the vector of floating point values into a TCL list. - * - * Results: - * The string representation of the vector is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -ValuesToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Element record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static void FreeStyles(ClientData clientData, Display *display, + char *widgRec, int offset) { - ElemValues *valuesPtr = (ElemValues *)(widgRec + offset); + Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); - switch (valuesPtr->type) { - case ELEM_SOURCE_VECTOR: - { - const char *vecName; - - vecName = Blt_NameOfVectorId(valuesPtr->vectorSource.vector); - return Tcl_NewStringObj(vecName, -1); - } - case ELEM_SOURCE_VALUES: - { - Tcl_Obj *listObjPtr; - double *vp, *vend; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (vp = valuesPtr->values, vend = vp + valuesPtr->nValues; - vp < vend; vp++) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(*vp)); - } - return listObjPtr; - } - default: - abort(); - } - return Tcl_NewStringObj("", 0); + Blt_FreeStylePalette(stylePalette); } -/*ARGSUSED*/ -static void -FreeValuePairs( - ClientData clientData, /* Not used. */ - Display *display, /* Not used. */ - char *widgRec, - int offset) /* Not used. */ +static int ObjToStyles(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *objPtr,char *widgRec, + int offset, int flags) { - Element *elemPtr = (Element *)widgRec; - - FreeDataValues(&elemPtr->x); - FreeDataValues(&elemPtr->y); + Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); + Blt_ChainLink link; + Element *elemPtr = (Element *)(widgRec); + PenStyle *stylePtr; + Tcl_Obj **objv; + int objc; + int i; + size_t size = (size_t)clientData; + + + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + /* Reserve the first entry for the "normal" pen. We'll set the + * style later */ + Blt_FreeStylePalette(stylePalette); + link = Blt_Chain_FirstLink(stylePalette); + if (link == NULL) { + link = Blt_Chain_AllocLink(size); + Blt_Chain_LinkAfter(stylePalette, link, NULL); + } + stylePtr = Blt_Chain_GetValue(link); + stylePtr->penPtr = elemPtr->normalPenPtr; + for (i = 0; i < objc; i++) { + link = Blt_Chain_AllocLink(size); + stylePtr = Blt_Chain_GetValue(link); + stylePtr->weight.min = (double)i; + stylePtr->weight.max = (double)i + 1.0; + stylePtr->weight.range = 1.0; + if (GetPenStyleFromObj(interp, elemPtr->obj.graphPtr, objv[i], + elemPtr->obj.classId, + (PenStyle *)stylePtr) != TCL_OK) { + Blt_FreeStylePalette(stylePalette); + return TCL_ERROR; + } + Blt_Chain_LinkAfter(stylePalette, link, NULL); + } + return TCL_OK; } +static Tcl_Obj *StylesToObj(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, char *widgRec, + int offset, int flags) +{ + Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); + Blt_ChainLink link; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + link = Blt_Chain_FirstLink(stylePalette); + if (link != NULL) { + /* Skip the first style (it's the default) */ + for (link = Blt_Chain_NextLink(link); link != NULL; + link = Blt_Chain_NextLink(link)) { + PenStyle *stylePtr; + Tcl_Obj *subListObjPtr; + + stylePtr = Blt_Chain_GetValue(link); + subListObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, subListObjPtr, + Tcl_NewStringObj(stylePtr->penPtr->name, -1)); + Tcl_ListObjAppendElement(interp, subListObjPtr, + Tcl_NewDoubleObj(stylePtr->weight.min)); + Tcl_ListObjAppendElement(interp, subListObjPtr, + Tcl_NewDoubleObj(stylePtr->weight.max)); + Tcl_ListObjAppendElement(interp, listObjPtr, subListObjPtr); + } + } + return listObjPtr; +} -/* - *--------------------------------------------------------------------------- - * - * ObjToValuePairs -- - * - * This procedure is like ObjToValues except that it interprets - * the list of numeric expressions as X Y coordinate pairs. The - * minimum and maximum for both the X and Y vectors are - * determined. - * - * Results: - * The return value is a standard TCL result. The vectors are - * passed back via the widget record (elemPtr). - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToValuePairs( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* TCL list of numeric expressions */ - char *widgRec, /* Element record */ - int offset, /* Not used. */ - int flags) /* Not used. */ +PenStyle **Blt_StyleMap(Element *elemPtr) { - Element *elemPtr = (Element *)widgRec; - double *values; - int nValues; - size_t newSize; + int i; + int nWeights; /* Number of weights to be examined. + * If there are more data points than + * weights, they will default to the + * normal pen. */ - if (ParseValues(interp, objPtr, &nValues, &values) != TCL_OK) { - return TCL_ERROR; - } - if (nValues & 1) { - Tcl_AppendResult(interp, "odd number of data points", (char *)NULL); - free(values); - return TCL_ERROR; - } - nValues /= 2; - newSize = nValues * sizeof(double); - FreeDataValues(&elemPtr->x); /* Release the current data sources. */ - FreeDataValues(&elemPtr->y); - if (newSize > 0) { - double *p; - int i; - - elemPtr->x.values = malloc(newSize); - elemPtr->y.values = malloc(newSize); - elemPtr->x.nValues = elemPtr->y.nValues = nValues; - for (p = values, i = 0; i < nValues; i++) { - elemPtr->x.values[i] = *p++; - elemPtr->y.values[i] = *p++; + PenStyle **dataToStyle; /* Directory of styles. Each array + * element represents the style for + * the data point at that index */ + Blt_ChainLink link; + PenStyle *stylePtr; + double *w; /* Weight vector */ + int nPoints; + + nPoints = NUMBEROFPOINTS(elemPtr); + nWeights = MIN(elemPtr->w.nValues, nPoints); + w = elemPtr->w.values; + link = Blt_Chain_FirstLink(elemPtr->stylePalette); + stylePtr = Blt_Chain_GetValue(link); + + /* + * Create a style mapping array (data point index to style), + * initialized to the default style. + */ + dataToStyle = malloc(nPoints * sizeof(PenStyle *)); + for (i = 0; i < nPoints; i++) { + dataToStyle[i] = stylePtr; + } + + for (i = 0; i < nWeights; i++) { + for (link = Blt_Chain_LastLink(elemPtr->stylePalette); link != NULL; + link = Blt_Chain_PrevLink(link)) { + stylePtr = Blt_Chain_GetValue(link); + + if (stylePtr->weight.range > 0.0) { + double norm; + + norm = (w[i] - stylePtr->weight.min) / stylePtr->weight.range; + if (((norm - 1.0) <= DBL_EPSILON) && + (((1.0 - norm) - 1.0) <= DBL_EPSILON)) { + dataToStyle[i] = stylePtr; + break; /* Done: found range that matches. */ } - free(values); - FindRange(&elemPtr->x); - FindRange(&elemPtr->y); + } } - return TCL_OK; + } + return dataToStyle; } -/* - *--------------------------------------------------------------------------- - * - * ValuePairsToObj -- - * - * Convert pairs of floating point values in the X and Y arrays - * into a TCL list. - * - * Results: - * The return value is a string (Tcl list). - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -ValuePairsToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Element information record */ - int offset, /* Not used. */ - int flags) /* Not used. */ + +static int GetIndex(Tcl_Interp *interp, Element *elemPtr, + Tcl_Obj *objPtr, int *indexPtr) { - Element *elemPtr = (Element *)widgRec; - Tcl_Obj *listObjPtr; - int i; - int length; + char *string; + + string = Tcl_GetString(objPtr); + if ((*string == 'e') && (strcmp("end", string) == 0)) { + *indexPtr = NUMBEROFPOINTS(elemPtr) - 1; + } else if (Blt_ExprIntFromObj(interp, objPtr, indexPtr) != TCL_OK) { + return TCL_ERROR; + } + return TCL_OK; +} - length = NUMBEROFPOINTS(elemPtr); - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (i = 0; i < length; i++) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(elemPtr->x.values[i])); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(elemPtr->y.values[i])); - } - return listObjPtr; +int Blt_GetElement(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, + Element **elemPtrPtr) +{ + Tcl_HashEntry *hPtr; + char *name; + + name = Tcl_GetString(objPtr); + hPtr = Tcl_FindHashEntry(&graphPtr->elements.table, name); + if (hPtr == NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "can't find element \"", name, + "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", + (char *)NULL); + } + return TCL_ERROR; + } + *elemPtrPtr = Tcl_GetHashValue(hPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * ObjToAlong -- - * - * Given a TCL list of numeric expression representing the element - * values, convert into an array of double precision values. In - * addition, the minimum and maximum values are saved. Since - * elastic values are allow (values which translate to the - * min/max of the graph), we must try to get the non-elastic - * minimum and maximum. - * - * Results: - * The return value is a standard TCL result. The vector is passed - * back via the valuesPtr. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToAlong( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* String representation of value. */ - char *widgRec, /* Widget record. */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static void DestroyElement(Element *elemPtr) { - int *intPtr = (int *)(widgRec + offset); - char *string; - - string = Tcl_GetString(objPtr); - if ((string[0] == 'x') && (string[1] == '\0')) { - *intPtr = SEARCH_X; - } else if ((string[0] == 'y') && (string[1] == '\0')) { - *intPtr = SEARCH_Y; - } else if ((string[0] == 'b') && (strcmp(string, "both") == 0)) { - *intPtr = SEARCH_BOTH; - } else { - Tcl_AppendResult(interp, "bad along value \"", string, "\"", - (char *)NULL); - return TCL_ERROR; - } - return TCL_OK; + Graph *graphPtr = elemPtr->obj.graphPtr; + + Blt_DeleteBindings(graphPtr->bindTable, elemPtr); + Blt_Legend_RemoveElement(graphPtr, elemPtr); + + /* + * Call the element's own destructor to release the memory and + * resources allocated for it. + */ + (*elemPtr->procsPtr->destroyProc) (graphPtr, elemPtr); + + /* Remove it also from the element display list */ + if (elemPtr->link != NULL) { + Blt_Chain_DeleteLink(graphPtr->elements.displayList, elemPtr->link); + if (!IGNORE_ELEMENT(elemPtr)) { + graphPtr->flags |= RESET_WORLD; + Blt_EventuallyRedrawGraph(graphPtr); + } + } + /* Remove the element for the graph's hash table of elements */ + if (elemPtr->hashPtr != NULL) { + Tcl_DeleteHashEntry(elemPtr->hashPtr); + } + if (elemPtr->obj.name != NULL) { + free((void*)(elemPtr->obj.name)); + } + if (elemPtr->label != NULL) { + free((void*)(elemPtr->label)); + } + free(elemPtr); } -/* - *--------------------------------------------------------------------------- - * - * AlongToObj -- - * - * Convert the vector of floating point values into a TCL list. - * - * Results: - * The string representation of the vector is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -AlongToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Not used. */ - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Widget record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +static void FreeElement(char* data) { - int along = *(int *)(widgRec + offset); - Tcl_Obj *objPtr; + Element *elemPtr = (Element *)data; + DestroyElement(elemPtr); +} - switch (along) { - case SEARCH_X: - objPtr = Tcl_NewStringObj("x", 1); - break; - case SEARCH_Y: - objPtr = Tcl_NewStringObj("y", 1); - break; - case SEARCH_BOTH: - objPtr = Tcl_NewStringObj("both", 4); - break; - default: - objPtr = Tcl_NewStringObj("unknown along value", 4); - break; - } - return objPtr; +static int CreateElement(Graph *graphPtr, Tcl_Interp *interp, int objc, + Tcl_Obj *const *objv, ClassId classId) +{ + Element *elemPtr; + Tcl_HashEntry *hPtr; + int isNew; + char *string; + + string = Tcl_GetString(objv[3]); + if (string[0] == '-') { + Tcl_AppendResult(graphPtr->interp, "name of element \"", string, + "\" can't start with a '-'", (char *)NULL); + return TCL_ERROR; + } + hPtr = Tcl_CreateHashEntry(&graphPtr->elements.table, string, &isNew); + if (!isNew) { + Tcl_AppendResult(interp, "element \"", string, + "\" already exists in \"", Tcl_GetString(objv[0]), + "\"", (char *)NULL); + return TCL_ERROR; + } + switch (classId) { + case CID_ELEM_BAR: + elemPtr = Blt_BarElement(graphPtr, string, classId); + break; + case CID_ELEM_LINE: + elemPtr = Blt_LineElement(graphPtr, string, classId); + break; + default: + return TCL_ERROR; + } + elemPtr->hashPtr = hPtr; + Tcl_SetHashValue(hPtr, elemPtr); + + /* + if (Blt_ConfigureComponentFromObj(interp, graphPtr->tkwin, + elemPtr->obj.name, "Element", elemPtr->configSpecs, objc - 4, objv + 4, + (char *)elemPtr, 0) != TCL_OK) { + DestroyElement(elemPtr); + return TCL_ERROR; + } + */ + (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr); + + elemPtr->link = Blt_Chain_Append(graphPtr->elements.displayList, elemPtr); + graphPtr->flags |= CACHE_DIRTY; + Blt_EventuallyRedrawGraph(graphPtr); + elemPtr->flags |= MAP_ITEM; + graphPtr->flags |= RESET_AXES; + Tcl_SetObjResult(interp, objv[3]); + return TCL_OK; } -void -Blt_FreeStylePalette(Blt_Chain stylePalette) +void Blt_DestroyElements(Graph *graphPtr) { - Blt_ChainLink link; + Tcl_HashEntry *hPtr; + Tcl_HashSearch iter; + Element *elemPtr; + + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + elemPtr = Tcl_GetHashValue(hPtr); + elemPtr->hashPtr = NULL; + DestroyElement(elemPtr); + } + Tcl_DeleteHashTable(&graphPtr->elements.table); + Tcl_DeleteHashTable(&graphPtr->elements.tagTable); + Blt_Chain_Destroy(graphPtr->elements.displayList); +} + +void Blt_ConfigureElements(Graph *graphPtr) +{ + Blt_ChainLink link; + + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - /* Skip the first slot. It contains the built-in "normal" pen of - * the element. */ - link = Blt_Chain_FirstLink(stylePalette); - if (link != NULL) { - Blt_ChainLink next; + elemPtr = Blt_Chain_GetValue(link); + (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr); + } +} - for (link = Blt_Chain_NextLink(link); link != NULL; link = next) { - PenStyle *stylePtr; +void Blt_MapElements(Graph *graphPtr) +{ + Blt_ChainLink link; - next = Blt_Chain_NextLink(link); - stylePtr = Blt_Chain_GetValue(link); - Blt_FreePen(stylePtr->penPtr); - Blt_Chain_DeleteLink(stylePalette, link); - } + if (graphPtr->mode != BARS_INFRONT) { + Blt_ResetBarGroups(graphPtr); + } + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (IGNORE_ELEMENT(elemPtr)) { + continue; + } + if ((graphPtr->flags & MAP_ALL) || (elemPtr->flags & MAP_ITEM)) { + (*elemPtr->procsPtr->mapProc) (graphPtr, elemPtr); + elemPtr->flags &= ~MAP_ITEM; } + } } -/*ARGSUSED*/ -static void -FreeStyles( - ClientData clientData, /* Not used. */ - Display *display, /* Not used. */ - char *widgRec, - int offset) +void Blt_DrawElements(Graph *graphPtr, Drawable drawable) { - Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); + Blt_ChainLink link; + + /* Draw with respect to the stacking order. */ + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; - Blt_FreeStylePalette(stylePalette); + elemPtr = Blt_Chain_GetValue(link); + if ((elemPtr->flags & (HIDE|DELETE_PENDING)) == 0) { + (*elemPtr->procsPtr->drawNormalProc)(graphPtr, drawable, elemPtr); + } + } } -/* - *--------------------------------------------------------------------------- - * - * Blt_ObjToStyles -- - * - * Parse the list of style names. - * - * Results: - * The return value is a standard TCL result. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToStyles( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* String representing style list */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +void Blt_DrawActiveElements(Graph *graphPtr, Drawable drawable) { - Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); - Blt_ChainLink link; - Element *elemPtr = (Element *)(widgRec); - PenStyle *stylePtr; - Tcl_Obj **objv; - int objc; - int i; - size_t size = (size_t)clientData; + Blt_ChainLink link; + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - /* Reserve the first entry for the "normal" pen. We'll set the - * style later */ - Blt_FreeStylePalette(stylePalette); - link = Blt_Chain_FirstLink(stylePalette); - if (link == NULL) { - link = Blt_Chain_AllocLink(size); - Blt_Chain_LinkAfter(stylePalette, link, NULL); - } - stylePtr = Blt_Chain_GetValue(link); - stylePtr->penPtr = elemPtr->normalPenPtr; - for (i = 0; i < objc; i++) { - link = Blt_Chain_AllocLink(size); - stylePtr = Blt_Chain_GetValue(link); - stylePtr->weight.min = (double)i; - stylePtr->weight.max = (double)i + 1.0; - stylePtr->weight.range = 1.0; - if (GetPenStyleFromObj(interp, elemPtr->obj.graphPtr, objv[i], - elemPtr->obj.classId, (PenStyle *)stylePtr) != TCL_OK) { - Blt_FreeStylePalette(stylePalette); - return TCL_ERROR; - } - Blt_Chain_LinkAfter(stylePalette, link, NULL); + elemPtr = Blt_Chain_GetValue(link); + if ((elemPtr->flags & (HIDE|ACTIVE|DELETE_PENDING)) == ACTIVE) { + (*elemPtr->procsPtr->drawActiveProc)(graphPtr, drawable, elemPtr); } - return TCL_OK; + } } -/* - *--------------------------------------------------------------------------- - * - * StylesToObj -- - * - * Convert the style information into a Tcl_Obj. - * - * Results: - * The string representing the style information is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -StylesToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Element information record */ - int offset, /* Offset to field in structure */ - int flags) /* Not used. */ +void Blt_ElementsToPostScript(Graph *graphPtr, Blt_Ps ps) { - Blt_Chain stylePalette = *(Blt_Chain *)(widgRec + offset); - Blt_ChainLink link; - Tcl_Obj *listObjPtr; + Blt_ChainLink link; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - link = Blt_Chain_FirstLink(stylePalette); - if (link != NULL) { - /* Skip the first style (it's the default) */ - for (link = Blt_Chain_NextLink(link); link != NULL; - link = Blt_Chain_NextLink(link)) { - PenStyle *stylePtr; - Tcl_Obj *subListObjPtr; - - stylePtr = Blt_Chain_GetValue(link); - subListObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - Tcl_ListObjAppendElement(interp, subListObjPtr, - Tcl_NewStringObj(stylePtr->penPtr->name, -1)); - Tcl_ListObjAppendElement(interp, subListObjPtr, - Tcl_NewDoubleObj(stylePtr->weight.min)); - Tcl_ListObjAppendElement(interp, subListObjPtr, - Tcl_NewDoubleObj(stylePtr->weight.max)); - Tcl_ListObjAppendElement(interp, listObjPtr, subListObjPtr); - } + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->flags & (HIDE|DELETE_PENDING)) { + continue; } - return listObjPtr; + /* Comment the PostScript to indicate the start of the element */ + Blt_Ps_Format(ps, "\n%% Element \"%s\"\n\n", elemPtr->obj.name); + (*elemPtr->procsPtr->printNormalProc) (graphPtr, ps, elemPtr); + } } -/* - *--------------------------------------------------------------------------- - * - * Blt_StyleMap -- - * - * Creates an array of style indices and fills it based on the weight - * of each data point. - * - * Results: - * None. - * - * Side effects: - * Memory is freed and allocated for the index array. - * - *--------------------------------------------------------------------------- - */ - -PenStyle ** -Blt_StyleMap(Element *elemPtr) +void Blt_ActiveElementsToPostScript( Graph *graphPtr, Blt_Ps ps) { - int i; - int nWeights; /* Number of weights to be examined. - * If there are more data points than - * weights, they will default to the - * normal pen. */ - - PenStyle **dataToStyle; /* Directory of styles. Each array - * element represents the style for - * the data point at that index */ - Blt_ChainLink link; - PenStyle *stylePtr; - double *w; /* Weight vector */ - int nPoints; - - nPoints = NUMBEROFPOINTS(elemPtr); - nWeights = MIN(elemPtr->w.nValues, nPoints); - w = elemPtr->w.values; - link = Blt_Chain_FirstLink(elemPtr->stylePalette); - stylePtr = Blt_Chain_GetValue(link); + Blt_ChainLink link; - /* - * Create a style mapping array (data point index to style), - * initialized to the default style. - */ - dataToStyle = malloc(nPoints * sizeof(PenStyle *)); - for (i = 0; i < nPoints; i++) { - dataToStyle[i] = stylePtr; - } + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; - for (i = 0; i < nWeights; i++) { - for (link = Blt_Chain_LastLink(elemPtr->stylePalette); link != NULL; - link = Blt_Chain_PrevLink(link)) { - stylePtr = Blt_Chain_GetValue(link); - - if (stylePtr->weight.range > 0.0) { - double norm; - - norm = (w[i] - stylePtr->weight.min) / stylePtr->weight.range; - if (((norm - 1.0) <= DBL_EPSILON) && - (((1.0 - norm) - 1.0) <= DBL_EPSILON)) { - dataToStyle[i] = stylePtr; - break; /* Done: found range that matches. */ - } - } - } + elemPtr = Blt_Chain_GetValue(link); + if ((elemPtr->flags & (DELETE_PENDING|HIDE|ACTIVE)) == ACTIVE) { + Blt_Ps_Format(ps, "\n%% Active Element \"%s\"\n\n", + elemPtr->obj.name); + (*elemPtr->procsPtr->printActiveProc)(graphPtr, ps, elemPtr); } - return dataToStyle; + } } - -/* - *--------------------------------------------------------------------------- - * - * GetIndex -- - * - * Given a string representing the index of a pair of x,y - * coordinates, return the numeric index. - * - * Results: - * A standard TCL result. - * - *--------------------------------------------------------------------------- - */ -static int -GetIndex(Tcl_Interp *interp, Element *elemPtr, Tcl_Obj *objPtr, int *indexPtr) +static int ActivateOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - char *string; + Element *elemPtr; + int i; + int *indices; + int nIndices; - string = Tcl_GetString(objPtr); - if ((*string == 'e') && (strcmp("end", string) == 0)) { - *indexPtr = NUMBEROFPOINTS(elemPtr) - 1; - } else if (Blt_ExprIntFromObj(interp, objPtr, indexPtr) != TCL_OK) { - return TCL_ERROR; + if (objc == 3) { + Tcl_HashEntry *hPtr; + Tcl_HashSearch iter; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + /* List all the currently active elements */ + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + elemPtr = Tcl_GetHashValue(hPtr); + if (elemPtr->flags & ACTIVE) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(elemPtr->obj.name, -1)); + } } + Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; + } + if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ + } + elemPtr->flags |= ACTIVE | ACTIVE_PENDING; + + indices = NULL; + nIndices = -1; + if (objc > 4) { + int *activePtr; + + nIndices = objc - 4; + activePtr = indices = malloc(sizeof(int) * nIndices); + for (i = 4; i < objc; i++) { + if (GetIndex(interp, elemPtr, objv[i], activePtr) != TCL_OK) { + return TCL_ERROR; + } + activePtr++; + } + } + if (elemPtr->activeIndices != NULL) { + free(elemPtr->activeIndices); + } + elemPtr->nActiveIndices = nIndices; + elemPtr->activeIndices = indices; + Blt_EventuallyRedrawGraph(graphPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * Blt_GetElement -- - * - * Find the element represented the given name, returning a pointer to - * its data structure via elemPtrPtr. - * - * Results: - * A standard TCL result. - * - *--------------------------------------------------------------------------- - */ -int -Blt_GetElement(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, - Element **elemPtrPtr) +ClientData Blt_MakeElementTag(Graph *graphPtr, const char *tagName) +{ + Tcl_HashEntry *hPtr; + int isNew; + + hPtr = Tcl_CreateHashEntry(&graphPtr->elements.tagTable, tagName, &isNew); + return Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); +} + +static int BindOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { + if (objc == 3) { Tcl_HashEntry *hPtr; - char *name; - - name = Tcl_GetString(objPtr); - hPtr = Tcl_FindHashEntry(&graphPtr->elements.table, name); - if (hPtr == NULL) { - if (interp != NULL) { - Tcl_AppendResult(interp, "can't find element \"", name, - "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL); - } - return TCL_ERROR; + Tcl_HashSearch iter; + char *tagName; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.tagTable, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + tagName = Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(tagName, -1)); } - *elemPtrPtr = Tcl_GetHashValue(hPtr); + Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; + } + + 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) +{ + return CreateElement(graphPtr, interp, objc, objv, classId); +} + +static int CgetOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) +{ + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "cget option"); + return TCL_ERROR; + } + + Element *elemPtr; + if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, (char*)elemPtr, + elemPtr->optionTable, + objv[4], graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; } /* *--------------------------------------------------------------------------- * - * DestroyElement -- + * ClosestOp -- * - * Add a new element to the graph. + * Find the element closest to the specified screen coordinates. + * Options: + * -halo Consider points only with this maximum distance + * from the picked coordinate. + * -interpolate Find closest point along element traces, not just + * data points. + * -along * * Results: - * The return value is a standard TCL result. + * A standard TCL result. If an element could be found within + * the halo distance, the interpreter result is "1", otherwise + * "0". If a closest element exists, the designated TCL array + * variable will be set with the following information: + * + * 1) the element name, + * 2) the index of the closest point, + * 3) the distance (in screen coordinates) from the picked X-Y + * coordinate and the closest point, + * 4) the X coordinate (graph coordinate) of the closest point, + * 5) and the Y-coordinate. * *--------------------------------------------------------------------------- */ -static void -DestroyElement(Element *elemPtr) -{ - Graph *graphPtr = elemPtr->obj.graphPtr; - Blt_DeleteBindings(graphPtr->bindTable, elemPtr); - Blt_Legend_RemoveElement(graphPtr, elemPtr); +static Blt_ConfigSpec closestSpecs[] = { + {BLT_CONFIG_PIXELS, "-halo", (char *)NULL, (char *)NULL, + (char *)NULL, Tk_Offset(ClosestSearch, halo), 0}, + {BLT_CONFIG_BOOLEAN, "-interpolate", (char *)NULL, (char *)NULL, + (char *)NULL, Tk_Offset(ClosestSearch, mode), 0 }, + {BLT_CONFIG_CUSTOM, "-along", (char *)NULL, (char *)NULL, + (char *)NULL, Tk_Offset(ClosestSearch, along), 0, &alongOption}, + {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, + (char *)NULL, 0, 0} +}; + +static int ClosestOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) +{ + Element *elemPtr; + ClosestSearch search; + int i, x, y; + char *string; + + if (graphPtr->flags & RESET_AXES) { + Blt_ResetAxes(graphPtr); + } + if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) { + Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { + Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL); + return TCL_ERROR; + } + for (i = 5; i < objc; i += 2) { /* Count switches-value pairs */ + string = Tcl_GetString(objv[i]); + if ((string[0] != '-') || + ((string[1] == '-') && (string[2] == '\0'))) { + break; + } + } + if (i > objc) { + i = objc; + } + + search.mode = SEARCH_POINTS; + search.halo = graphPtr->halo; + search.index = -1; + search.along = SEARCH_BOTH; + search.x = x; + search.y = y; + + if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin, closestSpecs, i - 5, + objv + 5, (char *)&search, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { + return TCL_ERROR; /* Error occurred processing an option. */ + } + if (i < objc) { + string = Tcl_GetString(objv[i]); + if (string[0] == '-') { + i++; /* Skip "--" */ + } + } + search.dist = (double)(search.halo + 1); + + if (i < objc) { + for ( /* empty */ ; i < objc; i++) { + if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ + } + if (IGNORE_ELEMENT(elemPtr)) { + continue; + } + if (elemPtr->flags & (HIDE|MAP_ITEM)) { + continue; + } + (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); + } + } else { + Blt_ChainLink link; - Blt_FreeOptions(elemPtr->configSpecs, (char *)elemPtr,graphPtr->display, 0); + /* + * Find the closest point from the set of displayed elements, + * searching the display list from back to front. That way if + * the points from two different elements overlay each other + * exactly, the last one picked will be the topmost. + */ + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->flags & (HIDE|MAP_ITEM|DELETE_PENDING)) { + continue; + } + (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); + } + } + if (search.dist < (double)search.halo) { + Tcl_Obj *listObjPtr; /* - * Call the element's own destructor to release the memory and - * resources allocated for it. + * Return a list of name value pairs. */ - (*elemPtr->procsPtr->destroyProc) (graphPtr, elemPtr); - - /* Remove it also from the element display list */ - if (elemPtr->link != NULL) { - Blt_Chain_DeleteLink(graphPtr->elements.displayList, elemPtr->link); - if (!IGNORE_ELEMENT(elemPtr)) { - graphPtr->flags |= RESET_WORLD; - Blt_EventuallyRedrawGraph(graphPtr); - } - } - /* Remove the element for the graph's hash table of elements */ - if (elemPtr->hashPtr != NULL) { - Tcl_DeleteHashEntry(elemPtr->hashPtr); - } - if (elemPtr->obj.name != NULL) { - free((void*)(elemPtr->obj.name)); - } - if (elemPtr->label != NULL) { - free((void*)(elemPtr->label)); - } - free(elemPtr); + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("name", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(search.elemPtr->obj.name, -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("index", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewIntObj(search.index)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("x", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(search.point.x)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("y", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(search.point.y)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj("dist", -1)); + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewDoubleObj(search.dist)); + Tcl_SetObjResult(interp, listObjPtr); + } + return TCL_OK; } -static void FreeElement(char* data) +static int ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) { - Element *elemPtr = (Element *)data; - DestroyElement(elemPtr); + Element* elemPtr; + if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) + return TCL_ERROR; + + if (objc <= 5) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(graphPtr->interp, (char*)elemPtr, + elemPtr->optionTable, + (objc == 5) ? objv[4] : NULL, + graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return ElementObjConfigure(interp, graphPtr, elemPtr, objc-4, objv+4); } -/* - *--------------------------------------------------------------------------- - * - * CreateElement -- - * - * Add a new element to the graph. - * - * Results: - * The return value is a standard TCL result. - * - *--------------------------------------------------------------------------- - */ -static int -CreateElement(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv, ClassId classId) +static int ElementObjConfigure(Tcl_Interp *interp, Graph* graphPtr, + Element* elemPtr, + int objc, Tcl_Obj* const objv[]) { - Element *elemPtr; - Tcl_HashEntry *hPtr; - int isNew; - char *string; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; - string = Tcl_GetString(objv[3]); - if (string[0] == '-') { - Tcl_AppendResult(graphPtr->interp, "name of element \"", string, - "\" can't start with a '-'", (char *)NULL); - return TCL_ERROR; - } - hPtr = Tcl_CreateHashEntry(&graphPtr->elements.table, string, &isNew); - if (!isNew) { - Tcl_AppendResult(interp, "element \"", string, - "\" already exists in \"", Tcl_GetString(objv[0]), - "\"", (char *)NULL); - return TCL_ERROR; + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)elemPtr, elemPtr->optionTable, + objc, objv, graphPtr->tkwin, &savedOptions, &mask) + != TCL_OK) + continue; } - if (classId == CID_ELEM_BAR) { - elemPtr = Blt_BarElement(graphPtr, string, classId); - } else { - /* Stripcharts are line graphs with some options enabled. */ - elemPtr = Blt_LineElement(graphPtr, string, classId); + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); } - assert(elemPtr->configSpecs != NULL); - elemPtr->hashPtr = hPtr; - Tcl_SetHashValue(hPtr, elemPtr); - if (Blt_ConfigureComponentFromObj(interp, graphPtr->tkwin, - elemPtr->obj.name, "Element", elemPtr->configSpecs, objc - 4, objv + 4, - (char *)elemPtr, 0) != TCL_OK) { - DestroyElement(elemPtr); - return TCL_ERROR; - } - (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr); - elemPtr->link = Blt_Chain_Append(graphPtr->elements.displayList, elemPtr); + graphPtr->flags |= mask; graphPtr->flags |= CACHE_DIRTY; + if ((*elemPtr->procsPtr->configProc) (graphPtr, elemPtr) != TCL_OK) + return TCL_ERROR; Blt_EventuallyRedrawGraph(graphPtr); - elemPtr->flags |= MAP_ITEM; - graphPtr->flags |= RESET_AXES; - Tcl_SetObjResult(interp, objv[3]); + + break; + } + + if (!error) { + Tk_FreeSavedOptions(&savedOptions); return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } } + /* + if (Blt_ConfigModified(elemPtr->configSpecs, "-hide", (char *)NULL)) { + graphPtr->flags |= RESET_AXES; + elemPtr->flags |= MAP_ITEM; + } + */ + /* If data points or axes have changed, reset the axes (may + * affect autoscaling) and recalculate the screen points of + * the element. */ -/* - *--------------------------------------------------------------------------- - * - * Blt_DestroyElements -- - * - * Removes all the graph's elements. This routine is called when - * the graph is destroyed. - * - * Results: - * None. - * - * Side effects: - * Memory allocated for the graph's elements is freed. - * - *--------------------------------------------------------------------------- - */ -void -Blt_DestroyElements(Graph *graphPtr) + /* + if (Blt_ConfigModified(elemPtr->configSpecs, "-*data", "-map*", "-x", + "-y", (char *)NULL)) { + graphPtr->flags |= RESET_WORLD; + elemPtr->flags |= MAP_ITEM; + } + */ + /* The new label may change the size of the legend */ + /* + if (Blt_ConfigModified(elemPtr->configSpecs, "-label", (char *)NULL)) { + graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); + } + */ + +static int DeactivateOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; + int i; + + for (i = 3; i < objc; i++) { Element *elemPtr; - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - elemPtr = Tcl_GetHashValue(hPtr); - elemPtr->hashPtr = NULL; - DestroyElement(elemPtr); + if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ } - Tcl_DeleteHashTable(&graphPtr->elements.table); - Tcl_DeleteHashTable(&graphPtr->elements.tagTable); - Blt_Chain_Destroy(graphPtr->elements.displayList); + elemPtr->flags &= ~(ACTIVE | ACTIVE_PENDING); + if (elemPtr->activeIndices != NULL) { + free(elemPtr->activeIndices); + elemPtr->activeIndices = NULL; + } + elemPtr->nActiveIndices = 0; + } + Blt_EventuallyRedrawGraph(graphPtr); + return TCL_OK; } -void -Blt_ConfigureElements(Graph *graphPtr) +static int DeleteOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; + int i; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + for (i = 3; i < objc; i++) { + Element *elemPtr; - elemPtr = Blt_Chain_GetValue(link); - (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr); + if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ } + elemPtr->flags |= DELETE_PENDING; + Tcl_EventuallyFree(elemPtr, FreeElement); + } + Blt_EventuallyRedrawGraph(graphPtr); + return TCL_OK; } -void -Blt_MapElements(Graph *graphPtr) +static int ExistsOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; + Tcl_HashEntry *hPtr; - if (graphPtr->mode != BARS_INFRONT) { - Blt_ResetBarGroups(graphPtr); - } - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (IGNORE_ELEMENT(elemPtr)) { - continue; - } - if ((graphPtr->flags & MAP_ALL) || (elemPtr->flags & MAP_ITEM)) { - (*elemPtr->procsPtr->mapProc) (graphPtr, elemPtr); - elemPtr->flags &= ~MAP_ITEM; - } - } + hPtr = Tcl_FindHashEntry(&graphPtr->elements.table, Tcl_GetString(objv[3])); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL)); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * Blt_DrawElements -- - * - * Calls the individual element drawing routines for each - * element. - * - * Results: - * None - * - * Side Effects: - * Elements are drawn into the drawable (pixmap) which will - * eventually be displayed in the graph window. - * - *--------------------------------------------------------------------------- - */ -void -Blt_DrawElements(Graph *graphPtr, Drawable drawable) +static int GetOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; + char *string; - /* Draw with respect to the stacking order. */ - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; + string = Tcl_GetString(objv[3]); + if ((string[0] == 'c') && (strcmp(string, "current") == 0)) { + Element *elemPtr; - elemPtr = Blt_Chain_GetValue(link); - if ((elemPtr->flags & (HIDE|DELETE_PENDING)) == 0) { - (*elemPtr->procsPtr->drawNormalProc)(graphPtr, drawable, elemPtr); - } + elemPtr = Blt_GetCurrentItem(graphPtr->bindTable); + /* Report only on elements. */ + if ((elemPtr != NULL) && ((elemPtr->flags & DELETE_PENDING) == 0) && + (elemPtr->obj.classId >= CID_ELEM_BAR) && + (elemPtr->obj.classId <= CID_ELEM_LINE)) { + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name,-1); } + } + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * Blt_DrawActiveElements -- - * - * Calls the individual element drawing routines to display - * the active colors for each element. - * - * Results: - * None - * - * Side Effects: - * Elements are drawn into the drawable (pixmap) which will - * eventually be displayed in the graph window. - * - *--------------------------------------------------------------------------- - */ -void -Blt_DrawActiveElements(Graph *graphPtr, Drawable drawable) +static Tcl_Obj *DisplayListObj(Graph *graphPtr) { - Blt_ChainLink link; + Tcl_Obj *listObjPtr; + Blt_ChainLink link; - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + Tcl_Obj *objPtr; - elemPtr = Blt_Chain_GetValue(link); - if ((elemPtr->flags & (HIDE|ACTIVE|DELETE_PENDING)) == ACTIVE) { - (*elemPtr->procsPtr->drawActiveProc)(graphPtr, drawable, elemPtr); - } - } + elemPtr = Blt_Chain_GetValue(link); + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(graphPtr->interp, listObjPtr, objPtr); + } + return listObjPtr; } -/* - *--------------------------------------------------------------------------- - * - * Blt_ElementsToPostScript -- - * - * Generates PostScript output for each graph element in the - * element display list. - * - *--------------------------------------------------------------------------- - */ -void -Blt_ElementsToPostScript(Graph *graphPtr, Blt_Ps ps) +static int LowerOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj* const objv[]) { - Blt_ChainLink link; - - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; + Blt_Chain chain; + Blt_ChainLink link, next; + int i; + + /* Move the links of lowered elements out of the display list into + * a temporary list. */ + chain = Blt_Chain_Create(); + for (i = 3; i < objc; i++) { + Element *elemPtr; - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->flags & (HIDE|DELETE_PENDING)) { - continue; - } - /* Comment the PostScript to indicate the start of the element */ - Blt_Ps_Format(ps, "\n%% Element \"%s\"\n\n", elemPtr->obj.name); - (*elemPtr->procsPtr->printNormalProc) (graphPtr, ps, elemPtr); - } + if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ + } + Blt_Chain_UnlinkLink(graphPtr->elements.displayList, elemPtr->link); + Blt_Chain_LinkAfter(chain, elemPtr->link, NULL); + } + /* Append the links to end of the display list. */ + for (link = Blt_Chain_FirstLink(chain); link != NULL; link = next) { + next = Blt_Chain_NextLink(link); + Blt_Chain_UnlinkLink(chain, link); + Blt_Chain_LinkAfter(graphPtr->elements.displayList, link, NULL); + } + Blt_Chain_Destroy(chain); + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + graphPtr->flags |= RESET_WORLD; + Blt_EventuallyRedrawGraph(graphPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * Blt_ActiveElementsToPostScript -- - * - *--------------------------------------------------------------------------- - */ -void -Blt_ActiveElementsToPostScript( Graph *graphPtr, Blt_Ps ps) +static int NamesOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; + Tcl_Obj *listObjPtr; - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (objc == 3) { + Tcl_HashEntry *hPtr; + Tcl_HashSearch iter; - elemPtr = Blt_Chain_GetValue(link); - if ((elemPtr->flags & (DELETE_PENDING|HIDE|ACTIVE)) == ACTIVE) { - Blt_Ps_Format(ps, "\n%% Active Element \"%s\"\n\n", - elemPtr->obj.name); - (*elemPtr->procsPtr->printActiveProc)(graphPtr, ps, elemPtr); - } + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + Element *elemPtr; + Tcl_Obj *objPtr; + + elemPtr = Tcl_GetHashValue(hPtr); + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } -} + } else { + Tcl_HashEntry *hPtr; + Tcl_HashSearch iter; -/* - *--------------------------------------------------------------------------- - * - * ActivateOp -- - * - * Marks data points of elements (given by their index) as active. - * - * Results: - * Returns TCL_OK if no errors occurred. - * - *--------------------------------------------------------------------------- - */ -static int -ActivateOp( - Graph *graphPtr, /* Graph widget */ - Tcl_Interp *interp, /* Interpreter to report errors to */ - int objc, /* Number of element names */ - Tcl_Obj *const *objv) /* List of element names */ -{ - Element *elemPtr; - int i; - int *indices; - int nIndices; - - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - /* List all the currently active elements */ - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - elemPtr = Tcl_GetHashValue(hPtr); - if (elemPtr->flags & ACTIVE) { - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(elemPtr->obj.name, -1)); - } - } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; - } - if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - elemPtr->flags |= ACTIVE | ACTIVE_PENDING; - - indices = NULL; - nIndices = -1; - if (objc > 4) { - int *activePtr; - - nIndices = objc - 4; - activePtr = indices = malloc(sizeof(int) * nIndices); - for (i = 4; i < objc; i++) { - if (GetIndex(interp, elemPtr, objv[i], activePtr) != TCL_OK) { - return TCL_ERROR; - } - activePtr++; - } - } - if (elemPtr->activeIndices != NULL) { - free(elemPtr->activeIndices); - } - elemPtr->nActiveIndices = nIndices; - elemPtr->activeIndices = indices; - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -ClientData -Blt_MakeElementTag(Graph *graphPtr, const char *tagName) -{ - Tcl_HashEntry *hPtr; - int isNew; + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + Element *elemPtr; + int i; - hPtr = Tcl_CreateHashEntry(&graphPtr->elements.tagTable, tagName, &isNew); - return Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); -} + elemPtr = Tcl_GetHashValue(hPtr); + for (i = 3; i < objc; i++) { + if (Tcl_StringMatch(elemPtr->obj.name,Tcl_GetString(objv[i]))) { + Tcl_Obj *objPtr; -/* - *--------------------------------------------------------------------------- - * - * BindOp -- - * - * .g element bind elemName sequence command - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -BindOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; - char *tagName; - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.tagTable, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - tagName = Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(tagName, -1)); + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + break; } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; + } } - return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable, - Blt_MakeElementTag(graphPtr, Tcl_GetString(objv[3])), - objc - 4, objv + 4); + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * CreateOp -- - * - * Add a new element to the graph (using the default type of the - * graph). - * - * Results: - * The return value is a standard TCL result. - * - *--------------------------------------------------------------------------- - */ -static int -CreateOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv, - ClassId classId) -{ - return CreateElement(graphPtr, interp, objc, objv, classId); -} - -/* - *--------------------------------------------------------------------------- - * - * CgetOp -- - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -CgetOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, /* Not used. */ - Tcl_Obj *const *objv) -{ - Element *elemPtr; - - if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - if (Blt_ConfigureValueFromObj(interp, graphPtr->tkwin, elemPtr->configSpecs, - (char *)elemPtr, objv[4], 0) != TCL_OK) { - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ClosestOp -- - * - * Find the element closest to the specified screen coordinates. - * Options: - * -halo Consider points only with this maximum distance - * from the picked coordinate. - * -interpolate Find closest point along element traces, not just - * data points. - * -along - * - * Results: - * A standard TCL result. If an element could be found within - * the halo distance, the interpreter result is "1", otherwise - * "0". If a closest element exists, the designated TCL array - * variable will be set with the following information: - * - * 1) the element name, - * 2) the index of the closest point, - * 3) the distance (in screen coordinates) from the picked X-Y - * coordinate and the closest point, - * 4) the X coordinate (graph coordinate) of the closest point, - * 5) and the Y-coordinate. - * - *--------------------------------------------------------------------------- - */ - -static Blt_ConfigSpec closestSpecs[] = { - {BLT_CONFIG_PIXELS, "-halo", (char *)NULL, (char *)NULL, - (char *)NULL, Tk_Offset(ClosestSearch, halo), 0}, - {BLT_CONFIG_BOOLEAN, "-interpolate", (char *)NULL, (char *)NULL, - (char *)NULL, Tk_Offset(ClosestSearch, mode), 0 }, - {BLT_CONFIG_CUSTOM, "-along", (char *)NULL, (char *)NULL, - (char *)NULL, Tk_Offset(ClosestSearch, along), 0, &alongOption}, - {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, - (char *)NULL, 0, 0} -}; - -static int -ClosestOp( - Graph *graphPtr, /* Graph widget */ - Tcl_Interp *interp, /* Interpreter to report results to */ - int objc, /* Number of element names */ - Tcl_Obj *const *objv) /* List of element names */ +static int RaiseOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { + Blt_Chain chain; + Blt_ChainLink link, prev; + int i; + + /* Move the links of lowered elements out of the display list into + * a temporary list. */ + chain = Blt_Chain_Create(); + for (i = 3; i < objc; i++) { Element *elemPtr; - ClosestSearch search; - int i, x, y; - char *string; - - if (graphPtr->flags & RESET_AXES) { - Blt_ResetAxes(graphPtr); - } - if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) { - Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL); - return TCL_ERROR; - } - if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { - Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL); - return TCL_ERROR; - } - for (i = 5; i < objc; i += 2) { /* Count switches-value pairs */ - string = Tcl_GetString(objv[i]); - if ((string[0] != '-') || - ((string[1] == '-') && (string[2] == '\0'))) { - break; - } - } - if (i > objc) { - i = objc; - } - - search.mode = SEARCH_POINTS; - search.halo = graphPtr->halo; - search.index = -1; - search.along = SEARCH_BOTH; - search.x = x; - search.y = y; - if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin, closestSpecs, i - 5, - objv + 5, (char *)&search, BLT_CONFIG_OBJV_ONLY) != TCL_OK) { - return TCL_ERROR; /* Error occurred processing an option. */ - } - if (i < objc) { - string = Tcl_GetString(objv[i]); - if (string[0] == '-') { - i++; /* Skip "--" */ - } - } - search.dist = (double)(search.halo + 1); - - if (i < objc) { - for ( /* empty */ ; i < objc; i++) { - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - if (IGNORE_ELEMENT(elemPtr)) { - continue; - } - if (elemPtr->flags & (HIDE|MAP_ITEM)) { - continue; - } - (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); - } - } else { - Blt_ChainLink link; - - /* - * Find the closest point from the set of displayed elements, - * searching the display list from back to front. That way if - * the points from two different elements overlay each other - * exactly, the last one picked will be the topmost. - */ - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->flags & (HIDE|MAP_ITEM|DELETE_PENDING)) { - continue; - } - (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search); - } - } - if (search.dist < (double)search.halo) { - Tcl_Obj *listObjPtr; - /* - * Return a list of name value pairs. - */ - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("name", -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj(search.elemPtr->obj.name, -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("index", -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewIntObj(search.index)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("x", -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(search.point.x)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("y", -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(search.point.y)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewStringObj("dist", -1)); - Tcl_ListObjAppendElement(interp, listObjPtr, - Tcl_NewDoubleObj(search.dist)); - Tcl_SetObjResult(interp, listObjPtr); - } - return TCL_OK; + if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ + } + Blt_Chain_UnlinkLink(graphPtr->elements.displayList, elemPtr->link); + Blt_Chain_LinkAfter(chain, elemPtr->link, NULL); + } + /* Prepend the links to beginning of the display list in reverse order. */ + for (link = Blt_Chain_LastLink(chain); link != NULL; link = prev) { + prev = Blt_Chain_PrevLink(link); + Blt_Chain_UnlinkLink(chain, link); + Blt_Chain_LinkBefore(graphPtr->elements.displayList, link, NULL); + } + Blt_Chain_Destroy(chain); + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + graphPtr->flags |= RESET_WORLD; + Blt_EventuallyRedrawGraph(graphPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * ConfigureOp -- - * - * Sets the element specifications by the given the command line - * arguments and calls the element specification configuration - * routine. If zero or one command line options are given, only - * information about the option(s) is returned in interp->result. - * If the element configuration has changed and the element is - * currently displayed, the axis limits are updated and - * recomputed. - * - * Results: - * The return value is a standard TCL result. - * - * Side Effects: - * Graph will be redrawn to reflect the new display list. - * - *--------------------------------------------------------------------------- - */ -static int -ConfigureOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - int nNames, nOpts; - Tcl_Obj *const *options; - int i; - - /* Figure out where the option value pairs begin */ - objc -= 3; - objv += 3; - for (i = 0; i < objc; i++) { - Element *elemPtr; - char *string; - - string = Tcl_GetString(objv[i]); - if (string[0] == '-') { - break; - } - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - } - nNames = i; /* Number of element names specified */ - nOpts = objc - i; /* Number of options specified */ - options = objv + nNames; /* Start of options in objv */ - - for (i = 0; i < nNames; i++) { - Element *elemPtr; - int flags; - - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; - } - flags = BLT_CONFIG_OBJV_ONLY; - if (nOpts == 0) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, - elemPtr->configSpecs, (char *)elemPtr, (Tcl_Obj *)NULL, flags); - } else if (nOpts == 1) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, - elemPtr->configSpecs, (char *)elemPtr, options[0], flags); - } - if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin, - elemPtr->configSpecs, nOpts, options, (char *)elemPtr, flags) - != TCL_OK) { - return TCL_ERROR; - } - if ((*elemPtr->procsPtr->configProc) (graphPtr, elemPtr) != TCL_OK) { - return TCL_ERROR; /* Failed to configure element */ - } - if (Blt_ConfigModified(elemPtr->configSpecs, "-hide", (char *)NULL)) { - graphPtr->flags |= RESET_AXES; - elemPtr->flags |= MAP_ITEM; - } - /* If data points or axes have changed, reset the axes (may - * affect autoscaling) and recalculate the screen points of - * the element. */ - - if (Blt_ConfigModified(elemPtr->configSpecs, "-*data", "-map*", "-x", - "-y", (char *)NULL)) { - graphPtr->flags |= RESET_WORLD; - elemPtr->flags |= MAP_ITEM; - } - /* The new label may change the size of the legend */ - if (Blt_ConfigModified(elemPtr->configSpecs, "-label", (char *)NULL)) { - graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); - } - } - /* Update the pixmap if any configuration option changed */ - graphPtr->flags |= CACHE_DIRTY; - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * DeactivateOp -- - * - * Clears the active bit for the named elements. - * - * Results: - * Returns TCL_OK if no errors occurred. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -DeactivateOp( - Graph *graphPtr, /* Graph widget */ - Tcl_Interp *interp, /* Not used. */ - int objc, /* Number of element names */ - Tcl_Obj *const *objv) /* List of element names */ +static int ShowOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - int i; - - for (i = 3; i < objc; i++) { - Element *elemPtr; - - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - elemPtr->flags &= ~(ACTIVE | ACTIVE_PENDING); - if (elemPtr->activeIndices != NULL) { - free(elemPtr->activeIndices); - elemPtr->activeIndices = NULL; - } - elemPtr->nActiveIndices = 0; - } - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * DeleteOp -- - * - * Delete the named elements from the graph. - * - * Results: - * TCL_ERROR is returned if any of the named elements can not be - * found. Otherwise TCL_OK is returned; - * - * Side Effects: - * If the element is currently displayed, the plotting area of - * the graph is redrawn. Memory and resources allocated by the - * elements are released. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -DeleteOp( - Graph *graphPtr, /* Graph widget */ - Tcl_Interp *interp, /* Not used. */ - int objc, /* Number of element names */ - Tcl_Obj *const *objv) /* List of element names */ -{ - int i; - - for (i = 3; i < objc; i++) { - Element *elemPtr; - - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - elemPtr->flags |= DELETE_PENDING; - Tcl_EventuallyFree(elemPtr, FreeElement); - } - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ExistsOp -- - * - * Indicates if the named element exists in the graph. - * - * Results: - * The return value is a standard TCL result. The interpreter - * result will contain "1" or "0". - * - *--------------------------------------------------------------------------- - */ -/* ARGSUSED */ -static int -ExistsOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, /* Not used. */ - Tcl_Obj *const *objv) -{ - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&graphPtr->elements.table, Tcl_GetString(objv[3])); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL)); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * GetOp -- - * - * Returns the name of the picked element (using the element - * bind operation). Right now, the only name accepted is - * "current". - * - * Results: - * A standard TCL result. The interpreter result will contain - * the name of the element. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -GetOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, /* Not used. */ - Tcl_Obj *const *objv) -{ - char *string; - - string = Tcl_GetString(objv[3]); - if ((string[0] == 'c') && (strcmp(string, "current") == 0)) { - Element *elemPtr; - - elemPtr = Blt_GetCurrentItem(graphPtr->bindTable); - /* Report only on elements. */ - if ((elemPtr != NULL) && ((elemPtr->flags & DELETE_PENDING) == 0) && - (elemPtr->obj.classId >= CID_ELEM_BAR) && - (elemPtr->obj.classId <= CID_ELEM_LINE)) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name,-1); - } - } - return TCL_OK; -} - -static Tcl_Obj * -DisplayListObj(Graph *graphPtr) -{ - Tcl_Obj *listObjPtr; + if (objc == 4) { + Blt_Chain chain; Blt_ChainLink link; + Tcl_Obj **elem; + int i, n; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - Tcl_Obj *objPtr; - - elemPtr = Blt_Chain_GetValue(link); - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(graphPtr->interp, listObjPtr, objPtr); + if (Tcl_ListObjGetElements(interp, objv[3], &n, &elem) != TCL_OK) { + return TCL_ERROR; } - return listObjPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * LowerOp -- - * - * Lowers the named elements to the bottom of the display list. - * - * Results: - * A standard TCL result. The interpreter result will contain the new - * display list of element names. - * - * .g element lower elem ?elem...? - * - *--------------------------------------------------------------------------- - */ -static int -LowerOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) -{ - Blt_Chain chain; - Blt_ChainLink link, next; - int i; - - /* Move the links of lowered elements out of the display list into - * a temporary list. */ + /* Collect the named elements into a list. */ chain = Blt_Chain_Create(); - for (i = 3; i < objc; i++) { - Element *elemPtr; + for (i = 0; i < n; i++) { + Element *elemPtr; /* Element information record */ - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - Blt_Chain_UnlinkLink(graphPtr->elements.displayList, elemPtr->link); - Blt_Chain_LinkAfter(chain, elemPtr->link, NULL); + if (Blt_GetElement(interp, graphPtr, elem[i], &elemPtr) != TCL_OK) { + Blt_Chain_Destroy(chain); + return TCL_ERROR; + } + Blt_Chain_Append(chain, elemPtr); } - /* Append the links to end of the display list. */ - for (link = Blt_Chain_FirstLink(chain); link != NULL; link = next) { - next = Blt_Chain_NextLink(link); - Blt_Chain_UnlinkLink(chain, link); - Blt_Chain_LinkAfter(graphPtr->elements.displayList, link, NULL); - } - Blt_Chain_Destroy(chain); - Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); - graphPtr->flags |= RESET_WORLD; - Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * NamesOp -- - * - * Returns the names of the elements is the graph matching - * one of more patterns provided. If no pattern arguments - * are given, then all element names will be returned. - * - * Results: - * The return value is a standard TCL result. The interpreter - * result will contain a TCL list of the element names. - * - *--------------------------------------------------------------------------- - */ -static int -NamesOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; - - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - Element *elemPtr; - Tcl_Obj *objPtr; - - elemPtr = Tcl_GetHashValue(hPtr); - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - } - } else { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; - - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.table, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - Element *elemPtr; - int i; - - elemPtr = Tcl_GetHashValue(hPtr); - for (i = 3; i < objc; i++) { - if (Tcl_StringMatch(elemPtr->obj.name,Tcl_GetString(objv[i]))) { - Tcl_Obj *objPtr; - - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - break; - } - } - } + /* Clear the links from the currently displayed elements. */ + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + elemPtr->link = NULL; } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; -} - - -/* - *--------------------------------------------------------------------------- - * - * RaiseOp -- - * - * Reset the element within the display list. - * - * Results: - * The return value is a standard TCL result. The interpreter - * result will contain the new display list of element names. - * - * .g element raise ?elem...? - * - *--------------------------------------------------------------------------- - */ -static int -RaiseOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) -{ - Blt_Chain chain; - Blt_ChainLink link, prev; - int i; - - /* Move the links of lowered elements out of the display list into - * a temporary list. */ - chain = Blt_Chain_Create(); - for (i = 3; i < objc; i++) { - Element *elemPtr; - - if (Blt_GetElement(interp, graphPtr, objv[i], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - Blt_Chain_UnlinkLink(graphPtr->elements.displayList, elemPtr->link); - Blt_Chain_LinkAfter(chain, elemPtr->link, NULL); + Blt_Chain_Destroy(graphPtr->elements.displayList); + graphPtr->elements.displayList = chain; + /* Set links on all the displayed elements. */ + for (link = Blt_Chain_FirstLink(chain); link != NULL; + link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + elemPtr->link = link; } - /* Prepend the links to beginning of the display list in reverse order. */ - for (link = Blt_Chain_LastLink(chain); link != NULL; link = prev) { - prev = Blt_Chain_PrevLink(link); - Blt_Chain_UnlinkLink(chain, link); - Blt_Chain_LinkBefore(graphPtr->elements.displayList, link, NULL); - } - Blt_Chain_Destroy(chain); - Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); graphPtr->flags |= RESET_WORLD; Blt_EventuallyRedrawGraph(graphPtr); - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ShowOp -- - * - * Queries or resets the element display list. - * - * Results: - * The return value is a standard TCL result. The interpreter - * result will contain the new display list of element names. - * - *--------------------------------------------------------------------------- - */ -static int -ShowOp( - Graph *graphPtr, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - if (objc == 4) { - Blt_Chain chain; - Blt_ChainLink link; - Tcl_Obj **elem; - int i, n; - - if (Tcl_ListObjGetElements(interp, objv[3], &n, &elem) != TCL_OK) { - return TCL_ERROR; - } - /* Collect the named elements into a list. */ - chain = Blt_Chain_Create(); - for (i = 0; i < n; i++) { - Element *elemPtr; /* Element information record */ - - if (Blt_GetElement(interp, graphPtr, elem[i], &elemPtr) != TCL_OK) { - Blt_Chain_Destroy(chain); - return TCL_ERROR; - } - Blt_Chain_Append(chain, elemPtr); - } - /* Clear the links from the currently displayed elements. */ - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - elemPtr->link = NULL; - } - Blt_Chain_Destroy(graphPtr->elements.displayList); - graphPtr->elements.displayList = chain; - /* Set links on all the displayed elements. */ - for (link = Blt_Chain_FirstLink(chain); link != NULL; - link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - elemPtr->link = link; - } - graphPtr->flags |= RESET_WORLD; - Blt_EventuallyRedrawGraph(graphPtr); - } - Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); - return TCL_OK; + } + Tcl_SetObjResult(interp, DisplayListObj(graphPtr)); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * TypeOp -- - * - * Returns the name of the type of the element given by some - * element name. - * - * Results: - * A standard TCL result. Returns the type of the element in - * interp->result. If the identifier given doesn't represent an - * element, then an error message is left in interp->result. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -TypeOp( - Graph *graphPtr, /* Graph widget */ - Tcl_Interp *interp, - int objc, /* Not used. */ - Tcl_Obj *const *objv) /* Element name */ +static int TypeOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj* const objv[]) { - Element *elemPtr; - const char *string; - - if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) { - return TCL_ERROR; /* Can't find named element */ - } - switch (elemPtr->obj.classId) { - case CID_ELEM_BAR: string = "bar"; break; - case CID_ELEM_LINE: string = "line"; break; - default: string = "???"; break; - } - Tcl_SetStringObj(Tcl_GetObjResult(interp), string, -1); - return TCL_OK; + Element *elemPtr; + const char *string; + + if (Blt_GetElement(interp, graphPtr, objv[3], &elemPtr) != TCL_OK) { + return TCL_ERROR; /* Can't find named element */ + } + switch (elemPtr->obj.classId) { + case CID_ELEM_BAR: string = "bar"; break; + case CID_ELEM_LINE: string = "line"; break; + default: string = "???"; break; + } + Tcl_SetStringObj(Tcl_GetObjResult(interp), string, -1); + return TCL_OK; } -/* - * Global routines: - */ static Blt_OpSpec elemOps[] = { - {"activate", 1, ActivateOp, 3, 0, "?elemName? ?index...?",}, - {"bind", 1, BindOp, 3, 6, "elemName sequence command",}, - {"cget", 2, CgetOp, 5, 5, "elemName option",}, - {"closest", 2, ClosestOp, 5, 0, - "x y ?option value?... ?elemName?...",}, - {"configure", 2, ConfigureOp, 4, 0, - "elemName ?elemName?... ?option value?...",}, - {"create", 2, CreateOp, 4, 0, "elemName ?option value?...",}, - {"deactivate", 3, DeactivateOp, 3, 0, "?elemName?...",}, - {"delete", 3, DeleteOp, 3, 0, "?elemName?...",}, - {"exists", 1, ExistsOp, 4, 4, "elemName",}, - {"get", 1, GetOp, 4, 4, "name",}, - {"lower", 1, LowerOp, 3, 0, "?elemName?...",}, - {"names", 1, NamesOp, 3, 0, "?pattern?...",}, - {"raise", 1, RaiseOp, 3, 0, "?elemName?...",}, - {"show", 1, ShowOp, 3, 4, "?elemList?",}, - {"type", 1, TypeOp, 4, 4, "elemName",}, + {"activate", 1, ActivateOp, 3, 0, "?elemName? ?index...?",}, + {"bind", 1, BindOp, 3, 6, "elemName sequence command",}, + {"cget", 2, CgetOp, 5, 5, "elemName option",}, + {"closest", 2, ClosestOp, 5, 0, + "x y ?option value?... ?elemName?...",}, + {"configure", 2, ConfigureOp, 4, 0, + "elemName ?elemName?... ?option value?...",}, + {"create", 2, CreateOp, 4, 0, "elemName ?option value?...",}, + {"deactivate", 3, DeactivateOp, 3, 0, "?elemName?...",}, + {"delete", 3, DeleteOp, 3, 0, "?elemName?...",}, + {"exists", 1, ExistsOp, 4, 4, "elemName",}, + {"get", 1, GetOp, 4, 4, "name",}, + {"lower", 1, LowerOp, 3, 0, "?elemName?...",}, + {"names", 1, NamesOp, 3, 0, "?pattern?...",}, + {"raise", 1, RaiseOp, 3, 0, "?elemName?...",}, + {"show", 1, ShowOp, 3, 4, "?elemList?",}, + {"type", 1, TypeOp, 4, 4, "elemName",}, }; static int numElemOps = sizeof(elemOps) / sizeof(Blt_OpSpec); - -/* - *--------------------------------------------------------------------------- - * - * Blt_ElementOp -- - * - * This procedure is invoked to process the TCL command that - * corresponds to a widget managed by this module. See the user - * documentation for details on what it does. - * - * Results: - * A standard TCL result. - * - * Side effects: - * See the user documentation. - * - *--------------------------------------------------------------------------- - */ -int -Blt_ElementOp( - Graph *graphPtr, /* Graph widget record */ - Tcl_Interp *interp, - int objc, /* # arguments */ - Tcl_Obj *const *objv, /* Argument list */ - ClassId classId) +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) { - return TCL_ERROR; - } - if (ptr == CreateOp) { - result = CreateOp(graphPtr, interp, objc, objv, classId); - } else { - GraphElementProc *proc; + void *ptr; + int result; + + ptr = Blt_GetOpFromObj(interp, numElemOps, elemOps, BLT_OP_ARG2, + objc, objv, 0); + if (ptr == NULL) { + return TCL_ERROR; + } + if (ptr == CreateOp) { + result = CreateOp(graphPtr, interp, objc, objv, classId); + } else { + GraphElementProc *proc; - proc = ptr; - result = (*proc) (graphPtr, interp, objc, objv); - } - return result; + proc = ptr; + result = (*proc) (graphPtr, interp, objc, objv); + } + return result; } diff --git a/src/bltGrElemOp.h b/src/bltGrElemOp.h index d898847..d5db973 100644 --- a/src/bltGrElemOp.h +++ b/src/bltGrElemOp.h @@ -223,7 +223,7 @@ struct _Element { * "flags", then all data points are * drawn active. */ ElementProcs *procsPtr; - Blt_ConfigSpec *configSpecs; /* Configuration specifications. */ + Tk_OptionTable optionTable; /* Configuration specifications. */ Pen *activePenPtr; /* Standard Pens */ Pen *normalPenPtr; Pen *builtinPenPtr; diff --git a/src/bltGrHairs.C b/src/bltGrHairs.C index 12d0fad..38f8e86 100644 --- a/src/bltGrHairs.C +++ b/src/bltGrHairs.C @@ -186,7 +186,9 @@ static int CrosshairsObjConfigure(Tcl_Interp *interp, Graph* graphPtr, Tk_RestoreSavedOptions(&savedOptions); } + graphPtr->flags |= mask; ConfigureCrosshairs(graphPtr); + break; } @@ -255,6 +257,7 @@ void Blt_DestroyCrosshairs(Graph* graphPtr) { Crosshairs *chPtr = graphPtr->crosshairs; if (chPtr != NULL) { + Tk_DeleteOptionTable(chPtr->optionTable); if (chPtr->gc != NULL) Blt_FreePrivateGC(graphPtr->display, chPtr->gc); diff --git a/src/bltGrLegd.C b/src/bltGrLegd.C index 94d8ebd..a63a0d6 100644 --- a/src/bltGrLegd.C +++ b/src/bltGrLegd.C @@ -596,9 +596,11 @@ static int LegendObjConfigure(Tcl_Interp *interp, Graph* graphPtr, Tk_RestoreSavedOptions(&savedOptions); } + graphPtr->flags |= mask; graphPtr->flags |= (RESET_WORLD | CACHE_DIRTY); ConfigureLegend(graphPtr); Blt_EventuallyRedrawGraph(graphPtr); + break; } @@ -725,10 +727,10 @@ void Blt_DeleteLegend(Graph* graphPtr) void Blt_DestroyLegend(Graph *graphPtr) { - Legend *legendPtr = graphPtr->legend; - - if (graphPtr->legend == NULL) + Legend* legendPtr = graphPtr->legend; + if (legendPtr == NULL) return; + Tk_DeleteOptionTable(legendPtr->optionTable); Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->style); Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->titleStyle); diff --git a/src/bltGrPenOp.C b/src/bltGrPenOp.C index e1f67ab..e6307e0 100644 --- a/src/bltGrPenOp.C +++ b/src/bltGrPenOp.C @@ -305,113 +305,107 @@ GetPenFromObj(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, return TCL_OK; } -static void -DestroyPen(Pen *penPtr) +static void DestroyPen(Pen* penPtr) { - Graph *graphPtr = penPtr->graphPtr; - - Blt_FreeOptions(penPtr->configSpecs, (char *)penPtr, graphPtr->display, 0); - (*penPtr->destroyProc) (graphPtr, penPtr); - if ((penPtr->name != NULL) && (penPtr->name[0] != '\0')) { - free((void*)(penPtr->name)); - } - if (penPtr->hashPtr != NULL) { - Tcl_DeleteHashEntry(penPtr->hashPtr); - } - free(penPtr); + Graph *graphPtr = penPtr->graphPtr; + + (*penPtr->destroyProc) (graphPtr, penPtr); + if ((penPtr->name != NULL) && (penPtr->name[0] != '\0')) { + free((void*)(penPtr->name)); + } + if (penPtr->hashPtr != NULL) { + Tcl_DeleteHashEntry(penPtr->hashPtr); + } + free(penPtr); } -void -Blt_FreePen(Pen *penPtr) +void Blt_FreePen(Pen *penPtr) { - if (penPtr != NULL) { - penPtr->refCount--; - if ((penPtr->refCount == 0) && (penPtr->flags & DELETE_PENDING)) { - DestroyPen(penPtr); - } + if (penPtr != NULL) { + penPtr->refCount--; + if ((penPtr->refCount == 0) && (penPtr->flags & DELETE_PENDING)) { + DestroyPen(penPtr); } + } } -Pen * -Blt_CreatePen(Graph *graphPtr, const char *penName, ClassId classId, - int objc, Tcl_Obj *const *objv) +Pen* Blt_CreatePen(Graph* graphPtr, const char* penName, ClassId classId, + int objc, Tcl_Obj* const objv[]) { - Pen *penPtr; - Tcl_HashEntry *hPtr; - unsigned int configFlags; - int isNew; - int i; + Pen *penPtr; + Tcl_HashEntry *hPtr; + unsigned int configFlags; + int isNew; + int i; + + /* + * Scan the option list for a "-type" entry. This will indicate what type + * of pen we are creating. Otherwise we'll default to the suggested type. + * Last -type option wins. + */ + for (i = 0; i < objc; i += 2) { + char *string; + int length; - /* - * Scan the option list for a "-type" entry. This will indicate what type - * of pen we are creating. Otherwise we'll default to the suggested type. - * Last -type option wins. - */ - for (i = 0; i < objc; i += 2) { - char *string; - int length; - - string = Tcl_GetStringFromObj(objv[i], &length); - if ((length > 2) && (strncmp(string, "-type", length) == 0)) { - char *arg; - - arg = Tcl_GetString(objv[i + 1]); - if (strcmp(arg, "bar") == 0) { - classId = CID_ELEM_BAR; - } else if (strcmp(arg, "line") == 0) { - classId = CID_ELEM_LINE; - } else { - Tcl_AppendResult(graphPtr->interp, "unknown pen type \"", - arg, "\" specified", (char *)NULL); - return NULL; - } - } + string = Tcl_GetStringFromObj(objv[i], &length); + if ((length > 2) && (strncmp(string, "-type", length) == 0)) { + char *arg; + + arg = Tcl_GetString(objv[i + 1]); + if (strcmp(arg, "bar") == 0) { + classId = CID_ELEM_BAR; + } else if (strcmp(arg, "line") == 0) { + classId = CID_ELEM_LINE; + } else { + Tcl_AppendResult(graphPtr->interp, "unknown pen type \"", + arg, "\" specified", (char *)NULL); + return NULL; + } } - classId = CID_ELEM_LINE; - hPtr = Tcl_CreateHashEntry(&graphPtr->penTable, penName, &isNew); - if (!isNew) { - penPtr = Tcl_GetHashValue(hPtr); - if ((penPtr->flags & DELETE_PENDING) == 0) { - Tcl_AppendResult(graphPtr->interp, "pen \"", penName, - "\" already exists in \"", Tk_PathName(graphPtr->tkwin), "\"", - (char *)NULL); - return NULL; - } - if (penPtr->classId != classId) { - Tcl_AppendResult(graphPtr->interp, "pen \"", penName, - "\" in-use: can't change pen type from \"", - Blt_GraphClassName(penPtr->classId), "\" to \"", - Blt_GraphClassName(classId), "\"", (char *)NULL); - return NULL; - } - penPtr->flags &= ~DELETE_PENDING; /* Undelete the pen. */ - } else { - if (classId == CID_ELEM_BAR) { - penPtr = Blt_BarPen(penName); - } else { - penPtr = Blt_LinePen(penName); - } - penPtr->classId = classId; - penPtr->hashPtr = hPtr; - penPtr->graphPtr = graphPtr; - Tcl_SetHashValue(hPtr, penPtr); + } + classId = CID_ELEM_LINE; + hPtr = Tcl_CreateHashEntry(&graphPtr->penTable, penName, &isNew); + if (!isNew) { + penPtr = Tcl_GetHashValue(hPtr); + if ((penPtr->flags & DELETE_PENDING) == 0) { + Tcl_AppendResult(graphPtr->interp, "pen \"", penName, + "\" already exists in \"", Tk_PathName(graphPtr->tkwin), "\"", + (char *)NULL); + return NULL; } - configFlags = (penPtr->flags & (ACTIVE_PEN | NORMAL_PEN)); - if (Blt_ConfigureComponentFromObj(graphPtr->interp, graphPtr->tkwin, - penPtr->name, "Pen", penPtr->configSpecs, objc, objv, - (char *)penPtr, configFlags) != TCL_OK) { - if (isNew) { - DestroyPen(penPtr); - } - return NULL; + if (penPtr->classId != classId) { + Tcl_AppendResult(graphPtr->interp, "pen \"", penName, + "\" in-use: can't change pen type from \"", + Blt_GraphClassName(penPtr->classId), "\" to \"", + Blt_GraphClassName(classId), "\"", (char *)NULL); + return NULL; + } + penPtr->flags &= ~DELETE_PENDING; /* Undelete the pen. */ + } else { + if (classId == CID_ELEM_BAR) + penPtr = Blt_BarPen(graphPtr, penName); + else + penPtr = Blt_LinePen(graphPtr, penName); + penPtr->classId = classId; + penPtr->hashPtr = hPtr; + penPtr->graphPtr = graphPtr; + Tcl_SetHashValue(hPtr, penPtr); + } + configFlags = (penPtr->flags & (ACTIVE_PEN | NORMAL_PEN)); + if (Blt_ConfigureComponentFromObj(graphPtr->interp, graphPtr->tkwin, + penPtr->name, "Pen", penPtr->configSpecs, objc, objv, + (char *)penPtr, configFlags) != TCL_OK) { + if (isNew) { + DestroyPen(penPtr); } - (*penPtr->configProc) (graphPtr, penPtr); - return penPtr; + return NULL; + } + (*penPtr->configProc) (graphPtr, penPtr); + return penPtr; } -int -Blt_GetPenFromObj(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, - ClassId classId, Pen **penPtrPtr) +int Blt_GetPenFromObj(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, + ClassId classId, Pen **penPtrPtr) { Tcl_HashEntry *hPtr; Pen *penPtr; diff --git a/src/bltGraph.C b/src/bltGraph.C index dce2c07..6238812 100644 --- a/src/bltGraph.C +++ b/src/bltGraph.C @@ -390,14 +390,14 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, goto error; if (Blt_CreateLegend(graphPtr) != TCL_OK) goto error; - - if (Blt_CreatePageSetup(graphPtr) != TCL_OK) - goto error; if (Blt_CreatePen(graphPtr, "activeLine", CID_ELEM_LINE, 0, NULL) == NULL) goto error; if (Blt_CreatePen(graphPtr, "activeBar", CID_ELEM_BAR, 0, NULL) == NULL) goto error; + if (Blt_CreatePageSetup(graphPtr) != TCL_OK) + goto error; + Tk_CreateEventHandler(graphPtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, GraphEventProc, graphPtr); @@ -731,6 +731,7 @@ static void GraphInstCmdDeleteProc(ClientData clientData) static void DestroyGraph(char* dataPtr) { Graph* graphPtr = (Graph*)dataPtr; + Tk_DeleteOptionTable(graphPtr->optionTable); Blt_DestroyCrosshairs(graphPtr); Blt_DestroyMarkers(graphPtr); diff --git a/src/bltGraph.h b/src/bltGraph.h index 60f762b..024657d 100644 --- a/src/bltGraph.h +++ b/src/bltGraph.h @@ -593,12 +593,12 @@ extern void Blt_DestroyPens(Graph *graphPtr); extern int Blt_GetPenFromObj(Tcl_Interp *interp, Graph *graphPtr, Tcl_Obj *objPtr, ClassId classId, Pen **penPtrPtr); -extern Pen *Blt_BarPen(const char *penName); +extern Pen* Blt_BarPen(Graph* graphPtr, const char* penName); -extern Pen *Blt_LinePen(const char *penName); +extern Pen* Blt_LinePen(Graph* graphPtr, const char* penName); -extern Pen *Blt_CreatePen(Graph *graphPtr, const char *penName, - ClassId classId, int objc, Tcl_Obj *const *objv); +extern Pen* Blt_CreatePen(Graph* graphPtr, const char* penName, + ClassId classId, int objc, Tcl_Obj* const objv[]); extern int Blt_InitLinePens(Graph *graphPtr); -- cgit v0.12