1 
2 /*
3  * bltGrGrid.c --
4  *
5  *	This module implements grid lines for the BLT graph widget.
6  *
7  * Copyright 1995-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  * Graph widget created by Sani Nassif and George Howlett.
28  */
29 
30 #include "bltGraph.h"
31 
32 extern Tk_CustomOption bltDistanceOption;
33 extern Tk_CustomOption bltDashesOption;
34 extern Tk_CustomOption bltAnyXAxisOption;
35 extern Tk_CustomOption bltAnyYAxisOption;
36 
37 
38 #define DEF_GRID_DASHES		"dot"
39 #define DEF_GRID_FOREGROUND	RGB_GREY64
40 #define DEF_GRID_FG_MONO	RGB_BLACK
41 #define DEF_GRID_LINE_WIDTH	"0"
42 #define DEF_GRID_HIDE_BARCHART	"no"
43 #define DEF_GRID_HIDE_GRAPH	"yes"
44 #define DEF_GRID_MINOR		"yes"
45 #define DEF_GRID_MAP_X_GRAPH	"x"
46 #define DEF_GRID_MAP_X_BARCHART	(char *)NULL
47 #define DEF_GRID_MAP_Y		"y"
48 #define DEF_GRID_POSITION	(char *)NULL
49 
50 static Tk_ConfigSpec configSpecs[] =
51 {
52     {TK_CONFIG_COLOR, "-color", "color", "Color",
53 	DEF_GRID_FOREGROUND, Tk_Offset(Grid, colorPtr),
54 	TK_CONFIG_COLOR_ONLY | ALL_GRAPHS},
55     {TK_CONFIG_COLOR, "-color", "color", "color",
56 	DEF_GRID_FG_MONO, Tk_Offset(Grid, colorPtr),
57 	TK_CONFIG_MONO_ONLY | ALL_GRAPHS},
58     {TK_CONFIG_CUSTOM, "-dashes", "dashes", "Dashes",
59 	DEF_GRID_DASHES, Tk_Offset(Grid, dashes),
60 	TK_CONFIG_NULL_OK | ALL_GRAPHS, &bltDashesOption},
61     {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
62 	DEF_GRID_HIDE_BARCHART, Tk_Offset(Grid, hidden), BARCHART},
63     {TK_CONFIG_BOOLEAN, "-hide", "hide", "Hide",
64 	DEF_GRID_HIDE_GRAPH, Tk_Offset(Grid, hidden), GRAPH | STRIPCHART},
65     {TK_CONFIG_CUSTOM, "-linewidth", "lineWidth", "Linewidth",
66 	DEF_GRID_LINE_WIDTH, Tk_Offset(Grid, lineWidth),
67 	TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS, &bltDistanceOption},
68     {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
69 	DEF_GRID_MAP_X_GRAPH, Tk_Offset(Grid, axes.x),
70 	GRAPH | STRIPCHART, &bltAnyXAxisOption},
71     {TK_CONFIG_CUSTOM, "-mapx", "mapX", "MapX",
72 	DEF_GRID_MAP_X_BARCHART, Tk_Offset(Grid, axes.x),
73 	BARCHART, &bltAnyXAxisOption},
74     {TK_CONFIG_CUSTOM, "-mapy", "mapY", "MapY",
75 	DEF_GRID_MAP_Y, Tk_Offset(Grid, axes.y),
76 	ALL_GRAPHS, &bltAnyYAxisOption},
77     {TK_CONFIG_BOOLEAN, "-minor", "minor", "Minor",
78 	DEF_GRID_MINOR, Tk_Offset(Grid, minorGrid),
79 	TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS},
80     {TK_CONFIG_BOOLEAN, "-raised", "raised", "Raised",
81 	"0", Tk_Offset(Grid, raised),
82 	TK_CONFIG_DONT_SET_DEFAULT | ALL_GRAPHS},
83     {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
84 };
85 
86 /*
87  *----------------------------------------------------------------------
88  *
89  * ConfigureGrid --
90  *
91  *	Configures attributes of the grid such as line width,
92  *	dashes, and position.  The grid are first turned off
93  *	before any of the attributes changes.
94  *
95  * Results:
96  *	None
97  *
98  * Side Effects:
99  *	Crosshair GC is allocated.
100  *
101  *----------------------------------------------------------------------
102  */
103 static void
ConfigureGrid(graphPtr,gridPtr)104 ConfigureGrid(graphPtr, gridPtr)
105     Graph *graphPtr;
106     Grid *gridPtr;
107 {
108     XGCValues gcValues;
109     unsigned long gcMask;
110     GC newGC;
111 
112     gcValues.background = gcValues.foreground = gridPtr->colorPtr->pixel;
113     gcValues.line_width = LineWidth(gridPtr->lineWidth);
114     gcMask = (GCForeground | GCBackground | GCLineWidth);
115     if (LineIsDashed(gridPtr->dashes)) {
116 	gcValues.line_style = LineOnOffDash;
117 	gcMask |= GCLineStyle;
118     }
119     newGC = Blt_GetPrivateGC(graphPtr->tkwin, gcMask, &gcValues);
120     if (LineIsDashed(gridPtr->dashes)) {
121 	Blt_SetDashes(graphPtr->display, newGC, &(gridPtr->dashes));
122     }
123     if (gridPtr->gc != NULL) {
124 	Blt_FreePrivateGC(graphPtr->display, gridPtr->gc);
125     }
126     gridPtr->gc = newGC;
127 }
128 
129 /*
130  *----------------------------------------------------------------------
131  *
132  * MapGrid --
133  *
134  *	Determines the coordinates of the line segments corresponding
135  *	to the grid lines for each axis.
136  *
137  * Results:
138  *	None.
139  *
140  *----------------------------------------------------------------------
141  */
142 void
Blt_MapGrid(graphPtr)143 Blt_MapGrid(graphPtr)
144     Graph *graphPtr;
145 {
146     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
147     int nSegments;
148     Segment2D *segments;
149 
150     if (gridPtr->x.segments != NULL) {
151 	Blt_Free(gridPtr->x.segments);
152 	gridPtr->x.segments = NULL;
153     }
154     if (gridPtr->y.segments != NULL) {
155 	Blt_Free(gridPtr->y.segments);
156 	gridPtr->y.segments = NULL;
157     }
158     gridPtr->x.nSegments = gridPtr->y.nSegments = 0;
159     /*
160      * Generate line segments to represent the grid.  Line segments
161      * are calculated from the major tick intervals of each axis mapped.
162      */
163     Blt_GetAxisSegments(graphPtr, gridPtr->axes.x, &segments, &nSegments);
164     if (nSegments > 0) {
165 	gridPtr->x.nSegments = nSegments;
166 	gridPtr->x.segments = segments;
167     }
168     Blt_GetAxisSegments(graphPtr, gridPtr->axes.y, &segments, &nSegments);
169     if (nSegments > 0) {
170 	gridPtr->y.nSegments = nSegments;
171 	gridPtr->y.segments = segments;
172     }
173 }
174 
175 /*
176  *----------------------------------------------------------------------
177  *
178  * DrawGrid --
179  *
180  *	Draws the grid lines associated with each axis.
181  *
182  * Results:
183  *	None.
184  *
185  *----------------------------------------------------------------------
186  */
187 void
Blt_DrawGrid(graphPtr,drawable)188 Blt_DrawGrid(graphPtr, drawable)
189     Graph *graphPtr;
190     Drawable drawable;		/* Pixmap or window to draw into */
191 {
192     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
193 
194     if (gridPtr->hidden) {
195 	return;
196     }
197     if (gridPtr->x.nSegments > 0) {
198 	Blt_Draw2DSegments(graphPtr->display, drawable, gridPtr->gc,
199 			 gridPtr->x.segments, gridPtr->x.nSegments);
200     }
201     if (gridPtr->y.nSegments > 0) {
202 	Blt_Draw2DSegments(graphPtr->display, drawable, gridPtr->gc,
203 	    gridPtr->y.segments, gridPtr->y.nSegments);
204     }
205 }
206 
207 /*
208  *----------------------------------------------------------------------
209  *
210  * Blt_GridToPostScript --
211  *
212  *	Prints the grid lines associated with each axis.
213  *
214  * Results:
215  *	None.
216  *
217  *----------------------------------------------------------------------
218  */
219 void
Blt_GridToPostScript(graphPtr,psToken)220 Blt_GridToPostScript(graphPtr, psToken)
221     Graph *graphPtr;
222     PsToken psToken;
223 {
224     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
225 
226     if (gridPtr->hidden) {
227 	return;
228     }
229     Blt_LineAttributesToPostScript(psToken, gridPtr->colorPtr,
230 	gridPtr->lineWidth, &(gridPtr->dashes), CapButt, JoinMiter);
231     if (gridPtr->x.nSegments > 0) {
232 	Blt_2DSegmentsToPostScript(psToken, gridPtr->x.segments,
233 			gridPtr->x.nSegments);
234     }
235     if (gridPtr->y.nSegments > 0) {
236 	Blt_2DSegmentsToPostScript(psToken, gridPtr->y.segments,
237 			gridPtr->y.nSegments);
238     }
239 }
240 
241 /*
242  *----------------------------------------------------------------------
243  *
244  * Blt_DestroyGrid --
245  *
246  * Results:
247  *	None
248  *
249  * Side Effects:
250  *	Grid GC is released.
251  *
252  *----------------------------------------------------------------------
253  */
254 void
Blt_DestroyGrid(graphPtr)255 Blt_DestroyGrid(graphPtr)
256     Graph *graphPtr;
257 {
258     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
259 
260     Tk_FreeOptions(configSpecs, (char *)gridPtr, graphPtr->display,
261 	Blt_GraphType(graphPtr));
262     if (gridPtr->gc != NULL) {
263 	Blt_FreePrivateGC(graphPtr->display, gridPtr->gc);
264     }
265     if (gridPtr->x.segments != NULL) {
266 	Blt_Free(gridPtr->x.segments);
267     }
268     if (gridPtr->y.segments != NULL) {
269 	Blt_Free(gridPtr->y.segments);
270     }
271     Blt_Free(gridPtr);
272 }
273 
274 /*
275  *----------------------------------------------------------------------
276  *
277  * Blt_CreateGrid --
278  *
279  *	Creates and initializes a new grid structure.
280  *
281  * Results:
282  *	Returns TCL_ERROR if the configuration failed, otherwise TCL_OK.
283  *
284  * Side Effects:
285  *	Memory for grid structure is allocated.
286  *
287  *----------------------------------------------------------------------
288  */
289 int
Blt_CreateGrid(graphPtr)290 Blt_CreateGrid(graphPtr)
291     Graph *graphPtr;
292 {
293     Grid *gridPtr;
294 
295     gridPtr = Blt_Calloc(1, sizeof(Grid));
296     assert(gridPtr);
297     gridPtr->minorGrid = TRUE;
298     graphPtr->gridPtr = gridPtr;
299 
300     if (Blt_ConfigureWidgetComponent(graphPtr->interp, graphPtr->tkwin, "grid",
301 	    "Grid", configSpecs, 0, (char **)NULL, (char *)gridPtr,
302 	    Blt_GraphType(graphPtr)) != TCL_OK) {
303 	return TCL_ERROR;
304     }
305     ConfigureGrid(graphPtr, gridPtr);
306     return TCL_OK;
307 }
308 
309 /*
310  *----------------------------------------------------------------------
311  *
312  * CgetOp --
313  *
314  *	Queries configuration attributes of the grid such as line
315  *	width, dashes, and position.
316  *
317  * Results:
318  *	A standard Tcl result.
319  *
320  *----------------------------------------------------------------------
321  */
322 /* ARGSUSED */
323 static int
CgetOp(graphPtr,interp,argc,argv)324 CgetOp(graphPtr, interp, argc, argv)
325     Graph *graphPtr;
326     Tcl_Interp *interp;
327     int argc;
328     char **argv;
329 {
330     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
331 
332     return Tk_ConfigureValue(interp, graphPtr->tkwin, configSpecs,
333 	(char *)gridPtr, argv[3], Blt_GraphType(graphPtr));
334 }
335 
336 /*
337  *----------------------------------------------------------------------
338  *
339  * ConfigureOp --
340  *
341  *	Queries or resets configuration attributes of the grid
342  * 	such as line width, dashes, and position.
343  *
344  * Results:
345  *	A standard Tcl result.
346  *
347  * Side Effects:
348  *	Grid attributes are reset.  The graph is redrawn at the
349  *	next idle point.
350  *
351  *----------------------------------------------------------------------
352  */
353 static int
ConfigureOp(graphPtr,interp,argc,argv)354 ConfigureOp(graphPtr, interp, argc, argv)
355     Graph *graphPtr;
356     Tcl_Interp *interp;
357     int argc;
358     CONST char **argv;
359 {
360     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
361     int flags;
362 
363     flags = Blt_GraphType(graphPtr) | TK_CONFIG_ARGV_ONLY;
364     if (argc == 3) {
365 	return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs,
366 	    (char *)gridPtr, (char *)NULL, flags);
367     } else if (argc == 4) {
368 	return Tk_ConfigureInfo(interp, graphPtr->tkwin, configSpecs,
369 	    (char *)gridPtr, argv[3], flags);
370     }
371     if (Tk_ConfigureWidget(graphPtr->interp, graphPtr->tkwin, configSpecs,
372 	    argc - 3, argv + 3, (char *)gridPtr, flags) != TCL_OK) {
373 	return TCL_ERROR;
374     }
375     ConfigureGrid(graphPtr, gridPtr);
376     graphPtr->flags |= REDRAW_BACKING_STORE;
377     Blt_EventuallyRedrawGraph(graphPtr);
378     return TCL_OK;
379 }
380 
381 /*
382  *----------------------------------------------------------------------
383  *
384  * MapOp --
385  *
386  *	Maps the grid.
387  *
388  * Results:
389  *	A standard Tcl result.
390  *
391  * Side Effects:
392  *	Grid attributes are reset and the graph is redrawn if necessary.
393  *
394  *----------------------------------------------------------------------
395  */
396 /*ARGSUSED*/
397 static int
MapOp(graphPtr,interp,argc,argv)398 MapOp(graphPtr, interp, argc, argv)
399     Graph *graphPtr;
400     Tcl_Interp *interp;
401     int argc;
402     char **argv;
403 {
404     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
405 
406     if (gridPtr->hidden) {
407 	gridPtr->hidden = FALSE;/* Changes "-hide" configuration option */
408 	graphPtr->flags |= REDRAW_BACKING_STORE;
409 	Blt_EventuallyRedrawGraph(graphPtr);
410     }
411     return TCL_OK;
412 }
413 
414 /*
415  *----------------------------------------------------------------------
416  *
417  * MapOp --
418  *
419  *	Maps or unmaps the grid (off or on).
420  *
421  * Results:
422  *	A standard Tcl result.
423  *
424  * Side Effects:
425  *	Grid attributes are reset and the graph is redrawn if necessary.
426  *
427  *----------------------------------------------------------------------
428  */
429 /*ARGSUSED*/
430 static int
UnmapOp(graphPtr,interp,argc,argv)431 UnmapOp(graphPtr, interp, argc, argv)
432     Graph *graphPtr;
433     Tcl_Interp *interp;
434     int argc;
435     char **argv;
436 {
437     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
438 
439     if (!gridPtr->hidden) {
440 	gridPtr->hidden = TRUE;	/* Changes "-hide" configuration option */
441 	graphPtr->flags |= REDRAW_BACKING_STORE;
442 	Blt_EventuallyRedrawGraph(graphPtr);
443     }
444     return TCL_OK;
445 }
446 
447 /*
448  *----------------------------------------------------------------------
449  *
450  * ToggleOp --
451  *
452  *	Toggles the state of the grid shown/hidden.
453  *
454  * Results:
455  *	A standard Tcl result.
456  *
457  * Side Effects:
458  *	Grid is hidden/displayed. The graph is redrawn at the next
459  *	idle time.
460  *
461  *----------------------------------------------------------------------
462  */
463 /*ARGSUSED*/
464 static int
ToggleOp(graphPtr,interp,argc,argv)465 ToggleOp(graphPtr, interp, argc, argv)
466     Graph *graphPtr;
467     Tcl_Interp *interp;
468     int argc;
469     char **argv;
470 {
471     Grid *gridPtr = (Grid *)graphPtr->gridPtr;
472 
473     gridPtr->hidden = (!gridPtr->hidden);
474     graphPtr->flags |= REDRAW_BACKING_STORE;
475     Blt_EventuallyRedrawGraph(graphPtr);
476     return TCL_OK;
477 }
478 
479 
480 static Blt_OpSpec gridOps[] =
481 {
482     {"cget", 2, (Blt_Op)CgetOp, 4, 4, "option",},
483     {"configure", 2, (Blt_Op)ConfigureOp, 3, 0, "?options...?",},
484     {"off", 2, (Blt_Op)UnmapOp, 3, 3, "",},
485     {"on", 2, (Blt_Op)MapOp, 3, 3, "",},
486     {"toggle", 1, (Blt_Op)ToggleOp, 3, 3, "",},
487 };
488 static int nGridOps = sizeof(gridOps) / sizeof(Blt_OpSpec);
489 
490 /*
491  *----------------------------------------------------------------------
492  *
493  * Blt_GridOp --
494  *
495  *	User routine to configure grid lines.  Grids are drawn
496  *	at major tick intervals across the graph.
497  *
498  * Results:
499  *	The return value is a standard Tcl result.
500  *
501  * Side Effects:
502  *	Grid may be drawn in the plotting area.
503  *
504  *----------------------------------------------------------------------
505  */
506 int
Blt_GridOp(graphPtr,interp,argc,argv)507 Blt_GridOp(graphPtr, interp, argc, argv)
508     Graph *graphPtr;
509     Tcl_Interp *interp;
510     int argc;
511     char **argv;
512 {
513     Blt_Op proc;
514 
515     proc = Blt_GetOp(interp, nGridOps, gridOps, BLT_OP_ARG2, argc, argv, 0);
516     if (proc == NULL) {
517 	return TCL_ERROR;
518     }
519     return (*proc) (graphPtr, interp, argc, argv);
520 }
521