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
75 static FCI_to_FontName_Table AQT_FontLookup[AQT_N_FontLookup] = {
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
132 const char *aqt_font_env_names[AQT_N_FontLookup] = {
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
NOOP_(id x,...)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
192 void plD_dispatch_init_aqt( PLDispatchTable *pdt );
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
plD_dispatch_init_aqt(PLDispatchTable * pdt)208 void plD_dispatch_init_aqt( PLDispatchTable *pdt )
209 {
210 #ifndef ENABLE_DYNDRIVERS
211 pdt->pl_MenuStr = "AquaTerm - Mac OS X";
212 pdt->pl_DevName = "aqt";
213 #endif
214 pdt->pl_type = plDevType_Interactive;
215 pdt->pl_seq = 1;
216 pdt->pl_init = (plD_init_fp) plD_init_aqt;
217 pdt->pl_line = (plD_line_fp) plD_line_aqt;
218 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_aqt;
219 pdt->pl_eop = (plD_eop_fp) plD_eop_aqt;
220 pdt->pl_bop = (plD_bop_fp) plD_bop_aqt;
221 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_aqt;
222 pdt->pl_state = (plD_state_fp) plD_state_aqt;
223 pdt->pl_esc = (plD_esc_fp) plD_esc_aqt;
224 }
225
226 //--------------------------------------------------------------------------
227 // aqt_init()
228 //
229 // Initialize device
230 //--------------------------------------------------------------------------
231
plD_init_aqt(PLStream * pls)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 {
267 windowXSize = AQT_Default_X;
268 windowYSize = AQT_Default_Y;
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
280 check_font_environment_variables();
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
plD_bop_aqt(PLStream * pls)299 void plD_bop_aqt( PLStream *pls )
300 {
301 currentPlot = currentPlot >= maxWindows ? 0 : currentPlot;
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
plD_line_aqt(PLStream * pls,short x1a,short y1a,short x2a,short y2a)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
plD_polyline_aqt(PLStream * pls,short * xa,short * ya,PLINT npts)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
plD_eop_aqt(PLStream * pls)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
plD_tidy_aqt(PLStream * pls)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
plD_state_aqt(PLStream * pls,PLINT op)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
plD_esc_aqt(PLStream * pls,PLINT op,void * ptr)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
get_cursor(PLStream * pls,PLGraphicsIn * gin)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
proc_str(PLStream * pls,EscText * args)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
create_string(const PLUNICODE * ucs4,int ucs4_len,PLFLT font_height)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
set_font_and_size(NSMutableAttributedString * str,PLUNICODE fci,PLFLT font_height,int cur_loc)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
check_font_environment_variables(void)769 void check_font_environment_variables( void )
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 }
806