PLplot
5.10.0
|
00001 // March 12, 2005 00002 // 00003 // PLplot driver for AquaTerm and Mac OS X. 00004 // 00005 // Copyright (C) Per Persson 00006 // Copyright (C) 2005 Hazen Babcock 00007 // 00008 // This file is part of PLplot. 00009 // 00010 // PLplot is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Library General Public License as published 00012 // by the Free Software Foundation; either version 2 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // PLplot is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Library General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Library General Public License 00021 // along with PLplot; if not, write to the Free Software 00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00023 // 00024 // 00025 00026 //--------------------------------------------- 00027 // Header files, defines and local variables 00028 // --------------------------------------------- 00029 00030 // OS X specific header files 00031 00032 #import <Foundation/Foundation.h> 00033 #import <AquaTerm/AQTAdapter.h> 00034 00035 // PLplot header files 00036 00037 #include "plplotP.h" 00038 #include "drivers.h" 00039 00040 // constants 00041 00042 #define SCALE 0.1 00043 #define AQT_Default_X 720 00044 #define AQT_Default_Y 540 00045 #define DPI 72.0 00046 00047 #define MAX_STRING_LEN 1000 00048 00049 // local variables 00050 00051 static NSAutoreleasePool *arpool; // Objective-C autorelease pool 00052 static id adapter; // Adapter object 00053 00054 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_aqt = "aqt:AquaTerm (Mac OS X):1:aqt:50:aqt\n"; 00055 00056 static int currentPlot = 0; 00057 static int maxWindows = 30; 00058 static int windowXSize = 0; 00059 static int windowYSize = 0; 00060 00061 static bool didTests = false; 00062 static bool hasShear = false; 00063 static bool hasAlpha = false; 00064 00065 // font stuff 00066 00067 // 00068 // AquaTerm font look-up table 00069 // 00070 // The table is initialized with lowest common denominator truetype 00071 // fonts that (I hope) most Macs will have. 00072 // 00073 00074 #define AQT_N_FontLookup 30 00075 static FCI_to_FontName_Table AQT_FontLookup[AQT_N_FontLookup] = { 00076 { PL_FCI_MARK | 0x000, (unsigned char *) "Helvetica" }, 00077 { PL_FCI_MARK | 0x001, (unsigned char *) "Times-Roman" }, 00078 { PL_FCI_MARK | 0x002, (unsigned char *) "Courier" }, 00079 { PL_FCI_MARK | 0x003, (unsigned char *) "Times-Roman" }, 00080 { PL_FCI_MARK | 0x004, (unsigned char *) "LucidaGrande Regular" }, 00081 { PL_FCI_MARK | 0x010, (unsigned char *) "Helvetica-Oblique" }, 00082 { PL_FCI_MARK | 0x011, (unsigned char *) "Times-Italic" }, 00083 { PL_FCI_MARK | 0x012, (unsigned char *) "Courier-Oblique" }, 00084 { PL_FCI_MARK | 0x013, (unsigned char *) "Times-Italic" }, 00085 { PL_FCI_MARK | 0x014, (unsigned char *) "LucidaGrande Regular" }, 00086 { PL_FCI_MARK | 0x020, (unsigned char *) "Helvetica-Oblique" }, 00087 { PL_FCI_MARK | 0x021, (unsigned char *) "Times-Italic" }, 00088 { PL_FCI_MARK | 0x022, (unsigned char *) "Courier-Oblique" }, 00089 { PL_FCI_MARK | 0x023, (unsigned char *) "Times-Italic" }, 00090 { PL_FCI_MARK | 0x024, (unsigned char *) "LucidaGrande Regular" }, 00091 { PL_FCI_MARK | 0x100, (unsigned char *) "Helvetica-Bold" }, 00092 { PL_FCI_MARK | 0x101, (unsigned char *) "Times-Bold" }, 00093 { PL_FCI_MARK | 0x102, (unsigned char *) "Courier-Bold" }, 00094 { PL_FCI_MARK | 0x103, (unsigned char *) "Times-Bold" }, 00095 { PL_FCI_MARK | 0x104, (unsigned char *) "LucidaGrande Regular" }, 00096 { PL_FCI_MARK | 0x110, (unsigned char *) "Helvetica-BoldOblique" }, 00097 { PL_FCI_MARK | 0x111, (unsigned char *) "Times-BoldItalic" }, 00098 { PL_FCI_MARK | 0x112, (unsigned char *) "Courier-BoldOblique" }, 00099 { PL_FCI_MARK | 0x113, (unsigned char *) "Times-BoldItalic" }, 00100 { PL_FCI_MARK | 0x114, (unsigned char *) "LucidaGrande Regular" }, 00101 { PL_FCI_MARK | 0x120, (unsigned char *) "Helvetica-BoldOblique" }, 00102 { PL_FCI_MARK | 0x121, (unsigned char *) "Times-BoldItalic" }, 00103 { PL_FCI_MARK | 0x122, (unsigned char *) "Courier-BoldOblique" }, 00104 { PL_FCI_MARK | 0x123, (unsigned char *) "Times-BoldItalic" }, 00105 { PL_FCI_MARK | 0x124, (unsigned char *) "LucidaGrande Regular" } 00106 }; 00107 00108 // 00109 // AquaTerm font environment variables 00110 // 00111 // When the driver is initialized it will check to see if 00112 // the user has opted to overide one of the above fonts by 00113 // setting one of the environment variables below. 00114 // 00115 // This list must be in the same order with the same number of 00116 // elements as the above list 00117 // 00118 // These are the same environment variable names as would be used 00119 // on a linux system, but they have a slightly different meaning. 00120 // Since AquaTerm will find the font for us (if it can) given 00121 // just the font name, you should only set the environment 00122 // variable to the font name. You don't need to provide 00123 // a path. If you installed the font using Font Book, AquaTerm 00124 // should not have any trouble finding it. 00125 // 00126 // FIXME: Would it be better to use different environment variable 00127 // names then plfreetype.c? If not, then it probably isn't 00128 // ideal to have two different copies of the same list of 00129 // environment variable names. 00130 // 00131 00132 const char *aqt_font_env_names[AQT_N_FontLookup] = { 00133 "PLPLOT_FREETYPE_SANS_FONT", 00134 "PLPLOT_FREETYPE_SERIF_FONT", 00135 "PLPLOT_FREETYPE_MONO_FONT", 00136 "PLPLOT_FREETYPE_SCRIPT_FONT", 00137 "PLPLOT_FREETYPE_SYMBOL_FONT", 00138 "PLPLOT_FREETYPE_SANS_ITALIC_FONT", 00139 "PLPLOT_FREETYPE_SERIF_ITALIC_FONT", 00140 "PLPLOT_FREETYPE_MONO_ITALIC_FONT", 00141 "PLPLOT_FREETYPE_SCRIPT_ITALIC_FONT", 00142 "PLPLOT_FREETYPE_SYMBOL_ITALIC_FONT", 00143 "PLPLOT_FREETYPE_SANS_OBLIQUE_FONT", 00144 "PLPLOT_FREETYPE_SERIF_OBLIQUE_FONT", 00145 "PLPLOT_FREETYPE_MONO_OBLIQUE_FONT", 00146 "PLPLOT_FREETYPE_SCRIPT_OBLIQUE_FONT", 00147 "PLPLOT_FREETYPE_SYMBOL_OBLIQUE_FONT", 00148 "PLPLOT_FREETYPE_SANS_BOLD_FONT", 00149 "PLPLOT_FREETYPE_SERIF_BOLD_FONT", 00150 "PLPLOT_FREETYPE_MONO_BOLD_FONT", 00151 "PLPLOT_FREETYPE_SCRIPT_BOLD_FONT", 00152 "PLPLOT_FREETYPE_SYMBOL_BOLD_FONT", 00153 "PLPLOT_FREETYPE_SANS_BOLD_ITALIC_FONT", 00154 "PLPLOT_FREETYPE_SERIF_BOLD_ITALIC_FONT", 00155 "PLPLOT_FREETYPE_MONO_BOLD_ITALIC_FONT", 00156 "PLPLOT_FREETYPE_SCRIPT_BOLD_ITALIC_FONT", 00157 "PLPLOT_FREETYPE_SYMBOL_BOLD_ITALIC_FONT", 00158 "PLPLOT_FREETYPE_SANS_BOLD_OBLIQUE_FONT", 00159 "PLPLOT_FREETYPE_SERIF_BOLD_OBLIQUE_FONT", 00160 "PLPLOT_FREETYPE_MONO_BOLD_OBLIQUE_FONT", 00161 "PLPLOT_FREETYPE_SCRIPT_BOLD_OBLIQUE_FONT", 00162 "PLPLOT_FREETYPE_SYMBOL_BOLD_OBLIQUE_FONT" 00163 }; 00164 00165 // Debugging extras 00166 00167 static inline void NOOP_( id x, ... ) 00168 { 00169 ; 00170 } 00171 00172 #ifdef LOGGING 00173 #define LOG NSLog 00174 #else 00175 #define LOG NOOP_ 00176 #endif // LOGGING 00177 00178 //----------------------------------------------- 00179 // function declarations 00180 // ----------------------------------------------- 00181 00182 // helper functions 00183 00184 static void get_cursor( PLStream *, PLGraphicsIn * ); 00185 static void proc_str( PLStream *, EscText * ); 00186 NSMutableAttributedString * create_string( const PLUNICODE *, int, PLFLT ); 00187 static void set_font_and_size( NSMutableAttributedString *, PLUNICODE, PLFLT, int ); 00188 static void check_font_environment_variables( void ); 00189 00190 // PLplot interface functions 00191 00192 void plD_dispatch_init_aqt( PLDispatchTable *pdt ); 00193 void plD_init_aqt( PLStream * ); 00194 void plD_line_aqt( PLStream *, short, short, short, short ); 00195 void plD_polyline_aqt( PLStream *, short *, short *, PLINT ); 00196 void plD_eop_aqt( PLStream * ); 00197 void plD_bop_aqt( PLStream * ); 00198 void plD_tidy_aqt( PLStream * ); 00199 void plD_state_aqt( PLStream *, PLINT ); 00200 void plD_esc_aqt( PLStream *, PLINT, void * ); 00201 00202 //-------------------------------------------------------------------------- 00203 // dispatch_init_init() 00204 // 00205 // Initialize device dispatch table 00206 //-------------------------------------------------------------------------- 00207 00208 void plD_dispatch_init_aqt( PLDispatchTable *pdt ) 00209 { 00210 #ifndef ENABLE_DYNDRIVERS 00211 pdt->pl_MenuStr = "AquaTerm - Mac OS X"; 00212 pdt->pl_DevName = "aqt"; 00213 #endif 00214 pdt->pl_type = plDevType_Interactive; 00215 pdt->pl_seq = 1; 00216 pdt->pl_init = (plD_init_fp) plD_init_aqt; 00217 pdt->pl_line = (plD_line_fp) plD_line_aqt; 00218 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_aqt; 00219 pdt->pl_eop = (plD_eop_fp) plD_eop_aqt; 00220 pdt->pl_bop = (plD_bop_fp) plD_bop_aqt; 00221 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_aqt; 00222 pdt->pl_state = (plD_state_fp) plD_state_aqt; 00223 pdt->pl_esc = (plD_esc_fp) plD_esc_aqt; 00224 } 00225 00226 //-------------------------------------------------------------------------- 00227 // aqt_init() 00228 // 00229 // Initialize device 00230 //-------------------------------------------------------------------------- 00231 00232 void plD_init_aqt( PLStream *pls ) 00233 { 00234 if ( arpool == NULL ) // Make sure we don't leak mem by allocating every time 00235 { 00236 arpool = [[NSAutoreleasePool alloc] init]; 00237 adapter = [[AQTAdapter alloc] init]; 00238 } 00239 [adapter setBackgroundColorRed : 0.5 green : 0.5 blue : 0.5]; 00240 00241 pls->termin = 1; // interactive device 00242 pls->dev_flush = 1; // Handle our own flushes 00243 pls->color = 1; // supports color 00244 pls->width = 1; 00245 pls->verbose = 1; 00246 pls->bytecnt = 0; 00247 pls->debug = 1; 00248 pls->dev_text = 1; // handles text 00249 pls->dev_unicode = 1; // wants text as unicode 00250 pls->page = 0; 00251 pls->dev_fill0 = 1; // supports hardware solid fills 00252 pls->dev_fill1 = 1; 00253 00254 pls->graphx = GRAPHICS_MODE; 00255 00256 if ( !pls->colorset ) 00257 pls->color = 1; 00258 00259 // Set up device parameters 00260 00261 plP_setpxl( DPI / 25.4 / SCALE, DPI / 25.4 / SCALE ); // Pixels/mm. 00262 00263 // Set the bounds for plotting. default is AQT_Default_X x AQT_Default_Y unless otherwise specified. 00264 00265 if ( pls->xlength <= 0 || pls->ylength <= 0 ) 00266 { 00267 windowXSize = AQT_Default_X; 00268 windowYSize = AQT_Default_Y; 00269 plP_setphy( (PLINT) 0, (PLINT) ( AQT_Default_X / SCALE ), (PLINT) 0, (PLINT) ( AQT_Default_Y / SCALE ) ); 00270 } 00271 else 00272 { 00273 windowXSize = pls->xlength; 00274 windowYSize = pls->ylength; 00275 plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / SCALE ), (PLINT) 0, (PLINT) ( pls->ylength / SCALE ) ); 00276 } 00277 00278 // check font environment variables & update font table as necessary 00279 00280 check_font_environment_variables(); 00281 00282 // Check to see if the users version of aquaterm supports sheared labels. 00283 // If it isn't available 3D plots will look a little strange but things should otherwise be okay. 00284 00285 if ( !didTests ) 00286 { 00287 hasShear = [adapter respondsToSelector:@selector( addLabel:atPoint:angle:shearAngle:align: )]; 00288 hasAlpha = [adapter respondsToSelector:@selector( setColorRed:green:blue:alpha: )]; 00289 didTests = true; 00290 } 00291 } 00292 00293 //-------------------------------------------------------------------------- 00294 // aqt_bop() 00295 // 00296 // Set up for the next page. 00297 //-------------------------------------------------------------------------- 00298 00299 void plD_bop_aqt( PLStream *pls ) 00300 { 00301 currentPlot = currentPlot >= maxWindows ? 0 : currentPlot; 00302 [adapter openPlotWithIndex : currentPlot++]; 00303 [adapter setPlotSize : NSMakeSize( windowXSize, windowYSize )]; 00304 [adapter setLinewidth : 1.0]; 00305 if ( hasAlpha ) 00306 { 00307 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00308 green : (float) ( pls->curcolor.g / 255. ) 00309 blue : (float) ( pls->curcolor.b / 255. ) 00310 alpha : (float) ( pls->curcolor.a )]; 00311 } 00312 else 00313 { 00314 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00315 green : (float) ( pls->curcolor.g / 255. ) 00316 blue : (float) ( pls->curcolor.b / 255. )]; 00317 } 00318 00319 pls->page++; 00320 } 00321 00322 //-------------------------------------------------------------------------- 00323 // aqt_line() 00324 // 00325 // Draw a line in the current color from (x1,y1) to (x2,y2). 00326 //-------------------------------------------------------------------------- 00327 00328 void plD_line_aqt( PLStream *pls, short x1a, short y1a, short x2a, short y2a ) 00329 { 00330 [adapter moveToPoint : NSMakePoint( (float) x1a * SCALE, (float) y1a * SCALE )]; 00331 [adapter addLineToPoint : NSMakePoint( (float) x2a * SCALE, (float) y2a * SCALE )]; 00332 } 00333 00334 //-------------------------------------------------------------------------- 00335 // aqt_polyline() 00336 // 00337 // Draw a polyline in the current color. 00338 //-------------------------------------------------------------------------- 00339 00340 void plD_polyline_aqt( PLStream *pls, short *xa, short *ya, PLINT npts ) 00341 { 00342 int i; 00343 00344 for ( i = 0; i < npts - 1; i++ ) 00345 plD_line_aqt( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] ); 00346 } 00347 00348 //-------------------------------------------------------------------------- 00349 // aqt_eop() 00350 // 00351 // End of page 00352 //-------------------------------------------------------------------------- 00353 00354 void plD_eop_aqt( PLStream *pls ) 00355 { 00356 [arpool release]; // prevents a memory leak by freeing everything in 00357 // the auto-release pool when the plot is closed. 00358 arpool = [[NSAutoreleasePool alloc] init]; 00359 [adapter renderPlot]; 00360 } 00361 00362 //-------------------------------------------------------------------------- 00363 // aqt_tidy() 00364 // 00365 // Close graphics file or otherwise clean up. 00366 //-------------------------------------------------------------------------- 00367 00368 void plD_tidy_aqt( PLStream *pls ) 00369 { 00370 [adapter closePlot]; 00371 } 00372 00373 //-------------------------------------------------------------------------- 00374 // plD_state_aqt() 00375 // 00376 // Handle change in PLStream state (color, pen width, fill attribute, etc). 00377 //-------------------------------------------------------------------------- 00378 00379 void plD_state_aqt( PLStream *pls, PLINT op ) 00380 { 00381 int i; 00382 float r, g, b; 00383 00384 switch ( op ) 00385 { 00386 case PLSTATE_WIDTH: 00387 [adapter setLinewidth : (float) pls->width]; 00388 break; 00389 00390 case PLSTATE_COLOR0: // this seems to work, but that isn't to say that it is done right... 00391 if ( hasAlpha ) 00392 { 00393 [adapter setBackgroundColorRed : (float) ( plsc->cmap0[0].r / 255.0 ) 00394 green : (float) ( plsc->cmap0[0].g / 255.0 ) 00395 blue : (float) ( plsc->cmap0[0].b / 255.0 ) 00396 alpha : (float) ( plsc->cmap0[0].a )]; 00397 } 00398 else 00399 { 00400 [adapter setBackgroundColorRed : (float) ( plsc->cmap0[0].r / 255.0 ) 00401 green : (float) ( plsc->cmap0[0].g / 255.0 ) 00402 blue : (float) ( plsc->cmap0[0].b / 255.0 )]; 00403 } 00404 case PLSTATE_COLOR1: 00405 case PLSTATE_FILL: 00406 if ( hasAlpha ) 00407 { 00408 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00409 green : (float) ( pls->curcolor.g / 255. ) 00410 blue : (float) ( pls->curcolor.b / 255. ) 00411 alpha : (float) ( pls->curcolor.a )]; 00412 } 00413 else 00414 { 00415 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00416 green : (float) ( pls->curcolor.g / 255. ) 00417 blue : (float) ( pls->curcolor.b / 255. )]; 00418 } 00419 break; 00420 00421 case PLSTATE_CMAP0: 00422 break; 00423 00424 case PLSTATE_CMAP1: 00425 break; 00426 } 00427 } 00428 00429 //-------------------------------------------------------------------------- 00430 // aqt_esc() 00431 // 00432 // Escape function. 00433 // 00434 // Functions: 00435 // 00436 // PLESC_EH Handle pending events 00437 // PLESC_EXPOSE Force an expose 00438 // PLESC_FILL Fill polygon 00439 // PLESC_FLUSH Flush X event buffer 00440 // PLESC_GETC Get coordinates upon mouse click 00441 // PLESC_REDRAW Force a redraw 00442 // PLESC_RESIZE Force a resize 00443 //-------------------------------------------------------------------------- 00444 00445 void plD_esc_aqt( PLStream *pls, PLINT op, void *ptr ) 00446 { 00447 int i; 00448 switch ( op ) 00449 { 00450 case PLESC_EXPOSE: // handle window expose 00451 break; 00452 case PLESC_RESIZE: // handle window resize 00453 break; 00454 case PLESC_REDRAW: // handle window redraw 00455 break; 00456 case PLESC_TEXT: // switch to text screen 00457 break; 00458 case PLESC_GRAPH: // switch to graphics screen 00459 break; 00460 case PLESC_FILL: // fill polygon 00461 [adapter moveToVertexPoint : NSMakePoint( pls->dev_x[0] * SCALE, pls->dev_y[0] * SCALE )]; 00462 for ( i = 1; i < pls->dev_npts; i++ ) 00463 { 00464 [adapter addEdgeToVertexPoint : NSMakePoint( pls->dev_x[i] * SCALE, pls->dev_y[i] * SCALE )]; 00465 } 00466 ; 00467 break; 00468 case PLESC_DI: // handle DI command 00469 break; 00470 case PLESC_FLUSH: // flush output 00471 [adapter renderPlot]; 00472 break; 00473 case PLESC_EH: // handle Window events 00474 break; 00475 case PLESC_GETC: // get cursor position 00476 [adapter renderPlot]; // needed to give the user something to click on 00477 get_cursor( pls, (PLGraphicsIn *) ptr ); 00478 break; 00479 case PLESC_SWIN: // set window parameters 00480 break; 00481 case PLESC_HAS_TEXT: 00482 proc_str( pls, (EscText *) ptr ); 00483 break; 00484 } 00485 } 00486 00487 //-------------------------------------------------------------------------- 00488 // get_cursor() 00489 // 00490 // returns the location of the next mouse click 00491 //-------------------------------------------------------------------------- 00492 00493 void get_cursor( PLStream *pls, PLGraphicsIn *gin ) 00494 { 00495 int scanned, x, y, button; 00496 NSString *temp; 00497 00498 plGinInit( gin ); 00499 00500 temp = [adapter waitNextEvent]; 00501 scanned = sscanf([temp cString], "1:{%d, %d}:%d", &x, &y, &button ); 00502 00503 if ( scanned == 3 ) // check that we did actually get a reasonable event string 00504 { 00505 gin->button = button; 00506 gin->pX = x; 00507 gin->pY = y; 00508 gin->dX = (PLFLT) x / ( (PLFLT) ( pls->xlength ) ); 00509 gin->dY = (PLFLT) y / ( (PLFLT) ( pls->ylength ) ); 00510 } 00511 else // just return zeroes if we did not 00512 { 00513 printf( "AquaTerm did not return a valid mouse location!\n" ); 00514 gin->button = 0; 00515 gin->pX = 0; 00516 gin->pY = 0; 00517 gin->dX = 0.0; 00518 gin->dY = 0.0; 00519 } 00520 } 00521 00522 //-------------------------------------------------------------------------- 00523 // proc_str() 00524 // 00525 // Processes strings for display. The actual parsing of the unicode 00526 // string is handled by the sub-routine create_string. 00527 //-------------------------------------------------------------------------- 00528 00529 void proc_str( PLStream *pls, EscText *args ) 00530 { 00531 PLFLT a1, ft_ht, angle, shear, stride; 00532 PLINT clxmin, clxmax, clymin, clymax; 00533 int i, jst, ref; 00534 NSMutableAttributedString *str; 00535 00536 // check that we got unicode, warning message and return if not 00537 00538 if ( args->unicode_array_len == 0 ) 00539 { 00540 printf( "Non unicode string passed to AquaTerm driver, ignoring\n" ); 00541 return; 00542 } 00543 00544 // check that unicode string isn't longer then the max we allow 00545 00546 if ( args->unicode_array_len >= MAX_STRING_LEN ) 00547 { 00548 printf( "Sorry, the AquaTerm driver only handles strings of length < %d\n", MAX_STRING_LEN ); 00549 return; 00550 } 00551 00552 // set the font height - the 1.2 factor was trial and error 00553 00554 ft_ht = 1.2 * pls->chrht * DPI / 25.4; // ft_ht in points. ht is in mm 00555 00556 // given transform, calculate rotation angle & shear angle 00557 plRotationShear( args->xform, &angle, &shear, &stride ); 00558 angle *= 180.0 / PI; 00559 shear *= -180.0 / PI; 00560 00561 // text justification, AquaTerm only supports 3 options, so we round appropriately 00562 00563 if ( args->just < 0.33 ) 00564 jst = AQTAlignLeft; // left 00565 else if ( args->just > 0.66 ) 00566 jst = AQTAlignRight; // right 00567 else 00568 jst = AQTAlignCenter; // center 00569 00570 // set the baseline of the string 00571 // Middle and Bottom are set to Middle since this seems to be what PLplot expects 00572 // as judged by where it renders the symbols in example 1. 00573 00574 if ( args->base == 2 ) // Top 00575 ref = AQTAlignTop; 00576 else if ( args->base == 1 ) // Bottom 00577 ref = AQTAlignMiddle; 00578 else 00579 ref = AQTAlignMiddle; // Middle 00580 00581 // create an appropriately formatted, etc... unicode string 00582 00583 str = create_string( args->unicode_array, args->unicode_array_len, ft_ht ); 00584 00585 // display the string 00586 00587 if ( hasAlpha ) 00588 { 00589 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00590 green : (float) ( pls->curcolor.g / 255. ) 00591 blue : (float) ( pls->curcolor.b / 255. ) 00592 alpha : (float) ( pls->curcolor.a )]; 00593 } 00594 else 00595 { 00596 [adapter setColorRed : (float) ( pls->curcolor.r / 255. ) 00597 green : (float) ( pls->curcolor.g / 255. ) 00598 blue : (float) ( pls->curcolor.b / 255. )]; 00599 } 00600 00601 if ( hasShear ) 00602 { 00603 [adapter addLabel : str 00604 atPoint : NSMakePoint( (float) args->x * SCALE, (float) args->y * SCALE ) 00605 angle : angle 00606 shearAngle : shear 00607 align : ( jst | ref )]; 00608 } 00609 else 00610 { 00611 [adapter addLabel : str 00612 atPoint : NSMakePoint( (float) args->x * SCALE, (float) args->y * SCALE ) 00613 angle : angle 00614 align : ( jst | ref )]; 00615 } 00616 00617 [str release]; 00618 } 00619 00620 //-------------------------------------------------------------------------- 00621 // create_string() 00622 // 00623 // create a NSMutableAttributedString from the plplot ucs4 string 00624 // 00625 // assumptions : 00626 // 1. font changes are unicode >= PL_FCI_MARK 00627 // 2. we'll never have to deal with a string longer then MAX_STRING_LEN characters 00628 // 3. <esc><esc> means we desired <esc> as a character & not actually as <esc> 00629 // 4. there are no two character <esc> sequences... i.e. <esc>fn is now covered by fci 00630 // 00631 //-------------------------------------------------------------------------- 00632 00633 NSMutableAttributedString * create_string( const PLUNICODE *ucs4, int ucs4_len, PLFLT font_height ) 00634 { 00635 PLUNICODE fci; 00636 char plplot_esc; 00637 int i; 00638 int cur_loc; 00639 int utf8_len; 00640 int updown; 00641 char dummy[MAX_STRING_LEN + 1]; 00642 char *font; 00643 char utf8[5]; 00644 NSMutableAttributedString *str; 00645 00646 updown = 0; 00647 00648 // initialize the attributed string 00649 00650 for ( i = 0; i < MAX_STRING_LEN; i++ ) 00651 dummy[i] = 'i'; 00652 dummy[MAX_STRING_LEN] = '\0'; 00653 str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithCString:dummy]]; 00654 00655 // get plplot escape character & current font 00656 00657 plgesc( &plplot_esc ); 00658 plgfci( &fci ); 00659 00660 // set the font for the string based on the current font & size 00661 00662 set_font_and_size( str, fci, font_height, 0 ); 00663 00664 // parse plplot ucs4 string 00665 00666 cur_loc = 0; 00667 i = 0; 00668 while ( i < ucs4_len ) 00669 { 00670 if ( ucs4[i] < PL_FCI_MARK ) // not a font change 00671 { 00672 if ( ucs4[i] != (PLUNICODE) plplot_esc ) // a character to display 00673 { 00674 ucs4_to_utf8( ucs4[i], utf8 ); 00675 [str replaceCharactersInRange : NSMakeRange( cur_loc, 1 ) 00676 withString :[NSString stringWithUTF8String : utf8]]; 00677 i++; 00678 cur_loc++; 00679 continue; 00680 } 00681 i++; 00682 if ( ucs4[i] == (PLUNICODE) plplot_esc ) 00683 { 00684 ucs4_to_utf8( ucs4[i], utf8 ); 00685 [str replaceCharactersInRange : NSMakeRange( cur_loc, 1 ) 00686 withString :[NSString stringWithUTF8String : utf8]]; 00687 i++; 00688 cur_loc++; 00689 continue; 00690 } 00691 else 00692 { 00693 if ( ucs4[i] == (PLUNICODE) 'f' ) // font change 00694 { 00695 i++; 00696 printf( "hmm, unicode string apparently not following fci convention...\n" ); 00697 } 00698 if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript 00699 { 00700 updown--; 00701 [str addAttribute : @ "NSSuperScript" 00702 value :[NSNumber numberWithInt : updown] 00703 range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )]; 00704 } 00705 if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript 00706 { 00707 updown++; 00708 [str addAttribute : @ "NSSuperScript" 00709 value :[NSNumber numberWithInt : updown] 00710 range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )]; 00711 } 00712 i++; 00713 } 00714 } 00715 else // a font change 00716 { 00717 set_font_and_size( str, ucs4[i], font_height, cur_loc ); 00718 i++; 00719 } 00720 } 00721 00722 // trim string to appropriate final length 00723 00724 [str deleteCharactersInRange : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )]; 00725 00726 return str; 00727 } 00728 00729 //-------------------------------------------------------------------------- 00730 // set_font_and_size 00731 // 00732 // set the font & size of a attributable string object 00733 //-------------------------------------------------------------------------- 00734 00735 void set_font_and_size( NSMutableAttributedString * str, PLUNICODE fci, PLFLT font_height, int cur_loc ) 00736 { 00737 char *font; 00738 00739 font = plP_FCI2FontName( fci, AQT_FontLookup, AQT_N_FontLookup ); 00740 00741 // check whether that font exists & if not, use standard font instead 00742 00743 if ( font == NULL ) 00744 { 00745 printf( "AquaTerm : Warning, could not find font given by fci = 0x%x\n", fci ); 00746 font = "Helvetica"; 00747 } 00748 /* font = "FreeSerif"; *//* force the font for debugging purposes */ 00749 // printf("Font at %d is : %s\n", cur_loc, font); 00750 00751 [str addAttribute : @ "AQTFontname" 00752 value :[NSString stringWithCString : font] 00753 range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )]; 00754 [str addAttribute : @ "AQTFontsize" 00755 value :[NSNumber numberWithFloat : font_height] 00756 range : NSMakeRange( cur_loc, ( MAX_STRING_LEN - cur_loc ) )]; 00757 } 00758 00759 //-------------------------------------------------------------------------- 00760 // check_font_environment_variables 00761 // 00762 // Checks to see if any font environment variables are defined. 00763 // If a font environment variable is defined, then the appropriate 00764 // element of the default font table is replaced with the font name 00765 // string specified by the environment variable. 00766 //-------------------------------------------------------------------------- 00767 00768 00769 void check_font_environment_variables( void ) 00770 { 00771 int i; 00772 char *new_font; 00773 char *begin; 00774 char *end; 00775 00776 for ( i = 0; i < AQT_N_FontLookup; i++ ) 00777 { 00778 if ( ( new_font = getenv( aqt_font_env_names[i] ) ) != NULL ) 00779 { 00780 // If the user is just blindly following the suggestions in 00781 // the plplot examples then we might get a font name with 00782 // a path and extension. We need to remove that since it 00783 // isn't relevant and will only cause trouble. We warn them 00784 // AquaTerm was not expecting a path or extension. 00785 00786 begin = strrchr( new_font, '/' ); 00787 end = strrchr( new_font, '.' ); 00788 00789 if ( end != NULL ) 00790 { 00791 printf( "Aquaterm : Warning, removing extension from font name : %s\n", new_font ); 00792 *end = '\0'; 00793 } 00794 if ( begin != NULL ) 00795 { 00796 printf( "AquaTerm : Warning, removing path from font name : %s\n", new_font ); 00797 new_font = begin + 1; 00798 } 00799 00800 // printf("new font : %s\n", new_font); 00801 00802 AQT_FontLookup[i].pfont = (unsigned char *) new_font; 00803 } 00804 } 00805 }