/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/prntbase.cpp
ViewVC logotype

Contents of /trunk/3rdparty/wxWidgets/src/common/prntbase.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 2 months ago) by william
File size: 64019 byte(s)
committing r3113 initial commit again...
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/prntbase.cpp
3 // Purpose: Printing framework base class implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id: prntbase.cpp 58209 2009-01-18 21:31:36Z RD $
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PRINTING_ARCHITECTURE
20
21 // change this to 1 to use experimental high-quality printing on Windows
22 // (NB: this can't be in msw/printwin.cpp because of binary compatibility)
23 #define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0
24
25 #if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
26 #if !defined(__WXMSW__) || !wxUSE_IMAGE || !wxUSE_WXDIB
27 #undef wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
28 #define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0
29 #endif
30 #endif
31
32 #include "wx/dcprint.h"
33
34 #ifndef WX_PRECOMP
35 #if defined(__WXMSW__)
36 #include "wx/msw/wrapcdlg.h"
37 #endif // MSW
38 #include "wx/utils.h"
39 #include "wx/dc.h"
40 #include "wx/app.h"
41 #include "wx/math.h"
42 #include "wx/msgdlg.h"
43 #include "wx/layout.h"
44 #include "wx/choice.h"
45 #include "wx/button.h"
46 #include "wx/settings.h"
47 #include "wx/dcmemory.h"
48 #include "wx/stattext.h"
49 #include "wx/intl.h"
50 #include "wx/textdlg.h"
51 #include "wx/sizer.h"
52 #include "wx/module.h"
53 #endif // !WX_PRECOMP
54
55 #include "wx/prntbase.h"
56 #include "wx/printdlg.h"
57 #include "wx/print.h"
58 #include "wx/dcprint.h"
59
60 #include <stdlib.h>
61 #include <string.h>
62
63 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
64 #include "wx/msw/printdlg.h"
65 #elif defined(__WXMAC__)
66 #include "wx/mac/printdlg.h"
67 #include "wx/mac/private/print.h"
68 #else
69 #include "wx/generic/prntdlgg.h"
70 #include "wx/dcps.h"
71 #endif
72
73 #ifdef __WXMSW__
74 #ifndef __WIN32__
75 #include <print.h>
76 #endif
77 #endif // __WXMSW__
78
79 #if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
80
81 #include "wx/msw/dib.h"
82 #include "wx/image.h"
83
84 typedef bool (wxPrintPreviewBase::*RenderPageIntoDCFunc)(wxDC&, int);
85 static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview,
86 RenderPageIntoDCFunc RenderPageIntoDC,
87 wxPrinterDC& printerDC,
88 wxBitmap& bmp, int pageNum,
89 int pageWidth, int pageHeight);
90 #endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
91
92 //----------------------------------------------------------------------------
93 // wxPrintFactory
94 //----------------------------------------------------------------------------
95
96 wxPrintFactory *wxPrintFactory::m_factory = NULL;
97
98 void wxPrintFactory::SetPrintFactory( wxPrintFactory *factory )
99 {
100 if (wxPrintFactory::m_factory)
101 delete wxPrintFactory::m_factory;
102
103 wxPrintFactory::m_factory = factory;
104 }
105
106 wxPrintFactory *wxPrintFactory::GetFactory()
107 {
108 if (!wxPrintFactory::m_factory)
109 wxPrintFactory::m_factory = new wxNativePrintFactory;
110
111 return wxPrintFactory::m_factory;
112 }
113
114 //----------------------------------------------------------------------------
115 // wxNativePrintFactory
116 //----------------------------------------------------------------------------
117
118 wxPrinterBase *wxNativePrintFactory::CreatePrinter( wxPrintDialogData *data )
119 {
120 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
121 return new wxWindowsPrinter( data );
122 #elif defined(__WXMAC__)
123 return new wxMacPrinter( data );
124 #elif defined(__WXPM__)
125 return new wxOS2Printer( data );
126 #else
127 return new wxPostScriptPrinter( data );
128 #endif
129 }
130
131 wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview,
132 wxPrintout *printout, wxPrintDialogData *data )
133 {
134 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
135 return new wxWindowsPrintPreview( preview, printout, data );
136 #elif defined(__WXMAC__)
137 return new wxMacPrintPreview( preview, printout, data );
138 #elif defined(__WXPM__)
139 return new wxOS2PrintPreview( preview, printout, data );
140 #else
141 return new wxPostScriptPrintPreview( preview, printout, data );
142 #endif
143 }
144
145 wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview,
146 wxPrintout *printout, wxPrintData *data )
147 {
148 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
149 return new wxWindowsPrintPreview( preview, printout, data );
150 #elif defined(__WXMAC__)
151 return new wxMacPrintPreview( preview, printout, data );
152 #elif defined(__WXPM__)
153 return new wxOS2PrintPreview( preview, printout, data );
154 #else
155 return new wxPostScriptPrintPreview( preview, printout, data );
156 #endif
157 }
158
159 wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent,
160 wxPrintDialogData *data )
161 {
162 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
163 return new wxWindowsPrintDialog( parent, data );
164 #elif defined(__WXMAC__)
165 return new wxMacPrintDialog( parent, data );
166 #else
167 return new wxGenericPrintDialog( parent, data );
168 #endif
169 }
170
171 wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent,
172 wxPrintData *data )
173 {
174 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
175 return new wxWindowsPrintDialog( parent, data );
176 #elif defined(__WXMAC__)
177 return new wxMacPrintDialog( parent, data );
178 #else
179 return new wxGenericPrintDialog( parent, data );
180 #endif
181 }
182
183 wxPageSetupDialogBase *wxNativePrintFactory::CreatePageSetupDialog( wxWindow *parent,
184 wxPageSetupDialogData *data )
185 {
186 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
187 return new wxWindowsPageSetupDialog( parent, data );
188 #elif defined(__WXMAC__)
189 return new wxMacPageSetupDialog( parent, data );
190 #else
191 return new wxGenericPageSetupDialog( parent, data );
192 #endif
193 }
194
195 bool wxNativePrintFactory::HasPrintSetupDialog()
196 {
197 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
198 return false;
199 #elif defined(__WXMAC__)
200 return false;
201 #else
202 // Only here do we need to provide the print setup
203 // dialog ourselves, the other platforms either have
204 // none, don't make it accessible or let you configure
205 // the printer from the wxPrintDialog anyway.
206 return true;
207 #endif
208
209 }
210
211 wxDialog *wxNativePrintFactory::CreatePrintSetupDialog( wxWindow *parent,
212 wxPrintData *data )
213 {
214 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
215 wxUnusedVar(parent);
216 wxUnusedVar(data);
217 return NULL;
218 #elif defined(__WXMAC__)
219 wxUnusedVar(parent);
220 wxUnusedVar(data);
221 return NULL;
222 #else
223 // Only here do we need to provide the print setup
224 // dialog ourselves, the other platforms either have
225 // none, don't make it accessible or let you configure
226 // the printer from the wxPrintDialog anyway.
227 return new wxGenericPrintSetupDialog( parent, data );
228 #endif
229 }
230
231 wxDC* wxNativePrintFactory::CreatePrinterDC( const wxPrintData& data )
232 {
233 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
234 return new wxPrinterDC(data);
235 #elif defined(__WXMAC__)
236 return new wxPrinterDC(data);
237 #else
238 return new wxPostScriptDC(data);
239 #endif
240 }
241
242 bool wxNativePrintFactory::HasOwnPrintToFile()
243 {
244 // Only relevant for PostScript and here the
245 // setup dialog provides no "print to file"
246 // option. In the GNOME setup dialog, the
247 // setup dialog has its own print to file.
248 return false;
249 }
250
251 bool wxNativePrintFactory::HasPrinterLine()
252 {
253 // Only relevant for PostScript for now
254 return true;
255 }
256
257 wxString wxNativePrintFactory::CreatePrinterLine()
258 {
259 // Only relevant for PostScript for now
260
261 // We should query "lpstat -d" here
262 return _("Generic PostScript");
263 }
264
265 bool wxNativePrintFactory::HasStatusLine()
266 {
267 // Only relevant for PostScript for now
268 return true;
269 }
270
271 wxString wxNativePrintFactory::CreateStatusLine()
272 {
273 // Only relevant for PostScript for now
274
275 // We should query "lpstat -r" or "lpstat -p" here
276 return _("Ready");
277 }
278
279 wxPrintNativeDataBase *wxNativePrintFactory::CreatePrintNativeData()
280 {
281 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
282 return new wxWindowsPrintNativeData;
283 #elif defined(__WXMAC__)
284 return new wxMacCarbonPrintData;
285 #else
286 return new wxPostScriptPrintNativeData;
287 #endif
288 }
289
290 //----------------------------------------------------------------------------
291 // wxPrintNativeDataBase
292 //----------------------------------------------------------------------------
293
294 IMPLEMENT_ABSTRACT_CLASS(wxPrintNativeDataBase, wxObject)
295
296 wxPrintNativeDataBase::wxPrintNativeDataBase()
297 {
298 m_ref = 1;
299 }
300
301 //----------------------------------------------------------------------------
302 // wxPrintFactoryModule
303 //----------------------------------------------------------------------------
304
305 class wxPrintFactoryModule: public wxModule
306 {
307 public:
308 wxPrintFactoryModule() {}
309 bool OnInit() { return true; }
310 void OnExit() { wxPrintFactory::SetPrintFactory( NULL ); }
311
312 private:
313 DECLARE_DYNAMIC_CLASS(wxPrintFactoryModule)
314 };
315
316 IMPLEMENT_DYNAMIC_CLASS(wxPrintFactoryModule, wxModule)
317
318 //----------------------------------------------------------------------------
319 // wxPrinterBase
320 //----------------------------------------------------------------------------
321
322 IMPLEMENT_CLASS(wxPrinterBase, wxObject)
323
324 wxPrinterBase::wxPrinterBase(wxPrintDialogData *data)
325 {
326 m_currentPrintout = (wxPrintout *) NULL;
327 sm_abortWindow = (wxWindow *) NULL;
328 sm_abortIt = false;
329 if (data)
330 m_printDialogData = (*data);
331 sm_lastError = wxPRINTER_NO_ERROR;
332 }
333
334 wxWindow *wxPrinterBase::sm_abortWindow = (wxWindow *) NULL;
335 bool wxPrinterBase::sm_abortIt = false;
336 wxPrinterError wxPrinterBase::sm_lastError = wxPRINTER_NO_ERROR;
337
338 wxPrinterBase::~wxPrinterBase()
339 {
340 }
341
342 wxWindow *wxPrinterBase::CreateAbortWindow(wxWindow *parent, wxPrintout * printout)
343 {
344 wxPrintAbortDialog *dialog = new wxPrintAbortDialog(parent, _("Printing ") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE);
345
346 wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL );
347 button_sizer->Add( new wxStaticText(dialog, wxID_ANY, _("Please wait while printing\n") + printout->GetTitle() ), 0, wxALL, 10 );
348 button_sizer->Add( new wxButton( dialog, wxID_CANCEL, wxT("Cancel") ), 0, wxALL | wxALIGN_CENTER, 10 );
349
350 dialog->SetAutoLayout( true );
351 dialog->SetSizer( button_sizer );
352
353 button_sizer->Fit(dialog);
354 button_sizer->SetSizeHints (dialog) ;
355
356 return dialog;
357 }
358
359 void wxPrinterBase::ReportError(wxWindow *parent, wxPrintout *WXUNUSED(printout), const wxString& message)
360 {
361 wxMessageBox(message, _("Printing Error"), wxOK, parent);
362 }
363
364 wxPrintDialogData& wxPrinterBase::GetPrintDialogData() const
365 {
366 return (wxPrintDialogData&) m_printDialogData;
367 }
368
369 //----------------------------------------------------------------------------
370 // wxPrinter
371 //----------------------------------------------------------------------------
372
373 IMPLEMENT_CLASS(wxPrinter, wxPrinterBase)
374
375 wxPrinter::wxPrinter(wxPrintDialogData *data)
376 {
377 m_pimpl = wxPrintFactory::GetFactory()->CreatePrinter( data );
378 }
379
380 wxPrinter::~wxPrinter()
381 {
382 delete m_pimpl;
383 }
384
385 wxWindow *wxPrinter::CreateAbortWindow(wxWindow *parent, wxPrintout *printout)
386 {
387 return m_pimpl->CreateAbortWindow( parent, printout );
388 }
389
390 void wxPrinter::ReportError(wxWindow *parent, wxPrintout *printout, const wxString& message)
391 {
392 m_pimpl->ReportError( parent, printout, message );
393 }
394
395 bool wxPrinter::Setup(wxWindow *parent)
396 {
397 return m_pimpl->Setup( parent );
398 }
399
400 bool wxPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt)
401 {
402 return m_pimpl->Print( parent, printout, prompt );
403 }
404
405 wxDC* wxPrinter::PrintDialog(wxWindow *parent)
406 {
407 return m_pimpl->PrintDialog( parent );
408 }
409
410 wxPrintDialogData& wxPrinter::GetPrintDialogData() const
411 {
412 return m_pimpl->GetPrintDialogData();
413 }
414
415 // ---------------------------------------------------------------------------
416 // wxPrintDialogBase: the dialog for printing.
417 // ---------------------------------------------------------------------------
418
419 IMPLEMENT_ABSTRACT_CLASS(wxPrintDialogBase, wxDialog)
420
421 wxPrintDialogBase::wxPrintDialogBase(wxWindow *parent,
422 wxWindowID id,
423 const wxString &title,
424 const wxPoint &pos,
425 const wxSize &size,
426 long style)
427 : wxDialog( parent, id, title.empty() ? wxString(_("Print")) : title,
428 pos, size, style )
429 {
430 }
431
432 // ---------------------------------------------------------------------------
433 // wxPrintDialog: the dialog for printing
434 // ---------------------------------------------------------------------------
435
436 IMPLEMENT_CLASS(wxPrintDialog, wxObject)
437
438 wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintDialogData* data)
439 {
440 m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data );
441 }
442
443 wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintData* data)
444 {
445 m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data );
446 }
447
448 wxPrintDialog::~wxPrintDialog()
449 {
450 delete m_pimpl;
451 }
452
453 int wxPrintDialog::ShowModal()
454 {
455 return m_pimpl->ShowModal();
456 }
457
458 wxPrintDialogData& wxPrintDialog::GetPrintDialogData()
459 {
460 return m_pimpl->GetPrintDialogData();
461 }
462
463 wxPrintData& wxPrintDialog::GetPrintData()
464 {
465 return m_pimpl->GetPrintData();
466 }
467
468 wxDC *wxPrintDialog::GetPrintDC()
469 {
470 return m_pimpl->GetPrintDC();
471 }
472
473 // ---------------------------------------------------------------------------
474 // wxPageSetupDialogBase: the page setup dialog
475 // ---------------------------------------------------------------------------
476
477 IMPLEMENT_ABSTRACT_CLASS(wxPageSetupDialogBase, wxDialog)
478
479 wxPageSetupDialogBase::wxPageSetupDialogBase(wxWindow *parent,
480 wxWindowID id,
481 const wxString &title,
482 const wxPoint &pos,
483 const wxSize &size,
484 long style)
485 : wxDialog( parent, id, title.empty() ? wxString(_("Page setup")) : title,
486 pos, size, style )
487 {
488 }
489
490 // ---------------------------------------------------------------------------
491 // wxPageSetupDialog: the page setup dialog
492 // ---------------------------------------------------------------------------
493
494 IMPLEMENT_CLASS(wxPageSetupDialog, wxObject)
495
496 wxPageSetupDialog::wxPageSetupDialog(wxWindow *parent, wxPageSetupDialogData *data )
497 {
498 m_pimpl = wxPrintFactory::GetFactory()->CreatePageSetupDialog( parent, data );
499 }
500
501 wxPageSetupDialog::~wxPageSetupDialog()
502 {
503 delete m_pimpl;
504 }
505
506 int wxPageSetupDialog::ShowModal()
507 {
508 return m_pimpl->ShowModal();
509 }
510
511 wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupDialogData()
512 {
513 return m_pimpl->GetPageSetupDialogData();
514 }
515
516 // old name
517 wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupData()
518 {
519 return m_pimpl->GetPageSetupDialogData();
520 }
521
522 //----------------------------------------------------------------------------
523 // wxPrintAbortDialog
524 //----------------------------------------------------------------------------
525
526 BEGIN_EVENT_TABLE(wxPrintAbortDialog, wxDialog)
527 EVT_BUTTON(wxID_CANCEL, wxPrintAbortDialog::OnCancel)
528 END_EVENT_TABLE()
529
530 void wxPrintAbortDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
531 {
532 wxPrinterBase::sm_abortIt = true;
533 wxPrinterBase::sm_abortWindow->Show(false);
534 wxPrinterBase::sm_abortWindow->Close(true);
535 wxPrinterBase::sm_abortWindow->Destroy();
536 wxPrinterBase::sm_abortWindow = (wxWindow *) NULL;
537 }
538
539 //----------------------------------------------------------------------------
540 // wxPrintout
541 //----------------------------------------------------------------------------
542
543 IMPLEMENT_ABSTRACT_CLASS(wxPrintout, wxObject)
544
545 wxPrintout::wxPrintout(const wxString& title)
546 {
547 m_printoutTitle = title ;
548 m_printoutDC = (wxDC *) NULL;
549 m_pageWidthMM = 0;
550 m_pageHeightMM = 0;
551 m_pageWidthPixels = 0;
552 m_pageHeightPixels = 0;
553 m_PPIScreenX = 0;
554 m_PPIScreenY = 0;
555 m_PPIPrinterX = 0;
556 m_PPIPrinterY = 0;
557 m_isPreview = false;
558 }
559
560 wxPrintout::~wxPrintout()
561 {
562 }
563
564 bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage), int WXUNUSED(endPage))
565 {
566 return GetDC()->StartDoc(_("Printing ") + m_printoutTitle);
567 }
568
569 void wxPrintout::OnEndDocument()
570 {
571 GetDC()->EndDoc();
572 }
573
574 void wxPrintout::OnBeginPrinting()
575 {
576 }
577
578 void wxPrintout::OnEndPrinting()
579 {
580 }
581
582 bool wxPrintout::HasPage(int page)
583 {
584 return (page == 1);
585 }
586
587 void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toPage)
588 {
589 *minPage = 1;
590 *maxPage = 32000;
591 *fromPage = 1;
592 *toPage = 1;
593 }
594
595 void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize)
596 {
597 // Set the DC scale and origin so that the given image size fits within the
598 // entire page and the origin is at the top left corner of the page. Note
599 // that with most printers, portions of the page will be non-printable. Use
600 // this if you're managing your own page margins.
601 if (!m_printoutDC) return;
602 wxRect paperRect = GetPaperRectPixels();
603 wxCoord pw, ph;
604 GetPageSizePixels(&pw, &ph);
605 wxCoord w, h;
606 m_printoutDC->GetSize(&w, &h);
607 float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x));
608 float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y));
609 float actualScale = wxMin(scaleX, scaleY);
610 m_printoutDC->SetUserScale(actualScale, actualScale);
611 m_printoutDC->SetDeviceOrigin(0, 0);
612 wxRect logicalPaperRect = GetLogicalPaperRect();
613 SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y);
614 }
615
616 void wxPrintout::FitThisSizeToPage(const wxSize& imageSize)
617 {
618 // Set the DC scale and origin so that the given image size fits within the
619 // printable area of the page and the origin is at the top left corner of
620 // the printable area.
621 if (!m_printoutDC) return;
622 int w, h;
623 m_printoutDC->GetSize(&w, &h);
624 float scaleX = float(w) / imageSize.x;
625 float scaleY = float(h) / imageSize.y;
626 float actualScale = wxMin(scaleX, scaleY);
627 m_printoutDC->SetUserScale(actualScale, actualScale);
628 m_printoutDC->SetDeviceOrigin(0, 0);
629 }
630
631 void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData)
632 {
633 // Set the DC scale and origin so that the given image size fits within the
634 // page margins defined in the given wxPageSetupDialogData object and the
635 // origin is at the top left corner of the page margins.
636 if (!m_printoutDC) return;
637 wxRect paperRect = GetPaperRectPixels();
638 wxCoord pw, ph;
639 GetPageSizePixels(&pw, &ph);
640 wxPoint topLeft = pageSetupData.GetMarginTopLeft();
641 wxPoint bottomRight = pageSetupData.GetMarginBottomRight();
642 wxCoord mw, mh;
643 GetPageSizeMM(&mw, &mh);
644 float mmToDeviceX = float(pw) / mw;
645 float mmToDeviceY = float(ph) / mh;
646 wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x),
647 paperRect.y + wxRound(mmToDeviceY * topLeft.y),
648 paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)),
649 paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y)));
650 wxCoord w, h;
651 m_printoutDC->GetSize(&w, &h);
652 float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x);
653 float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y);
654 float actualScale = wxMin(scaleX, scaleY);
655 m_printoutDC->SetUserScale(actualScale, actualScale);
656 m_printoutDC->SetDeviceOrigin(0, 0);
657 wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData);
658 SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y);
659 }
660
661 void wxPrintout::MapScreenSizeToPaper()
662 {
663 // Set the DC scale so that an image on the screen is the same size on the
664 // paper and the origin is at the top left of the paper. Note that with most
665 // printers, portions of the page will be cut off. Use this if you're
666 // managing your own page margins.
667 if (!m_printoutDC) return;
668 MapScreenSizeToPage();
669 wxRect logicalPaperRect = GetLogicalPaperRect();
670 SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y);
671 }
672
673 void wxPrintout::MapScreenSizeToPage()
674 {
675 // Set the DC scale and origin so that an image on the screen is the same
676 // size on the paper and the origin is at the top left of the printable area.
677 if (!m_printoutDC) return;
678 int ppiScreenX, ppiScreenY;
679 GetPPIScreen(&ppiScreenX, &ppiScreenY);
680 int ppiPrinterX, ppiPrinterY;
681 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
682 int w, h;
683 m_printoutDC->GetSize(&w, &h);
684 int pageSizePixelsX, pageSizePixelsY;
685 GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY);
686 float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX);
687 float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY);
688 m_printoutDC->SetUserScale(userScaleX, userScaleY);
689 m_printoutDC->SetDeviceOrigin(0, 0);
690 }
691
692 void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData)
693 {
694 // Set the DC scale so that an image on the screen is the same size on the
695 // paper and the origin is at the top left of the page margins defined by
696 // the given wxPageSetupDialogData object.
697 if (!m_printoutDC) return;
698 MapScreenSizeToPage();
699 wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData);
700 SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y);
701 }
702
703 void wxPrintout::MapScreenSizeToDevice()
704 {
705 // Set the DC scale so that a screen pixel is the same size as a device
706 // pixel and the origin is at the top left of the printable area.
707 if (!m_printoutDC) return;
708 int w, h;
709 m_printoutDC->GetSize(&w, &h);
710 int pageSizePixelsX, pageSizePixelsY;
711 GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY);
712 float userScaleX = float(w) / pageSizePixelsX;
713 float userScaleY = float(h) / pageSizePixelsY;
714 m_printoutDC->SetUserScale(userScaleX, userScaleY);
715 m_printoutDC->SetDeviceOrigin(0, 0);
716 }
717
718 wxRect wxPrintout::GetLogicalPaperRect() const
719 {
720 // Return the rectangle in logical units that corresponds to the paper
721 // rectangle.
722 wxRect paperRect = GetPaperRectPixels();
723 wxCoord pw, ph;
724 GetPageSizePixels(&pw, &ph);
725 wxCoord w, h;
726 m_printoutDC->GetSize(&w, &h);
727 if (w == pw && h == ph) {
728 // this DC matches the printed page, so no scaling
729 return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x),
730 m_printoutDC->DeviceToLogicalY(paperRect.y),
731 m_printoutDC->DeviceToLogicalXRel(paperRect.width),
732 m_printoutDC->DeviceToLogicalYRel(paperRect.height));
733 }
734 // This DC doesn't match the printed page, so we have to scale.
735 float scaleX = float(w) / pw;
736 float scaleY = float(h) / ph;
737 return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(paperRect.x * scaleX)),
738 m_printoutDC->DeviceToLogicalY(wxRound(paperRect.y * scaleY)),
739 m_printoutDC->DeviceToLogicalXRel(wxRound(paperRect.width * scaleX)),
740 m_printoutDC->DeviceToLogicalYRel(wxRound(paperRect.height * scaleY)));
741 }
742
743 wxRect wxPrintout::GetLogicalPageRect() const
744 {
745 // Return the rectangle in logical units that corresponds to the printable
746 // area.
747 int w, h;
748 m_printoutDC->GetSize(&w, &h);
749 return wxRect(m_printoutDC->DeviceToLogicalX(0),
750 m_printoutDC->DeviceToLogicalY(0),
751 m_printoutDC->DeviceToLogicalXRel(w),
752 m_printoutDC->DeviceToLogicalYRel(h));
753 }
754
755 wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const
756 {
757 // Return the rectangle in logical units that corresponds to the region
758 // within the page margins as specified by the given wxPageSetupDialogData
759 // object.
760 wxRect paperRect = GetPaperRectPixels();
761 wxCoord pw, ph;
762 GetPageSizePixels(&pw, &ph);
763 wxPoint topLeft = pageSetupData.GetMarginTopLeft();
764 wxPoint bottomRight = pageSetupData.GetMarginBottomRight();
765 wxCoord mw, mh;
766 GetPageSizeMM(&mw, &mh);
767 float mmToDeviceX = float(pw) / mw;
768 float mmToDeviceY = float(ph) / mh;
769 wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x),
770 paperRect.y + wxRound(mmToDeviceY * topLeft.y),
771 paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)),
772 paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y)));
773 wxCoord w, h;
774 m_printoutDC->GetSize(&w, &h);
775 if (w == pw && h == ph) {
776 // this DC matches the printed page, so no scaling
777 return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x),
778 m_printoutDC->DeviceToLogicalY(pageMarginsRect.y),
779 m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width),
780 m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height));
781 }
782 // This DC doesn't match the printed page, so we have to scale.
783 float scaleX = float(w) / pw;
784 float scaleY = float(h) / ph;
785 return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(pageMarginsRect.x * scaleX)),
786 m_printoutDC->DeviceToLogicalY(wxRound(pageMarginsRect.y * scaleY)),
787 m_printoutDC->DeviceToLogicalXRel(wxRound(pageMarginsRect.width * scaleX)),
788 m_printoutDC->DeviceToLogicalYRel(wxRound(pageMarginsRect.height * scaleY)));
789 }
790
791 void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y)
792 {
793 // Set the device origin by specifying a point in logical coordinates.
794 m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x),
795 m_printoutDC->LogicalToDeviceY(y));
796 }
797
798 void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff)
799 {
800 // Offset the device origin by a specified distance in device coordinates.
801 wxCoord x = m_printoutDC->LogicalToDeviceX(0);
802 wxCoord y = m_printoutDC->LogicalToDeviceY(0);
803 m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff),
804 y + m_printoutDC->LogicalToDeviceYRel(yoff));
805 }
806
807
808 //----------------------------------------------------------------------------
809 // wxPreviewCanvas
810 //----------------------------------------------------------------------------
811
812 IMPLEMENT_CLASS(wxPreviewCanvas, wxWindow)
813
814 BEGIN_EVENT_TABLE(wxPreviewCanvas, wxScrolledWindow)
815 EVT_PAINT(wxPreviewCanvas::OnPaint)
816 EVT_CHAR(wxPreviewCanvas::OnChar)
817 EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged)
818 #if wxUSE_MOUSEWHEEL
819 EVT_MOUSEWHEEL(wxPreviewCanvas::OnMouseWheel)
820 #endif
821 END_EVENT_TABLE()
822
823 // VZ: the current code doesn't refresh properly without
824 // wxFULL_REPAINT_ON_RESIZE, this must be fixed as otherwise we have
825 // really horrible flicker when resizing the preview frame, but without
826 // this style it simply doesn't work correctly at all...
827 wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase *preview, wxWindow *parent,
828 const wxPoint& pos, const wxSize& size, long style, const wxString& name):
829 wxScrolledWindow(parent, wxID_ANY, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name)
830 {
831 m_printPreview = preview;
832 #ifdef __WXMAC__
833 // The app workspace colour is always white, but we should have
834 // a contrast with the page.
835 wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW;
836 #elif defined(__WXGTK__)
837 wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE;
838 #else
839 wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE;
840 #endif
841 SetBackgroundColour(wxSystemSettings::GetColour(colourIndex));
842
843 SetScrollbars(10, 10, 100, 100);
844 }
845
846 wxPreviewCanvas::~wxPreviewCanvas()
847 {
848 }
849
850 void wxPreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
851 {
852 wxPaintDC dc(this);
853 PrepareDC( dc );
854
855 /*
856 #ifdef __WXGTK__
857 if (!GetUpdateRegion().IsEmpty())
858 dc.SetClippingRegion( GetUpdateRegion() );
859 #endif
860 */
861
862 if (m_printPreview)
863 {
864 m_printPreview->PaintPage(this, dc);
865 }
866 }
867
868 // Responds to colour changes, and passes event on to children.
869 void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent& event)
870 {
871 #ifdef __WXMAC__
872 // The app workspace colour is always white, but we should have
873 // a contrast with the page.
874 wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW;
875 #elif defined(__WXGTK__)
876 wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE;
877 #else
878 wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE;
879 #endif
880 SetBackgroundColour(wxSystemSettings::GetColour(colourIndex));
881 Refresh();
882
883 // Propagate the event to the non-top-level children
884 wxWindow::OnSysColourChanged(event);
885 }
886
887 void wxPreviewCanvas::OnChar(wxKeyEvent &event)
888 {
889 wxPreviewControlBar* controlBar = ((wxPreviewFrame*) GetParent())->GetControlBar();
890 if (event.GetKeyCode() == WXK_ESCAPE)
891 {
892 ((wxPreviewFrame*) GetParent())->Close(true);
893 return;
894 }
895 else if (event.GetKeyCode() == WXK_TAB)
896 {
897 controlBar->OnGoto();
898 return;
899 }
900 else if (event.GetKeyCode() == WXK_RETURN)
901 {
902 controlBar->OnPrint();
903 return;
904 }
905
906 if (!event.ControlDown())
907 {
908 event.Skip();
909 return;
910 }
911
912 switch(event.GetKeyCode())
913 {
914 case WXK_PAGEDOWN:
915 controlBar->OnNext(); break;
916 case WXK_PAGEUP:
917 controlBar->OnPrevious(); break;
918 case WXK_HOME:
919 controlBar->OnFirst(); break;
920 case WXK_END:
921 controlBar->OnLast(); break;
922 default:
923 event.Skip();
924 }
925 }
926
927 #if wxUSE_MOUSEWHEEL
928
929 void wxPreviewCanvas::OnMouseWheel(wxMouseEvent& event)
930 {
931 wxPreviewControlBar *
932 controlBar = wxStaticCast(GetParent(), wxPreviewFrame)->GetControlBar();
933
934 if ( controlBar )
935 {
936 if ( event.ControlDown() && event.GetWheelRotation() != 0 )
937 {
938 int currentZoom = controlBar->GetZoomControl();
939
940 int delta;
941 if ( currentZoom < 100 )
942 delta = 5;
943 else if ( currentZoom <= 120 )
944 delta = 10;
945 else
946 delta = 50;
947
948 if ( event.GetWheelRotation() > 0 )
949 delta = -delta;
950
951 int newZoom = currentZoom + delta;
952 if ( newZoom < 10 )
953 newZoom = 10;
954 if ( newZoom > 200 )
955 newZoom = 200;
956 if ( newZoom != currentZoom )
957 {
958 controlBar->SetZoomControl(newZoom);
959 m_printPreview->SetZoom(newZoom);
960 Refresh();
961 }
962 return;
963 }
964 }
965
966 event.Skip();
967 }
968
969 #endif // wxUSE_MOUSEWHEEL
970
971 //----------------------------------------------------------------------------
972 // wxPreviewControlBar
973 //----------------------------------------------------------------------------
974
975 IMPLEMENT_CLASS(wxPreviewControlBar, wxWindow)
976
977 BEGIN_EVENT_TABLE(wxPreviewControlBar, wxPanel)
978 EVT_BUTTON(wxID_PREVIEW_CLOSE, wxPreviewControlBar::OnWindowClose)
979 EVT_BUTTON(wxID_PREVIEW_PRINT, wxPreviewControlBar::OnPrintButton)
980 EVT_BUTTON(wxID_PREVIEW_PREVIOUS, wxPreviewControlBar::OnPreviousButton)
981 EVT_BUTTON(wxID_PREVIEW_NEXT, wxPreviewControlBar::OnNextButton)
982 EVT_BUTTON(wxID_PREVIEW_FIRST, wxPreviewControlBar::OnFirstButton)
983 EVT_BUTTON(wxID_PREVIEW_LAST, wxPreviewControlBar::OnLastButton)
984 EVT_BUTTON(wxID_PREVIEW_GOTO, wxPreviewControlBar::OnGotoButton)
985 EVT_CHOICE(wxID_PREVIEW_ZOOM, wxPreviewControlBar::OnZoom)
986 EVT_PAINT(wxPreviewControlBar::OnPaint)
987 END_EVENT_TABLE()
988
989 wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase *preview, long buttons,
990 wxWindow *parent, const wxPoint& pos, const wxSize& size,
991 long style, const wxString& name):
992 wxPanel(parent, wxID_ANY, pos, size, style, name)
993 {
994 m_printPreview = preview;
995 m_closeButton = (wxButton *) NULL;
996 m_nextPageButton = (wxButton *) NULL;
997 m_previousPageButton = (wxButton *) NULL;
998 m_printButton = (wxButton *) NULL;
999 m_zoomControl = (wxChoice *) NULL;
1000 m_buttonFlags = buttons;
1001 }
1002
1003 wxPreviewControlBar::~wxPreviewControlBar()
1004 {
1005 }
1006
1007 void wxPreviewControlBar::OnPaint(wxPaintEvent& WXUNUSED(event))
1008 {
1009 wxPaintDC dc(this);
1010
1011 int w, h;
1012 GetSize(&w, &h);
1013 dc.SetPen(*wxBLACK_PEN);
1014 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1015 dc.DrawLine( 0, h-1, w, h-1 );
1016 }
1017
1018 void wxPreviewControlBar::OnWindowClose(wxCommandEvent& WXUNUSED(event))
1019 {
1020 wxPreviewFrame *frame = (wxPreviewFrame *)GetParent();
1021 frame->Close(true);
1022 }
1023
1024 void wxPreviewControlBar::OnPrint(void)
1025 {
1026 wxPrintPreviewBase *preview = GetPrintPreview();
1027 preview->Print(true);
1028 }
1029
1030 void wxPreviewControlBar::OnNext(void)
1031 {
1032 wxPrintPreviewBase *preview = GetPrintPreview();
1033 if (preview)
1034 {
1035 int currentPage = preview->GetCurrentPage();
1036 if ((preview->GetMaxPage() > 0) &&
1037 (currentPage < preview->GetMaxPage()) &&
1038 preview->GetPrintout()->HasPage(currentPage + 1))
1039 {
1040 preview->SetCurrentPage(currentPage + 1);
1041 }
1042 }
1043 }
1044
1045 void wxPreviewControlBar::OnPrevious(void)
1046 {
1047 wxPrintPreviewBase *preview = GetPrintPreview();
1048 if (preview)
1049 {
1050 int currentPage = preview->GetCurrentPage();
1051 if ((preview->GetMinPage() > 0) &&
1052 (currentPage > preview->GetMinPage()) &&
1053 preview->GetPrintout()->HasPage(currentPage - 1))
1054 {
1055 preview->SetCurrentPage(currentPage - 1);
1056 }
1057 }
1058 }
1059
1060 void wxPreviewControlBar::OnFirst(void)
1061 {
1062 wxPrintPreviewBase *preview = GetPrintPreview();
1063 if (preview)
1064 {
1065 int currentPage = preview->GetMinPage();
1066 if (preview->GetPrintout()->HasPage(currentPage))
1067 {
1068 preview->SetCurrentPage(currentPage);
1069 }
1070 }
1071 }
1072
1073 void wxPreviewControlBar::OnLast(void)
1074 {
1075 wxPrintPreviewBase *preview = GetPrintPreview();
1076 if (preview)
1077 {
1078 int currentPage = preview->GetMaxPage();
1079 if (preview->GetPrintout()->HasPage(currentPage))
1080 {
1081 preview->SetCurrentPage(currentPage);
1082 }
1083 }
1084 }
1085
1086 void wxPreviewControlBar::OnGoto(void)
1087 {
1088 wxPrintPreviewBase *preview = GetPrintPreview();
1089 if (preview)
1090 {
1091 long currentPage;
1092
1093 if (preview->GetMinPage() > 0)
1094 {
1095 wxString strPrompt;
1096 wxString strPage;
1097
1098 strPrompt.Printf( _("Enter a page number between %d and %d:"),
1099 preview->GetMinPage(), preview->GetMaxPage());
1100 strPage.Printf( wxT("%d"), preview->GetCurrentPage() );
1101
1102 strPage =
1103 wxGetTextFromUser( strPrompt, _("Goto Page"), strPage, GetParent());
1104
1105 if ( strPage.ToLong( &currentPage ) )
1106 if (preview->GetPrintout()->HasPage(currentPage))
1107 {
1108 preview->SetCurrentPage(currentPage);
1109 }
1110 }
1111 }
1112 }
1113
1114 void wxPreviewControlBar::OnZoom(wxCommandEvent& WXUNUSED(event))
1115 {
1116 int zoom = GetZoomControl();
1117 if (GetPrintPreview())
1118 GetPrintPreview()->SetZoom(zoom);
1119 }
1120
1121 void wxPreviewControlBar::CreateButtons()
1122 {
1123 SetSize(0, 0, 400, 40);
1124
1125 wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL );
1126
1127 m_closeButton = new wxButton( this, wxID_PREVIEW_CLOSE, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 );
1128 item0->Add( m_closeButton, 0, wxALIGN_CENTRE|wxALL, 5 );
1129
1130 if (m_buttonFlags & wxPREVIEW_PRINT)
1131 {
1132 m_printButton = new wxButton( this, wxID_PREVIEW_PRINT, _("&Print..."), wxDefaultPosition, wxDefaultSize, 0 );
1133 item0->Add( m_printButton, 0, wxALIGN_CENTRE|wxALL, 5 );
1134 }
1135
1136 // Exact-fit buttons are too tiny on wxUniversal
1137 int navButtonStyle;
1138 wxSize navButtonSize;
1139 #ifdef __WXUNIVERSAL__
1140 navButtonStyle = 0;
1141 navButtonSize = wxSize(40, m_closeButton->GetSize().y);
1142 #else
1143 navButtonStyle = wxBU_EXACTFIT;
1144 navButtonSize = wxDefaultSize;
1145 #endif
1146
1147 if (m_buttonFlags & wxPREVIEW_FIRST)
1148 {
1149 m_firstPageButton = new wxButton( this, wxID_PREVIEW_FIRST, _("|<<"), wxDefaultPosition, navButtonSize, navButtonStyle );
1150 item0->Add( m_firstPageButton, 0, wxALIGN_CENTRE|wxALL, 5 );
1151 }
1152
1153 if (m_buttonFlags & wxPREVIEW_PREVIOUS)
1154 {
1155 m_previousPageButton = new wxButton( this, wxID_PREVIEW_PREVIOUS, _("<<"), wxDefaultPosition, navButtonSize, navButtonStyle );
1156 item0->Add( m_previousPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 );
1157 }
1158
1159 if (m_buttonFlags & wxPREVIEW_NEXT)
1160 {
1161 m_nextPageButton = new wxButton( this, wxID_PREVIEW_NEXT, _(">>"), wxDefaultPosition, navButtonSize, navButtonStyle );
1162 item0->Add( m_nextPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 );
1163 }
1164
1165 if (m_buttonFlags & wxPREVIEW_LAST)
1166 {
1167 m_lastPageButton = new wxButton( this, wxID_PREVIEW_LAST, _(">>|"), wxDefaultPosition, navButtonSize, navButtonStyle );
1168 item0->Add( m_lastPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 );
1169 }
1170
1171 if (m_buttonFlags & wxPREVIEW_GOTO)
1172 {
1173 m_gotoPageButton = new wxButton( this, wxID_PREVIEW_GOTO, _("&Goto..."), wxDefaultPosition, wxDefaultSize, 0 );
1174 item0->Add( m_gotoPageButton, 0, wxALIGN_CENTRE|wxALL, 5 );
1175 }
1176
1177 if (m_buttonFlags & wxPREVIEW_ZOOM)
1178 {
1179 wxString choices[] =
1180 {
1181 wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"),
1182 wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"),
1183 wxT("120%"), wxT("150%"), wxT("200%")
1184 };
1185 int n = WXSIZEOF(choices);
1186
1187 m_zoomControl = new wxChoice( this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0 );
1188 item0->Add( m_zoomControl, 0, wxALIGN_CENTRE|wxALL, 5 );
1189 SetZoomControl(m_printPreview->GetZoom());
1190 }
1191
1192 SetSizer(item0);
1193 item0->Fit(this);
1194 }
1195
1196 void wxPreviewControlBar::SetZoomControl(int zoom)
1197 {
1198 if (m_zoomControl)
1199 {
1200 int n, count = m_zoomControl->GetCount();
1201 long val;
1202 for (n=0; n<count; n++)
1203 {
1204 if (m_zoomControl->GetString(n).BeforeFirst(wxT('%')).ToLong(&val) &&
1205 (val >= long(zoom)))
1206 {
1207 m_zoomControl->SetSelection(n);
1208 return;
1209 }
1210 }
1211
1212 m_zoomControl->SetSelection(count-1);
1213 }
1214 }
1215
1216 int wxPreviewControlBar::GetZoomControl()
1217 {
1218 if (m_zoomControl && (m_zoomControl->GetStringSelection() != wxEmptyString))
1219 {
1220 long val;
1221 if (m_zoomControl->GetStringSelection().BeforeFirst(wxT('%')).ToLong(&val))
1222 return int(val);
1223 }
1224
1225 return 0;
1226 }
1227
1228
1229 /*
1230 * Preview frame
1231 */
1232
1233 IMPLEMENT_CLASS(wxPreviewFrame, wxFrame)
1234
1235 BEGIN_EVENT_TABLE(wxPreviewFrame, wxFrame)
1236 EVT_CLOSE(wxPreviewFrame::OnCloseWindow)
1237 END_EVENT_TABLE()
1238
1239 wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase *preview, wxWindow *parent, const wxString& title,
1240 const wxPoint& pos, const wxSize& size, long style, const wxString& name):
1241 wxFrame(parent, wxID_ANY, title, pos, size, style, name)
1242 {
1243 m_printPreview = preview;
1244 m_controlBar = NULL;
1245 m_previewCanvas = NULL;
1246 m_windowDisabler = NULL;
1247
1248 // Give the application icon
1249 #ifdef __WXMSW__
1250 wxFrame* topFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
1251 if (topFrame)
1252 SetIcon(topFrame->GetIcon());
1253 #endif
1254 }
1255
1256 wxPreviewFrame::~wxPreviewFrame()
1257 {
1258 }
1259
1260 void wxPreviewFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
1261 {
1262 if (m_windowDisabler)
1263 delete m_windowDisabler;
1264
1265 // Need to delete the printout and the print preview
1266 wxPrintout *printout = m_printPreview->GetPrintout();
1267 if (printout)
1268 {
1269 delete printout;
1270 m_printPreview->SetPrintout(NULL);
1271 m_printPreview->SetCanvas(NULL);
1272 m_printPreview->SetFrame(NULL);
1273 }
1274 delete m_printPreview;
1275
1276 Destroy();
1277 }
1278
1279 void wxPreviewFrame::Initialize()
1280 {
1281 #if wxUSE_STATUSBAR
1282 CreateStatusBar();
1283 #endif
1284 CreateCanvas();
1285 CreateControlBar();
1286
1287 m_printPreview->SetCanvas(m_previewCanvas);
1288 m_printPreview->SetFrame(this);
1289
1290 wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL );
1291
1292 item0->Add( m_controlBar, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 );
1293 item0->Add( m_previewCanvas, 1, wxGROW|wxALIGN_CENTER_VERTICAL, 5 );
1294
1295 SetAutoLayout( true );
1296 SetSizer( item0 );
1297
1298 m_windowDisabler = new wxWindowDisabler(this);
1299
1300 Layout();
1301
1302 m_printPreview->AdjustScrollbars(m_previewCanvas);
1303 m_previewCanvas->SetFocus();
1304 m_controlBar->SetFocus();
1305 }
1306
1307 void wxPreviewFrame::CreateCanvas()
1308 {
1309 m_previewCanvas = new wxPreviewCanvas(m_printPreview, this);
1310 }
1311
1312 void wxPreviewFrame::CreateControlBar()
1313 {
1314 long buttons = wxPREVIEW_DEFAULT;
1315 if (m_printPreview->GetPrintoutForPrinting())
1316 buttons |= wxPREVIEW_PRINT;
1317
1318 m_controlBar = new wxPreviewControlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400, 40));
1319 m_controlBar->CreateButtons();
1320 }
1321
1322 /*
1323 * Print preview
1324 */
1325
1326 IMPLEMENT_CLASS(wxPrintPreviewBase, wxObject)
1327
1328 wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout,
1329 wxPrintout *printoutForPrinting,
1330 wxPrintData *data)
1331 {
1332 if (data)
1333 m_printDialogData = (*data);
1334
1335 Init(printout, printoutForPrinting);
1336 }
1337
1338 wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout,
1339 wxPrintout *printoutForPrinting,
1340 wxPrintDialogData *data)
1341 {
1342 if (data)
1343 m_printDialogData = (*data);
1344
1345 Init(printout, printoutForPrinting);
1346 }
1347
1348 void wxPrintPreviewBase::Init(wxPrintout *printout,
1349 wxPrintout *printoutForPrinting)
1350 {
1351 m_isOk = true;
1352 m_previewPrintout = printout;
1353 if (m_previewPrintout)
1354 m_previewPrintout->SetIsPreview(true);
1355
1356 m_printPrintout = printoutForPrinting;
1357
1358 m_previewCanvas = NULL;
1359 m_previewFrame = NULL;
1360 m_previewBitmap = NULL;
1361 m_currentPage = 1;
1362 m_currentZoom = 70;
1363 m_topMargin = 40;
1364 m_leftMargin = 40;
1365 m_pageWidth = 0;
1366 m_pageHeight = 0;
1367 m_printingPrepared = false;
1368 m_minPage = 1;
1369 m_maxPage = 1;
1370 }
1371
1372 wxPrintPreviewBase::~wxPrintPreviewBase()
1373 {
1374 if (m_previewPrintout)
1375 delete m_previewPrintout;
1376 if (m_previewBitmap)
1377 delete m_previewBitmap;
1378 if (m_printPrintout)
1379 delete m_printPrintout;
1380 }
1381
1382 bool wxPrintPreviewBase::SetCurrentPage(int pageNum)
1383 {
1384 if (m_currentPage == pageNum)
1385 return true;
1386
1387 m_currentPage = pageNum;
1388 if (m_previewBitmap)
1389 {
1390 delete m_previewBitmap;
1391 m_previewBitmap = NULL;
1392 }
1393
1394 if (m_previewCanvas)
1395 {
1396 AdjustScrollbars(m_previewCanvas);
1397
1398 if (!RenderPage(pageNum))
1399 return false;
1400 m_previewCanvas->Refresh();
1401 m_previewCanvas->SetFocus();
1402 }
1403 return true;
1404 }
1405
1406 int wxPrintPreviewBase::GetCurrentPage() const
1407 { return m_currentPage; }
1408 void wxPrintPreviewBase::SetPrintout(wxPrintout *printout)
1409 { m_previewPrintout = printout; }
1410 wxPrintout *wxPrintPreviewBase::GetPrintout() const
1411 { return m_previewPrintout; }
1412 wxPrintout *wxPrintPreviewBase::GetPrintoutForPrinting() const
1413 { return m_printPrintout; }
1414 void wxPrintPreviewBase::SetFrame(wxFrame *frame)
1415 { m_previewFrame = frame; }
1416 void wxPrintPreviewBase::SetCanvas(wxPreviewCanvas *canvas)
1417 { m_previewCanvas = canvas; }
1418 wxFrame *wxPrintPreviewBase::GetFrame() const
1419 { return m_previewFrame; }
1420 wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const
1421 { return m_previewCanvas; }
1422
1423 void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect)
1424 {
1425 // Calculate the rectangles for the printable area of the page and the
1426 // entire paper as they appear on the canvas on-screen.
1427 int canvasWidth, canvasHeight;
1428 canvas->GetSize(&canvasWidth, &canvasHeight);
1429
1430 float zoomScale = float(m_currentZoom) / 100;
1431 float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX;
1432 float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY;
1433
1434 wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels();
1435 wxCoord devicePrintableWidth, devicePrintableHeight;
1436 m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight);
1437 float scaleX = screenPrintableWidth / devicePrintableWidth;
1438 float scaleY = screenPrintableHeight / devicePrintableHeight;
1439 paperRect.width = wxCoord(scaleX * devicePaperRect.width);
1440 paperRect.height = wxCoord(scaleY * devicePaperRect.height);
1441
1442 paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0);
1443 if (paperRect.x < m_leftMargin)
1444 paperRect.x = m_leftMargin;
1445 paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0);
1446 if (paperRect.y < m_topMargin)
1447 paperRect.y = m_topMargin;
1448
1449 pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x);
1450 pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y);
1451 pageRect.width = wxCoord(screenPrintableWidth);
1452 pageRect.height = wxCoord(screenPrintableHeight);
1453 }
1454
1455
1456 bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc)
1457 {
1458 DrawBlankPage(canvas, dc);
1459
1460 if (!m_previewBitmap)
1461 if (!RenderPage(m_currentPage))
1462 return false;
1463 if (!m_previewBitmap)
1464 return false;
1465 if (!canvas)
1466 return false;
1467
1468 wxRect pageRect, paperRect;
1469 CalcRects(canvas, pageRect, paperRect);
1470 wxMemoryDC temp_dc;
1471 temp_dc.SelectObject(*m_previewBitmap);
1472
1473 dc.Blit(pageRect.x, pageRect.y,
1474 m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0);
1475
1476 temp_dc.SelectObject(wxNullBitmap);
1477 return true;
1478 }
1479
1480 // Adjusts the scrollbars for the current scale
1481 void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas)
1482 {
1483 if (!canvas)
1484 return ;
1485
1486 wxRect pageRect, paperRect;
1487 CalcRects(canvas, pageRect, paperRect);
1488 int totalWidth = paperRect.width + 2 * m_leftMargin;
1489 int totalHeight = paperRect.height + 2 * m_topMargin;
1490 int scrollUnitsX = totalWidth / 10;
1491 int scrollUnitsY = totalHeight / 10;
1492 wxSize virtualSize = canvas->GetVirtualSize();
1493 if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight)
1494 canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true);
1495 }
1496
1497 bool wxPrintPreviewBase::RenderPageIntoDC(wxDC& dc, int pageNum)
1498 {
1499 m_previewPrintout->SetDC(&dc);
1500 m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight);
1501
1502 // Need to delay OnPreparePrinting() until here, so we have enough
1503 // information.
1504 if (!m_printingPrepared)
1505 {
1506 m_previewPrintout->OnPreparePrinting();
1507 int selFrom, selTo;
1508 m_previewPrintout->GetPageInfo(&m_minPage, &m_maxPage, &selFrom, &selTo);
1509 m_printingPrepared = true;
1510 }
1511
1512 m_previewPrintout->OnBeginPrinting();
1513
1514 if (!m_previewPrintout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage()))
1515 {
1516 wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK);
1517 return false;
1518 }
1519
1520 m_previewPrintout->OnPrintPage(pageNum);
1521 m_previewPrintout->OnEndDocument();
1522 m_previewPrintout->OnEndPrinting();
1523
1524 m_previewPrintout->SetDC(NULL);
1525
1526 return true;
1527 }
1528
1529 bool wxPrintPreviewBase::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum)
1530 {
1531 #if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
1532 // try high quality rendering first:
1533 static bool s_hqPreviewFailed = false;
1534 if ( !s_hqPreviewFailed )
1535 {
1536 wxPrinterDC printerDC(m_printDialogData.GetPrintData());
1537 if ( RenderPageIntoBitmapHQ(this,
1538 &wxPrintPreviewBase::RenderPageIntoDC,
1539 printerDC,
1540 bmp, pageNum,
1541 m_pageWidth, m_pageHeight) )
1542 {
1543 return true;
1544 }
1545 else
1546 {
1547 wxLogTrace(_T("printing"),
1548 _T("high-quality preview failed, falling back to normal"));
1549 s_hqPreviewFailed = true; // don't bother re-trying
1550 }
1551 }
1552 #endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
1553
1554 wxMemoryDC memoryDC;
1555 memoryDC.SelectObject(bmp);
1556 memoryDC.Clear();
1557
1558 return RenderPageIntoDC(memoryDC, pageNum);
1559 }
1560
1561 bool wxPrintPreviewBase::RenderPage(int pageNum)
1562 {
1563 wxBusyCursor busy;
1564
1565 if (!m_previewCanvas)
1566 {
1567 wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!"));
1568 return false;
1569 }
1570
1571 wxRect pageRect, paperRect;
1572 CalcRects(m_previewCanvas, pageRect, paperRect);
1573
1574 if (!m_previewBitmap)
1575 {
1576 m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height);
1577
1578 if (!m_previewBitmap || !m_previewBitmap->Ok())
1579 {
1580 if (m_previewBitmap) {
1581 delete m_previewBitmap;
1582 m_previewBitmap = NULL;
1583 }
1584 wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK);
1585 return false;
1586 }
1587 }
1588
1589 if ( !RenderPageIntoBitmap(*m_previewBitmap, pageNum) )
1590 {
1591 wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK);
1592
1593 delete m_previewBitmap;
1594 m_previewBitmap = NULL;
1595 return false;
1596 }
1597
1598 #if wxUSE_STATUSBAR
1599 wxString status;
1600 if (m_maxPage != 0)
1601 status = wxString::Format(_("Page %d of %d"), pageNum, m_maxPage);
1602 else
1603 status = wxString::Format(_("Page %d"), pageNum);
1604
1605 if (m_previewFrame)
1606 m_previewFrame->SetStatusText(status);
1607 #endif
1608
1609 return true;
1610 }
1611
1612 bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc)
1613 {
1614 wxRect pageRect, paperRect;
1615
1616 CalcRects(canvas, pageRect, paperRect);
1617
1618 // Draw shadow, allowing for 1-pixel border AROUND the actual paper
1619 wxCoord shadowOffset = 4;
1620
1621 dc.SetPen(*wxBLACK_PEN);
1622 dc.SetBrush(*wxBLACK_BRUSH);
1623 dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1,
1624 paperRect.width, shadowOffset);
1625
1626 dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset,
1627 shadowOffset, paperRect.height);
1628
1629 // Draw blank page allowing for 1-pixel border AROUND the actual paper
1630 dc.SetPen(*wxBLACK_PEN);
1631 dc.SetBrush(*wxWHITE_BRUSH);
1632 dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1,
1633 paperRect.width + 3, paperRect.height + 2);
1634
1635 return true;
1636 }
1637
1638 void wxPrintPreviewBase::SetZoom(int percent)
1639 {
1640 if (m_currentZoom == percent)
1641 return;
1642
1643 m_currentZoom = percent;
1644 if (m_previewBitmap)
1645 {
1646 delete m_previewBitmap;
1647 m_previewBitmap = NULL;
1648 }
1649
1650 if (m_previewCanvas)
1651 {
1652 AdjustScrollbars(m_previewCanvas);
1653 RenderPage(m_currentPage);
1654 ((wxScrolledWindow *) m_previewCanvas)->Scroll(0, 0);
1655 m_previewCanvas->ClearBackground();
1656 m_previewCanvas->Refresh();
1657 m_previewCanvas->SetFocus();
1658 }
1659 }
1660
1661 wxPrintDialogData& wxPrintPreviewBase::GetPrintDialogData()
1662 {
1663 return m_printDialogData;
1664 }
1665
1666 int wxPrintPreviewBase::GetZoom() const
1667 { return m_currentZoom; }
1668 int wxPrintPreviewBase::GetMaxPage() const
1669 { return m_maxPage; }
1670 int wxPrintPreviewBase::GetMinPage() const
1671 { return m_minPage; }
1672 bool wxPrintPreviewBase::IsOk() const
1673 { return m_isOk; }
1674 void wxPrintPreviewBase::SetOk(bool ok)
1675 { m_isOk = ok; }
1676
1677 //----------------------------------------------------------------------------
1678 // wxPrintPreview
1679 //----------------------------------------------------------------------------
1680
1681 IMPLEMENT_CLASS(wxPrintPreview, wxPrintPreviewBase)
1682
1683 wxPrintPreview::wxPrintPreview(wxPrintout *printout,
1684 wxPrintout *printoutForPrinting,
1685 wxPrintDialogData *data) :
1686 wxPrintPreviewBase( printout, printoutForPrinting, data )
1687 {
1688 m_pimpl = wxPrintFactory::GetFactory()->
1689 CreatePrintPreview( printout, printoutForPrinting, data );
1690 }
1691
1692 wxPrintPreview::wxPrintPreview(wxPrintout *printout,
1693 wxPrintout *printoutForPrinting,
1694 wxPrintData *data ) :
1695 wxPrintPreviewBase( printout, printoutForPrinting, data )
1696 {
1697 m_pimpl = wxPrintFactory::GetFactory()->
1698 CreatePrintPreview( printout, printoutForPrinting, data );
1699 }
1700
1701 wxPrintPreview::~wxPrintPreview()
1702 {
1703 delete m_pimpl;
1704
1705 // don't delete twice
1706 m_printPrintout = NULL;
1707 m_previewPrintout = NULL;
1708 m_previewBitmap = NULL;
1709 }
1710
1711 bool wxPrintPreview::SetCurrentPage(int pageNum)
1712 {
1713 return m_pimpl->SetCurrentPage( pageNum );
1714 }
1715
1716 int wxPrintPreview::GetCurrentPage() const
1717 {
1718 return m_pimpl->GetCurrentPage();
1719 }
1720
1721 void wxPrintPreview::SetPrintout(wxPrintout *printout)
1722 {
1723 m_pimpl->SetPrintout( printout );
1724 }
1725
1726 wxPrintout *wxPrintPreview::GetPrintout() const
1727 {
1728 return m_pimpl->GetPrintout();
1729 }
1730
1731 wxPrintout *wxPrintPreview::GetPrintoutForPrinting() const
1732 {
1733 return m_pimpl->GetPrintoutForPrinting();
1734 }
1735
1736 void wxPrintPreview::SetFrame(wxFrame *frame)
1737 {
1738 m_pimpl->SetFrame( frame );
1739 }
1740
1741 void wxPrintPreview::SetCanvas(wxPreviewCanvas *canvas)
1742 {
1743 m_pimpl->SetCanvas( canvas );
1744 }
1745
1746 wxFrame *wxPrintPreview::GetFrame() const
1747 {
1748 return m_pimpl->GetFrame();
1749 }
1750
1751 wxPreviewCanvas *wxPrintPreview::GetCanvas() const
1752 {
1753 return m_pimpl->GetCanvas();
1754 }
1755
1756 bool wxPrintPreview::PaintPage(wxPreviewCanvas *canvas, wxDC& dc)
1757 {
1758 return m_pimpl->PaintPage( canvas, dc );
1759 }
1760
1761 bool wxPrintPreview::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc)
1762 {
1763 return m_pimpl->DrawBlankPage( canvas, dc );
1764 }
1765
1766 void wxPrintPreview::AdjustScrollbars(wxPreviewCanvas *canvas)
1767 {
1768 m_pimpl->AdjustScrollbars( canvas );
1769 }
1770
1771 bool wxPrintPreview::RenderPage(int pageNum)
1772 {
1773 return m_pimpl->RenderPage( pageNum );
1774 }
1775
1776 void wxPrintPreview::SetZoom(int percent)
1777 {
1778 m_pimpl->SetZoom( percent );
1779 }
1780
1781 int wxPrintPreview::GetZoom() const
1782 {
1783 return m_pimpl->GetZoom();
1784 }
1785
1786 wxPrintDialogData& wxPrintPreview::GetPrintDialogData()
1787 {
1788 return m_pimpl->GetPrintDialogData();
1789 }
1790
1791 int wxPrintPreview::GetMaxPage() const
1792 {
1793 return m_pimpl->GetMaxPage();
1794 }
1795
1796 int wxPrintPreview::GetMinPage() const
1797 {
1798 return m_pimpl->GetMinPage();
1799 }
1800
1801 bool wxPrintPreview::IsOk() const
1802 {
1803 return m_pimpl->Ok();
1804 }
1805
1806 void wxPrintPreview::SetOk(bool ok)
1807 {
1808 m_pimpl->SetOk( ok );
1809 }
1810
1811 bool wxPrintPreview::Print(bool interactive)
1812 {
1813 return m_pimpl->Print( interactive );
1814 }
1815
1816 void wxPrintPreview::DetermineScaling()
1817 {
1818 m_pimpl->DetermineScaling();
1819 }
1820
1821 //----------------------------------------------------------------------------
1822 // experimental backport of high-quality preview on Windows
1823 //----------------------------------------------------------------------------
1824
1825 #if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
1826
1827 // The preview, as implemented in wxPrintPreviewBase (and as used prior to wx3)
1828 // is inexact: it uses screen DC, which has much lower resolution and has
1829 // other properties different from printer DC, so the preview is not quite
1830 // right.
1831 //
1832 // To make matters worse, if the application depends heavily on GetTextExtent()
1833 // or does text layout itself, the output in preview and on paper can be very
1834 // different. In particular, wxHtmlEasyPrinting is affected and the preview
1835 // can be easily off by several pages.
1836 //
1837 // To fix this, we attempt to render the preview into high-resolution bitmap
1838 // using DC with same resolution etc. as the printer DC. This takes lot of
1839 // memory, so the code is more complicated than it could be, but the results
1840 // are much better.
1841 //
1842 // Finally, this code is specific to wxMSW, because it doesn't make sense to
1843 // bother with it on other platforms. Both OSX and modern GNOME/GTK+
1844 // environments have builtin accurate preview (that applications should use
1845 // instead) and the differences between screen and printer DC in wxGTK are so
1846 // large than this trick doesn't help at all.
1847
1848 namespace
1849 {
1850
1851 // If there's not enough memory, we need to render the preview in parts.
1852 // Unfortunately we cannot simply use wxMemoryDC, because it reports its size
1853 // as bitmap's size, and we need to use smaller bitmap while still reporting
1854 // original ("correct") DC size, because printing code frequently uses
1855 // GetSize() to determine scaling factor. This DC class handles this.
1856
1857 class PageFragmentDC : public wxMemoryDC
1858 {
1859 public:
1860 PageFragmentDC(wxDC *printer, wxBitmap& bmp,
1861 const wxPoint& offset,
1862 const wxSize& fullSize)
1863 : wxMemoryDC(printer),
1864 m_offset(offset),
1865 m_fullSize(fullSize)
1866 {
1867 SetDeviceOrigin(0, 0);
1868 SelectObject(bmp);
1869 }
1870
1871 virtual void SetDeviceOrigin(wxCoord x, wxCoord y)
1872 {
1873 wxMemoryDC::SetDeviceOrigin(x - m_offset.x, y - m_offset.y);
1874 }
1875
1876 virtual void DoGetDeviceOrigin(wxCoord *x, wxCoord *y) const
1877 {
1878 wxMemoryDC::DoGetDeviceOrigin(x, y);
1879 if ( x ) *x += m_offset.x;
1880 if ( x ) *y += m_offset.y;
1881 }
1882
1883 virtual void DoGetSize(int *width, int *height) const
1884 {
1885 if ( width )
1886 *width = m_fullSize.x;
1887 if ( height )
1888 *height = m_fullSize.y;
1889 }
1890
1891 private:
1892 wxPoint m_offset;
1893 wxSize m_fullSize;
1894 };
1895
1896 // estimate how big chunks we can render, given available RAM
1897 long ComputeFragmentSize(long printerDepth,
1898 long width,
1899 long height)
1900 {
1901 // Compute the amount of memory needed to generate the preview.
1902 // Memory requirements of RenderPageFragment() are as follows:
1903 //
1904 // (memory DC - always)
1905 // width * height * printerDepth/8
1906 // (wxImage + wxDIB instance)
1907 // width * height * (3 + 4)
1908 // (this could be reduced to *3 if using wxGraphicsContext)
1909 //
1910 // So, given amount of memory M, we can render at most
1911 //
1912 // height = M / (width * (printerDepth/8 + F))
1913 //
1914 // where F is 3 or 7 depending on whether wxGraphicsContext is used or not
1915
1916 wxMemorySize memAvail = wxGetFreeMemory();
1917 if ( memAvail == -1 )
1918 {
1919 // we don't know; 10meg shouldn't be a problem hopefully
1920 memAvail = 10000000;
1921 }
1922 else
1923 {
1924 // limit ourselves to half of available RAM to have a margin for other
1925 // apps, for our rendering code, and for miscalculations
1926 memAvail /= 2;
1927 }
1928
1929 const float perPixel = float(printerDepth)/8 + (3 + 4);
1930
1931 const long perLine = long(width * perPixel);
1932 const long maxstep = (memAvail / perLine).GetValue();
1933 const long step = wxMin(height, maxstep);
1934
1935 wxLogTrace(_T("printing"),
1936 _T("using %liMB of RAM (%li lines) for preview, %li %lipx fragments"),
1937 long((memAvail >> 20).GetValue()),
1938 maxstep,
1939 (height+step-1) / step,
1940 step);
1941
1942 return step;
1943 }
1944
1945 } // anonymous namespace
1946
1947
1948 static bool RenderPageFragment(wxPrintPreviewBase *preview,
1949 RenderPageIntoDCFunc RenderPageIntoDC,
1950 float scaleX, float scaleY,
1951 int *nextFinalLine,
1952 wxPrinterDC& printer,
1953 wxMemoryDC& finalDC,
1954 const wxRect& rect,
1955 int pageWidth, int pageHeight,
1956 int pageNum)
1957 {
1958 // compute 'rect' equivalent in the small final bitmap:
1959 const wxRect smallRect(wxPoint(0, *nextFinalLine),
1960 wxPoint(int(rect.GetRight() * scaleX),
1961 int(rect.GetBottom() * scaleY)));
1962 wxLogTrace(_T("printing"),
1963 _T("rendering fragment of page %i: [%i,%i,%i,%i] scaled down to [%i,%i,%i,%i]"),
1964 pageNum,
1965 rect.x, rect.y, rect.GetRight(), rect.GetBottom(),
1966 smallRect.x, smallRect.y, smallRect.GetRight(), smallRect.GetBottom()
1967 );
1968
1969 // create DC and bitmap compatible with printer DC:
1970 wxBitmap large(rect.width, rect.height, printer);
1971 if ( !large.IsOk() )
1972 return false;
1973
1974 // render part of the page into it:
1975 {
1976 PageFragmentDC memoryDC(&printer, large,
1977 rect.GetPosition(),
1978 wxSize(pageWidth, pageHeight));
1979 if ( !memoryDC.IsOk() )
1980 return false;
1981
1982 memoryDC.Clear();
1983
1984 if ( !(preview->*RenderPageIntoDC)(memoryDC, pageNum) )
1985 return false;
1986 } // release bitmap from memoryDC
1987
1988 // now scale the rendered part down and blit it into final output:
1989
1990 wxImage img;
1991 {
1992 wxDIB dib(large);
1993 if ( !dib.IsOk() )
1994 return false;
1995 large = wxNullBitmap; // free memory a.s.a.p.
1996 img = dib.ConvertToImage();
1997 } // free the DIB now that it's no longer needed, too
1998
1999 if ( !img.IsOk() )
2000 return false;
2001
2002 img.Rescale(smallRect.width, smallRect.height, wxIMAGE_QUALITY_HIGH);
2003 if ( !img.IsOk() )
2004 return false;
2005
2006 wxBitmap bmp(img);
2007 if ( !bmp.IsOk() )
2008 return false;
2009
2010 img = wxNullImage;
2011 finalDC.DrawBitmap(bmp, smallRect.x, smallRect.y);
2012 if ( bmp.IsOk() )
2013 {
2014 *nextFinalLine += smallRect.height;
2015 return true;
2016 }
2017
2018 return false;
2019 }
2020
2021 static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview,
2022 RenderPageIntoDCFunc RenderPageIntoDC,
2023 wxPrinterDC& printerDC,
2024 wxBitmap& bmp, int pageNum,
2025 int pageWidth, int pageHeight)
2026 {
2027 wxLogTrace(_T("printing"), _T("rendering HQ preview of page %i"), pageNum);
2028
2029 if ( !printerDC.IsOk() )
2030 return false;
2031
2032 // compute scale factor
2033 const float scaleX = float(bmp.GetWidth()) / float(pageWidth);
2034 const float scaleY = float(bmp.GetHeight()) / float(pageHeight);
2035
2036 wxMemoryDC bmpDC;
2037 bmpDC.SelectObject(bmp);
2038 bmpDC.Clear();
2039
2040 const int initialStep = ComputeFragmentSize(printerDC.GetDepth(),
2041 pageWidth, pageHeight);
2042
2043 wxRect todo(0, 0, pageWidth, initialStep); // rect to render
2044 int nextFinalLine = 0; // first not-yet-rendered output line
2045
2046 while ( todo.y < pageHeight )
2047 {
2048 todo.SetBottom(wxMin(todo.GetBottom(), pageHeight - 1));
2049
2050 if ( !RenderPageFragment(preview, RenderPageIntoDC,
2051 scaleX, scaleY,
2052 &nextFinalLine,
2053 printerDC,
2054 bmpDC,
2055 todo,
2056 pageWidth, pageHeight,
2057 pageNum) )
2058 {
2059 if ( todo.height < 20 )
2060 {
2061 // something is very wrong if we can't render even at this
2062 // slow space, let's bail out and fall back to low quality
2063 // preview
2064 wxLogTrace(_T("printing"),
2065 _T("it seems that HQ preview doesn't work at all"));
2066 return false;
2067 }
2068
2069 // it's possible our memory calculation was off, or conditions
2070 // changed, or there's not enough _bitmap_ resources; try if using
2071 // smaller bitmap would help:
2072 todo.height /= 2;
2073
2074 wxLogTrace(_T("printing"),
2075 _T("preview of fragment failed, reducing height to %ipx"),
2076 todo.height);
2077
2078 continue; // retry at the same position again
2079 }
2080
2081 // move to the next segment
2082 todo.Offset(0, todo.height);
2083 }
2084
2085 return true;
2086 }
2087
2088 #endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW
2089
2090 #endif // wxUSE_PRINTING_ARCHITECTURE

  ViewVC Help
Powered by ViewVC 1.1.22