source: trunk/kitgen/8.x/blt/generic/bltGrElem.c

Last change on this file was 175, checked in by demin, 12 years ago

initial commit

File size: 60.9 KB
Line 
1
2/*
3 * bltGrElem.c --
4 *
5 * This module implements generic elements for the BLT graph widget.
6 *
7 * Copyright 1993-1998 Lucent Technologies, Inc.
8 *
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.
17 *
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
25 * software.
26 */
27
28#include "bltVecInt.h"
29#include "bltGraph.h"
30#include "bltChain.h"
31#include <X11/Xutil.h>
32
33
34static Tk_OptionParseProc StringToData;
35static Tk_OptionPrintProc DataToString;
36static Tk_OptionParseProc StringToDataPairs;
37static Tk_OptionPrintProc DataPairsToString;
38static Tk_OptionParseProc StringToAlong;
39static Tk_OptionPrintProc AlongToString;
40static Tk_CustomOption alongOption =
41{
42 StringToAlong, AlongToString, (ClientData)0
43};
44Tk_CustomOption bltDataOption =
45{
46 StringToData, DataToString, (ClientData)0
47};
48Tk_CustomOption bltDataPairsOption =
49{
50 StringToDataPairs, DataPairsToString, (ClientData)0
51};
52extern Tk_CustomOption bltDistanceOption;
53
54
55
56static int counter;
57
58#include "bltGrElem.h"
59
60extern Element *Blt_BarElement();
61extern Element *Blt_LineElement();
62
63static Blt_VectorChangedProc VectorChangedProc;
64
65EXTERN int Blt_VectorExists2 _ANSI_ARGS_((Tcl_Interp *interp, char *vecName));
66
67/*
68 * ----------------------------------------------------------------------
69 * Custom option parse and print procedures
70 * ----------------------------------------------------------------------
71 */
72static int
73GetPenStyle(graphPtr, string, type, stylePtr)
74 Graph *graphPtr;
75 char *string;
76 Blt_Uid type;
77 PenStyle *stylePtr;
78{
79 Pen *penPtr;
80 Tcl_Interp *interp = graphPtr->interp;
81 char **elemArr;
82 int nElem;
83
84 elemArr = NULL;
85 if (Tcl_SplitList(interp, string, &nElem, &elemArr) != TCL_OK) {
86 return TCL_ERROR;
87 }
88 if ((nElem != 1) && (nElem != 3)) {
89 Tcl_AppendResult(interp, "bad style \"", string, "\": should be ",
90 "\"penName\" or \"penName min max\"", (char *)NULL);
91 if (elemArr != NULL) {
92 Blt_Free(elemArr);
93 }
94 return TCL_ERROR;
95 }
96 if (Blt_GetPen(graphPtr, elemArr[0], type, &penPtr) != TCL_OK) {
97 Blt_Free(elemArr);
98 return TCL_ERROR;
99 }
100 if (nElem == 3) {
101 double min, max;
102
103 if ((Tcl_GetDouble(interp, elemArr[1], &min) != TCL_OK) ||
104 (Tcl_GetDouble(interp, elemArr[2], &max) != TCL_OK)) {
105 Blt_Free(elemArr);
106 return TCL_ERROR;
107 }
108 SetWeight(stylePtr->weight, min, max);
109 }
110 stylePtr->penPtr = penPtr;
111 Blt_Free(elemArr);
112 return TCL_OK;
113}
114
115double
116Blt_VecMin(vecPtr)
117 Blt_Vector *vecPtr;
118{
119 VectorObject *vPtr = (VectorObject *)vecPtr;
120
121 if (!FINITE(vPtr->min)) {
122 double min;
123 register int i;
124
125 min = bltNaN;
126 for (i = 0; i < vPtr->length; i++) {
127 if (FINITE(vPtr->valueArr[i])) {
128 min = vPtr->valueArr[i];
129 break;
130 }
131 }
132 for (/* empty */; i < vPtr->length; i++) {
133 if (FINITE(vPtr->valueArr[i])) {
134 if (min > vPtr->valueArr[i]) {
135 min = vPtr->valueArr[i];
136 }
137 }
138 }
139 vPtr->min = min;
140 }
141 return vPtr->min;
142}
143
144double
145Blt_VecMax(vecPtr)
146 Blt_Vector *vecPtr;
147{
148 VectorObject *vPtr = (VectorObject *)vecPtr;
149
150 if (!FINITE(vPtr->max)) {
151 double max;
152 register int i;
153
154 max = bltNaN;
155 for (i = 0; i < vPtr->length; i++) {
156 if (FINITE(vPtr->valueArr[i])) {
157 max = vPtr->valueArr[i];
158 break;
159 }
160 }
161 for (/* empty */; i < vPtr->length; i++) {
162 if (FINITE(vPtr->valueArr[i])) {
163 if (max < vPtr->valueArr[i]) {
164 max = vPtr->valueArr[i];
165 }
166 }
167 }
168 vPtr->max = max;
169 }
170 return vPtr->max;
171}
172
173static void
174SyncElemVector(vPtr)
175 ElemVector *vPtr;
176{
177 vPtr->nValues = Blt_VecLength(vPtr->vecPtr);
178 vPtr->valueArr = Blt_VecData(vPtr->vecPtr);
179 vPtr->min = Blt_VecMin(vPtr->vecPtr);
180 vPtr->max = Blt_VecMax(vPtr->vecPtr);
181}
182
183/*
184 *----------------------------------------------------------------------
185 *
186 * FindRange --
187 *
188 * Find the minimum, positive minimum, and maximum values in a
189 * given vector and store the results in the vector structure.
190 *
191 * Results:
192 * None.
193 *
194 * Side Effects:
195 * Minimum, positive minimum, and maximum values are stored in
196 * the vector.
197 *
198 *----------------------------------------------------------------------
199 */
200static void
201FindRange(vPtr)
202 ElemVector *vPtr;
203{
204 register int i;
205 register double *x;
206 register double min, max;
207
208 if ((vPtr->nValues < 1) || (vPtr->valueArr == NULL)) {
209 return; /* This shouldn't ever happen. */
210 }
211 x = vPtr->valueArr;
212
213 min = DBL_MAX, max = -DBL_MAX;
214 for(i = 0; i < vPtr->nValues; i++) {
215 if (FINITE(x[i])) {
216 min = max = x[i];
217 break;
218 }
219 }
220 /* Initialize values to track the vector range */
221 for (/* empty */; i < vPtr->nValues; i++) {
222 if (FINITE(x[i])) {
223 if (x[i] < min) {
224 min = x[i];
225 } else if (x[i] > max) {
226 max = x[i];
227 }
228 }
229 }
230 vPtr->min = min, vPtr->max = max;
231}
232
233/*
234 *----------------------------------------------------------------------
235 *
236 * Blt_FindElemVectorMinimum --
237 *
238 * Find the minimum, positive minimum, and maximum values in a
239 * given vector and store the results in the vector structure.
240 *
241 * Results:
242 * None.
243 *
244 * Side Effects:
245 * Minimum, positive minimum, and maximum values are stored in
246 * the vector.
247 *
248 *----------------------------------------------------------------------
249 */
250double
251Blt_FindElemVectorMinimum(vPtr, minLimit)
252 ElemVector *vPtr;
253 double minLimit;
254{
255 register int i;
256 register double *arr;
257 register double min, x;
258
259 min = DBL_MAX;
260 arr = vPtr->valueArr;
261 for (i = 0; i < vPtr->nValues; i++) {
262 x = arr[i];
263 if (x < 0.0) {
264 /* What do you do about negative values when using log
265 * scale values seems like a grey area. Mirror. */
266 x = -x;
267 }
268 if ((x > minLimit) && (min > x)) {
269 min = x;
270 }
271 }
272 if (min == DBL_MAX) {
273 min = minLimit;
274 }
275 return min;
276}
277
278static void
279FreeDataVector(vPtr)
280 ElemVector *vPtr;
281{
282 if (vPtr->clientId != NULL) {
283 Blt_FreeVectorId(vPtr->clientId); /* Free the old vector */
284 vPtr->clientId = NULL;
285 } else if (vPtr->valueArr != NULL) {
286 Blt_Free(vPtr->valueArr);
287 }
288 vPtr->valueArr = NULL;
289 vPtr->nValues = 0;
290}
291
292/*
293 *----------------------------------------------------------------------
294 *
295 * VectorChangedProc --
296 *
297 *
298 * Results:
299 * None.
300 *
301 * Side Effects:
302 * Graph is redrawn.
303 *
304 *----------------------------------------------------------------------
305 */
306static void
307VectorChangedProc(interp, clientData, notify)
308 Tcl_Interp *interp;
309 ClientData clientData;
310 Blt_VectorNotify notify;
311{
312 ElemVector *vPtr = clientData;
313 Element *elemPtr = vPtr->elemPtr;
314 Graph *graphPtr = elemPtr->graphPtr;
315
316 switch (notify) {
317 case BLT_VECTOR_NOTIFY_DESTROY:
318 vPtr->clientId = NULL;
319 vPtr->valueArr = NULL;
320 vPtr->nValues = 0;
321 break;
322
323 case BLT_VECTOR_NOTIFY_UPDATE:
324 default:
325 Blt_GetVectorById(interp, vPtr->clientId, &vPtr->vecPtr);
326 SyncElemVector(vPtr);
327 break;
328 }
329 graphPtr->flags |= RESET_AXES;
330 elemPtr->flags |= MAP_ITEM;
331 if (!elemPtr->hidden) {
332 graphPtr->flags |= REDRAW_BACKING_STORE;
333 Blt_EventuallyRedrawGraph(graphPtr);
334 }
335}
336
337static int
338EvalExprList(interp, list, nElemPtr, arrayPtr)
339 Tcl_Interp *interp;
340 char *list;
341 int *nElemPtr;
342 double **arrayPtr;
343{
344 int nElem;
345 char **elemArr;
346 double *array;
347 int result;
348
349 result = TCL_ERROR;
350 elemArr = NULL;
351 if (Tcl_SplitList(interp, list, &nElem, &elemArr) != TCL_OK) {
352 return TCL_ERROR;
353 }
354 array = NULL;
355 if (nElem > 0) {
356 register double *valuePtr;
357 register int i;
358
359 counter++;
360 array = Blt_Malloc(sizeof(double) * nElem);
361 if (array == NULL) {
362 Tcl_AppendResult(interp, "can't allocate new vector", (char *)NULL);
363 goto badList;
364 }
365 valuePtr = array;
366 for (i = 0; i < nElem; i++) {
367 if (Tcl_ExprDouble(interp, elemArr[i], valuePtr) != TCL_OK) {
368 goto badList;
369 }
370 valuePtr++;
371 }
372 }
373 result = TCL_OK;
374
375 badList:
376 Blt_Free(elemArr);
377 *arrayPtr = array;
378 *nElemPtr = nElem;
379 if (result != TCL_OK) {
380 Blt_Free(array);
381 }
382 return result;
383}
384
385/*
386 *----------------------------------------------------------------------
387 *
388 * StringToData --
389 *
390 * Given a Tcl list of numeric expression representing the element
391 * values, convert into an array of double precision values. In
392 * addition, the minimum and maximum values are saved. Since
393 * elastic values are allow (values which translate to the
394 * min/max of the graph), we must try to get the non-elastic
395 * minimum and maximum.
396 *
397 * Results:
398 * The return value is a standard Tcl result. The vector is passed
399 * back via the vPtr.
400 *
401 *----------------------------------------------------------------------
402 */
403/*ARGSUSED*/
404static int
405StringToData(clientData, interp, tkwin, string, widgRec, offset)
406 ClientData clientData; /* Type of axis vector to fill */
407 Tcl_Interp *interp; /* Interpreter to send results back to */
408 Tk_Window tkwin; /* Not used. */
409 char *string; /* Tcl list of expressions */
410 char *widgRec; /* Element record */
411 int offset; /* Offset of vector in Element record */
412{
413 Element *elemPtr = (Element *)(widgRec);
414 ElemVector *vPtr = (ElemVector *)(widgRec + offset);
415
416 FreeDataVector(vPtr);
417 if (Blt_VectorExists2(interp, string)) {
418 Blt_VectorId clientId;
419
420 clientId = Blt_AllocVectorId(interp, string);
421 if (Blt_GetVectorById(interp, clientId, &vPtr->vecPtr) != TCL_OK) {
422 return TCL_ERROR;
423 }
424 Blt_SetVectorChangedProc(clientId, VectorChangedProc, vPtr);
425 vPtr->elemPtr = elemPtr;
426 vPtr->clientId = clientId;
427 SyncElemVector(vPtr);
428 elemPtr->flags |= MAP_ITEM;
429 } else {
430 double *newArr;
431 int nValues;
432
433 if (EvalExprList(interp, string, &nValues, &newArr) != TCL_OK) {
434 return TCL_ERROR;
435 }
436 if (nValues > 0) {
437 vPtr->valueArr = newArr;
438 }
439 vPtr->nValues = nValues;
440 FindRange(vPtr);
441 }
442 return TCL_OK;
443}
444
445/*
446 *----------------------------------------------------------------------
447 *
448 * DataToString --
449 *
450 * Convert the vector of floating point values into a Tcl list.
451 *
452 * Results:
453 * The string representation of the vector is returned.
454 *
455 *----------------------------------------------------------------------
456 */
457/*ARGSUSED*/
458static char *
459DataToString(clientData, tkwin, widgRec, offset, freeProcPtr)
460 ClientData clientData; /* Type of axis vector to print */
461 Tk_Window tkwin; /* Not used. */
462 char *widgRec; /* Element record */
463 int offset; /* Offset of vector in Element record */
464 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
465{
466 ElemVector *vPtr = (ElemVector *)(widgRec + offset);
467 Element *elemPtr = (Element *)(widgRec);
468 Tcl_DString dString;
469 char *result;
470 char string[TCL_DOUBLE_SPACE + 1];
471 double *p, *endPtr;
472
473 if (vPtr->clientId != NULL) {
474 return Blt_NameOfVectorId(vPtr->clientId);
475 }
476 if (vPtr->nValues == 0) {
477 return "";
478 }
479 Tcl_DStringInit(&dString);
480 endPtr = vPtr->valueArr + vPtr->nValues;
481 for (p = vPtr->valueArr; p < endPtr; p++) {
482 Tcl_PrintDouble(elemPtr->graphPtr->interp, *p, string);
483 Tcl_DStringAppendElement(&dString, string);
484 }
485 result = Tcl_DStringValue(&dString);
486
487 /*
488 * If memory wasn't allocated for the dynamic string, do it here (it's
489 * currently on the stack), so that Tcl can free it normally.
490 */
491 if (result == dString.staticSpace) {
492 result = Blt_Strdup(result);
493 }
494 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
495 return result;
496}
497
498/*
499 *----------------------------------------------------------------------
500 *
501 * StringToDataPairs --
502 *
503 * This procedure is like StringToData except that it interprets
504 * the list of numeric expressions as X Y coordinate pairs. The
505 * minimum and maximum for both the X and Y vectors are
506 * determined.
507 *
508 * Results:
509 * The return value is a standard Tcl result. The vectors are
510 * passed back via the widget record (elemPtr).
511 *
512 *----------------------------------------------------------------------
513 */
514/*ARGSUSED*/
515static int
516StringToDataPairs(clientData, interp, tkwin, string, widgRec, offset)
517 ClientData clientData; /* Not used. */
518 Tcl_Interp *interp; /* Interpreter to send results back to */
519 Tk_Window tkwin; /* Not used. */
520 char *string; /* Tcl list of numeric expressions */
521 char *widgRec; /* Element record */
522 int offset; /* Not used. */
523{
524 Element *elemPtr = (Element *)widgRec;
525 int nElem;
526 unsigned int newSize;
527 double *newArr;
528
529 if (EvalExprList(interp, string, &nElem, &newArr) != TCL_OK) {
530 return TCL_ERROR;
531 }
532 if (nElem & 1) {
533 Tcl_AppendResult(interp, "odd number of data points", (char *)NULL);
534 Blt_Free(newArr);
535 return TCL_ERROR;
536 }
537 nElem /= 2;
538 newSize = nElem * sizeof(double);
539
540 FreeDataVector(&elemPtr->x);
541 FreeDataVector(&elemPtr->y);
542
543 elemPtr->x.valueArr = Blt_Malloc(newSize);
544 elemPtr->y.valueArr = Blt_Malloc(newSize);
545 assert(elemPtr->x.valueArr && elemPtr->y.valueArr);
546 elemPtr->x.nValues = elemPtr->y.nValues = nElem;
547
548 if (newSize > 0) {
549 register double *dataPtr;
550 register int i;
551
552 for (dataPtr = newArr, i = 0; i < nElem; i++) {
553 elemPtr->x.valueArr[i] = *dataPtr++;
554 elemPtr->y.valueArr[i] = *dataPtr++;
555 }
556 Blt_Free(newArr);
557 FindRange(&elemPtr->x);
558 FindRange(&elemPtr->y);
559 }
560 return TCL_OK;
561}
562
563/*
564 *----------------------------------------------------------------------
565 *
566 * DataPairsToString --
567 *
568 * Convert pairs of floating point values in the X and Y arrays
569 * into a Tcl list.
570 *
571 * Results:
572 * The return value is a string (Tcl list).
573 *
574 *----------------------------------------------------------------------
575 */
576/*ARGSUSED*/
577static char *
578DataPairsToString(clientData, tkwin, widgRec, offset, freeProcPtr)
579 ClientData clientData; /* Not used. */
580 Tk_Window tkwin; /* Not used. */
581 char *widgRec; /* Element information record */
582 int offset; /* Not used. */
583 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
584{
585 Element *elemPtr = (Element *)widgRec;
586 Tcl_Interp *interp = elemPtr->graphPtr->interp;
587 int i;
588 int length;
589 char *result;
590 char string[TCL_DOUBLE_SPACE + 1];
591 Tcl_DString dString;
592
593 length = NumberOfPoints(elemPtr);
594 if (length < 1) {
595 return "";
596 }
597 Tcl_DStringInit(&dString);
598 for (i = 0; i < length; i++) {
599 Tcl_PrintDouble(interp, elemPtr->x.valueArr[i], string);
600 Tcl_DStringAppendElement(&dString, string);
601 Tcl_PrintDouble(interp, elemPtr->y.valueArr[i], string);
602 Tcl_DStringAppendElement(&dString, string);
603 }
604 result = Tcl_DStringValue(&dString);
605
606 /*
607 * If memory wasn't allocated for the dynamic string, do it here
608 * (it's currently on the stack), so that Tcl can free it
609 * normally.
610 */
611 if (result == dString.staticSpace) {
612 result = Blt_Strdup(result);
613 }
614 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
615 return result;
616}
617
618/*
619 *----------------------------------------------------------------------
620 *
621 * StringToAlong --
622 *
623 * Given a Tcl list of numeric expression representing the element
624 * values, convert into an array of double precision values. In
625 * addition, the minimum and maximum values are saved. Since
626 * elastic values are allow (values which translate to the
627 * min/max of the graph), we must try to get the non-elastic
628 * minimum and maximum.
629 *
630 * Results:
631 * The return value is a standard Tcl result. The vector is passed
632 * back via the vPtr.
633 *
634 *----------------------------------------------------------------------
635 */
636/*ARGSUSED*/
637static int
638StringToAlong(clientData, interp, tkwin, string, widgRec, offset)
639 ClientData clientData; /* Not used. */
640 Tcl_Interp *interp; /* Interpreter to send results back to */
641 Tk_Window tkwin; /* Not used. */
642 char *string; /* String representation of value. */
643 char *widgRec; /* Widget record. */
644 int offset; /* Offset of field in widget record. */
645{
646 int *intPtr = (int *)(widgRec + offset);
647
648 if ((string[0] == 'x') && (string[1] == '\0')) {
649 *intPtr = SEARCH_X;
650 } else if ((string[0] == 'y') && (string[1] == '\0')) {
651 *intPtr = SEARCH_Y;
652 } else if ((string[0] == 'b') && (strcmp(string, "both") == 0)) {
653 *intPtr = SEARCH_BOTH;
654 } else {
655 Tcl_AppendResult(interp, "bad along value \"", string, "\"",
656 (char *)NULL);
657 return TCL_ERROR;
658 }
659 return TCL_OK;
660}
661
662/*
663 *----------------------------------------------------------------------
664 *
665 * AlongToString --
666 *
667 * Convert the vector of floating point values into a Tcl list.
668 *
669 * Results:
670 * The string representation of the vector is returned.
671 *
672 *----------------------------------------------------------------------
673 */
674/*ARGSUSED*/
675static char *
676AlongToString(clientData, tkwin, widgRec, offset, freeProcPtr)
677 ClientData clientData; /* Not used. */
678 Tk_Window tkwin; /* Not used. */
679 char *widgRec; /* Widget record */
680 int offset; /* Offset of field in widget record */
681 Tcl_FreeProc **freeProcPtr; /* Memory deallocation scheme to use */
682{
683 int along = *(int *)(widgRec + offset);
684
685 switch (along) {
686 case SEARCH_X:
687 return "x";
688 case SEARCH_Y:
689 return "y";
690 case SEARCH_BOTH:
691 return "both";
692 default:
693 return "unknown along value";
694 }
695}
696
697void
698Blt_FreePalette(graphPtr, palette)
699 Graph *graphPtr;
700 Blt_Chain *palette;
701{
702 Blt_ChainLink *linkPtr;
703
704 /* Skip the first slot. It contains the built-in "normal" pen of
705 * the element. */
706 linkPtr = Blt_ChainFirstLink(palette);
707 if (linkPtr != NULL) {
708 register PenStyle *stylePtr;
709 Blt_ChainLink *nextPtr;
710
711 for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL;
712 linkPtr = nextPtr) {
713 nextPtr = Blt_ChainNextLink(linkPtr);
714 stylePtr = Blt_ChainGetValue(linkPtr);
715 Blt_FreePen(graphPtr, stylePtr->penPtr);
716 Blt_ChainDeleteLink(palette, linkPtr);
717 }
718 }
719}
720
721/*
722 *----------------------------------------------------------------------
723 *
724 * Blt_StringToStyles --
725 *
726 * Parse the list of style names.
727 *
728 * Results:
729 * The return value is a standard Tcl result.
730 *
731 *----------------------------------------------------------------------
732 */
733/*ARGSUSED*/
734int
735Blt_StringToStyles(clientData, interp, tkwin, string, widgRec, offset)
736 ClientData clientData; /* Not used. */
737 Tcl_Interp *interp; /* Interpreter to send results back to */
738 Tk_Window tkwin; /* Not used. */
739 char *string; /* String representing style list */
740 char *widgRec; /* Element information record */
741 int offset; /* Offset of symbol type field in record */
742{
743 Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset);
744 Blt_ChainLink *linkPtr;
745 Element *elemPtr = (Element *)(widgRec);
746 PenStyle *stylePtr;
747 char **elemArr;
748 int nStyles;
749 register int i;
750 size_t size = (size_t)clientData;
751
752 elemArr = NULL;
753 Blt_FreePalette(elemPtr->graphPtr, palette);
754 if ((string == NULL) || (*string == '\0')) {
755 nStyles = 0;
756 } else if (Tcl_SplitList(interp, string, &nStyles, &elemArr) != TCL_OK) {
757 return TCL_ERROR;
758 }
759 /* Reserve the first entry for the "normal" pen. We'll set the
760 * style later */
761 linkPtr = Blt_ChainFirstLink(palette);
762 if (linkPtr == NULL) {
763 linkPtr = Blt_ChainAllocLink(size);
764 Blt_ChainLinkBefore(palette, linkPtr, NULL);
765 }
766 stylePtr = Blt_ChainGetValue(linkPtr);
767 stylePtr->penPtr = elemPtr->normalPenPtr;
768
769 for (i = 0; i < nStyles; i++) {
770 linkPtr = Blt_ChainAllocLink(size);
771 stylePtr = Blt_ChainGetValue(linkPtr);
772 stylePtr->weight.min = (double)i;
773 stylePtr->weight.max = (double)i + 1.0;
774 stylePtr->weight.range = 1.0;
775 if (GetPenStyle(elemPtr->graphPtr, elemArr[i], elemPtr->classUid,
776 (PenStyle *)stylePtr) != TCL_OK) {
777 Blt_Free(elemArr);
778 Blt_FreePalette(elemPtr->graphPtr, palette);
779 return TCL_ERROR;
780 }
781 Blt_ChainLinkBefore(palette, linkPtr, NULL);
782 }
783 if (elemArr != NULL) {
784 Blt_Free(elemArr);
785 }
786 return TCL_OK;
787}
788
789/*
790 *----------------------------------------------------------------------
791 *
792 * Blt_StylesToString --
793 *
794 * Convert the style information into a string.
795 *
796 * Results:
797 * The string representing the style information is returned.
798 *
799 *----------------------------------------------------------------------
800 */
801/*ARGSUSED*/
802char *
803Blt_StylesToString(clientData, tkwin, widgRec, offset, freeProcPtr)
804 ClientData clientData; /* Not used. */
805 Tk_Window tkwin; /* Not used. */
806 char *widgRec; /* Element information record */
807 int offset; /* Not used. */
808 Tcl_FreeProc **freeProcPtr; /* Not used. */
809{
810 Blt_Chain *palette = *(Blt_Chain **)(widgRec + offset);
811 Tcl_DString dString;
812 char *result;
813 Blt_ChainLink *linkPtr;
814
815 Tcl_DStringInit(&dString);
816 linkPtr = Blt_ChainFirstLink(palette);
817 if (linkPtr != NULL) {
818 Element *elemPtr = (Element *)(widgRec);
819 char string[TCL_DOUBLE_SPACE];
820 Tcl_Interp *interp;
821 PenStyle *stylePtr;
822
823 interp = elemPtr->graphPtr->interp;
824 for (linkPtr = Blt_ChainNextLink(linkPtr); linkPtr != NULL;
825 linkPtr = Blt_ChainNextLink(linkPtr)) {
826 stylePtr = Blt_ChainGetValue(linkPtr);
827 Tcl_DStringStartSublist(&dString);
828 Tcl_DStringAppendElement(&dString, stylePtr->penPtr->name);
829 Tcl_PrintDouble(interp, stylePtr->weight.min, string);
830 Tcl_DStringAppendElement(&dString, string);
831 Tcl_PrintDouble(interp, stylePtr->weight.max, string);
832 Tcl_DStringAppendElement(&dString, string);
833 Tcl_DStringEndSublist(&dString);
834 }
835 }
836 result = Blt_Strdup(Tcl_DStringValue(&dString));
837 *freeProcPtr = (Tcl_FreeProc *)Blt_Free;
838 return result;
839}
840
841/*
842 *----------------------------------------------------------------------
843 *
844 * Blt_StyleMap --
845 *
846 * Creates an array of style indices and fills it based on the weight
847 * of each data point.
848 *
849 * Results:
850 * None.
851 *
852 * Side effects:
853 * Memory is freed and allocated for the index array.
854 *
855 *----------------------------------------------------------------------
856 */
857
858PenStyle **
859Blt_StyleMap(elemPtr)
860 Element *elemPtr;
861{
862 register int i;
863 int nWeights; /* Number of weights to be examined.
864 * If there are more data points than
865 * weights, they will default to the
866 * normal pen. */
867
868 PenStyle **dataToStyle; /* Directory of styles. Each array
869 * element represents the style for
870 * the data point at that index */
871 Blt_ChainLink *linkPtr;
872 PenStyle *stylePtr;
873 double *w; /* Weight vector */
874 int nPoints;
875
876 nPoints = NumberOfPoints(elemPtr);
877 nWeights = MIN(elemPtr->w.nValues, nPoints);
878 w = elemPtr->w.valueArr;
879 linkPtr = Blt_ChainFirstLink(elemPtr->palette);
880 stylePtr = Blt_ChainGetValue(linkPtr);
881
882 /*
883 * Create a style mapping array (data point index to style),
884 * initialized to the default style.
885 */
886 dataToStyle = Blt_Malloc(nPoints * sizeof(PenStyle *));
887 assert(dataToStyle);
888 for (i = 0; i < nPoints; i++) {
889 dataToStyle[i] = stylePtr;
890 }
891
892 for (i = 0; i < nWeights; i++) {
893 for (linkPtr = Blt_ChainLastLink(elemPtr->palette); linkPtr != NULL;
894 linkPtr = Blt_ChainPrevLink(linkPtr)) {
895 stylePtr = Blt_ChainGetValue(linkPtr);
896
897 if (stylePtr->weight.range > 0.0) {
898 double norm;
899
900 norm = (w[i] - stylePtr->weight.min) / stylePtr->weight.range;
901 if (((norm - 1.0) <= DBL_EPSILON) &&
902 (((1.0 - norm) - 1.0) <= DBL_EPSILON)) {
903 dataToStyle[i] = stylePtr;
904 break; /* Done: found range that matches. */
905 }
906 }
907 }
908 }
909 return dataToStyle;
910}
911
912
913/*
914 *----------------------------------------------------------------------
915 *
916 * Blt_MapErrorBars --
917 *
918 * Creates two arrays of points and pen indices, filled with
919 * the screen coordinates of the visible
920 *
921 * Results:
922 * None.
923 *
924 * Side effects:
925 * Memory is freed and allocated for the index array.
926 *
927 *----------------------------------------------------------------------
928 */
929void
930Blt_MapErrorBars(graphPtr, elemPtr, dataToStyle)
931 Graph *graphPtr;
932 Element *elemPtr;
933 PenStyle **dataToStyle;
934{
935 int n, nPoints;
936 Extents2D exts;
937 PenStyle *stylePtr;
938
939 Blt_GraphExtents(graphPtr, &exts);
940 nPoints = NumberOfPoints(elemPtr);
941 if (elemPtr->xError.nValues > 0) {
942 n = MIN(elemPtr->xError.nValues, nPoints);
943 } else {
944 n = MIN3(elemPtr->xHigh.nValues, elemPtr->xLow.nValues, nPoints);
945 }
946 if (n > 0) {
947 Segment2D *errorBars;
948 Segment2D *segPtr;
949 double high, low;
950 double x, y;
951 int *errorToData;
952 int *indexPtr;
953 register int i;
954
955 segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D));
956 indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int));
957 for (i = 0; i < n; i++) {
958 x = elemPtr->x.valueArr[i];
959 y = elemPtr->y.valueArr[i];
960 stylePtr = dataToStyle[i];
961 if ((FINITE(x)) && (FINITE(y))) {
962 if (elemPtr->xError.nValues > 0) {
963 high = x + elemPtr->xError.valueArr[i];
964 low = x - elemPtr->xError.valueArr[i];
965 } else {
966 high = elemPtr->xHigh.valueArr[i];
967 low = elemPtr->xLow.valueArr[i];
968 }
969 if ((FINITE(high)) && (FINITE(low))) {
970 Point2D p, q;
971
972 p = Blt_Map2D(graphPtr, high, y, &elemPtr->axes);
973 q = Blt_Map2D(graphPtr, low, y, &elemPtr->axes);
974 segPtr->p = p;
975 segPtr->q = q;
976 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
977 segPtr++;
978 *indexPtr++ = i;
979 }
980 /* Left cap */
981 segPtr->p.x = segPtr->q.x = p.x;
982 segPtr->p.y = p.y - stylePtr->errorBarCapWidth;
983 segPtr->q.y = p.y + stylePtr->errorBarCapWidth;
984 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
985 segPtr++;
986 *indexPtr++ = i;
987 }
988 /* Right cap */
989 segPtr->p.x = segPtr->q.x = q.x;
990 segPtr->p.y = q.y - stylePtr->errorBarCapWidth;
991 segPtr->q.y = q.y + stylePtr->errorBarCapWidth;
992 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
993 segPtr++;
994 *indexPtr++ = i;
995 }
996 }
997 }
998 }
999 elemPtr->xErrorBars = errorBars;
1000 elemPtr->xErrorBarCnt = segPtr - errorBars;
1001 elemPtr->xErrorToData = errorToData;
1002 }
1003 if (elemPtr->yError.nValues > 0) {
1004 n = MIN(elemPtr->yError.nValues, nPoints);
1005 } else {
1006 n = MIN3(elemPtr->yHigh.nValues, elemPtr->yLow.nValues, nPoints);
1007 }
1008 if (n > 0) {
1009 Segment2D *errorBars;
1010 Segment2D *segPtr;
1011 double high, low;
1012 double x, y;
1013 int *errorToData;
1014 int *indexPtr;
1015 register int i;
1016
1017 segPtr = errorBars = Blt_Malloc(n * 3 * sizeof(Segment2D));
1018 indexPtr = errorToData = Blt_Malloc(n * 3 * sizeof(int));
1019 for (i = 0; i < n; i++) {
1020 x = elemPtr->x.valueArr[i];
1021 y = elemPtr->y.valueArr[i];
1022 stylePtr = dataToStyle[i];
1023 if ((FINITE(x)) && (FINITE(y))) {
1024 if (elemPtr->yError.nValues > 0) {
1025 high = y + elemPtr->yError.valueArr[i];
1026 low = y - elemPtr->yError.valueArr[i];
1027 } else {
1028 high = elemPtr->yHigh.valueArr[i];
1029 low = elemPtr->yLow.valueArr[i];
1030 }
1031 if ((FINITE(high)) && (FINITE(low))) {
1032 Point2D p, q;
1033
1034 p = Blt_Map2D(graphPtr, x, high, &elemPtr->axes);
1035 q = Blt_Map2D(graphPtr, x, low, &elemPtr->axes);
1036 segPtr->p = p;
1037 segPtr->q = q;
1038 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
1039 segPtr++;
1040 *indexPtr++ = i;
1041 }
1042 /* Top cap. */
1043 segPtr->p.y = segPtr->q.y = p.y;
1044 segPtr->p.x = p.x - stylePtr->errorBarCapWidth;
1045 segPtr->q.x = p.x + stylePtr->errorBarCapWidth;
1046 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
1047 segPtr++;
1048 *indexPtr++ = i;
1049 }
1050 /* Bottom cap. */
1051 segPtr->p.y = segPtr->q.y = q.y;
1052 segPtr->p.x = q.x - stylePtr->errorBarCapWidth;
1053 segPtr->q.x = q.x + stylePtr->errorBarCapWidth;
1054 if (Blt_LineRectClip(&exts, &segPtr->p, &segPtr->q)) {
1055 segPtr++;
1056 *indexPtr++ = i;
1057 }
1058 }
1059 }
1060 }
1061 elemPtr->yErrorBars = errorBars;
1062 elemPtr->yErrorBarCnt = segPtr - errorBars;
1063 elemPtr->yErrorToData = errorToData;
1064 }
1065}
1066
1067
1068/*
1069 *----------------------------------------------------------------------
1070 *
1071 * GetIndex --
1072 *
1073 * Given a string representing the index of a pair of x,y
1074 * coordinates, return the numeric index.
1075 *
1076 * Results:
1077 * A standard TCL result.
1078 *
1079 *----------------------------------------------------------------------
1080 */
1081static int
1082GetIndex(interp, elemPtr, string, indexPtr)
1083 Tcl_Interp *interp;
1084 Element *elemPtr;
1085 char *string;
1086 int *indexPtr;
1087{
1088 long ielem;
1089 int last;
1090
1091 last = NumberOfPoints(elemPtr) - 1;
1092 if ((*string == 'e') && (strcmp("end", string) == 0)) {
1093 ielem = last;
1094 } else if (Tcl_ExprLong(interp, string, &ielem) != TCL_OK) {
1095 return TCL_ERROR;
1096 }
1097 *indexPtr = (int)ielem;
1098 return TCL_OK;
1099}
1100
1101/*
1102 *----------------------------------------------------------------------
1103 *
1104 * NameToElement --
1105 *
1106 * Find the element represented the given name, returning
1107 * a pointer to its data structure via elemPtrPtr.
1108 *
1109 * Results:
1110 * A standard TCL result.
1111 *
1112 *----------------------------------------------------------------------
1113 */
1114static int
1115NameToElement(graphPtr, name, elemPtrPtr)
1116 Graph *graphPtr;
1117 char *name;
1118 Element **elemPtrPtr;
1119{
1120 Blt_HashEntry *hPtr;
1121
1122 if (name == NULL) {
1123 return TCL_ERROR;
1124 }
1125 hPtr = Blt_FindHashEntry(&graphPtr->elements.table, name);
1126 if (hPtr == NULL) {
1127 Tcl_AppendResult(graphPtr->interp, "can't find element \"", name,
1128 "\" in \"", Tk_PathName(graphPtr->tkwin), "\"", (char *)NULL);
1129 return TCL_ERROR;
1130 }
1131 *elemPtrPtr = (Element *)Blt_GetHashValue(hPtr);
1132 return TCL_OK;
1133}
1134
1135/*
1136 *----------------------------------------------------------------------
1137 *
1138 * DestroyElement --
1139 *
1140 * Add a new element to the graph.
1141 *
1142 * Results:
1143 * The return value is a standard Tcl result.
1144 *
1145 *----------------------------------------------------------------------
1146 */
1147static void
1148DestroyElement(graphPtr, elemPtr)
1149 Graph *graphPtr;
1150 Element *elemPtr;
1151{
1152 Blt_ChainLink *linkPtr;
1153
1154 Blt_DeleteBindings(graphPtr->bindTable, elemPtr);
1155 Blt_LegendRemoveElement(graphPtr->legend, elemPtr);
1156
1157 Tk_FreeOptions(elemPtr->specsPtr, (char *)elemPtr, graphPtr->display, 0);
1158 /*
1159 * Call the element's own destructor to release the memory and
1160 * resources allocated for it.
1161 */
1162 (*elemPtr->procsPtr->destroyProc) (graphPtr, elemPtr);
1163
1164 /* Remove it also from the element display list */
1165 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1166 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1167 if (elemPtr == Blt_ChainGetValue(linkPtr)) {
1168 Blt_ChainDeleteLink(graphPtr->elements.displayList, linkPtr);
1169 if (!elemPtr->hidden) {
1170 graphPtr->flags |= RESET_WORLD;
1171 Blt_EventuallyRedrawGraph(graphPtr);
1172 }
1173 break;
1174 }
1175 }
1176 /* Remove the element for the graph's hash table of elements */
1177 if (elemPtr->hashPtr != NULL) {
1178 Blt_DeleteHashEntry(&graphPtr->elements.table, elemPtr->hashPtr);
1179 }
1180 if (elemPtr->name != NULL) {
1181 Blt_Free(elemPtr->name);
1182 }
1183 Blt_Free(elemPtr);
1184}
1185
1186/*
1187 *----------------------------------------------------------------------
1188 *
1189 * CreateElement --
1190 *
1191 * Add a new element to the graph.
1192 *
1193 * Results:
1194 * The return value is a standard Tcl result.
1195 *
1196 *----------------------------------------------------------------------
1197 */
1198static int
1199CreateElement(graphPtr, interp, argc, argv, classUid)
1200 Graph *graphPtr;
1201 Tcl_Interp *interp;
1202 int argc;
1203 char **argv;
1204 Blt_Uid classUid;
1205{
1206 Element *elemPtr;
1207 Blt_HashEntry *hPtr;
1208 int isNew;
1209
1210 if (argv[3][0] == '-') {
1211 Tcl_AppendResult(graphPtr->interp, "name of element \"", argv[3],
1212 "\" can't start with a '-'", (char *)NULL);
1213 return TCL_ERROR;
1214 }
1215 hPtr = Blt_CreateHashEntry(&graphPtr->elements.table, argv[3], &isNew);
1216 if (!isNew) {
1217 Tcl_AppendResult(interp, "element \"", argv[3],
1218 "\" already exists in \"", argv[0], "\"", (char *)NULL);
1219 return TCL_ERROR;
1220 }
1221 if (classUid == bltBarElementUid) {
1222 elemPtr = Blt_BarElement(graphPtr, argv[3], classUid);
1223 } else {
1224 /* Stripcharts are line graphs with some options enabled. */
1225 elemPtr = Blt_LineElement(graphPtr, argv[3], classUid);
1226 }
1227 elemPtr->hashPtr = hPtr;
1228 Blt_SetHashValue(hPtr, elemPtr);
1229
1230 if (Blt_ConfigureWidgetComponent(interp, graphPtr->tkwin, elemPtr->name,
1231 "Element", elemPtr->specsPtr, argc - 4, argv + 4,
1232 (char *)elemPtr, 0) != TCL_OK) {
1233 DestroyElement(graphPtr, elemPtr);
1234 return TCL_ERROR;
1235 }
1236 (*elemPtr->procsPtr->configProc) (graphPtr, elemPtr);
1237 Blt_ChainPrepend(graphPtr->elements.displayList, elemPtr);
1238
1239 if (!elemPtr->hidden) {
1240 /* If the new element isn't hidden then redraw the graph. */
1241 graphPtr->flags |= REDRAW_BACKING_STORE;
1242 Blt_EventuallyRedrawGraph(graphPtr);
1243 }
1244 elemPtr->flags |= MAP_ITEM;
1245 graphPtr->flags |= RESET_AXES;
1246 Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE);
1247 return TCL_OK;
1248}
1249
1250/*
1251 *----------------------------------------------------------------------
1252 *
1253 * RebuildDisplayList --
1254 *
1255 * Given a Tcl list of element names, this procedure rebuilds the
1256 * display list, ignoring invalid element names. This list describes
1257 * not only only which elements to draw, but in what order. This is
1258 * only important for bar and pie charts.
1259 *
1260 * Results:
1261 * The return value is a standard Tcl result. Only if the Tcl list
1262 * can not be split, a TCL_ERROR is returned and interp->result contains
1263 * an error message.
1264 *
1265 * Side effects:
1266 * The graph is eventually redrawn using the new display list.
1267 *
1268 *----------------------------------------------------------------------
1269 */
1270static int
1271RebuildDisplayList(graphPtr, newList)
1272 Graph *graphPtr; /* Graph widget record */
1273 char *newList; /* Tcl list of element names */
1274{
1275 int nNames; /* Number of names found in Tcl name list */
1276 char **nameArr; /* Broken out array of element names */
1277 register int i;
1278 Element *elemPtr; /* Element information record */
1279
1280 if (Tcl_SplitList(graphPtr->interp, newList, &nNames, &nameArr) != TCL_OK) {
1281 Tcl_AppendResult(graphPtr->interp, "can't split name list \"", newList,
1282 "\"", (char *)NULL);
1283 return TCL_ERROR;
1284 }
1285 /* Clear the display list and mark all elements as hidden. */
1286 Blt_ChainReset(graphPtr->elements.displayList);
1287
1288 /* Rebuild the display list, checking that each name it exists
1289 * (currently ignoring invalid element names). */
1290 for (i = 0; i < nNames; i++) {
1291 if (NameToElement(graphPtr, nameArr[i], &elemPtr) == TCL_OK) {
1292 Blt_ChainAppend(graphPtr->elements.displayList, elemPtr);
1293 }
1294 }
1295 Blt_Free(nameArr);
1296 graphPtr->flags |= RESET_WORLD;
1297 Blt_EventuallyRedrawGraph(graphPtr);
1298 Tcl_ResetResult(graphPtr->interp);
1299 return TCL_OK;
1300}
1301
1302
1303/*
1304 *----------------------------------------------------------------------
1305 *
1306 * Blt_DestroyElements --
1307 *
1308 * Removes all the graph's elements. This routine is called when
1309 * the graph is destroyed.
1310 *
1311 * Results:
1312 * None.
1313 *
1314 * Side effects:
1315 * Memory allocated for the graph's elements is freed.
1316 *
1317 *----------------------------------------------------------------------
1318 */
1319void
1320Blt_DestroyElements(graphPtr)
1321 Graph *graphPtr;
1322{
1323 Blt_HashEntry *hPtr;
1324 Blt_HashSearch cursor;
1325 Element *elemPtr;
1326
1327 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
1328 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1329 elemPtr = (Element *)Blt_GetHashValue(hPtr);
1330 elemPtr->hashPtr = NULL;
1331 DestroyElement(graphPtr, elemPtr);
1332 }
1333 Blt_DeleteHashTable(&graphPtr->elements.table);
1334 Blt_DeleteHashTable(&graphPtr->elements.tagTable);
1335 Blt_ChainDestroy(graphPtr->elements.displayList);
1336}
1337
1338void
1339Blt_MapElements(graphPtr)
1340 Graph *graphPtr;
1341{
1342 Element *elemPtr;
1343 Blt_ChainLink *linkPtr;
1344
1345 if (graphPtr->mode != MODE_INFRONT) {
1346 Blt_ResetStacks(graphPtr);
1347 }
1348 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1349 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1350 elemPtr = Blt_ChainGetValue(linkPtr);
1351 if (elemPtr->hidden) {
1352 continue;
1353 }
1354 if ((graphPtr->flags & MAP_ALL) || (elemPtr->flags & MAP_ITEM)) {
1355 (*elemPtr->procsPtr->mapProc) (graphPtr, elemPtr);
1356 elemPtr->flags &= ~MAP_ITEM;
1357 }
1358 }
1359}
1360
1361/*
1362 * -----------------------------------------------------------------
1363 *
1364 * Blt_DrawElements --
1365 *
1366 * Calls the individual element drawing routines for each
1367 * element.
1368 *
1369 * Results:
1370 * None
1371 *
1372 * Side Effects:
1373 * Elements are drawn into the drawable (pixmap) which will
1374 * eventually be displayed in the graph window.
1375 *
1376 * -----------------------------------------------------------------
1377 */
1378void
1379Blt_DrawElements(graphPtr, drawable)
1380 Graph *graphPtr;
1381 Drawable drawable; /* Pixmap or window to draw into */
1382{
1383 Blt_ChainLink *linkPtr;
1384 Element *elemPtr;
1385
1386 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1387 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1388 elemPtr = Blt_ChainGetValue(linkPtr);
1389 if (!elemPtr->hidden) {
1390 (*elemPtr->procsPtr->drawNormalProc) (graphPtr, drawable, elemPtr);
1391 }
1392 }
1393}
1394
1395/*
1396 * -----------------------------------------------------------------
1397 *
1398 * Blt_DrawActiveElements --
1399 *
1400 * Calls the individual element drawing routines to display
1401 * the active colors for each element.
1402 *
1403 * Results:
1404 * None
1405 *
1406 * Side Effects:
1407 * Elements are drawn into the drawable (pixmap) which will
1408 * eventually be displayed in the graph window.
1409 *
1410 * -----------------------------------------------------------------
1411 */
1412void
1413Blt_DrawActiveElements(graphPtr, drawable)
1414 Graph *graphPtr;
1415 Drawable drawable; /* Pixmap or window to draw into */
1416{
1417 Blt_ChainLink *linkPtr;
1418 Element *elemPtr;
1419
1420 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1421 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1422 elemPtr = Blt_ChainGetValue(linkPtr);
1423 if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) {
1424 (*elemPtr->procsPtr->drawActiveProc) (graphPtr, drawable, elemPtr);
1425 }
1426 }
1427}
1428
1429/*
1430 * -----------------------------------------------------------------
1431 *
1432 * Blt_ElementsToPostScript --
1433 *
1434 * Generates PostScript output for each graph element in the
1435 * element display list.
1436 *
1437 * -----------------------------------------------------------------
1438 */
1439void
1440Blt_ElementsToPostScript(graphPtr, psToken)
1441 Graph *graphPtr;
1442 PsToken psToken;
1443{
1444 Blt_ChainLink *linkPtr;
1445 Element *elemPtr;
1446
1447 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1448 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1449 elemPtr = Blt_ChainGetValue(linkPtr);
1450 if (!elemPtr->hidden) {
1451 /* Comment the PostScript to indicate the start of the element */
1452 Blt_FormatToPostScript(psToken, "\n%% Element \"%s\"\n\n",
1453 elemPtr->name);
1454 (*elemPtr->procsPtr->printNormalProc) (graphPtr, psToken, elemPtr);
1455 }
1456 }
1457}
1458
1459/*
1460 * -----------------------------------------------------------------
1461 *
1462 * Blt_ActiveElementsToPostScript --
1463 *
1464 * -----------------------------------------------------------------
1465 */
1466void
1467Blt_ActiveElementsToPostScript(graphPtr, psToken)
1468 Graph *graphPtr;
1469 PsToken psToken;
1470{
1471 Blt_ChainLink *linkPtr;
1472 Element *elemPtr;
1473
1474 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1475 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1476 elemPtr = Blt_ChainGetValue(linkPtr);
1477 if ((!elemPtr->hidden) && (elemPtr->flags & ELEM_ACTIVE)) {
1478 Blt_FormatToPostScript(psToken, "\n%% Active Element \"%s\"\n\n",
1479 elemPtr->name);
1480 (*elemPtr->procsPtr->printActiveProc) (graphPtr, psToken, elemPtr);
1481 }
1482 }
1483}
1484
1485int
1486Blt_GraphUpdateNeeded(graphPtr)
1487 Graph *graphPtr;
1488{
1489 Blt_ChainLink *linkPtr;
1490 Element *elemPtr;
1491
1492 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1493 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1494 elemPtr = Blt_ChainGetValue(linkPtr);
1495 if (elemPtr->hidden) {
1496 continue;
1497 }
1498 /* Check if the x or y vectors have notifications pending */
1499 if ((Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1500 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1501 return 1;
1502 }
1503 }
1504 return 0;
1505}
1506
1507
1508
1509/*
1510 *----------------------------------------------------------------------
1511 *
1512 * ActivateOp --
1513 *
1514 * Marks data points of elements (given by their index) as active.
1515 *
1516 * Results:
1517 * Returns TCL_OK if no errors occurred.
1518 *
1519 *----------------------------------------------------------------------
1520 */
1521static int
1522ActivateOp(graphPtr, interp, argc, argv)
1523 Graph *graphPtr; /* Graph widget */
1524 Tcl_Interp *interp; /* Interpreter to report errors to */
1525 int argc; /* Number of element names */
1526 char **argv; /* List of element names */
1527{
1528 Element *elemPtr;
1529 register int i;
1530 int *activeArr;
1531 int nActiveIndices;
1532
1533 if (argc == 3) {
1534 register Blt_HashEntry *hPtr;
1535 Blt_HashSearch cursor;
1536
1537 /* List all the currently active elements */
1538 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
1539 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1540 elemPtr = (Element *)Blt_GetHashValue(hPtr);
1541 if (elemPtr->flags & ELEM_ACTIVE) {
1542 Tcl_AppendElement(graphPtr->interp, elemPtr->name);
1543 }
1544 }
1545 return TCL_OK;
1546 }
1547 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
1548 return TCL_ERROR; /* Can't find named element */
1549 }
1550 elemPtr->flags |= ELEM_ACTIVE | ACTIVE_PENDING;
1551
1552 activeArr = NULL;
1553 nActiveIndices = -1;
1554 if (argc > 4) {
1555 register int *activePtr;
1556
1557 nActiveIndices = argc - 4;
1558 activePtr = activeArr = Blt_Malloc(sizeof(int) * nActiveIndices);
1559 assert(activeArr);
1560 for (i = 4; i < argc; i++) {
1561 if (GetIndex(interp, elemPtr, argv[i], activePtr) != TCL_OK) {
1562 return TCL_ERROR;
1563 }
1564 activePtr++;
1565 }
1566 }
1567 if (elemPtr->activeIndices != NULL) {
1568 Blt_Free(elemPtr->activeIndices);
1569 }
1570 elemPtr->nActiveIndices = nActiveIndices;
1571 elemPtr->activeIndices = activeArr;
1572 Blt_EventuallyRedrawGraph(graphPtr);
1573 return TCL_OK;
1574}
1575
1576ClientData
1577Blt_MakeElementTag(graphPtr, tagName)
1578 Graph *graphPtr;
1579 char *tagName;
1580{
1581 Blt_HashEntry *hPtr;
1582 int isNew;
1583
1584 hPtr = Blt_CreateHashEntry(&graphPtr->elements.tagTable, tagName, &isNew);
1585 assert(hPtr);
1586 return Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr);
1587}
1588
1589/*
1590 *----------------------------------------------------------------------
1591 *
1592 * BindOp --
1593 *
1594 * .g element bind elemName sequence command
1595 *
1596 *----------------------------------------------------------------------
1597 */
1598/*ARGSUSED*/
1599static int
1600BindOp(graphPtr, interp, argc, argv)
1601 Graph *graphPtr;
1602 Tcl_Interp *interp;
1603 int argc;
1604 char **argv;
1605{
1606 if (argc == 3) {
1607 Blt_HashEntry *hPtr;
1608 Blt_HashSearch cursor;
1609 char *tagName;
1610
1611 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.tagTable, &cursor);
1612 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1613 tagName = Blt_GetHashKey(&graphPtr->elements.tagTable, hPtr);
1614 Tcl_AppendElement(interp, tagName);
1615 }
1616 return TCL_OK;
1617 }
1618 return Blt_ConfigureBindings(interp, graphPtr->bindTable,
1619 Blt_MakeElementTag(graphPtr, argv[3]), argc - 4, argv + 4);
1620}
1621
1622/*
1623 *----------------------------------------------------------------------
1624 *
1625 * CreateOp --
1626 *
1627 * Add a new element to the graph (using the default type of the
1628 * graph).
1629 *
1630 * Results:
1631 * The return value is a standard Tcl result.
1632 *
1633 *----------------------------------------------------------------------
1634 */
1635static int
1636CreateOp(graphPtr, interp, argc, argv, type)
1637 Graph *graphPtr;
1638 Tcl_Interp *interp;
1639 int argc;
1640 char **argv;
1641 Blt_Uid type;
1642{
1643 return CreateElement(graphPtr, interp, argc, argv, type);
1644}
1645
1646/*
1647 *----------------------------------------------------------------------
1648 *
1649 * CgetOp --
1650 *
1651 *----------------------------------------------------------------------
1652 */
1653/*ARGSUSED*/
1654static int
1655CgetOp(graphPtr, interp, argc, argv)
1656 Graph *graphPtr;
1657 Tcl_Interp *interp;
1658 int argc;
1659 char *argv[];
1660{
1661 Element *elemPtr;
1662
1663 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
1664 return TCL_ERROR; /* Can't find named element */
1665 }
1666 if (Tk_ConfigureValue(interp, graphPtr->tkwin, elemPtr->specsPtr,
1667 (char *)elemPtr, argv[4], 0) != TCL_OK) {
1668 return TCL_ERROR;
1669 }
1670 return TCL_OK;
1671}
1672
1673/*
1674 *----------------------------------------------------------------------
1675 *
1676 * ClosestOp --
1677 *
1678 * Find the element closest to the specified screen coordinates.
1679 * Options:
1680 * -halo Consider points only with this maximum distance
1681 * from the picked coordinate.
1682 * -interpolate Find closest point along element traces, not just
1683 * data points.
1684 * -along
1685 *
1686 * Results:
1687 * A standard Tcl result. If an element could be found within
1688 * the halo distance, the interpreter result is "1", otherwise
1689 * "0". If a closest element exists, the designated Tcl array
1690 * variable will be set with the following information:
1691 *
1692 * 1) the element name,
1693 * 2) the index of the closest point,
1694 * 3) the distance (in screen coordinates) from the picked X-Y
1695 * coordinate and the closest point,
1696 * 4) the X coordinate (graph coordinate) of the closest point,
1697 * 5) and the Y-coordinate.
1698 *
1699 *----------------------------------------------------------------------
1700 */
1701
1702static Tk_ConfigSpec closestSpecs[] =
1703{
1704 {TK_CONFIG_CUSTOM, "-halo", (char *)NULL, (char *)NULL,
1705 (char *)NULL, Tk_Offset(ClosestSearch, halo), 0, &bltDistanceOption},
1706 {TK_CONFIG_BOOLEAN, "-interpolate", (char *)NULL, (char *)NULL,
1707 (char *)NULL, Tk_Offset(ClosestSearch, mode), 0 },
1708 {TK_CONFIG_CUSTOM, "-along", (char *)NULL, (char *)NULL,
1709 (char *)NULL, Tk_Offset(ClosestSearch, along), 0, &alongOption},
1710 {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
1711 (char *)NULL, 0, 0}
1712};
1713
1714static int
1715ClosestOp(graphPtr, interp, argc, argv)
1716 Graph *graphPtr; /* Graph widget */
1717 Tcl_Interp *interp; /* Interpreter to report results to */
1718 int argc; /* Number of element names */
1719 char **argv; /* List of element names */
1720{
1721 Element *elemPtr;
1722 ClosestSearch search;
1723 int i, x, y;
1724 int flags = TCL_LEAVE_ERR_MSG;
1725 int found;
1726
1727 if (graphPtr->flags & RESET_AXES) {
1728 Blt_ResetAxes(graphPtr);
1729 }
1730 if (Tk_GetPixels(interp, graphPtr->tkwin, argv[3], &x) != TCL_OK) {
1731 Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL);
1732 return TCL_ERROR;
1733 }
1734 if (Tk_GetPixels(interp, graphPtr->tkwin, argv[4], &y) != TCL_OK) {
1735 Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL);
1736 return TCL_ERROR;
1737 }
1738 if (graphPtr->inverted) {
1739 int temp;
1740
1741 temp = x, x = y, y = temp;
1742 }
1743 for (i = 6; i < argc; i += 2) { /* Count switches-value pairs */
1744 if ((argv[i][0] != '-') ||
1745 ((argv[i][1] == '-') && (argv[i][2] == '\0'))) {
1746 break;
1747 }
1748 }
1749 if (i > argc) {
1750 i = argc;
1751 }
1752
1753 search.mode = SEARCH_POINTS;
1754 search.halo = graphPtr->halo;
1755 search.index = -1;
1756 search.along = SEARCH_BOTH;
1757 search.x = x;
1758 search.y = y;
1759
1760 if (Tk_ConfigureWidget(interp, graphPtr->tkwin, closestSpecs, i - 6,
1761 argv + 6, (char *)&search, TK_CONFIG_ARGV_ONLY) != TCL_OK) {
1762 return TCL_ERROR; /* Error occurred processing an option. */
1763 }
1764 if ((i < argc) && (argv[i][0] == '-')) {
1765 i++; /* Skip "--" */
1766 }
1767 search.dist = (double)(search.halo + 1);
1768
1769 if (i < argc) {
1770 Blt_ChainLink *linkPtr;
1771
1772 for ( /* empty */ ; i < argc; i++) {
1773 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1774 return TCL_ERROR; /* Can't find named element */
1775 }
1776 found = FALSE;
1777 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
1778 linkPtr == NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
1779 if (elemPtr == Blt_ChainGetValue(linkPtr)) {
1780 found = TRUE;
1781 break;
1782 }
1783 }
1784 if ((!found) || (elemPtr->hidden)) {
1785 Tcl_AppendResult(interp, "element \"", argv[i], "\" is hidden",
1786 (char *)NULL);
1787 return TCL_ERROR; /* Element isn't visible */
1788 }
1789 /* Check if the X or Y vectors have notifications pending */
1790 if ((elemPtr->flags & MAP_ITEM) ||
1791 (Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1792 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1793 continue;
1794 }
1795 (*elemPtr->procsPtr->closestProc) (graphPtr, elemPtr, &search);
1796 }
1797 } else {
1798 Blt_ChainLink *linkPtr;
1799
1800 /*
1801 * Find the closest point from the set of displayed elements,
1802 * searching the display list from back to front. That way if
1803 * the points from two different elements overlay each other
1804 * exactly, the last one picked will be the topmost.
1805 */
1806 for (linkPtr = Blt_ChainLastLink(graphPtr->elements.displayList);
1807 linkPtr != NULL; linkPtr = Blt_ChainPrevLink(linkPtr)) {
1808 elemPtr = Blt_ChainGetValue(linkPtr);
1809 /* Check if the X or Y vectors have notifications pending */
1810 if ((elemPtr->hidden) ||
1811 (elemPtr->flags & MAP_ITEM) ||
1812 (Blt_VectorNotifyPending(elemPtr->x.clientId)) ||
1813 (Blt_VectorNotifyPending(elemPtr->y.clientId))) {
1814 continue;
1815 }
1816 (*elemPtr->procsPtr->closestProc)(graphPtr, elemPtr, &search);
1817 }
1818
1819 }
1820 if (search.dist < (double)search.halo) {
1821 char string[200];
1822 /*
1823 * Return an array of 5 elements
1824 */
1825 if (Tcl_SetVar2(interp, argv[5], "name",
1826 search.elemPtr->name, flags) == NULL) {
1827 return TCL_ERROR;
1828 }
1829 sprintf(string, "%d", search.index);
1830 if (Tcl_SetVar2(interp, argv[5], "index", string, flags) == NULL) {
1831 return TCL_ERROR;
1832 }
1833 Tcl_PrintDouble(interp, search.point.x, string);
1834 if (Tcl_SetVar2(interp, argv[5], "x", string, flags) == NULL) {
1835 return TCL_ERROR;
1836 }
1837 Tcl_PrintDouble(interp, search.point.y, string);
1838 if (Tcl_SetVar2(interp, argv[5], "y", string, flags) == NULL) {
1839 return TCL_ERROR;
1840 }
1841 Tcl_PrintDouble(interp, search.dist, string);
1842 if (Tcl_SetVar2(interp, argv[5], "dist", string, flags) == NULL) {
1843 return TCL_ERROR;
1844 }
1845 Tcl_SetResult(interp, "1", TCL_STATIC);
1846 } else {
1847 if (Tcl_SetVar2(interp, argv[5], "name", "", flags) == NULL) {
1848 return TCL_ERROR;
1849 }
1850 Tcl_SetResult(interp, "0", TCL_STATIC);
1851 }
1852 return TCL_OK;
1853}
1854
1855/*
1856 *----------------------------------------------------------------------
1857 *
1858 * ConfigureOp --
1859 *
1860 * Sets the element specifications by the given the command line
1861 * arguments and calls the element specification configuration
1862 * routine. If zero or one command line options are given, only
1863 * information about the option(s) is returned in interp->result.
1864 * If the element configuration has changed and the element is
1865 * currently displayed, the axis limits are updated and
1866 * recomputed.
1867 *
1868 * Results:
1869 * The return value is a standard Tcl result.
1870 *
1871 * Side Effects:
1872 * Graph will be redrawn to reflect the new display list.
1873 *
1874 *----------------------------------------------------------------------
1875 */
1876static int
1877ConfigureOp(graphPtr, interp, argc, argv)
1878 Graph *graphPtr;
1879 Tcl_Interp *interp;
1880 int argc;
1881 char *argv[];
1882{
1883 Element *elemPtr;
1884 int flags;
1885 int numNames, numOpts;
1886 char **options;
1887 register int i;
1888
1889 /* Figure out where the option value pairs begin */
1890 argc -= 3;
1891 argv += 3;
1892 for (i = 0; i < argc; i++) {
1893 if (argv[i][0] == '-') {
1894 break;
1895 }
1896 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1897 return TCL_ERROR; /* Can't find named element */
1898 }
1899 }
1900 numNames = i; /* Number of element names specified */
1901 numOpts = argc - i; /* Number of options specified */
1902 options = argv + numNames; /* Start of options in argv */
1903
1904 for (i = 0; i < numNames; i++) {
1905 NameToElement(graphPtr, argv[i], &elemPtr);
1906 flags = TK_CONFIG_ARGV_ONLY;
1907 if (numOpts == 0) {
1908 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
1909 elemPtr->specsPtr, (char *)elemPtr, (char *)NULL, flags);
1910 } else if (numOpts == 1) {
1911 return Tk_ConfigureInfo(interp, graphPtr->tkwin,
1912 elemPtr->specsPtr, (char *)elemPtr, options[0], flags);
1913 }
1914 if (Tk_ConfigureWidget(interp, graphPtr->tkwin, elemPtr->specsPtr,
1915 numOpts, options, (char *)elemPtr, flags) != TCL_OK) {
1916 return TCL_ERROR;
1917 }
1918 if ((*elemPtr->procsPtr->configProc) (graphPtr, elemPtr) != TCL_OK) {
1919 return TCL_ERROR; /* Failed to configure element */
1920 }
1921 if (Blt_ConfigModified(elemPtr->specsPtr, "-hide", (char *)NULL)) {
1922 graphPtr->flags |= RESET_AXES;
1923 elemPtr->flags |= MAP_ITEM;
1924 }
1925 /* If data points or axes have changed, reset the axes (may
1926 * affect autoscaling) and recalculate the screen points of
1927 * the element. */
1928
1929 if (Blt_ConfigModified(elemPtr->specsPtr, "-*data", "-map*", "-x",
1930 "-y", (char *)NULL)) {
1931 graphPtr->flags |= RESET_WORLD;
1932 elemPtr->flags |= MAP_ITEM;
1933 }
1934 /* The new label may change the size of the legend */
1935 if (Blt_ConfigModified(elemPtr->specsPtr, "-label", (char *)NULL)) {
1936 graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD);
1937 }
1938 }
1939 /* Update the pixmap if any configuration option changed */
1940 graphPtr->flags |= (REDRAW_BACKING_STORE | DRAW_MARGINS);
1941 Blt_EventuallyRedrawGraph(graphPtr);
1942 return TCL_OK;
1943}
1944
1945/*
1946 *----------------------------------------------------------------------
1947 *
1948 * DeactivateOp --
1949 *
1950 * Clears the active bit for the named elements.
1951 *
1952 * Results:
1953 * Returns TCL_OK if no errors occurred.
1954 *
1955 *----------------------------------------------------------------------
1956 */
1957/*ARGSUSED*/
1958static int
1959DeactivateOp(graphPtr, interp, argc, argv)
1960 Graph *graphPtr; /* Graph widget */
1961 Tcl_Interp *interp; /* Not used. */
1962 int argc; /* Number of element names */
1963 char **argv; /* List of element names */
1964{
1965 Element *elemPtr;
1966 register int i;
1967
1968 for (i = 3; i < argc; i++) {
1969 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
1970 return TCL_ERROR; /* Can't find named element */
1971 }
1972 elemPtr->flags &= ~ELEM_ACTIVE;
1973 if (elemPtr->activeIndices != NULL) {
1974 Blt_Free(elemPtr->activeIndices);
1975 elemPtr->activeIndices = NULL;
1976 }
1977 elemPtr->nActiveIndices = 0;
1978 }
1979 Blt_EventuallyRedrawGraph(graphPtr);
1980 return TCL_OK;
1981}
1982
1983/*
1984 *----------------------------------------------------------------------
1985 *
1986 * DeleteOp --
1987 *
1988 * Delete the named elements from the graph.
1989 *
1990 * Results:
1991 * TCL_ERROR is returned if any of the named elements can not be
1992 * found. Otherwise TCL_OK is returned;
1993 *
1994 * Side Effects:
1995 * If the element is currently displayed, the plotting area of
1996 * the graph is redrawn. Memory and resources allocated by the
1997 * elements are released.
1998 *
1999 *----------------------------------------------------------------------
2000 */
2001/*ARGSUSED*/
2002static int
2003DeleteOp(graphPtr, interp, argc, argv)
2004 Graph *graphPtr; /* Graph widget */
2005 Tcl_Interp *interp; /* Not used. */
2006 int argc; /* Number of element names */
2007 char **argv; /* List of element names */
2008{
2009 Element *elemPtr;
2010 register int i;
2011
2012 for (i = 3; i < argc; i++) {
2013 if (NameToElement(graphPtr, argv[i], &elemPtr) != TCL_OK) {
2014 return TCL_ERROR; /* Can't find named element */
2015 }
2016 DestroyElement(graphPtr, elemPtr);
2017 }
2018 Blt_EventuallyRedrawGraph(graphPtr);
2019 return TCL_OK;
2020}
2021
2022/*
2023 *----------------------------------------------------------------------
2024 *
2025 * ExistsOp --
2026 *
2027 * Indicates if the named element exists in the graph.
2028 *
2029 * Results:
2030 * The return value is a standard Tcl result. The interpreter
2031 * result will contain "1" or "0".
2032 *
2033 *----------------------------------------------------------------------
2034 */
2035/* ARGSUSED */
2036static int
2037ExistsOp(graphPtr, interp, argc, argv)
2038 Graph *graphPtr;
2039 Tcl_Interp *interp;
2040 int argc; /* Not used. */
2041 char **argv;
2042{
2043 Blt_HashEntry *hPtr;
2044
2045 hPtr = Blt_FindHashEntry(&graphPtr->elements.table, argv[3]);
2046 Blt_SetBooleanResult(interp, (hPtr != NULL));
2047 return TCL_OK;
2048}
2049
2050/*
2051 *----------------------------------------------------------------------
2052 *
2053 * GetOp --
2054 *
2055 * Returns the name of the picked element (using the element
2056 * bind operation). Right now, the only name accepted is
2057 * "current".
2058 *
2059 * Results:
2060 * A standard Tcl result. The interpreter result will contain
2061 * the name of the element.
2062 *
2063 *----------------------------------------------------------------------
2064 */
2065/*ARGSUSED*/
2066static int
2067GetOp(graphPtr, interp, argc, argv)
2068 Graph *graphPtr;
2069 Tcl_Interp *interp;
2070 int argc; /* Not used. */
2071 char *argv[];
2072{
2073 register Element *elemPtr;
2074
2075 if ((argv[3][0] == 'c') && (strcmp(argv[3], "current") == 0)) {
2076 elemPtr = (Element *)Blt_GetCurrentItem(graphPtr->bindTable);
2077 /* Report only on elements. */
2078 if ((elemPtr != NULL) &&
2079 ((elemPtr->classUid == bltBarElementUid) ||
2080 (elemPtr->classUid == bltLineElementUid) ||
2081 (elemPtr->classUid == bltStripElementUid))) {
2082 Tcl_SetResult(interp, elemPtr->name, TCL_VOLATILE);
2083 }
2084 }
2085 return TCL_OK;
2086}
2087
2088/*
2089 *----------------------------------------------------------------------
2090 *
2091 * NamesOp --
2092 *
2093 * Returns the names of the elements is the graph matching
2094 * one of more patterns provided. If no pattern arguments
2095 * are given, then all element names will be returned.
2096 *
2097 * Results:
2098 * The return value is a standard Tcl result. The interpreter
2099 * result will contain a Tcl list of the element names.
2100 *
2101 *----------------------------------------------------------------------
2102 */
2103static int
2104NamesOp(graphPtr, interp, argc, argv)
2105 Graph *graphPtr;
2106 Tcl_Interp *interp;
2107 int argc;
2108 char **argv;
2109{
2110 Element *elemPtr;
2111 Blt_HashSearch cursor;
2112 register Blt_HashEntry *hPtr;
2113 register int i;
2114
2115 for (hPtr = Blt_FirstHashEntry(&graphPtr->elements.table, &cursor);
2116 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
2117 elemPtr = (Element *)Blt_GetHashValue(hPtr);
2118 if (argc == 3) {
2119 Tcl_AppendElement(graphPtr->interp, elemPtr->name);
2120 continue;
2121 }
2122 for (i = 3; i < argc; i++) {
2123 if (Tcl_StringMatch(elemPtr->name, argv[i])) {
2124 Tcl_AppendElement(interp, elemPtr->name);
2125 break;
2126 }
2127 }
2128 }
2129 return TCL_OK;
2130}
2131
2132/*
2133 *----------------------------------------------------------------------
2134 *
2135 * ShowOp --
2136 *
2137 * Queries or resets the element display list.
2138 *
2139 * Results:
2140 * The return value is a standard Tcl result. The interpreter
2141 * result will contain the new display list of element names.
2142 *
2143 *----------------------------------------------------------------------
2144 */
2145static int
2146ShowOp(graphPtr, interp, argc, argv)
2147 Graph *graphPtr;
2148 Tcl_Interp *interp;
2149 int argc;
2150 char **argv;
2151{
2152 Element *elemPtr;
2153 Blt_ChainLink *linkPtr;
2154
2155 if (argc == 4) {
2156 if (RebuildDisplayList(graphPtr, argv[3]) != TCL_OK) {
2157 return TCL_ERROR;
2158 }
2159 }
2160 for (linkPtr = Blt_ChainFirstLink(graphPtr->elements.displayList);
2161 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2162 elemPtr = Blt_ChainGetValue(linkPtr);
2163 Tcl_AppendElement(interp, elemPtr->name);
2164 }
2165 return TCL_OK;
2166}
2167
2168/*
2169 *----------------------------------------------------------------------
2170 *
2171 * TypeOp --
2172 *
2173 * Returns the name of the type of the element given by some
2174 * element name.
2175 *
2176 * Results:
2177 * A standard Tcl result. Returns the type of the element in
2178 * interp->result. If the identifier given doesn't represent an
2179 * element, then an error message is left in interp->result.
2180 *
2181 *----------------------------------------------------------------------
2182 */
2183/*ARGSUSED*/
2184static int
2185TypeOp(graphPtr, interp, argc, argv)
2186 Graph *graphPtr; /* Graph widget */
2187 Tcl_Interp *interp;
2188 int argc; /* Not used. */
2189 char **argv; /* Element name */
2190{
2191 Element *elemPtr;
2192
2193 if (NameToElement(graphPtr, argv[3], &elemPtr) != TCL_OK) {
2194 return TCL_ERROR; /* Can't find named element */
2195 }
2196 Tcl_SetResult(interp, elemPtr->classUid, TCL_STATIC);
2197 return TCL_OK;
2198}
2199
2200/*
2201 * Global routines:
2202 */
2203static Blt_OpSpec elemOps[] =
2204{
2205 {"activate", 1, (Blt_Op)ActivateOp, 3, 0, "?elemName? ?index...?",},
2206 {"bind", 1, (Blt_Op)BindOp, 3, 6, "elemName sequence command",},
2207 {"cget", 2, (Blt_Op)CgetOp, 5, 5, "elemName option",},
2208 {"closest", 2, (Blt_Op)ClosestOp, 6, 0,
2209 "x y varName ?option value?... ?elemName?...",},
2210 {"configure", 2, (Blt_Op)ConfigureOp, 4, 0,
2211 "elemName ?elemName?... ?option value?...",},
2212 {"create", 2, (Blt_Op)CreateOp, 4, 0, "elemName ?option value?...",},
2213 {"deactivate", 3, (Blt_Op)DeactivateOp, 3, 0, "?elemName?...",},
2214 {"delete", 3, (Blt_Op)DeleteOp, 3, 0, "?elemName?...",},
2215 {"exists", 1, (Blt_Op)ExistsOp, 4, 4, "elemName",},
2216 {"get", 1, (Blt_Op)GetOp, 4, 4, "name",},
2217 {"names", 1, (Blt_Op)NamesOp, 3, 0, "?pattern?...",},
2218 {"show", 1, (Blt_Op)ShowOp, 3, 4, "?elemList?",},
2219 {"type", 1, (Blt_Op)TypeOp, 4, 4, "elemName",},
2220};
2221static int numElemOps = sizeof(elemOps) / sizeof(Blt_OpSpec);
2222
2223
2224/*
2225 * ----------------------------------------------------------------
2226 *
2227 * Blt_ElementOp --
2228 *
2229 * This procedure is invoked to process the Tcl command that
2230 * corresponds to a widget managed by this module. See the user
2231 * documentation for details on what it does.
2232 *
2233 * Results:
2234 * A standard Tcl result.
2235 *
2236 * Side effects:
2237 * See the user documentation.
2238 *
2239 * ----------------------------------------------------------------
2240 */
2241int
2242Blt_ElementOp(graphPtr, interp, argc, argv, type)
2243 Graph *graphPtr; /* Graph widget record */
2244 Tcl_Interp *interp;
2245 int argc; /* # arguments */
2246 char **argv; /* Argument list */
2247 Blt_Uid type;
2248{
2249 Blt_Op proc;
2250 int result;
2251
2252 proc = Blt_GetOp(interp, numElemOps, elemOps, BLT_OP_ARG2, argc, argv, 0);
2253 if (proc == NULL) {
2254 return TCL_ERROR;
2255 }
2256 if (proc == CreateOp) {
2257 result = CreateOp(graphPtr, interp, argc, argv, type);
2258 } else {
2259 result = (*proc) (graphPtr, interp, argc, argv);
2260 }
2261 return result;
2262}
Note: See TracBrowser for help on using the repository browser.