1/*
2 * $Id: context.trm,v 1.9 2014/01/30 05:50:52 sfeam Exp $
3 */
4
5/* GNUPLOT - context.trm */
6
7/*[
8 * Copyright (c) 2006-2011, Mojca Miklavec
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * - Redistributions of source code must retain the above copyright notice,
15 *   this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright notice,
17 *   this list of conditions and the following disclaimer in the documentation
18 *   and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31]*/
32
33/*
34 * AUTHORS:
35 *   Mojca Miklavec
36 *       <mojca.miklavec.lists at gmail.com>
37 *     - author of this file
38 *     - improvements to m-gnuplot.tex
39 *     - mp-gnuplot.mp - metapost macros to support gnuplot-specifics
40 *       inside ConTeXt
41 *
42 *   Hans Hagen (author of ConTeXt)
43 *        <pragma at wxs.nl>
44 *      - a lot of functionality added to ConTeXt to enable better support
45 *        of Gnuplot module, many bugs fixed
46 *      - author of the module m-gnuplot.tex to support inclusion of Gnuplot
47 *        graphics into ConTeXt
48 *      - constant support on the most tricky issues
49 *   Taco Hoekwater (developer of MetaPost, pdfTeX & LuaTeX)
50 *        <taco at elvenkind.com>
51 *      - some code of this file, many tricks, lots of bug fixes,
52 *        suggestions and testing
53 *      - Hans's right hand in ConTeXt development:
54 *        constant support on even more tricky issues
55 *
56 *   For questions, suggestions, comments, improvements please contact:
57 *     - Mojca Miklavec <mojca.miklavec.lists at gmail.com> or
58 *     - <gnuplot-context at googlegroups.com>
59 *     - http://wiki.contextgarden.net/Gnuplot
60 *
61 * With special thanks to:
62 * - Peter Münster (ctx) for the initiative
63 * - Renaud Aubin (ctx) for maintaining the first source code repository
64 * - Aditya Mahajan (ctx) for some tricky parts in m-gnuplot.tex
65 * - Timothée Lecomte & Ethan A Merritt (gnuplot) for many suggestion about improving this terminal
66 * - Bastian Märkisch (gnuplot) for code improvements
67 *
68 */
69
70/*
71 * GNUPLOT -- context.trm
72 *
73 * This driver creates a ConTeXt document with embded metapost (metafun)
74 * commands and is consequently used for creation of PDF documents.
75 *
76 * It is in a way similar to pslatex, but specialized for ConTeXt,
77 * where it can also be used in the following way:
78 *
79 * \usemodule[gnuplot]
80 *
81 * \starttext
82 * \title{Drawing nice graphs with \sc gnuplot}
83 * \startGNUPLOTscript{sin}
84 * plot sin(x) t '$\sin(x)$'
85 * \stopGNUPLOTscript
86 * \useGNUPLOTgraphic[sin]
87 * \stoptext
88 *
89 * For more information see http://wiki.contextgarden.net/Gnuplot
90 *
91 * Mostly based on:
92 * - default settings copied from LaTeX terminal (because I liked it)
93 * - path construction & drawing routines from MetaPost terminal
94 * - advanced functionality with reference to PostScript terminal
95 *
96 * Future plans:
97 * - most important
98 *   - different syntax for font switching
99 *   - improve support for (transparent) binary images
100 * - add missing functionality:
101 *   - improved support for palettes
102 *   - smooth shading in color bars
103 *   - gouraud shading (if it will be implemented in gnuplot)
104 *   - other color spaces
105 * - derive a better metapost terminal out of this one (to replace the old one)
106 */
107
108#include "driver.h"
109#include "pm3d.h"
110
111#ifdef TERM_REGISTER
112register_term(context)
113#endif
114
115#ifdef TERM_PROTO
116TERM_PUBLIC void CONTEXT_options __PROTO((void));
117TERM_PUBLIC void CONTEXT_init __PROTO((void));
118TERM_PUBLIC void CONTEXT_reset __PROTO((void));
119TERM_PUBLIC void CONTEXT_text __PROTO((void));
120TERM_PUBLIC void CONTEXT_graphics __PROTO((void));
121TERM_PUBLIC void CONTEXT_move __PROTO((unsigned int x, unsigned int y));
122TERM_PUBLIC void CONTEXT_vector __PROTO((unsigned int x, unsigned int y));
123TERM_PUBLIC void CONTEXT_linetype __PROTO((int lt));
124TERM_PUBLIC void CONTEXT_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
125
126TERM_PUBLIC  int CONTEXT_text_angle __PROTO((int ang));
127TERM_PUBLIC  int CONTEXT_justify_text __PROTO((enum JUSTIFY mode));
128TERM_PUBLIC void CONTEXT_point __PROTO((unsigned int x, unsigned int y, int number));
129TERM_PUBLIC void CONTEXT_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head));
130TERM_PUBLIC  int CONTEXT_set_font __PROTO((const char *font)); /* "font,size" */
131TERM_PUBLIC void CONTEXT_pointsize __PROTO((double pointsize));
132TERM_PUBLIC void CONTEXT_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)); /* clear part of multiplot */
133TERM_PUBLIC void CONTEXT_fill __PROTO((int style));
134TERM_PUBLIC void CONTEXT_linewidth __PROTO((double linewidth));
135TERM_PUBLIC  int CONTEXT_make_palette __PROTO((t_sm_palette *palette));
136/* TERM_PUBLIC void CONTEXT_previous_palette __PROTO((void)); do we need it? */
137TERM_PUBLIC void CONTEXT_set_color __PROTO((t_colorspec *colorspec));
138TERM_PUBLIC void CONTEXT_filled_polygon __PROTO((int points, gpiPoint *corners));
139TERM_PUBLIC void CONTEXT_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
140
141/* Metapost < 1.750 can only deal with numbers between 2^{-16} and 2^12=4069 */
142/* scale is 1cm = 1000 units */
143
144#define CONTEXT_DPCM 1000
145#define CONTEXT_DPI (2.54 * CONTEXT_DPCM)
146/* default plot size will be 5in x 3in */
147#define CONTEXT_XSIZE_VALUE 5
148#define CONTEXT_YSIZE_VALUE 3
149#define CONTEXT_SIZE_UNIT INCHES
150#define CONTEXT_XMAX (CONTEXT_XSIZE_VALUE * CONTEXT_DPI)
151#define CONTEXT_YMAX (CONTEXT_YSIZE_VALUE * CONTEXT_DPI)
152/* default fontsize: 12pt */
153#define CONTEXT_FONTSIZE 12.0
154/* default height of char: 12pt by default */
155#define CONTEXT_VCHAR (CONTEXT_DPI * CONTEXT_FONTSIZE / 72.27)
156/* in ConTeXt 12pt LM font is the default;
157 * at that size digits are 5.8749847pt wide
158 * in LaTeX, which assumes 11pt, the ratio is 5.3/11, which is similar */
159#define CONTEXT_LM_H_TO_V_RATIO 0.4895
160#define CONTEXT_HCHAR (CONTEXT_LM_H_TO_V_RATIO * CONTEXT_VCHAR)
161/* default tic size: 3.5bp (chosen to suit the size of plot approximately)
162 * - in LaTeX it is 5bp
163 * - in TikZ it is 0.18cm (approximately 5.1bp)
164 * - in PostScript it is 3.15pt
165 * - MetaPost uses 5pt or 5bp
166 */
167#define CONTEXT_HTIC (3.5 * CONTEXT_DPI / 72)
168#define CONTEXT_VTIC CONTEXT_HTIC
169
170#endif /* TERM_PROTO */
171
172
173#ifndef TERM_PROTO_ONLY
174#ifdef TERM_BODY
175
176/*
177 * started counting when the code was included into CVS
178 *
179 * major number should change only in case of a complete rewrite or major incompatibility
180 * minor number should change for every new functionality
181 * patch number & date should change in every commit
182 */
183static const char CONTEXT_term_version[] = "1.0";
184static const char CONTEXT_term_patch[]   = "0";
185static const char CONTEXT_term_date[]    = "2011-11-05";
186
187static void CONTEXT_params_reset __PROTO((void));
188
189static void CONTEXT_adjust_dimensions __PROTO((void));
190static void CONTEXT_fontstring_parse __PROTO((char *from_string, char *to_string, int to_size, double *fontsize));
191
192static void CONTEXT_startpath __PROTO((void));
193static void CONTEXT_endpath __PROTO((void));
194
195static void CONTEXT_write_palette __PROTO((t_sm_palette *palette));
196static void CONTEXT_write_palette_gradient __PROTO((gradient_struct *gradient, int cnt));
197
198/* Each number is divided by 100 (1/100th of a point is drawn) */
199
200static int CONTEXT_posx;
201static int CONTEXT_posy;
202/* remembers where we started the path:
203 * if we finish it in the same point, the path is closed with --cycle
204 *
205 * After I implemented this, the functionality has been added to gnuplot core
206 * and PostScript terminal uses it, but to be on the safe side,
207 * I prefer not to add last-minute patches which could potentially break something.
208 * (the code written here proved to be rather safe & working so far)
209 * In the next version the core functionality should be integrated & tested.
210 */
211static int CONTEXT_path_start_x;
212static int CONTEXT_path_start_y;
213/* fontname, fontsize */
214static char CONTEXT_font[MAX_ID_LEN+1] = "";
215static double CONTEXT_fontsize = CONTEXT_FONTSIZE;
216
217/* fontname,fontsize to be put next to font labels if needed */
218static char CONTEXT_font_explicit[2*MAX_ID_LEN+1] = "";
219/* this is only set to >0 if asked for explicitely (for example with set_font(",15")) */
220static double CONTEXT_fontsize_explicit = 0.0;
221
222/* the last pointsize used (it will only be changed if it becomes different) */
223static double CONTEXT_old_pointsize = 1.0;
224/* the last linewidth used (it will only be changed if it becomes different) */
225static double CONTEXT_old_linewidth = 1.0;
226/* the last linetype used (it will only be changed if it becomes different) */
227static int CONTEXT_old_linetype = -3;
228/* was the color changed explicitly? */
229static TBOOLEAN CONTEXT_color_changed = FALSE;
230
231/* the number of path nodes before a newline (doesn't really matter,
232 * could be set to 1000; check if any editors have problems with that) */
233#define CONTEXT_LINEMAX 4
234
235/* if we're inside a path (unfinished line) then path_count > 0
236 * (PDF has PDF_pathIsOpen) */
237static unsigned int CONTEXT_path_count = 0;
238/* this true/false switch is used to help distinguish dots from paths */
239static unsigned int CONTEXT_path_is_dot = 0;
240
241/* angle of text rotation */
242static int CONTEXT_ang = 0;
243/* left/middle/right text justification */
244static enum JUSTIFY CONTEXT_justify = LEFT;
245
246#ifdef OS2 /* same constants are defined in os2emx.h */
247enum LINEJOIN { LINEJOIN_MITER=LINEJOIN_MITRE, _LINEJOIN_ROUND=LINEJOIN_ROUND, _LINEJOIN_BEVEL=LINEJOIN_BEVEL };
248#else
249enum LINEJOIN { LINEJOIN_MITER, LINEJOIN_ROUND, LINEJOIN_BEVEL };
250#endif
251enum LINECAP  { LINECAP_BUTT, LINECAP_ROUND, LINECAP_SQUARE };
252
253/* whether points are drawn with metapost or typeset with TeX (easy configurable) */
254enum CONTEXT_POINTS { CONTEXT_POINTS_WITH_METAPOST, CONTEXT_POINTS_WITH_TEX };
255/* whether images are inline or written out as PNGs and included (in MKII only external work) */
256enum CONTEXT_IMAGES { CONTEXT_IMAGES_INLINE, CONTEXT_IMAGES_EXTERNAL };
257
258/* counts the number of graphics */
259static int   CONTEXT_counter = 0;
260/* counts the number of external PNG images */
261static int   CONTEXT_image_counter = 0;
262/* length of basename for storing image name (including path, excluding extension) */
263static int   CONTEXT_image_filename_length = 0;
264/* if name is a path, remember at which index basename starts */
265static int   CONTEXT_image_filename_start = 0;
266static char *CONTEXT_image_filename = NULL;
267/* whether images will be external or not */
268enum CONTEXT_IMAGES CONTEXT_images = CONTEXT_IMAGES_INLINE;
269
270/* Pallete has to be stored for the usage in later plots */
271static t_sm_palette *CONTEXT_old_palette;
272
273/*********************/
274/* global parameters */
275/*********************/
276
277typedef struct CONTEXT_params_t {
278	double              xsize;               /* 5in    */
279	double              ysize;               /* 3in    */
280	size_units          unit;                /* INCHES */
281	TBOOLEAN            standalone;          /* false  */
282	TBOOLEAN            timestamp;           /* true   */
283	char               *header;              /* ""     */
284	TBOOLEAN            color;               /* true   */
285	TBOOLEAN            dashed;              /* true   */
286	enum LINEJOIN       linejoin;            /* MITER  */
287	enum LINECAP        linecap;             /* BUTT   */
288	double              scale_dashlength;    /* 1.0    */
289	double              scale_linewidth;     /* 1.0    */
290	double              scale_text;          /* 1.0    */
291	enum CONTEXT_POINTS points;              /* CONTEXT_POINTS_WITH_METAPOST */
292	enum CONTEXT_IMAGES images;              /* CONTEXT_IMAGES_INLINE */
293	char                font[MAX_ID_LEN+1];  /* ""     */
294	double              fontsize;            /* 12pt   */
295} CONTEXT_params_t;
296
297
298#define CONTEXT_PARAMS_DEFAULT { \
299	CONTEXT_XSIZE_VALUE,\
300	CONTEXT_YSIZE_VALUE,\
301	INCHES,\
302	FALSE,\
303	TRUE,\
304	NULL,\
305	TRUE,\
306	TRUE,\
307	LINEJOIN_MITER,\
308	LINECAP_BUTT,\
309	1.0,\
310	1.0,\
311	1.0,\
312	CONTEXT_POINTS_WITH_METAPOST,\
313	CONTEXT_IMAGES_INLINE,\
314	"",\
315	CONTEXT_FONTSIZE\
316}
317
318static CONTEXT_params_t CONTEXT_params = CONTEXT_PARAMS_DEFAULT;
319
320enum CONTEXT_id {
321	CONTEXT_OPT_DEFAULT,
322	CONTEXT_OPT_SIZE,
323	CONTEXT_OPT_SIZE_DEFAULT,
324	CONTEXT_OPT_INPUT, CONTEXT_OPT_STANDALONE,
325	CONTEXT_OPT_TIMESTAMP, CONTEXT_OPT_NOTIMESTAMP,
326	CONTEXT_OPT_HEADER, CONTEXT_OPT_NOHEADER,
327	CONTEXT_OPT_COLOR, CONTEXT_OPT_MONOCHROME,
328	CONTEXT_OPT_DASHED, CONTEXT_OPT_SOLID,
329	CONTEXT_OPT_LINEJOIN_MITERED, CONTEXT_OPT_LINEJOIN_ROUNDED, CONTEXT_OPT_LINEJOIN_BEVELED,
330	CONTEXT_OPT_LINECAP_BUTT, CONTEXT_OPT_LINECAP_ROUNDED, CONTEXT_OPT_LINECAP_SQUARED,
331	CONTEXT_OPT_SCALE_DASHLENGTH, CONTEXT_OPT_SCALE_LINEWIDTH, CONTEXT_OPT_SCALE_TEXT,
332	CONTEXT_OPT_POINTS_WITH_METAPOST, CONTEXT_OPT_POINTS_WITH_TEX,
333	CONTEXT_OPT_IMAGES_INLINE, CONTEXT_OPT_IMAGES_EXTERNAL,
334	CONTEXT_OPT_DEFAULTFONT,
335	CONTEXT_OPT_FONT,
336	CONTEXT_OPT_OTHER
337};
338static struct gen_table CONTEXT_opts[] = {
339	{ "d$efault", CONTEXT_OPT_DEFAULT },
340	{ "size", CONTEXT_OPT_SIZE },
341	{ "defaultsize", CONTEXT_OPT_SIZE_DEFAULT },
342	{ "inp$ut", CONTEXT_OPT_INPUT },
343	{ "stand$alone", CONTEXT_OPT_STANDALONE },
344	{ "time$stamp", CONTEXT_OPT_TIMESTAMP },
345	{ "notime$stamp", CONTEXT_OPT_NOTIMESTAMP },
346	{ "header", CONTEXT_OPT_HEADER },
347	{ "noheader", CONTEXT_OPT_NOHEADER },
348	{ "col$or", CONTEXT_OPT_COLOR },
349	{ "col$our", CONTEXT_OPT_COLOR },
350	{ "mono$chrome", CONTEXT_OPT_MONOCHROME },
351	{ "da$shed", CONTEXT_OPT_DASHED },
352	{ "so$lid", CONTEXT_OPT_SOLID },
353	{ "miter$ed", CONTEXT_OPT_LINEJOIN_MITERED },
354	{ "rounded", CONTEXT_OPT_LINEJOIN_ROUNDED },
355	{ "bevel$ed", CONTEXT_OPT_LINEJOIN_BEVELED },
356	{ "butt", CONTEXT_OPT_LINECAP_BUTT },
357	{ "round", CONTEXT_OPT_LINECAP_ROUNDED },
358	{ "square$d", CONTEXT_OPT_LINECAP_SQUARED },
359	{ "dashl$ength", CONTEXT_OPT_SCALE_DASHLENGTH },
360	{ "dl", CONTEXT_OPT_SCALE_DASHLENGTH },
361	{ "linew$idth", CONTEXT_OPT_SCALE_LINEWIDTH },
362	{ "lw", CONTEXT_OPT_SCALE_LINEWIDTH },
363	{ "fontscale", CONTEXT_OPT_SCALE_TEXT },
364	{ "textscale", CONTEXT_OPT_SCALE_TEXT },                   /* backward compatibility */
365	{ "mp$points", CONTEXT_OPT_POINTS_WITH_METAPOST},
366	{ "tex$points", CONTEXT_OPT_POINTS_WITH_TEX},
367	{ "pointswithmp", CONTEXT_OPT_POINTS_WITH_METAPOST},       /* (removable) backward compatibility */
368	{ "pointswithmetapost", CONTEXT_OPT_POINTS_WITH_METAPOST}, /* (removable) backward compatibility */
369	{ "pointswithtex", CONTEXT_OPT_POINTS_WITH_TEX},           /* (removable) backward compatibility */
370	{ "inline$images", CONTEXT_OPT_IMAGES_INLINE},
371	{ "external$images", CONTEXT_OPT_IMAGES_EXTERNAL},
372	{ "font", CONTEXT_OPT_FONT },
373	{ "defaultfont", CONTEXT_OPT_DEFAULTFONT },
374	{ NULL, CONTEXT_OPT_OTHER }
375};
376
377/* **********************
378 * CONTEXT_params_reset *
379 * **********************
380 *
381 * Resets all parameters of the terminal to their default value.
382 */
383static void
384CONTEXT_params_reset()
385{
386	static const CONTEXT_params_t CONTEXT_params_default = CONTEXT_PARAMS_DEFAULT;
387
388	/* free the memory with header first */
389	if (CONTEXT_params.header) {
390		free(CONTEXT_params.header);
391		CONTEXT_params.header = NULL;
392	}
393
394	memcpy(&CONTEXT_params, &CONTEXT_params_default, sizeof(CONTEXT_params_t));
395}
396
397
398/* *****************
399 * CONTEXT_options *
400 * *****************
401 *
402 * Parses "set term context [options]".
403 */
404TERM_PUBLIC void
405CONTEXT_options()
406{
407	struct value a;
408	char   *tmp_string;
409	char   tmp_term_options[MAX_LINE_LEN+1] = "";
410
411	while (!END_OF_COMMAND) {
412		switch (lookup_table(&CONTEXT_opts[0], c_token)) {
413		case CONTEXT_OPT_DEFAULT:
414			c_token++;
415			/* there should be a better way to do it, but I don't know how */
416			CONTEXT_params_reset();
417			break;
418		case CONTEXT_OPT_SIZE: {
419			float xmax_t, ymax_t;
420			size_units unit;
421			c_token++;
422
423			/* size <xsize> {cm|in}, <ysize> {cm|in} */
424			unit = parse_term_size(&xmax_t, &ymax_t, CM);
425			CONTEXT_params.xsize = (double)xmax_t / gp_resolution;
426			CONTEXT_params.ysize = (double)ymax_t / gp_resolution;
427			CONTEXT_params.unit  = unit;
428			if (unit == CM) {
429				CONTEXT_params.xsize *= 2.54;
430				CONTEXT_params.ysize *= 2.54;
431			}
432			break;
433		}
434		case CONTEXT_OPT_SIZE_DEFAULT:
435			c_token++;
436			CONTEXT_params.xsize = CONTEXT_XSIZE_VALUE;
437			CONTEXT_params.ysize = CONTEXT_YSIZE_VALUE;
438			CONTEXT_params.unit  = CONTEXT_SIZE_UNIT;
439			break;
440		case CONTEXT_OPT_INPUT:
441			c_token++;
442			CONTEXT_params.standalone = FALSE;
443			break;
444		case CONTEXT_OPT_STANDALONE:
445			c_token++;
446			CONTEXT_params.standalone = TRUE;
447			break;
448		case CONTEXT_OPT_TIMESTAMP:
449			c_token++;
450			CONTEXT_params.timestamp = TRUE;
451			break;
452		case CONTEXT_OPT_NOTIMESTAMP:
453			c_token++;
454			CONTEXT_params.timestamp = FALSE;
455			break;
456
457		case CONTEXT_OPT_HEADER:
458			c_token++;
459			/* parse the string */
460			tmp_string = try_to_get_string();
461			if (!tmp_string) {
462				int_error(c_token,"String containing header information expected");
463			/* only touch the options if the string is OK */
464			} else {
465				/* remove the old header if any */
466				if (CONTEXT_params.header) {
467					free(CONTEXT_params.header);
468					CONTEXT_params.header = NULL;
469				}
470				/* and set the new one if nonempty;
471				 * empty header will be treated as 'noheader' */
472				if (strlen(tmp_string) > 0) {
473					CONTEXT_params.header = tmp_string;
474				} else {
475					free(tmp_string);
476				}
477			}
478			break;
479		case CONTEXT_OPT_NOHEADER:
480			c_token++;
481			/* delete the header if it exists */
482			if (CONTEXT_params.header) {
483				free(CONTEXT_params.header);
484				CONTEXT_params.header = NULL;
485			}
486			break;
487		case CONTEXT_OPT_COLOR:
488			c_token++;
489			CONTEXT_params.color = TRUE;
490			/* just mimick other terminals; no idea what it does;
491			   at the moment monochrome is not fully implemented either */
492			term->flags &= ~TERM_MONOCHROME;
493			break;
494		case CONTEXT_OPT_MONOCHROME:
495			c_token++;
496			CONTEXT_params.color = FALSE;
497			term->flags |= TERM_MONOCHROME;
498			break;
499		case CONTEXT_OPT_DASHED:
500			c_token++;
501			CONTEXT_params.dashed = TRUE;
502			break;
503		case CONTEXT_OPT_SOLID:
504			c_token++;
505			CONTEXT_params.dashed = FALSE;
506			break;
507		case CONTEXT_OPT_LINEJOIN_MITERED:
508			c_token++;
509			CONTEXT_params.linejoin = LINEJOIN_MITER;
510			break;
511		case CONTEXT_OPT_LINEJOIN_ROUNDED:
512			c_token++;
513			CONTEXT_params.linejoin = LINEJOIN_ROUND;
514			break;
515		case CONTEXT_OPT_LINEJOIN_BEVELED:
516			c_token++;
517			CONTEXT_params.linejoin = LINEJOIN_BEVEL;
518			break;
519		case CONTEXT_OPT_LINECAP_BUTT:
520			c_token++;
521			CONTEXT_params.linecap = LINECAP_BUTT;
522			break;
523		case CONTEXT_OPT_LINECAP_ROUNDED:
524			c_token++;
525			CONTEXT_params.linecap = LINECAP_ROUND;
526			break;
527		case CONTEXT_OPT_LINECAP_SQUARED:
528			c_token++;
529			CONTEXT_params.linecap = LINECAP_SQUARE;
530			break;
531		case CONTEXT_OPT_SCALE_DASHLENGTH:
532			c_token++;
533			CONTEXT_params.scale_dashlength = real(const_express(&a));
534			break;
535		case CONTEXT_OPT_SCALE_LINEWIDTH:
536			c_token++;
537			CONTEXT_params.scale_linewidth = real(const_express(&a));
538			break;
539		case CONTEXT_OPT_SCALE_TEXT:
540			c_token++;
541			CONTEXT_params.scale_text = real(const_express(&a));
542			break;
543		case CONTEXT_OPT_DEFAULTFONT:
544			c_token++;
545			/* CONTEXT_params.font should be an empty string */
546			CONTEXT_params.font[0] = 0;
547			/* default fontsize is 12pt */
548			CONTEXT_params.fontsize = CONTEXT_FONTSIZE;
549			break;
550		case CONTEXT_OPT_POINTS_WITH_METAPOST:
551			c_token++;
552			CONTEXT_params.points = CONTEXT_POINTS_WITH_METAPOST;
553			break;
554		case CONTEXT_OPT_POINTS_WITH_TEX:
555			c_token++;
556			CONTEXT_params.points = CONTEXT_POINTS_WITH_TEX;
557			break;
558		case CONTEXT_OPT_IMAGES_INLINE:
559			c_token++;
560			CONTEXT_params.images = CONTEXT_IMAGES_INLINE;
561			break;
562		case CONTEXT_OPT_IMAGES_EXTERNAL:
563#ifdef WRITE_PNG_IMAGE
564			c_token++;
565			CONTEXT_params.images = CONTEXT_IMAGES_EXTERNAL;
566#else
567			int_warn(c_token, "Gnuplot was built without support for PNG images. You cannot use this option unless you rebuild gnuplot.");
568#endif
569			break;
570		/*
571		 * The preferred way to set the font is to set it in a document itself,
572		 * labels in gnuplot in graphs will then inherit that font.
573		 *
574		 * However, it is important to tell gnuplot which size is going to be used,
575		 * so that it can estimate size of text labels.
576		 *
577		 * Whenever you specify
578		 *     set term context font "fontname,14"
579		 *
580		 * there are two possibilities:
581		 * - if STANDALONE mode is on, then the whole string will be used as
582		 *   \setupbodyfont[fontname,14pt]
583		 *   somewhere on top of the document (you still have to make sure that you
584		 *   included the proper typescript, so that "fontname" will be recognised
585		 * - in the other case (INPUT mode) only the font size will be used
586		 *   internally to estimate sizes of labels, but the font name
587		 *   won't be written anywhere
588		 */
589		case CONTEXT_OPT_FONT: {
590			double tmp_fontsize;
591			char tmp_font[MAX_ID_LEN+1] = "";
592			c_token++;
593			if ((tmp_string = try_to_get_string()) && (tmp_string != NULL)) {
594				CONTEXT_fontstring_parse(tmp_string, tmp_font, MAX_ID_LEN+1, &tmp_fontsize);
595				/* copies font name to parameters */
596				safe_strncpy(CONTEXT_params.font, tmp_font, sizeof(CONTEXT_params.font));
597				tmp_font[MAX_ID_LEN] = NUL;
598				free(tmp_string);
599				/* save font size:
600				 *
601				 * - if size > 0, copy
602				 * - if size < 0, fix the size to default value (12pt)
603				 * - if size = 0, ignore
604				 */
605				if (tmp_fontsize > 0)
606					CONTEXT_params.fontsize = tmp_fontsize;
607				else if (tmp_fontsize < 0)
608					CONTEXT_params.fontsize = CONTEXT_FONTSIZE;
609			}
610			break;
611		}
612		case CONTEXT_OPT_OTHER:
613		default:
614			/* error */
615			int_error(c_token, "extraneous argument in set terminal %s",term->name);
616			break;
617		}
618	}
619
620	/* current font size in pt (to be used in CONTEXT_adjust_dimensions) */
621	CONTEXT_fontsize = CONTEXT_params.fontsize;
622
623	/* sets term->xmax, ymax, vchar, hchar */
624	CONTEXT_adjust_dimensions();
625
626	snprintf(term_options, sizeof(term_options),
627			"size %g%s,%g%s %s %s %s",
628			CONTEXT_params.xsize,
629			(CONTEXT_params.unit == INCHES) ? "in" : "cm",
630			CONTEXT_params.ysize,
631			(CONTEXT_params.unit == INCHES) ? "in" : "cm",
632			CONTEXT_params.standalone ? "standalone" : "input",
633			CONTEXT_params.timestamp ? "timestamp" : "notimestamp",
634			CONTEXT_params.header == NULL ? "noheader \\\n   " : "\\\n   header ");
635
636	if (CONTEXT_params.header != NULL) {
637		strncat(term_options,"\"",                  sizeof(term_options)-strlen(term_options)-1);
638		strncat(term_options,CONTEXT_params.header, sizeof(term_options)-strlen(term_options)-1);
639		strncat(term_options,"\" \\\n   ",          sizeof(term_options)-strlen(term_options)-1);
640	}
641
642	strncat(term_options,
643		CONTEXT_params.color ? "color " : "monochrome ",
644		sizeof(term_options)-strlen(term_options)-1);
645
646	switch (CONTEXT_params.linejoin) {
647		case LINEJOIN_MITER:
648			strncat(term_options, "mitered ",
649				sizeof(term_options)-strlen(term_options)-1);
650                        break;
651		case LINEJOIN_ROUND:
652			strncat(term_options, "rounded ",
653				sizeof(term_options)-strlen(term_options)-1);
654                        break;
655		case LINEJOIN_BEVEL:
656			strncat(term_options, "beveled ",
657				sizeof(term_options)-strlen(term_options)-1);
658                        break;
659	}
660	switch (CONTEXT_params.linecap) {
661		case LINECAP_BUTT  :
662			strncat(term_options, "butt",
663				sizeof(term_options)-strlen(term_options)-1);
664                        break;
665		case LINECAP_ROUND :
666			strncat(term_options, "round",
667				sizeof(term_options)-strlen(term_options)-1);
668                        break;
669		case LINECAP_SQUARE:
670			strncat(term_options, "squared",
671				sizeof(term_options)-strlen(term_options)-1);
672                        break;
673	}
674
675	snprintf(tmp_term_options, sizeof(tmp_term_options),
676		" %s dashlength %g linewidth %g fontscale %g \\\n   ",
677		CONTEXT_params.dashed ? "dashed" : "solid",
678		CONTEXT_params.scale_dashlength,
679		CONTEXT_params.scale_linewidth,
680		CONTEXT_params.scale_text
681		);
682	strncat(term_options, tmp_term_options, sizeof(term_options)-strlen(term_options)-1);
683
684	switch (CONTEXT_params.points) {
685		case CONTEXT_POINTS_WITH_TEX :
686			strncat(term_options, "texpoints ",
687				sizeof(term_options)-strlen(term_options)-1);
688                        break;
689		case CONTEXT_POINTS_WITH_METAPOST :
690			strncat(term_options, "mppoints ",
691				sizeof(term_options)-strlen(term_options)-1);
692                        break;
693	}
694#ifdef WRITE_PNG_IMAGE
695	switch (CONTEXT_params.images) {
696		case CONTEXT_IMAGES_INLINE :
697			strncat(term_options, "inlineimages ",
698				sizeof(term_options)-strlen(term_options)-1);
699                        break;
700		case CONTEXT_IMAGES_EXTERNAL :
701			strncat(term_options, "externalimages ",
702				sizeof(term_options)-strlen(term_options)-1);
703                        break;
704	}
705#endif
706	snprintf(tmp_term_options, sizeof(tmp_term_options), "font \"%s,%g\"",
707		CONTEXT_params.font, CONTEXT_params.fontsize);
708	strncat(term_options, tmp_term_options, sizeof(term_options) - strlen(term_options)-1);
709}
710
711/* **************
712 * CONTEXT_init *
713 * **************
714 *
715 * Starts a new file.
716 *
717 * XXX: "set term context" multiple times will only include those graphics
718 *      that were create before issuing a new "set term context options"
719 *      this should be fixed in the core by reopening the file
720 *      (removing previously written content).
721 * - PDF & binary terminals start a new file
722 * - PS & TeX-based terminals continue
723 */
724TERM_PUBLIC void
725CONTEXT_init()
726{
727	time_t now;
728	char timebuffer[100];
729	int i;
730
731	time(&now);
732
733	CONTEXT_posx = CONTEXT_posy = 0;
734	CONTEXT_path_count = 0;
735	CONTEXT_path_is_dot = 0;
736
737	CONTEXT_counter = 0;
738
739	/* setup bitmap images */
740	CONTEXT_image_counter = 0;
741	/* the default is to use inline images */
742	CONTEXT_images = CONTEXT_IMAGES_INLINE;
743
744	/* only if external images are both requested and supported, we switch to them (double paranoia) */
745	/* delete the stored filename first */
746	if (CONTEXT_image_filename) {
747		free(CONTEXT_image_filename);
748		CONTEXT_image_filename = NULL;
749		CONTEXT_image_filename_length = 0;
750		CONTEXT_image_filename_start  = 0;
751	};
752#ifdef WRITE_PNG_IMAGE
753	if (CONTEXT_params.images == CONTEXT_IMAGES_EXTERNAL) {
754		CONTEXT_images = CONTEXT_IMAGES_EXTERNAL;
755
756		/* but only if 'set output' was set because we use that string as base for image names */
757		if (outstr) {
758			CONTEXT_image_filename_length = strlen(outstr);
759			CONTEXT_image_filename_start  = strlen(outstr) - strlen(gp_basename(outstr));
760			/* we will cut off the last .tex ending if present */
761			/* find the last dot if present */
762			for (i = CONTEXT_image_filename_length - 1; i >= 0 && outstr[i] != '.'; i--);
763			if (outstr[i] == '.')
764				CONTEXT_image_filename_length = i;
765			/* it would also be very nice to do some sanity checks on filenames */
766
767			/* <name>.xx.png; must be at least 7 characters long */
768			CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename");
769			strncpy(CONTEXT_image_filename, outstr, CONTEXT_image_filename_length);
770			CONTEXT_image_filename[CONTEXT_image_filename_length] = 0;
771		} else {
772			CONTEXT_image_filename_length = strlen("gp_image");
773			CONTEXT_image_filename_start  = 0;
774			/* <name>.xx.png; must be at least 7 characters long */
775			CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename");
776			strncpy(CONTEXT_image_filename, "gp_image", CONTEXT_image_filename_length);
777			CONTEXT_image_filename[CONTEXT_image_filename_length] = 0;
778		}
779	}
780#endif
781
782	fprintf(gpoutfile, "%% Written by ConTeXt terminal for GNUPLOT");
783	if (CONTEXT_params.timestamp) {
784		if (strftime(timebuffer, 100, "%Y-%m-%d %H:%M %Z", localtime(&now)) != 0)
785			fprintf(gpoutfile, " on: %s", timebuffer);
786	}
787	fprintf(gpoutfile, "\n");
788	fprintf(gpoutfile, "%% GNUPLOT version: %s.%s, terminal version: %s.%s (%s)\n",
789		gnuplot_version, gnuplot_patchlevel, CONTEXT_term_version, CONTEXT_term_patch, CONTEXT_term_date);
790	fprintf(gpoutfile, "%% See also http://wiki.contextgarden.net/Gnuplot\n%%\n");
791
792	/* place the header first if this is a standalone graphic */
793	if (CONTEXT_params.standalone) {
794		/* If encoding is explicitely set to UTF-8 by gnuplot, use that setting.
795		 * \enableregime only makes a difference for pdfTeX; in LuaTeX and XeTeX UTF-8 is already default,
796		 * so this line will be ignored.
797		 *
798		 * There is no extra support for other encodings on purpose:
799		 * - ConTeXt doesn't support all encodings supported by Gnuplot.
800		 * - In LuaTeX and XeTeX one should not use any other encoding anyway.
801		 * - pdfTeX users are free to use "header '\enableregime[...]'" */
802		switch (encoding) {
803			case S_ENC_UTF8:
804				fputs("\\enableregime\n   [utf-8]\n", gpoutfile);
805				break;
806			default:
807				/* do nothing */
808				break;
809		}
810		/* load the gnuplot module */
811		fputs("\\usemodule\n   [gnuplot]\n", gpoutfile);
812		/* enable or disable color (the only place where "color" is indeed used so far) */
813		fprintf(gpoutfile, "\\setupcolors\n   [state=%s]\n", CONTEXT_params.color ? "start" : "stop");
814		/* additional user-provided header information (if available) */
815		if (CONTEXT_params.header)
816			fprintf(gpoutfile, "%s\n", CONTEXT_params.header);
817		/* for some reason setting \bodyfontenvironment is needed,
818		 * otherwise \switchtobodyfont[name] doesn't work OK */
819		if (!(CONTEXT_params.fontsize == CONTEXT_FONTSIZE))
820			fprintf(gpoutfile, "\\definebodyfontenvironment\n   [%gpt]\n",
821				CONTEXT_params.fontsize);
822		/* set the proper font: \setupbodyfont[{fontname,}fontsize sizeunit] */
823		fprintf(gpoutfile, "\\setupbodyfont\n   [%s%s%gpt]\n",
824			CONTEXT_params.font,
825			/* write a comma only if the last string was non-empty */
826			((strlen(CONTEXT_params.font)>0) ? "," : ""),
827			CONTEXT_params.fontsize);
828
829		/*---------*
830		 * options *
831		 *---------*/
832		fprintf(gpoutfile, "\\setupGNUPLOTterminal\n   [context]\n   [");
833
834		/* color (gp_use_color): yes/no (true/false)
835		 * default: yes
836		 * - doesn't do anything useful yet;
837		 *   and besides that, it's already set in \setupcolors[state=start] */
838		/* fprintf(gpoutfile, "    color=%s, %% *yes* | no\n", CONTEXT_params.color ? "yes" : "no"); */
839
840		/* linejoin: mitered/rounded/beveled
841		 * default: mitered */
842		fprintf(gpoutfile, "linejoin=");
843		switch (CONTEXT_params.linejoin) {
844			case LINEJOIN_MITER: fprintf(gpoutfile, "mitered"); break;
845			case LINEJOIN_ROUND: fprintf(gpoutfile, "rounded"); break;
846			case LINEJOIN_BEVEL: fprintf(gpoutfile, "beveled"); break;
847		}
848		fprintf(gpoutfile, ", %% *mitered* | rounded | beveled\n");
849
850		/* linecap: butt/rounded/squared
851		 * default: butt */
852		fprintf(gpoutfile, "    linecap=");
853		switch (CONTEXT_params.linecap) {
854			case LINECAP_BUTT  : fprintf(gpoutfile, "butt"); break;
855			case LINECAP_ROUND : fprintf(gpoutfile, "rounded"); break;
856			case LINECAP_SQUARE: fprintf(gpoutfile, "squared"); break;
857		}
858		fprintf(gpoutfile, ", %% *butt* | rounded | squared\n");
859
860		/* dashed (gp_use_dashed): yes/no (true/false)
861		 * default: yes */
862		fprintf(gpoutfile, "    dashed=%s, %% *yes* | no\n", CONTEXT_params.dashed ? "yes" : "no");
863		/* dashlength (gp_scale_dashlength): 1.0 */
864		fprintf(gpoutfile, "    dashlength=%g, %% scaling factor for dash lengths\n", CONTEXT_params.scale_dashlength);
865
866		/* linewidth (gp_scale_linewidth): 1.0 */
867		fprintf(gpoutfile, "    linewidth=%g, %% scaling factor for line widths (1.0 means 0.5bp)\n", CONTEXT_params.scale_linewidth);
868
869		/* fontscale (gp_scale_text): 1.0 */
870		/* written out just for reference - it's commented out since it needs to be part of graphic
871		   and affects estimation of label sizes */
872		fprintf(gpoutfile, "    %%fontscale=%g, %% scaling factor for text labels\n", CONTEXT_params.scale_text);
873
874		/* points (gp_points_with): metapost/tex (gp_points_with_metapost/gp_points_with_tex)
875		 * default: metapost */
876		fprintf(gpoutfile, "    points=%s, %% *metapost* | tex (Should points be drawn with MetaPost or TeX?)\n",
877			CONTEXT_params.points == CONTEXT_POINTS_WITH_METAPOST ? "metapost" : "tex");
878
879		/* images
880		 * default: inline */
881		fprintf(gpoutfile, "    images=%s] %% *inline* | external (inline only works in MKIV, external requires png support in gnuplot)\n",
882			CONTEXT_images == CONTEXT_IMAGES_INLINE ? "inline" : "external");
883
884		/*----------------*
885		 * end of options *
886		 *----------------*/
887
888		fputs("\n\\starttext\n\n", gpoutfile);
889	} else {
890		/* Sorry, nothing! In non-standalone graphic, parameters make no sense.
891		 * Setup everything in the file which includes such a graphic instead.
892		 */
893	}
894}
895
896/* ***************
897 * CONTEXT_reset *
898 * ***************
899 *
900 * finish writing the file
901 */
902TERM_PUBLIC void
903CONTEXT_reset()
904{
905	/* we only have to end the document if this is a stand-alone graphic */
906	if (CONTEXT_params.standalone) {
907		fputs("\\stoptext\n", gpoutfile);
908	} else {
909		/* This means that any subsequent plots to the same file will be ignored.
910		 * I don't like that - gnuplot should delete the old contents instead,
911		 * just as it does in case of PNG or PDF -
912		 * but it will be at least consistent with standalone graphics that way
913		 */
914		fputs("\\endinput\n", gpoutfile);
915	}
916	/* deallocate image name if present */
917	if (CONTEXT_image_filename) {
918		free(CONTEXT_image_filename);
919		CONTEXT_image_filename = NULL;
920		CONTEXT_image_filename_length = 0;
921		CONTEXT_image_filename_start  = 0;
922	};
923}
924
925/* **************
926 * CONTEXT_text *
927 * **************
928 *
929 * Ends the current graphic.
930 */
931TERM_PUBLIC void
932CONTEXT_text()
933{
934	/* close and draw the current path first */
935	if (CONTEXT_path_count > 0)
936		CONTEXT_endpath();
937
938	fprintf(gpoutfile, "setbounds currentpicture to unitsquare xyscaled (w,h);\n");
939
940	/* standalone graphic is a whole-page graphic */
941	if (CONTEXT_params.standalone) {
942		fputs("\\stopGNUPLOTpage\n", gpoutfile);
943	/* otherwise we define a MPgraphic to be included later */
944	} else {
945		fputs("\\stopGNUPLOTgraphic\n", gpoutfile);
946	}
947}
948
949/* ******************
950 * CONTEXT_graphics *
951 * ******************
952 *
953 * Starts a new graphic.
954 */
955TERM_PUBLIC void
956CONTEXT_graphics()
957{
958	/* standalone graphic is a whole-page graphic */
959	if (CONTEXT_params.standalone) {
960		fprintf(gpoutfile, "\\startGNUPLOTpage %% Graphic Nr. %d\n", ++CONTEXT_counter);
961	/* otherwise we define a MPgraphic to be included later */
962	} else {
963		/* the first parameter holds the graphic number */
964		fprintf(gpoutfile, "\\startGNUPLOTgraphic[%d]\n", ++CONTEXT_counter);
965	}
966
967	fprintf(gpoutfile, "string gnuplotversion; gnuplotversion := \"%s\";\n", gnuplot_version);
968	fprintf(gpoutfile, "string termversion;    termversion    := \"%s\";\n", CONTEXT_term_version);
969	/*
970	 * MetaPost can only handle numbers up to 4096. Too high resolution
971	 * would thus result in number overflow, that's why we scale down all the
972	 * integers from gnuplot by 1000 and multiply those numbers later by
973	 * appropriate scaling factor 'a' to get the proper dimensions.
974	 */
975	fprintf(gpoutfile, "%% scaling factor, width and height of the figure\na := 1cm; w := %.3fa; h := %.3fa; %% (%g%s, %g%s)\n",
976		CONTEXT_params.xsize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */
977		CONTEXT_params.ysize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */
978		CONTEXT_params.xsize, (CONTEXT_params.unit == INCHES) ? "in" : "cm",
979		CONTEXT_params.ysize, (CONTEXT_params.unit == INCHES) ? "in" : "cm");
980	/* TODO: the following if-else could be slightly nicer */
981	if (CONTEXT_images == CONTEXT_IMAGES_INLINE) {
982		fprintf(gpoutfile, "%% temporary variable for storing the path and images\nsave p, img, ima; path p; string img, ima;\n");
983	} else {
984		fprintf(gpoutfile, "%% temporary variable for storing the path\nsave p; path p;\n");
985	}
986	fprintf(gpoutfile, "%% -------------------------\n");
987	fprintf(gpoutfile, "%% Different initialisations\n");
988	fprintf(gpoutfile, "%% -------------------------\n");
989	fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_before;\n");
990	/* needed (depends on terminal settings & needs to be passed) */
991	fprintf(gpoutfile, "%% text scaling factor for the whole figure\n");
992	fprintf(gpoutfile, "gp_scale_text := %g;\n", CONTEXT_params.scale_text);
993	fprintf(gpoutfile, "%% pointsize scaling factor\n");
994	fprintf(gpoutfile, "gp_set_pointsize(%g);\n", CONTEXT_old_pointsize);
995	/* needed (provided by terminal) */
996	fprintf(gpoutfile, "%% linewidth scaling factor for individual lines\n");
997	fprintf(gpoutfile, "gp_set_linewidth(%g);\n", CONTEXT_old_linewidth);
998	fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_after;\n");
999	fprintf(gpoutfile, "%% -------------------------\n");
1000
1001	/* since palette is initialized only once, subsequent plots wouldn't see it
1002	 * unless we write it on the top of relevant plots explicitely */
1003	if (is_plot_with_palette()) {
1004		CONTEXT_write_palette(CONTEXT_old_palette);
1005	}
1006
1007	/* needed, otherwise the first linetype(-2) would be ignored */
1008	CONTEXT_old_linetype = -3;
1009	/* different initializations - not really needed, but they cannot hurt */
1010	CONTEXT_posx = CONTEXT_posy = 0;
1011	CONTEXT_path_count = 0;
1012	CONTEXT_path_is_dot = 0;
1013}
1014
1015/* ---------------
1016 * CONTEXT_endpath
1017 * ---------------
1018 *
1019 * Closes and strokes (draws) the current path.
1020 *
1021 * It the path ends where it started, it ends it with --cycle (we get cyclic path),
1022 * otherwise just with a semicolon.
1023 */
1024static void
1025CONTEXT_endpath()
1026{
1027	/* if we have a dot, draw only the dot */
1028	if (CONTEXT_path_is_dot) {
1029		fprintf(gpoutfile, "gp_dot(%.3fa,%.3fa);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1030		CONTEXT_path_is_dot = 0;
1031
1032	/* cyclic path, so let's end it with "--cycle" */
1033	} else if ((CONTEXT_posx == CONTEXT_path_start_x) && (CONTEXT_posy == CONTEXT_path_start_y)) {
1034		fputs("--cycle;\ngp_draw(p);\n", gpoutfile);
1035
1036	/* regular non-cyclic path */
1037	} else {
1038		fprintf(gpoutfile, "--(%.3fa,%.3fa);\ngp_draw(p);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1039	}
1040
1041	/* we're not inside path any more */
1042	CONTEXT_path_count = 0;
1043}
1044
1045/* **************
1046 * CONTEXT_move *
1047 * **************
1048 *
1049 * Remembers the new location for a path.
1050 *
1051 * If it doesn't differ from the current location, this is simply ignored.
1052 * If we're still in the middle of path construction and location differs,
1053 * it strokes the old path.
1054 *
1055 */
1056TERM_PUBLIC void
1057CONTEXT_move(unsigned int x, unsigned int y)
1058{
1059	/* we seem to be there already */
1060	if ((x == CONTEXT_posx) && (y == CONTEXT_posy))
1061		return;
1062
1063	/* close and draw the current path before the move */
1064	if (CONTEXT_path_count > 0)
1065		CONTEXT_endpath();
1066
1067	CONTEXT_posx = x;
1068	CONTEXT_posy = y;
1069}
1070
1071/* -----------------
1072 * CONTEXT_startpath
1073 * -----------------
1074 *
1075 * Starts ([but not yet] drawing) a new path.
1076 */
1077static void
1078CONTEXT_startpath()
1079{
1080	CONTEXT_path_start_x = CONTEXT_posx;
1081	CONTEXT_path_start_y = CONTEXT_posy;
1082	CONTEXT_path_count = 2;
1083
1084	fprintf(gpoutfile, "p := (%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1085}
1086
1087/* ****************
1088 * CONTEXT_vector *
1089 * ****************
1090 *
1091 * Prolongs the current path for an additional line (from the last point to (x,y))
1092 * unless it has a zero-length.
1093 *
1094 * Points have to be treated as a special case, since gnuplot sometimes tries
1095 * to draw them as moveto(a,b)--lineto(a,b) - without the proper linecap,
1096 * that wouldn't draw anything in MetaPost or PS.
1097 * (I hope that I got that part right, but I'm not completely sure.)
1098 */
1099TERM_PUBLIC void
1100CONTEXT_vector(unsigned int x, unsigned int y)
1101{
1102	/* this is zero-length line (or a dot)
1103	 *
1104	 * stupid background, has to handle
1105	 * - move(0,0), vector(0,0), whatever: draw a dot
1106	 * - move(0,0), vector(0,0), vector (1,1): draw a line
1107	 */
1108	if ((x == CONTEXT_posx) && (y==CONTEXT_posy)) {
1109		/* as long as this is still a dot candidate, mark it so
1110		 * however - further vector() commands may set this back to 0 */
1111		if (CONTEXT_path_count == 0)
1112			CONTEXT_path_is_dot = 1;
1113		/* if some path was already drawn up to this place, ignore (it's not a dot) */
1114		return;
1115	}
1116
1117	/* start the path if none is started yet */
1118	if (CONTEXT_path_count == 0) {
1119		/* the path is not a dot */
1120		CONTEXT_path_is_dot = 0;
1121		CONTEXT_startpath();
1122	} else {
1123		/* or prevent too long lines if you're in the middle of a path */
1124		if ((CONTEXT_path_count % CONTEXT_LINEMAX) == 2) {
1125			fputs("\n  ", gpoutfile);
1126			CONTEXT_path_count = 2;
1127		}
1128		/* and output the previous point */
1129		fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1130	}
1131
1132	CONTEXT_posx = x;
1133	CONTEXT_posy = y;
1134	CONTEXT_path_count++;
1135}
1136
1137/* ******************
1138 * CONTEXT_linetype *
1139 * ******************
1140 *
1141 * - If only color has been changed (recently), but not the linetype,
1142 *   it resets only the color.
1143 * - If linetype was changed, it sets the new linetype
1144 */
1145TERM_PUBLIC void
1146CONTEXT_linetype(int lt)
1147{
1148	/* reset the color in case it has been changed in CONTEXT_set_color() */
1149	if (CONTEXT_old_linetype != lt || CONTEXT_color_changed) {
1150		/* close and draw the current path first */
1151		if (CONTEXT_path_count > 0)
1152			CONTEXT_endpath();
1153
1154		fprintf(gpoutfile, "gp_set_linetype(%d);\n", lt);
1155
1156		CONTEXT_old_linetype = lt;
1157		CONTEXT_color_changed = FALSE;
1158	}
1159}
1160
1161/* ******************
1162 * CONTEXT_put_text *
1163 * ******************
1164 *
1165 * Places text labels.
1166 */
1167TERM_PUBLIC void
1168CONTEXT_put_text(unsigned int x, unsigned int y, const char str[])
1169{
1170	const char *s; /* pointer to string */
1171	int  alignment = 0;
1172	char alignments[3][10] = {"center", "left", "right"};
1173
1174	/* ignore empty strings */
1175	if (!str || !strlen(str))
1176		return;
1177
1178	/* close and draw the current path first */
1179	if (CONTEXT_path_count > 0)
1180		CONTEXT_endpath();
1181
1182	/* see the values of "alignments" above */
1183	switch (CONTEXT_justify) {
1184		case CENTRE:
1185			alignment = 0;
1186			break;
1187		case LEFT:
1188			alignment = 1;
1189			break;
1190		case RIGHT:
1191			alignment = 2;
1192			break;
1193	}
1194
1195	/* remove whitespaces at the beginning of string
1196	 * (usually problem in positive numbers)
1197	 * They interfere with positioning: whitespace at the beginning takes
1198	 * some place although it's invisible, so left-aligned and centered labels
1199	 * are posioned wrong otherwise.
1200	 * Example:
1201	 *   -1 0 1 2: centered labels on x axis
1202	 * if we had a space in front, positive numbers would be "centered" in a weird way*/
1203	for (s = str; s[0] == ' '; s++);
1204
1205	/* label position */
1206	fprintf(gpoutfile, "gp_put_text((%.3fa, %.3fa), ", 0.001*x, 0.001*y);
1207	/* angle of rotation - optional and needed only if it's different from 0 */
1208	if (CONTEXT_ang != 0)
1209		fprintf(gpoutfile, "angle(%d), ", CONTEXT_ang);
1210
1211	/* alignment - "center" is optional, but we'll add it anyway */
1212	fprintf(gpoutfile, "align(%s), \\sometxt[gp]", alignments[alignment]);
1213	/* fontface/fontsize - optional second argument */
1214	if (CONTEXT_font_explicit[0] != 0)
1215		fprintf(gpoutfile, "[%s]", CONTEXT_font_explicit);
1216	/* finally the text label itself */
1217	fprintf(gpoutfile, "{%s});\n", s);
1218}
1219
1220
1221/* ********************
1222 * CONTEXT_text_angle *
1223 * ********************
1224 *
1225 * Saves text angle to be used for text labels.
1226 */
1227TERM_PUBLIC int
1228CONTEXT_text_angle(int ang)
1229{
1230	CONTEXT_ang = ang;
1231	return TRUE;
1232}
1233
1234/* **********************
1235 * CONTEXT_justify_text *
1236 * **********************
1237 *
1238 * Saves horizontal text justification (left/middle/right) to be used for text labels.
1239 */
1240TERM_PUBLIC int
1241CONTEXT_justify_text(enum JUSTIFY mode)
1242{
1243	CONTEXT_justify = mode;
1244	return TRUE;
1245}
1246
1247/* ***************
1248 * CONTEXT_point *
1249 * ***************
1250 *
1251 * There are two/three possible ways of drawing points in ConTeXt:
1252 * - let gnuplot draw the points with standard move/vector commands
1253 *   (points_default): not enabled
1254 * - use the points predefined in mp-gnuplot.mp (drawn with metapost)
1255 *   which can easily be redefined
1256 *   (points_with_metapost)
1257 * - use symbols from a symbol set predefined in m-gnuplot.tex (drawn with TeX)
1258 *   (points_with_tex)
1259 *
1260 * At first this routine took care of that, but now it's up to the high-level
1261 * user interface to switch between the last two options.
1262 */
1263TERM_PUBLIC void
1264CONTEXT_point (unsigned int x, unsigned int y, int number)
1265{
1266	/* finish the current line first before the move */
1267	if (CONTEXT_path_count > 0)
1268		CONTEXT_endpath();
1269
1270	fprintf(gpoutfile, "gp_point(%.3fa,%.3fa,%d);\n", 0.001*x, 0.001*y, number);
1271}
1272
1273/* ***************
1274 * CONTEXT_arrow *
1275 * ***************
1276 * ConTeXt could draw nice arrows on its own and in such a way that user could
1277 * simply redefine arrow heads in the template file.
1278 *
1279 * This function is left here just in case that anyoune would find it useful
1280 * to define his own arrow-drawing commands.
1281 *
1282 * Currently it just calls the default gnuplot function for drawing arrows.
1283 */
1284TERM_PUBLIC void
1285CONTEXT_arrow (unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)
1286{
1287	do_arrow(sx, sy, ex, ey, head);
1288}
1289
1290
1291/* ------------------------
1292 * CONTEXT_fontstring_parse
1293 * ------------------------
1294 *
1295 * Parses from_string, which is divided by commas (,)
1296 * and copies the whole content to to_string except for the part
1297 * which starts with a numeric value.
1298 *
1299 * That value is interpreted separately and saved to fontsize.
1300 *
1301 * to_size is the size of to_string which may not be exceeded while copying the string
1302 */
1303static void
1304CONTEXT_fontstring_parse(char *from_string, char *to_string, int to_size, double *fontsize)
1305{
1306	double tmp_fontsize = 0.;
1307	char * comma;
1308	size_t n;
1309
1310	comma = strrchr(from_string, ',');
1311	if (comma) {
1312		sscanf(comma + 1, "%lf", &tmp_fontsize);
1313		n = comma - from_string;
1314	} else {
1315		n = strlen(from_string);
1316	}
1317	*fontsize = tmp_fontsize;
1318	if (n >= to_size)
1319		n = to_size - 1;
1320	memcpy(to_string, from_string, n);
1321	to_string[n] = NUL;
1322}
1323
1324
1325/* -------------------------
1326 * CONTEXT_adjust_dimensions
1327 * -------------------------
1328 *
1329 * - sets the v_char and h_char based on current font size (approximation only)
1330 *   using CONTEXT_fontsize in points (from CONTEXT_params.fontsize) and CONTEXT_params.scale_text
1331 * - sets xmax and ymax based on CONTEXT_params.xsize and CONTEXT_params.ysize
1332 */
1333static void
1334CONTEXT_adjust_dimensions()
1335{
1336	/* sets vertical dimension of characters based on current fontsize in pt */
1337	term->v_char = (unsigned int)((double)CONTEXT_DPI *
1338		CONTEXT_fontsize / 72.27 * CONTEXT_params.scale_text + 0.5);
1339	/* based on proportions of LM digits at 12pt */
1340	term->h_char = (unsigned int)(CONTEXT_LM_H_TO_V_RATIO * term->v_char + 0.5);
1341
1342	/* we might want to fix CONTEXT_DPI in case that the figure becomes too big */
1343	if (CONTEXT_params.unit == INCHES) {
1344		term->xmax = (unsigned int)((double)CONTEXT_DPI  * CONTEXT_params.xsize + 0.5);
1345		term->ymax = (unsigned int)((double)CONTEXT_DPI  * CONTEXT_params.ysize + 0.5);
1346	} else {
1347		term->xmax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.xsize + 0.5);
1348		term->ymax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.ysize + 0.5);
1349	}
1350}
1351
1352/* *****************
1353 * CONTEXT_set_font*
1354 * *****************
1355 *
1356 * Official description:
1357 * - empty string restores the terminal's default font
1358 * - fonts are selected as strings "name,size",
1359 *   where size should be a floating point number interpreted as "pt" (point)
1360 *
1361 * It's the user's own responsibility to make sure that the proper typescripts
1362 * are included in the header, else the selected font won't work out-of-the-box
1363 *
1364 * The ConTeXt terminal should support things such as
1365 *   "iwona,ss,12"   (iwona sans serif) or
1366 *   ",10"           (10 points)  or
1367 *   "tt"            (typewriter)
1368 *
1369 * The routine saves font name to CONTEXT_font
1370 * and fontsize to CONTEXT_fontsize.
1371 *
1372 * The two are joined in CONTEXT_font_explicit for the usage in
1373 *   \sometxt[gp][fontname,fontsize]{label}
1374 */
1375TERM_PUBLIC int
1376CONTEXT_set_font(const char *font)
1377{
1378	char tmp_fontstring[MAX_ID_LEN+1] = "";
1379
1380	/* saves font name & family to CONTEXT_font */
1381	CONTEXT_fontstring_parse((char *)font, CONTEXT_font, sizeof(CONTEXT_font), &CONTEXT_fontsize_explicit);
1382	safe_strncpy(CONTEXT_font_explicit, CONTEXT_font, sizeof(CONTEXT_font_explicit));
1383
1384	/* valid fontsize has been provided */
1385	if (CONTEXT_fontsize_explicit > 0.) { /* XXX: if valid */
1386
1387		CONTEXT_fontsize = CONTEXT_fontsize_explicit;
1388
1389		snprintf(tmp_fontstring, sizeof(tmp_fontstring), ",%gpt", CONTEXT_fontsize_explicit);
1390		strncat(CONTEXT_font_explicit, tmp_fontstring,
1391                        sizeof(CONTEXT_font_explicit) - strlen(CONTEXT_font_explicit)-1);
1392		tmp_fontstring[MAX_ID_LEN] = NUL;
1393
1394	/* no fontsize has been provided: switch back to default terminal fontsize */
1395	} else if (CONTEXT_fontsize_explicit == 0) {
1396		CONTEXT_fontsize = CONTEXT_params.fontsize;
1397	}
1398
1399	/* tell to gnuplot how big the fonts in labels are */
1400	CONTEXT_adjust_dimensions();
1401
1402	return TRUE;
1403}
1404
1405/* *******************
1406 * CONTEXT_pointsize *
1407 * *******************
1408 *
1409 * Sets the (relative) point size for subsequent points
1410 *
1411 * The base point size is defined "somewhere else":
1412 * - depends on the font[size] used when "texpoints" option is on
1413 */
1414TERM_PUBLIC void
1415CONTEXT_pointsize(double pointsize)
1416{
1417	/*
1418	 * my first thought was not to allow negative sizes of points,
1419	 * but I see no reason why one shouldn't be able to play with
1420	 * inverted point shapes, so finally I commented this out again
1421	 *
1422	 *   if (pointsize < 0)
1423	 *      pointsize = 1;
1424	 */
1425
1426	if (CONTEXT_old_pointsize != pointsize) {
1427		/* close and draw the current path first */
1428		if (CONTEXT_path_count > 0)
1429			CONTEXT_endpath();
1430		fprintf(gpoutfile, "gp_set_pointsize(%.3f);\n", pointsize);
1431		CONTEXT_old_pointsize = pointsize;
1432	}
1433}
1434
1435/* *****************
1436 * CONTEXT_fillbox *
1437 * *****************
1438 *
1439 * Creates the path for the rectangle and calls the CONTEXT_fill(style)
1440 * routine (shared with CONTEXT_filled_polygon) to actually fill that shape
1441 */
1442TERM_PUBLIC void
1443CONTEXT_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
1444{
1445	/* close and draw the current path first */
1446	if (CONTEXT_path_count > 0)
1447		CONTEXT_endpath();
1448
1449	/* create a new path */
1450	fprintf(gpoutfile, "p := unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n", 0.001*width, 0.001*height, 0.001*x1, 0.001*y1);
1451	/* fprintf(gpoutfile, "p := gp_rect ((%.3fa,%.3fa),(%.3fa,%.3fa));\n", 0.001*x1, 0.001*y1, 0.001*width, 0.001*height); */
1452
1453	/* fills the box according to the "style"
1454	 * the code went out of this routine because of undocumented behaviour
1455	 * that also the filled_polygon should paint with patterns ... */
1456	CONTEXT_fill(style);
1457}
1458
1459/* **************
1460 * CONTEXT_fill *
1461 * **************
1462 *
1463 * Filling routine, yet another undocumented feature of Gnuplot.
1464 * The code was mostly cloned from the PostScript terminal,
1465 * so that you know whom to accuse if it doesn't do what you would expect
1466 * it to do. (In case of cloning errors please inform the author of this terminal.)
1467 *
1468 * The lowest 4 bits of "style" seem to represent the style of filling
1469 * (whether it is solid or pattern-based or whatever that might appear
1470 * in that place in the future).
1471 *
1472 * The rest of the bits of "style" represent either the density
1473 * (ranging from 0 to 100) or the number of the pattern that the polygon
1474 * should be filled with.
1475 *
1476 * Used by CONTEXT_fillbox(...) and CONTEXT_filled_polygon(...)
1477 */
1478TERM_PUBLIC void
1479CONTEXT_fill(int style)
1480{
1481	int density;
1482	int pattern;
1483
1484	/* used in FS_[TRANSPARENT_]SOLID --> fill with intensity according to filldensity
1485	   it extracts a percentage out of "style" */
1486	density = (style >> 4);
1487	if (density < 0)
1488		density = 0;
1489	if (density > 100)
1490		density = 100;
1491
1492	fputs("gp_fill(p", gpoutfile);
1493
1494	/* do some strange trickery */
1495	switch (style & 0xf) {
1496
1497	case FS_DEFAULT:
1498		break;
1499
1500	case FS_TRANSPARENT_SOLID:
1501		/* just a flag to tell the terminal that density() should be used to interpret transparency */
1502		fprintf(gpoutfile, ",transparent");
1503	case FS_SOLID:
1504		/* fill the box with density "density": if no parameter density is specified,
1505		   it implies 100% density by default */
1506		if (density < 100)
1507			fprintf(gpoutfile, ",density(%.2f)", 0.01*density);
1508		break;
1509
1510	case FS_TRANSPARENT_PATTERN:
1511		/* just a flag that should be interpreted in metapost,
1512		   non-transparent patterns have to fill with background color before drawing the pattern */
1513		fprintf(gpoutfile, ",transparent");
1514	case FS_PATTERN:
1515		pattern = (style >> 4);
1516		fprintf(gpoutfile, ",pattern(%d)", pattern);
1517		break;
1518
1519	default: /* style == 0 (FS_EMPTY) or unknown --> fill with background color */
1520		fprintf(gpoutfile, ",density(0)");
1521	}
1522	/* TODO: FS_DEFAULT is missing; what should that one do? */
1523
1524	/* gp_fill(p,...); */
1525	fputs(");\n", gpoutfile);
1526}
1527
1528/* *******************
1529 * CONTEXT_linewidth *
1530 * *******************
1531 *
1532 * scale line width (similar to pointsize)
1533 * remembers the values locally (no serious need for that actually) and writes them into file
1534 */
1535TERM_PUBLIC void
1536CONTEXT_linewidth(double linewidth)
1537{
1538	if (linewidth < 0)
1539		linewidth = 1.0;
1540
1541	if (CONTEXT_old_linewidth != linewidth) {
1542		/* close and draw the current path first */
1543		if (CONTEXT_path_count > 0)
1544			CONTEXT_endpath();
1545		fprintf(gpoutfile, "gp_set_linewidth(%.3f);\n", linewidth);
1546		CONTEXT_old_linewidth = linewidth;
1547	}
1548}
1549
1550/* ------------------------------
1551 * CONTEXT_write_palette_gradient
1552 * ------------------------------
1553 *
1554 * Writes the colors and positions for a gradient pallete.
1555 */
1556static void
1557CONTEXT_write_palette_gradient(gradient_struct *gradient, int cnt)
1558{
1559	int i;
1560
1561	/* i-th color */
1562	fprintf(gpoutfile, "colors(");
1563	for (i = 0; i < cnt; i++) {
1564		if (i > 0)
1565		    fprintf(gpoutfile, ",");
1566		fprintf(gpoutfile, "(%.3g,%.3g,%.3g)", gradient[i].col.r, gradient[i].col.g, gradient[i].col.b);
1567	}
1568
1569	/* position of the i-th color */
1570	fprintf(gpoutfile, ");positions(");
1571	for (i = 0; i < cnt; i++) {
1572		if (i > 0)
1573			fprintf(gpoutfile, ",");
1574		fprintf(gpoutfile, "%.4g", gradient[i].pos);
1575	}
1576	fprintf(gpoutfile, ")");
1577}
1578
1579/* ---------------------
1580 * CONTEXT_write_palette
1581 * ---------------------
1582 *
1583 */
1584static void
1585CONTEXT_write_palette(t_sm_palette *palette)
1586{
1587	if (palette == NULL)
1588		return;
1589
1590/* TODO
1591	// Color models: RGB, HSV, CMY, XYZ
1592	//
1593	// RGB: Red, Green, Blue
1594	// HSV: Hue, Saturation, Value
1595	// CMY
1596	//
1597	// two models that gnuplot uses, but which probably won't be supported by this terminal:
1598	// XYZ: three primary colors of the color model defined by the 'Commission Internationale de l'Eclairage' (CIE)
1599	// http://www.cs.rit.edu/~ncs/color/glossary.htm
1600	// http://cs.fit.edu/wds/classes/cse5255/cse5255/davis/index.html
1601*/
1602	fprintf(gpoutfile, "gp_make_palette(");
1603	switch (sm_palette.colorMode) {
1604		/* grayscale only */
1605		case SMPAL_COLOR_MODE_GRAY:
1606			fprintf(gpoutfile, "color_mode(gray)");
1607			break;
1608		/* one of several fixed transformations */
1609		case SMPAL_COLOR_MODE_RGB:
1610			fprintf(gpoutfile, "color_mode(rgb);formulae(%d,%d,%d)",
1611				sm_palette.formulaR,
1612				sm_palette.formulaG,
1613				sm_palette.formulaB);
1614			break;
1615		/* user defined transforms */
1616		case SMPAL_COLOR_MODE_FUNCTIONS:
1617			fprintf(gpoutfile, "color_mode(functions)");
1618			break;
1619		/* interpolated table: explicitely defined or read from file */
1620		case SMPAL_COLOR_MODE_GRADIENT:
1621			fprintf(gpoutfile, "color_mode(gradient);");
1622			CONTEXT_write_palette_gradient(palette->gradient, palette->gradient_num);
1623			break;
1624		case SMPAL_COLOR_MODE_NONE:
1625			break;
1626		default:
1627			break;
1628	}
1629	fprintf(gpoutfile, ");\n");
1630}
1631
1632/* *********************
1633 * CONTEXT_make_palette*
1634 * *********************
1635 *
1636 * 1. if palette==NULL, then return nice/suitable
1637 *    maximal number of colours supported by this terminal.
1638 *    Returns 0 if it can make colours without palette (like
1639 *    postscript).
1640 * 2. if palette!=NULL, then allocate its own palette
1641 *    return value is undefined
1642 * 3. available: some negative values of max_colors for whatever
1643 *    can be useful
1644 */
1645TERM_PUBLIC int
1646CONTEXT_make_palette(t_sm_palette *palette)
1647{
1648	if (palette == NULL)
1649		return 0;  /* ConTeXt can do continuous colors */
1650
1651	/* save the palette */
1652	CONTEXT_old_palette = palette;
1653
1654	return 0;
1655}
1656
1657
1658/*
1659 * most probably this one is not needed
1660 *
1661 * TERM_PUBLIC void
1662 * CONTEXT_previous_palette(){}
1663 *
1664 */
1665
1666/* *******************
1667 * CONTEXT_set_color *
1668 * *******************
1669 *
1670 * typedef struct t_colorspec {
1671 *    int    type;    // TC_ DEFAULT, LT, LINESTYLE, RGB, CB, FRAC, Z
1672 *    int    lt;      // used for TC_LT, TC_LINESTYLE and TC_RGB
1673 *    double value;   // used for TC_CB and TC_FRAC
1674 * } t_colorspec;
1675 */
1676TERM_PUBLIC void
1677CONTEXT_set_color(t_colorspec *colorspec)
1678{
1679	double gray, r, g, b;
1680	/* ConTeXt doesn't offer full support for palettes yet
1681	   (I don't know how to trick metapost to accept the full palette specification)
1682	   so we convert the colors from palettes to RGB instead.
1683	   If terminal starts supporting palettes, this behaviour will change.
1684	*/
1685	rgb_color rgb1;
1686
1687/* If (colorspec->type == TC_FRAC):
1688   Set current color according to colorspec->value, where 0 <= value <= 1.
1689   If using a palette, first map value to an integer i in the interval
1690   [0...num_colors-1], then set to the ith color in the palette.
1691   If (colorspec->type == TC_RGB):
1692   Set current color to the rgb triple given in colorspec->lt. */
1693
1694	/* close and draw the current path first */
1695	if (CONTEXT_path_count > 0)
1696		CONTEXT_endpath();
1697
1698	switch (colorspec->type) {
1699
1700	/* TC_DEFAULT, TC_CB, TC_Z: probably unused; what about linestyle? */
1701
1702	/* color equal as that of linetype in colorspec->lt */
1703	case TC_LT:
1704		fprintf(gpoutfile, "gp_set_color(lt(%d));\n", colorspec->lt);
1705		CONTEXT_color_changed = TRUE;
1706		break;
1707
1708	/* rgb color */
1709	case TC_RGB:
1710		r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
1711		g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
1712		b = (double)(colorspec->lt & 255) / 255.;
1713
1714		fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", r, g, b);
1715		CONTEXT_color_changed = TRUE;
1716		break;
1717
1718	/* map [0:1] to gray colors or to the corresponding color from the palette */
1719	case TC_FRAC:
1720		gray = colorspec->value;
1721
1722		/* limit negative and >1 values to [0:1] first */
1723		if (gray < 0) gray = 0;
1724		if (gray > 1) gray = 1;
1725
1726		/* TODO: if ConTeXt start supporting palettes, we'll uncomment the following: */
1727		fprintf(gpoutfile, "%%gp_set_color(frac(%.4f));\n", gray);
1728		/* but now it doesn't, so let's use the fallback instead: */
1729		rgb1maxcolors_from_gray(gray, &rgb1);
1730		fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", rgb1.r, rgb1.g, rgb1.b);
1731
1732		CONTEXT_color_changed = TRUE;
1733		break;
1734	default:
1735		int_warn(NO_CARET,"context.trm set_color unknown colorspec->type %i", colorspec->type);
1736		break;
1737	}
1738}
1739
1740
1741/* ************************
1742 * CONTEXT_filled_polygon *
1743 * ************************
1744 *
1745 * Draws a polygon with the fill color set by set_color, and no border.
1746 */
1747TERM_PUBLIC void
1748CONTEXT_filled_polygon(int points, gpiPoint *corners)
1749{
1750	int i;
1751
1752	/* nothing to be filled if less than 3 points */
1753	if (points < 3)
1754		return;
1755
1756	/* close and draw the current path first */
1757	if (CONTEXT_path_count > 0)
1758		CONTEXT_endpath();
1759
1760	/* if the first point equals the last one, skip the last point; --cycle does that already
1761	 * this condition is probably always true in gnuplot, so the if condition may not be needed */
1762	if ((corners[0].x == corners[points-1].x) && (corners[0].y == corners[points-1].y))
1763		points--;
1764
1765	/* create new path with corners */
1766	fputs("p := ", gpoutfile);
1767	fprintf(gpoutfile, "(%.3fa,%.3fa)", 0.001*corners[0].x, 0.001*corners[0].y);
1768	for (i = 1; i < points; i++) {
1769		if (i % CONTEXT_LINEMAX == 0)
1770			fputs("\n  ", gpoutfile);
1771		fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*corners[i].x, 0.001*corners[i].y);
1772	}
1773	/* and fill it */
1774	fprintf(gpoutfile, "--cycle;\n");
1775
1776	/* fill the polygon
1777	 * undocumented gnuplot behaviour, copied from PostScript terminal
1778	 * see comments for CONTEXT_fill for details */
1779	CONTEXT_fill(corners->style);
1780}
1781
1782/* ***************
1783 * CONTEXT_image *
1784 * ***************
1785 *
1786   Plot a pixel-based image on the display device.
1787   'M' is the number of pixels along the y-dimension of the image and
1788   'N' is the number of pixels along the x-dimension of the image.  The
1789   coordval pointer 'image' is the pixel values normalized to the range
1790   [0:1].  These values should be scaled appropriately for the output
1791   device.  The 'image' data starts in the upper left corner and scans
1792   along rows finishing in the lower right corner.  If 'color_mode' is
1793   IC_PALETTE, the terminal is to use palette lookup to generate color
1794   information.  In this scenario the size of 'image' is M*N.  If
1795   'color_mode' is IC_RGB, successive bytes of the data structure are
1796   interpreted as RGB components of a single pixel.  In this scenario
1797   the size of 'image' is 3*M*N.  The data appears in RGB triples, i.e.,
1798   image[0] = R(1,1), image[1] = G(1,1), image[2] = B(1,1),
1799   image[3] = R(1,2), image[4] = G(1,2), ..., image[3*M*N-1] = B(M,N).
1800   The mode IC_RGBA is similar except that four values red, green, blue,
1801   alpha per pixel are passed to the terminal in the image structure.
1802   The 'image' is actually an "input" image in the sense that
1803   it must also be properly resampled for the output device.  Many output
1804   media, e.g., PostScript, do this work via various driver functions.
1805   To determine the appropriate rescaling, the 'corner' information
1806   should be used.  There are four entries in the gpiPoint data array.
1807   'corner[0]' is the upper left corner (in terms of plot location) of
1808   the outer edge of the image.  Similarly, 'corner[1]' is the lower
1809   right corner of the outer edge of the image.  (Outer edge means the
1810   outer extent of the corner pixels, not the middle of the corner
1811   pixels.)  'corner[2]' is the upper left corner of the visible part
1812   of the image, and 'corner[3]' is the lower right corner of the visible
1813   part of the image.  The information is provided in this way because
1814   often it is necessary to clip a portion of the outer pixels of the
1815   image.
1816 */
1817
1818/* TODO: this code needs some improvements
1819 *
1820 * There are two different modes:
1821 *
1822 * 1. creating PNG image and including it
1823 *    - it only works if gnuplot has been compiled with cairo or gdlib libraries
1824 *    - there are some bugs in MKII/MKIV handling: a different syntax is required
1825 *      and can only be fixed in ConTeXt core; I could abstract the code a bit
1826 * 2. printing out a string with colors
1827 *    - MKIV: works, but transparency is not yet implemented
1828 *    - MKII: requires MetaPost > 0.750 and is not implemented at all
1829 *            two possible approaches: drawing rectangles & creating proper image
1830 *            it might require one additional level of abstraction like gp_image(...)
1831 */
1832TERM_PUBLIC void
1833CONTEXT_image(unsigned M, unsigned N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
1834{
1835	int i, k, line_length, components_per_color;
1836	rgb_color color;
1837	TBOOLEAN is_clipped = FALSE;
1838
1839	if ((corner[2].x > corner[0].x) || (corner[0].y > corner[2].y) ||
1840	    (corner[1].x > corner[3].x) || (corner[3].y > corner[1].y))
1841		is_clipped = TRUE;
1842
1843	if (CONTEXT_images == CONTEXT_IMAGES_EXTERNAL) {
1844#ifdef WRITE_PNG_IMAGE
1845		/* we reserved 10 extra bytes, so we can afford images up to 9999 */
1846		snprintf(CONTEXT_image_filename + CONTEXT_image_filename_length, 9, "_%02d.png", ++CONTEXT_image_counter);
1847		write_png_image (M, N, image, color_mode, CONTEXT_image_filename);
1848
1849		if (is_clipped)
1850			fprintf(gpoutfile, "draw image(\n  ");
1851		fprintf(gpoutfile, "externalfigure \"%s\" xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n",
1852			CONTEXT_image_filename + CONTEXT_image_filename_start, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y);
1853		if (is_clipped) {
1854			fprintf(gpoutfile, "  clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n",
1855				0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y);
1856		}
1857#endif
1858	} else {
1859
1860		/* Palette colors have to be converted into RGB first */
1861		if (color_mode == IC_PALETTE) {
1862			/* write the image data */
1863			fprintf(gpoutfile, "img := \"%%\n");
1864			line_length = 0;
1865			for (i = 0; i < M * N; i++) {
1866				if (line_length++ >= 16) {
1867					line_length = 1;
1868					fprintf(gpoutfile, "%%\n");
1869				}
1870				rgb1maxcolors_from_gray(image[i], &color);
1871				fprintf(gpoutfile, "%02x%02x%02x", (unsigned char)(255*color.r), (unsigned char)(255*color.g), (unsigned char)(255*color.b));
1872			}
1873			fprintf(gpoutfile, "\";\n");
1874
1875		/* IC_RGB or IC_RGBA */
1876		} else {
1877			if (color_mode == IC_RGBA) {
1878				components_per_color = 4;
1879			} else { /* IC_RGB */
1880				components_per_color = 3;
1881			}
1882
1883			/* write the image data */
1884			fprintf(gpoutfile, "img := \"%%\n");
1885			line_length = 0;
1886			for (i = 0; i < M * N; i++) {
1887				if (line_length++ >= 16) {
1888					line_length = 1;
1889					fprintf(gpoutfile, "%%\n");
1890				}
1891				for (k = 0; k < 3; k++) {
1892					fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+k]*255));
1893				}
1894			}
1895			fprintf(gpoutfile, "\";\n");
1896
1897			/* transparency mask */
1898			if (color_mode == IC_RGBA) {
1899				fprintf(gpoutfile, "ima := \"%%\n");
1900				line_length = 0;
1901				for (i = 0; i < M * N; i++) {
1902					if (line_length++ >= 3*16) {
1903						line_length = 1;
1904						fprintf(gpoutfile, "%%\n");
1905					};
1906					fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+3]*255));
1907				}
1908				fprintf(gpoutfile, "\";\n");
1909			}
1910		}
1911
1912		/* TODO: transparency handling is not yet supported in ConTeXt */
1913		if (is_clipped)
1914			fprintf(gpoutfile, "draw image(\n  ");
1915		fprintf(gpoutfile, "draw bitmapimage (%u,%u,img) xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n",
1916			N, M, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y);
1917		if (is_clipped) {
1918			fprintf(gpoutfile, "  clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n",
1919				0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y);
1920		}
1921
1922		/* (alternative implementation) *
1923		fprintf(gpoutfile, "gp_image_rgb");
1924		if (color_mode == IC_RGB)
1925			fprintf(gpoutfile, "_alpha");
1926		fprintf(gpoutfile, "((%u,%u),(%.3fa,%.3fa),(%.3fa,%.3fa));\n",
1927			N, M, 0.001*corner[0].x, 0.001*corner[1].y, 0.001*corner[1].x, 0.001*corner[0].y);
1928		*/
1929	}
1930}
1931
1932/*
1933 * TODO: Implement this function for smooth shading
1934 *
1935 * you need to fix draw_color_smooth_box(MODE_SPLOT) in graph3d.c -> color.c
1936 *
1937static void
1938CONTEXT_draw_inside_color_smooth_box()
1939{
1940}
1941 */
1942
1943#endif /* TERM_BODY */
1944
1945#ifdef TERM_TABLE
1946
1947TERM_TABLE_START(context_driver)
1948	"context", "ConTeXt with MetaFun (for PDF documents)",
1949	CONTEXT_XMAX, CONTEXT_YMAX, CONTEXT_VCHAR, CONTEXT_HCHAR,
1950	CONTEXT_VTIC, CONTEXT_HTIC, CONTEXT_options, CONTEXT_init,
1951	CONTEXT_reset, CONTEXT_text, null_scale, CONTEXT_graphics,
1952	CONTEXT_move, CONTEXT_vector,
1953	CONTEXT_linetype, CONTEXT_put_text, CONTEXT_text_angle,
1954	CONTEXT_justify_text, CONTEXT_point, CONTEXT_arrow, CONTEXT_set_font,
1955	CONTEXT_pointsize,
1956	/* also add TERM_CAN_CLIP once you understand what it does */
1957	TERM_CAN_DASH | TERM_ALPHA_CHANNEL | TERM_LINEWIDTH | TERM_FONTSCALE | TERM_IS_LATEX /* flags */,
1958	0 /* suspend */, 0 /* resume*/,
1959	CONTEXT_fillbox, CONTEXT_linewidth
1960#ifdef USE_MOUSE
1961	, 0, 0, 0, 0, 0 /* no mouse support */
1962#endif /* USE_MOUSE */
1963	, CONTEXT_make_palette,
1964	0, /* XXX: CONTEXT_previous_palette: not sure if we need it at all (PS does "grestore") */
1965	CONTEXT_set_color,
1966	CONTEXT_filled_polygon,
1967	CONTEXT_image,
1968	0, 0, 0, /* No enhanced text mode because this is TeX */
1969	0,       /* layer (used to signal front/back text, used in canvas, PS, epslatex, ...); XXX: figure out what this has to do */
1970	0        /* path (Path control for end-joins of closed polygons on PostScript-like devices); TODO: implement it (CONTEXT_path) */
1971TERM_TABLE_END(context_driver)
1972#undef LAST_TERM
1973#define LAST_TERM context_driver
1974
1975#endif /* TERM_TABLE */
1976#endif /* TERM_PROTO_ONLY */
1977
1978#ifdef TERM_HELP
1979START_HELP(context)
1980"1 context",
1981"?commands set terminal context",
1982"?set terminal context",
1983"?terminal context",
1984"?set term context",
1985"?term context",
1986"?context",
1987" ConTeXt is a macro package for TeX, highly integrated with Metapost",
1988" (for drawing figures) and intended for creation of high-quality PDF documents.",
1989" The terminal outputs Metafun source, which can be edited manually,",
1990" but you should be able to configure most things from outside.",
1991"",
1992" For an average user of ConTeXt + gnuplot module it's recommended to refer to",
1993" `Using ConTeXt` rather than reading this page",
1994" or to read the manual of the gnuplot module for ConTeXt.",
1995"",
1996" The `context` terminal supports the following options:",
1997"",
1998" Syntax:",
1999"      set term context {default}",
2000"              {defaultsize | size <scale> | size <xsize>{in|cm}, <ysize>{in|cm}}",
2001"              {input | standalone}",
2002"              {timestamp | notimestamp}",
2003"              {noheader | header \"<header>\"}",
2004"              {color | colour | monochrome}",
2005"              {rounded | mitered | beveled} {round | butt | squared}",
2006"              {dashed | solid} {dashlength | dl <dl>}",
2007"              {linewidth | lw <lw>}",
2008"              {fontscale <fontscale>}",
2009"              {mppoints | texpoints}",
2010"              {inlineimages | externalimages}",
2011"              {defaultfont | font \"{<fontname>}{,<fontsize>}\"}",
2012"",
2013" In non-standalone (`input`) graphic only parameters `size` to select graphic",
2014" size, `fontscale` to scale all the labels for a factor <fontscale>",
2015" and font size, make sense, the rest is silently",
2016" ignored and should be configured in the .tex file which inputs the graphic.",
2017" It's highly recommended to set the proper fontsize if document font differs from",
2018" 12pt, so that gnuplot will know how much space to reserve for labels.",
2019"",
2020" `default` resets all the options to their default values.",
2021"",
2022" `defaultsize` sets the plot size to 5in,3in.",
2023" `size` <scale> sets the plot size to <scale> times <default value>.",
2024" If two arguments are given (separated with ','), the first one sets",
2025" the horizontal size and the second one the vertical size.",
2026" Size may be given without units (in which case it means relative to the default",
2027" value), with inches ('in') or centimeters ('cm').",
2028"",
2029" `input` (default) creates a graphic that can be included into another ConTeXt",
2030" document.",
2031" `standalone` adds some lines, so that the document might be compiled as-is.",
2032" You might also want to add `header` in that case.",
2033"",
2034" Use `header` for any additional settings/definitions/macros",
2035" that you might want to include in a standalone graphic. `noheader` is the default.",
2036"",
2037" `notimestamp` prevents printing creation time in comments",
2038" (if version control is used, one may prefer not to commit new version when only date changes).",
2039"",
2040" `color` to make color plots is the default, but `monochrome` doesn't do anything special yet.",
2041" If you have any good ideas how the behaviour should differ to suit the monochrome printers better,",
2042" your suggestions are welcome.",
2043"",
2044" `rounded` (default), `mitered` and `beveled` control the shape of line joins.",
2045" `round` (default), `butt` and `squared` control the shape of line caps.",
2046" See PostScript or PDF Reference Manual for explanation. For wild-behaving functions",
2047" and thick lines",
2048" it is better to use `rounded` and `round` to prevent sharp corners in line joins.",
2049" (Some general support for this should be added to Gnuplot, so that the same options",
2050" could be set for each line (style) separately).",
2051"",
2052" `dashed` (default) uses different dash patterns for different line types,",
2053" `solid` draws all plots with solid lines.",
2054"",
2055" `dashlength` or `dl` scales the length of the dashed-line segments by <dl>.",
2056" `linewidth` or `lw` scales all linewidths by <lw>.",
2057" (lw 1 stands for 0.5bp, which is the default line width when drawing with Metapost.)",
2058" `fontscale` scales text labels for factor <fontscale> relative to default document font.",
2059"",
2060" `mppoints` uses predefined point shapes, drawn in Metapost.",
2061" `texpoints` uses easily configurable set of symbols, defined with ConTeXt",
2062" in the following way:",
2063"      \\defineconversion[my own points][+,{\\ss x},\\mathematics{\\circ}]",
2064"      \\setupGNUPLOTterminal[context][points=tex,pointset=my own points]",
2065"",
2066" `inlineimages` writes binary images to a string and only works in ConTeXt MKIV.",
2067" `externalimages` writes PNG files to disk and also works with ConTeXt MKII.",
2068" Gnuplot needs to have support for PNG images built in for this to work.",
2069"",
2070" With `font` you can set font name and size in standalone graphics.",
2071" In non-standalone (`input`) mode only the font size is important",
2072" to reserve enough space for text labels.",
2073" The command",
2074"      set term context font \"myfont,ss,10\"",
2075" will result in",
2076"      \\setupbodyfont[myfont,ss,10pt]",
2077" If you additionally set `fontscale` to 0.8 for example,",
2078" then the resulting font will be 8pt big and",
2079"      set label ... font \"myfont,12\"",
2080" will come out as 9.6pt.",
2081"",
2082" It is your own responsibility to provide proper typescripts (and header),",
2083" otherwise switching the font will have no effect.",
2084" For a standard font in ConTeXt MKII (pdfTeX) you could use:",
2085"      set terminal context standalone header '\\usetypescript[iwona][ec]' \\",
2086"          font \"iwona,ss,11\"",
2087" Please take a look into ConTeXt documentation, wiki or mailing list (archives)",
2088" for any up-to-date information about font usage.",
2089"",
2090" Examples:",
2091"      set terminal context size 10cm, 5cm     # 10cm, 5cm",
2092"      set terminal context size 4in, 3in      # 4in, 3in",
2093" For standalone (whole-page) plots with labels in UTF-8 encoding:",
2094"      set terminal context standalone header '\\enableregime[utf-8]'",
2095"", /* TODO: LaTeX formatting */
2096"2 Requirements",
2097" You need gnuplot module for ConTeXt",
2098"^ <a href=\"http://ctan.org/pkg/context-gnuplot\">",
2099"      http://ctan.org/pkg/context-gnuplot",
2100"^ </a>",
2101" and a recent version of ConTeXt.",
2102" If you want to call gnuplot on-the-fly, you also need write18 enabled.",
2103" In most TeX distributions this can be set with shell_escape=t in texmf.cnf.",
2104"",
2105" See",
2106"^ <a href=\"http://wiki.contextgarden.net/Gnuplot\">",
2107"           http://wiki.contextgarden.net/Gnuplot",
2108"^ </a>",
2109" for details about this terminal and for more exhaustive help & examples.",
2110"",
2111"2 Calling gnuplot from ConTeXt",
2112" The easiest way to make plots in ConTeXt documents is",
2113"      \\usemodule[gnuplot]",
2114"      \\starttext",
2115"      \\title{How to draw nice plots with {\\sc gnuplot}?}",
2116"      \\startGNUPLOTscript[sin]",
2117"      set format y \"%.1f\"",
2118"      plot sin(x) t '$\\sin(x)$'",
2119"      \\stopGNUPLOTscript",
2120"      \\useGNUPLOTgraphic[sin]",
2121"      \\stoptext",
2122" This will run gnuplot automatically and include the resulting figure in the document."
2123END_HELP(context)
2124#endif /* TERM_HELP */
2125
2126