5 * This module implements generic elements for the BLT graph widget.
7 * Copyright 1993-1998 Lucent Technologies, Inc.
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
30 #include <X11/Xutil.h>
33 static Tk_OptionParseProc StringToData;
34 static Tk_OptionPrintProc DataToString;
35 static Tk_OptionParseProc StringToDataPairs;
36 static Tk_OptionPrintProc DataPairsToString;
37 static Tk_OptionParseProc StringToAlong;
38 static Tk_OptionPrintProc AlongToString;
39 static Tk_CustomOption alongOption =
41 StringToAlong, AlongToString, (ClientData)0
43 Tk_CustomOption bltDataOption =
45 StringToData, DataToString, (ClientData)0
47 Tk_CustomOption bltDataPairsOption =
49 StringToDataPairs, DataPairsToString, (ClientData)0
51 extern Tk_CustomOption bltDistanceOption;
56 #include "bltGrElem.h"
58 extern Element *Blt_BarElement();
59 extern Element *Blt_LineElement();
61 static Blt_VectorChangedProc VectorChangedProc;
63 EXTERN int Blt_VectorExists2 _ANSI_ARGS_((Tcl_Interp *interp, char *vecName));
66 * ----------------------------------------------------------------------
67 * Custom option parse and print procedures
68 * ----------------------------------------------------------------------
71 GetPenStyle(graphPtr, string, type, stylePtr)
78 Tcl_Interp *interp = graphPtr->interp;
83 if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) {
86 if ((nElem != 1) && (nElem != 3)) {
87 Tcl_AppendResult(interp, "bad style \"", string, "\": should be ",
88 "\"penName\" or \"penName min max\"", (char *)NULL);
89 if (elemArr != NULL) {
94 if (Blt_GetPen(graphPtr, elemArr[0], type, &penPtr) != TCL_OK) {
101 if ((Tcl_GetDouble(interp, elemArr[1], &min) != TCL_OK) ||
102 (Tcl_GetDouble(interp, elemArr[2], &max) != TCL_OK)) {
106 SetWeight(stylePtr->weight, min, max);
108 stylePtr->penPtr = penPtr;
118 vPtr->nValues = Blt_VecLength(vPtr->vecPtr);
119 vPtr->valueArr = Blt_VecData(vPtr->vecPtr);
120 vPtr->min = Blt_VecMin(vPtr->vecPtr);
121 vPtr->max = Blt_VecMax(vPtr->vecPtr);
125 *----------------------------------------------------------------------
129 * Find the minimum, positive minimum, and maximum values in a
130 * given vector and store the results in the vector structure.
136 * Minimum, positive minimum, and maximum values are stored in
139 *----------------------------------------------------------------------
147 register double min, max;
149 if ((vPtr->nValues < 1) || (vPtr->valueArr == NULL)) {
150 return; /* This shouldn't ever happen. */
154 min = DBL_MAX, max = -DBL_MAX;
155 for(i = 0; i < vPtr->nValues; i++) {
161 /* Initialize values to track the vector range */
162 for (/* empty */; i < vPtr->nValues; i++) {
166 } else if (x[i] > max) {
171 vPtr->min = min, vPtr->max = max;
175 *----------------------------------------------------------------------
177 * Blt_FindElemVectorMinimum --
179 * Find the minimum, positive minimum, and maximum values in a
180 * given vector and store the results in the vector structure.
186 * Minimum, positive minimum, and maximum values are stored in
189 *----------------------------------------------------------------------
192 Blt_FindElemVectorMinimum(vPtr, minLimit)
197 register double *arr;
198 register double min, x;
201 arr = vPtr->valueArr;
202 for (i = 0; i < vPtr->nValues; i++) {
205 /* What do you do about negative values when using log
206 * scale values seems like a grey area. Mirror. */
209 if ((x > minLimit) && (min > x)) {
213 if (min == DBL_MAX) {
223 if (vPtr->clientId != NULL) {
224 Blt_FreeVectorId(vPtr->clientId); /* Free the old vector */
225 vPtr->clientId = NULL;
226 } else if (vPtr->valueArr != NULL) {
227 Blt_Free(vPtr->valueArr);
229 vPtr->valueArr = NULL;
234 *----------------------------------------------------------------------
236 * VectorChangedProc --
245 *----------------------------------------------------------------------
248 VectorChangedProc(interp, clientData, notify)
250 ClientData clientData;
251 Blt_VectorNotify notify;
253 ElemVector *vPtr = clientData;
254 Element *elemPtr = vPtr->elemPtr;
255 Graph *graphPtr = elemPtr->graphPtr;
258 case BLT_VECTOR_NOTIFY_DESTROY:
259 vPtr->clientId = NULL;
260 vPtr->valueArr = NULL;
264 case BLT_VECTOR_NOTIFY_UPDATE:
266 Blt_GetVectorById(interp, vPtr->clientId, &vPtr->vecPtr);
267 SyncElemVector(vPtr);
270 graphPtr->flags |= RESET_AXES;
271 elemPtr->flags |= MAP_ITEM;
272 if (!elemPtr->hidden) {
273 graphPtr->flags |= REDRAW_BACKING_STORE;
274 Blt_EventuallyRedrawGraph(graphPtr);
279 EvalExprList(interp, list, nElemPtr, arrayPtr)
292 if (Tcl_SplitList(interp, list, &nElem, &elemArr) != TCL_OK) {
297 register double *valuePtr;
301 array = Blt_Malloc(sizeof(double) * nElem);
303 Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL);
307 for (i = 0; i < nElem; i++) {
308 if (Tcl_ExprDouble(interp, elemArr[i], valuePtr) != TCL_OK) {
320 if (result != TCL_OK) {
327 *----------------------------------------------------------------------
331 * Given a Tcl list of numeric expression representing the element
332 * values, convert into an array of double precision values. In
333 * addition, the minimum and maximum values are saved. Since
334 * elastic values are allow (values which translate to the
335 * min/max of the graph), we must try to get the non-elastic
336 * minimum and maximum.
339 * The return value is a standard Tcl result. The vector is passed
342 *----------------------------------------------------------------------
346 StringToData(clientData, interp, tkwin, string, widgRec, offset)
347 ClientData clientData; /* Type of axis vector to fill */
348 Tcl_Interp *interp; /* Interpreter to send results back to */
349 Tk_Window tkwin; /* Not used. */
350 char *string; /* Tcl list of expressions */
351 char *widgRec; /* Element record */
352 int offset; /* Offset of vector in Element record */
354 Element *elemPtr = (Element *)(widgRec);
355 ElemVector *vPtr = (ElemVector *)(widgRec + offset);
357 FreeDataVector(vPtr);
358 if (Blt_VectorExists2(interp, string)) {
359 Blt_VectorId clientId;
361 clientId = Blt_AllocVectorId(interp, string);
362 if (Blt_GetVectorById(interp, clientId, &vPtr->vecPtr) != TCL_OK) {
365 Blt_SetVectorChangedProc(clientId, VectorChangedProc, vPtr);
366 vPtr->elemPtr = elemPtr;
367 vPtr->clientId = clientId;
368 SyncElemVector(vPtr);
369 elemPtr->flags |= MAP_ITEM;
374 if (EvalExprList(interp, string, &nValues, &newArr) != TCL_OK) {
378 vPtr->valueArr = newArr;
380 vPtr->nValues = nValues;
387 *----------------------------------------------------------------------
391 * Convert the vector of floating point values into a Tcl list.
394 * The string representation of the vector is returned.
396 *----------------------------------------------------------------------
400 DataToString(clientData, tkwin, widgRec, offset, freeProcPtr)
401 ClientData clientData; /* Type of axis vector to print */
402 Tk_Window tkwin; /* Not used. */
403 char *widgRec; /* Element record */
404 int offset; /* Offset of vector in Element record */
405 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
407 ElemVector *vPtr = (ElemVector *)(widgRec + offset);
408 Element *elemPtr = (Element *)(widgRec);
411 char string[TCL_DOUBLE_SPACE + 1];
414 if (vPtr->clientId != NULL) {
415 return Blt_NameOfVectorId(vPtr->clientId);
417 if (vPtr->nValues == 0) {
420 Tcl_DStringInit(&dString);
421 endPtr = vPtr->valueArr + vPtr->nValues;
422 for (p = vPtr->valueArr; p < endPtr; p++) {
423 Tcl_PrintDouble(elemPtr->graphPtr->interp, *p, string);
424 Tcl_DStringAppendElement(&dString, string);
426 result = Tcl_DStringValue(&dString);
429 * If memory wasn't allocated for the dynamic string, do it here (it's
430 * currently on the stack), so that Tcl can free it normally.
432 if (result == dString.staticSpace) {
433 result = Blt_Strdup(result);
435 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
440 *----------------------------------------------------------------------
442 * StringToDataPairs --
444 * This procedure is like StringToData except that it interprets
445 * the list of numeric expressions as X Y coordinate pairs. The
446 * minimum and maximum for both the X and Y vectors are
450 * The return value is a standard Tcl result. The vectors are
451 * passed back via the widget record (elemPtr).
453 *----------------------------------------------------------------------
457 StringToDataPairs(clientData, interp, tkwin, string, widgRec, offset)
458 ClientData clientData; /* Not used. */
459 Tcl_Interp *interp; /* Interpreter to send results back to */
460 Tk_Window tkwin; /* Not used. */
461 char *string; /* Tcl list of numeric expressions */
462 char *widgRec; /* Element record */
463 int offset; /* Not used. */
465 Element *elemPtr = (Element *)widgRec;
467 unsigned int newSize;
470 if (EvalExprList(interp, string, &nElem, &newArr) != TCL_OK) {
474 Tcl_AppendResult(interp, "odd number of data points", (char *)NULL);
479 newSize = nElem * sizeof(double);
481 FreeDataVector(&elemPtr->x);
482 FreeDataVector(&elemPtr->y);
484 elemPtr->x.valueArr = Blt_Malloc(newSize);
485 elemPtr->y.valueArr = Blt_Malloc(newSize);
486 assert(elemPtr->x.valueArr && elemPtr->y.valueArr);
487 elemPtr->x.nValues = elemPtr->y.nValues = nElem;
490 register double *dataPtr;
493 for (dataPtr = newArr, i = 0; i < nElem; i++) {
494 elemPtr->x.valueArr[i] = *dataPtr++;
495 elemPtr->y.valueArr[i] = *dataPtr++;
498 FindRange(&elemPtr->x);
499 FindRange(&elemPtr->y);
505 *----------------------------------------------------------------------
507 * DataPairsToString --
509 * Convert pairs of floating point values in the X and Y arrays
513 * The return value is a string (Tcl list).
515 *----------------------------------------------------------------------
519 DataPairsToString(clientData, tkwin, widgRec, offset, freeProcPtr)
520 ClientData clientData; /* Not used. */
521 Tk_Window tkwin; /* Not used. */
522 char *widgRec; /* Element information record */
523 int offset; /* Not used. */
524 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
526 Element *elemPtr = (Element *)widgRec;
527 Tcl_Interp *interp = elemPtr->graphPtr->interp;
531 char string[TCL_DOUBLE_SPACE + 1];
534 length = NumberOfPoints(elemPtr);
538 Tcl_DStringInit(&dString);
539 for (i = 0; i < length; i++) {
540 Tcl_PrintDouble(interp, elemPtr->x.valueArr[i], string);
541 Tcl_DStringAppendElement(&dString, string);
542 Tcl_PrintDouble(interp, elemPtr->y.valueArr[i], string);
543 Tcl_DStringAppendElement(&dString, string);
545 result = Tcl_DStringValue(&dString);
548 * If memory wasn't allocated for the dynamic string, do it here
549 * (it's currently on the stack), so that Tcl can free it
552 if (result == dString.staticSpace) {
553 result = Blt_Strdup(result);
555 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
560 *----------------------------------------------------------------------
564 * Given a Tcl list of numeric expression representing the element
565 * values, convert into an array of double precision values. In
566 * addition, the minimum and maximum values are saved. Since
567 * elastic values are allow (values which translate to the
568 * min/max of the graph), we must try to get the non-elastic
569 * minimum and maximum.
572 * The return value is a standard Tcl result. The vector is passed
575 *----------------------------------------------------------------------
579 StringToAlong(clientData, interp, tkwin, string, widgRec, offset)
580 ClientData clientData; /* Not used. */
581 Tcl_Interp *interp; /* Interpreter to send results back to */
582 Tk_Window tkwin; /* Not used. */
583 char *string; /* String representation of value. */
584 char *widgRec; /* Widget record. */
585 int offset; /* Offset of field in widget record. */
587 int *intPtr = (int *)(widgRec + offset);
589 if ((string[0] == 'x') && (string[1] == '\0')) {
591 } else if ((string[0] == 'y') && (string[1] == '\0')) {
593 } else if ((string[0] == 'b') && (strcmp(string, "both") == 0)) {
594 *intPtr = SEARCH_BOTH;
596 Tcl_AppendResult(interp, "bad along value \"", string, "\"",
604 *----------------------------------------------------------------------
608 * Convert the vector of floating point values into a Tcl list.
611 * The string representation of the vector is returned.
613 *----------------------------------------------------------------------
617 AlongToString(clientData, tkwin, widgRec, offset, freeProcPtr)
618 ClientData clientData; /* Not used. */
619 Tk_Window tkwin; /* Not used. */
620 char *widgRec; /* Widget record */
621 int offset; /* Offset of field in widget record */
622 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
624 int along = *(int *)(widgRec + offset);
634 return "unknown along value";
639 Blt_FreePalette(graphPtr, palette)
643 Blt_ChainLink *linkPtr;
645 /* Skip the first slot. It contains the built-in "normal" pen of
647 linkPtr = Blt_ChainFirstLink(palette);
648 if (linkPtr != NULL) {
649 register PenStyle *stylePtr;
650 Blt_ChainLink *nextPtr;
652 for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL;
654 nextPtr = Blt_ChainNextLink(linkPtr);
655 stylePtr = Blt_ChainGetValue(linkPtr);
656 Blt_FreePen(graphPtr, stylePtr->penPtr);
657 Blt_ChainDeleteLink(palette, linkPtr);
663 *----------------------------------------------------------------------
665 * Blt_StringToStyles --
667 * Parse the list of style names.
670 * The return value is a standard Tcl result.
672 *----------------------------------------------------------------------
676 Blt_StringToStyles(clientData, interp, tkwin, string, widgRec, offset)
677 ClientData clientData; /* Not used. */
678 Tcl_Interp *interp; /* Interpreter to send results back to */
679 Tk_Window tkwin; /* Not used. */
680 char *string; /* String representing style list */
681 char *widgRec; /* Element information record */
682 int offset; /* Offset of symbol type field in record */
684 Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset);
685 Blt_ChainLink *linkPtr;
686 Element *elemPtr = (Element *)(widgRec);
691 size_t size = (size_t)clientData;
694 Blt_FreePalette(elemPtr->graphPtr, palette);
695 if ((string == NULL) || (*string == '\0')) {
697 } else if (Tcl_SplitList(interp, string, &nStyles, &elemArr) != TCL_OK) {
700 /* Reserve the first entry for the "normal" pen. We'll set the
702 linkPtr = Blt_ChainFirstLink(palette);
703 if (linkPtr == NULL) {
704 linkPtr = Blt_ChainAllocLink(size);
705 Blt_ChainLinkBefore(palette, linkPtr, NULL);
707 stylePtr = Blt_ChainGetValue(linkPtr);
708 stylePtr->penPtr = elemPtr->normalPenPtr;
710 for (i = 0; i < nStyles; i++) {
711 linkPtr = Blt_ChainAllocLink(size);
712 stylePtr = Blt_ChainGetValue(linkPtr);
713 stylePtr->weight.min = (double)i;
714 stylePtr->weight.max = (double)i + 1.0;
715 stylePtr->weight.range = 1.0;
716 if (GetPenStyle(elemPtr->graphPtr, elemArr[i], elemPtr->classUid,
717 (PenStyle *)stylePtr) != TCL_OK) {
719 Blt_FreePalette(elemPtr->graphPtr, palette);
722 Blt_ChainLinkBefore(palette, linkPtr, NULL);
724 if (elemArr != NULL) {
731 *----------------------------------------------------------------------
733 * Blt_StylesToString --
735 * Convert the style information into a string.
738 * The string representing the style information is returned.
740 *----------------------------------------------------------------------
744 Blt_StylesToString(clientData, tkwin, widgRec, offset, freeProcPtr)
745 ClientData clientData; /* Not used. */
746 Tk_Window tkwin; /* Not used. */
747 char *widgRec; /* Element information record */
748 int offset; /* Not used. */
749 Tcl_FreeProc **freeProcPtr; /* Not used. */
751 Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset);
754 Blt_ChainLink *linkPtr;
756 Tcl_DStringInit(&dString);
757 linkPtr = Blt_ChainFirstLink(palette);
758 if (linkPtr != NULL) {
759 Element *elemPtr = (Element *)(widgRec);
760 char string[TCL_DOUBLE_SPACE];
764 interp = elemPtr->graphPtr->interp;
765 for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL;
766 linkPtr = Blt_ChainNextLink(linkPtr)) {
767 stylePtr = Blt_ChainGetValue(linkPtr);
768 Tcl_DStringStartSublist(&dString);
769 Tcl_DStringAppendElement(&dString, stylePtr->penPtr->name);
770 Tcl_PrintDouble(interp, stylePtr->weight.min, string);
771 Tcl_DStringAppendElement(&dString, string);
772 Tcl_PrintDouble(interp, stylePtr->weight.max, string);
773 Tcl_DStringAppendElement(&dString, string);
774 Tcl_DStringEndSublist(&dString);
777 result = Tcl_DStringValue(&dString);
778 if (result == dString.staticSpace) {
779 result = Blt_Strdup(result);
781 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
786 *----------------------------------------------------------------------
790 * Creates an array of style indices and fills it based on the weight
791 * of each data point.
797 * Memory is freed and allocated for the index array.
799 *----------------------------------------------------------------------
803 Blt_StyleMap(elemPtr)
807 int nWeights; /* Number of weights to be examined.
808 * If there are more data points than
809 * weights, they will default to the
812 PenStyle **dataToStyle; /* Directory of styles. Each array
813 * element represents the style for
814 * the data point at that index */
815 Blt_ChainLink *linkPtr;
817 double *w; /* Weight vector */
820 nPoints = NumberOfPoints(elemPtr);
821 nWeights = MIN(elemPtr->w.nValues, nPoints);
822 w = elemPtr->w.valueArr;
823 linkPtr = Blt_ChainFirstLink(elemPtr->palette);
824 stylePtr = Blt_ChainGetValue(linkPtr);
827 * Create a style mapping array (data point index to style),
828 * initialized to the default style.
830 dataToStyle = Blt_Malloc(nPoints * sizeof(PenStyle *));
832 for (i = 0; i < nPoints; i++) {
833 dataToStyle[i] = stylePtr;
836 for (i = 0; i < nWeights; i++) {
837 for (linkPtr = Blt_ChainLastLink(elemPtr->palette); linkPtr != NULL;
838 linkPtr = Blt_ChainPrevLink(linkPtr)) {
839 stylePtr = Blt_ChainGetValue(linkPtr);
841 if (stylePtr->weight.range > 0.0) {
844 norm = (w[i] - stylePtr->weight.min) / stylePtr->weight.range;
845 if (((norm - 1.0) <= DBL_EPSILON) &&
846 (((1.0 - norm) - 1.0) <= DBL_EPSILON)) {
847 dataToStyle[i] = stylePtr;
848 break; /* Done: found range that matches. */
858 *----------------------------------------------------------------------
860 * Blt_MapErrorBars --
862 * Creates two arrays of points and pen indices, filled with
863 * the screen coordinates of the visible
869 * Memory is freed and allocated for the index array.
871 *----------------------------------------------------------------------
874 Blt_MapErrorBars(graphPtr, elemPtr, dataToStyle)
877 PenStyle **dataToStyle;
883 Blt_GraphExtents(graphPtr, &exts);
884 nPoints = NumberOfPoints(elemPtr);
885 if (elemPtr->xError.nValues > 0) {
886 n = MIN(elemPtr->xError.nValues, nPoints);
888 n = MIN3(elemPtr->xHigh.nValues, elemPtr->xLow.nValues, nPoints);
891 Segment2D *errorBars;
899 segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D));
900 indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int));
901 for (i = 0; i < n; i++) {
902 x = elemPtr->x.valueArr[i];
903 y = elemPtr->y.valueArr[i];
904 stylePtr = dataToStyle[i];
905 if ((FINITE(x)) && (FINITE(y))) {
906 if (elemPtr->xError.nValues > 0) {
907 high = x + elemPtr->xError.valueArr[i];
908 low = x - elemPtr->xError.valueArr[i];
910 high = elemPtr->xHigh.valueArr[i];
911 low = elemPtr->xLow.valueArr[i];
913 if ((FINITE(high)) && (FINITE(low))) {
916 p = Blt_Map2D(graphPtr, high, y, &elemPtr->axes);
917 q = Blt_Map2D(graphPtr, low, y, &elemPtr->axes);
920 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
925 segPtr->p.x = segPtr->q.x = p.x;
926 segPtr->p.y = p.y - stylePtr->errorBarCapWidth;
927 segPtr->q.y = p.y + stylePtr->errorBarCapWidth;
928 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
933 segPtr->p.x = segPtr->q.x = q.x;
934 segPtr->p.y = q.y - stylePtr->errorBarCapWidth;
935 segPtr->q.y = q.y + stylePtr->errorBarCapWidth;
936 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
943 elemPtr->xErrorBars = errorBars;
944 elemPtr->xErrorBarCnt = segPtr - errorBars;
945 elemPtr->xErrorToData = errorToData;
947 if (elemPtr->yError.nValues > 0) {
948 n = MIN(elemPtr->yError.nValues, nPoints);
950 n = MIN3(elemPtr->yHigh.nValues, elemPtr->yLow.nValues, nPoints);
953 Segment2D *errorBars;
961 segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D));
962 indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int));
963 for (i = 0; i < n; i++) {
964 x = elemPtr->x.valueArr[i];
965 y = elemPtr->y.valueArr[i];
966 stylePtr = dataToStyle[i];
967 if ((FINITE(x)) && (FINITE(y))) {
968 if (elemPtr->yError.nValues > 0) {
969 high = y + elemPtr->yError.valueArr[i];
970 low = y - elemPtr->yError.valueArr[i];
972 high = elemPtr->yHigh.valueArr[i];
973 low = elemPtr->yLow.valueArr[i];
975 if ((FINITE(high)) && (FINITE(low))) {
978 p = Blt_Map2D(graphPtr, x, high, &elemPtr->axes);
979 q = Blt_Map2D(graphPtr, x, low, &elemPtr->axes);
982 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
987 segPtr->p.y = segPtr->q.y = p.y;
988 segPtr->p.x = p.x - stylePtr->errorBarCapWidth;
989 segPtr->q.x = p.x + stylePtr->errorBarCapWidth;
990 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
995 segPtr->p.y = segPtr->q.y = q.y;
996 segPtr->p.x = q.x - stylePtr->errorBarCapWidth;
997 segPtr->q.x = q.x + stylePtr->errorBarCapWidth;
998 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
1005 elemPtr->yErrorBars = errorBars;
1006 elemPtr->yErrorBarCnt = segPtr - errorBars;
1007 elemPtr->yErrorToData = errorToData;
1013 *----------------------------------------------------------------------
1017 * Given a string representing the index of a pair of x,y
1018 * coordinates, return the numeric index.
1021 * A standard TCL result.
1023 *----------------------------------------------------------------------
1026 GetIndex(interp, elemPtr, string, indexPtr)
1035 last = NumberOfPoints(elemPtr) - 1;
1036 if ((*string == 'e') && (strcmp("end", string) == 0)) {
1038 } else if (Tcl_ExprLong(interp, string, &ielem) != TCL_OK) {
1041 *indexPtr = (int)ielem;
1046 *----------------------------------------------------------------------
1050 * Find the element represented the given name, returning
1051 * a pointer to its data structure via elemPtrPtr.
1054 * A standard TCL result.
1056 *----------------------------------------------------------------------
1059 NameToElement(graphPtr, name, elemPtrPtr)
1062 Element **elemPtrPtr;
1064 Blt_HashEntry *hPtr;
1069 hPtr = Blt_FindHashEntry(&graphPtr->elements.table, name);
1071 Tcl_AppendResult(graphPtr->interp, "can't find element \"", name,
1072 "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL);
1075 *elemPtrPtr = (Element *)Blt_GetHashValue(hPtr);
1080 *----------------------------------------------------------------------
1084 * Add a new element to the graph.
1087 * The return value is a standard Tcl result.
1089 *----------------------------------------------------------------------
1092 DestroyElement(graphPtr, elemPtr)
1096 Blt_ChainLink *linkPtr;
1098 Blt_DeleteBindings(graphPtr->bindTable, elemPtr);
1099 Blt_LegendRemoveElement(graphPtr->legend, elemPtr);
1101 Tk_FreeOptions(elemPtr->specsPtr, (char *)elemPtr, graphPtr->display, 0);
1103 * Call the element's own destructor to release the memory and
1104 * resources allocated for it.
1106 (*elemPtr->procsPtr->destroyProc) (graphPtr, elemPtr);
1108 /* Remove it also from the element display list */
1109 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1110 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1111 if (elemPtr == Blt_ChainGetValue(linkPtr)) {
1112 Blt_ChainDeleteLink(graphPtr->elements.displayList, linkPtr);
1113 if (!elemPtr->hidden) {
1114 graphPtr->flags |= RESET_WORLD;
1115 Blt_EventuallyRedrawGraph(graphPtr);
1120 /* Remove the element for the graph's hash table of elements */
1121 if (elemPtr->hashPtr != NULL) {
1122 Blt_DeleteHashEntry(&graphPtr->elements.table, elemPtr->hashPtr);
1124 if (elemPtr->name != NULL) {
1125 Blt_Free(elemPtr->name);
1131 *----------------------------------------------------------------------
1135 * Add a new element to the graph.
1138 * The return value is a standard Tcl result.
1140 *----------------------------------------------------------------------
1143 CreateElement(graphPtr, interp, argc, argv, classUid)
1151 Blt_HashEntry *hPtr;
1154 if (argv[3][0] == '-') {
1155 Tcl_AppendResult(graphPtr->interp, "name of element \"", argv[3],
1156 "\" can't start with a '-'", (char *)NULL);
1159 hPtr = Blt_CreateHashEntry(&graphPtr->elements.table, argv[3], &isNew);
1161 Tcl_AppendResult(interp, "element \"", argv[3],
1162 "\" already exists in \"", argv[0], "\"", (char *)NULL);
1165 if (classUid == bltBarElementUid) {
1166 elemPtr = Blt_BarElement(graphPtr, argv[3], classUid);
1168 /* Stripcharts are line graphs with some options enabled. */
1169 elemPtr = Blt_LineElement(graphPtr, argv[3], classUid);
1171 elemPtr->hashPtr = hPtr;
1172 Blt_SetHashValue(hPtr, elemPtr);
1174 if (Blt_ConfigureWidgetComponent(interp, graphPtr->tkwin, elemPtr->name,
1175 "Element", elemPtr->specsPtr, argc - 4, argv + 4,
1176 (char *)elemPtr, 0) != TCL_OK) {
1177 DestroyElement(graphPtr, elemPtr);
1180 (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr);
1181 Blt_ChainPrepend(graphPtr->elements.displayList, elemPtr);
1183 if (!elemPtr->hidden) {
1184 /* If the new element isn't hidden then redraw the graph. */
1185 graphPtr->flags |= REDRAW_BACKING_STORE;
1186 Blt_EventuallyRedrawGraph(graphPtr);
1188 elemPtr->flags |= MAP_ITEM;
1189 graphPtr->flags |= RESET_AXES;
1190 Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE);
1195 *----------------------------------------------------------------------
1197 * RebuildDisplayList --
1199 * Given a Tcl list of element names, this procedure rebuilds the
1200 * display list, ignoring invalid element names. This list describes
1201 * not only only which elements to draw, but in what order. This is
1202 * only important for bar and pie charts.
1205 * The return value is a standard Tcl result. Only if the Tcl list
1206 * can not be split, a TCL_ERROR is returned and interp->result contains
1210 * The graph is eventually redrawn using the new display list.
1212 *----------------------------------------------------------------------
1215 RebuildDisplayList(graphPtr, newList)
1216 Graph *graphPtr; /* Graph widget record */
1217 char *newList; /* Tcl list of element names */
1219 int nNames; /* Number of names found in Tcl name list */
1220 char **nameArr; /* Broken out array of element names */
1222 Element *elemPtr; /* Element information record */
1224 if (Tcl_SplitList(graphPtr->interp, newList, &nNames, &nameArr) != TCL_OK) {
1225 Tcl_AppendResult(graphPtr->interp, "can't split name list \"", newList,
1226 "\"", (char *)NULL);
1229 /* Clear the display list and mark all elements as hidden. */
1230 Blt_ChainReset(graphPtr->elements.displayList);
1232 /* Rebuild the display list, checking that each name it exists
1233 * (currently ignoring invalid element names). */
1234 for (i = 0; i < nNames; i++) {
1235 if (NameToElement(graphPtr, nameArr[i], &elemPtr) == TCL_OK) {
1236 Blt_ChainAppend(graphPtr->elements.displayList, elemPtr);
1240 graphPtr->flags |= RESET_WORLD;
1241 Blt_EventuallyRedrawGraph(graphPtr);
1242 Tcl_ResetResult(graphPtr->interp);
1247 *----------------------------------------------------------------------
1249 * Blt_DestroyElements --
1251 * Removes all the graph's elements. This routine is called when
1252 * the graph is destroyed.
1258 * Memory allocated for the graph's elements is freed.
1260 *----------------------------------------------------------------------
1263 Blt_DestroyElements(graphPtr)
1266 Blt_HashEntry *hPtr;
1267 Blt_HashSearch cursor;
1270 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
1271 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1272 elemPtr = (Element *)Blt_GetHashValue(hPtr);
1273 elemPtr->hashPtr = NULL;
1274 DestroyElement(graphPtr, elemPtr);
1276 Blt_DeleteHashTable(&graphPtr->elements.table);
1277 Blt_DeleteHashTable(&graphPtr->elements.tagTable);
1278 Blt_ChainDestroy(graphPtr->elements.displayList);
1282 Blt_MapElements(graphPtr)
1286 Blt_ChainLink *linkPtr;
1288 if (graphPtr->mode != MODE_INFRONT) {
1289 Blt_ResetStacks(graphPtr);
1291 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1292 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1293 elemPtr = Blt_ChainGetValue(linkPtr);
1294 if (elemPtr->hidden) {
1297 if ((graphPtr->flags & MAP_ALL) || (elemPtr->flags & MAP_ITEM)) {
1298 (*elemPtr->procsPtr->mapProc) (graphPtr, elemPtr);
1299 elemPtr->flags &= ~MAP_ITEM;
1305 * -----------------------------------------------------------------
1307 * Blt_DrawElements --
1309 * Calls the individual element drawing routines for each
1316 * Elements are drawn into the drawable (pixmap) which will
1317 * eventually be displayed in the graph window.
1319 * -----------------------------------------------------------------
1322 Blt_DrawElements(graphPtr, drawable)
1324 Drawable drawable; /* Pixmap or window to draw into */
1326 Blt_ChainLink *linkPtr;
1329 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1330 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1331 elemPtr = Blt_ChainGetValue(linkPtr);
1332 if (!elemPtr->hidden) {
1333 (*elemPtr->procsPtr->drawNormalProc) (graphPtr, drawable, elemPtr);
1339 * -----------------------------------------------------------------
1341 * Blt_DrawActiveElements --
1343 * Calls the individual element drawing routines to display
1344 * the active colors for each element.
1350 * Elements are drawn into the drawable (pixmap) which will
1351 * eventually be displayed in the graph window.
1353 * -----------------------------------------------------------------
1356 Blt_DrawActiveElements(graphPtr, drawable)
1358 Drawable drawable; /* Pixmap or window to draw into */
1360 Blt_ChainLink *linkPtr;
1363 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1364 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1365 elemPtr = Blt_ChainGetValue(linkPtr);
1366 if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) {
1367 (*elemPtr->procsPtr->drawActiveProc) (graphPtr, drawable, elemPtr);
1373 * -----------------------------------------------------------------
1375 * Blt_ElementsToPostScript --
1377 * Generates PostScript output for each graph element in the
1378 * element display list.
1380 * -----------------------------------------------------------------
1383 Blt_ElementsToPostScript(graphPtr, psToken)
1387 Blt_ChainLink *linkPtr;
1390 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1391 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1392 elemPtr = Blt_ChainGetValue(linkPtr);
1393 if (!elemPtr->hidden) {
1394 /* Comment the PostScript to indicate the start of the element */
1395 Blt_FormatToPostScript(psToken, "\n%% Element \"%s\"\n\n",
1397 (*elemPtr->procsPtr->printNormalProc) (graphPtr, psToken, elemPtr);
1403 * -----------------------------------------------------------------
1405 * Blt_ActiveElementsToPostScript --
1407 * -----------------------------------------------------------------
1410 Blt_ActiveElementsToPostScript(graphPtr, psToken)
1414 Blt_ChainLink *linkPtr;
1417 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1418 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1419 elemPtr = Blt_ChainGetValue(linkPtr);
1420 if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) {
1421 Blt_FormatToPostScript(psToken, "\n%% Active Element \"%s\"\n\n",
1423 (*elemPtr->procsPtr->printActiveProc) (graphPtr, psToken, elemPtr);
1429 Blt_GraphUpdateNeeded(graphPtr)
1432 Blt_ChainLink *linkPtr;
1435 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1436 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1437 elemPtr = Blt_ChainGetValue(linkPtr);
1438 if (elemPtr->hidden) {
1441 /* Check if the x or y vectors have notifications pending */
1442 if ((Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1443 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1452 *----------------------------------------------------------------------
1456 * Marks data points of elements (given by their index) as active.
1459 * Returns TCL_OK if no errors occurred.
1461 *----------------------------------------------------------------------
1464 ActivateOp(graphPtr, interp, argc, argv)
1465 Graph *graphPtr; /* Graph widget */
1466 Tcl_Interp *interp; /* Interpreter to report errors to */
1467 int argc; /* Number of element names */
1468 char **argv; /* List of element names */
1476 register Blt_HashEntry *hPtr;
1477 Blt_HashSearch cursor;
1479 /* List all the currently active elements */
1480 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
1481 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1482 elemPtr = (Element *)Blt_GetHashValue(hPtr);
1483 if (elemPtr->flags & ELEM_ACTIVE) {
1484 Tcl_AppendElement(graphPtr->interp, elemPtr->name);
1489 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
1490 return TCL_ERROR; /* Can't find named element */
1492 elemPtr->flags |= ELEM_ACTIVE | ACTIVE_PENDING;
1495 nActiveIndices = -1;
1497 register int *activePtr;
1499 nActiveIndices = argc - 4;
1500 activePtr = activeArr = Blt_Malloc(sizeof(int) * nActiveIndices);
1502 for (i = 4; i < argc; i++) {
1503 if (GetIndex(interp, elemPtr, argv[i], activePtr) != TCL_OK) {
1509 if (elemPtr->activeIndices != NULL) {
1510 Blt_Free(elemPtr->activeIndices);
1512 elemPtr->nActiveIndices = nActiveIndices;
1513 elemPtr->activeIndices = activeArr;
1514 Blt_EventuallyRedrawGraph(graphPtr);
1519 Blt_MakeElementTag(graphPtr, tagName)
1523 Blt_HashEntry *hPtr;
1526 hPtr = Blt_CreateHashEntry(&graphPtr->elements.tagTable, tagName, &isNew);
1528 return Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr);
1532 *----------------------------------------------------------------------
1536 * .g element bind elemName sequence command
1538 *----------------------------------------------------------------------
1542 BindOp(graphPtr, interp, argc, argv)
1549 Blt_HashEntry *hPtr;
1550 Blt_HashSearch cursor;
1553 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.tagTable, &cursor);
1554 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1555 tagName = Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr);
1556 Tcl_AppendElement(interp, tagName);
1560 return Blt_ConfigureBindings(interp, graphPtr->bindTable,
1561 Blt_MakeElementTag(graphPtr, argv[3]), argc - 4, argv + 4);
1565 *----------------------------------------------------------------------
1569 * Add a new element to the graph (using the default type of the
1573 * The return value is a standard Tcl result.
1575 *----------------------------------------------------------------------
1578 CreateOp(graphPtr, interp, argc, argv, type)
1585 return CreateElement(graphPtr, interp, argc, argv, type);
1589 *----------------------------------------------------------------------
1593 *----------------------------------------------------------------------
1597 CgetOp(graphPtr, interp, argc, argv)
1605 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
1606 return TCL_ERROR; /* Can't find named element */
1608 if (Tk_ConfigureValue(interp, graphPtr->tkwin, elemPtr->specsPtr,
1609 (char *)elemPtr, argv[4], 0) != TCL_OK) {
1616 *----------------------------------------------------------------------
1620 * Find the element closest to the specified screen coordinates.
1622 * -halo Consider points only with this maximum distance
1623 * from the picked coordinate.
1624 * -interpolate Find closest point along element traces, not just
1629 * A standard Tcl result. If an element could be found within
1630 * the halo distance, the interpreter result is "1", otherwise
1631 * "0". If a closest element exists, the designated Tcl array
1632 * variable will be set with the following information:
1634 * 1) the element name,
1635 * 2) the index of the closest point,
1636 * 3) the distance (in screen coordinates) from the picked X-Y
1637 * coordinate and the closest point,
1638 * 4) the X coordinate (graph coordinate) of the closest point,
1639 * 5) and the Y-coordinate.
1641 *----------------------------------------------------------------------
1644 static Tk_ConfigSpec closestSpecs[] =
1646 {TK_CONFIG_CUSTOM, "-halo", (char *)NULL, (char *)NULL,
1647 (char *)NULL, Tk_Offset(ClosestSearch, halo), 0, &bltDistanceOption},
1648 {TK_CONFIG_BOOLEAN, "-interpolate", (char *)NULL, (char *)NULL,
1649 (char *)NULL, Tk_Offset(ClosestSearch, mode), 0 },
1650 {TK_CONFIG_CUSTOM, "-along", (char *)NULL, (char *)NULL,
1651 (char *)NULL, Tk_Offset(ClosestSearch, along), 0, &alongOption},
1652 {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
1657 ClosestOp(graphPtr, interp, argc, argv)
1658 Graph *graphPtr; /* Graph widget */
1659 Tcl_Interp *interp; /* Interpreter to report results to */
1660 int argc; /* Number of element names */
1661 char **argv; /* List of element names */
1664 ClosestSearch search;
1666 int flags = TCL_LEAVE_ERR_MSG;
1668 if (graphPtr->flags & RESET_AXES) {
1669 Blt_ResetAxes(graphPtr);
1671 if (Tk_GetPixels(interp, graphPtr->tkwin, argv[3], &x) != TCL_OK) {
1672 Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL);
1675 if (Tk_GetPixels(interp, graphPtr->tkwin, argv[4], &y) != TCL_OK) {
1676 Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL);
1679 if (graphPtr->inverted) {
1682 temp = x, x = y, y = temp;
1684 for (i = 6; i < argc; i += 2) { /* Count switches-value pairs */
1685 if ((argv[i][0] != '-') ||
1686 ((argv[i][1] == '-') && (argv[i][2] == '\0'))) {
1694 search.mode = SEARCH_POINTS;
1695 search.halo = graphPtr->halo;
1697 search.along = SEARCH_BOTH;
1701 if (Tk_ConfigureWidget(interp, graphPtr->tkwin, closestSpecs, i - 6,
1702 argv + 6, (char *)&search, TK_CONFIG_ARGV_ONLY) != TCL_OK) {
1703 return TCL_ERROR; /* Error occurred processing an option. */
1705 if ((i < argc) && (argv[i][0] == '-')) {
1706 i++; /* Skip "--" */
1708 search.dist = (double)(search.halo + 1);
1712 for ( /* empty */ ; i < argc; i++) {
1713 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1714 return TCL_ERROR; /* Can't find named element */
1716 if (elemPtr->hidden) {
1717 Tcl_AppendResult(interp, "element \"", argv[i],
1718 "\" is hidden", (char *)NULL);
1719 return TCL_ERROR; /* Element isn't visible */
1722 /* Check if the X or Y vectors have notifications pending */
1723 if ((elemPtr->flags & MAP_ITEM) ||
1724 (Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1725 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1728 (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search);
1731 Blt_ChainLink *linkPtr;
1734 * Find the closest point from the set of displayed elements,
1735 * searching the display list from back to front. That way if
1736 * the points from two different elements overlay each other
1737 * exactly, the last one picked will be the topmost.
1739 for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList);
1740 linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) {
1741 elemPtr = Blt_ChainGetValue(linkPtr);
1742 /* Check if the X or Y vectors have notifications pending */
1743 if ((elemPtr->hidden) ||
1744 (elemPtr->flags & MAP_ITEM) ||
1745 (Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1746 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1749 (*elemPtr->procsPtr->closestProc)(graphPtr, elemPtr, &search);
1753 if (search.dist < (double)search.halo) {
1756 * Return an array of 5 elements
1758 if (Tcl_SetVar2(interp, argv[5], "name",
1759 search.elemPtr->name, flags) == NULL) {
1762 sprintf(string, "%d", search.index);
1763 if (Tcl_SetVar2(interp, argv[5], "index", string, flags) == NULL) {
1766 Tcl_PrintDouble(interp, search.point.x, string);
1767 if (Tcl_SetVar2(interp, argv[5], "x", string, flags) == NULL) {
1770 Tcl_PrintDouble(interp, search.point.y, string);
1771 if (Tcl_SetVar2(interp, argv[5], "y", string, flags) == NULL) {
1774 Tcl_PrintDouble(interp, search.dist, string);
1775 if (Tcl_SetVar2(interp, argv[5], "dist", string, flags) == NULL) {
1778 Tcl_SetResult(interp, "1", TCL_STATIC);
1780 if (Tcl_SetVar2(interp, argv[5], "name", "", flags) == NULL) {
1783 Tcl_SetResult(interp, "0", TCL_STATIC);
1789 *----------------------------------------------------------------------
1793 * Sets the element specifications by the given the command line
1794 * arguments and calls the element specification configuration
1795 * routine. If zero or one command line options are given, only
1796 * information about the option(s) is returned in interp->result.
1797 * If the element configuration has changed and the element is
1798 * currently displayed, the axis limits are updated and
1802 * The return value is a standard Tcl result.
1805 * Graph will be redrawn to reflect the new display list.
1807 *----------------------------------------------------------------------
1810 ConfigureOp(graphPtr, interp, argc, argv)
1818 int numNames, numOpts;
1822 /* Figure out where the option value pairs begin */
1825 for (i = 0; i < argc; i++) {
1826 if (argv[i][0] == '-') {
1829 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1830 return TCL_ERROR; /* Can't find named element */
1833 numNames = i; /* Number of element names specified */
1834 numOpts = argc - i; /* Number of options specified */
1835 options = argv + numNames; /* Start of options in argv */
1837 for (i = 0; i < numNames; i++) {
1838 NameToElement(graphPtr, argv[i], &elemPtr);
1839 flags = TK_CONFIG_ARGV_ONLY;
1841 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
1842 elemPtr->specsPtr, (char *)elemPtr, (char *)NULL, flags);
1843 } else if (numOpts == 1) {
1844 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
1845 elemPtr->specsPtr, (char *)elemPtr, options[0], flags);
1847 if (Tk_ConfigureWidget(interp, graphPtr->tkwin, elemPtr->specsPtr,
1848 numOpts, options, (char *)elemPtr, flags) != TCL_OK) {
1851 if ((*elemPtr->procsPtr->configProc) (graphPtr, elemPtr) != TCL_OK) {
1852 return TCL_ERROR; /* Failed to configure element */
1854 if (Blt_ConfigModified(elemPtr->specsPtr, graphPtr->interp, "-hide", (char *)NULL)) {
1855 graphPtr->flags |= RESET_AXES;
1856 elemPtr->flags |= MAP_ITEM;
1858 /* If data points or axes have changed, reset the axes (may
1859 * affect autoscaling) and recalculate the screen points of
1862 if (Blt_ConfigModified(elemPtr->specsPtr, graphPtr->interp, "-*data", "-map*", "-x",
1863 "-y", (char *)NULL)) {
1864 graphPtr->flags |= RESET_WORLD;
1865 elemPtr->flags |= MAP_ITEM;
1867 /* The new label may change the size of the legend */
1868 if (Blt_ConfigModified(elemPtr->specsPtr, graphPtr->interp, "-label", (char *)NULL)) {
1869 graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD);
1872 /* Update the pixmap if any configuration option changed */
1873 graphPtr->flags |= (REDRAW_BACKING_STORE | DRAW_MARGINS);
1874 Blt_EventuallyRedrawGraph(graphPtr);
1879 *----------------------------------------------------------------------
1883 * Clears the active bit for the named elements.
1886 * Returns TCL_OK if no errors occurred.
1888 *----------------------------------------------------------------------
1892 DeactivateOp(graphPtr, interp, argc, argv)
1893 Graph *graphPtr; /* Graph widget */
1894 Tcl_Interp *interp; /* Not used. */
1895 int argc; /* Number of element names */
1896 char **argv; /* List of element names */
1901 for (i = 3; i < argc; i++) {
1902 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1903 return TCL_ERROR; /* Can't find named element */
1905 elemPtr->flags &= ~ELEM_ACTIVE;
1906 if (elemPtr->activeIndices != NULL) {
1907 Blt_Free(elemPtr->activeIndices);
1908 elemPtr->activeIndices = NULL;
1910 elemPtr->nActiveIndices = 0;
1912 Blt_EventuallyRedrawGraph(graphPtr);
1917 *----------------------------------------------------------------------
1921 * Delete the named elements from the graph.
1924 * TCL_ERROR is returned if any of the named elements can not be
1925 * found. Otherwise TCL_OK is returned;
1928 * If the element is currently displayed, the plotting area of
1929 * the graph is redrawn. Memory and resources allocated by the
1930 * elements are released.
1932 *----------------------------------------------------------------------
1936 DeleteOp(graphPtr, interp, argc, argv)
1937 Graph *graphPtr; /* Graph widget */
1938 Tcl_Interp *interp; /* Not used. */
1939 int argc; /* Number of element names */
1940 char **argv; /* List of element names */
1945 for (i = 3; i < argc; i++) {
1946 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1947 return TCL_ERROR; /* Can't find named element */
1949 DestroyElement(graphPtr, elemPtr);
1951 Blt_EventuallyRedrawGraph(graphPtr);
1956 *----------------------------------------------------------------------
1960 * Indicates if the named element exists in the graph.
1963 * The return value is a standard Tcl result. The interpreter
1964 * result will contain "1" or "0".
1966 *----------------------------------------------------------------------
1970 ExistsOp(graphPtr, interp, argc, argv)
1973 int argc; /* Not used. */
1976 Blt_HashEntry *hPtr;
1978 hPtr = Blt_FindHashEntry(&graphPtr->elements.table, argv[3]);
1979 Blt_SetBooleanResult(interp, (hPtr != NULL));
1984 *----------------------------------------------------------------------
1988 * Returns the name of the picked element (using the element
1989 * bind operation). Right now, the only name accepted is
1993 * A standard Tcl result. The interpreter result will contain
1994 * the name of the element.
1996 *----------------------------------------------------------------------
2000 GetOp(graphPtr, interp, argc, argv)
2003 int argc; /* Not used. */
2006 register Element *elemPtr;
2008 if ((argv[3][0] == 'c') && (strcmp(argv[3], "current") == 0)) {
2009 elemPtr = (Element *)Blt_GetCurrentItem(graphPtr->bindTable);
2010 /* Report only on elements. */
2011 if ((elemPtr != NULL) &&
2012 ((elemPtr->classUid == bltBarElementUid) ||
2013 (elemPtr->classUid == bltLineElementUid) ||
2014 (elemPtr->classUid == bltStripElementUid))) {
2015 Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE);
2022 *----------------------------------------------------------------------
2026 * Returns the names of the elements is the graph matching
2027 * one of more patterns provided. If no pattern arguments
2028 * are given, then all element names will be returned.
2031 * The return value is a standard Tcl result. The interpreter
2032 * result will contain a Tcl list of the element names.
2034 *----------------------------------------------------------------------
2037 NamesOp(graphPtr, interp, argc, argv)
2044 Blt_HashSearch cursor;
2045 register Blt_HashEntry *hPtr;
2048 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
2049 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
2050 elemPtr = (Element *)Blt_GetHashValue(hPtr);
2052 Tcl_AppendElement(graphPtr->interp, elemPtr->name);
2055 for (i = 3; i < argc; i++) {
2056 if (Tcl_StringMatch(elemPtr->name, argv[i])) {
2057 Tcl_AppendElement(interp, elemPtr->name);
2066 *----------------------------------------------------------------------
2070 * Queries or resets the element display list.
2073 * The return value is a standard Tcl result. The interpreter
2074 * result will contain the new display list of element names.
2076 *----------------------------------------------------------------------
2079 ShowOp(graphPtr, interp, argc, argv)
2086 Blt_ChainLink *linkPtr;
2089 if (RebuildDisplayList(graphPtr, argv[3]) != TCL_OK) {
2093 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
2094 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2095 elemPtr = Blt_ChainGetValue(linkPtr);
2096 Tcl_AppendElement(interp, elemPtr->name);
2102 *----------------------------------------------------------------------
2106 * Returns the name of the type of the element given by some
2110 * A standard Tcl result. Returns the type of the element in
2111 * interp->result. If the identifier given doesn't represent an
2112 * element, then an error message is left in interp->result.
2114 *----------------------------------------------------------------------
2118 TypeOp(graphPtr, interp, argc, argv)
2119 Graph *graphPtr; /* Graph widget */
2121 int argc; /* Not used. */
2122 char **argv; /* Element name */
2126 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
2127 return TCL_ERROR; /* Can't find named element */
2129 Tcl_SetResult(interp, elemPtr->classUid, TCL_STATIC);
2136 static Blt_OpSpec elemOps[] =
2138 {"activate", 1, (Blt_Op)ActivateOp, 3, 0, "?elemName? ?index...?",},
2139 {"bind", 1, (Blt_Op)BindOp, 3, 6, "elemName sequence command",},
2140 {"cget", 2, (Blt_Op)CgetOp, 5, 5, "elemName option",},
2141 {"closest", 2, (Blt_Op)ClosestOp, 6, 0,
2142 "x y varName ?option value?... ?elemName?...",},
2143 {"configure", 2, (Blt_Op)ConfigureOp, 4, 0,
2144 "elemName ?elemName?... ?option value?...",},
2145 {"create", 2, (Blt_Op)CreateOp, 4, 0, "elemName ?option value?...",},
2146 {"deactivate", 3, (Blt_Op)DeactivateOp, 3, 0, "?elemName?...",},
2147 {"delete", 3, (Blt_Op)DeleteOp, 3, 0, "?elemName?...",},
2148 {"exists", 1, (Blt_Op)ExistsOp, 4, 4, "elemName",},
2149 {"get", 1, (Blt_Op)GetOp, 4, 4, "name",},
2150 {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",},
2151 {"show", 1, (Blt_Op)ShowOp, 3, 4, "?elemList?",},
2152 {"type", 1, (Blt_Op)TypeOp, 4, 4, "elemName",},
2154 static int numElemOps = sizeof(elemOps) / sizeof(Blt_OpSpec);
2158 * ----------------------------------------------------------------
2162 * This procedure is invoked to process the Tcl command that
2163 * corresponds to a widget managed by this module. See the user
2164 * documentation for details on what it does.
2167 * A standard Tcl result.
2170 * See the user documentation.
2172 * ----------------------------------------------------------------
2175 Blt_ElementOp(graphPtr, interp, argc, argv, type)
2176 Graph *graphPtr; /* Graph widget record */
2178 int argc; /* # arguments */
2179 char **argv; /* Argument list */
2185 proc = Blt_GetOp(interp, numElemOps, elemOps, BLT_OP_ARG2, argc, argv, 0);
2189 if (proc == CreateOp) {
2190 result = CreateOp(graphPtr, interp, argc, argv, type);
2192 result = (*proc) (graphPtr, interp, argc, argv);