Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / mif.trm
1 /* Hello, Emacs, this is -*-C-*-
2  * $Id: mif.trm,v 1.33 2006/07/21 02:35:47 sfeam Exp $
3  */
4
5 /* GNUPLOT -- mif.trm */
6
7 /*[
8  * Copyright 1992, 1993, 1998, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * This file is included by ../term.c.
39  *
40  * This terminal driver was developed for
41  *      gnuplot for unix version 3.0 (patchlevel 1)
42  *      gnuplot for unix version 3.2 (patchlevel 2)
43  *
44  * This terminal driver supports:
45  *      Frame Maker MIF format version 3.00
46  *
47  * Options for this terminal driver (set terminal mif [options]):
48  *      colour /        Draw primitives with line types >= 0 in colour (sep. 2-7)
49  *      monochrome      Draw primitives in black (sep. 0)
50  *
51  *      polyline /      Draw lines as continuous curves
52  *      vectors         Draw lines as collections of vectors
53  *
54  *      help / ?        Print short usage description on stderr
55  *
56  * Properties for this terminal driver:
57  *     -Gnuplot size of worksheet:              MIF_XMAX * MIF_YMAX
58  *     -Unit in MIF output:                     cm
59  *     -Plot primitives with the same pen will
60  *      be grouped in the same MIF group.
61  *     -Plot primitives with line types >= 0
62  *      will as default be drawn in colour.
63  *     -Lines are plotted as collections of
64  *      vectors, or as continuous lines (default)
65  *     -Plot primitives in a plot will be in a
66  *      Frame in MIF. Several plot Frames will
67  *      be collected in one large Frame.
68  *     -Point size of MIF output characters:    MIF_PSIZE
69  *     -Used font for MIF output characters:    Times
70  *     -Supports vertical text
71  *     -points and dots as characters
72  *     -character formats for TextLines
73  *
74  * AUTHORS:
75  *      Olof Franksson, Physics IV, KTH, S-100 44 Stockholm, Sweden
76  *
77  * NEW TERMINAL FORMAT:  David C. Schooley
78
79  * COMMENTS:
80  *      Send comments and/or suggestions to olof@fysik4.kth.se
81  *
82  * CHANGES:
83  *      Changed to new terminal format 9/29/95          schooley@ee.gatech.edu
84  *      Changed order of routine declarations.          olof@fysik4.kth.se
85  *      Changed mechanism for pen pattern selection.    kssingvo@immd4.informatik.uni-erlangen.de
86  *      Support for vertical text.                      kssingvo@immd4.informatik.uni-erlangen.de
87  *      Fixed plot bug for "set size XS,YS", XS/YS > 1. olof@fysik4.kth.se
88  *      Support colored text                            merritt@u.washington.edu
89  *      Support box fill and pattern fill               merritt@u.washington.edu
90  *
91  */
92
93 #include "driver.h"
94
95 #ifdef TERM_REGISTER
96 register_term(mif)
97 #endif
98
99
100
101 #ifdef TERM_PROTO
102 TERM_PUBLIC void MIF_init __PROTO((void));
103 TERM_PUBLIC void MIF_graphics __PROTO((void));
104 TERM_PUBLIC void MIF_text __PROTO((void));
105 TERM_PUBLIC void MIF_linetype __PROTO((int linetype));
106 TERM_PUBLIC void MIF_move __PROTO((unsigned int x, unsigned int y));
107 TERM_PUBLIC void MIF_vector __PROTO((unsigned int x, unsigned int y));
108 TERM_PUBLIC void MIF_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
109 TERM_PUBLIC int MIF_text_angle __PROTO((int ang));
110 TERM_PUBLIC void MIF_reset __PROTO((void));
111 TERM_PUBLIC void MIF_options __PROTO((void));
112 TERM_PUBLIC int MIF_justify_text __PROTO((enum JUSTIFY mode));
113 TERM_PUBLIC void MIF_point __PROTO((unsigned int x, unsigned int y, int number));
114 TERM_PUBLIC void MIF_boxfill __PROTO((int style, unsigned int x1, unsigned int y1,
115             unsigned int width, unsigned int height));
116 TERM_PUBLIC void MIF_filled_polygon __PROTO((int points, gpiPoint* corners));
117
118 /** Coordinates **/
119 /* The cast to float is not necessary because we are dividing by a float */
120 /* On OSK the cast to a float is not allowed in a constant expression wich */
121 /* is used by the declaration and initialization of mif_line */
122 /* Converts gnuplot units to MIF units */
123 #define GNP_TO_MIF(P)   ((P) / 1000.0)
124 /* Basic unit: 0.01 mm (15cm -> 15*10*100=15000) */
125 #define MIF_XMAX 15000
126 /* Basic unit: 0.01 mm (10cm -> 10*10*100=10000) */
127 #define MIF_YMAX 10000
128
129 #define MIF_XLAST (MIF_XMAX - 1)
130 #define MIF_YLAST (MIF_YMAX - 1)
131
132 static int insert_mif_line __PROTO((double fx, double fy));
133 static int proc_group_id __PROTO((int group_id));
134 static void free_mif_line __PROTO((void));
135 static void put_mif_line __PROTO((void));
136 static void MIF_set_font __PROTO((const char *));
137 static void mif_put_point __PROTO((unsigned int x, unsigned int y, int np));
138
139 #endif
140
141 #ifndef TERM_PROTO_ONLY
142 #ifdef TERM_BODY
143
144 #ifndef cfree
145 # define cfree free
146 #endif
147
148 static struct mif_line {        /* Line point structure specification */
149     float fpos_x;               /* Line point X coordinate */
150     float fpos_y;               /*            Y coordinate */
151     struct mif_line *next;      /* Pointer to next line point */
152     struct mif_line *prev;      /* Pointer to previous line point */
153 } mif_line =
154 {                               /* Current position structure. Adjust for orign. Local for this file. */
155     GNP_TO_MIF(0),
156         GNP_TO_MIF(MIF_YLAST),
157         &mif_line,
158         &mif_line
159 };
160
161 /** Characters **/
162 #define MIF_PSIZE 9             /* Point size of used characters */
163
164 #define MIF_VCHAR (MIF_YMAX/31) /* Distance between rows (a guess) */
165 #define MIF_HCHAR (MIF_XMAX/95) /* Distance between characters (a guess) */
166
167 /** Scale marks **/
168 #define MIF_VTIC  (MIF_YMAX/150)        /* Size of scale mark (vert) */
169 #define MIF_HTIC  (MIF_XMAX/225)        /* Size of scale mark (hor) */
170
171 /** Drawing properties **/
172 static char mif_justify[64];    /* How to justify the used text */
173 static char mif_pen[64], mif_pen_width[64], mif_separation[64];         /* How to plot */
174 static char mif_textcolor[64];  /* EAM parallels separation */
175
176 static int mif_text_ang = 0;            /* Rotation angle of text */
177
178 static int mif_fill_patterns[] = {7,12,3,0,9,8,14,13};
179 #define MIF_FILL_SOLID  0
180 #define MIF_FILL_NONE  15
181
182 #define MIF_NPENS 16            /* Number of MIF pen types */
183 static int mif_pentype = 0;     /* Pen type to use. Also used to create groups for graphics */
184 #define MIF_PEN_TO_GROUP(P)     ( 1 + (P) )     /* Map pen type to group number. Must be >= 1 */
185
186 static int mif_pattern_table[MIF_NPENS] =
187 { /* Table, which pattern should be used for drawing */
188     0,                          /* border  */
189     1,                          /* not used */
190     2, 3, 4, 8, 12, 13,         /* other lines: functions, data, ... (5 is used for grid; 6,7 is (nearly) invisible) */
191     5,                          /* grid */
192     9, 10, 11, 12, 13, 14, 15   /* not used */
193 };
194
195 /** MIF groups administration **/
196 #define MIF_NGROUP_ID           20
197 static struct mif_group_id {
198     int group_existance;
199 /* This group id should generate a MIF group */
200 #define MIF_GROUP_EXISTS        1
201 /* This group id should not generate a MIF group */
202 #define MIF_GROUP_NOT_EXISTS    0
203
204     int group_id;
205 #define MIF_INVALID_GROUP_ID    0       /* An invalid MIF group ID */
206
207 } mif_group_id[MIF_NGROUP_ID];  /* List of used group ID:s and corresponding MIF groups existance */
208
209 /** Semaphores **/
210 static int mif_initialized = 0; /* != 0 when output is active */
211 static int mif_in_frame = 0;    /* != 0 when inside a plot frame */
212 static int mif_frameno = -1;    /* Current frame number */
213 static int mif_colour = TRUE;   /* == TRUE when colour should be used */
214 static int mif_polyline = TRUE; /* == TRUE when lines are drawn as continuous curves */
215
216 struct mpt {                    /* point definition structure */
217     int chr;                    /* character for point */
218     float x_offset, y_offset;   /* offset for vertical positioning */
219     char *font;                 /* font */
220 };
221
222 static char zgnuplot[] = "ZGnuplot"; /* character formats */
223 static char zgnuplotp[] = "ZGnuplotP";
224 static char zgnuplotd[] = "ZGnuplotD";
225 static const char *mif_font = NULL; /* actual character format */
226
227 static struct mpt mpt[POINT_TYPES + 1] =
228 {                               /* point definition data */
229     {'.', 0.000, 0.005, zgnuplotd, /* dot */ },
230
231     {'G', 0.002, 0.084, zgnuplotp, /* diamond */ },
232     {';', 0.002, 0.084, zgnuplotp, /* plus */ },
233     {'n', 0.002, 0.084, zgnuplotp, /* box */ },
234     {'5', 0.002, 0.084, zgnuplotp, /* X */ },
235     {'s', 0.002, 0.062, zgnuplotp, /* triangle */ },
236     {'K', 0.005, 0.075, zgnuplotp, /* star */ },
237 };
238
239 /* diamond is offset 0, dot is offset -1 */
240 static struct mpt *mif_point = &(mpt[1]);
241
242
243 /** Declaration of routine/s for internal use **/
244 static int insert_mif_line __PROTO((double fx, double fy));
245 static int proc_group_id __PROTO((int group_id));
246
247 enum MIF_id {
248     MIF_MONOCHROME, MIF_COLOR, MIF_VECTORS, MIF_POLYLINE, MIF_HELP,
249     MIF_OTHER
250 };
251
252 static struct gen_table MIF_opts[] =
253 {
254     { "m$onochrome", MIF_MONOCHROME },
255     { "c$olor", MIF_COLOR },
256     { "c$olour", MIF_COLOR },
257     { "v$ectors", MIF_VECTORS },
258     { "p$olyline", MIF_POLYLINE },
259     { "h$elp", MIF_HELP },
260     { "?$", MIF_HELP },
261     { NULL, MIF_OTHER }
262 };
263
264 /** Routine/s **/
265
266 /* Called when this terminal type is set in order to parse options */
267 TERM_PUBLIC void
268 MIF_options()
269 {
270     while (!END_OF_COMMAND) {
271         switch(lookup_table(&MIF_opts[0],c_token)) {
272         /* Colour options */
273         case MIF_MONOCHROME:
274             mif_colour = FALSE;
275             c_token++;
276             break;
277         case MIF_COLOR:
278             mif_colour = TRUE;
279             c_token++;
280             break;
281         /* Curve options */
282         case MIF_VECTORS:
283             mif_polyline = FALSE;
284             c_token++;
285             break;
286         case MIF_POLYLINE:
287             mif_polyline = TRUE;
288             c_token++;
289             break;
290         /* Short help */
291         case MIF_HELP:
292         case MIF_OTHER:
293         default:
294             fprintf(stderr, "\
295 Usage: set terminal mif [options]\n\
296 \toptions:\n\
297 \t\tcolour /        Draw primitives with line types >= 0 in colour (sep. 2-7)\n\
298 \t\tmonochrome      Draw primitives in black (sep. 0)\n\n\
299 \t\tpolyline /      Draw lines as continuous curves\n\
300 \t\tvectors         Draw lines as collections of vectors\n\n\
301 \t\thelp / ?        Print short usage description on stderr\n");
302             c_token++;
303             break;
304         }
305     }
306     sprintf(term_options, "%s %s",
307             (mif_colour == TRUE) ? "colour" : "monochrome",
308             (mif_polyline == TRUE) ? "polyline" : "vectors");
309 }
310
311 /* Deallocate the used line structure elements */
312 static void
313 free_mif_line()
314 {
315     struct mif_line *tline;
316
317     while (mif_line.prev != &mif_line) {
318         /* Unlink */
319         tline = mif_line.prev;
320         mif_line.prev = mif_line.prev->prev;
321         mif_line.prev->next = &mif_line;
322
323         /* Deallocate */
324         free(tline);
325     }
326
327     /* Make sure that the list will be empty */
328     mif_line.prev = &mif_line;
329     mif_line.next = &mif_line;
330 }
331
332 /* Draw the pending line. Change current position. */
333 static void
334 put_mif_line()
335 {
336     int np, i;
337     struct mif_line *tline;
338
339     /* Process if inside a Frame */
340     if (mif_initialized != 0 && mif_in_frame != 0) {
341
342         /* Count the number of available points */
343         for (tline = mif_line.next, np = 1; tline != &mif_line; tline = tline->next, np++);
344
345         /* Draw line (at least two points) */
346         if (np >= 2) {
347
348             /* Line preamble */
349             fprintf(gpoutfile, "\t<PolyLine <GroupID %d> %s %s %s <Fill 15>\n",
350                     MIF_PEN_TO_GROUP(mif_pentype), mif_pen, mif_pen_width, mif_separation);
351
352             /* Draw the line elements */
353             fprintf(gpoutfile, "\t\t<NumPoints %d> ", np);
354             for (i = 0, tline = &mif_line; i < np; i++, tline = tline->next) {
355                 if (i % 4 == 0)
356                     fputs("\n\t\t", gpoutfile);
357                 fprintf(gpoutfile, "<Point  %.3f %.3f> ",
358                         tline->fpos_x, tline->fpos_y);
359             }
360
361             /* Line post amble */
362             fputs("\n\t>\n", gpoutfile);
363
364             /* Register the used group ID */
365             proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
366
367             /* Avoid to redraw this. The MIF system should remember it. */
368             mif_pen[0] = '\0';
369             mif_pen_width[0] = '\0';
370             mif_separation[0] = '\0';
371
372             /* Move current position to end of line */
373             mif_line.fpos_x = mif_line.prev->fpos_x;
374             mif_line.fpos_y = mif_line.prev->fpos_y;
375
376             /* Restore the line */
377             free_mif_line();
378         }
379     }                           /* Line processed */
380 }
381
382 /* Filled box support - Ethan Merritt <merritt@u.washington.edu> */
383 TERM_PUBLIC void
384 MIF_boxfill(int style, unsigned int x1, unsigned int y1,
385             unsigned int width, unsigned int height)
386 {
387     int fill_pattern;
388
389     int fillpar = style >> 4;
390     style &= 0xf;
391     switch (style) {
392         default:
393         case FS_EMPTY:  fill_pattern = 7;
394                         break;
395         case FS_SOLID:  fill_pattern = MIF_FILL_SOLID;
396                         break;
397         case FS_PATTERN:fill_pattern = mif_fill_patterns[fillpar % 8];
398                         break;
399     }
400
401     /* Object preamble */
402     fprintf(gpoutfile, "\t<Rectangle <GroupID %d> %s\n",
403             MIF_PEN_TO_GROUP(mif_pentype), mif_separation);
404
405     /* Set fill type */
406     fprintf(gpoutfile, "\t\t<Fill %d>\n", fill_pattern);
407
408     /* Draw the box */
409     fprintf(gpoutfile, "\t\t<ShapeRect %.3f %.3f %.3f %.3f>\n",
410         GNP_TO_MIF(x1), GNP_TO_MIF(MIF_YLAST - (y1+height)),
411         GNP_TO_MIF(width), GNP_TO_MIF(height));
412
413     /* End of object */
414     fputs("\n\t>\n", gpoutfile);
415
416     /* Register the used group ID */
417     proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
418
419 }
420
421 /* Filled polygon. Ethan Merritt <merritt@u.washington.edu> */
422 TERM_PUBLIC void
423 MIF_filled_polygon(int points, gpiPoint* corners)
424 {
425     int i;
426
427     /* Object preamble */
428     fprintf(gpoutfile, "\t<Polygon <GroupID %d>\n",
429             MIF_PEN_TO_GROUP(mif_pentype));
430
431     /* Set fill type */
432     fprintf(gpoutfile, "\t\t<Fill %d>\n", MIF_FILL_SOLID);
433
434     /* Draw the line elements */
435     fprintf(gpoutfile, "\t\t<NumPoints %d> ", points);
436     for (i=0; i<points; i++) {
437         fprintf(gpoutfile, "<Point  %.3f %.3f> ",
438                 GNP_TO_MIF(corners[i].x),
439                 GNP_TO_MIF(MIF_YLAST - corners[i].y));
440     }
441
442     /* End of object */
443     fputs("\n\t>\n", gpoutfile);
444
445     /* Register the used group ID */
446     proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
447
448 }
449
450 /* Draw a point */
451 static void
452 mif_put_point(unsigned int x, unsigned int y, int np)
453 {
454     /* Process if inside a Frame */
455     if (mif_initialized != 0 && mif_in_frame != 0) {
456
457         /* Draw pending line */
458         if (mif_polyline == TRUE)
459             put_mif_line();
460
461         /* Adjust current position for text-graphics alignment */
462         MIF_move(x, y);
463
464         /* center text */
465         MIF_justify_text(CENTRE);
466
467         /* Draw the point */
468         fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s\n",
469                 MIF_PEN_TO_GROUP(mif_pentype),
470                 mif_textcolor);
471
472         MIF_set_font(mif_point[np].font);
473
474         fprintf(gpoutfile, "\t\t<TLOrigin  %.3f %.3f> %s <String `%c'>\n",
475                 mif_line.fpos_x + mif_point[np].x_offset,
476                 mif_line.fpos_y + mif_point[np].y_offset,
477                 mif_justify,
478                 mif_point[np].chr);
479         fputs("\t>\n", gpoutfile);
480
481         /* Register the used group ID */
482         proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
483
484         /* Avoid to redraw this. The MIF system should remember it. */
485         mif_justify[0] = '\0';
486
487     }                           /* Point processed */
488 }
489
490
491 /*
492  *  draw points
493  */
494 TERM_PUBLIC void
495 MIF_point(unsigned int x, unsigned int y, int number)
496 {
497     if (number < 0) {           /* dot */
498         number = -1;
499     } else {                    /* point */
500         number %= POINT_TYPES;
501     }
502     mif_put_point(x, y, number);
503 }
504
505
506 /* Set up a MIF output file */
507 TERM_PUBLIC void
508 MIF_init()
509 {
510     int i;
511
512     /* Process if not inside a MIF file and Frame */
513     if (mif_initialized == 0 && mif_in_frame == 0) {
514         /* Tell this terminal driver that the output is initialized and
515          * no current frames are processed */
516         mif_initialized = 1;
517         mif_in_frame = 0;
518
519         /* Reset internal position */
520         free_mif_line();
521         mif_line.fpos_x = GNP_TO_MIF(0);
522         mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
523
524         /* Reset drawing properties strings */
525         mif_pen[0] = '\0';
526         mif_pen_width[0] = '\0';
527         mif_separation[0] = '\0';
528
529         MIF_justify_text(LEFT);
530
531         /* Reset group ID generator */
532         for (i = 0; i < MIF_NGROUP_ID; i++) {
533             mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
534             mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
535         }
536
537         /* Identify ourselves */
538         /*bs show borders */
539         /* Setup a default environment to use */
540         fprintf(gpoutfile, "\
541 <MIFFile 3.00> # Generated by gnuplot version %s patchlevel %s; identifies this as a MIF file\n\
542 #\n\
543 # show borders\n\
544 <Document\n<DBordersOn Yes>\n>\n\
545 # Set a default pen pattern, pen width, unit and font for subsequent objects\n\
546 <Pen 0>\n\
547 <Fill 15>\n\
548 <PenWidth 0.5 pt>\n\
549 <Separation 0>\n\
550 <Units Ucm>\n\
551 <FontCatalog\n\
552 \t<Font <FTag `%s'><FFamily `Times'><FSize %d><FPlain Yes>>\n\
553 \t<Font <FTag `%s'><FFamily `ZapfDingbats'><FSize 7.0 pt><FPlain Yes>>\n\
554 \t<Font <FTag `%s'><FFamily `Symbol'><FSize 5.0 pt><FPlain Yes>>\n\
555 >\n\
556 #\n",
557                 gnuplot_version, gnuplot_patchlevel,
558                 zgnuplot, MIF_PSIZE,
559                 zgnuplotp,
560                 zgnuplotd);
561     }                           /* MIF file created */
562 }
563
564 /* Finish of a MIF output file */
565 TERM_PUBLIC void
566 MIF_reset()
567 {
568     /* Process if inside a MIF file and not inside a Frame */
569     if (mif_initialized != 0 && mif_in_frame == 0) {
570         /* Finish off the MIF file */
571         fputs("\
572 #\n\
573 # End of MIFFile\n", gpoutfile);
574
575         /* Tell this terminal driver that the output is finished */
576         mif_initialized = 0;
577
578         /* bs: reset frame number */
579         mif_frameno = -1;
580
581     }                           /* MIF file finished */
582 }
583
584 /* Start plotting a Frame (-> graphics mode) */
585 TERM_PUBLIC void
586 MIF_graphics()
587 {
588     int i;
589
590     /* Process if not inside a Frame */
591     if (mif_initialized != 0 && mif_in_frame == 0) {
592         /* Tell that this terminal driver is working with a plot frame */
593         mif_in_frame = 1;
594
595         /* Update frame number */
596         mif_frameno++;
597
598         /* Set current position */
599         free_mif_line();
600         mif_line.fpos_x = GNP_TO_MIF(0);
601         mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
602
603         /* Set drawing properties */
604         mif_pen[0] = '\0';
605         mif_pen_width[0] = '\0';
606         mif_separation[0] = '\0';
607
608         MIF_justify_text(LEFT);
609
610         /* Reset group ID generator */
611         for (i = 0; i < MIF_NGROUP_ID; i++) {
612             mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
613             mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
614         }
615
616         /* Frame preamble */
617         fprintf(gpoutfile, "\
618 #\n\
619 # Frame number %d with plot of graphics\n\
620 <Frame\n\
621 \t<Pen 15>\n\
622 \t<Fill 15>\n\
623 \t<PenWidth  0.5 pt>\n\
624 \t<Separation 0>\n\
625 \t<BRect 2.000 %.3f %.3f %.3f>\n\
626 \t<NSOffset  0.000>\n\
627 \t<BLOffset  0.000>\n",
628             mif_frameno,
629             ((float) mif_frameno) * GNP_TO_MIF(MIF_YMAX + 100),
630             GNP_TO_MIF(MIF_XMAX), GNP_TO_MIF(MIF_YMAX));
631     }                           /* Frame created */
632 }
633
634 /* Stop plotting a Frame (-> text mode) */
635 TERM_PUBLIC void
636 MIF_text()
637 {
638     int i;
639
640     /* Process if inside a Frame */
641     if (mif_initialized != 0 && mif_in_frame != 0) {
642
643         /* Draw pending line */
644         if (mif_polyline == TRUE)
645             put_mif_line();
646
647         /* Group the used plot primitives */
648         fputs("\
649 \t#\n\
650 \t# Group the the objects in groups to make the chart easier to manipulate\n\
651 \t# after it's imported into FrameMaker.\n", gpoutfile);
652
653         for (i = 0; i < MIF_NGROUP_ID; i++) {
654             if (mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
655                 mif_group_id[i].group_existance == MIF_GROUP_EXISTS) {
656                 fprintf(gpoutfile, "\
657 \t<Group\n\
658 \t\t<ID %d>\n\
659 \t>\n", mif_group_id[i].group_id);
660             }
661         }
662
663         /* Frame post amble */
664         fprintf(gpoutfile, "\
665 >\n\
666 # End of Frame number %d\n\
667 #\n",
668                 mif_frameno);
669
670         /* Tell that this terminal driver is not working with a plot frame */
671         mif_in_frame = 0;
672     }                           /* Frame finshed */
673 }
674
675 /* Select type of line in grapics */
676 /* NOTE: actually written to output the first time a primitive
677  * is drawn AFTER this call */
678 /* -2=border, -1=X/Y-axis, 0-13=lines, and 14-=mapped back */
679 TERM_PUBLIC void
680 MIF_linetype(int linetype)
681 {
682     /* Process if inside a Frame */
683     if (mif_initialized != 0 && mif_in_frame != 0) {
684
685         /* Draw pending line */
686         if (mif_polyline == TRUE)
687             put_mif_line();
688
689         /* Translate gnuplot pen types to MIF pen types */
690         if (linetype < 0) {     /* Special lines */
691             if (linetype == LT_AXIS) {
692                 mif_pentype = 8 + MIF_NPENS;    /* -1 */
693                 if (mif_colour == TRUE)
694                     sprintf(mif_separation, " <Separation 0> ");
695             } else {
696                 mif_pentype = 0 + MIF_NPENS;    /* -2 or less */
697                 if (mif_colour == TRUE)
698                     sprintf(mif_separation, " <Separation 0> ");
699             }
700             sprintf(mif_pen_width, " <PenWidth 1.0 pt> ");
701             /* EAM - set text color to black */
702             sprintf(mif_textcolor, " <Font <FSeparation 0>> ");
703         } else {                /* Normal lines */
704             mif_pentype = (linetype) % MIF_NPENS;       /* 0-(MIF_NPENS-1) */
705             sprintf(mif_pen_width, " <PenWidth 0.1 pt> ");
706             if (mif_colour == TRUE)
707                 sprintf(mif_separation, " <Separation %d> ",
708                         2 + (mif_pentype % 6)); /* 2-7 */
709             /* EAM - set text color also */
710             if (mif_colour == TRUE)
711                 sprintf(mif_textcolor, " <Font <FSeparation %d>> ",
712                         2 + (mif_pentype % 6)); /* 2-7 */
713         }
714
715         /* Set pen type */
716         sprintf(mif_pen, " <Pen %d> ",
717                 mif_pattern_table[mif_pentype % MIF_NPENS]);
718
719     }                           /* Primitive processed */
720 }
721
722 /* Allow arbitrary text rotation */
723 TERM_PUBLIC int
724 MIF_text_angle(int ang)
725 {
726     mif_text_ang = ang;
727     return (TRUE);
728 }
729
730 /* Justify following text lines (MIF_put_text()) relative to the
731  * insertion point
732  * NOTE: actually written to output in text primitives which are
733  * drawn AFTER this call */
734 TERM_PUBLIC int
735 MIF_justify_text(enum JUSTIFY mode)
736 {
737     int rval = TRUE;
738
739     /* Process if inside a Frame */
740     if (mif_initialized != 0 && mif_in_frame != 0) {
741         switch (mode) {
742         case LEFT:
743             sprintf(mif_justify, " <TLAlignment Left> ");
744             break;
745         case CENTRE:
746             sprintf(mif_justify, " <TLAlignment Center> ");
747             break;
748         case RIGHT:
749             sprintf(mif_justify, " <TLAlignment Right> ");
750             break;
751         default:
752             rval = FALSE;
753             break;
754         }
755
756     }
757     /* Primitive processed */
758     else {
759         rval = FALSE;
760     }
761
762     return (rval);
763 }
764
765 /* Draw a vector from current position to (x, y) and change current position.
766  * NOTE: actually written to output the first time another primitive
767  * is called AFTER this call */
768 TERM_PUBLIC void
769 MIF_vector(unsigned int x, unsigned int y)
770 {
771     /* Process if inside a Frame */
772     if (mif_initialized != 0 && mif_in_frame != 0) {
773
774         /* Setup the vector as a part of the line */
775         insert_mif_line(GNP_TO_MIF(x), GNP_TO_MIF(MIF_YLAST - (int) y));
776
777         /* Draw pending line -> vector */
778         if (mif_polyline == FALSE)
779             put_mif_line();
780
781     }                           /* Vector processed */
782 }
783
784 /* Move current position */
785 TERM_PUBLIC void
786 MIF_move(unsigned int x, unsigned int y)
787 {
788     /* Process if inside a Frame */
789     if (mif_initialized != 0 && mif_in_frame != 0) {
790
791         /* Draw pending line */
792         if (mif_polyline == TRUE)
793             put_mif_line();
794
795         mif_line.fpos_x = GNP_TO_MIF(x);
796         mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST - (int) y);
797     }
798 }
799
800
801 /* set font */
802 static void
803 MIF_set_font(const char *font)
804 {
805     if (font != mif_font) {
806         fprintf(gpoutfile, "\t\t<Font\n\t\t\t<FTag `%s'>\n\t\t>\n", font);
807         mif_font = font;
808     }
809 }
810
811
812 /* Draw the text string str at (x, y). Adjust according to MIF_justify_text().
813  * Change current position. */
814 TERM_PUBLIC void
815 MIF_put_text(unsigned int x, unsigned int y, const char str[])
816 {
817     /* Process if inside a Frame */
818     if (mif_initialized != 0 && mif_in_frame != 0) {
819
820         /* Draw pending line */
821         if (mif_polyline == TRUE)
822             put_mif_line();
823
824         /* Adjust current position for text-graphics alignment */
825         MIF_move(x, y - MIF_VCHAR / 5);
826
827         if (strlen(str) > 0) {
828
829             /* Draw the text */
830             fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s %s %s %s\n",
831                     MIF_PEN_TO_GROUP(mif_pentype), mif_pen,
832                     mif_pen_width, mif_separation, mif_textcolor);
833
834             MIF_set_font(zgnuplot);
835
836             fprintf(gpoutfile, "\
837 \t\t<TLOrigin  %.3f %.3f> %s <Angle %d> <String `%s'>\n\
838 \t>\n",
839                     mif_line.fpos_x, mif_line.fpos_y, mif_justify,
840                     mif_text_ang, str);
841
842             /* Register the used group ID */
843             proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
844
845             /* Avoid to redraw this. The MIF system should remember it. */
846             mif_pen[0] = '\0';
847             mif_pen_width[0] = '\0';
848             mif_separation[0] = '\0';
849
850             mif_justify[0] = '\0';      /* Independent of linetype */
851         }
852     }                           /* Text processed */
853 }
854
855
856 /* Insert one point in the line */
857 static int
858 insert_mif_line(double fx, double fy)
859 {
860     int rval = TRUE;
861
862     if ((mif_line.prev->next = (struct mif_line *) gp_alloc(sizeof(struct mif_line),
863         "MIF driver")) != (struct mif_line *) NULL) {
864         /* Link */
865         mif_line.prev->next->next = &mif_line;
866         mif_line.prev->next->prev = mif_line.prev;
867         mif_line.prev = mif_line.prev->next;
868
869         /* Fill */
870         mif_line.prev->fpos_x = fx;
871         mif_line.prev->fpos_y = fy;
872
873         rval = TRUE;
874     } else {                    /* Failed to allocate */
875         /* Relink */
876         mif_line.prev->next = &mif_line;
877
878         rval = FALSE;
879     }
880
881     return (rval);
882 }
883
884 /* Register group ID. Update group ID existance. */
885 /* Returns:     1       group_id belongs to a MIF group
886                 0       group_id does not belong to a MIF group
887                -1       not inside a Frame
888                -2       group ID list is full
889  */
890 static int
891 proc_group_id(int group_id)
892 {
893     int i, rval = 0;
894
895     /* Process if inside a Frame */
896     if (mif_initialized != 0 && mif_in_frame != 0) {
897
898         /* Find out the group ID, or a free group ID slot index. */
899         for (i = 0; i < MIF_NGROUP_ID &&
900              mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
901              mif_group_id[i].group_id != group_id;
902              i++) {
903             /* Don't check the group_existance variable */
904         }
905
906         if (i < MIF_NGROUP_ID) {
907             if (mif_group_id[i].group_id == MIF_INVALID_GROUP_ID) {
908                 /* Register as new group ID for eventual use as MIF group */
909                 mif_group_id[i].group_id = group_id;
910                 mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
911             } else {
912                 /* If second use of this group ID -> create a new MIF group */
913                 if (mif_group_id[i].group_id == group_id) {
914                     mif_group_id[i].group_existance = MIF_GROUP_EXISTS;
915                     /* NOTE: a group MUST have at least two members. */
916                     rval = 1;
917                 }
918             }
919         } else {
920             rval = -2;          /* No place for this group ID in the list */
921         }
922
923     }
924     /* Group ID processed */
925     else {
926         rval = -1;              /* Not inside a Frame */
927     }
928
929     /* Return MIF group status */
930     return (rval);
931 }
932
933
934 #endif
935
936
937 #ifdef TERM_TABLE
938
939 TERM_TABLE_START(mif_driver)
940     "mif", "Frame maker MIF 3.00 format",
941     MIF_XMAX, MIF_YMAX, MIF_VCHAR, MIF_HCHAR,
942     MIF_VTIC, MIF_HTIC, MIF_options, MIF_init, MIF_reset,
943     MIF_text, null_scale, MIF_graphics, MIF_move, MIF_vector,
944     MIF_linetype, MIF_put_text, MIF_text_angle,
945     MIF_justify_text, MIF_point, do_arrow, set_font_null,
946     0, /* pointsize */
947     0, /* flags */
948     0, 0, /* suspend, resume */
949     MIF_boxfill,
950     0  /* linewidth */
951 #ifdef USE_MOUSE
952     , 0, 0, 0, 0, 0
953 #endif
954     ,0 /* make_palette */
955     ,0 /* previous_palette */
956     ,0 /* set_color */
957     ,MIF_filled_polygon /* filled_polygon */
958 TERM_TABLE_END(mif_driver)
959
960 #undef LAST_TERM
961 #define LAST_TERM mif_driver
962
963 #endif
964 #endif /* TERM_PROTO_ONLY */
965
966 #ifdef TERM_HELP
967 START_HELP(mif)
968 "1 mif",
969 "?commands set terminal mif",
970 "?set terminal mif",
971 "?set term mif",
972 "?terminal mif",
973 "?term mif",
974 "?mif",
975 " The `mif` terminal driver produces Frame Maker MIF format version 3.00.  It",
976 " plots in MIF Frames with the size 15*10 cm, and plot primitives with the same",
977 " pen will be grouped in the same MIF group.  Plot primitives in a `gnuplot`",
978 " page will be plotted in a MIF Frame, and several MIF Frames are collected in",
979 " one large MIF Frame.  The MIF font used for text is \"Times\".",
980 "",
981 " Several options may be set in the MIF 3.00 driver.",
982 "",
983 " Syntax:",
984 "       set terminal mif {color | colour | monochrome} {polyline | vectors}",
985 "                        {help | ?}",
986 "",
987 " `colour` plots lines with line types >= 0 in colour (MIF sep. 2--7) and",
988 " `monochrome` plots all line types in black (MIF sep. 0).",
989 " `polyline` plots curves as continuous curves and `vectors` plots curves as",
990 " collections of vectors.",
991 " `help` and `?` print online help on standard error output---both print a",
992 " short description of the usage; `help` also lists the options.",
993 "",
994 " Examples:",
995 "       set term mif colour polylines    # defaults",
996 "       set term mif                     # defaults",
997 "       set term mif vectors",
998 "       set term mif help"
999 END_HELP(mif)
1000 #endif /* TERM_HELP */