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