1 /*
2 * $Id: style.i,v 1.1 2005-09-18 22:06:10 dhmunro Exp $
3 * Get and set graphics styles from within the Yorick interpreter.
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 func get_style(&landscape, &systems, &legends, &clegends)
12 /* DOCUMENT get_style, landscape, systems, legends, clegends
13
14 get the detailed style of the current drawing. The arguments
15 are all outputs:
16
17 landscape: 1 if drawing is landscape orientation, 0 if portrait
18 system: an array of GfakeSystem struct instances, one per
19 coordinate system in this drawing (ordinarily just one).
20 legends: a GeLegendBox structure instance describing the layout
21 of the plot legends
22 clegends: a GeLegendBox structure instance describing the layout
23 of the contour legends
24
25 See the help for the GeLegendBox and GpTextAttribs structs for
26 the details of the legends and clegends arguments. Basically,
27 you can adjust the location of the legends on the page, the
28 font and height of the characters used to render legends, and
29 whether the legends are split into two columns.
30
31 The coordinate systems are the systems accessible via the
32 plsys command. The index of the system in the system array is
33 the index you use to switch to it in the plsys command. Simple
34 styles have only one coordinate system, and you should carefully
35 consider whether you should design a graphic style with multiple
36 coordinate systems -- most likely, you can do a better job by
37 combining several separate Yorick pictures with some sort of
38 page layout program, rather than trying to do this work within
39 Yorick itself.
40
41 See the help for the GfakeSystem struct for complete details of
42 what you can adjust. The most interesting features you can
43 control are the location and aspect ratio of the viewport, and
44 the details of the axis ticks and labels. The gridxy function
45 provides a simpler interface for fiddling with ticks and labels
46 if that is all you need. The system.viewport member is the
47 [xmin,xmax,ymin,ymax] of the rectangle on the page where your
48 plots will appear, expressed in NDC coordinates (0.0013 NDC units
49 equals one point, and there are 72.27 points per inch, and 2.54
50 cm per inch; the NDC origin is always at the lower left hand
51 corner of the paper, with x increasing leftward and y increasing
52 upward). If you change the size of the viewport, you will also
53 need to change the parameters of the tick-generating model; like
54 other problems in typography and page layout, this is harder
55 than you might think.
56
57 SEE ALSO: set_style, read_style, write_style
58 */
59 {
60 landscape= [0n];
61 n= raw_style(0, landscape, &[], &[]);
62 if (!n) error, "no current drawing";
63 systems= array(GfakeSystem, n);
64 legends= array(GeLegendBox, 2);
65 raw_style, 0, landscape, &systems, &legends;
66 landscape= landscape(1);
67 clegends= legends(2);
68 legends= legends(1);
69 }
70
set_style(landscape,systems,legends,clegends)71 func set_style(landscape, systems, legends, clegends)
72 /* DOCUMENT set_style, landscape, systems, legends, clegends
73
74 set the detailed style of the current drawing. The arguments
75 are all inputs, having the same meanings as for get_style (which
76 see). All arguments are required, so you may need to call
77 get_style as a starting point, if you only want to make a few
78 changes. See the Y_SITE/g/work.gs and the other .gs files for
79 examples of reasonable values to choose.
80
81 Calling set_style destroys anything that was plotted in the
82 window, like the style= keyword of the window command.
83
84 SEE ALSO: get_style, read_style, write_style
85 */
86 {
87 if (structof(systems)!=GfakeSystem || structof(legends)!=GeLegendBox ||
88 structof(clegends)!=GeLegendBox || numberof(legends)!=1 ||
89 numberof(clegends)!=1 || numberof(landscape)!=1 ||
90 structof(landscape+0)!=long)
91 error, "illegal input data types or sizes";
92 landscape= [int(landscape(1))];
93 raw_style, numberof(systems), landscape, &systems, &[legends,clegends];
94 }
95
96 /* ------------------------------------------------------------------------ */
97
write_style(file,landscape,systems,legends,clegends)98 func write_style(file, landscape, systems, legends, clegends)
99 /* DOCUMENT write_style, file, landscape, systems, legends, clegends
100
101 write a Gist style sheet (.gs file), using the data structures
102 as described in the get_style function. The FILE can be a
103 filename or a text file stream.
104
105 SEE ALSO: get_style, set_style, read_style
106 */
107 {
108 if (structof(file)==string) file= create(file);
109
110 write,file,format="# %s\n",
111 "Gist style sheet made by Yorick write_style function";
112 write,file,format="# Created: %s\n", timestamp();
113 write,file,format="# (%ld coordinate systems)\n\n", numberof(systems);
114
115 write,file,format="landscape= %d\n\n", (landscape!=0);
116
117 for (i=1 ; i<=numberof(systems) ; ++i) {
118 sys= systems(i);
119 if (i==1) {
120 default= sys;
121 which= "default";
122 } else {
123 which= "system";
124 }
125 legend= sys.legend;
126 if (!strlen(legend)) legend= "0";
127 else legend= "\""+legend+"\"";
128 write,file,format="%s= { legend= %s", which, (i>1? legend : "0");
129 final= " }";
130 vp= sys.viewport;
131 if (i==1 || anyof(vp!=default.viewport)) {
132 final= "}";
133 write,file,format=",\n viewport= { %f, %f, %f, %f }",
134 vp(1),vp(2),vp(3),vp(4);
135 }
136 ticks= sys.ticks;
137 if (i==1 || ticks!=default.ticks) {
138 final= "}";
139 write,file,format=",\n%s\n", " ticks= {"
140 axes= [ticks.horiz, ticks.vert];
141 daxes= [default.ticks.horiz, default.ticks.vert];
142 prefix= "\n ";
143 for (j=1 ; j<=2 ; ++j) {
144 axis= axes(j);
145 daxis= daxes(j);
146 if (i==1 || axis!=daxis) {
147 write,file,format="%s%s= {\n", prefix, (j==1? "horiz" : "vert");
148 nitems= 0;
149 prefix= " "; suffix= "";
150 if (i==1 || axis.nMajor!=daxis.nMajor) {
151 write,file,format="%snMajor= %f", prefix, axis.nMajor;
152 prefix= ", "; suffix= " ";
153 ++nitems;
154 }
155 if (i==1 || axis.nMinor!=daxis.nMinor) {
156 write,file,format="%snMinor= %f", prefix, axis.nMinor;
157 prefix= ", "; suffix= " ";
158 ++nitems;
159 }
160 if (i==1 || axis.logAdjMajor!=daxis.logAdjMajor) {
161 write,file,format="%slogAdjMajor= %f", prefix, axis.logAdjMajor;
162 prefix= ", "; suffix= " ";
163 if ((++nitems)==3) {
164 nitems= 0;
165 prefix= ",\n ";
166 }
167 }
168 if (i==1 || axis.logAdjMinor!=daxis.logAdjMinor) {
169 write,file,format="%slogAdjMinor= %f", prefix, axis.logAdjMinor;
170 prefix= ", "; suffix= " ";
171 if ((++nitems)==3) {
172 nitems= 0;
173 prefix= ",\n ";
174 }
175 }
176 if (i==1 || axis.nDigits!=daxis.nDigits) {
177 write,file,format="%snDigits= %d", prefix, axis.nDigits;
178 prefix= ", "; suffix= " ";
179 if ((++nitems)==3) {
180 nitems= 0;
181 prefix= ",\n ";
182 }
183 }
184 if (i==1 || axis.gridLevel!=daxis.gridLevel) {
185 write,file,format="%sgridLevel= %d", prefix, axis.gridLevel;
186 prefix= ", "; suffix= " ";
187 if ((++nitems)==3) {
188 nitems= 0;
189 prefix= ",\n ";
190 }
191 }
192 if (i==1 || axis.flags!=daxis.flags) {
193 write,file,format="%sflags= 0x%03x", prefix, axis.flags;
194 prefix= ", "; suffix= " ";
195 if ((++nitems)==3) {
196 nitems= 0;
197 prefix= ",\n ";
198 }
199 }
200 if (i==1 || axis.tickOff!=daxis.tickOff) {
201 write,file,format="%stickOff= %f", prefix, axis.tickOff;
202 prefix= ", "; suffix= " ";
203 if ((++nitems)==3) {
204 nitems= 0;
205 prefix= ",\n ";
206 }
207 }
208 if (i==1 || axis.labelOff!=daxis.labelOff) {
209 write,file,format="%slabelOff= %f", prefix, axis.labelOff;
210 prefix= ", "; suffix= " ";
211 if ((++nitems)==3) {
212 nitems= 0;
213 prefix= ",\n ";
214 }
215 }
216 if (i==1 || anyof(axis.tickLen!=daxis.tickLen)) {
217 if (prefix!=" ") prefix= ",\n ";
218 _style_wvect, file, prefix, "tickLen", axis.tickLen;
219 prefix= ",\n "; suffix= ""; nitems= 0;
220 }
221 if (i==1 || axis.tickStyle!=daxis.tickStyle) {
222 if (prefix!=" ") prefix= ",\n ";
223 _style_wline, file, prefix, "tickStyle", axis.tickStyle;
224 prefix= ",\n "; suffix= ""; nitems= 0;
225 }
226 if (i==1 || axis.gridStyle!=daxis.gridStyle) {
227 if (prefix!=" ") prefix= ",\n ";
228 _style_wline, file, prefix, "gridStyle", axis.gridStyle;
229 prefix= ",\n "; suffix= ""; nitems= 0;
230 }
231 if (i==1 || axis.textStyle!=daxis.textStyle) {
232 if (prefix!=" ") prefix= ",\n ";
233 _style_wtext, file, prefix, "textStyle", axis.textStyle;
234 prefix= ",\n "; suffix= ""; nitems= 0;
235 }
236 if (i==1 || axis.xOver!=daxis.xOver) {
237 write,file,format="%sxOver= %f", prefix, axis.xOver;
238 prefix= ", "; suffix= " ";
239 if ((++nitems)==3) prefix= ",\n ";
240 }
241 if (i==1 || axis.yOver!=daxis.yOver) {
242 write,file,format="%syOver= %f", prefix, axis.yOver;
243 suffix= " ";
244 }
245 write,file,format="%s}", suffix;
246 prefix= ",\n\n "; suffix= "";
247 }
248 }
249 if (i==1 || ticks.frame!=default.ticks.frame) {
250 write,file,format="%sframe= %d", prefix, ticks.frame;
251 prefix= ",\n "; suffix= " ";
252 }
253 if (i==1 || ticks.frameStyle!=default.ticks.frameStyle) {
254 _style_wline, file, prefix, "frameStyle", ticks.frameStyle;
255 suffix= "";
256 }
257 write,file,format="%s}", suffix;
258 }
259 write,file,format="%s\n", final;
260
261 if (i==1) {
262 write,file,format="\nsystem= { legend= %s }\n", legend;
263 }
264 }
265
266 legs= [legends,clegends];
267 for (i=1 ; i<=2 ; ++i) {
268 leg= legs(i);
269 if (leg.nlines) {
270 write,file,format="\n%slegends= {\n", (i==1? "" : "c");
271 write,file,format=" x= %f, y= %f, dx= %f, dy= %f",
272 leg.x, leg.y, leg.dx, leg.dy;
273 _style_wtext, file, ",\n ", "textStyle", leg.textStyle;
274 write,file,format=",\n nchars= %d, nlines= %d, nwrap= %d }\n",
275 leg.nchars, leg.nlines, leg.nwrap;
276 } else {
277 write,file,format="\n%slegends= { nlines= 0 }\n", (i==1? "" : "c");
278 }
279 }
280
281 return file;
282 }
283
_style_wvect(file,prefix,member,value)284 func _style_wvect(file, prefix, member, value)
285 {
286 write,file,format="%s%s= {", prefix, member;
287 prefix= " ";
288 for (i=1 ; i<=numberof(value) ; ++i) {
289 write,file,format="%s%f", prefix, value(i);
290 prefix= ", ";
291 }
292 write,file,format="%s}", " ";
293 }
294
_style_wline(file,prefix,member,style)295 func _style_wline(file, prefix, member, style)
296 {
297 write,file,format="%s%s= { color= %d, type= %d, width= %f }",
298 prefix, member, style.color, style.type, style.width;
299 }
300
_style_wtext(file,prefix,member,style)301 func _style_wtext(file, prefix, member, style)
302 {
303 write,file,format="%s%s= { color= %d, font= 0x%02x, height= %f",
304 prefix, member, style.color, style.font, style.height;
305 if (strpart(prefix,1:1)!=",") {
306 if (strpart(prefix,1:1)!="\n") prefix= ",\n"+prefix;
307 else prefix= ","+prefix;
308 }
309 write,file,format="%s orient= %d, alignH= %d, alignV= %d, opaque= %d }",
310 prefix, style.orient, style.alignH, style.alignV, style.opaque;
311 }
312
313 func read_style(file, &landscape, &systems, &legends, &clegends)
314 /* DOCUMENT read_style, file, landscape, systems, legends, clegends
315
316 read a Gist style sheet (.gs file), and return the data
317 structures as described in the get_style function. The FILE
318 can be a filename or a text file stream.
319
320 SEE ALSO: get_style, set_style, write_style
321 */
322 {
323 if (structof(file)==string) {
324 f= open(file, "r", 1);
325 if (!f) {
326 /* maybe the file is in one of the standard locations */
327 f= open("~/gist/"+file, "r", 1);
328 if (!f) {
329 f= open("~/Gist/"+file, "r", 1);
330 if (!f) {
331 f= open(Y_SITE+"g/"+file, "r", 1);
332 if (!f) error, "missing style file: "+file;
333 }
334 }
335 }
336 } else {
337 f= file;
338 }
339
340 /* set up default values (same as work.gs) */
341 landscape= 0n;
342 default_line= GpLineAttribs(color= 254, type= 1, width= 1.0);
343 default_text= GpTextAttribs(
344 color= 254, font= 0x08, height= 0.0182,
345 orient= 0, alignH= 0, alignV= 0, opaque= 0);
346 default_ltxt= GpTextAttribs(
347 color= 254, font= 0x00, height= 0.0156,
348 orient= 0, alignH= 1, alignV= 1, opaque= 0);
349 default= GfakeSystem(viewport=[0.19, 0.60, 0.44, 0.85],
350 ticks= GaTickStyle(
351 horiz= GaAxisStyle(
352 nMajor=7.5, nMinor=50.0, logAdjMajor=1.2, logAdjMinor=1.2,
353 nDigits=3, gridLevel=1, flags=0x033, tickOff=0.0007, labelOff=0.0182,
354 tickLen= [0.0143, 0.0091, 0.0052, 0.0026, 0.0013],
355 tickStyle= default_line,
356 gridStyle= GpLineAttribs(color= 254, type= 3, width= 1.0),
357 textStyle= default_text,
358 xOver= 0.395, yOver= 0.370),
359 vert= GaAxisStyle(
360 nMajor=7.5, nMinor=50.0, logAdjMajor=1.2, logAdjMinor=1.2,
361 nDigits=3, gridLevel=1, flags=0x033, tickOff=0.0007, labelOff=0.0182,
362 tickLen= [0.0143, 0.0091, 0.0052, 0.0026, 0.0013],
363 tickStyle= default_line,
364 gridStyle= GpLineAttribs(color= 254, type= 3, width= 1.0),
365 textStyle= default_text,
366 xOver= 0.150, yOver= 0.370),
367 frame= 0,
368 frameStyle= GpLineAttribs(color= 254, type= 1, width= 1.0)));
369 default_legb= GeLegendBox(
370 x= 0.04698, y= 0.360, dx= 0.3758, dy= 0.0,
371 textStyle= default_ltxt, nchars= 36, nlines= 20, nwrap= 2);
372 default_clegb= GeLegendBox(
373 x= 0.6182, y= 0.8643, dx= 0.0, dy= 0.0,
374 textStyle= default_ltxt, nchars= 14, nlines= 28, nwrap= 1);
375 legends= default_legb;
376 clegends= default_clegb;
377
378 /* parse the file */
379 systems= [];
380 type= [];
381 line= "";
382 for (;;) {
383 s= _style_token(f, line, type);
384 if (!line) break;
385 if (type!=3) _style_goof, f, line, s;
386 if (s=="landscape") {
387 landscape= _style_token(f, line, type);
388 if (type!=2 || structof(landscape)!=long)
389 _style_goof, f, line, "landscape= ????";
390 landscape= (landscape!=0);
391 } else if (s=="default") {
392 default= _style_system(f, line, default);
393 } else if (s=="system") {
394 grow, systems, [_style_system(f, line, default)];
395 } else if (s=="legends") {
396 legends= _style_legends(f, line, default_legb);
397 } else if (s=="clegends") {
398 clegends= _style_legends(f, line, default_clegb);
399 } else {
400 _style_goof, f, line, s;
401 }
402 }
403
404 if (is_void(systems)) systems= [default];
405 }
406
407 func _style_system(f, &line, default)
408 {
409 system= default;
410 type= [];
411 s= _style_token(f, line, type);
412 if (s!="{") _style_goof, f, line, s;
413 for (;;) {
414 s= _style_token(f, line, type);
415 if (type!=3) _style_goof, f, line, s;
416 if (s=="legend") {
417 s= _style_token(f, line, type);
418 if (type!=1) {
419 if (type==2 && s==0) s= string(0);
420 else _style_goof, f, line, s;
421 }
422 system.legend= s;
423 } else if (s=="viewport") {
424 system.viewport= _style_vector(f,line);
425 } else if (s=="ticks") {
426 system.ticks= _style_ticks(f,line,system.ticks);
427 } else {
428 _style_goof, f, line, s;
429 }
430 s= _style_token(f, line, type);
431 if (s=="}") break;
432 if (s!=",") _style_goof, f, line, s;
433 }
434 return system;
435 }
436
437 func _style_legends(f, &line, default)
438 {
439 legend= default;
440 type= [];
441 s= _style_token(f, line, type);
442 if (s!="{") _style_goof, f, line, s;
443 for (;;) {
444 s= _style_token(f, line, type);
445 if (type!=3) _style_goof, f, line, s;
446 if (s=="textStyle")
447 get_member(legend,s)= _style_text(f,line,default.textStyle);
448 else
449 get_member(legend,s)= _style_token(f,line,type);
450 s= _style_token(f, line, type);
451 if (s=="}") break;
452 if (s!=",") _style_goof, f, line, s;
453 }
454 return legend;
455 }
456
457 func _style_ticks(f, &line, default)
458 {
459 ticks= default;
460 type= [];
461 s= _style_token(f, line, type);
462 if (s!="{") _style_goof, f, line, s;
463 for (;;) {
464 s= _style_token(f, line, type);
465 if (type!=3) _style_goof, f, line, s;
466 if (s=="horiz" || s=="vert") {
467 get_member(ticks,s)= _style_axis(f,line,get_member(ticks,s));
468 } else if (s=="frame") {
469 ticks.frame= _style_token(f,line,type);
470 } else if (s=="frameStyle") {
471 ticks.frameStyle= _style_line(f,line,ticks.frameStyle);
472 } else {
473 _style_goof, f, line, s;
474 }
475 s= _style_token(f, line, type);
476 if (s=="}") break;
477 if (s!=",") _style_goof, f, line, s;
478 }
479 return ticks;
480 }
481
482 func _style_axis(f, &line, default)
483 {
484 axis= default;
485 type= [];
486 s= _style_token(f, line, type);
487 if (s!="{") _style_goof, f, line, s;
488 for (;;) {
489 s= _style_token(f, line, type);
490 if (type!=3) _style_goof, f, line, s;
491 if (s=="tickLen") {
492 value= _style_vector(f, line);
493 axis.tickLen(1:numberof(value))= value;
494 } else if (s=="tickStyle" || s=="gridStyle") {
495 get_member(axis,s)= _style_line(f,line,get_member(axis,s));
496 } else if (s=="textStyle") {
497 axis.textStyle= _style_text(f,line,axis.textStyle);
498 } else {
499 get_member(axis,s)= _style_token(f,line,type);
500 }
501 s= _style_token(f, line, type);
502 if (s=="}") break;
503 if (s!=",") _style_goof, f, line, s;
504 }
505 return axis;
506 }
507
508 func _style_vector(f, &line)
509 {
510 vector= type= [];
511 s= _style_token(f, line, type);
512 if (s!="{") _style_goof, f, line, s;
513 for (;;) {
514 s= _style_token(f, line, type);
515 if (type!=2) _style_goof, f, line, s;
516 grow, vector, [double(s)];
517 s= _style_token(f, line, type);
518 if (s=="}") break;
519 if (s!=",") _style_goof, f, line, s;
520 }
521 return vector;
522 }
523
524 func _style_text(f, &line, default)
525 {
526 junk= [0.0];
527 text= default;
528 type= [];
529 s= _style_token(f, line, type);
530 if (s!="{") _style_goof, f, line, s;
531 for (;;) {
532 s= _style_token(f, line, type);
533 if (type!=3) _style_goof, f, line, s;
534 if (text=="path") text= "orient";
535 if (noneof(text==["expand","spacing","upX","upY"]))
536 get_member(text,s)= _style_token(f,line,type);
537 else
538 junk(1)= _style_token(f,line,type);
539 s= _style_token(f, line, type);
540 if (s=="}") break;
541 if (s!=",") _style_goof, f, line, s;
542 }
543 if (text.color < 0) text.color += 256;
544 return text;
545 }
546
547 func _style_line(f, &line, default)
548 {
549 style= default;
550 type= [];
551 s= _style_token(f, line, type);
552 if (s!="{") _style_goof, f, line, s;
553 for (;;) {
554 s= _style_token(f, line, type);
555 if (type!=3) _style_goof, f, line, s;
556 get_member(style,s)= _style_token(f,line,type);
557 s= _style_token(f, line, type);
558 if (s=="}") break;
559 if (s!=",") _style_goof, f, line, s;
560 }
561 if (style.color < 0) style.color += 256;
562 return style;
563 }
564
565 /* retrieve next token from file, updating current line
566 -- set line to "" initially
567 -- on output, type= 0 is delimiter, 1 is quoted, 2 is number, 3 keyword
568 */
569 func _style_token(f, &line, &type, norecurse)
570 {
571 s= "";
572 for (;;) {
573 /* give up if no more lines in file */
574 if (!line) return line;
575 /* remove leading whitespace */
576 sread, line, s, format="%[ \t]";
577 line= strpart(line, 1+strlen(s):0);
578 /* stop if line has more chars, and is not a comment */
579 if (strlen(line)) {
580 s= strpart(line,1:1);
581 if (s!="#") break;
582 }
583 /* otherwise get the next line and try again */
584 line= rdline(f);
585 }
586
587 /* look at first character to see if this is a delimiter */
588 cs= (*pointer(s))(1);
589 if (anyof(['{','}',',','=']==cs)) {
590 /* token is one of the four valid delimiters */
591 line= strpart(line,2:0);
592 type= 0;
593 return string(&[cs,'\0']);
594 } else if (cs=='"') {
595 /* token is a quoted string */
596 s= strtok(line, "\"");
597 type= 1;
598 line= s(2);
599 return s(1);
600 }
601
602 /* token must be either a number or a keyword */
603 s= strtok(line, " \t{},=")(1);
604 line= strpart(line, strlen(s)+1:0);
605 if ((cs>='0' && cs<='9') || cs=='.' || cs=='-') {
606 /* token is a number */
607 if (strmatch(s,".") || strmatch(s,"e",1)) {
608 value= 0.0;
609 if (!sread(s,value)) _style_goof, f, line, s;
610 } else {
611 value= 0;
612 if (!sread(s,value,format="%i")) _style_goof, f, line, s;
613 }
614 type= 2;
615 return value;
616 } else {
617 /* if next token is =, this token is a keyword */
618 if (!norecurse) next= _style_token(f, line, type, 1);
619 if (type==0 && next=="=") {
620 type= 3;
621 return s;
622 } else {
623 _style_goof, f, line, s;
624 }
625 }
626 }
627
_style_goof(f,line,s)628 func _style_goof(f, line, s)
629 {
630 write, "graphics style file format error at or just before:";
631 write, print(f)(2);
632 error, "unrecognized token: "+pr1(s);
633 }
634
635 /* ------------------------------------------------------------------------ */
636 /* The following structure definitions must match those in
637 Gist/gist.h and Gist/draw.h */
638
639 /* Note: NDC units 0.0013 equals one point equals 1/72.27 inch */
640 one_point= 0.0013;
641 one_inch= 72.27*one_point;
642
643 struct GpLineAttribs {
644 long color; /* 255=bg 254=fg 253=b 252=w ...=rgb ...=cmy */
645 int type; /* line types: 0=none 1=solid 2=- 3=. 4=-. 5=-.. */
646 double width; /* 1.0 is normal width of a line (1/2 point) */
647 }
648
649 struct GpTextAttribs {
650 long color; /* 255=bg 254=fg 253=b 252=w ...=rgb ...=cmy */
651 int font; /* text font
652 fonts: 0=courier 4=times 8=helvetica 12=symbol
653 16=newcentury
654 or with 1 for bold, 2 for italic */
655 double height; /* character height in NDC, default 0.0156 (12pt)
656 UNLIKE GKS, GIST font sizes are always specified
657 in NDC. This drastically simplifies coding for
658 devices like X windows, which must load a font
659 at each size. It also conforms better with
660 a Mac-like user interface in which font size
661 in points is selected by the user. */
662 int orient; /* text orientation: 0=right 1=left 2=up 3=down */
663 int alignH, alignV; /* text alignments:
664 alignH: 0=normal 1=left 2=center 3=right
665 alignV: 0=normal 1=top 2=cap 3=half 4=base 5=bot */
666
667 int opaque;
668 }
669
670 struct GaAxisStyle {
671 double nMajor, nMinor, logAdjMajor, logAdjMinor;
672 int nDigits, gridLevel;
673 int flags; /* 0x001 ticks on lower edge
674 0x002 ticks on upper edge
675 0x004 ticks in center
676 0x008 inward ticks
677 0x010 outward ticks
678 0x020 labels on lower edge
679 0x040 labels on upper edge
680 0x080 full grid lines
681 0x100 origin grid line */
682
683 double tickOff, labelOff; /* offsets in NDC from the edge of the
684 viewport to the ticks or labels */
685 double tickLen(5); /* tick lengths in NDC */
686
687 GpLineAttribs tickStyle, gridStyle;
688 GpTextAttribs textStyle; /* alignment ignored, set correctly */
689 double xOver, yOver; /* position for overflow label */
690 }
691
692 struct GaTickStyle {
693 GaAxisStyle horiz, vert;
694 int frame;
695 GpLineAttribs frameStyle;
696 }
697
698 struct GeLegendBox {
699 double x, y; /* NDC location of this legend box */
700 double dx, dy; /* if non-zero, offset to 2nd column */
701 GpTextAttribs textStyle; /* font, size, etc. of these legends */
702 int nchars, nlines; /* max number of characters per line, lines */
703 int nwrap; /* max number of lines to wrap long legends */
704 }
705
706 struct GfakeSystem {
707 double viewport(4); /* [xmin,xmax,ymin,ymax] in NDC coordinates */
708 GaTickStyle ticks; /* tick style for this coordinate system */
709 string legend; /* e.g.- "System 0" or "System 1" */
710 }
711
712 /* ------------------------------------------------------------------------ */
713