Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / aquaterm.trm
1 /* -*- objc -*-
2  * $Id: aquaterm.trm,v 1.31.2.2 2009/07/03 05:36:28 sfeam Exp $
3  *
4  */
5
6 /* GNUPLOT - aquaTerm.trm */
7
8
9 /*
10  * This file is included by ../term.c via ../term.h.
11  *
12  * This terminal driver supports:
13  *     Aqua (Mac OS X/Cocoa)
14  *
15  * AUTHORS
16  *  Per Persson from openstep.trm by Robert Lutwak
17  *
18  * Homepage: http://aquaterm.sourceforge.net
19  * send your comments or suggestions to (persquare@users.sourceforge.net).
20  *
21  * This terminal attempts to connect, via the Mac OS X Distributed
22  * Objects system, to the "aquatermServer."  If there is no such
23  * service registered with the OS, the terminal attempts to fire
24  * up AquaTerm.app.  If the user has not set the environment variable
25  * AQUATERM_PATH, the terminal searches for AquaTerm.app in standard
26  * locations like /Applications, ~/Applications, etc.
27  * In order to use this filter, you MUST have AquaTerm.app installed
28  * on your system.
29  *
30  * Once connected to the server, all gnuplot graphs are sent,
31  * via the D.O. system, to AquaTerm.app, which produces renders graphs,
32  * manages the windows, takes care of printing etc.
33  *
34  */
35
36 #include "driver.h"
37
38 #ifdef TERM_REGISTER
39 register_term(aqua)
40 #endif
41
42 #ifdef TERM_PROTO
43 /* Required entries */
44 TERM_PUBLIC void AQUA_options __PROTO((void));
45 TERM_PUBLIC void AQUA_init __PROTO((void));
46 TERM_PUBLIC void AQUA_reset __PROTO((void));
47 TERM_PUBLIC void AQUA_text __PROTO((void));
48 TERM_PUBLIC void AQUA_graphics __PROTO((void));
49 TERM_PUBLIC void AQUA_move __PROTO((unsigned int x, unsigned int y));
50 TERM_PUBLIC void AQUA_vector __PROTO((unsigned int x, unsigned int y));
51 TERM_PUBLIC void AQUA_linetype __PROTO((int linetype));
52 TERM_PUBLIC void AQUA_put_text __PROTO((unsigned int x, unsigned int y,const char *str));
53 /* Optional entries */
54 TERM_PUBLIC int AQUA_text_angle __PROTO((int));
55 TERM_PUBLIC int AQUA_justify_text __PROTO((enum JUSTIFY));
56 TERM_PUBLIC int AQUA_set_font __PROTO((const char *font));  /* "font,size" */
57 TERM_PUBLIC void AQUA_set_pointsize __PROTO((double size)); /* notification of set pointsize */
58 TERM_PUBLIC void AQUA_point __PROTO((unsigned int, unsigned int, int));
59 TERM_PUBLIC int flags; /* various flags */
60 TERM_PUBLIC void AQUA_suspend __PROTO((void)); /* after one plot of multiplot */
61 TERM_PUBLIC void AQUA_resume __PROTO((void));  /* before subsequent plot of multiplot */
62 TERM_PUBLIC void AQUA_boxfill __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)); /* clear part of multiplot */
63 TERM_PUBLIC void AQUA_linewidth __PROTO((double linewidth));
64 TERM_PUBLIC void AQUA_pointsize __PROTO((double pointsize));
65 TERM_PUBLIC int AQUA_make_palette __PROTO((t_sm_palette *palette));
66 TERM_PUBLIC void AQUA_previous_palette __PROTO((void));
67 TERM_PUBLIC void AQUA_set_color __PROTO((t_colorspec *));
68 TERM_PUBLIC void AQUA_filled_polygon __PROTO((int points, gpiPoint *corners));
69 # ifdef WITH_IMAGE
70 TERM_PUBLIC void AQUA_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
71 # endif
72 TERM_PUBLIC void ENHAQUA_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
73 TERM_PUBLIC void ENHAQUA_open __PROTO((char * fontname, double fontsize,
74                                        double base, TBOOLEAN widthflag, TBOOLEAN showflag,
75                                        int overprint));
76 TERM_PUBLIC void ENHAQUA_flush __PROTO((void));
77 TERM_PUBLIC void ENHAQUA_writec __PROTO((int c));
78 /* End of entries */
79
80 #define AQUA_RESOLUTION (20.0)                    /* Increase resolution */
81 #define AQUA_XMAX (11.75 * 72 * AQUA_RESOLUTION)  /* = paper width (in) times screen resolution */
82 #define AQUA_YMAX (8.25 * 72 * AQUA_RESOLUTION)   /* = paper height (in) times screen resolution */
83 #define AQUA_VTIC (8.0*AQUA_RESOLUTION)
84 #define AQUA_HTIC (8.0*AQUA_RESOLUTION)
85 #define AQUA_VCHAR (16.0*AQUA_RESOLUTION)         /* default font is Times at 14 points */
86 #define AQUA_HCHAR (AQUA_VCHAR*6.0/10.0)
87 #define AQUA_DASH_PATTERNS 8
88 #define AQUA_DEFAULT_DASHLENGTH_FACTOR 0.5
89
90 #define SPECIAL_COLORS 4
91 #define CYCLIC_COLORS 9
92
93 #define GOT_AQUA_PROTO
94 #endif /* TERM_PROTO */
95
96 #ifndef TERM_PROTO_ONLY
97
98 #ifdef TERM_BODY
99 #import <aquaterm/AQTAdapter.h>
100
101 #import <Foundation/NSAutoreleasePool.h>
102 #import <Foundation/NSArray.h>
103 #import <Foundation/NSDictionary.h>
104 #import <Foundation/NSAttributedString.h>
105 #import <stdarg.h>
106
107 /* Debugging extras */
108 static inline void NOOP_(id x, ...) {;}
109
110 #ifdef LOGGING
111 #define LOG  NSLog
112 #else
113 #define LOG  NOOP_
114 #endif  /* LOGGING */
115
116 /* AquaTerm specific */
117 static NSAutoreleasePool *arpool;
118 static NSAutoreleasePool *loopPool;
119 static AQTAdapter *adapter;
120
121 /* Internal state */
122 static int AQUA_plotRef = 0; /* A ref to the current plot */
123 static char AQUA_title[MAX_LINE_LEN + 1] = "Figure 0"; /* Plot title (in windowbar) */
124
125 static unsigned int AQUA_xSize = AQUA_XMAX; /* plot horizontal size */
126 static unsigned int AQUA_ySize = AQUA_YMAX; /* plot vertical size*/
127
128 static int AQUA_LineType = -3; /* current line type*/
129 static float AQUA_LineWidth = 1.0; /* current line width*/
130 static float AQUA_TextAngle = 0.0; /* current text orientation*/
131 static enum JUSTIFY AQUA_TextJust = LEFT; /* current text justification*/
132
133 /* default text font family: */
134 static char AQUA_fontNameDef[MAX_ID_LEN + 1] = "Times-Roman";
135 static double AQUA_fontSizeDef = 14; /* default text size*/
136 /* current text font family: */
137 static char AQUA_fontNameCur[MAX_ID_LEN + 1] = "Times-Roman";
138 static double AQUA_fontSizeCur = 14; /* current text size*/
139
140 /* dash patterns */
141 static TBOOLEAN AQUA_dashedlines = FALSE;
142 static float AQUA_dashlength_factor = AQUA_DEFAULT_DASHLENGTH_FACTOR;
143 static int AQUA_dashPatternLengths[AQUA_DASH_PATTERNS] = {0, 2, 2, 2, 4, 4, 4, 6};
144 static int AQUA_dashPatterns[AQUA_DASH_PATTERNS][6] = {
145         {0, 0, 0, 0, 0, 0},
146         {8, 8, 0, 0, 0, 0},
147         {4, 6, 0, 0, 0, 0},
148         {2, 3, 0, 0, 0, 0},
149         {12, 4, 2, 4, 0, 0},
150         {6, 6, 2, 6, 0, 0},
151         {4, 4, 4, 12, 0, 0},
152         {1, 4, 12, 4, 1, 4}
153     };
154
155 /* Helper functions */
156 static NSString* AQUA_convert_using_encoding __PROTO((const char *string));
157
158 /*
159  * ----------------------------------------------------------------
160  * Aquaterm driver implementation
161  * ----------------------------------------------------------------
162  *
163  *   Current options are:
164  *   <n> title "theTitle" size <x> <y> fname "fontface" fsize <fontsize>
165  */
166 TERM_PUBLIC void
167 AQUA_options()
168 {
169   struct value a;
170   char *s;
171   TBOOLEAN set_number = FALSE;
172   
173   AQUA_title[0] = '\0'; /* Force re-interpretation of title string */
174
175   while (!END_OF_COMMAND) {
176   
177     if (almost_equals(c_token, "ti$tle"))  {
178         c_token++;
179
180         if (!(s = try_to_get_string()))
181             int_error(c_token,"fname: expecting plot title");
182         strncpy(AQUA_title,s,sizeof(AQUA_title));
183         free(s);
184         continue;
185     }
186
187     if (almost_equals(c_token, "s$ize")) {
188         double value;
189
190         c_token++;
191
192         if (END_OF_COMMAND)
193             int_error(c_token,"expecting x size");
194         value = real(const_express (&a));
195         if (value < 2 || value > 2048)
196             int_error(c_token,"x size out of range");
197         AQUA_xSize = (unsigned int) value * AQUA_RESOLUTION;
198
199         if (END_OF_COMMAND)
200             int_error(c_token,"expecting y size");
201         if (equals(c_token, ","))
202             c_token++;
203         value = real(const_express (&a));
204         if (value < 2 || value > 2048)
205             int_error(c_token,"y size out of range");
206         AQUA_ySize = (unsigned int) value * AQUA_RESOLUTION;
207         continue;
208     }
209
210     if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font"))  {
211         char *comma;
212         c_token++;
213     
214         if (!(s = try_to_get_string()))
215             int_error(c_token,"expecting font specifier");
216         comma = strrchr(s, ',');
217         if (comma && (1 == sscanf(comma+1, "%lf", &AQUA_fontSizeCur)))
218             *comma = '\0';
219         if (*s)
220             strncpy(AQUA_fontNameCur, s, sizeof(AQUA_fontNameCur));
221         free(s);
222         continue;
223     }
224
225     if (almost_equals(c_token, "fs$ize")) {
226         c_token++;
227
228         if (END_OF_COMMAND)
229             int_error(c_token,"expecting font size");
230         AQUA_fontSizeCur = real (const_express (&a));
231         continue;
232     }
233
234         if (equals(c_token, "solid")) {
235             c_token++;
236             AQUA_dashedlines = FALSE;
237             continue;
238         }
239         
240         if (almost_equals(c_token, "dash$ed")) {
241             c_token++;
242             AQUA_dashedlines = TRUE;
243             continue;
244         }
245
246         if (equals(c_token, "dl") || almost_equals(c_token, "dashl$ength")) {
247             c_token++;
248             if (END_OF_COMMAND)
249                 int_error(c_token, "expecting dashlength multiplier");
250             AQUA_dashlength_factor = real(const_express(&a));
251             if (AQUA_dashlength_factor < 0.0)
252                 AQUA_dashlength_factor = AQUA_DEFAULT_DASHLENGTH_FACTOR;
253             continue;
254         }
255
256     if (almost_equals(c_token, "enh$anced")) {
257       term->put_text = ENHAQUA_put_text;
258       c_token++;
259       term->flags |= TERM_ENHANCED_TEXT;
260       continue;
261     }
262
263     if (almost_equals(c_token, "noenh$anced")) {
264       term->put_text = AQUA_put_text;
265       c_token++;
266       term->flags &= ~TERM_ENHANCED_TEXT;
267       continue;
268     }
269
270     if (!set_number) { /* plot ref number */
271         AQUA_plotRef = (int) real (const_express (&a));
272         set_number = TRUE;
273         continue;
274     }
275
276     int_error(c_token, "unexpected text at end of command");
277   }
278
279   if (AQUA_title[0]=='\0') /* always set title */
280     sprintf(AQUA_title, "Figure %d", AQUA_plotRef);
281   /* Save options back into options string in normalized format */
282   sprintf(term_options, "%d title \"%s\" size %d,%d font \"%s,%g\" %s %s",
283           AQUA_plotRef,
284           AQUA_title,
285           (unsigned int) (AQUA_xSize/AQUA_RESOLUTION), (unsigned int) (AQUA_ySize/AQUA_RESOLUTION),
286           AQUA_fontNameCur, AQUA_fontSizeCur,
287           term->put_text == ENHAQUA_put_text?"enhanced":"noenhanced", 
288           AQUA_dashedlines?"dashed":"solid");
289   if (AQUA_dashedlines)
290     sprintf(&(term_options[strlen(term_options)]), " dl %3.1f", AQUA_dashlength_factor);
291 }
292
293 static NSString* 
294 AQUA_convert_using_encoding(const char *string)
295 {
296   static bool didCheckEncodingSupport = false;
297   static bool hasStringEncodingSupport = false;
298   NSStringEncoding currentEncoding;
299   NSString *translatedString;
300
301   /* Check encoding support in system on first call */
302   if(!didCheckEncodingSupport) {
303     didCheckEncodingSupport = true;
304     hasStringEncodingSupport = [NSString respondsToSelector:@selector(stringWithCString:encoding:)];
305   }
306   /* Set encoding as requested by user via "set encoding" */
307   switch(encoding){
308   case S_ENC_ISO8859_1:
309     currentEncoding = NSISOLatin1StringEncoding;
310     break;
311   case S_ENC_ISO8859_2:
312     currentEncoding = NSISOLatin2StringEncoding;
313     break;
314   case S_ENC_CP1250:
315     currentEncoding = NSWindowsCP1250StringEncoding;
316     break;
317     /* FIXME: Add more encodings... */
318   case S_ENC_DEFAULT:  /* Fallthrough */
319   default :
320     /* UTF8 is 'default' */
321     currentEncoding = NSUTF8StringEncoding;
322     break;
323   }
324   /* Perform translation (into UTF8 encoding used by Mac OS X) */
325   if (hasStringEncodingSupport) {
326     translatedString = [NSString stringWithCString:string encoding:currentEncoding];
327   } else {
328     translatedString = [NSString stringWithCString:string];
329   }
330   /* Check for nil result before returning */
331   return translatedString?translatedString:@"";
332 }
333
334 TERM_PUBLIC void
335 AQUA_init()
336 {
337   float fontSize, fontWHRatio;
338   NSString *title;
339
340   LOG(@"Aqua Init (open plot)");
341   if (arpool == NULL) {
342     /* FIXME: This should be removed when pools are handled in gnuplot proper */
343     arpool = [[NSAutoreleasePool alloc] init];
344   }
345   if (adapter == NULL) {
346     adapter = [[AQTAdapter alloc] init];
347     if (!adapter) { /* server could be invalid (=nil) for several reasons */
348       /* FIXME: Issue warning here? */
349     }
350   }
351
352   /* Must open plot before all other commands */
353   [adapter openPlotWithIndex:AQUA_plotRef];
354
355   /* set xmax, ymax*/
356   term->xmax = AQUA_xSize;
357   term->ymax = AQUA_ySize;
358   /* set current font*/
359   [adapter setFontname:AQUA_convert_using_encoding(AQUA_fontNameCur)];
360   [adapter setFontsize:AQUA_fontSizeCur];
361   /* set h_char, v_char*/
362   term->h_char = (int) (AQUA_fontSizeCur * 0.6 * AQUA_RESOLUTION);
363   term->v_char = (int) (AQUA_fontSizeCur * 1.5 * AQUA_RESOLUTION);
364   /* set h_tic, v_tic*/
365   term->h_tic = term->v_char / 3;
366   term->v_tic = term->v_char / 3;
367
368   [adapter setPlotSize:NSMakeSize(AQUA_xSize/AQUA_RESOLUTION, AQUA_ySize/AQUA_RESOLUTION)];
369   [adapter setPlotTitle:AQUA_convert_using_encoding(AQUA_title)];
370
371   /*
372    * Set up the basic indexed colormap for gnuplot
373    */
374   /*  Special colors */
375   [adapter setColormapEntry:0 red:0.1 green:0.1 blue:0.1]; /* linetype -4 */
376   [adapter setColormapEntry:1 red:0.9 green:0.9 blue:0.9]; /* linetype -3 (xor;interactive) light gray */
377   [adapter setColormapEntry:2 red:0.0 green:0.0 blue:0.0]; /* linetype -2 (border) black */
378   [adapter setColormapEntry:3 red:0.8 green:0.8 blue:0.8]; /* linetype -1 (gridlines) light grey */
379   /*  Cyclic colors */
380   [adapter setColormapEntry:4 red:1.0 green:0.0 blue:0.0]; /* red */
381   [adapter setColormapEntry:5 red:0.0 green:1.0 blue:0.0]; /* green */
382   [adapter setColormapEntry:6 red:0.0 green:0.0 blue:1.0]; /* blue */
383   [adapter setColormapEntry:7 red:1.0 green:0.0 blue:1.0]; /* magenta */
384   [adapter setColormapEntry:8 red:0.0 green:1.0 blue:1.0]; /* cyan */
385   [adapter setColormapEntry:9 red:0.6275 green:0.3216 blue:0.1765]; /* sienna */
386   [adapter setColormapEntry:10 red:1.0 green:0.6471 blue:0.0]; /* orange */
387   [adapter setColormapEntry:11 red:0.5 green:0.4980 blue:0.3137]; /* coral */
388   [adapter setColormapEntry:12 red:0.25 green:0.25 blue:0.25]; /* grey */
389
390 }
391
392 TERM_PUBLIC void
393 AQUA_reset()
394 {
395   LOG(@"Aqua reset");
396 }
397
398 TERM_PUBLIC void
399 AQUA_text()
400 {
401   LOG(@"Aqua text (render)");
402   [adapter renderPlot];
403 }
404
405 TERM_PUBLIC void
406 AQUA_graphics()
407 {
408 #ifdef LOGGING
409   /* Keep the compiler quiet when not debugging */
410   LOG(@"Pre:  (arpool + loopPool, loopPool) =(%d, %d)", [NSAutoreleasePool autoreleasedObjectCount],
411       [NSAutoreleasePool topAutoreleasePoolCount]);
412 #endif
413   /* Avoid buildup of objects in the autoreleasepools */
414   [loopPool release];
415   loopPool = [[NSAutoreleasePool alloc] init];
416 #ifdef LOGGING
417   /* Keep the compiler quiet when not debugging */
418   LOG(@"Post: (arpool + loopPool, loopPool) =(%d, %d)",[NSAutoreleasePool autoreleasedObjectCount],
419       [NSAutoreleasePool topAutoreleasePoolCount]);
420 #endif
421   [adapter eraseRect:NSMakeRect(0.0, 0.0, AQUA_xSize/AQUA_RESOLUTION, AQUA_ySize/AQUA_RESOLUTION)];
422 }
423
424 TERM_PUBLIC void
425 AQUA_move(unsigned int x, unsigned int y)
426 {
427   [adapter moveToPoint:NSMakePoint(x/AQUA_RESOLUTION, y/AQUA_RESOLUTION)];
428 }
429
430 TERM_PUBLIC void
431 AQUA_vector(unsigned int x, unsigned int y)
432 {
433   [adapter addLineToPoint:NSMakePoint(x/AQUA_RESOLUTION, y/AQUA_RESOLUTION)];
434 }
435
436 TERM_PUBLIC void
437 AQUA_linetype(int linetype)
438 {
439   float dash[8];
440   int i, style;
441   LOG(@"AQUA_linetype(%d) ---> entry: %d", linetype, (linetype%CYCLIC_COLORS)+SPECIAL_COLORS);
442   if (linetype != AQUA_LineType) {
443     /* Note: this operation maps linestyle -4 to -1 onto colormap entries 0 to 3 */
444     AQUA_LineType = linetype;
445     [adapter takeColorFromColormapEntry:(linetype%CYCLIC_COLORS)+SPECIAL_COLORS];
446   }
447   if (AQUA_dashedlines) {
448     style = linetype%AQUA_DASH_PATTERNS;
449     if (style <= 0) {
450        [adapter setLinestyleSolid];
451     } else {      
452        // Set up a dash array
453            for(i = 0; i<AQUA_dashPatternLengths[style]; i++) {
454               dash[i] = AQUA_dashPatterns[style][i] * AQUA_dashlength_factor;
455            }
456        [adapter setLinestylePattern:dash count:AQUA_dashPatternLengths[style] phase:0.0];
457     }
458   }
459 }
460
461 TERM_PUBLIC void
462 AQUA_put_text(unsigned int x, unsigned int y, const char *str)
463 {
464   if (!strlen(str))
465     return;
466   [adapter  addLabel:AQUA_convert_using_encoding(str)
467              atPoint:NSMakePoint(x/AQUA_RESOLUTION, y/AQUA_RESOLUTION)
468                angle:AQUA_TextAngle
469                align:(AQUA_TextJust | AQTAlignMiddle)];
470 }
471
472 TERM_PUBLIC int
473 AQUA_justify_text (enum JUSTIFY mode)
474 {
475   AQUA_TextJust = mode;
476   return (TRUE);
477 }
478
479 TERM_PUBLIC int
480 AQUA_text_angle (int angle)
481 {
482   AQUA_TextAngle = (float)angle;
483   return (TRUE);
484 }
485
486 TERM_PUBLIC int
487 AQUA_set_font(const char *font) /* "font,size" */
488 {
489   /* Obtain default fontname and fontsize. If these are invalid, AquaTerm will handle it. */
490   NSString *fontFace = AQUA_convert_using_encoding(AQUA_fontNameCur);
491   float fontSize = AQUA_fontSizeCur;
492   
493   if (strlen(font) > 0) {
494     /* Try to split the non-empty string into array parts (as string objects) */
495     NSArray *parts = [AQUA_convert_using_encoding(font) componentsSeparatedByString:@","];
496     /* Check that we have both non-empty name and size, otherwise stay with defaults */
497     if ([parts count] > 0 && ![[parts objectAtIndex:0] isEqualToString:@""] ) {
498       fontFace = [parts objectAtIndex:0]; /* fontname */
499       if ([parts count] > 1 && ![[parts objectAtIndex:1] isEqualToString:@""] ) {
500         fontSize = [[parts objectAtIndex:1] floatValue]; /* Convert (optional) 2nd string object (fontsize) to float */ 
501       }   
502     }
503   }
504
505   LOG(@"Setting:(%@,%f)", fontFace, fontSize);
506   [adapter setFontname:fontFace];
507   [adapter setFontsize:fontSize];
508
509   term->h_char = (int) (fontSize * 0.6 * AQUA_RESOLUTION);
510   term->v_char = (int) (fontSize * 1.5 * AQUA_RESOLUTION);
511
512   return (TRUE);
513 }
514
515 TERM_PUBLIC void
516 AQUA_set_pointsize(double size) /* notification of set pointsize */
517 {
518   LOG(@"AQUA_set_pointsize(%f)", size);
519 }
520
521 TERM_PUBLIC void
522 AQUA_point(unsigned int x, unsigned int y, int number)
523 {
524   /* The default dot-routine doesn't work with AQT */
525   [adapter setLinestyleSolid]; /* Symbols should never be dashed */
526   [adapter setLinewidth:1.0];  
527   [adapter setLineCapStyle:AQTRoundLineCapStyle]; /* Set line cap style to round to create a dot */
528   [adapter moveToPoint:NSMakePoint(x/AQUA_RESOLUTION-0.005, y/AQUA_RESOLUTION)];
529   [adapter addLineToPoint:NSMakePoint(x/AQUA_RESOLUTION+0.005, y/AQUA_RESOLUTION)];
530   [adapter moveToPoint:NSMakePoint(0,0)]; /* Force a path end  to work around a bug in AquaTerm 1.0.0 */
531   /* Round caps results in nicer symbols too */  
532   if (number>=0) {
533     do_point(x, y, number);
534   }
535   [adapter moveToPoint:NSMakePoint(0,0)]; /* Force a path end to work around a bug in AquaTerm 1.0.0 */
536   [adapter setLineCapStyle:AQTButtLineCapStyle]; /* Reset line capstyle */
537 }
538
539 /* after one plot of multiplot */
540 TERM_PUBLIC void
541 AQUA_suspend()
542 {
543   [adapter renderPlot];
544 }
545
546 /* before subsequent plot of multiplot */
547 TERM_PUBLIC void
548 AQUA_resume()
549 {
550 }
551
552 /* clear part of multiplot */
553 TERM_PUBLIC void
554 AQUA_boxfill(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
555 {
556   float r,g,b;
557
558   LOG(@"\nstyle=%d\nstyle & 0xf = %d\nfillpar=%d\n", style, style & 0xf, style >> 4);
559   /* Save current color */
560   [adapter getColorRed:&r green:&g blue:&b];
561
562   /* fillpar:
563    * - solid   : 0 - 100
564    * - pattern : 0 - 100
565    */
566   int fillpar = style >> 4;
567
568   style &= 0xf;
569
570   switch (style) {
571   case 0: /* fill with background color */
572     {
573       float rb, gb, bb;
574       [adapter getBackgroundColorRed:&rb green:&gb blue:&bb];
575       [adapter setColorRed:rb green:gb blue:bb];
576     }
577     break;
578   case FS_SOLID: /* solid fill */
579     {
580       /* Alpha channel? RGB -> HSV -> R'G'B'? */
581       float density = (100 - fillpar)*0.01;
582       [adapter setColorRed:r*(1-density) + density
583                      green:g*(1-density) + density
584                       blue:b*(1-density) + density];
585     }
586     break;
587   case FS_PATTERN: /* pattern fill */
588     /* Can't do pattern easily, using colors. */
589     [adapter takeColorFromColormapEntry:(fillpar%CYCLIC_COLORS)+SPECIAL_COLORS];
590     break;
591   default:
592     break;
593   }
594
595   NSRect scaledRect = NSMakeRect(x1/AQUA_RESOLUTION, y1/AQUA_RESOLUTION, width/AQUA_RESOLUTION, height/AQUA_RESOLUTION);
596   [adapter eraseRect:scaledRect];
597   [adapter addFilledRect:scaledRect];
598   /* Restore color */
599   [adapter setColorRed:r green:g blue:b];
600 }
601
602 TERM_PUBLIC void
603 AQUA_linewidth(double linewidth)
604 {
605   [adapter setLinewidth:linewidth];
606 }
607
608 TERM_PUBLIC void
609 AQUA_pointsize(double pointsize)
610 {
611   LOG(@"AQUA_pointsize(%f)", pointsize);
612   term_pointsize = pointsize;
613 }
614
615 TERM_PUBLIC int
616 AQUA_make_palette(t_sm_palette *palette)
617 {
618   if (palette == NULL) {
619     /* AquaTerm can do continuous colors */
620     return 0;
621   }
622   return 0;
623 }
624
625 TERM_PUBLIC void
626 AQUA_set_color(t_colorspec *colorspec)
627 {
628   rgb_color color;
629   
630   switch (colorspec->type) {
631   case TC_FRAC:
632     rgb1maxcolors_from_gray(colorspec->value, &color);
633     [adapter setColorRed:color.r green:color.g blue:color.b];
634     break;
635   case TC_RGB:
636     color.r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
637     color.g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
638     color.b = (double)(colorspec->lt & 255) / 255.;
639     [adapter setColorRed:color.r green:color.g blue:color.b];
640     break;
641   case TC_LT:
642     [adapter takeColorFromColormapEntry:((colorspec->lt)%CYCLIC_COLORS)+SPECIAL_COLORS];
643     break;
644   default:
645     break;
646   }
647   AQUA_LineType = LT_UNDEFINED;
648 }
649
650 TERM_PUBLIC void
651 AQUA_filled_polygon(int pc, gpiPoint *corners)
652 {
653   int i;
654   [adapter moveToVertexPoint:NSMakePoint(corners[0].x/AQUA_RESOLUTION,
655                                          corners[0].y/AQUA_RESOLUTION)];
656   for (i=1; i<pc; i++) {
657     [adapter addEdgeToVertexPoint:NSMakePoint(corners[i].x/AQUA_RESOLUTION,
658                                               corners[i].y/AQUA_RESOLUTION)];
659   }
660 }
661
662 TERM_PUBLIC void
663 AQUA_previous_palette()
664 {
665 }
666
667 #ifdef WITH_IMAGE
668
669 TERM_PUBLIC void
670 AQUA_image (unsigned int M, unsigned int N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
671 {
672   float width = (corner[1].x - corner[0].x)/AQUA_RESOLUTION;   
673   float height = (corner[0].y - corner[1].y)/AQUA_RESOLUTION;
674   float xPos = corner[0].x/AQUA_RESOLUTION;
675   float yPos = corner[1].y/AQUA_RESOLUTION;  
676   int bitmapSize = M*N;
677   int targetSize = 3 * bitmapSize;
678   int srcSize;
679   unsigned char *bitmap;
680   int i;
681
682   bitmap = malloc(targetSize*sizeof(unsigned char));
683   if (bitmap != nil) {
684     if (color_mode == IC_RGB) {
685       srcSize = targetSize;
686       for (i=0;i<srcSize;i++) {
687         bitmap[i] = (unsigned char)(255*image[i]);
688       }
689     } else if (color_mode == IC_PALETTE) {
690       rgb_color color;
691       unsigned char *bitmapPtr = bitmap;
692       srcSize = bitmapSize;
693       for (i=0;i<srcSize;i++) {
694         rgb1maxcolors_from_gray(image[i], &color);
695         *bitmapPtr = (unsigned char)(255*color.r);
696         bitmapPtr++;
697         *bitmapPtr = (unsigned char)(255*color.g);
698         bitmapPtr++;
699         *bitmapPtr = (unsigned char)(255*color.b);
700         bitmapPtr++;
701       }
702     } else {
703       NSLog(@"Unknown bitmap format");
704     }
705     [adapter addImageWithBitmap:bitmap 
706              size:NSMakeSize(M, N)
707              bounds:NSMakeRect(xPos, yPos, width, height)];
708     free(bitmap);
709   }
710   return;
711 }
712
713 #endif /* WITH_IMAGE */
714
715 /*
716  * Per Persson 20041019
717  * Support for enhanced text mode
718  * 
719  * Known issues:
720  *   - Overprinting not implemented 
721  *   - The sub/superscript level is determined from relative fontsize,
722  *     it may break if fontsize is changed for individual characters.
723  */
724
725 static NSMutableAttributedString *enhString;
726 static NSMutableDictionary *attributes;
727
728 TERM_PUBLIC void 
729 ENHAQUA_put_text(unsigned int x, unsigned int y, const char str[])
730 {
731   if (!strpbrk(str, "{}^_@&~"))
732     {
733       AQUA_put_text(x,y,str);
734       return;
735     }
736   /* set up the global variables needed by enhanced_recursion() */
737   enhanced_max_height = -1000;
738   enhanced_min_height = 1000;
739   enhanced_fontscale = 1;
740   strncpy(enhanced_escape_format,"\\%o",sizeof(enhanced_escape_format));
741   
742   /* Clear the attributed string */
743   [enhString release];
744   enhString = [[NSMutableAttributedString alloc] init];
745   [enhString setAttributedString:[[NSAttributedString alloc] initWithString:@""]];
746
747   while (*(str = enhanced_recursion((char *)str, TRUE, AQUA_fontNameCur,
748                                     (double)(AQUA_fontSizeCur), 0.0, TRUE, TRUE, 0))) {
749     /* I think we can only get here if *str == '}' */
750     enh_err_check(str);
751
752     if (!*++str)
753       break; /* end of string */
754     /* else carry on and process the rest of the string */
755   }
756
757   /* Now, send the attributed string to the adapter */
758   [adapter  addLabel:enhString
759             atPoint:NSMakePoint(x/AQUA_RESOLUTION, y/AQUA_RESOLUTION)
760             angle:AQUA_TextAngle
761             align:(AQUA_TextJust | AQTAlignMiddle)];
762
763 }
764
765 TERM_PUBLIC void 
766 ENHAQUA_open(char * fontname, double fontsize,
767              double base, TBOOLEAN widthflag, TBOOLEAN showflag,
768              int overprint)
769 {
770   LOG(@"%s %.1f %.1f %s %s %d", fontname, fontsize, base,
771       widthflag ? "true" : "false",
772       showflag ? "true" : "false",
773       overprint);
774   
775   if (overprint != 0)
776     return;
777   
778   [attributes release];
779   attributes = [[NSMutableDictionary alloc] initWithCapacity:16]; 
780   [attributes setObject:AQUA_convert_using_encoding(fontname) forKey:@"AQTFontname"];
781
782   if (abs(base)>0.01) { 
783     /* consider this as super/subscript, and compute subscript level */
784     int n = (int)round(log(fontsize/AQUA_fontSizeCur)/log(0.8)); 
785     [attributes setObject:[NSNumber numberWithInt:(base > 0)?n:-n] 
786                    forKey:@"NSSuperScript"];
787   } else if (abs(fontsize - AQUA_fontSizeCur)>0.01) {
788     /* Fontsize was set explicitly */
789     [attributes setObject:[NSNumber numberWithFloat:fontsize] forKey:@"AQTFontsize"];
790   }
791
792   if (!showflag)
793     [attributes setObject:[NSNumber numberWithInt:1] 
794                    forKey:@"AQTNonPrintingChar"];
795 }
796
797 /* Local buffer used in encoding conversion */
798 #define ENHAQUA_CSTRBUFLEN 1023
799 static char cStrBuf[ENHAQUA_CSTRBUFLEN + 1]; 
800 static unsigned int cStrBufIndex = 0;
801
802 TERM_PUBLIC void 
803 ENHAQUA_flush(void)
804 {
805   /* Convert cStrBuf UTF8 according to encoding, use convert_using_encoding()
806      and apply attributes before adding to enhString 
807   */
808   NSAttributedString *aStr;
809   cStrBuf[cStrBufIndex] = '\0';
810   cStrBufIndex = 0; 
811   aStr = [[NSAttributedString alloc] initWithString:AQUA_convert_using_encoding(cStrBuf) attributes:attributes];
812   [enhString appendAttributedString:aStr];
813   [aStr release];
814 }
815
816 TERM_PUBLIC void 
817 ENHAQUA_writec(int c)
818
819   /* Buffer byte sequence into cStrBuf */
820   LOG(@"int c = 0x%04x", c);
821   cStrBuf[cStrBufIndex] = (char)(c+0x100) & 0xFF; /* FIXME: Sometimes c is overflowed */
822   if (cStrBufIndex < ENHAQUA_CSTRBUFLEN) 
823     cStrBufIndex++;
824 }
825 #endif /* TERM_BODY */
826
827 #ifdef TERM_TABLE
828
829 TERM_TABLE_START(aqua_driver)
830   "aqua",
831   "Interface to graphics terminal server for Mac OS X",
832   0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
833   0 /* vtic */ , 0 /* htic */ ,
834   AQUA_options, AQUA_init, AQUA_reset,
835   AQUA_text, null_scale, AQUA_graphics, AQUA_move, AQUA_vector,
836   AQUA_linetype, AQUA_put_text,
837   /* optionals */
838   AQUA_text_angle,
839   AQUA_justify_text, AQUA_point, do_arrow, AQUA_set_font,
840   AQUA_pointsize, TERM_CAN_MULTIPLOT|TERM_NO_OUTPUTFILE,
841   AQUA_suspend, AQUA_resume,
842   AQUA_boxfill, AQUA_linewidth
843 #ifdef USE_MOUSE
844   , 0, 0, 0, 0, 0
845 #endif /* USE_MOUSE */
846   , AQUA_make_palette,
847   AQUA_previous_palette,
848   AQUA_set_color,
849   AQUA_filled_polygon
850 #ifdef WITH_IMAGE
851   , AQUA_image
852 #endif
853     , ENHAQUA_open, ENHAQUA_flush, ENHAQUA_writec
854 TERM_TABLE_END(aqua_driver)
855
856 #undef LAST_TERM
857 #define LAST_TERM aqua_driver
858
859 #endif /* TERM_TABLE */
860 #endif /* TERM_PROTO_ONLY */
861
862 #ifdef TERM_HELP
863 START_HELP(aqua)
864 "1 aqua",
865 "?commands set terminal aqua",
866 "?set terminal aqua",
867 "?set term aqua",
868 "?terminal aqua",
869 "?term aqua",
870 "?aqua",
871 "?Aqua",
872 " This terminal relies on AquaTerm.app for display on Mac OS X.",
873 "",
874 " Syntax:",
875 "       set terminal aqua {<n>} {title \"<wintitle>\"} {size <x> <y>}",
876 "                         {font \"<fontname>{,<fontsize>}\"}",
877 "                         {{no}enhanced} {solid|dashed} {dl <dashlength>}}",
878 "",
879 " where <n> is the number of the window to draw in (default is 0),",
880 " <wintitle> is the name shown in the title bar (default \"Figure <n>\"),",
881 " <x> <y> is the size of the plot (default is 846x594 pt = 11.75x8.25 in).",
882 "",
883 " Use <fontname> to specify the font to use (default is \"Times-Roman\"),",
884 " and <fontsize> to specify the font size (default is 14.0 pt). The old syntax",
885 " {fname \"<fontname>\"} {fsize <fontsize>} is still supported.",
886 "",
887 " The aqua terminal supports enhanced text mode (see `enhanced`), except for",
888 " overprint. Font support is limited to the fonts available on the system.",
889 " Character encoding can be selected by `set encoding` and currently supports",
890 " iso_latin_1, iso_latin_2, cp1250, and default which equals UTF8.",
891 "",
892 " Lines can be drawn either solid or dashed, (default is solid) and the dash",
893 " spacing can be modified by <dashlength> which is a multiplier > 0.",
894 ""
895 END_HELP(aqua)
896 #endif /* TERM_HELP */
897
898