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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 64019 byte(s)
committing r3113 initial commit again...
1 william 31 /////////////////////////////////////////////////////////////////////////////
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