/branches/v5_9_8_debian/drivers/wxwidgets.cpp
C++ | 1373 lines | 813 code | 228 blank | 332 comment | 127 complexity | 077d0f205b40ad15d0bbc5c8bdc91e01 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0
- // $Id: wxwidgets.cpp 11760 2011-06-01 19:29:11Z airwin $
- //
- // Copyright (C) 2005 Werner Smekal, Sjaak Verdoold
- // Copyright (C) 2005 Germain Carrera Corraleche
- // Copyright (C) 1999 Frank Huebner
- //
- // This file is part of PLplot.
- //
- // PLplot is free software; you can redistribute it and/or modify
- // it under the terms of the GNU Library General Public License as published
- // by the Free Software Foundation; either version 2 of the License, or
- // (at your option) any later version.
- //
- // PLplot is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Library General Public License for more details.
- //
- // You should have received a copy of the GNU Library General Public License
- // along with PLplot; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // TODO:
- // - NA
- //
- // wxwidgets headers
- #include <wx/wx.h>
- #include <wx/wfstream.h>
- #include <wx/except.h>
- #include "plDevs.h"
- // plplot headers
- #include "plplotP.h"
- #include "drivers.h"
- // C/C++ headers
- #include <cstdio>
- #include "wxwidgets.h"
- #ifdef __WXMAC__
- #include <Carbon/Carbon.h>
- extern "C" { void CPSEnableForegroundOperation( ProcessSerialNumber* psn ); }
- #endif
- DECLARE_PLAPP( wxPLplotApp )
- //--------------------------------------------------------------------------
- // void Log_Verbose( const char *fmt, ... )
- //
- // Print verbose debug message to stderr (printf style).
- //--------------------------------------------------------------------------
- void Log_Verbose( const char *fmt, ... )
- {
- #ifdef _DEBUG_VERBOSE
- va_list args;
- va_start( args, fmt );
- fprintf( stderr, "Verbose: " );
- vfprintf( stderr, fmt, args );
- fprintf( stderr, "\n" );
- va_end( args );
- fflush( stderr );
- #endif
- }
- //--------------------------------------------------------------------------
- // void Log_Debug( const char *fmt, ... )
- //
- // Print debug message to stderr (printf style).
- //--------------------------------------------------------------------------
- void Log_Debug( const char *fmt, ... )
- {
- #ifdef _DEBUG
- va_list args;
- va_start( args, fmt );
- fprintf( stderr, "Debug: " );
- vfprintf( stderr, fmt, args );
- fprintf( stderr, "\n" );
- va_end( args );
- fflush( stderr );
- #endif
- }
- //--------------------------------------------------------------------------
- // In the following you'll find the driver functions which are
- // are needed by the plplot core.
- //--------------------------------------------------------------------------
- // Device info
- #ifdef __cplusplus
- extern "C" {
- #endif
- PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_wxwidgets =
- #ifdef PLD_wxwidgets
- "wxwidgets:wxWidgets Driver:1:wxwidgets:51:wxwidgets\n"
- #endif
- #ifdef PLD_wxpng
- "wxpng:wxWidgets PNG Driver:0:wxwidgets:52:wxpng\n"
- #endif
- ;
- #ifdef __cplusplus
- }
- #endif
- //--------------------------------------------------------------------------
- // wxPLDevBase::wxPLDevBase( void )
- //
- // Contructor of base class of wxPLDev classes.
- //--------------------------------------------------------------------------
- wxPLDevBase::wxPLDevBase( int bcknd ) : backend( bcknd )
- {
- // Log_Verbose( "wxPLDevBase::wxPLDevBase()" );
- ready = false;
- ownGUI = false;
- waiting = false;
- resizing = false;
- exit = false;
- comcount = 0;
- m_frame = NULL;
- xpos = 0;
- ypos = 0;
- // width, height are set in plD_init_wxwidgets
- // bm_width, bm_height are set in install_buffer
- // xmin, xmax, ymin, ymax are set in plD_init_wxwidgets
- // scalex, scaley are set in plD_init_wxwidgets
- plstate_width = false;
- plstate_color0 = false;
- plstate_color1 = false;
- locate_mode = 0;
- draw_xhair = false;
- newclipregion = true;
- clipminx = 1024;
- clipmaxx = 0;
- clipminy = 800;
- clipmaxy = 0;
- freetype = 0;
- smooth_text = 0;
- devName = (const char **) malloc( NDEV * sizeof ( char** ) );
- memset( devName, '\0', NDEV * sizeof ( char** ) );
- devDesc = (const char **) malloc( NDEV * sizeof ( char** ) );
- memset( devDesc, '\0', NDEV * sizeof ( char** ) );
- ndev = NDEV;
- }
- wxPLDevBase::~wxPLDevBase( void )
- {
- if ( devDesc )
- free( devDesc );
- if ( devName )
- free( devName );
- }
- void wxPLDevBase::AddtoClipRegion( int x1, int y1, int x2, int y2 )
- {
- newclipregion = false;
- if ( x1 < x2 )
- {
- if ( x1 < clipminx )
- clipminx = x1;
- if ( x2 > clipmaxx )
- clipmaxx = x2;
- }
- else
- {
- if ( x2 < clipminx )
- clipminx = x2;
- if ( x1 > clipmaxx )
- clipmaxx = x1;
- }
- if ( y1 < y2 )
- {
- if ( y1 < clipminy )
- clipminy = y1;
- if ( y2 > clipmaxy )
- clipmaxy = y2;
- }
- else
- {
- if ( y2 < clipminy )
- clipminy = y2;
- if ( y1 > clipmaxy )
- clipmaxy = y1;
- }
- }
- void wxPLDevBase::PSDrawText( PLUNICODE* ucs4, int ucs4Len, bool drawText )
- {
- int i = 0;
- char utf8_string[max_string_length];
- char utf8[5];
- memset( utf8_string, '\0', max_string_length );
- // Get PLplot escape character
- char plplotEsc;
- plgesc( &plplotEsc );
- // Get the curent font
- fontScale = 1.0;
- yOffset = 0.0;
- PLUNICODE fci;
- plgfci( &fci );
- PSSetFont( fci );
- textWidth = 0;
- textHeight = 0;
- while ( i < ucs4Len )
- {
- if ( ucs4[i] < PL_FCI_MARK ) // not a font change
- {
- if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
- {
- ucs4_to_utf8( ucs4[i], utf8 );
- strncat( utf8_string, utf8, max_string_length );
- i++;
- continue;
- }
- i++;
- if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
- {
- ucs4_to_utf8( ucs4[i], utf8 );
- strncat( utf8_string, utf8, max_string_length );
- i++;
- continue;
- }
- else
- {
- if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
- { // draw string so far
- PSDrawTextToDC( utf8_string, drawText );
- // change font scale
- if ( yOffset < -0.0001 )
- fontScale *= 1.25; // Subscript scaling parameter
- else
- fontScale *= 0.8; // Subscript scaling parameter
- PSSetFont( fci );
- yOffset += scaley * fontSize * fontScale / 2.;
- }
- if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
- { // draw string so far
- PSDrawTextToDC( utf8_string, drawText );
- // change font scale
- double old_fontScale = fontScale;
- if ( yOffset > 0.0001 )
- fontScale *= 1.25; // Subscript scaling parameter
- else
- fontScale *= 0.8; // Subscript scaling parameter
- PSSetFont( fci );
- yOffset -= scaley * fontSize * old_fontScale / 2.;
- }
- if ( ucs4[i] == (PLUNICODE) '-' ) // underline
- { // draw string so far
- PSDrawTextToDC( utf8_string, drawText );
- underlined = !underlined;
- PSSetFont( fci );
- }
- if ( ucs4[i] == (PLUNICODE) '+' ) // overline
- { // not implemented yet
- }
- i++;
- }
- }
- else // a font change
- {
- // draw string so far
- PSDrawTextToDC( utf8_string, drawText );
- // get new font
- fci = ucs4[i];
- PSSetFont( fci );
- i++;
- }
- }
- PSDrawTextToDC( utf8_string, drawText );
- }
- //--------------------------------------------------------------------------
- // void common_init( PLStream *pls )
- //
- // Basic initialization for all devices.
- //--------------------------------------------------------------------------
- wxPLDevBase* common_init( PLStream *pls )
- {
- // Log_Verbose( "common_init()" );
- wxPLDevBase* dev;
- // default options
- static PLINT freetype = -1;
- static PLINT smooth_text = 1;
- static PLINT text = -1;
- static PLINT hrshsym = 0;
- // default backend uses wxGraphicsContext, if not available
- // the agg library will be used, if not available the basic
- // backend will be used.
- static PLINT backend = wxBACKEND_DC;
- #if wxUSE_GRAPHICS_CONTEXT
- backend = wxBACKEND_GC;
- #else
- #ifdef HAVE_AGG
- backend = wxBACKEND_AGG;
- #endif
- #endif
- DrvOpt wx_options[] = {
- #ifdef HAVE_FREETYPE
- { "freetype", DRV_INT, &freetype, "Use FreeType library" },
- { "smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)" },
- #endif
- { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" },
- { "backend", DRV_INT, &backend, "Choose backend: (0) standard, (1) using AGG library, (2) using wxGraphicsContext" },
- { "text", DRV_INT, &text, "Use own text routines (text=0|1)" },
- { NULL, DRV_INT, NULL, NULL }
- };
- // Check for and set up driver options
- plParseDrvOpts( wx_options );
- // allocate memory for the device storage
- switch ( backend )
- {
- case wxBACKEND_GC:
- // in case wxGraphicsContext isn't available, the next backend (agg
- // if available) in this list will be used
- #if wxUSE_GRAPHICS_CONTEXT
- dev = new wxPLDevGC;
- // by default the own text routines are used for wxGC
- if ( text == -1 )
- text = 1;
- freetype = 0; // this backend is vector oriented and doesn't know pixels
- break;
- #endif
- case wxBACKEND_AGG:
- // in case the agg library isn't available, the standard backend
- // will be used
- #ifdef HAVE_AGG
- dev = new wxPLDevAGG;
- // by default the freetype text routines are used for wxAGG
- text = 0; // text processing doesn't work yet for the AGG backend
- if ( freetype == -1 )
- freetype = 1;
- break;
- #endif
- default:
- dev = new wxPLDevDC;
- // by default the own text routines are used for wxDC
- if ( text == -1 )
- if ( freetype != 1 )
- text = 1;
- else
- text = 0;
- if ( freetype == -1 )
- freetype = 0;
- break;
- }
- if ( dev == NULL )
- {
- plexit( "Insufficient memory" );
- }
- pls->dev = (void *) dev;
- // be verbose and write out debug messages
- #ifdef _DEBUG
- pls->verbose = 1;
- pls->debug = 1;
- #endif
- pls->color = 1; // Is a color device
- pls->dev_flush = 1; // Handles flushes
- pls->dev_fill0 = 1; // Can handle solid fills
- pls->dev_fill1 = 0; // Can't handle pattern fills
- pls->dev_dash = 0;
- pls->dev_clear = 1; // driver supports clear
- if ( text )
- {
- pls->dev_text = 1; // want to draw text
- pls->dev_unicode = 1; // want unicode
- if ( hrshsym )
- pls->dev_hrshsym = 1;
- }
- #ifdef HAVE_FREETYPE
- // own text routines have higher priority over freetype
- // if text and freetype option are set to 1
- if ( !text )
- {
- dev->smooth_text = smooth_text;
- dev->freetype = freetype;
- }
- if ( dev->freetype )
- {
- pls->dev_text = 1; // want to draw text
- pls->dev_unicode = 1; // want unicode
- if ( hrshsym )
- pls->dev_hrshsym = 1;
- init_freetype_lv1( pls );
- FT_Data* FT = (FT_Data *) pls->FT;
- FT->want_smooth_text = smooth_text;
- }
- #endif
- // initialize frame size and position
- if ( pls->xlength <= 0 || pls->ylength <= 0 )
- plspage( 0.0, 0.0, (PLINT) ( CANVAS_WIDTH * DEVICE_PIXELS_PER_IN ),
- (PLINT) ( CANVAS_HEIGHT * DEVICE_PIXELS_PER_IN ), 0, 0 );
- dev->width = pls->xlength;
- dev->height = pls->ylength;
- dev->clipminx = pls->xlength;
- dev->clipminy = pls->ylength;
- if ( pls->xoffset != 0 || pls->yoffset != 0 )
- {
- dev->xpos = (int) ( pls->xoffset );
- dev->ypos = (int) ( pls->yoffset );
- }
- // If portrait mode, apply a rotation and set freeaspect
- if ( pls->portrait )
- {
- plsdiori( (PLFLT) ( 4 - ORIENTATION ) );
- pls->freeaspect = 1;
- }
- // Set the number of pixels per mm
- plP_setpxl( (PLFLT) VIRTUAL_PIXELS_PER_MM, (PLFLT) VIRTUAL_PIXELS_PER_MM );
- // Set up physical limits of plotting device (in drawing units)
- plP_setphy( (PLINT) 0, (PLINT) ( CANVAS_WIDTH * VIRTUAL_PIXELS_PER_IN ),
- (PLINT) 0, (PLINT) ( CANVAS_HEIGHT * VIRTUAL_PIXELS_PER_IN ) );
- // get physical device limits coordinates
- plP_gphy( &dev->xmin, &dev->xmax, &dev->ymin, &dev->ymax );
- // setting scale factors
- dev->scalex = (PLFLT) ( dev->xmax - dev->xmin ) / ( dev->width );
- dev->scaley = (PLFLT) ( dev->ymax - dev->ymin ) / ( dev->height );
- // set dpi
- plspage( VIRTUAL_PIXELS_PER_IN / dev->scalex, VIRTUAL_PIXELS_PER_IN / dev->scaley, 0, 0, 0, 0 );
- #ifdef HAVE_FREETYPE
- if ( dev->freetype )
- init_freetype_lv2( pls );
- #endif
- // find out what file drivers are available
- plgFileDevs( &dev->devDesc, &dev->devName, &dev->ndev );
- return dev;
- }
- #ifdef PLD_wxwidgets
- //--------------------------------------------------------------------------
- // void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
- //
- // Make wxwidgets driver functions known to plplot.
- //--------------------------------------------------------------------------
- void plD_dispatch_init_wxwidgets( PLDispatchTable *pdt )
- {
- #ifndef ENABLE_DYNDRIVERS
- pdt->pl_MenuStr = "wxWidgets DC";
- pdt->pl_DevName = "wxwidgets";
- #endif
- pdt->pl_type = plDevType_Interactive;
- pdt->pl_seq = 51;
- pdt->pl_init = (plD_init_fp) plD_init_wxwidgets;
- pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
- pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
- pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
- pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
- pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
- pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
- pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
- }
- //--------------------------------------------------------------------------
- // plD_init_wxwidgets( PLStream* pls )
- //
- // Initialize wxWidgets device.
- //--------------------------------------------------------------------------
- void plD_init_wxwidgets( PLStream* pls )
- {
- // Log_Verbose( "plD_init_wxwidgets()" );
- wxPLDevBase* dev;
- dev = common_init( pls );
- pls->plbuf_write = 1; // use the plot buffer!
- pls->termin = 1; // interactive device
- 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)
- dev->showGUI = true;
- dev->bitmapType = (wxBitmapType) 0;
- }
- #endif // PLD_wxwidgets
- #ifdef PLD_wxpng
- //--------------------------------------------------------------------------
- // void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
- //
- // Make wxpng driver functions known to plplot.
- //--------------------------------------------------------------------------
- void plD_dispatch_init_wxpng( PLDispatchTable *pdt )
- {
- #ifndef ENABLE_DYNDRIVERS
- pdt->pl_MenuStr = "wxWidgets PNG driver";
- pdt->pl_DevName = "wxpng";
- #endif
- pdt->pl_type = plDevType_FileOriented;
- pdt->pl_seq = 52;
- pdt->pl_init = (plD_init_fp) plD_init_wxpng;
- pdt->pl_line = (plD_line_fp) plD_line_wxwidgets;
- pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wxwidgets;
- pdt->pl_eop = (plD_eop_fp) plD_eop_wxwidgets;
- pdt->pl_bop = (plD_bop_fp) plD_bop_wxwidgets;
- pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wxwidgets;
- pdt->pl_state = (plD_state_fp) plD_state_wxwidgets;
- pdt->pl_esc = (plD_esc_fp) plD_esc_wxwidgets;
- }
- //--------------------------------------------------------------------------
- // void plD_init_wxpng( PLStream *pls )
- //
- // Initialize wxpng device.
- //--------------------------------------------------------------------------
- void plD_init_wxpng( PLStream *pls )
- {
- // Log_Verbose( "plD_init_wxwidgets()" );
- wxPLDevBase* dev;
- dev = common_init( pls );
- // Initialize family file info
- plFamInit( pls );
- // Prompt for a file name if not already set.
- plOpenFile( pls );
- pls->plbuf_write = 1; // use the plot buffer!
- pls->dev_flush = 0; // No need for flushes
- pls->termin = 0; // file oriented device
- 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)
- pls->page = 0;
- dev->showGUI = false;
- dev->bitmapType = wxBITMAP_TYPE_PNG;
- }
- #endif // PLD_wxpng
- //--------------------------------------------------------------------------
- // void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a,
- // short x2a, short y2a )
- //
- // Draws a line from (x1a, y1a) to (x2a, y2a).
- //--------------------------------------------------------------------------
- void plD_line_wxwidgets( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
- {
- // Log_Verbose( "plD_line_wxwidgets(x1a=%d, y1a=%d, x2a=%d, y2a=%d)", x1a, y1a, x2a, y2a );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- dev->DrawLine( x1a, y1a, x2a, y2a );
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- dev->comcount++;
- if ( dev->comcount > MAX_COMCOUNT )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- }
- }
- //--------------------------------------------------------------------------
- // void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya,
- // PLINT npts )
- //
- // Draw a poly line - points are in xa and ya arrays.
- //--------------------------------------------------------------------------
- void plD_polyline_wxwidgets( PLStream *pls, short *xa, short *ya, PLINT npts )
- {
- // Log_Verbose( "plD_polyline_wxwidgets()" );
- // should be changed to use the wxDC::DrawLines function?
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- dev->DrawPolyline( xa, ya, npts );
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- dev->comcount++;
- if ( dev->comcount > MAX_COMCOUNT )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- }
- }
- //--------------------------------------------------------------------------
- // void plD_eop_wxwidgets( PLStream *pls )
- //
- // End of Page. This function is called if a "end of page" is send by the
- // user. This command is ignored if we have the plot embedded in a
- // wxWidgets application, otherwise the application created by the device
- // takes over.
- //--------------------------------------------------------------------------
- void plD_eop_wxwidgets( PLStream *pls )
- {
- // Log_Verbose( "plD_eop_wxwidgets()" );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- if ( dev->bitmapType )
- {
- wxMemoryDC memDC;
- wxBitmap bitmap( dev->width, dev->height, -1 );
- memDC.SelectObject( bitmap );
- dev->BlitRectangle( &memDC, 0, 0, dev->width, dev->height );
- wxImage buffer = bitmap.ConvertToImage();
- wxFFileOutputStream fstream( pls->OutFile );
- if ( !( buffer.SaveFile( fstream, dev->bitmapType ) ) )
- puts( "Troubles saving file!" );
- memDC.SelectObject( wxNullBitmap );
- }
- if ( dev->ownGUI )
- if ( pls->nopause || !dev->showGUI )
- wxRunApp( pls, true );
- else
- wxRunApp( pls );
- }
- //--------------------------------------------------------------------------
- // void plD_bop_wxwidgets( PLStream *pls )
- //
- // Begin of page. Before any plot command, this function is called, If we
- // have already a dc the background is cleared in background color and some
- // state calls are resent - this is because at the first call of this
- // function, a dc does most likely not exist, but state calls are recorded
- // and when a new dc is created this function is called again.
- //--------------------------------------------------------------------------
- void plD_bop_wxwidgets( PLStream *pls )
- {
- // Log_Verbose( "plD_bop_wxwidgets()" );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- if ( dev->ready )
- {
- //if( pls->termin==0 ) {
- // plGetFam( pls );
- // force new file if pls->family set for all subsequent calls to plGetFam
- // n.b. putting this after plGetFam call is important since plinit calls
- // bop, and you don't want the familying sequence started until after
- // that first call to bop.
- // n.b. pls->dev can change because of an indirect call to plD_init_png
- // from plGetFam if familying is enabled. Thus, wait to define dev until
- // now.
- //dev = (wxPLDevBase*)pls->dev;
- //
- // pls->famadv = 1;
- // pls->page++;
- // }
- // clear background
- PLINT bgr, bgg, bgb; // red, green, blue
- plgcolbg( &bgr, &bgg, &bgb ); // get background color information
- dev->ClearBackground( bgr, bgg, bgb );
- // Replay escape calls that come in before PLESC_DEVINIT. All of them
- // required a DC that didn't exist yet.
- //
- if ( dev->plstate_width )
- plD_state_wxwidgets( pls, PLSTATE_WIDTH );
- dev->plstate_width = false;
- if ( dev->plstate_color0 )
- plD_state_wxwidgets( pls, PLSTATE_COLOR0 );
- dev->plstate_color0 = false;
- if ( dev->plstate_color1 )
- plD_state_wxwidgets( pls, PLSTATE_COLOR1 );
- dev->plstate_color1 = false;
- // why this? xwin driver has this
- // pls->page++;
- }
- }
- //--------------------------------------------------------------------------
- // void plD_tidy_wxwidgets( PLStream *pls )
- //
- // This function is called, if all plots are done.
- //--------------------------------------------------------------------------
- void plD_tidy_wxwidgets( PLStream *pls )
- {
- // Log_Verbose( "plD_tidy_wxwidgets()" );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- #ifdef HAVE_FREETYPE
- if ( dev->freetype )
- {
- FT_Data *FT = (FT_Data *) pls->FT;
- plscmap0n( FT->ncol0_org );
- plD_FreeType_Destroy( pls );
- }
- #endif
- if ( dev->ownGUI )
- {
- wxPLGetApp().RemoveFrame( dev->m_frame );
- if ( !wxPLGetApp().FrameCount() )
- wxUninitialize();
- }
- delete dev;
- pls->dev = NULL; // since in plcore.c pls->dev is free_mem'd
- }
- //--------------------------------------------------------------------------
- // void plD_state_wxwidgets( PLStream *pls, PLINT op )
- //
- // Handler for several state codes. Here we take care of setting the width
- // and color of the pen.
- //--------------------------------------------------------------------------
- void plD_state_wxwidgets( PLStream *pls, PLINT op )
- {
- // Log_Verbose( "plD_state_wxwidgets(op=%d)", op );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- switch ( op )
- {
- case PLSTATE_WIDTH: // 1
- if ( dev->ready )
- dev->SetWidth( pls );
- else
- dev->plstate_width = true;
- break;
- case PLSTATE_COLOR0: // 2
- if ( dev->ready )
- dev->SetColor0( pls );
- else
- dev->plstate_color0 = true;
- break;
- case PLSTATE_COLOR1: // 3
- if ( dev->ready )
- dev->SetColor1( pls );
- else
- dev->plstate_color1 = true;
- break;
- default:
- if ( !( dev->ready ) )
- install_buffer( pls );
- }
- }
- //--------------------------------------------------------------------------
- // void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
- //
- // Handler for several escape codes. Here we take care of filled polygons,
- // XOR or copy mode, initialize device (install dc from outside), and if
- // there is freetype support, rerendering of text.
- //--------------------------------------------------------------------------
- void plD_esc_wxwidgets( PLStream *pls, PLINT op, void *ptr )
- {
- // Log_Verbose( "plD_esc_wxwidgets(op=%d, ptr=%x)", op, ptr );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- switch ( op )
- {
- case PLESC_FILL:
- fill_polygon( pls );
- break;
- case PLESC_XORMOD:
- // switch between wxXOR and wxCOPY
- // if( dev->ready ) {
- // if( dev->m_dc->GetLogicalFunction() == wxCOPY )
- // dev->m_dc->SetLogicalFunction( wxXOR );
- // else if( dev->m_dc->GetLogicalFunction() == wxXOR )
- // dev->m_dc->SetLogicalFunction( wxCOPY );
- // }
- break;
- case PLESC_DEVINIT:
- dev->SetExternalBuffer( ptr );
- // replay begin of page call and state settings
- plD_bop_wxwidgets( pls );
- break;
- case PLESC_HAS_TEXT:
- if ( !( dev->ready ) )
- install_buffer( pls );
- if ( dev->freetype )
- {
- #ifdef HAVE_FREETYPE
- plD_render_freetype_text( pls, (EscText *) ptr );
- #endif
- }
- else
- dev->ProcessString( pls, (EscText *) ptr );
- break;
- case PLESC_RESIZE:
- {
- wxSize* size = (wxSize *) ptr;
- wx_set_size( pls, size->GetWidth(), size->GetHeight() );
- }
- break;
- case PLESC_CLEAR:
- if ( !( dev->ready ) )
- install_buffer( pls );
- // Since the plot is updated only every MAX_COMCOUNT commands (usually 5000)
- // before we clear the screen we need to show the plot at least once :)
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- dev->ClearBackground( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b,
- pls->sppxmi, pls->sppymi, pls->sppxma, pls->sppyma );
- break;
- case PLESC_FLUSH: // forced update of the window
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- break;
- case PLESC_GETC:
- if ( dev->ownGUI )
- GetCursorCmd( pls, (PLGraphicsIn *) ptr );
- break;
- case PLESC_GETBACKEND:
- *( (int *) ptr ) = dev->backend;
- break;
- default:
- break;
- }
- }
- //--------------------------------------------------------------------------
- // static void fill_polygon( PLStream *pls )
- //
- // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
- //--------------------------------------------------------------------------
- static void fill_polygon( PLStream *pls )
- {
- // Log_Verbose( "fill_polygon(), npts=%d, x[0]=%d, y[0]=%d", pls->dev_npts, pls->dev_y[0], pls->dev_y[0] );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- dev->FillPolygon( pls );
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- dev->comcount += 10;
- if ( dev->comcount > MAX_COMCOUNT )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- }
- }
- //--------------------------------------------------------------------------
- // void wx_set_size( PLStream* pls, int width, int height )
- //
- // Adds a dc to the stream. The associated device is attached to the canvas
- // as the property "dev".
- //--------------------------------------------------------------------------
- void wx_set_size( PLStream* pls, int width, int height )
- {
- // TODO: buffer must be resized here or in wxplotstream
- // Log_Verbose( "wx_set_size()" );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- // set new size and scale parameters
- dev->width = width;
- dev->height = height;
- dev->scalex = (PLFLT) ( dev->xmax - dev->xmin ) / dev->width;
- dev->scaley = (PLFLT) ( dev->ymax - dev->ymin ) / dev->height;
- // recalculate the dpi used in calculation of fontsize
- pls->xdpi = VIRTUAL_PIXELS_PER_IN / dev->scalex;
- pls->ydpi = VIRTUAL_PIXELS_PER_IN / dev->scaley;
- // clear background if we have a dc, since it's invalid (TODO: why, since in bop
- // it must be cleared anyway?)
- if ( dev->ready )
- {
- PLINT bgr, bgg, bgb; // red, green, blue
- plgcolbg( &bgr, &bgg, &bgb ); // get background color information
- dev->CreateCanvas();
- dev->ClearBackground( bgr, bgg, bgb );
- }
- // freetype parameters must also be changed
- #ifdef HAVE_FREETYPE
- if ( dev->freetype )
- {
- FT_Data *FT = (FT_Data *) pls->FT;
- FT->scalex = dev->scalex;
- FT->scaley = dev->scaley;
- FT->ymax = dev->height;
- }
- #endif
- }
- //--------------------------------------------------------------------------
- // int plD_errorexithandler_wxwidgets( const char *errormessage )
- //
- // If an PLplot error occurs, this function shows a dialog regarding
- // this error and than exits.
- //--------------------------------------------------------------------------
- int plD_errorexithandler_wxwidgets( const char *errormessage )
- {
- if ( errormessage[0] )
- {
- wxMessageDialog dialog( 0, wxString( errormessage, *wxConvCurrent ), wxString( "wxWidgets PLplot App error", *wxConvCurrent ), wxOK | wxICON_ERROR );
- dialog.ShowModal();
- }
- return 0;
- }
- //--------------------------------------------------------------------------
- // void plD_erroraborthandler_wxwidgets( const char *errormessage )
- //
- // If PLplot aborts, this function shows a dialog regarding
- // this error.
- //--------------------------------------------------------------------------
- void plD_erroraborthandler_wxwidgets( const char *errormessage )
- {
- if ( errormessage[0] )
- {
- wxMessageDialog dialog( 0, ( wxString( errormessage, *wxConvCurrent ) + wxString( " aborting operation...", *wxConvCurrent ) ), wxString( "wxWidgets PLplot App abort", *wxConvCurrent ), wxOK | wxICON_ERROR );
- dialog.ShowModal();
- }
- }
- #ifdef HAVE_FREETYPE
- //--------------------------------------------------------------------------
- // static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
- //
- // callback function, of type "plD_pixel_fp", which specifies how a single
- // pixel is set in the current colour.
- //--------------------------------------------------------------------------
- static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
- {
- // Log_Verbose( "plD_pixel_wxwidgets" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- dev->PutPixel( x, y );
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- dev->comcount++;
- if ( dev->comcount > MAX_COMCOUNT )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- }
- }
- //--------------------------------------------------------------------------
- // static void plD_pixel_wxwidgets( PLStream *pls, short x, short y )
- //
- // callback function, of type "plD_pixel_fp", which specifies how a single
- // pixel is set in the current colour.
- //--------------------------------------------------------------------------
- static void plD_set_pixel_wxwidgets( PLStream *pls, short x, short y, PLINT colour )
- {
- // Log_Verbose( "plD_set_pixel_wxwidgets" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- dev->PutPixel( x, y, colour );
- if ( !( dev->resizing ) && dev->ownGUI )
- {
- dev->comcount++;
- if ( dev->comcount > MAX_COMCOUNT )
- {
- wxRunApp( pls, true );
- dev->comcount = 0;
- }
- }
- }
- //--------------------------------------------------------------------------
- // void plD_read_pixel_wxwidgets (PLStream *pls, short x, short y)
- //
- // callback function, of type "plD_pixel_fp", which specifies how a single
- // pixel is read.
- //--------------------------------------------------------------------------
- static PLINT plD_read_pixel_wxwidgets( PLStream *pls, short x, short y )
- {
- // Log_Verbose( "plD_read_pixel_wxwidgets" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- if ( !( dev->ready ) )
- install_buffer( pls );
- return dev->GetPixel( x, y );
- }
- //--------------------------------------------------------------------------
- // void init_freetype_lv1 (PLStream *pls)
- //
- // "level 1" initialisation of the freetype library.
- // "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
- // memory to the pls->FT structure, then sets up the pixel callback
- // function.
- //--------------------------------------------------------------------------
- static void init_freetype_lv1( PLStream *pls )
- {
- // Log_Verbose( "init_freetype_lv1" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- plD_FreeType_init( pls );
- FT_Data *FT = (FT_Data *) pls->FT;
- FT->pixel = (plD_pixel_fp) plD_pixel_wxwidgets;
- //
- // See if we have a 24 bit device (or better), in which case
- // we can use the better antialising.
- //
- // the bitmap we are using in the antialized case has always
- // 32 bit depth
- FT->BLENDED_ANTIALIASING = 1;
- FT->read_pixel = (plD_read_pixel_fp) plD_read_pixel_wxwidgets;
- FT->set_pixel = (plD_set_pixel_fp) plD_set_pixel_wxwidgets;
- }
- //--------------------------------------------------------------------------
- // void init_freetype_lv2 (PLStream *pls)
- //
- // "Level 2" initialisation of the freetype library.
- // "Level 2" fills in a few setting that aren't public until after the
- // graphics sub-syetm has been initialised.
- // The "level 2" initialisation fills in a few things that are defined
- // later in the initialisation process for the GD driver.
- //
- // FT->scale is a scaling factor to convert co-ordinates. This is used by
- // the GD and other drivers to scale back a larger virtual page and this
- // eliminate the "hidden line removal bug". Set it to 1 if your device
- // doesn't have scaling.
- //
- // Some coordinate systems have zero on the bottom, others have zero on
- // the top. Freetype does it one way, and most everything else does it the
- // other. To make sure everything is working ok, we have to "flip" the
- // coordinates, and to do this we need to know how big in the Y dimension
- // the page is, and whether we have to invert the page or leave it alone.
- //
- // FT->ymax specifies the size of the page FT->invert_y=1 tells us to
- // invert the y-coordinates, FT->invert_y=0 will not invert the
- // coordinates.
- //--------------------------------------------------------------------------
- static void init_freetype_lv2( PLStream *pls )
- {
- // Log_Verbose( "init_freetype_lv2" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- FT_Data *FT = (FT_Data *) pls->FT;
- FT->scalex = dev->scalex;
- FT->scaley = dev->scaley;
- FT->ymax = dev->height;
- FT->invert_y = 1;
- FT->smooth_text = 0;
- if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) ) // do we want to at least *try* for smoothing ?
- {
- FT->ncol0_org = pls->ncol0; // save a copy of the original size of ncol0
- FT->ncol0_xtra = 16777216 - ( pls->ncol1 + pls->ncol0 ); // work out how many free slots we have
- FT->ncol0_width = FT->ncol0_xtra / ( pls->ncol0 - 1 ); // find out how many different shades of anti-aliasing we can do
- if ( FT->ncol0_width > 4 ) // are there enough colour slots free for text smoothing ?
- {
- if ( FT->ncol0_width > max_number_of_grey_levels_used_in_text_smoothing )
- FT->ncol0_width = max_number_of_grey_levels_used_in_text_smoothing; // set a maximum number of shades
- plscmap0n( FT->ncol0_org + ( FT->ncol0_width * pls->ncol0 ) ); // redefine the size of cmap0
- // the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
- // call in plscmap0 which (a) leads to segfaults since the GD image is
- // not defined at this point and (b) would be inefficient in any case since
- // setcmap is always called later (see plD_bop_png) to update the driver
- // color palette to be consistent with cmap0.
- {
- PLINT level_save;
- level_save = pls->level;
- pls->level = 0;
- pl_set_extended_cmap0( pls, FT->ncol0_width, FT->ncol0_org ); // call the function to add the extra cmap0 entries and calculate stuff
- pls->level = level_save;
- }
- FT->smooth_text = 1; // Yippee ! We had success setting up the extended cmap0
- }
- else
- plwarn( "Insufficient colour slots available in CMAP0 to do text smoothing." );
- }
- 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
- {
- FT->smooth_text = 1;
- }
- }
- #endif
- //--------------------------------------------------------------------------
- // GetCursorCmd()
- //
- // Waits for a graphics input event and returns coordinates.
- //--------------------------------------------------------------------------
- static void GetCursorCmd( PLStream* pls, PLGraphicsIn* ptr )
- {
- // Log_Verbose( "GetCursorCmd" );
- wxPLDevBase *dev = (wxPLDevBase *) pls->dev;
- PLGraphicsIn *gin = &( dev->gin );
- // Initialize
- plGinInit( gin );
- dev->locate_mode = LOCATE_INVOKED_VIA_API;
- dev->draw_xhair = true;
- // Run event loop until a point is selected
- wxRunApp( pls, false );
- *ptr = *gin;
- if ( dev->locate_mode )
- {
- dev->locate_mode = 0;
- dev->draw_xhair = false;
- }
- }
- //--------------------------------------------------------------------------
- // This part includes wxWidgets specific functions, which allow to
- // open a window from the command line, if needed.
- //--------------------------------------------------------------------------
- //--------------------------------------------------------------------------
- // void install_buffer( PLStream *pls )
- //
- // If this driver is called from a command line executable (and not
- // from within a wxWidgets program), this function prepares a DC and a
- // bitmap to plot into.
- //--------------------------------------------------------------------------
- static void install_buffer( PLStream *pls )
- {
- // Log_Verbose( "install_buffer" );
- wxPLDevBase * dev = (wxPLDevBase *) pls->dev;
- static bool initApp = false;
- if ( !initApp )
- {
- // this hack enables to have a GUI on Mac OSX even if the
- // program was called from the command line (and isn't a bundle)
- #ifdef __WXMAC__
- ProcessSerialNumber psn;
- GetCurrentProcess( &psn );
- CPSEnableForegroundOperation( &psn );
- SetFrontProcess( &psn );
- #endif
- // initialize wxWidgets
- wxInitialize();
- wxLog::GetActiveTarget();
- wxTRY {
- wxPLGetApp().CallOnInit();
- }
- wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit( "Can't init wxWidgets!" ); )
- initApp = true;
- }
- wxString title( pls->plwindow, *wxConvCurrent );
- switch ( dev->backend )
- {
- case wxBACKEND_DC:
- title += wxT( " - wxWidgets (basic)" );
- break;
- case wxBACKEND_GC:
- title += wxT( " - wxWidgets (wxGC)" );
- break;
- case wxBACKEND_AGG:
- title += wxT( " - wxWidgets (AGG)" );
- break;
- default:
- break;
- }
- dev->m_frame = new wxPLplotFrame( title, pls );
- wxPLGetApp().AddFrame( dev->m_frame );
- // set size and position of window
- dev->m_frame->SetClientSize( dev->width, dev->height );
- if ( dev->xpos != 0 || dev->ypos != 0 )
- dev->m_frame->SetSize( dev->xpos, dev->ypos,
- wxDefaultCoord, wxDefaultCoord,
- wxSIZE_USE_EXISTING );
- if ( dev->showGUI )
- {
- dev->m_frame->Show( true );
- dev->m_frame->Raise();
- }
- else
- dev->m_frame->Show( false );
- // get a DC and a bitmap or an imagebuffer
- dev->ownGUI = true;
- dev->bm_width = dev->width;
- dev->bm_height = dev->height;
- dev->CreateCanvas();
- dev->ready = true;
- // Set wx error handler for various errors in plplot
- plsexit( plD_errorexithandler_wxwidgets );
- plsabort( plD_erroraborthandler_wxwidgets );
- // replay command we may have missed
- plD_bop_wxwidgets( pls );
- }
- //--------------------------------------------------------------------------
- // void wxRunApp( PLStream *pls, bool runonce )
- //
- // This is a hacked wxEntry-function, so that wxUninitialize is not
- // called twice. Here we actually start the wxApplication.
- //--------------------------------------------------------------------------
- static void wxRunApp( PLStream *pls, bool runonce )
- {
- // Log_Verbose( "wxRunApp" );
- wxPLDevBase* dev = (wxPLDevBase *) pls->dev;
- dev->waiting = true;
- wxTRY
- {
- class CallOnExit
- {
- public:
- // only call OnExit if exit is true (i.e. due an exception)
- ~CallOnExit() { if ( exit ) wxPLGetApp().OnExit();}
- bool exit;
- } callOnExit;
- callOnExit.exit = true;
- wxPLGetApp().SetAdvanceFlag( runonce );
- wxPLGetApp().SetRefreshFlag();
- // add an idle event is necessary for Linux (wxGTK2)
- // but not for Windows, but it doesn't harm
- wxIdleEvent event;
- wxPLGetApp().AddPendingEvent( event );
- wxPLGetApp().OnRun(); // start wxWidgets application
- callOnExit.exit = false;
- }
- wxCATCH_ALL( wxPLGetApp().OnUnhandledException(); plexit( "Problem running wxWidgets!" ); )
- if ( dev->exit )
- {
- wxPLGetApp().OnExit();
- plexit( "" );
- }
- dev->waiting = false;
- }