]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dcprint.cpp
1. wxMSW::wxNotebook::SetPageSize() and SetPadding() added
[wxWidgets.git] / src / msw / dcprint.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcprint.cpp
3 // Purpose: wxPrinterDC class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dcprint.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/window.h"
35 #include "wx/dcmemory.h"
36 #endif
37
38 #include "wx/msw/private.h"
39 #include "wx/dcprint.h"
40 #include "math.h"
41
42 #if wxUSE_COMMON_DIALOGS || defined(__WXWINE__)
43 #include <commdlg.h>
44 #endif
45
46 #ifndef __WIN32__
47 #include <print.h>
48 #endif
49
50 // ----------------------------------------------------------------------------
51 // wxWin macros
52 // ----------------------------------------------------------------------------
53 IMPLEMENT_CLASS(wxPrinterDC, wxDC)
54
55 // ============================================================================
56 // implementation
57 // ============================================================================
58
59 // ----------------------------------------------------------------------------
60 // wxPrinterDC construction
61 // ----------------------------------------------------------------------------
62
63 // This form is deprecated
64 wxPrinterDC::wxPrinterDC(const wxString& driver_name, const wxString& device_name, const wxString& file, bool interactive, int orientation)
65 {
66 m_isInteractive = interactive;
67
68 if ( !!file )
69 m_printData.SetFilename(file);
70
71 #if wxUSE_COMMON_DIALOGS
72 if (interactive)
73 {
74 PRINTDLG pd;
75
76 pd.lStructSize = sizeof( PRINTDLG );
77 pd.hwndOwner=(HWND) NULL;
78 pd.hDevMode=(HANDLE)NULL;
79 pd.hDevNames=(HANDLE)NULL;
80 pd.Flags=PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
81 pd.nFromPage=0;
82 pd.nToPage=0;
83 pd.nMinPage=0;
84 pd.nMaxPage=0;
85 pd.nCopies=1;
86 pd.hInstance=(HINSTANCE)NULL;
87
88 if ( PrintDlg( &pd ) != 0 )
89 {
90 m_hDC = (WXHDC) pd.hDC;
91 m_ok = TRUE;
92 }
93 else
94 {
95 m_ok = FALSE;
96 return;
97 }
98
99 // m_dontDelete = TRUE;
100 }
101 else
102 #endif // wxUSE_COMMON_DIALOGS
103 if ((!driver_name.IsNull() && driver_name != wxT("")) &&
104 (!device_name.IsNull() && device_name != wxT("")) &&
105 (!file.IsNull() && file != wxT("")))
106 {
107 m_hDC = (WXHDC) CreateDC(WXSTRINGCAST driver_name, WXSTRINGCAST device_name, WXSTRINGCAST file, NULL);
108 m_ok = m_hDC ? TRUE: FALSE;
109 }
110 else
111 {
112 wxPrintData printData;
113 printData.SetOrientation(orientation);
114 m_hDC = wxGetPrinterDC(printData);
115 m_ok = m_hDC ? TRUE: FALSE;
116 }
117
118 if (m_hDC)
119 {
120 // int width = GetDeviceCaps(m_hDC, VERTRES);
121 // int height = GetDeviceCaps(m_hDC, HORZRES);
122 SetMapMode(wxMM_TEXT);
123 }
124 SetBrush(*wxBLACK_BRUSH);
125 SetPen(*wxBLACK_PEN);
126 }
127
128 wxPrinterDC::wxPrinterDC(const wxPrintData& printData)
129 {
130 m_printData = printData;
131
132 m_isInteractive = FALSE;
133
134 m_hDC = wxGetPrinterDC(printData);
135 m_ok = (m_hDC != 0);
136
137 if (m_hDC)
138 SetMapMode(wxMM_TEXT);
139
140 SetBrush(*wxBLACK_BRUSH);
141 SetPen(*wxBLACK_PEN);
142 }
143
144
145 wxPrinterDC::wxPrinterDC(WXHDC theDC)
146 {
147 m_isInteractive = FALSE;
148
149 m_hDC = theDC;
150 m_ok = TRUE;
151 if (m_hDC)
152 {
153 // int width = GetDeviceCaps(m_hDC, VERTRES);
154 // int height = GetDeviceCaps(m_hDC, HORZRES);
155 SetMapMode(wxMM_TEXT);
156 }
157 SetBrush(*wxBLACK_BRUSH);
158 SetPen(*wxBLACK_PEN);
159 }
160
161 wxPrinterDC::~wxPrinterDC()
162 {
163 }
164
165 // ----------------------------------------------------------------------------
166 // wxPrinterDC {Start/End}{Page/Doc} methods
167 // ----------------------------------------------------------------------------
168
169 bool wxPrinterDC::StartDoc(const wxString& message)
170 {
171 DOCINFO docinfo;
172 docinfo.cbSize = sizeof(DOCINFO);
173 docinfo.lpszDocName = (const wxChar*)message;
174
175 wxString filename(m_printData.GetFilename());
176
177 if (filename.IsEmpty())
178 docinfo.lpszOutput = NULL;
179 else
180 docinfo.lpszOutput = (const wxChar *) filename;
181
182 #if defined(__WIN95__)
183 docinfo.lpszDatatype = NULL;
184 docinfo.fwType = 0;
185 #endif
186
187 if (!m_hDC)
188 return FALSE;
189
190 int ret = ::StartDoc(GetHdc(), &docinfo);
191
192 #ifndef __WIN16__
193 if (ret <= 0)
194 {
195 DWORD lastError = GetLastError();
196 wxLogDebug(wxT("wxDC::StartDoc failed with error: %d\n"), lastError);
197 }
198 #endif
199
200 return (ret > 0);
201 }
202
203 void wxPrinterDC::EndDoc()
204 {
205 if (m_hDC) ::EndDoc((HDC) m_hDC);
206 }
207
208 void wxPrinterDC::StartPage()
209 {
210 if (m_hDC)
211 ::StartPage((HDC) m_hDC);
212 }
213
214 void wxPrinterDC::EndPage()
215 {
216 if (m_hDC)
217 ::EndPage((HDC) m_hDC);
218 }
219
220 // Returns default device and port names
221 static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
222 {
223 deviceName = "";
224
225 LPDEVNAMES lpDevNames;
226 LPSTR lpszDriverName;
227 LPSTR lpszDeviceName;
228 LPSTR lpszPortName;
229
230 PRINTDLG pd;
231
232 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
233 #ifdef __GNUWIN32__
234 pd.lStructSize = 66; // sizeof(PRINTDLG);
235 #else
236 pd.lStructSize = sizeof(PRINTDLG);
237 #endif
238
239 pd.hwndOwner = (HWND)NULL;
240 pd.hDevMode = NULL; // Will be created by PrintDlg
241 pd.hDevNames = NULL; // Ditto
242 pd.Flags = PD_RETURNDEFAULT;
243 pd.nCopies = 1;
244
245 if (!PrintDlg((LPPRINTDLG)&pd))
246 {
247 if ( pd.hDevMode )
248 GlobalFree(pd.hDevMode);
249 if (pd.hDevNames)
250 GlobalFree(pd.hDevNames);
251
252 return FALSE;
253 }
254
255 if (pd.hDevNames)
256 {
257 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
258 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
259 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
260 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
261
262 deviceName = lpszDeviceName;
263 portName = lpszPortName;
264
265 GlobalUnlock(pd.hDevNames);
266 GlobalFree(pd.hDevNames);
267 pd.hDevNames=NULL;
268 }
269
270 if (pd.hDevMode)
271 {
272 GlobalFree(pd.hDevMode);
273 pd.hDevMode=NULL;
274 }
275 return ( deviceName != wxT("") );
276 }
277
278 #if 0
279 // This uses defaults, except for orientation, so we should eliminate this function
280 // and use the 2nd form (passing wxPrintData) instead.
281 WXHDC wxGetPrinterDC(int orientation)
282 {
283 HDC hDC;
284 LPDEVMODE lpDevMode = NULL;
285 LPDEVNAMES lpDevNames;
286 LPSTR lpszDriverName;
287 LPSTR lpszDeviceName;
288 LPSTR lpszPortName;
289
290 PRINTDLG pd;
291 // __GNUWIN32__ has trouble believing PRINTDLG is 66 bytes - thinks it is 68
292 #ifdef __GNUWIN32__
293 pd.lStructSize = 66; // sizeof(PRINTDLG);
294 #else
295 pd.lStructSize = sizeof(PRINTDLG);
296 #endif
297 pd.hwndOwner = (HWND)NULL;
298 pd.hDevMode = NULL; // Will be created by PrintDlg
299 pd.hDevNames = NULL; // Ditto
300 pd.Flags = PD_RETURNDEFAULT;
301 pd.nCopies = 1;
302
303 if (!PrintDlg((LPPRINTDLG)&pd))
304 {
305 if ( pd.hDevMode )
306 GlobalFree(pd.hDevMode);
307 if (pd.hDevNames)
308 GlobalFree(pd.hDevNames);
309
310 return(0);
311 }
312
313 if (!pd.hDevNames)
314 {
315 if ( pd.hDevMode )
316 GlobalFree(pd.hDevMode);
317 }
318
319 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
320 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
321 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
322 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
323 GlobalUnlock(pd.hDevNames);
324
325 if ( pd.hDevMode )
326 {
327 lpDevMode = (DEVMODE*) GlobalLock(pd.hDevMode);
328 lpDevMode->dmOrientation = orientation;
329 lpDevMode->dmFields |= DM_ORIENTATION;
330 }
331
332 #ifdef __WIN32__
333 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (DEVMODE *)lpDevMode);
334 #else
335 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (LPSTR)lpDevMode);
336 #endif
337
338 if (pd.hDevMode && lpDevMode)
339 GlobalUnlock(pd.hDevMode);
340
341 if (pd.hDevNames)
342 {
343 GlobalFree(pd.hDevNames);
344 pd.hDevNames=NULL;
345 }
346 if (pd.hDevMode)
347 {
348 GlobalFree(pd.hDevMode);
349 pd.hDevMode=NULL;
350 }
351 return (WXHDC) hDC;
352 }
353 #endif
354
355 // Gets an HDC for the specified printer configuration
356 WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
357 {
358 wxPrintData printData = printDataConst;
359 printData.ConvertToNative();
360
361 wxChar* driverName = (wxChar*) NULL;
362
363 wxString devNameStr = printData.GetPrinterName();
364 wxChar* portName = (wxChar*) NULL; // Obsolete in WIN32
365
366 const wxChar* deviceName;
367 if ( !devNameStr )
368 deviceName = (wxChar*) NULL;
369 else
370 deviceName = devNameStr.c_str();
371
372 LPDEVMODE lpDevMode = (LPDEVMODE) NULL;
373
374 HGLOBAL hDevMode = (HGLOBAL)(DWORD) printData.GetNativeData();
375
376 if ( hDevMode )
377 lpDevMode = (DEVMODE*) GlobalLock(hDevMode);
378
379 if ( !devNameStr )
380 {
381 // Retrieve the default device name
382 wxString portName;
383 #ifdef __WXDEBUG__
384 bool ret =
385 #else // !Debug
386 (void)
387 #endif // Debug/Release
388 wxGetDefaultDeviceName(devNameStr, portName);
389
390 wxASSERT_MSG( ret, wxT("Could not get default device name.") );
391
392 deviceName = devNameStr.c_str();
393 }
394
395 #ifdef __WIN32__
396 HDC hDC = CreateDC(driverName, deviceName, portName, (DEVMODE *) lpDevMode);
397 #else
398 HDC hDC = CreateDC(driverName, deviceName, portName, (LPSTR) lpDevMode);
399 #endif
400
401 if (hDevMode && lpDevMode)
402 GlobalUnlock(hDevMode);
403
404 return (WXHDC) hDC;
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxPrinterDC bit blitting/bitmap drawing
409 // ----------------------------------------------------------------------------
410
411 void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
412 wxCoord x, wxCoord y,
413 bool useMask)
414 {
415 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
416
417 int width = bmp.GetWidth(),
418 height = bmp.GetHeight();
419
420 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
421 {
422 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
423 memset( info, 0, sizeof( BITMAPINFOHEADER ) );
424
425 int iBitsSize = ((width + 3 ) & ~3 ) * height;
426
427 void* bits = malloc( iBitsSize );
428
429 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
430 info->bmiHeader.biWidth = width;
431 info->bmiHeader.biHeight = height;
432 info->bmiHeader.biPlanes = 1;
433 info->bmiHeader.biBitCount = 8;
434 info->bmiHeader.biCompression = BI_RGB;
435
436 ScreenHDC display;
437 if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
438 bmp.GetHeight(), bits, info,
439 DIB_RGB_COLORS) )
440 {
441 if ( ::StretchDIBits(GetHdc(), x, y,
442 width, height,
443 0 , 0, width, height,
444 bits, info,
445 DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
446 {
447 wxLogLastError("StretchDIBits");
448 }
449 }
450
451 free(bits);
452 free(info);
453 }
454 else // no support for StretchDIBits()
455 {
456 wxMemoryDC memDC;
457 memDC.SelectObject(bmp);
458
459 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
460
461 memDC.SelectObject(wxNullBitmap);
462 }
463 }
464
465 bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
466 wxCoord width, wxCoord height,
467 wxDC *source,
468 wxCoord xsrc, wxCoord ysrc,
469 int rop, bool useMask)
470 {
471 bool success = TRUE;
472
473 if ( useMask )
474 {
475 // If we are printing source colours are screen colours
476 // not printer colours and so we need copy the bitmap
477 // pixel by pixel.
478 RECT rect;
479 HDC dc_src = GetHdcOf(*source);
480 HDC dc_mask = ::CreateCompatibleDC(dc_src);
481
482 ::SelectObject(dc_mask, (HBITMAP) source->GetSelectedBitmap().GetMask()->GetMaskBitmap());
483 for (int x = 0; x < width; x++)
484 {
485 for (int y = 0; y < height; y++)
486 {
487 COLORREF cref = ::GetPixel(dc_mask, x, y);
488 if (cref)
489 {
490 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
491 rect.left = xdest + x;
492 rect.right = rect.left + 1;
493 rect.top = ydest + y;
494 rect.bottom = rect.top + 1;
495 ::FillRect(GetHdc(), &rect, brush);
496 ::DeleteObject(brush);
497 }
498 }
499 }
500 ::SelectObject(dc_mask, 0);
501 ::DeleteDC(dc_mask);
502 }
503 else // no mask
504 {
505 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
506 {
507 wxBitmap& bmp = source->GetSelectedBitmap();
508 int width = bmp.GetWidth(),
509 height = bmp.GetHeight();
510
511 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
512 int iBitsSize = ((width + 3 ) & ~3 ) * height;
513
514 void* bits = malloc( iBitsSize );
515
516 memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
517
518 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
519 info->bmiHeader.biWidth = width;
520 info->bmiHeader.biHeight = height;
521 info->bmiHeader.biPlanes = 1;
522 info->bmiHeader.biBitCount = 8;
523 info->bmiHeader.biCompression = BI_RGB;
524
525 ScreenHDC display;
526 if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
527 height, bits, info, DIB_RGB_COLORS) )
528 {
529 wxLogLastError("GetDIBits");
530
531 success = FALSE;
532 }
533
534 if ( success )
535 {
536 success = ::StretchDIBits(GetHdc(), xdest, ydest,
537 width, height,
538 xsrc, ysrc,
539 width, height,
540 bits, info ,
541 DIB_RGB_COLORS,
542 SRCCOPY) != GDI_ERROR;
543 if ( !success )
544 {
545 wxLogLastError("StretchDIBits");
546 }
547 }
548
549 free(bits);
550 free(info);
551 }
552 else // no support for StretchDIBits
553 {
554 // as we are printing, source colours are screen colours not printer
555 // colours and so we need copy the bitmap pixel by pixel.
556 HDC dc_src = GetHdcOf(*source);
557 RECT rect;
558 for (int y = 0; y < height; y++)
559 {
560 // This is Stefan Csomor's optimisation, where identical adjacent
561 // pixels are drawn together.
562 for (int x = 0; x < width; x++)
563 {
564 COLORREF col = ::GetPixel(dc_src, x, y);
565 HBRUSH brush = ::CreateSolidBrush( col );
566
567 rect.left = xdest + x;
568 rect.top = ydest + y;
569 while( (x + 1 < width) && (::GetPixel(dc_src, x + 1, y) == col ) )
570 {
571 ++x;
572 }
573 rect.right = xdest + x + 1;
574 rect.bottom = rect.top + 1;
575 ::FillRect((HDC) m_hDC, &rect, brush);
576 ::DeleteObject(brush);
577 }
578 }
579 }
580 }
581
582 return success;
583 }