PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/tags/v5_9_2/drivers/wxwidgets.cpp

#
C++ | 1259 lines | 720 code | 223 blank | 316 comment | 101 complexity | 3bae7ad59612e3a6abd33dc7369afb24 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0
  1. /* $Id: wxwidgets.cpp 9320 2009-01-16 08:56:02Z smekal $
  2. Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
  3. Copyright (C) 2005 Germain Carrera Corraleche
  4. Copyright (C) 1999 Frank Huebner
  5. This file is part of PLplot.
  6. PLplot is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Library Public License as published
  8. by the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. PLplot is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public License
  15. along with PLplot; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. /* TODO:
  19. * - NA
  20. */
  21. #include "plDevs.h"
  22. /* plplot headers */
  23. #include "plplotP.h"
  24. #include "drivers.h"
  25. /* C/C++ headers */
  26. #include <cstdio>
  27. /* wxwidgets headers */
  28. #include <wx/wx.h>
  29. #include <wx/wfstream.h>
  30. #include <wx/except.h>
  31. #include "wxwidgets.h"
  32. #ifdef __WXMAC__
  33. #include <Carbon/Carbon.h>
  34. extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
  35. #endif
  36. DECLARE_PLAPP( wxPLplotApp )
  37. /*--------------------------------------------------------------------------
  38. * void Log_Verbose( const char *fmt, ... )
  39. *
  40. * Print verbose debug message to stderr (printf style).
  41. *--------------------------------------------------------------------------*/
  42. void Log_Verbose( const char *fmt, ... )
  43. {
  44. #ifdef _DEBUG_VERBOSE
  45. va_list args;
  46. va_start( args, fmt );
  47. fprintf( stderr, "Verbose: " );
  48. vfprintf( stderr, fmt, args );
  49. fprintf( stderr, "\n" );
  50. va_end( args );
  51. fflush( stderr );
  52. #endif
  53. }
  54. /*--------------------------------------------------------------------------
  55. * void Log_Debug( const char *fmt, ... )
  56. *
  57. * Print debug message to stderr (printf style).
  58. *--------------------------------------------------------------------------*/
  59. void Log_Debug( const char *fmt, ... )
  60. {
  61. #ifdef _DEBUG
  62. va_list args;
  63. va_start( args, fmt );
  64. fprintf( stderr, "Debug: " );
  65. vfprintf( stderr, fmt, args );
  66. fprintf( stderr, "\n" );
  67. va_end( args );
  68. fflush( stderr );
  69. #endif
  70. }
  71. /*----------------------------------------------------------------------
  72. * In the following you'll find the driver functions which are
  73. * are needed by the plplot core.
  74. *----------------------------------------------------------------------*/
  75. /* Device info */
  76. #ifdef __cplusplus
  77. extern "C" {
  78. #endif
  79. PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_wxwidgets =
  80. #ifdef PLD_wxwidgets
  81. "wxwidgets:wxWidgets Driver:1:wxwidgets:51:wxwidgets\n"
  82. #endif
  83. #ifdef PLD_wxpng
  84. "wxpng:wxWidgets PNG Driver:0:wxwidgets:52:wxpng\n"
  85. #endif
  86. ;
  87. #ifdef __cplusplus
  88. }
  89. #endif
  90. /*--------------------------------------------------------------------------
  91. * wxPLDevBase::wxPLDevBase( void )
  92. *
  93. * Contructor of base class of wxPLDev classes.
  94. *--------------------------------------------------------------------------*/
  95. wxPLDevBase::wxPLDevBase( void )
  96. {
  97. // Log_Verbose( "wxPLDevBase::wxPLDevBase()" );
  98. ready = false;
  99. ownGUI = false;
  100. waiting = false;
  101. resizing = false;
  102. exit=false;
  103. comcount = 0;
  104. m_frame=NULL;
  105. // width, height are set in plD_init_wxwidgets
  106. // bm_width, bm_height are set in install_buffer
  107. // xmin, xmax, ymin, ymax are set in plD_init_wxwidgets
  108. // scalex, scaley are set in plD_init_wxwidgets
  109. plstate_width = false;
  110. plstate_color0 = false;
  111. plstate_color1 = false;
  112. locate_mode=0;
  113. draw_xhair=false;
  114. newclipregion=true;
  115. clipminx=1024;
  116. clipmaxx=0;
  117. clipminy=800;
  118. clipmaxy=0;
  119. freetype=0;
  120. smooth_text=0;
  121. devName = (const char **)malloc( NDEV * sizeof(char**) );
  122. memset( devName, '\0', NDEV * sizeof(char**) );
  123. devDesc = (const char **)malloc( NDEV * sizeof(char**) );
  124. memset( devDesc, '\0', NDEV * sizeof(char**) );
  125. ndev=NDEV;
  126. }
  127. wxPLDevBase::~wxPLDevBase( void )
  128. {
  129. if( devDesc )
  130. free( devDesc );
  131. if( devName )
  132. free( devName );
  133. }
  134. void wxPLDevBase::AddtoClipRegion( int x1, int y1, int x2, int y2 )
  135. {
  136. newclipregion=false;
  137. if( x1<x2 ) {
  138. if( x1<clipminx ) clipminx=x1;
  139. if( x2>clipmaxx ) clipmaxx=x2;
  140. } else {
  141. if( x2<clipminx ) clipminx=x2;
  142. if( x1>clipmaxx ) clipmaxx=x1;
  143. }
  144. if( y1<y2 ) {
  145. if( y1<clipminy ) clipminy=y1;
  146. if( y2>clipmaxy ) clipmaxy=y2;
  147. } else {
  148. if( y2<clipminy ) clipminy=y2;
  149. if( y1>clipmaxy ) clipmaxy=y1;
  150. }
  151. }
  152. void wxPLDevBase::PSDrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText )
  153. {
  154. int i = 0;
  155. char utf8_string[max_string_length];
  156. char utf8[5];
  157. memset( utf8_string, '\0', max_string_length );
  158. /* Get PLplot escape character */
  159. char plplotEsc;
  160. plgesc( &plplotEsc );
  161. /* Get the curent font */
  162. fontScale = 1.0;
  163. yOffset = 0.0;
  164. PLUNICODE fci;
  165. plgfci( &fci );
  166. PSSetFont( fci );
  167. textWidth=0;
  168. textHeight=0;
  169. while( i < ucs4Len ) {
  170. if( ucs4[i] < PL_FCI_MARK ) { /* not a font change */
  171. if( ucs4[i] != (PLUNICODE)plplotEsc ) { /* a character to display */
  172. ucs4_to_utf8( ucs4[i], utf8 );
  173. strcat( utf8_string, utf8 );
  174. i++;
  175. continue;
  176. }
  177. i++;
  178. if( ucs4[i] == (PLUNICODE)plplotEsc ) { /* a escape character to display */
  179. ucs4_to_utf8( ucs4[i], utf8 );
  180. strcat( utf8_string, utf8 );
  181. i++;
  182. continue;
  183. } else {
  184. if( ucs4[i] == (PLUNICODE)'u' ) { /* Superscript */
  185. // draw string so far
  186. PSDrawTextToDC( utf8_string, drawText );
  187. // change font scale
  188. if( yOffset<0.0 )
  189. fontScale *= 1.25; /* Subscript scaling parameter */
  190. else
  191. fontScale *= 0.8; /* Subscript scaling parameter */
  192. PSSetFont( fci );
  193. yOffset += scaley * fontSize * fontScale / 2.;
  194. }
  195. if( ucs4[i] == (PLUNICODE)'d' ) { /* Subscript */
  196. // draw string so far
  197. PSDrawTextToDC( utf8_string, drawText );
  198. // change font scale
  199. double old_fontScale=fontScale;
  200. if( yOffset>0.0 )
  201. fontScale *= 1.25; /* Subscript scaling parameter */
  202. else
  203. fontScale *= 0.8; /* Subscript scaling parameter */
  204. PSSetFont( fci );
  205. yOffset -= scaley * fontSize * old_fontScale / 2.;
  206. }
  207. if( ucs4[i] == (PLUNICODE)'-' ) { /* underline */
  208. // draw string so far
  209. PSDrawTextToDC( utf8_string, drawText );
  210. underlined = !underlined;
  211. PSSetFont( fci );
  212. }
  213. if( ucs4[i] == (PLUNICODE)'+' ) { /* overline */
  214. /* not implemented yet */
  215. }
  216. i++;
  217. }
  218. } else { /* a font change */
  219. // draw string so far
  220. PSDrawTextToDC( utf8_string, drawText );
  221. // get new font
  222. fci = ucs4[i];
  223. PSSetFont( fci );
  224. i++;
  225. }
  226. }
  227. PSDrawTextToDC( utf8_string, drawText );
  228. }
  229. /*--------------------------------------------------------------------------
  230. * void common_init( PLStream *pls )
  231. *
  232. * Basic initialization for all devices.
  233. *--------------------------------------------------------------------------*/
  234. wxPLDevBase* common_init( PLStream *pls )
  235. {
  236. // Log_Verbose( "common_init()" );
  237. wxPLDevBase* dev;
  238. /* default options */
  239. static PLINT freetype=0;
  240. static PLINT smooth_text=1;
  241. static PLINT text=1;
  242. static PLINT hrshsym = 0;
  243. /* default backend uses wxGraphicsContext, if not available
  244. the agg library will be used, if not available the basic
  245. backend will be used. */
  246. static PLINT backend=wxBACKEND_DC;
  247. #if wxUSE_GRAPHICS_CONTEXT
  248. backend=wxBACKEND_GC;
  249. #else
  250. #ifdef HAVE_AGG
  251. backend=wxBACKEND_AGG;
  252. #endif
  253. #endif
  254. DrvOpt wx_options[] = {
  255. #ifdef HAVE_FREETYPE
  256. {"freetype", DRV_INT, &freetype, "Use FreeType library"},
  257. {"smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)"},
  258. #endif
  259. {"hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)"},
  260. {"backend", DRV_INT, &backend, "Choose backend: (0) standard, (1) using AGG library, (2) using wxGraphicsContext"},
  261. {"text", DRV_INT, &text, "Use own text routines (text=0|1)"},
  262. {NULL, DRV_INT, NULL, NULL}};
  263. /* Check for and set up driver options */
  264. plParseDrvOpts( wx_options );
  265. /* allocate memory for the device storage */
  266. switch( backend )
  267. {
  268. case wxBACKEND_GC:
  269. /* in case wxGraphicsContext isn't available, the next backend (agg
  270. if available) in this list will be used */
  271. #if wxUSE_GRAPHICS_CONTEXT
  272. dev = new wxPLDevGC;
  273. freetype = 0; /* this backend is vector oriented and doesn't know pixels */
  274. break;
  275. #endif
  276. case wxBACKEND_AGG:
  277. /* in case the agg library isn't available, the standard backend
  278. will be used */
  279. #ifdef HAVE_AGG
  280. dev = new wxPLDevAGG;
  281. text = 0; /* text processing doesn't work yet for the AGG backend */
  282. break;
  283. #endif
  284. default:
  285. dev = new wxPLDevDC;
  286. break;
  287. }
  288. if( dev == NULL) {
  289. fprintf( stderr, "Insufficient memory\n" );
  290. exit( 0 );
  291. }
  292. pls->dev = (void*)dev;
  293. /* be verbose and write out debug messages */
  294. #ifdef _DEBUG
  295. pls->verbose = 1;
  296. pls->debug = 1;
  297. #else
  298. pls->verbose = 0;
  299. pls->debug = 0;
  300. #endif
  301. pls->color = 1; /* Is a color device */
  302. pls->dev_fill0 = 1; /* Can handle solid fills */
  303. pls->dev_fill1 = 0; /* Can't handle pattern fills */
  304. pls->dev_dash = 0;
  305. pls->dev_clear = 1; /* driver supports clear */
  306. if( text ) {
  307. pls->dev_text = 1; /* want to draw text */
  308. pls->dev_unicode = 1; /* want unicode */
  309. if( hrshsym )
  310. pls->dev_hrshsym = 1;
  311. }
  312. #ifdef HAVE_FREETYPE
  313. if( !text) {
  314. dev->smooth_text=smooth_text;
  315. dev->freetype=freetype;
  316. }
  317. if( dev->freetype ) {
  318. pls->dev_text = 1; /* want to draw text */
  319. pls->dev_unicode = 1; /* want unicode */
  320. if( hrshsym )
  321. pls->dev_hrshsym = 1;
  322. init_freetype_lv1( pls );
  323. FT_Data* FT=(FT_Data *)pls->FT;
  324. FT->want_smooth_text=smooth_text;
  325. }
  326. #endif
  327. /* initialize device storage */
  328. if( pls->xlength <= 0 || pls->ylength <=0 )
  329. plspage( 0.0, 0.0, (PLINT)(CANVAS_WIDTH*DEVICE_PIXELS_PER_IN),
  330. (PLINT)(CANVAS_HEIGHT*DEVICE_PIXELS_PER_IN), 0, 0 );
  331. dev->width=pls->xlength;
  332. dev->height=pls->ylength;
  333. dev->clipminx=pls->xlength;
  334. dev->clipminy=pls->ylength;
  335. /* If portrait mode, apply a rotation and set freeaspect */
  336. if( pls->portrait ) {
  337. plsdiori( (PLFLT)(4 - ORIENTATION) );
  338. pls->freeaspect = 1;
  339. }
  340. /* Set the number of pixels per mm */
  341. plP_setpxl( (PLFLT)VIRTUAL_PIXELS_PER_MM, (PLFLT)VIRTUAL_PIXELS_PER_MM );
  342. /* Set up physical limits of plotting device (in drawing units) */
  343. plP_setphy( (PLINT)0, (PLINT)(CANVAS_WIDTH*VIRTUAL_PIXELS_PER_IN),
  344. (PLINT)0, (PLINT)(CANVAS_HEIGHT*VIRTUAL_PIXELS_PER_IN) );
  345. /* get physical device limits coordinates */
  346. plP_gphy( &dev->xmin, &dev->xmax, &dev->ymin, &dev->ymax );
  347. /* setting scale factors */
  348. dev->scalex=(PLFLT)(dev->xmax-dev->xmin)/(dev->width);
  349. dev->scaley=(PLFLT)(dev->ymax-dev->ymin)/(dev->height);
  350. /* set dpi */
  351. plspage(VIRTUAL_PIXELS_PER_IN/dev->scalex, VIRTUAL_PIXELS_PER_IN/dev->scaley, 0, 0, 0, 0);
  352. #ifdef HAVE_FREETYPE
  353. if( dev->freetype )
  354. init_freetype_lv2( pls );
  355. #endif
  356. /* find out what file drivers are available */
  357. plgFileDevs( &dev->devDesc, &dev->devName, &dev->ndev );
  358. return dev;
  359. }
  360. #ifdef PLD_wxwidgets
  361. /*--------------------------------------------------------------------------
  362. * void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
  363. *
  364. * Make wxwidgets driver functions known to plplot.
  365. *--------------------------------------------------------------------------*/
  366. void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
  367. {
  368. #ifndef ENABLE_DYNDRIVERS
  369. pdt->pl_MenuStr = "wxWidgets DC";
  370. pdt->pl_DevName = "wxwidgets";
  371. #endif
  372. pdt->pl_type = plDevType_Interactive;
  373. pdt->pl_seq = 51;
  374. pdt->pl_init = (plD_init_fp) plD_init_wxwidgets;
  375. pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
  376. pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
  377. pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
  378. pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
  379. pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
  380. pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
  381. pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
  382. }
  383. /*--------------------------------------------------------------------------
  384. * plD_init_wxwidgets( PLStream* pls )
  385. *
  386. * Initialize wxWidgets device.
  387. *--------------------------------------------------------------------------*/
  388. void plD_init_wxwidgets( PLStream* pls )
  389. {
  390. // Log_Verbose( "plD_init_wxwidgets()" );
  391. wxPLDevBase* dev;
  392. dev = common_init( pls );
  393. pls->plbuf_write = 1; /* use the plot buffer! */
  394. pls->termin = 1; /* interactive device */
  395. pls->graphx = GRAPHICS_MODE; /* No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination) */
  396. dev->showGUI = true;
  397. dev->bitmapType = (wxBitmapType)0;
  398. }
  399. #endif /* PLD_wxwidgets */
  400. #ifdef PLD_wxpng
  401. /*--------------------------------------------------------------------------
  402. * void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
  403. *
  404. * Make wxpng driver functions known to plplot.
  405. *--------------------------------------------------------------------------*/
  406. void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
  407. {
  408. #ifndef ENABLE_DYNDRIVERS
  409. pdt->pl_MenuStr = "wxWidgets PNG driver";
  410. pdt->pl_DevName = "wxpng";
  411. #endif
  412. pdt->pl_type = plDevType_FileOriented;
  413. pdt->pl_seq = 52;
  414. pdt->pl_init = (plD_init_fp) plD_init_wxpng;
  415. pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
  416. pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
  417. pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
  418. pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
  419. pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
  420. pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
  421. pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
  422. }
  423. /*--------------------------------------------------------------------------
  424. * void plD_init_wxpng( PLStream *pls )
  425. *
  426. * Initialize wxpng device.
  427. *--------------------------------------------------------------------------*/
  428. void plD_init_wxpng( PLStream *pls )
  429. {
  430. // Log_Verbose( "plD_init_wxwidgets()" );
  431. wxPLDevBase* dev;
  432. dev = common_init( pls );
  433. /* Initialize family file info */
  434. plFamInit( pls );
  435. /* Prompt for a file name if not already set. */
  436. plOpenFile( pls );
  437. pls->plbuf_write = 1; /* use the plot buffer! */
  438. pls->termin = 0; /* interactive device */
  439. pls->graphx = GRAPHICS_MODE; /* No text mode for this driver (at least for now, might add a console window if I ever figure it out and have the inclination) */
  440. dev->showGUI = false;
  441. dev->bitmapType = wxBITMAP_TYPE_PNG;
  442. }
  443. #endif /* PLD_wxpng */
  444. /*--------------------------------------------------------------------------
  445. * void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a,
  446. * short x2a, short y2a )
  447. *
  448. * Draws a line from (x1a, y1a) to (x2a, y2a).
  449. *--------------------------------------------------------------------------*/
  450. void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
  451. {
  452. // Log_Verbose( "plD_line_wxwidgets(x1a=%d, y1a=%d, x2a=%d, y2a=%d)", x1a, y1a, x2a, y2a );
  453. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  454. if( !(dev->ready) )
  455. install_buffer( pls );
  456. dev->DrawLine( x1a, y1a, x2a, y2a );
  457. if( !(dev->resizing) && dev->ownGUI ) {
  458. dev->comcount+=10;
  459. if( dev->comcount>MAX_COMCOUNT ) {
  460. wxRunApp( pls, true );
  461. dev->comcount=0;
  462. }
  463. }
  464. }
  465. /*--------------------------------------------------------------------------
  466. * void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya,
  467. * PLINT npts )
  468. *
  469. * Draw a poly line - points are in xa and ya arrays.
  470. *--------------------------------------------------------------------------*/
  471. void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya, PLINT npts )
  472. {
  473. // Log_Verbose( "plD_polyline_wxwidgets()" );
  474. /* should be changed to use the wxDC::DrawLines function? */
  475. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  476. if( !(dev->ready) )
  477. install_buffer( pls );
  478. dev->DrawPolyline( xa, ya, npts );
  479. if( !(dev->resizing) && dev->ownGUI ) {
  480. dev->comcount+=10;
  481. if( dev->comcount>MAX_COMCOUNT ) {
  482. wxRunApp( pls, true );
  483. dev->comcount=0;
  484. }
  485. }
  486. }
  487. /*--------------------------------------------------------------------------
  488. * void plD_eop_wxwidgets( PLStream *pls )
  489. *
  490. * End of Page. This function is called if a "end of page" is send by the
  491. * user. This command is ignored if we have the plot embedded in a
  492. * wxWidgets application, otherwise the application created by the device
  493. * takes over.
  494. *--------------------------------------------------------------------------*/
  495. void plD_eop_wxwidgets( PLStream *pls )
  496. {
  497. // Log_Verbose( "plD_eop_wxwidgets()" );
  498. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  499. if( dev->bitmapType ) {
  500. wxMemoryDC memDC;
  501. wxBitmap bitmap( dev->width, dev->height, -1 );
  502. memDC.SelectObject( bitmap );
  503. dev->BlitRectangle( &memDC, 0, 0, dev->width, dev->height );
  504. wxImage buffer=bitmap.ConvertToImage();
  505. wxFFileOutputStream fstream( pls->OutFile );
  506. if(!(buffer.SaveFile( fstream, dev->bitmapType )))
  507. puts("Troubles saving file!");
  508. memDC.SelectObject( wxNullBitmap );
  509. }
  510. if( dev->ownGUI )
  511. if ( pls->nopause || !dev->showGUI )
  512. wxRunApp( pls, true );
  513. else
  514. wxRunApp( pls );
  515. }
  516. /*--------------------------------------------------------------------------
  517. * void plD_bop_wxwidgets( PLStream *pls )
  518. *
  519. * Begin of page. Before any plot command, this function is called, If we
  520. * have already a dc the background is cleared in background color and some
  521. * state calls are resent - this is because at the first call of this
  522. * function, a dc does most likely not exist, but state calls are recorded
  523. * and when a new dc is created this function is called again.
  524. *--------------------------------------------------------------------------*/
  525. void plD_bop_wxwidgets( PLStream *pls )
  526. {
  527. // Log_Verbose( "plD_bop_wxwidgets()" );
  528. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  529. if( dev->ready ) {
  530. /* clear background */
  531. PLINT bgr, bgg, bgb; /* red, green, blue */
  532. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  533. dev->ClearBackground( bgr, bgg, bgb );
  534. /* Replay escape calls that come in before PLESC_DEVINIT. All of them
  535. * required a DC that didn't exist yet.
  536. */
  537. if( dev->plstate_width )
  538. plD_state_wxwidgets( pls, PLSTATE_WIDTH );
  539. dev->plstate_width = false;
  540. if( dev->plstate_color0 )
  541. plD_state_wxwidgets( pls, PLSTATE_COLOR0 );
  542. dev->plstate_color0 = false;
  543. if( dev->plstate_color1 )
  544. plD_state_wxwidgets( pls, PLSTATE_COLOR1 );
  545. dev->plstate_color1 = false;
  546. /* why this? xwin driver has this */
  547. /* pls->page++; */
  548. }
  549. }
  550. /*--------------------------------------------------------------------------
  551. * void plD_tidy_wxwidgets( PLStream *pls )
  552. *
  553. * This function is called, if all plots are done.
  554. *--------------------------------------------------------------------------*/
  555. void plD_tidy_wxwidgets( PLStream *pls )
  556. {
  557. // Log_Verbose( "plD_tidy_wxwidgets()" );
  558. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  559. #ifdef HAVE_FREETYPE
  560. if( dev->freetype ) {
  561. FT_Data *FT=(FT_Data *)pls->FT;
  562. plscmap0n( FT->ncol0_org );
  563. plD_FreeType_Destroy( pls );
  564. }
  565. #endif
  566. if( dev->ownGUI ) {
  567. wxPLGetApp().RemoveFrame( dev->m_frame );
  568. if( !wxPLGetApp().FrameCount() )
  569. wxUninitialize();
  570. }
  571. delete dev;
  572. pls->dev=NULL; /* since in plcore.c pls->dev is free_mem'd */
  573. }
  574. /*--------------------------------------------------------------------------*\
  575. * void plD_state_wxwidgets( PLStream *pls, PLINT op )
  576. *
  577. * Handler for several state codes. Here we take care of setting the width
  578. * and color of the pen.
  579. \*--------------------------------------------------------------------------*/
  580. void plD_state_wxwidgets( PLStream *pls, PLINT op )
  581. {
  582. // Log_Verbose( "plD_state_wxwidgets(op=%d)", op );
  583. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  584. switch( op ) {
  585. case PLSTATE_WIDTH: /* 1 */
  586. if( dev->ready )
  587. dev->SetWidth( pls );
  588. else
  589. dev->plstate_width = true;
  590. break;
  591. case PLSTATE_COLOR0: /* 2 */
  592. if( dev->ready )
  593. dev->SetColor0( pls );
  594. else
  595. dev->plstate_color0 = true;
  596. break;
  597. case PLSTATE_COLOR1: /* 3 */
  598. if( dev->ready )
  599. dev->SetColor1( pls );
  600. else
  601. dev->plstate_color1 = true;
  602. break;
  603. default:
  604. if( !(dev->ready) )
  605. install_buffer( pls );
  606. }
  607. }
  608. /*--------------------------------------------------------------------------*\
  609. * void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  610. *
  611. * Handler for several escape codes. Here we take care of filled polygons,
  612. * XOR or copy mode, initialize device (install dc from outside), and if
  613. * there is freetype support, rerendering of text.
  614. \*--------------------------------------------------------------------------*/
  615. void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
  616. {
  617. // Log_Verbose( "plD_esc_wxwidgets(op=%d, ptr=%x)", op, ptr );
  618. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  619. switch (op) {
  620. case PLESC_FILL:
  621. fill_polygon( pls );
  622. break;
  623. case PLESC_XORMOD:
  624. /* switch between wxXOR and wxCOPY */
  625. /* if( dev->ready ) {
  626. if( dev->m_dc->GetLogicalFunction() == wxCOPY )
  627. dev->m_dc->SetLogicalFunction( wxXOR );
  628. else if( dev->m_dc->GetLogicalFunction() == wxXOR )
  629. dev->m_dc->SetLogicalFunction( wxCOPY );
  630. } */
  631. break;
  632. case PLESC_DEVINIT:
  633. dev->SetExternalBuffer( ptr );
  634. /* replay begin of page call and state settings */
  635. plD_bop_wxwidgets( pls );
  636. break;
  637. case PLESC_HAS_TEXT:
  638. if( !(dev->ready) )
  639. install_buffer( pls );
  640. if( dev->freetype ) {
  641. #ifdef HAVE_FREETYPE
  642. plD_render_freetype_text( pls, (EscText *)ptr );
  643. #endif
  644. } else
  645. dev->ProcessString( pls, (EscText *)ptr );
  646. break;
  647. case PLESC_RESIZE:
  648. {
  649. wxSize* size=(wxSize*)ptr;
  650. wx_set_size( pls, size->GetWidth(), size->GetHeight() );
  651. }
  652. break;
  653. case PLESC_CLEAR:
  654. if( !(dev->ready) )
  655. install_buffer( pls );
  656. /* Since the plot is updated only every MAX_COMCOUNT commands (usually 5000)
  657. before we clear the screen we need to show the plot at least once :) */
  658. if( !(dev->resizing) && dev->ownGUI ) {
  659. wxRunApp( pls, true );
  660. dev->comcount=0;
  661. }
  662. dev->ClearBackground( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b,
  663. pls->sppxmi, pls->sppymi, pls->sppxma, pls->sppyma );
  664. break;
  665. case PLESC_GETC:
  666. if( dev->ownGUI )
  667. GetCursorCmd( pls, (PLGraphicsIn *) ptr );
  668. break;
  669. default:
  670. break;
  671. }
  672. }
  673. /*--------------------------------------------------------------------------*\
  674. * static void fill_polygon( PLStream *pls )
  675. *
  676. * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
  677. \*--------------------------------------------------------------------------*/
  678. static void fill_polygon( PLStream *pls )
  679. {
  680. // Log_Verbose( "fill_polygon(), npts=%d, x[0]=%d, y[0]=%d", pls->dev_npts, pls->dev_y[0], pls->dev_y[0] );
  681. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  682. if( !(dev->ready) )
  683. install_buffer( pls );
  684. dev->FillPolygon( pls );
  685. if( !(dev->resizing) && dev->ownGUI ) {
  686. dev->comcount+=10;
  687. if( dev->comcount>MAX_COMCOUNT ) {
  688. wxRunApp( pls, true );
  689. dev->comcount=0;
  690. }
  691. }
  692. }
  693. /*--------------------------------------------------------------------------*\
  694. * void wx_set_size( PLStream* pls, int width, int height )
  695. *
  696. * Adds a dc to the stream. The associated device is attached to the canvas
  697. * as the property "dev".
  698. \*--------------------------------------------------------------------------*/
  699. void wx_set_size( PLStream* pls, int width, int height )
  700. {
  701. /* TODO: buffer must be resized here or in wxplotstream */
  702. // Log_Verbose( "wx_set_size()" );
  703. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  704. /* set new size and scale parameters */
  705. dev->width = width;
  706. dev->height = height;
  707. dev->scalex=(PLFLT)(dev->xmax-dev->xmin)/dev->width;
  708. dev->scaley=(PLFLT)(dev->ymax-dev->ymin)/dev->height;
  709. /* recalculate the dpi used in calculation of fontsize */
  710. pls->xdpi = VIRTUAL_PIXELS_PER_IN/dev->scalex;
  711. pls->ydpi = VIRTUAL_PIXELS_PER_IN/dev->scaley;
  712. /* clear background if we have a dc, since it's invalid (TODO: why, since in bop
  713. it must be cleared anyway?) */
  714. if( dev->ready ) {
  715. PLINT bgr, bgg, bgb; /* red, green, blue */
  716. plgcolbg( &bgr, &bgg, &bgb); /* get background color information */
  717. dev->CreateCanvas();
  718. dev->ClearBackground( bgr, bgg, bgb );
  719. }
  720. /* freetype parameters must also be changed */
  721. #ifdef HAVE_FREETYPE
  722. if( dev->freetype ) {
  723. FT_Data *FT=(FT_Data *)pls->FT;
  724. FT->scalex=dev->scalex;
  725. FT->scaley=dev->scaley;
  726. FT->ymax=dev->height;
  727. }
  728. #endif
  729. }
  730. /*----------------------------------------------------------------------
  731. * int plD_errorexithandler_wxwidgets( const char *errormessage )
  732. *
  733. * If an PLplot error occurs, this function shows a dialog regarding
  734. * this error and than exits.
  735. *----------------------------------------------------------------------*/
  736. int plD_errorexithandler_wxwidgets( const char *errormessage )
  737. {
  738. if( errormessage[0] ) {
  739. wxMessageDialog dialog( 0, wxString(errormessage, *wxConvCurrent),wxString("wxWidgets PLplot App error",*wxConvCurrent),wxOK|wxICON_ERROR );
  740. dialog.ShowModal();
  741. }
  742. return 0;
  743. }
  744. /*----------------------------------------------------------------------
  745. * void plD_erroraborthandler_wxwidgets( const char *errormessage )
  746. *
  747. * If PLplot aborts, this function shows a dialog regarding
  748. * this error.
  749. *----------------------------------------------------------------------*/
  750. void plD_erroraborthandler_wxwidgets( const char *errormessage )
  751. {
  752. if( errormessage[0] ) {
  753. wxMessageDialog dialog( 0,(wxString(errormessage, *wxConvCurrent)+wxString(" aborting operation...", *wxConvCurrent)), wxString("wxWidgets PLplot App abort",*wxConvCurrent), wxOK|wxICON_ERROR );
  754. dialog.ShowModal();
  755. }
  756. }
  757. #ifdef HAVE_FREETYPE
  758. /*----------------------------------------------------------------------*\
  759. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  760. *
  761. * callback function, of type "plD_pixel_fp", which specifies how a single
  762. * pixel is set in the current colour.
  763. \*----------------------------------------------------------------------*/
  764. static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  765. {
  766. // Log_Verbose( "plD_pixel_wxwidgets" );
  767. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  768. if( !(dev->ready) )
  769. install_buffer( pls );
  770. dev->PutPixel( x, y );
  771. if( !(dev->resizing) && dev->ownGUI ) {
  772. dev->comcount++;
  773. if( dev->comcount>MAX_COMCOUNT ) {
  774. wxRunApp( pls, true );
  775. dev->comcount=0;
  776. }
  777. }
  778. }
  779. /*----------------------------------------------------------------------*\
  780. * static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
  781. *
  782. * callback function, of type "plD_pixel_fp", which specifies how a single
  783. * pixel is set in the current colour.
  784. \*----------------------------------------------------------------------*/
  785. static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour)
  786. {
  787. // Log_Verbose( "plD_set_pixel_wxwidgets" );
  788. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  789. if( !(dev->ready) )
  790. install_buffer( pls );
  791. dev->PutPixel( x, y, colour );
  792. if( !(dev->resizing) && dev->ownGUI ) {
  793. dev->comcount++;
  794. if( dev->comcount>MAX_COMCOUNT ) {
  795. wxRunApp( pls, true );
  796. dev->comcount=0;
  797. }
  798. }
  799. }
  800. /*--------------------------------------------------------------------------*\
  801. * void plD_read_pixel_wxwidgets (PLStream *pls, short x, short y)
  802. *
  803. * callback function, of type "plD_pixel_fp", which specifies how a single
  804. * pixel is read.
  805. \*--------------------------------------------------------------------------*/
  806. static PLINT plD_read_pixel_wxwidgets ( PLStream *pls, short x, short y )
  807. {
  808. // Log_Verbose( "plD_read_pixel_wxwidgets" );
  809. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  810. if( !(dev->ready) )
  811. install_buffer( pls );
  812. return dev->GetPixel( x, y );
  813. }
  814. /*----------------------------------------------------------------------*\
  815. * void init_freetype_lv1 (PLStream *pls)
  816. *
  817. * "level 1" initialisation of the freetype library.
  818. * "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
  819. * memory to the pls->FT structure, then sets up the pixel callback
  820. * function.
  821. \*----------------------------------------------------------------------*/
  822. static void init_freetype_lv1( PLStream *pls )
  823. {
  824. // Log_Verbose( "init_freetype_lv1" );
  825. wxPLDevBase *dev=(wxPLDevBase*)pls->dev;
  826. plD_FreeType_init( pls );
  827. FT_Data *FT=(FT_Data *)pls->FT;
  828. FT->pixel = (plD_pixel_fp)plD_pixel_wxwidgets;
  829. /*
  830. * See if we have a 24 bit device (or better), in which case
  831. * we can use the better antialising.
  832. */
  833. // the bitmap we are using in the antialized case has always
  834. // 32 bit depth
  835. FT->BLENDED_ANTIALIASING=1;
  836. FT->read_pixel= (plD_read_pixel_fp)plD_read_pixel_wxwidgets;
  837. FT->set_pixel= (plD_set_pixel_fp)plD_set_pixel_wxwidgets;
  838. }
  839. /*----------------------------------------------------------------------*\
  840. * void init_freetype_lv2 (PLStream *pls)
  841. *
  842. * "Level 2" initialisation of the freetype library.
  843. * "Level 2" fills in a few setting that aren't public until after the
  844. * graphics sub-syetm has been initialised.
  845. * The "level 2" initialisation fills in a few things that are defined
  846. * later in the initialisation process for the GD driver.
  847. *
  848. * FT->scale is a scaling factor to convert co-ordinates. This is used by
  849. * the GD and other drivers to scale back a larger virtual page and this
  850. * eliminate the "hidden line removal bug". Set it to 1 if your device
  851. * doesn't have scaling.
  852. *
  853. * Some coordinate systems have zero on the bottom, others have zero on
  854. * the top. Freetype does it one way, and most everything else does it the
  855. * other. To make sure everything is working ok, we have to "flip" the
  856. * coordinates, and to do this we need to know how big in the Y dimension
  857. * the page is, and whether we have to invert the page or leave it alone.
  858. *
  859. * FT->ymax specifies the size of the page FT->invert_y=1 tells us to
  860. * invert the y-coordinates, FT->invert_y=0 will not invert the
  861. * coordinates.
  862. \*----------------------------------------------------------------------*/
  863. static void init_freetype_lv2( PLStream *pls )
  864. {
  865. // Log_Verbose( "init_freetype_lv2" );
  866. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  867. FT_Data *FT=(FT_Data *)pls->FT;
  868. FT->scalex=dev->scalex;
  869. FT->scaley=dev->scaley;
  870. FT->ymax=dev->height;
  871. FT->invert_y=1;
  872. FT->smooth_text=0;
  873. if ((FT->want_smooth_text==1)&&(FT->BLENDED_ANTIALIASING==0)) /* do we want to at least *try* for smoothing ? */
  874. {
  875. FT->ncol0_org=pls->ncol0; /* save a copy of the original size of ncol0 */
  876. FT->ncol0_xtra=16777216-(pls->ncol1+pls->ncol0); /* work out how many free slots we have */
  877. FT->ncol0_width=FT->ncol0_xtra/(pls->ncol0-1); /* find out how many different shades of anti-aliasing we can do */
  878. if (FT->ncol0_width>4) /* are there enough colour slots free for text smoothing ? */
  879. {
  880. if (FT->ncol0_width>max_number_of_grey_levels_used_in_text_smoothing)
  881. FT->ncol0_width=max_number_of_grey_levels_used_in_text_smoothing; /* set a maximum number of shades */
  882. plscmap0n(FT->ncol0_org+(FT->ncol0_width*pls->ncol0)); /* redefine the size of cmap0 */
  883. /* the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
  884. * call in plscmap0 which (a) leads to segfaults since the GD image is
  885. * not defined at this point and (b) would be inefficient in any case since
  886. * setcmap is always called later (see plD_bop_png) to update the driver
  887. * color palette to be consistent with cmap0. */
  888. {
  889. PLINT level_save;
  890. level_save = pls->level;
  891. pls->level = 0;
  892. pl_set_extended_cmap0(pls, FT->ncol0_width, FT->ncol0_org); /* call the function to add the extra cmap0 entries and calculate stuff */
  893. pls->level = level_save;
  894. }
  895. FT->smooth_text=1; /* Yippee ! We had success setting up the extended cmap0 */
  896. }
  897. } else if ((FT->want_smooth_text==1)&&(FT->BLENDED_ANTIALIASING==1)) /* If we have a truecolour device, we wont even bother trying to change the palette */
  898. {
  899. FT->smooth_text=1;
  900. } else
  901. plwarn("Insufficient colour slots available in CMAP0 to do text smoothing.");
  902. }
  903. #endif
  904. /*--------------------------------------------------------------------------
  905. * GetCursorCmd()
  906. *
  907. * Waits for a graphics input event and returns coordinates.
  908. *--------------------------------------------------------------------------*/
  909. static void GetCursorCmd( PLStream* pls, PLGraphicsIn* ptr)
  910. {
  911. // Log_Verbose( "GetCursorCmd" );
  912. wxPLDevBase *dev=(wxPLDevBase *)pls->dev;
  913. PLGraphicsIn *gin = &(dev->gin);
  914. /* Initialize */
  915. plGinInit( gin );
  916. dev->locate_mode = LOCATE_INVOKED_VIA_API;
  917. dev->draw_xhair=true;
  918. /* Run event loop until a point is selected */
  919. wxRunApp( pls, false );
  920. *ptr = *gin;
  921. if( dev->locate_mode ) {
  922. dev->locate_mode = 0;
  923. dev->draw_xhair=false;
  924. }
  925. }
  926. /*----------------------------------------------------------------------
  927. * This part includes wxWidgets specific functions, which allow to
  928. * open a window from the command line, if needed.
  929. *----------------------------------------------------------------------*/
  930. /*----------------------------------------------------------------------
  931. * void install_buffer( PLStream *pls )
  932. *
  933. * If this driver is called from a command line executable (and not
  934. * from within a wxWidgets program), this function prepares a DC and a
  935. * bitmap to plot into.
  936. *----------------------------------------------------------------------*/
  937. static void install_buffer( PLStream *pls )
  938. {
  939. // Log_Verbose( "install_buffer" );
  940. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  941. static bool initApp=false;
  942. if( !initApp ) {
  943. /* this hack enables to have a GUI on Mac OSX even if the
  944. program was called from the command line (and isn't a bundle) */
  945. #ifdef __WXMAC__
  946. ProcessSerialNumber psn;
  947. GetCurrentProcess( &psn );
  948. CPSEnableForegroundOperation( &psn );
  949. SetFrontProcess( &psn );
  950. #endif
  951. /* initialize wxWidgets */
  952. wxInitialize();
  953. wxLog::GetActiveTarget();
  954. wxTRY {
  955. wxPLGetApp().CallOnInit();
  956. }
  957. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); fprintf(stderr, "Can't init wxWidgets!\n"); exit(0); )
  958. initApp=true;
  959. }
  960. wxString title=wxT("wxWidgets PLplot App");
  961. switch(dev->backend) {
  962. case wxBACKEND_DC:
  963. title += wxT(" (basic)");
  964. break;
  965. case wxBACKEND_GC:
  966. title += wxT(" (wxGC)");
  967. break;
  968. case wxBACKEND_AGG:
  969. title += wxT(" (AGG)");
  970. break;
  971. default:
  972. break;
  973. }
  974. dev->m_frame = new wxPLplotFrame( title, pls );
  975. wxPLGetApp().AddFrame( dev->m_frame );
  976. dev->m_frame->SetClientSize( dev->width, dev->height );
  977. if( dev->showGUI ) {
  978. dev->m_frame->Show( true );
  979. dev->m_frame->Raise();
  980. }
  981. else
  982. dev->m_frame->Show( false );
  983. /* get a DC and a bitmap or an imagebuffer */
  984. dev->ownGUI = true;
  985. dev->bm_width=dev->width;
  986. dev->bm_height=dev->height;
  987. dev->CreateCanvas();
  988. dev->ready = true;
  989. /* Set wx error handler for various errors in plplot*/
  990. plsexit( plD_errorexithandler_wxwidgets );
  991. plsabort( plD_erroraborthandler_wxwidgets );
  992. /* replay command we may have missed */
  993. plD_bop_wxwidgets( pls );
  994. }
  995. /*----------------------------------------------------------------------
  996. * void wxRunApp( PLStream *pls, bool runonce )
  997. *
  998. * This is a hacked wxEntry-function, so that wxUninitialize is not
  999. * called twice. Here we actually start the wxApplication.
  1000. *----------------------------------------------------------------------*/
  1001. static void wxRunApp( PLStream *pls, bool runonce )
  1002. {
  1003. // Log_Verbose( "wxRunApp" );
  1004. wxPLDevBase* dev = (wxPLDevBase*)pls->dev;
  1005. dev->waiting=true;
  1006. wxTRY
  1007. {
  1008. class CallOnExit
  1009. {
  1010. public:
  1011. /* only call OnExit if exit is true (i.e. due an exception) */
  1012. ~CallOnExit() { if(exit) wxPLGetApp().OnExit(); }
  1013. bool exit;
  1014. } callOnExit;
  1015. callOnExit.exit=true;
  1016. wxPLGetApp().SetAdvanceFlag( runonce );
  1017. wxPLGetApp().SetRefreshFlag();
  1018. /* add an idle event is necessary for Linux (wxGTK2)
  1019. but not for Windows, but it doesn't harm */
  1020. wxIdleEvent event;
  1021. wxPLGetApp().AddPendingEvent( event );
  1022. wxPLGetApp().OnRun(); /* start wxWidgets application */
  1023. callOnExit.exit=false;
  1024. }
  1025. wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); fprintf(stderr, "Problem running wxWidgets!\n"); exit(0); )
  1026. if( dev->exit ) {
  1027. wxPLGetApp().OnExit();
  1028. plexit("");
  1029. }
  1030. dev->waiting=false;
  1031. }