PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
aqt.c
Go to the documentation of this file.
1 // March 12, 2005
2 //
3 // PLplot driver for AquaTerm and Mac OS X.
4 //
5 // Copyright (C) Per Persson
6 // Copyright (C) 2005 Hazen Babcock
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 //
25 
26 //---------------------------------------------
27 // Header files, defines and local variables
28 // ---------------------------------------------
29 
30 // OS X specific header files
31 
32 #import <Foundation/Foundation.h>
33 #import <AquaTerm/AQTAdapter.h>
34 
35 // PLplot header files
36 
37 #include "plplotP.h"
38 #include "drivers.h"
39 
40 // constants
41 
42 #define SCALE 0.1
43 #define AQT_Default_X 720
44 #define AQT_Default_Y 540
45 #define DPI 72.0
46 
47 #define MAX_STRING_LEN 1000
48 
49 // local variables
50 
51 static NSAutoreleasePool *arpool; // Objective-C autorelease pool
52 static id adapter; // Adapter object
53 
54 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_aqt = "aqt:AquaTerm (Mac OS X):1:aqt:50:aqt\n";
55 
56 static int currentPlot = 0;
57 static int maxWindows = 30;
58 static int windowXSize = 0;
59 static int windowYSize = 0;
60 
61 static bool didTests = false;
62 static bool hasShear = false;
63 static bool hasAlpha = false;
64 
65 // font stuff
66 
67 //
68 // AquaTerm font look-up table
69 //
70 // The table is initialized with lowest common denominator truetype
71 // fonts that (I hope) most Macs will have.
72 //
73 
74 #define AQT_N_FontLookup 30
76  { PL_FCI_MARK | 0x000, (unsigned char *) "Helvetica" },
77  { PL_FCI_MARK | 0x001, (unsigned char *) "Times-Roman" },
78  { PL_FCI_MARK | 0x002, (unsigned char *) "Courier" },
79  { PL_FCI_MARK | 0x003, (unsigned char *) "Times-Roman" },
80  { PL_FCI_MARK | 0x004, (unsigned char *) "LucidaGrande Regular" },
81  { PL_FCI_MARK | 0x010, (unsigned char *) "Helvetica-Oblique" },
82  { PL_FCI_MARK | 0x011, (unsigned char *) "Times-Italic" },
83  { PL_FCI_MARK | 0x012, (unsigned char *) "Courier-Oblique" },
84  { PL_FCI_MARK | 0x013, (unsigned char *) "Times-Italic" },
85  { PL_FCI_MARK | 0x014, (unsigned char *) "LucidaGrande Regular" },
86  { PL_FCI_MARK | 0x020, (unsigned char *) "Helvetica-Oblique" },
87  { PL_FCI_MARK | 0x021, (unsigned char *) "Times-Italic" },
88  { PL_FCI_MARK | 0x022, (unsigned char *) "Courier-Oblique" },
89  { PL_FCI_MARK | 0x023, (unsigned char *) "Times-Italic" },
90  { PL_FCI_MARK | 0x024, (unsigned char *) "LucidaGrande Regular" },
91  { PL_FCI_MARK | 0x100, (unsigned char *) "Helvetica-Bold" },
92  { PL_FCI_MARK | 0x101, (unsigned char *) "Times-Bold" },
93  { PL_FCI_MARK | 0x102, (unsigned char *) "Courier-Bold" },
94  { PL_FCI_MARK | 0x103, (unsigned char *) "Times-Bold" },
95  { PL_FCI_MARK | 0x104, (unsigned char *) "LucidaGrande Regular" },
96  { PL_FCI_MARK | 0x110, (unsigned char *) "Helvetica-BoldOblique" },
97  { PL_FCI_MARK | 0x111, (unsigned char *) "Times-BoldItalic" },
98  { PL_FCI_MARK | 0x112, (unsigned char *) "Courier-BoldOblique" },
99  { PL_FCI_MARK | 0x113, (unsigned char *) "Times-BoldItalic" },
100  { PL_FCI_MARK | 0x114, (unsigned char *) "LucidaGrande Regular" },
101  { PL_FCI_MARK | 0x120, (unsigned char *) "Helvetica-BoldOblique" },
102  { PL_FCI_MARK | 0x121, (unsigned char *) "Times-BoldItalic" },
103  { PL_FCI_MARK | 0x122, (unsigned char *) "Courier-BoldOblique" },
104  { PL_FCI_MARK | 0x123, (unsigned char *) "Times-BoldItalic" },
105  { PL_FCI_MARK | 0x124, (unsigned char *) "LucidaGrande Regular" }
106 };
107 
108 //
109 // AquaTerm font environment variables
110 //
111 // When the driver is initialized it will check to see if
112 // the user has opted to overide one of the above fonts by
113 // setting one of the environment variables below.
114 //
115 // This list must be in the same order with the same number of
116 // elements as the above list
117 //
118 // These are the same environment variable names as would be used
119 // on a linux system, but they have a slightly different meaning.
120 // Since AquaTerm will find the font for us (if it can) given
121 // just the font name, you should only set the environment
122 // variable to the font name. You don't need to provide
123 // a path. If you installed the font using Font Book, AquaTerm
124 // should not have any trouble finding it.
125 //
126 // FIXME: Would it be better to use different environment variable
127 // names then plfreetype.c? If not, then it probably isn't
128 // ideal to have two different copies of the same list of
129 // environment variable names.
130 //
131 
133  "PLPLOT_FREETYPE_SANS_FONT",
134  "PLPLOT_FREETYPE_SERIF_FONT",
135  "PLPLOT_FREETYPE_MONO_FONT",
136  "PLPLOT_FREETYPE_SCRIPT_FONT",
137  "PLPLOT_FREETYPE_SYMBOL_FONT",
138  "PLPLOT_FREETYPE_SANS_ITALIC_FONT",
139  "PLPLOT_FREETYPE_SERIF_ITALIC_FONT",
140  "PLPLOT_FREETYPE_MONO_ITALIC_FONT",
141  "PLPLOT_FREETYPE_SCRIPT_ITALIC_FONT",
142  "PLPLOT_FREETYPE_SYMBOL_ITALIC_FONT",
143  "PLPLOT_FREETYPE_SANS_OBLIQUE_FONT",
144  "PLPLOT_FREETYPE_SERIF_OBLIQUE_FONT",
145  "PLPLOT_FREETYPE_MONO_OBLIQUE_FONT",
146  "PLPLOT_FREETYPE_SCRIPT_OBLIQUE_FONT",
147  "PLPLOT_FREETYPE_SYMBOL_OBLIQUE_FONT",
148  "PLPLOT_FREETYPE_SANS_BOLD_FONT",
149  "PLPLOT_FREETYPE_SERIF_BOLD_FONT",
150  "PLPLOT_FREETYPE_MONO_BOLD_FONT",
151  "PLPLOT_FREETYPE_SCRIPT_BOLD_FONT",
152  "PLPLOT_FREETYPE_SYMBOL_BOLD_FONT",
153  "PLPLOT_FREETYPE_SANS_BOLD_ITALIC_FONT",
154  "PLPLOT_FREETYPE_SERIF_BOLD_ITALIC_FONT",
155  "PLPLOT_FREETYPE_MONO_BOLD_ITALIC_FONT",
156  "PLPLOT_FREETYPE_SCRIPT_BOLD_ITALIC_FONT",
157  "PLPLOT_FREETYPE_SYMBOL_BOLD_ITALIC_FONT",
158  "PLPLOT_FREETYPE_SANS_BOLD_OBLIQUE_FONT",
159  "PLPLOT_FREETYPE_SERIF_BOLD_OBLIQUE_FONT",
160  "PLPLOT_FREETYPE_MONO_BOLD_OBLIQUE_FONT",
161  "PLPLOT_FREETYPE_SCRIPT_BOLD_OBLIQUE_FONT",
162  "PLPLOT_FREETYPE_SYMBOL_BOLD_OBLIQUE_FONT"
163 };
164 
165 // Debugging extras
166 
167 static inline void NOOP_( id x, ... )
168 {
169  ;
170 }
171 
172 #ifdef LOGGING
173 #define LOG NSLog
174 #else
175 #define LOG NOOP_
176 #endif // LOGGING
177 
178 //-----------------------------------------------
179 // function declarations
180 // -----------------------------------------------
181 
182 // helper functions
183 
184 static void get_cursor( PLStream *, PLGraphicsIn * );
185 static void proc_str( PLStream *, EscText * );
186 NSMutableAttributedString * create_string( const PLUNICODE *, int, PLFLT );
187 static void set_font_and_size( NSMutableAttributedString *, PLUNICODE, PLFLT, int );
188 static void check_font_environment_variables( void );
189 
190 // PLplot interface functions
191 
193 void plD_init_aqt( PLStream * );
194 void plD_line_aqt( PLStream *, short, short, short, short );
195 void plD_polyline_aqt( PLStream *, short *, short *, PLINT );
196 void plD_eop_aqt( PLStream * );
197 void plD_bop_aqt( PLStream * );
198 void plD_tidy_aqt( PLStream * );
199 void plD_state_aqt( PLStream *, PLINT );
200 void plD_esc_aqt( PLStream *, PLINT, void * );
201 
202 //--------------------------------------------------------------------------
203 // dispatch_init_init()
204 //
205 // Initialize device dispatch table
206 //--------------------------------------------------------------------------
207 
209 {
210 #ifndef ENABLE_DYNDRIVERS
211  pdt->pl_MenuStr = "AquaTerm - Mac OS X";
212  pdt->pl_DevName = "aqt";
213 #endif
215  pdt->pl_seq = 1;
219  pdt->pl_eop = (plD_eop_fp) plD_eop_aqt;
220  pdt->pl_bop = (plD_bop_fp) plD_bop_aqt;
223  pdt->pl_esc = (plD_esc_fp) plD_esc_aqt;
224 }
225 
226 //--------------------------------------------------------------------------
227 // aqt_init()
228 //
229 // Initialize device
230 //--------------------------------------------------------------------------
231 
232 void plD_init_aqt( PLStream *pls )
233 {
234  if ( arpool == NULL ) // Make sure we don't leak mem by allocating every time
235  {
236  arpool = [[NSAutoreleasePool alloc] init];
237  adapter = [[AQTAdapter alloc] init];
238  }
239  [adapter setBackgroundColorRed : 0.5 green : 0.5 blue : 0.5];
240 
241  pls->termin = 1; // interactive device
242  pls->dev_flush = 1; // Handle our own flushes
243  pls->color = 1; // supports color
244  pls->width = 1;
245  pls->verbose = 1;
246  pls->bytecnt = 0;
247  pls->debug = 1;
248  pls->dev_text = 1; // handles text
249  pls->dev_unicode = 1; // wants text as unicode
250  pls->page = 0;
251  pls->dev_fill0 = 1; // supports hardware solid fills
252  pls->dev_fill1 = 1;
253 
254  pls->graphx = GRAPHICS_MODE;
255 
256  if ( !pls->colorset )
257  pls->color = 1;
258 
259  // Set up device parameters
260 
261  plP_setpxl( DPI / 25.4 / SCALE, DPI / 25.4 / SCALE ); // Pixels/mm.
262 
263  // Set the bounds for plotting. default is AQT_Default_X x AQT_Default_Y unless otherwise specified.
264 
265  if ( pls->xlength <= 0 || pls->ylength <= 0 )
266  {
269  plP_setphy( (PLINT) 0, (PLINT) ( AQT_Default_X / SCALE ), (PLINT) 0, (PLINT) ( AQT_Default_Y / SCALE ) );
270  }
271  else
272  {
273  windowXSize = pls->xlength;
274  windowYSize = pls->ylength;
275  plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / SCALE ), (PLINT) 0, (PLINT) ( pls->ylength / SCALE ) );
276  }
277 
278  // check font environment variables & update font table as necessary
279 
281 
282  // Check to see if the users version of aquaterm supports sheared labels.
283  // If it isn't available 3D plots will look a little strange but things should otherwise be okay.
284 
285  if ( !didTests )
286  {
287  hasShear = [adapter respondsToSelector:@selector( addLabel:atPoint:angle:shearAngle:align: )];
288  hasAlpha = [adapter respondsToSelector:@selector( setColorRed:green:blue:alpha: )];
289  didTests = true;
290  }
291 }
292 
293 //--------------------------------------------------------------------------
294 // aqt_bop()
295 //
296 // Set up for the next page.
297 //--------------------------------------------------------------------------
298 
299 void plD_bop_aqt( PLStream *pls )
300 {
302  [adapter openPlotWithIndex : currentPlot++];
303  [adapter setPlotSize : NSMakeSize( windowXSize, windowYSize )];
304  [adapter setLinewidth : 1.0];
305  if ( hasAlpha )
306  {
307  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
308  green : (float) ( pls->curcolor.g / 255. )
309  blue : (float) ( pls->curcolor.b / 255. )
310  alpha : (float) ( pls->curcolor.a )];
311  }
312  else
313  {
314  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
315  green : (float) ( pls->curcolor.g / 255. )
316  blue : (float) ( pls->curcolor.b / 255. )];
317  }
318 
319  pls->page++;
320 }
321 
322 //--------------------------------------------------------------------------
323 // aqt_line()
324 //
325 // Draw a line in the current color from (x1,y1) to (x2,y2).
326 //--------------------------------------------------------------------------
327 
328 void plD_line_aqt( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
329 {
330  [adapter moveToPoint : NSMakePoint( (float) x1a * SCALE, (float) y1a * SCALE )];
331  [adapter addLineToPoint : NSMakePoint( (float) x2a * SCALE, (float) y2a * SCALE )];
332 }
333 
334 //--------------------------------------------------------------------------
335 // aqt_polyline()
336 //
337 // Draw a polyline in the current color.
338 //--------------------------------------------------------------------------
339 
340 void plD_polyline_aqt( PLStream *pls, short *xa, short *ya, PLINT npts )
341 {
342  int i;
343 
344  for ( i = 0; i < npts - 1; i++ )
345  plD_line_aqt( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] );
346 }
347 
348 //--------------------------------------------------------------------------
349 // aqt_eop()
350 //
351 // End of page
352 //--------------------------------------------------------------------------
353 
354 void plD_eop_aqt( PLStream *pls )
355 {
356  [arpool release]; // prevents a memory leak by freeing everything in
357  // the auto-release pool when the plot is closed.
358  arpool = [[NSAutoreleasePool alloc] init];
359  [adapter renderPlot];
360 }
361 
362 //--------------------------------------------------------------------------
363 // aqt_tidy()
364 //
365 // Close graphics file or otherwise clean up.
366 //--------------------------------------------------------------------------
367 
368 void plD_tidy_aqt( PLStream *pls )
369 {
370  [adapter closePlot];
371 }
372 
373 //--------------------------------------------------------------------------
374 // plD_state_aqt()
375 //
376 // Handle change in PLStream state (color, pen width, fill attribute, etc).
377 //--------------------------------------------------------------------------
378 
379 void plD_state_aqt( PLStream *pls, PLINT op )
380 {
381  int i;
382  float r, g, b;
383 
384  switch ( op )
385  {
386  case PLSTATE_WIDTH:
387  [adapter setLinewidth : (float) pls->width];
388  break;
389 
390  case PLSTATE_COLOR0: // this seems to work, but that isn't to say that it is done right...
391  if ( hasAlpha )
392  {
393  [adapter setBackgroundColorRed : (float) ( plsc->cmap0[0].r / 255.0 )
394  green : (float) ( plsc->cmap0[0].g / 255.0 )
395  blue : (float) ( plsc->cmap0[0].b / 255.0 )
396  alpha : (float) ( plsc->cmap0[0].a )];
397  }
398  else
399  {
400  [adapter setBackgroundColorRed : (float) ( plsc->cmap0[0].r / 255.0 )
401  green : (float) ( plsc->cmap0[0].g / 255.0 )
402  blue : (float) ( plsc->cmap0[0].b / 255.0 )];
403  }
404  case PLSTATE_COLOR1:
405  case PLSTATE_FILL:
406  if ( hasAlpha )
407  {
408  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
409  green : (float) ( pls->curcolor.g / 255. )
410  blue : (float) ( pls->curcolor.b / 255. )
411  alpha : (float) ( pls->curcolor.a )];
412  }
413  else
414  {
415  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
416  green : (float) ( pls->curcolor.g / 255. )
417  blue : (float) ( pls->curcolor.b / 255. )];
418  }
419  break;
420 
421  case PLSTATE_CMAP0:
422  break;
423 
424  case PLSTATE_CMAP1:
425  break;
426  }
427 }
428 
429 //--------------------------------------------------------------------------
430 // aqt_esc()
431 //
432 // Escape function.
433 //
434 // Functions:
435 //
436 // PLESC_EH Handle pending events
437 // PLESC_EXPOSE Force an expose
438 // PLESC_FILL Fill polygon
439 // PLESC_FLUSH Flush X event buffer
440 // PLESC_GETC Get coordinates upon mouse click
441 // PLESC_REDRAW Force a redraw
442 // PLESC_RESIZE Force a resize
443 //--------------------------------------------------------------------------
444 
445 void plD_esc_aqt( PLStream *pls, PLINT op, void *ptr )
446 {
447  int i;
448  switch ( op )
449  {
450  case PLESC_EXPOSE: // handle window expose
451  break;
452  case PLESC_RESIZE: // handle window resize
453  break;
454  case PLESC_REDRAW: // handle window redraw
455  break;
456  case PLESC_TEXT: // switch to text screen
457  break;
458  case PLESC_GRAPH: // switch to graphics screen
459  break;
460  case PLESC_FILL: // fill polygon
461  [adapter moveToVertexPoint : NSMakePoint( pls->dev_x[0] * SCALE, pls->dev_y[0] * SCALE )];
462  for ( i = 1; i < pls->dev_npts; i++ )
463  {
464  [adapter addEdgeToVertexPoint : NSMakePoint( pls->dev_x[i] * SCALE, pls->dev_y[i] * SCALE )];
465  }
466  ;
467  break;
468  case PLESC_DI: // handle DI command
469  break;
470  case PLESC_FLUSH: // flush output
471  [adapter renderPlot];
472  break;
473  case PLESC_EH: // handle Window events
474  break;
475  case PLESC_GETC: // get cursor position
476  [adapter renderPlot]; // needed to give the user something to click on
477  get_cursor( pls, (PLGraphicsIn *) ptr );
478  break;
479  case PLESC_SWIN: // set window parameters
480  break;
481  case PLESC_HAS_TEXT:
482  proc_str( pls, (EscText *) ptr );
483  break;
484  }
485 }
486 
487 //--------------------------------------------------------------------------
488 // get_cursor()
489 //
490 // returns the location of the next mouse click
491 //--------------------------------------------------------------------------
492 
493 void get_cursor( PLStream *pls, PLGraphicsIn *gin )
494 {
495  int scanned, x, y, button;
496  NSString *temp;
497 
498  plGinInit( gin );
499 
500  temp = [adapter waitNextEvent];
501  scanned = sscanf([temp cString], "1:{%d, %d}:%d", &x, &y, &button );
502 
503  if ( scanned == 3 ) // check that we did actually get a reasonable event string
504  {
505  gin->button = button;
506  gin->pX = x;
507  gin->pY = y;
508  gin->dX = (PLFLT) x / ( (PLFLT) ( pls->xlength ) );
509  gin->dY = (PLFLT) y / ( (PLFLT) ( pls->ylength ) );
510  }
511  else // just return zeroes if we did not
512  {
513  printf( "AquaTerm did not return a valid mouse location!\n" );
514  gin->button = 0;
515  gin->pX = 0;
516  gin->pY = 0;
517  gin->dX = 0.0;
518  gin->dY = 0.0;
519  }
520 }
521 
522 //--------------------------------------------------------------------------
523 // proc_str()
524 //
525 // Processes strings for display. The actual parsing of the unicode
526 // string is handled by the sub-routine create_string.
527 //--------------------------------------------------------------------------
528 
529 void proc_str( PLStream *pls, EscText *args )
530 {
531  PLFLT a1, ft_ht, angle, shear, stride;
532  PLINT clxmin, clxmax, clymin, clymax;
533  int i, jst, ref;
534  NSMutableAttributedString *str;
535 
536  // check that we got unicode, warning message and return if not
537 
538  if ( args->unicode_array_len == 0 )
539  {
540  printf( "Non unicode string passed to AquaTerm driver, ignoring\n" );
541  return;
542  }
543 
544  // check that unicode string isn't longer then the max we allow
545 
546  if ( args->unicode_array_len >= MAX_STRING_LEN )
547  {
548  printf( "Sorry, the AquaTerm driver only handles strings of length < %d\n", MAX_STRING_LEN );
549  return;
550  }
551 
552  // set the font height - the 1.2 factor was trial and error
553 
554  ft_ht = 1.2 * pls->chrht * DPI / 25.4; // ft_ht in points. ht is in mm
555 
556  // given transform, calculate rotation angle & shear angle
557  plRotationShear( args->xform, &angle, &shear, &stride );
558  angle *= 180.0 / PI;
559  shear *= -180.0 / PI;
560 
561  // text justification, AquaTerm only supports 3 options, so we round appropriately
562 
563  if ( args->just < 0.33 )
564  jst = AQTAlignLeft; // left
565  else if ( args->just > 0.66 )
566  jst = AQTAlignRight; // right
567  else
568  jst = AQTAlignCenter; // center
569 
570  // set the baseline of the string
571  // Middle and Bottom are set to Middle since this seems to be what PLplot expects
572  // as judged by where it renders the symbols in example 1.
573 
574  if ( args->base == 2 ) // Top
575  ref = AQTAlignTop;
576  else if ( args->base == 1 ) // Bottom
577  ref = AQTAlignMiddle;
578  else
579  ref = AQTAlignMiddle; // Middle
580 
581  // create an appropriately formatted, etc... unicode string
582 
583  str = create_string( args->unicode_array, args->unicode_array_len, ft_ht );
584 
585  // display the string
586 
587  if ( hasAlpha )
588  {
589  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
590  green : (float) ( pls->curcolor.g / 255. )
591  blue : (float) ( pls->curcolor.b / 255. )
592  alpha : (float) ( pls->curcolor.a )];
593  }
594  else
595  {
596  [adapter setColorRed : (float) ( pls->curcolor.r / 255. )
597  green : (float) ( pls->curcolor.g / 255. )
598  blue : (float) ( pls->curcolor.b / 255. )];
599  }
600 
601  if ( hasShear )
602  {
603  [adapter addLabel : str
604  atPoint : NSMakePoint( (float) args->x * SCALE, (float) args->y * SCALE )
605  angle : angle
606  shearAngle : shear
607  align : ( jst | ref )];
608  }
609  else
610  {
611  [adapter addLabel : str
612  atPoint : NSMakePoint( (float) args->x * SCALE, (float) args->y * SCALE )
613  angle : angle
614  align : ( jst | ref )];
615  }
616 
617  [str release];
618 }
619 
620 //--------------------------------------------------------------------------
621 // create_string()
622 //
623 // create a NSMutableAttributedString from the plplot ucs4 string
624 //
625 // assumptions :
626 // 1. font changes are unicode >= PL_FCI_MARK
627 // 2. we'll never have to deal with a string longer then MAX_STRING_LEN characters
628 // 3. <esc><esc> means we desired <esc> as a character & not actually as <esc>
629 // 4. there are no two character <esc> sequences... i.e. <esc>fn is now covered by fci
630 //
631 //--------------------------------------------------------------------------
632 
633 NSMutableAttributedString * create_string( const PLUNICODE *ucs4, int ucs4_len, PLFLT font_height )
634 {
635  PLUNICODE fci;
636  char plplot_esc;
637  int i;
638  int cur_loc;
639  int utf8_len;
640  int updown;
641  char dummy[MAX_STRING_LEN + 1];
642  char *font;
643  char utf8[5];
644  NSMutableAttributedString *str;
645 
646  updown = 0;
647 
648  // initialize the attributed string
649 
650  for ( i = 0; i < MAX_STRING_LEN; i++ )
651  dummy[i] = 'i';
652  dummy[MAX_STRING_LEN] = '\0';
653  str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithCString:dummy]];
654 
655  // get plplot escape character & current font
656 
657  plgesc( &plplot_esc );
658  plgfci( &fci );
659 
660  // set the font for the string based on the current font & size
661 
662  set_font_and_size( str, fci, font_height, 0 );
663 
664  // parse plplot ucs4 string
665 
666  cur_loc = 0;
667  i = 0;
668  while ( i < ucs4_len )
669  {
670  if ( ucs4[i] < PL_FCI_MARK ) // not a font change
671  {
672  if ( ucs4[i] != (PLUNICODE) plplot_esc ) // a character to display
673  {
674  ucs4_to_utf8( ucs4[i], utf8 );
675  [str replaceCharactersInRange : NSMakeRange( cur_loc, 1 )
676  withString :[NSString stringWithUTF8String : utf8]];
677  i++;
678  cur_loc++;
679  continue;
680  }
681  i++;
682  if ( ucs4[i] == (PLUNICODE) plplot_esc )
683  {
684  ucs4_to_utf8( ucs4[i], utf8 );
685  [str replaceCharactersInRange : NSMakeRange( cur_loc, 1 )
686  withString :[NSString stringWithUTF8String : utf8]];
687  i++;
688  cur_loc++;
689  continue;
690  }
691  else
692  {
693  if ( ucs4[i] == (PLUNICODE) 'f' ) // font change
694  {
695  i++;
696  printf( "hmm, unicode string apparently not following fci convention...\n" );
697  }
698  if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
699  {
700  updown--;
701  [str addAttribute : @ "NSSuperScript"
702  value :[NSNumber numberWithInt : updown]
703  range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )];
704  }
705  if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
706  {
707  updown++;
708  [str addAttribute : @ "NSSuperScript"
709  value :[NSNumber numberWithInt : updown]
710  range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )];
711  }
712  i++;
713  }
714  }
715  else // a font change
716  {
717  set_font_and_size( str, ucs4[i], font_height, cur_loc );
718  i++;
719  }
720  }
721 
722  // trim string to appropriate final length
723 
724  [str deleteCharactersInRange : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )];
725 
726  return str;
727 }
728 
729 //--------------------------------------------------------------------------
730 // set_font_and_size
731 //
732 // set the font & size of a attributable string object
733 //--------------------------------------------------------------------------
734 
735 void set_font_and_size( NSMutableAttributedString * str, PLUNICODE fci, PLFLT font_height, int cur_loc )
736 {
737  char *font;
738 
739  font = plP_FCI2FontName( fci, AQT_FontLookup, AQT_N_FontLookup );
740 
741  // check whether that font exists & if not, use standard font instead
742 
743  if ( font == NULL )
744  {
745  printf( "AquaTerm : Warning, could not find font given by fci = 0x%x\n", fci );
746  font = "Helvetica";
747  }
748  /* font = "FreeSerif"; *//* force the font for debugging purposes */
749  // printf("Font at %d is : %s\n", cur_loc, font);
750 
751  [str addAttribute : @ "AQTFontname"
752  value :[NSString stringWithCString : font]
753  range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )];
754  [str addAttribute : @ "AQTFontsize"
755  value :[NSNumber numberWithFloat : font_height]
756  range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )];
757 }
758 
759 //--------------------------------------------------------------------------
760 // check_font_environment_variables
761 //
762 // Checks to see if any font environment variables are defined.
763 // If a font environment variable is defined, then the appropriate
764 // element of the default font table is replaced with the font name
765 // string specified by the environment variable.
766 //--------------------------------------------------------------------------
767 
768 
770 {
771  int i;
772  char *new_font;
773  char *begin;
774  char *end;
775 
776  for ( i = 0; i < AQT_N_FontLookup; i++ )
777  {
778  if ( ( new_font = getenv( aqt_font_env_names[i] ) ) != NULL )
779  {
780  // If the user is just blindly following the suggestions in
781  // the plplot examples then we might get a font name with
782  // a path and extension. We need to remove that since it
783  // isn't relevant and will only cause trouble. We warn them
784  // AquaTerm was not expecting a path or extension.
785 
786  begin = strrchr( new_font, '/' );
787  end = strrchr( new_font, '.' );
788 
789  if ( end != NULL )
790  {
791  printf( "Aquaterm : Warning, removing extension from font name : %s\n", new_font );
792  *end = '\0';
793  }
794  if ( begin != NULL )
795  {
796  printf( "AquaTerm : Warning, removing path from font name : %s\n", new_font );
797  new_font = begin + 1;
798  }
799 
800  // printf("new font : %s\n", new_font);
801 
802  AQT_FontLookup[i].pfont = (unsigned char *) new_font;
803  }
804  }
805 }