PLplot  5.11.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
wingcc.c
Go to the documentation of this file.
1 // PLplot WIN32 under GCC device driver.
2 //
3 // Copyright (C) 2004 Andrew Roach
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 //
22 #include "plDevs.h"
23 
24 #ifdef PLD_wingcc
25 
26 #include <string.h>
27 #include <windows.h>
28 #if !defined ( __CYGWIN__ )
29 #include <tchar.h>
30 #else
31 #include <winnt.h>
32 #define _T( a ) __TEXT( a )
33 #endif
34 #ifdef _WIN64
35 #define GWL_USERDATA GWLP_USERDATA
36 #define GCL_HCURSOR GCLP_HCURSOR
37 #endif
38 
39 #include "plplotP.h"
40 #include "drivers.h"
41 #include "plevent.h"
42 
43 #ifdef PL_HAVE_FREETYPE
44 
45 //
46 // Freetype support has been added to the wingcc driver using the
47 // plfreetype.c module, and implemented as a driver-specific optional extra
48 // invoked via the -drvopt command line toggle. It uses the
49 // "PLESC_HAS_TEXT" command for rendering within the driver.
50 //
51 // Freetype support is turned on/off at compile time by defining
52 // "PL_HAVE_FREETYPE".
53 //
54 // To give the user some level of control over the fonts that are used,
55 // environmental variables can be set to over-ride the definitions used by
56 // the five default plplot fonts.
57 //
58 // Freetype rendering is used with the command line "-drvopt text".
59 // Anti-aliased fonts can be used by issuing "-drvopt text,smooth"
60 //
61 
62 #include "plfreetype.h"
63 
64 #ifndef max_number_of_grey_levels_used_in_text_smoothing
65 #define max_number_of_grey_levels_used_in_text_smoothing 64
66 #endif
67 
68 #endif
69 
70 
71 // Device info
72 
73 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_wingcc = "wingcc:Win32 (GCC):1:wingcc:9:wingcc\n";
74 
75 // Struct to hold device-specific info.
76 
77 typedef struct
78 {
79  PLFLT scale; // scaling factor to "blow up" to the "virtual" page in removing hidden lines
80  PLINT width; // Window width (which can change)
81  PLINT height; // Window Height
82 
83  PLFLT PRNT_scale;
84  PLINT PRNT_width;
85  PLINT PRNT_height;
86 
87  PLGraphicsIn gin;
88 
89  char FT_smooth_text;
90 //
91 // WIN32 API variables
92 //
93 
94  COLORREF colour; // Current Colour
95  COLORREF oldcolour; // Used for high-speed background erasing
96  MSG msg; // A Win32 message structure.
97  WNDCLASSEX wndclass; // An extended window class structure.
98  HWND hwnd; // Handle for the main window.
99  HPEN pen; // Windows pen used for drawing
100  HDC hdc; // Driver Context
101  HDC hdc2; // Driver Context II - used for Blitting
102  HDC SCRN_hdc; // The screen's context
103  HDC PRNT_hdc; // used for printing
104  PAINTSTRUCT ps; // used to paint the client area of a window owned by that application
105  RECT rect; // defines the coordinates of the upper-left and lower-right corners of a rectangle
106  RECT oldrect; // used for re-sizing comparisons
107  RECT paintrect; // used for painting etc...
108  HBRUSH fillbrush; // brush used for fills
109  HCURSOR cursor; // Current windows cursor for this window
110  HBITMAP bitmap; // Bitmap of current display; used for fast redraws via blitting
111  HGDIOBJ oldobject; // Used for tracking objects probably not really needed but
112  HMENU PopupMenu;
113 
114  PLINT draw_mode;
115  char truecolour; // Flag to indicate 24 bit mode
116  char waiting; // Flag to indicate drawing is done, and it is waiting;
117  // we only do a windows redraw if plplot is plotting
118  char enterresize; // Used to keep track of reszing messages from windows
119  char already_erased; // Used to track first and only first backgroudn erases
120 
121  struct wingcc_Dev *push; // A copy of the entire structure used when printing
122  // We push and pop it off a virtual stack
123 } wingcc_Dev;
124 
125 
127 
128 void plD_init_wingcc( PLStream * );
129 void plD_line_wingcc( PLStream *, short, short, short, short );
130 void plD_polyline_wingcc( PLStream *, short *, short *, PLINT );
131 void plD_eop_wingcc( PLStream * );
132 void plD_bop_wingcc( PLStream * );
133 void plD_tidy_wingcc( PLStream * );
134 void plD_wait_wingcc( PLStream * );
135 void plD_state_wingcc( PLStream *, PLINT );
136 void plD_esc_wingcc( PLStream *, PLINT, void * );
137 
138 #ifdef PL_HAVE_FREETYPE
139 
140 static void plD_pixel_wingcc( PLStream *pls, short x, short y );
141 static void plD_pixelV_wingcc( PLStream *pls, short x, short y );
142 static PLINT plD_read_pixel_wingcc( PLStream *pls, short x, short y );
143 static void plD_set_pixel_wingcc( PLStream *pls, short x, short y, PLINT colour );
144 static void plD_set_pixelV_wingcc( PLStream *pls, short x, short y, PLINT colour );
145 static void init_freetype_lv1( PLStream *pls );
146 static void init_freetype_lv2( PLStream *pls );
147 
148 #endif
149 
150 
151 //--------------------------------------------------------------------------
152 // Local Function definitions and function-like defines
153 //--------------------------------------------------------------------------
154 
155 static int GetRegValue( TCHAR *key_name, TCHAR *key_word, char *buffer, int size );
156 static int SetRegValue( TCHAR *key_name, TCHAR *key_word, char *buffer, int dwType, int size );
157 static void Resize( PLStream *pls );
158 static void plD_fill_polygon_wingcc( PLStream *pls );
159 static void CopySCRtoBMP( PLStream *pls );
160 static void PrintPage( PLStream *pls );
161 static void UpdatePageMetrics( PLStream *pls, char flag );
162 
163 #define SetRegStringValue( a, b, c ) SetRegValue( a, b, c, REG_SZ, strlen( c ) + 1 )
164 #define SetRegBinaryValue( a, b, c, d ) SetRegValue( a, b, (char *) c, REG_BINARY, d )
165 #define SetRegIntValue( a, b, c ) SetRegValue( a, b, (char *) c, REG_DWORD, 4 )
166 #define GetRegStringValue( a, b, c, d ) GetRegValue( a, b, c, d )
167 #define GetRegIntValue( a, b, c ) GetRegValue( a, b, (char *) c, 4 )
168 #define GetRegBinaryValue( a, b, c, d ) GetRegValue( a, b, (char *) c, d )
169 
170 //--------------------------------------------------------------------------
171 // Some debugging macros
172 //--------------------------------------------------------------------------
173 
174 #if defined ( _MSC_VER )
175  #define Debug( a ) do { if ( pls->debug ) { fprintf( stderr, ( a ) ); } } while ( 0 )
176  #define Debug2( a, b ) do { if ( pls->debug ) { fprintf( stderr, ( a ), ( b ) ); } } while ( 0 )
177  #define Debug3( a, b, c ) do { if ( pls->debug ) { fprintf( stderr, ( a ), ( b ), ( c ) ); } } while ( 0 )
178 #elif defined ( __BORLANDC__ )
179  #define Debug if ( pls->debug ) printf
180  #define Debug2 if ( pls->debug ) printf
181  #define Debug3 if ( pls->debug ) printf
182 #else
183  #define Verbose( ... ) do { if ( pls->verbose ) { fprintf( stderr, __VA_ARGS__ ); } } while ( 0 )
184  #define Debug( ... ) do { if ( pls->debug ) { fprintf( stderr, __VA_ARGS__ ); } } while ( 0 )
185  #define Debug2( ... ) do { if ( pls->debug ) { fprintf( stderr, __VA_ARGS__ ); } } while ( 0 )
186  #define Debug3( ... ) do { if ( pls->debug ) { fprintf( stderr, __VA_ARGS__ ); } } while ( 0 )
187 #endif
188 
189 #define ReportWinError() do { \
190  LPVOID lpMsgBuf; \
191  FormatMessage( \
192  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, \
193  NULL, GetLastError(), \
194  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPTSTR) &lpMsgBuf, 0, NULL ); \
195  MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK | MB_ICONINFORMATION ); \
196  LocalFree( lpMsgBuf ); } while ( 0 )
197 
198 #define CrossHairCursor() do { \
199  dev->cursor = LoadCursor( NULL, IDC_CROSS ); \
200  SetClassLong( dev->hwnd, GCL_HCURSOR, (long) dev->cursor ); \
201  SetCursor( dev->cursor ); } while ( 0 )
202 
203 #define NormalCursor() do { \
204  dev->cursor = LoadCursor( NULL, IDC_ARROW ); \
205  SetClassLongPtr( dev->hwnd, GCL_HCURSOR, (LONG_PTR) dev->cursor ); \
206  SetCursor( dev->cursor ); } while ( 0 )
207 
208 #define BusyCursor() do { \
209  dev->cursor = LoadCursor( NULL, IDC_WAIT ); \
210  SetClassLongPtr( dev->hwnd, GCL_HCURSOR, (LONG_PTR) dev->cursor ); \
211  SetCursor( dev->cursor ); } while ( 0 )
212 
213 #define PopupPrint 0x08A1
214 #define PopupNextPage 0x08A2
215 #define PopupQuit 0x08A3
216 
217 
219 {
220 #ifndef ENABLE_DYNDRIVERS
221  pdt->pl_MenuStr = "Win32 GCC device";
222  pdt->pl_DevName = "wingcc";
223 #endif
225  pdt->pl_seq = 9;
226  pdt->pl_init = (plD_init_fp) plD_init_wingcc;
227  pdt->pl_line = (plD_line_fp) plD_line_wingcc;
228  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_wingcc;
229  pdt->pl_eop = (plD_eop_fp) plD_eop_wingcc;
230  pdt->pl_bop = (plD_bop_fp) plD_bop_wingcc;
231  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wingcc;
232  pdt->pl_state = (plD_state_fp) plD_state_wingcc;
233  pdt->pl_esc = (plD_esc_fp) plD_esc_wingcc;
234  pdt->pl_wait = (plD_wait_fp) plD_wait_wingcc;
235 }
236 
237 static TCHAR* szWndClass = _T( "PlplotWin" );
238 
239 
240 //--------------------------------------------------------------------------
241 // This is the window function for the plot window. Whenever a message is
242 // dispatched using DispatchMessage (or sent with SendMessage) this function
243 // gets called with the contents of the message.
244 //--------------------------------------------------------------------------
245 
246 LRESULT CALLBACK PlplotWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
247 {
248  PLStream *pls = NULL;
249  wingcc_Dev *dev = NULL;
250 
251 //
252 // The window carries a 32bit user defined pointer which points to the
253 // plplot stream (pls). This is used for tracking the window.
254 // Unfortunately, this is "attached" to the window AFTER it is created
255 // so we can not initialise PLStream or wingcc_Dev "blindly" because
256 // they may not yet have been initialised.
257 // WM_CREATE is called before we get to initialise those variables, so
258 // we wont try to set them.
259 //
260 
261  if ( nMsg == WM_CREATE )
262  {
263  return ( 0 );
264  }
265  else
266  {
267 #ifndef _WIN64
268 #undef GetWindowLongPtr
269 #define GetWindowLongPtr GetWindowLong
270 #endif
271  pls = (PLStream *) GetWindowLongPtr( hwnd, GWL_USERDATA ); // Try to get the address to pls for this window
272  if ( pls ) // If we got it, then we will initialise this windows plplot private data area
273  {
274  dev = (wingcc_Dev *) pls->dev;
275  }
276  }
277 
278 //
279 // Process the windows messages
280 //
281 // Everything except WM_CREATE is done here and it is generally hoped that
282 // pls and dev are defined already by this stage.
283 // That will be true MOST of the time. Some times WM_PAINT will be called
284 // before we get to initialise the user data area of the window with the
285 // pointer to the windows plplot stream
286 //
287 
288  switch ( nMsg )
289  {
290  case WM_DESTROY:
291  if ( dev )
292  Debug( "WM_DESTROY\t" );
293  PostQuitMessage( 0 );
294  return ( 0 );
295  break;
296 
297  case WM_PAINT:
298  if ( dev )
299  {
300  Debug( "WM_PAINT\t" );
301  if ( GetUpdateRect( dev->hwnd, &dev->paintrect, TRUE ) )
302  {
303  BusyCursor();
304  BeginPaint( dev->hwnd, &dev->ps );
305 
306  if ( ( dev->waiting == 1 ) && ( dev->already_erased == 1 ) )
307  {
308  Debug( "Remaking\t" );
309 
310  if ( dev->ps.fErase )
311  {
312  dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
313  ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, _T( "" ), 0, 0 );
314  SetBkColor( dev->hdc, dev->oldcolour );
315  }
316 
317  plRemakePlot( pls );
318  CopySCRtoBMP( pls );
319  dev->already_erased++;
320  }
321  else if ( ( dev->waiting == 1 ) && ( dev->already_erased == 2 ) )
322  {
323  dev->oldobject = SelectObject( dev->hdc2, dev->bitmap );
324  BitBlt( dev->hdc, dev->paintrect.left, dev->paintrect.top,
325  dev->paintrect.right, dev->paintrect.bottom,
326  dev->hdc2, dev->paintrect.left, dev->paintrect.top, SRCCOPY );
327  SelectObject( dev->hdc2, dev->oldobject );
328  }
329 
330  EndPaint( dev->hwnd, &dev->ps );
331  NormalCursor();
332  return ( 0 );
333  }
334  }
335  return ( 1 );
336  break;
337 
338  case WM_SIZE:
339  if ( dev )
340  {
341  Debug( "WM_SIZE\t" );
342 
343  if ( dev->enterresize == 0 )
344  Resize( pls );
345  }
346  return ( 0 );
347  break;
348 
349  case WM_ENTERSIZEMOVE:
350  if ( dev )
351  {
352  Debug( "WM_ENTERSIZEMOVE\t" );
353  dev->enterresize = 1;
354  }
355  return ( 0 );
356  break;
357 
358 
359  case WM_EXITSIZEMOVE:
360  if ( dev )
361  {
362  Debug( "WM_EXITSIZEMOVE\t" );
363  Resize( pls );
364  dev->enterresize = 0; // Reset the variables that track sizing ops
365  }
366  return ( 0 );
367  break;
368 
369  case WM_ERASEBKGND:
370 
371  if ( dev )
372  {
373  if ( dev->already_erased == 0 )
374  {
375  Debug( "WM_ERASEBKGND\t" );
376 
377  //
378  // This is a new "High Speed" way of filling in the background.
379  // supposidely this executes faster than creating a brush and
380  // filling a rectangle - go figure ?
381  //
382 
383  dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
384  ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, _T( "" ), 0, 0 );
385  SetBkColor( dev->hdc, dev->oldcolour );
386 
387  dev->already_erased = 1;
388  return ( 1 );
389  }
390  }
391  return ( 0 );
392  break;
393 
394  case WM_COMMAND:
395  if ( dev )
396  Debug( "WM_COMMAND\t" );
397  return ( 0 );
398  break;
399  }
400 
401  // If we don't handle a message completely we hand it to the system
402  // provided default window function.
403  return DefWindowProc( hwnd, nMsg, wParam, lParam );
404 }
405 
406 
407 //--------------------------------------------------------------------------
408 // plD_init_wingcc()
409 //
410 // Initialize device (terminal).
411 //--------------------------------------------------------------------------
412 
413 void
414 plD_init_wingcc( PLStream *pls )
415 {
416  wingcc_Dev *dev;
417 
418 #ifdef PL_HAVE_FREETYPE
419  static int freetype = 0;
420  static int smooth_text = 0;
421  static int save_reg = 0;
422  FT_Data *FT;
423 
424 //
425 // Variables used for reading the registary keys
426 // might eventually add a user defined pallette here, but for now it just does freetype
427 //
428  TCHAR key_name[] = _T( "Software\\PLplot\\wingcc" );
429  TCHAR Keyword_text[] = _T( "freetype" );
430  TCHAR Keyword_smooth[] = _T( "smooth" );
431 #endif
432 
433  DrvOpt wingcc_options[] = {
434 #ifdef PL_HAVE_FREETYPE
435  { "text", DRV_INT, &freetype, "Use driver text (FreeType)" },
436  { "smooth", DRV_INT, &smooth_text, "Turn text smoothing on (1) or off (0)" },
437  { "save", DRV_INT, &save_reg, "Save defaults to registary" },
438 
439 #endif
440  { NULL, DRV_INT, NULL, NULL }
441  };
442 
443 //
444 // Variable for storing the program name
445 //
446  TCHAR *program;
447  int programlength;
448 
449 // Allocate and initialize device-specific data
450 
451  if ( pls->dev != NULL )
452  free( (void *) pls->dev );
453 
454  pls->dev = calloc( 1, (size_t) sizeof ( wingcc_Dev ) );
455  if ( pls->dev == NULL )
456  plexit( "plD_init_wingcc_Dev: Out of memory." );
457 
458  dev = (wingcc_Dev *) pls->dev;
459 
460  pls->icol0 = 1; // Set a fall back pen colour in case user doesn't
461 
462  pls->termin = 1; // interactive device
463  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)
464  pls->dev_fill0 = 1; // driver can do solid area fills
465  pls->dev_xor = 1; // driver supports xor mode
466  pls->dev_clear = 0; // driver does not support clear - what is the proper API?
467  pls->dev_dash = 0; // driver can not do dashed lines (yet)
468  pls->plbuf_write = 1; // driver uses the buffer for redraws
469 
470  if ( !pls->colorset )
471  pls->color = 1;
472 
473 
474 #ifdef PL_HAVE_FREETYPE
475 
476 //
477 // Read registry to see if the user has set up default values
478 // for text and smoothing. These will be overriden by anything that
479 // might be given on the command line, so we will load the
480 // values right into the same memory slots we pass to plParseDrvOpts
481 //
482 
483  GetRegIntValue( key_name, Keyword_text, &freetype );
484  GetRegIntValue( key_name, Keyword_smooth, &smooth_text );
485 
486 #endif
487 
488 // Check for and set up driver options
489 
490  plParseDrvOpts( wingcc_options );
491 
492 #ifdef PL_HAVE_FREETYPE
493 
494 //
495 // We will now save the settings to the registary if the user wants
496 //
497 
498  if ( save_reg == 1 )
499  {
500  SetRegIntValue( key_name, Keyword_text, &freetype );
501  SetRegIntValue( key_name, Keyword_smooth, &smooth_text );
502  }
503 
504 #endif
505 
506 // Set up device parameters
507 
508  if ( pls->xlength <= 0 || pls->ylength <= 0 )
509  {
510  // use default width, height of 800x600 if not specifed by -geometry option
511  // or plspage
512  plspage( 0., 0., 800, 600, 0, 0 );
513  }
514 
515  dev->width = pls->xlength - 1; // should I use -1 or not???
516  dev->height = pls->ylength - 1;
517 
518 //
519 // Begin initialising the window
520 //
521 
522  // Initialize the entire structure to zero.
523  memset( &dev->wndclass, 0, sizeof ( WNDCLASSEX ) );
524 
525  // This class is called WinTestWin
526  dev->wndclass.lpszClassName = szWndClass;
527 
528  // cbSize gives the size of the structure for extensibility.
529  dev->wndclass.cbSize = sizeof ( WNDCLASSEX );
530 
531  // All windows of this class redraw when resized.
532  dev->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
533 
534  // All windows of this class use the WndProc window function.
535  dev->wndclass.lpfnWndProc = PlplotWndProc;
536 
537  // This class is used with the current program instance.
538 
539  dev->wndclass.hInstance = GetModuleHandle( NULL );
540 
541  // Use standard application icon and arrow cursor provided by the OS
542  dev->wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
543  dev->wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
544  dev->wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
545  // Color the background white
546  dev->wndclass.hbrBackground = NULL;
547 
548  dev->wndclass.cbWndExtra = sizeof ( pls );
549 
550 
551  //
552  // Now register the window class for use.
553  //
554 
555  RegisterClassEx( &dev->wndclass );
556 
557  //
558  //convert the program name to wide char if needed
559  //
560 
561 #ifdef UNICODE
562  printf( pls->program );
563  programlength = strlen( pls->program ) + 1;
564  program = malloc( programlength * sizeof ( TCHAR ) );
565  MultiByteToWideChar( CP_UTF8, 0, pls->program, programlength, program, programlength );
566 #else
567  program = pls->program;
568 #endif
569  //
570  // Create our main window using that window class.
571  //
572  dev->hwnd = CreateWindowEx( WS_EX_WINDOWEDGE + WS_EX_LEFT,
573  szWndClass, // Class name
574  program, // Caption
575  WS_OVERLAPPEDWINDOW, // Style
576  pls->xoffset, // Initial x (use default)
577  pls->yoffset, // Initial y (use default)
578  pls->xlength, // Initial x size (use default)
579  pls->ylength, // Initial y size (use default)
580  NULL, // No parent window
581  NULL, // No menu
582  dev->wndclass.hInstance, // This program instance
583  NULL // Creation parameters
584  );
585 
586 #ifdef UNICODE
587  free( program );
588 #endif
589 
590 //
591 // Attach a pointer to the stream to the window's user area
592 // this pointer will be used by the windows call back for
593 // process this window
594 //
595 
596 #ifdef _WIN64
597  SetWindowLongPtr( dev->hwnd, GWL_USERDATA, (LONG_PTR) pls );
598 #else
599  SetWindowLong( dev->hwnd, GWL_USERDATA, (LONG) pls );
600 #endif
601 
602  dev->SCRN_hdc = dev->hdc = GetDC( dev->hwnd );
603 
604 //
605 // Setup the popup menu
606 //
607 
608  dev->PopupMenu = CreatePopupMenu();
609  AppendMenu( dev->PopupMenu, MF_STRING, PopupPrint, _T( "Print" ) );
610  AppendMenu( dev->PopupMenu, MF_STRING, PopupNextPage, _T( "Next Page" ) );
611  AppendMenu( dev->PopupMenu, MF_STRING, PopupQuit, _T( "Quit" ) );
612 
613 #ifdef PL_HAVE_FREETYPE
614 
615  if ( freetype )
616  {
617  pls->dev_text = 1; // want to draw text
618  pls->dev_unicode = 1; // want unicode
619  init_freetype_lv1( pls );
620  FT = (FT_Data *) pls->FT;
621  FT->want_smooth_text = smooth_text;
622  }
623 
624 #endif
625 
626 
627 
628  plD_state_wingcc( pls, PLSTATE_COLOR0 );
629  //
630  // Display the window which we just created (using the nShow
631  // passed by the OS, which allows for start minimized and that
632  // sort of thing).
633  //
634  ShowWindow( dev->hwnd, SW_SHOWDEFAULT );
635  SetForegroundWindow( dev->hwnd );
636 
637  //
638  // Set up the DPI etc...
639  //
640 
641 
642  if ( pls->xdpi <= 0 ) // Get DPI from windows
643  {
644  plspage( GetDeviceCaps( dev->hdc, HORZRES ) / GetDeviceCaps( dev->hdc, HORZSIZE ) * 25.4,
645  GetDeviceCaps( dev->hdc, VERTRES ) / GetDeviceCaps( dev->hdc, VERTSIZE ) * 25.4, 0, 0, 0, 0 );
646  }
647  else
648  {
649  pls->ydpi = pls->xdpi; // Set X and Y dpi's to the same value
650  }
651 
652 
653 //
654 // Now we have to find out, from windows, just how big our drawing area is
655 // when we specified the page size earlier on, that includes the borders,
656 // title bar etc... so now that windows has done all its initialisations,
657 // we will ask how big the drawing area is, and tell plplot
658 //
659 
660  GetClientRect( dev->hwnd, &dev->rect );
661  dev->width = dev->rect.right;
662  dev->height = dev->rect.bottom;
663 
664  if ( dev->width > dev->height ) // Work out the scaling factor for the
665  { // "virtual" (oversized) page
666  dev->scale = (PLFLT) ( PIXELS_X - 1 ) / dev->width;
667  }
668  else
669  {
670  dev->scale = (PLFLT) PIXELS_Y / dev->height;
671  }
672 
673  Debug2( "Scale = %f (FLT)\n", dev->scale );
674 
675  plP_setpxl( dev->scale * pls->xdpi / 25.4, dev->scale * pls->ydpi / 25.4 );
676  plP_setphy( 0, (PLINT) ( dev->scale * dev->width ), 0, (PLINT) ( dev->scale * dev->height ) );
677 
678  // Set fill rule.
679  if ( pls->dev_eofill )
680  SetPolyFillMode( dev->hdc, ALTERNATE );
681  else
682  SetPolyFillMode( dev->hdc, WINDING );
683 
684 #ifdef PL_HAVE_FREETYPE
685  if ( pls->dev_text )
686  {
687  init_freetype_lv2( pls );
688  }
689 #endif
690 }
691 
692 //--------------------------------------------------------------------------
693 // plD_line_wingcc()
694 //
695 // Draw a line in the current color from (x1,y1) to (x2,y2).
696 //--------------------------------------------------------------------------
697 
698 void
699 plD_line_wingcc( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
700 {
701  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
702  POINT points[2];
703 
704 
705  points[0].x = (LONG) ( x1a / dev->scale );
706  points[1].x = (LONG) ( x2a / dev->scale );
707  points[0].y = (LONG) ( dev->height - ( y1a / dev->scale ) );
708  points[1].y = (LONG) ( dev->height - ( y2a / dev->scale ) );
709 
710  dev->oldobject = SelectObject( dev->hdc, dev->pen );
711 
712  if ( points[0].x != points[1].x || points[0].y != points[1].y )
713  {
714  Polyline( dev->hdc, points, 2 );
715  }
716  else
717  {
718  SetPixel( dev->hdc, points[0].x, points[0].y, dev->colour );
719  }
720  SelectObject( dev->hdc, dev->oldobject );
721 }
722 
723 
724 //--------------------------------------------------------------------------
725 // plD_polyline_wingcc()
726 //
727 // Draw a polyline in the current color.
728 //--------------------------------------------------------------------------
729 
730 void
731 plD_polyline_wingcc( PLStream *pls, short *xa, short *ya, PLINT npts )
732 {
733  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
734  int i;
735  POINT *points = NULL;
736 
737  if ( npts > 0 )
738  {
739  points = GlobalAlloc( GMEM_ZEROINIT | GMEM_FIXED, (size_t) npts * sizeof ( POINT ) );
740  if ( points != NULL )
741  {
742  for ( i = 0; i < npts; i++ )
743  {
744  points[i].x = (LONG) ( xa[i] / dev->scale );
745  points[i].y = (LONG) ( dev->height - ( ya[i] / dev->scale ) );
746  }
747  dev->oldobject = SelectObject( dev->hdc, dev->pen );
748  Polyline( dev->hdc, points, npts );
749  SelectObject( dev->hdc, dev->oldobject );
750  GlobalFree( points );
751  }
752  else
753  {
754  plexit( "Could not allocate memory to \"plD_polyline_wingcc\"\n" );
755  }
756  }
757 }
758 
759 //--------------------------------------------------------------------------
760 // plD_fill_polygon_wingcc()
761 //
762 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
763 //--------------------------------------------------------------------------
764 
765 static void
766 plD_fill_polygon_wingcc( PLStream *pls )
767 {
768  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
769  int i;
770  POINT *points = NULL;
771  HPEN hpen, hpenOld;
772 
773  if ( pls->dev_npts > 0 )
774  {
775  points = GlobalAlloc( GMEM_ZEROINIT, (size_t) pls->dev_npts * sizeof ( POINT ) );
776 
777  if ( points == NULL )
778  plexit( "Could not allocate memory to \"plD_fill_polygon_wingcc\"\n" );
779 
780  for ( i = 0; i < pls->dev_npts; i++ )
781  {
782  points[i].x = (PLINT) ( pls->dev_x[i] / dev->scale );
783  points[i].y = (PLINT) ( dev->height - ( pls->dev_y[i] / dev->scale ) );
784  }
785 
786  dev->fillbrush = CreateSolidBrush( dev->colour );
787  hpen = CreatePen( PS_SOLID, 1, dev->colour );
788  dev->oldobject = SelectObject( dev->hdc, dev->fillbrush );
789  hpenOld = SelectObject( dev->hdc, hpen );
790  Polygon( dev->hdc, points, pls->dev_npts );
791  SelectObject( dev->hdc, dev->oldobject );
792  DeleteObject( dev->fillbrush );
793  SelectObject( dev->hdc, hpenOld );
794  DeleteObject( hpen );
795  GlobalFree( points );
796  }
797 }
798 
799 //--------------------------------------------------------------------------
800 // static void CopySCRtoBMP(PLStream *pls)
801 // Function copies the screen contents into a bitmap which is
802 // later used for fast redraws of the screen (when it gets corrupted)
803 // rather than remaking the plot from the plot buffer.
804 //--------------------------------------------------------------------------
805 
806 static void CopySCRtoBMP( PLStream *pls )
807 {
808  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
809 
810  //
811  // Clean up the old bitmap and DC
812  //
813 
814  if ( dev->hdc2 != NULL )
815  DeleteDC( dev->hdc2 );
816  if ( dev->bitmap != NULL )
817  DeleteObject( dev->bitmap );
818 
819  dev->hdc2 = CreateCompatibleDC( dev->hdc );
820  GetClientRect( dev->hwnd, &dev->rect );
821  dev->bitmap = CreateCompatibleBitmap( dev->hdc, dev->rect.right, dev->rect.bottom );
822  dev->oldobject = SelectObject( dev->hdc2, dev->bitmap );
823  BitBlt( dev->hdc2, 0, 0, dev->rect.right, dev->rect.bottom, dev->hdc, 0, 0, SRCCOPY );
824  SelectObject( dev->hdc2, dev->oldobject );
825 }
826 
827 
828 
829 void
830 plD_eop_wingcc( PLStream *pls )
831 {
832  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
833 
834  Debug( "End of the page\n" );
835  CopySCRtoBMP( pls );
836  dev->already_erased = 2;
837 
838  NormalCursor();
839 }
840 
841 //--------------------------------------------------------------------------
842 // Beginning of the new page
843 //--------------------------------------------------------------------------
844 void
845 plD_bop_wingcc( PLStream *pls )
846 {
847  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
848 #ifdef PL_HAVE_FREETYPE
849  FT_Data *FT = (FT_Data *) pls->FT;
850 #endif
851  Debug( "Start of Page\t" );
852 
853 //
854 // Turn the cursor to a busy sign, clear the page by "invalidating" it
855 // then reset the colours and pen width
856 //
857 
858  BusyCursor();
859  dev->already_erased = 0;
860  RedrawWindow( dev->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW );
861 
862  plD_state_wingcc( pls, PLSTATE_COLOR0 );
863 }
864 
865 void
866 plD_tidy_wingcc( PLStream *pls )
867 {
868  wingcc_Dev *dev = NULL;
869 
870 #ifdef PL_HAVE_FREETYPE
871  if ( pls->dev_text )
872  {
873  FT_Data *FT = (FT_Data *) pls->FT;
874  plscmap0n( FT->ncol0_org );
875  plD_FreeType_Destroy( pls );
876  }
877 #endif
878  Debug( "plD_tidy_wingcc" );
879 
880  if ( pls->dev != NULL )
881  {
882  dev = (wingcc_Dev *) pls->dev;
883 
884  DeleteMenu( dev->PopupMenu, PopupPrint, 0 );
885  DeleteMenu( dev->PopupMenu, PopupNextPage, 0 );
886  DeleteMenu( dev->PopupMenu, PopupQuit, 0 );
887  DestroyMenu( dev->PopupMenu );
888 
889  if ( dev->hdc2 != NULL )
890  DeleteDC( dev->hdc2 );
891  if ( dev->hdc != NULL )
892  ReleaseDC( dev->hwnd, dev->hdc );
893  if ( dev->bitmap != NULL )
894  DeleteObject( dev->bitmap );
895 
896  free_mem( pls->dev );
897  }
898 }
899 
900 void
901 plD_wait_wingcc( PLStream * pls )
902 {
903  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
904 
905  Debug( "Wait for user input\n" );
906 
907  dev->waiting = 1;
908  while ( dev->waiting == 1 && GetMessage( &dev->msg, NULL, 0, 0 ) )
909  {
910  TranslateMessage( &dev->msg );
911  switch ( (int) dev->msg.message )
912  {
913  case WM_RBUTTONDOWN:
914  case WM_CONTEXTMENU:
915  TrackPopupMenu( dev->PopupMenu, TPM_CENTERALIGN | TPM_RIGHTBUTTON, LOWORD( dev->msg.lParam ),
916  HIWORD( dev->msg.lParam ), 0, dev->hwnd, NULL );
917  break;
918 
919  case WM_CHAR:
920  if ( ( (TCHAR) ( dev->msg.wParam ) == 32 ) ||
921  ( (TCHAR) ( dev->msg.wParam ) == 13 ) )
922  {
923  dev->waiting = 0;
924  }
925  else if ( ( (TCHAR) ( dev->msg.wParam ) == 27 ) ||
926  ( (TCHAR) ( dev->msg.wParam ) == 'q' ) ||
927  ( (TCHAR) ( dev->msg.wParam ) == 'Q' ) )
928  {
929  dev->waiting = 0;
930  PostQuitMessage( 0 );
931  }
932  break;
933 
934  case WM_LBUTTONDBLCLK:
935  Debug( "WM_LBUTTONDBLCLK\t" );
936  dev->waiting = 0;
937  break;
938 
939  case WM_COMMAND:
940  switch ( LOWORD( dev->msg.wParam ) )
941  {
942  case PopupPrint:
943  Debug( "PopupPrint" );
944  PrintPage( pls );
945  break;
946  case PopupNextPage:
947  Debug( "PopupNextPage" );
948  dev->waiting = 0;
949  break;
950  case PopupQuit:
951  Debug( "PopupQuit" );
952  dev->waiting = 0;
953  PostQuitMessage( 0 );
954  break;
955  }
956  break;
957 
958  default:
959  DispatchMessage( &dev->msg );
960  break;
961  }
962  }
963 }
964 
965 
966 //--------------------------------------------------------------------------
967 // plD_state_wingcc()
968 //
969 // Handle change in PLStream state (color, pen width, fill attribute, etc).
970 //--------------------------------------------------------------------------
971 
972 void
973 plD_state_wingcc( PLStream *pls, PLINT op )
974 {
975  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
976 
977  switch ( op )
978  {
979  case PLSTATE_COLOR0:
980  case PLSTATE_COLOR1:
981  dev->colour = RGB( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b );
982  break;
983 
984  case PLSTATE_CMAP0:
985  case PLSTATE_CMAP1:
986  dev->colour = RGB( pls->curcolor.r, pls->curcolor.g, pls->curcolor.b );
987  break;
988  }
989 
990  if ( dev->pen != NULL )
991  DeleteObject( dev->pen );
992  dev->pen = CreatePen( PS_SOLID, pls->width, dev->colour );
993 }
994 
995 //--------------------------------------------------------------------------
996 // GetCursorCmd()
997 //
998 // Handle events connected to selecting points (modelled after xwin)
999 //--------------------------------------------------------------------------
1000 
1001 static void
1002 GetCursorCmd( PLStream *pls, PLGraphicsIn *gin )
1003 {
1004  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1005 
1006  HCURSOR crosshair;
1007  HCURSOR previous;
1008 
1009  plGinInit( gin );
1010 
1011  crosshair = LoadCursor( GetModuleHandle( NULL ), IDC_CROSS );
1012  previous = SetCursor( crosshair );
1013 
1014  while ( gin->pX < 0 )
1015  {
1016  GetMessage( &dev->msg, NULL, 0, 0 );
1017  TranslateMessage( &dev->msg );
1018  switch ( (int) dev->msg.message )
1019  {
1020  case WM_LBUTTONDOWN:
1021  if ( dev->msg.wParam & MK_LBUTTON )
1022  {
1023  gin->pX = dev->msg.pt.x;
1024  gin->pY = dev->msg.pt.y;
1025  gin->dX = (PLFLT) gin->pX / ( dev->width - 1 );
1026  gin->dY = 1.0 - (PLFLT) gin->pY / ( dev->height - 1 );
1027 
1028  gin->button = 1; // AM: there is no macro to indicate the pressed button!
1029  gin->state = 0; // AM: is there an equivalent under Windows?
1030  gin->keysym = 0x20;
1031  }
1032  break;
1033  case WM_CHAR:
1034  gin->pX = dev->msg.pt.x;
1035  gin->pY = dev->msg.pt.y;
1036  gin->dX = (PLFLT) gin->pX / ( dev->width - 1 );
1037  gin->dY = 1.0 - (PLFLT) gin->pY / ( dev->height - 1 );
1038 
1039  gin->button = 0;
1040  gin->state = 0;
1041  gin->keysym = dev->msg.wParam;
1042 
1043  break;
1044  }
1045  }
1046 
1047  // Restore the previous cursor
1048  SetCursor( previous );
1049 
1050 // if ( GetCursorPos(&p) )
1051 // {
1052 // if ( ScreenToClient( dev->hwnd, &p ) )
1053 // {
1054 // // Fill the fields, but actually we need to run the event loop
1055 // // We need to call GetMessage() in a loop. Unclear as yet to the
1056 // // actual interface: key/button presses?
1057 // }
1058 // }
1059 }
1060 
1061 //--------------------------------------------------------------------------
1062 // plD_esc_wingcc()
1063 //
1064 // Handle PLplot escapes
1065 //--------------------------------------------------------------------------
1066 
1067 void
1068 plD_esc_wingcc( PLStream *pls, PLINT op, void *ptr )
1069 {
1070  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1071  PLGraphicsIn *gin = &( dev->gin );
1072 
1073 
1074  switch ( op )
1075  {
1076  case PLESC_GETC:
1077  GetCursorCmd( pls, (PLGraphicsIn *) ptr );
1078  break;
1079 
1080  case PLESC_FILL:
1081  plD_fill_polygon_wingcc( pls );
1082  break;
1083 
1084  case PLESC_DOUBLEBUFFERING:
1085  break;
1086 
1087  case PLESC_XORMOD:
1088  if ( *(PLINT *) ( ptr ) == 0 )
1089  SetROP2( dev->hdc, R2_COPYPEN );
1090  else
1091  SetROP2( dev->hdc, R2_XORPEN );
1092  break;
1093 
1094 #ifdef PL_HAVE_FREETYPE
1095  case PLESC_HAS_TEXT:
1096  plD_render_freetype_text( pls, (EscText *) ptr );
1097  break;
1098 
1099 // case PLESC_LIKES_UNICODE:
1100 // plD_render_freetype_sym(pls, (EscText *)ptr);
1101 // break;
1102 
1103 #endif
1104  }
1105 }
1106 
1107 //--------------------------------------------------------------------------
1108 // static void Resize( PLStream *pls )
1109 //
1110 // This function calculates how to resize a window after a message has been
1111 // received from windows telling us the window has been changed.
1112 // It tries to recalculate the scale of the window so everything works out
1113 // just right.
1114 // The window is only resized if plplot has finished all of its plotting.
1115 // That means that if you resize while a picture is being plotted,
1116 // unpredictable results may result. The reason I do this is because the
1117 // resize function calls redraw window, which replays the whole plot.
1118 //--------------------------------------------------------------------------
1119 
1120 static void Resize( PLStream *pls )
1121 {
1122  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1123 #ifdef PL_HAVE_FREETYPE
1124  FT_Data *FT = (FT_Data *) pls->FT;
1125 #endif
1126  Debug( "Resizing" );
1127 
1128  if ( dev->waiting == 1 ) // Only resize the window IF plplot has finished with it
1129  {
1130  memcpy( &dev->oldrect, &dev->rect, sizeof ( RECT ) );
1131  GetClientRect( dev->hwnd, &dev->rect );
1132  Debug3( "[%d %d]", dev->rect.right, dev->rect.bottom );
1133 
1134  if ( ( dev->rect.right > 0 ) && ( dev->rect.bottom > 0 ) ) // Check to make sure it isn't just minimised (i.e. zero size)
1135  {
1136  if ( memcmp( &dev->rect, &dev->oldrect, sizeof ( RECT ) ) != 0 ) // See if the window's changed size or not
1137  {
1138  dev->already_erased = 0;
1139  dev->width = dev->rect.right;
1140  dev->height = dev->rect.bottom;
1141  if ( dev->width > dev->height ) // Work out the scaling factor for the
1142  { // "virtual" (oversized) page
1143  dev->scale = (PLFLT) ( PIXELS_X - 1 ) / dev->width;
1144  }
1145  else
1146  {
1147  dev->scale = (PLFLT) PIXELS_Y / dev->height;
1148  }
1149 
1150 #ifdef PL_HAVE_FREETYPE
1151  if ( FT )
1152  {
1153  FT->scale = dev->scale;
1154  FT->ymax = dev->height;
1155  }
1156 #endif
1157  }
1158  RedrawWindow( dev->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW );
1159  }
1160  else
1161  {
1162  memcpy( &dev->rect, &dev->oldrect, sizeof ( RECT ) ); // restore the old size to current size since the window is minimised
1163  }
1164  }
1165 }
1166 
1167 
1168 //--------------------------------------------------------------------------
1169 // int SetRegValue(char *key_name, char *key_word, char *buffer,int dwType, int size)
1170 //
1171 // Function set the registry; if registary entry does not exist, it is
1172 // created. Actually, the key is created before it is set just to make sure
1173 // that is is there !
1174 //--------------------------------------------------------------------------
1175 
1176 static int SetRegValue( TCHAR *key_name, TCHAR *key_word, char *buffer, int dwType, int size )
1177 {
1178  int j = 0;
1179 
1180  DWORD lpdwDisposition;
1181  HKEY hKey;
1182 
1183  j = RegCreateKeyEx(
1184  HKEY_CURRENT_USER,
1185  key_name,
1186  0, // reserved
1187  NULL, // address of class string
1188  REG_OPTION_NON_VOLATILE, // special options flag
1189  KEY_WRITE, // desired security access
1190  NULL, // address of key security structure
1191  &hKey, // address of buffer for opened handle
1192  &lpdwDisposition // address of disposition value buffer
1193  );
1194 
1195  if ( j == ERROR_SUCCESS )
1196  {
1197  RegSetValueEx( hKey, key_word, 0, dwType, buffer, size );
1198  RegCloseKey( hKey );
1199  }
1200  return ( j );
1201 }
1202 
1203 //--------------------------------------------------------------------------
1204 // int GetRegValue(char *key_name, char *key_word, char *buffer, int size)
1205 //
1206 // Function reads the registry and gets a string value from it
1207 // buffer must be allocated by the caller, and the size is given in the size
1208 // paramater.
1209 // Return code is 1 for success, and 0 for failure.
1210 //--------------------------------------------------------------------------
1211 
1212 static int GetRegValue( TCHAR *key_name, TCHAR *key_word, char *buffer, int size )
1213 {
1214  int ret = 0;
1215  HKEY hKey;
1216  int dwType;
1217  int dwSize = size;
1218 
1219  if ( RegOpenKeyEx( HKEY_CURRENT_USER, key_name, 0, KEY_READ, &hKey ) == ERROR_SUCCESS )
1220  {
1221  if ( RegQueryValueEx( hKey, key_word, 0, (LPDWORD) &dwType, buffer, (LPDWORD) &dwSize ) == ERROR_SUCCESS )
1222  {
1223  ret = 1;
1224  }
1225  RegCloseKey( hKey );
1226  }
1227  return ( ret );
1228 }
1229 
1230 #ifdef PL_HAVE_FREETYPE
1231 
1232 //--------------------------------------------------------------------------
1233 // void plD_pixel_wingcc (PLStream *pls, short x, short y)
1234 //
1235 // callback function, of type "plD_pixel_fp", which specifies how a single
1236 // pixel is set in the current colour.
1237 //--------------------------------------------------------------------------
1238 
1239 static void plD_pixel_wingcc( PLStream *pls, short x, short y )
1240 {
1241  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1242 
1243  SetPixel( dev->hdc, x, y, dev->colour );
1244 }
1245 
1246 static void plD_pixelV_wingcc( PLStream *pls, short x, short y )
1247 {
1248  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1249 
1250  SetPixelV( dev->hdc, x, y, dev->colour );
1251 }
1252 
1253 //--------------------------------------------------------------------------
1254 // void plD_set_pixelV_wingcc (PLStream *pls, short x, short y,PLINT colour)
1255 //
1256 // callback function, of type "plD_set_pixel_fp", which specifies how a
1257 // single pixel is set in the s[ecified colour. This colour
1258 // by-passes plplot's internal table, and directly 'hits the hardware'.
1259 //--------------------------------------------------------------------------
1260 
1261 static void plD_set_pixel_wingcc( PLStream *pls, short x, short y, PLINT colour )
1262 {
1263  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1264 
1265  SetPixel( dev->hdc, x, y, colour );
1266 }
1267 
1268 static void plD_set_pixelV_wingcc( PLStream *pls, short x, short y, PLINT colour )
1269 {
1270  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1271 
1272  SetPixelV( dev->hdc, x, y, colour );
1273 }
1274 
1275 
1276 //--------------------------------------------------------------------------
1277 // void plD_read_pixel_wingcc (PLStream *pls, short x, short y)
1278 //
1279 // callback function, of type "plD_pixel_fp", which specifies how a single
1280 // pixel is read.
1281 //--------------------------------------------------------------------------
1282 static PLINT plD_read_pixel_wingcc( PLStream *pls, short x, short y )
1283 {
1284  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1285 
1286  return ( GetPixel( dev->hdc, x, y ) );
1287 }
1288 
1289 
1290 //--------------------------------------------------------------------------
1291 // void init_freetype_lv1 (PLStream *pls)
1292 //
1293 // "level 1" initialisation of the freetype library.
1294 // "Level 1" initialisation calls plD_FreeType_init(pls) which allocates
1295 // memory to the pls->FT structure, then sets up the pixel callback
1296 // function.
1297 //--------------------------------------------------------------------------
1298 
1299 static void init_freetype_lv1( PLStream *pls )
1300 {
1301  FT_Data *FT;
1302  int x;
1303  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1304 
1305  plD_FreeType_init( pls );
1306 
1307  FT = (FT_Data *) pls->FT;
1308 
1309 
1310 
1311 //
1312 // Work out if our device support "fast" pixel setting
1313 // and if so, use that instead of "slow" pixel setting
1314 //
1315 
1316  x = GetDeviceCaps( dev->hdc, RASTERCAPS );
1317 
1318  if ( x & RC_BITBLT )
1319  FT->pixel = (plD_pixel_fp) plD_pixelV_wingcc;
1320  else
1321  FT->pixel = (plD_pixel_fp) plD_pixel_wingcc;
1322 
1323 //
1324 // See if we have a 24 bit device (or better), in which case
1325 // we can use the better antialaaising.
1326 //
1327 
1328  if ( GetDeviceCaps( dev->hdc, BITSPIXEL ) > 24 )
1329  {
1330  FT->BLENDED_ANTIALIASING = 1;
1331  FT->read_pixel = (plD_read_pixel_fp) plD_read_pixel_wingcc;
1332 
1333  if ( x & RC_BITBLT )
1334  FT->set_pixel = (plD_set_pixel_fp) plD_set_pixelV_wingcc;
1335  else
1336  FT->set_pixel = (plD_set_pixel_fp) plD_set_pixel_wingcc;
1337  }
1338 }
1339 
1340 //--------------------------------------------------------------------------
1341 // void init_freetype_lv2 (PLStream *pls)
1342 //
1343 // "Level 2" initialisation of the freetype library.
1344 // "Level 2" fills in a few setting that aren't public until after the
1345 // graphics sub-system has been initialised.
1346 // The "level 2" initialisation fills in a few things that are defined
1347 // later in the initialisation process for the GD driver.
1348 //
1349 // FT->scale is a scaling factor to convert co-ordinates. This is used by
1350 // the GD and other drivers to scale back a larger virtual page and this
1351 // eliminate the "hidden line removal bug". Set it to 1 if your device
1352 // doesn't have scaling.
1353 //
1354 // Some coordinate systems have zero on the bottom, others have zero on
1355 // the top. Freetype does it one way, and most everything else does it the
1356 // other. To make sure everything is working ok, we have to "flip" the
1357 // coordinates, and to do this we need to know how big in the Y dimension
1358 // the page is, and whether we have to invert the page or leave it alone.
1359 //
1360 // FT->ymax specifies the size of the page FT->invert_y=1 tells us to
1361 // invert the y-coordinates, FT->invert_y=0 will not invert the
1362 // coordinates.
1363 //--------------------------------------------------------------------------
1364 
1365 static void init_freetype_lv2( PLStream *pls )
1366 {
1367  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1368  FT_Data *FT = (FT_Data *) pls->FT;
1369 
1370  FT->scale = dev->scale;
1371  FT->ymax = dev->height;
1372  FT->invert_y = 1;
1373 
1374  if ( ( FT->want_smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) ) // do we want to at least *try* for smoothing ?
1375  {
1376  FT->ncol0_org = pls->ncol0; // save a copy of the original size of ncol0
1377  FT->ncol0_xtra = 16777216 - ( pls->ncol1 + pls->ncol0 ); // work out how many free slots we have
1378  FT->ncol0_width = max_number_of_grey_levels_used_in_text_smoothing; // find out how many different shades of anti-aliasing we can do
1379  FT->ncol0_width = max_number_of_grey_levels_used_in_text_smoothing; // set a maximum number of shades
1380  plscmap0n( FT->ncol0_org + ( FT->ncol0_width * pls->ncol0 ) ); // redefine the size of cmap0
1381 // the level manipulations are to turn off the plP_state(PLSTATE_CMAP0)
1382 // call in plscmap0 which (a) leads to segfaults since the GD image is
1383 // not defined at this point and (b) would be inefficient in any case since
1384 // setcmap is always called later (see plD_bop_png) to update the driver
1385 // color palette to be consistent with cmap0.
1386  {
1387  PLINT level_save;
1388  level_save = pls->level;
1389  pls->level = 0;
1390  pl_set_extended_cmap0( pls, FT->ncol0_width, FT->ncol0_org ); // call the function to add the extra cmap0 entries and calculate stuff
1391  pls->level = level_save;
1392  }
1393  FT->smooth_text = 1; // Yippee ! We had success setting up the extended cmap0
1394  }
1395  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
1396  {
1397  FT->smooth_text = 1;
1398  }
1399 }
1400 #endif
1401 
1402 //--------------------------------------------------------------------------
1403 // static void UpdatePageMetrics ( PLStream *pls, char flag )
1404 //
1405 // UpdatePageMetrics is a simple function which simply gets new vales for
1406 // a changed DC, be it swapping from printer to screen or vice-versa.
1407 // The flag variable is used to tell the function if it is updating
1408 // from the printer (1) or screen (0).
1409 //--------------------------------------------------------------------------
1410 
1411 static void UpdatePageMetrics( PLStream *pls, char flag )
1412 {
1413  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1414  #ifdef PL_HAVE_FREETYPE
1415  FT_Data *FT = (FT_Data *) pls->FT;
1416  #endif
1417 
1418  if ( flag == 1 )
1419  {
1420  dev->width = GetDeviceCaps( dev->hdc, HORZRES ); // Get the page size from the printer
1421  dev->height = GetDeviceCaps( dev->hdc, VERTRES );
1422  }
1423  else
1424  {
1425  GetClientRect( dev->hwnd, &dev->rect );
1426  dev->width = dev->rect.right;
1427  dev->height = dev->rect.bottom;
1428  }
1429 
1430  if ( dev->width > dev->height ) // Work out the scaling factor for the
1431  { // "virtual" (oversized) page
1432  dev->scale = (PLFLT) ( PIXELS_X - 1 ) / dev->width;
1433  }
1434  else
1435  {
1436  dev->scale = (PLFLT) PIXELS_Y / dev->height;
1437  }
1438 
1439  #ifdef PL_HAVE_FREETYPE
1440  if ( FT ) // If we are using freetype, then set it up next
1441  {
1442  FT->scale = dev->scale;
1443  FT->ymax = dev->height;
1444  if ( GetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_BITBLT )
1445  FT->pixel = (plD_pixel_fp) plD_pixelV_wingcc;
1446  else
1447  FT->pixel = (plD_pixel_fp) plD_pixel_wingcc;
1448  }
1449  #endif
1450 
1451  pls->xdpi = GetDeviceCaps( dev->hdc, HORZRES ) / GetDeviceCaps( dev->hdc, HORZSIZE ) * 25.4;
1452  pls->ydpi = GetDeviceCaps( dev->hdc, VERTRES ) / GetDeviceCaps( dev->hdc, VERTSIZE ) * 25.4;
1453  plP_setpxl( dev->scale * pls->xdpi / 25.4, dev->scale * pls->ydpi / 25.4 );
1454  plP_setphy( 0, (PLINT) ( dev->scale * dev->width ), 0, (PLINT) ( dev->scale * dev->height ) );
1455 }
1456 
1457 //--------------------------------------------------------------------------
1458 // static void PrintPage ( PLStream *pls )
1459 //
1460 // Function brings up a standard printer dialog and, after the user
1461 // has selected a printer, replots the current page to the windows
1462 // printer.
1463 //--------------------------------------------------------------------------
1464 
1465 static void PrintPage( PLStream *pls )
1466 {
1467  wingcc_Dev *dev = (wingcc_Dev *) pls->dev;
1468  #ifdef PL_HAVE_FREETYPE
1469  FT_Data *FT = (FT_Data *) pls->FT;
1470  #endif
1471  PRINTDLG Printer;
1472  DOCINFO docinfo;
1473 
1474  //
1475  // Reset the docinfo structure to 0 and set it's fields up
1476  // This structure is used to supply a name to the print queue
1477  //
1478 
1479  ZeroMemory( &docinfo, sizeof ( docinfo ) );
1480  docinfo.cbSize = sizeof ( docinfo );
1481  docinfo.lpszDocName = _T( "Plplot Page" );
1482 
1483  //
1484  // Reset out printer structure to zero and initialise it
1485  //
1486 
1487  ZeroMemory( &Printer, sizeof ( PRINTDLG ) );
1488  Printer.lStructSize = sizeof ( PRINTDLG );
1489  Printer.hwndOwner = dev->hwnd;
1490  Printer.Flags = PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC;
1491  Printer.nCopies = 1;
1492 
1493  //
1494  // Call the printer dialog function.
1495  // If the user has clicked on "Print", then we will continue
1496  // processing and print out the page.
1497  //
1498 
1499  if ( PrintDlg( &Printer ) != 0 )
1500  {
1501  //
1502  // Before doing anything, we will take some backup copies
1503  // of the existing values for page size and the like, because
1504  // all we are going to do is a quick and dirty modification
1505  // of plplot's internals to match the new page size and hope
1506  // it all works out ok. After that, we will manip the values,
1507  // and when all is done, restore them.
1508  //
1509 
1510  if ( ( dev->push = GlobalAlloc( GMEM_ZEROINIT, sizeof ( wingcc_Dev ) ) ) != NULL )
1511  {
1512  BusyCursor();
1513  memcpy( dev->push, dev, sizeof ( wingcc_Dev ) );
1514 
1515  dev->hdc = dev->PRNT_hdc = Printer.hDC; // Copy the printer HDC
1516 
1517  UpdatePageMetrics( pls, 1 );
1518 
1519  #ifdef PL_HAVE_FREETYPE
1520  if ( FT ) // If we are using freetype, then set it up next
1521  {
1522  dev->FT_smooth_text = FT->smooth_text; // When printing, we don't want smoothing
1523  FT->smooth_text = 0;
1524  }
1525  #endif
1526 
1527  //
1528  // Now the stuff that actually does the printing !!
1529  //
1530 
1531  StartDoc( dev->hdc, &docinfo );
1532  plRemakePlot( pls );
1533  EndDoc( dev->hdc );
1534 
1535  //
1536  // Now to undo everything back to what it was for the screen
1537  //
1538 
1539  dev->hdc = dev->SCRN_hdc; // Reset the screen HDC to the default
1540  UpdatePageMetrics( pls, 0 );
1541 
1542  #ifdef PL_HAVE_FREETYPE
1543  if ( FT ) // If we are using freetype, then set it up next
1544  {
1545  FT->smooth_text = dev->FT_smooth_text;
1546  }
1547  #endif
1548  memcpy( dev, dev->push, sizeof ( wingcc_Dev ) ); // POP our "stack" now to restore the values
1549 
1550  GlobalFree( dev->push );
1551  NormalCursor();
1552  RedrawWindow( dev->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW );
1553  }
1554  }
1555 }
1556 
1557 
1558 
1559 #else
1560 int
1562 {
1563  return ( 0 );
1564 }
1565 
1566 #endif // PLD_wingccdev