1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Printing framework base class implementation
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "prntbase.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
29 #include "wx/msgdlg.h"
30 #include "wx/layout.h"
31 #include "wx/choice.h"
32 #include "wx/button.h"
33 #include "wx/settings.h"
34 #include "wx/dcmemory.h"
35 #include "wx/stattext.h"
39 #include "wx/prntbase.h"
40 #include "wx/dcprint.h"
41 #include "wx/printdlg.h"
42 #include "wx/module.h"
51 // Clash with Windows header files
63 #if !USE_SHARED_LIBRARY
64 IMPLEMENT_CLASS(wxPrinterBase
, wxObject
)
65 IMPLEMENT_ABSTRACT_CLASS(wxPrintout
, wxObject
)
66 IMPLEMENT_CLASS(wxPreviewCanvas
, wxWindow
)
67 IMPLEMENT_CLASS(wxPreviewControlBar
, wxWindow
)
68 IMPLEMENT_CLASS(wxPreviewFrame
, wxFrame
)
69 IMPLEMENT_CLASS(wxPrintPreviewBase
, wxObject
)
70 IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperType
, wxObject
)
72 BEGIN_EVENT_TABLE(wxPrintAbortDialog
, wxDialog
)
73 EVT_BUTTON(wxID_CANCEL
, wxPrintAbortDialog::OnCancel
)
76 BEGIN_EVENT_TABLE(wxPreviewCanvas
, wxScrolledWindow
)
77 EVT_PAINT(wxPreviewCanvas::OnPaint
)
78 EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged
)
86 wxPrinterBase::wxPrinterBase(wxPrintData
*data
)
88 m_currentPrintout
= (wxPrintout
*) NULL
;
89 sm_abortWindow
= (wxWindow
*) NULL
;
92 m_printData
= (*data
);
95 wxWindow
*wxPrinterBase::sm_abortWindow
= (wxWindow
*) NULL
;
96 bool wxPrinterBase::sm_abortIt
= FALSE
;
98 wxPrinterBase::~wxPrinterBase()
102 void wxPrintAbortDialog::OnCancel(wxCommandEvent
& WXUNUSED(event
))
104 wxPrinterBase::sm_abortIt
= TRUE
;
105 wxPrinterBase::sm_abortWindow
->Show(FALSE
);
106 wxPrinterBase::sm_abortWindow
->Close(TRUE
);
107 wxPrinterBase::sm_abortWindow
= (wxWindow
*) NULL
;
110 wxWindow
*wxPrinterBase::CreateAbortWindow(wxWindow
*parent
, wxPrintout
*WXUNUSED(printout
))
112 wxPrintAbortDialog
*dialog
= new wxPrintAbortDialog(parent
, _("Printing"), wxPoint(0, 0), wxSize(400, 400), wxDEFAULT_DIALOG_STYLE
);
113 (void) new wxStaticText(dialog
, -1, _("Please wait..."), wxPoint(5, 5));
115 wxButton
*button
= new wxButton(dialog
, wxID_CANCEL
, _("Cancel"), wxPoint(5, 30));
118 button
->Centre(wxHORIZONTAL
);
124 void wxPrinterBase::ReportError(wxWindow
*parent
, wxPrintout
*WXUNUSED(printout
), char *message
)
126 wxMessageBox(message
, _("Printing Error"), wxOK
, parent
);
133 wxPrintout::wxPrintout(const wxString
& title
)
135 m_printoutTitle
= title
;
136 m_printoutDC
= (wxDC
*) NULL
;
139 m_pageWidthPixels
= 0;
140 m_pageHeightPixels
= 0;
148 wxPrintout::~wxPrintout()
152 bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage
), int WXUNUSED(endPage
))
154 return GetDC()->StartDoc(_("Printing"));
157 void wxPrintout::OnEndDocument()
162 void wxPrintout::OnBeginPrinting()
166 void wxPrintout::OnEndPrinting()
170 bool wxPrintout::HasPage(int page
)
175 void wxPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *fromPage
, int *toPage
)
187 wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase
*preview
, wxWindow
*parent
,
188 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
):
189 wxScrolledWindow(parent
, -1, pos
, size
, style
, name
)
191 m_printPreview
= preview
;
192 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
194 SetScrollbars(15, 18, 100, 100);
197 wxPreviewCanvas::~wxPreviewCanvas()
201 void wxPreviewCanvas::OnPaint(wxPaintEvent
& WXUNUSED(event
))
208 m_printPreview
->PaintPage(this, dc
);
212 // Responds to colour changes, and passes event on to children.
213 void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent
& event
)
215 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
218 // Propagate the event to the non-top-level children
219 wxWindow::OnSysColourChanged(event
);
223 * Preview control bar
226 BEGIN_EVENT_TABLE(wxPreviewControlBar
, wxPanel
)
227 EVT_BUTTON(wxID_PREVIEW_CLOSE
, wxPreviewControlBar::OnWindowClose
)
228 EVT_BUTTON(wxID_PREVIEW_PRINT
, wxPreviewControlBar::OnPrint
)
229 EVT_BUTTON(wxID_PREVIEW_PREVIOUS
, wxPreviewControlBar::OnPrevious
)
230 EVT_BUTTON(wxID_PREVIEW_NEXT
, wxPreviewControlBar::OnNext
)
231 EVT_CHOICE(wxID_PREVIEW_ZOOM
, wxPreviewControlBar::OnZoom
)
232 EVT_PAINT(wxPreviewControlBar::OnPaint
)
235 wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase
*preview
, long buttons
,
236 wxWindow
*parent
, const wxPoint
& pos
, const wxSize
& size
,
237 long style
, const wxString
& name
):
238 wxPanel(parent
, -1, pos
, size
, style
, name
)
240 m_printPreview
= preview
;
241 m_closeButton
= (wxButton
*) NULL
;
242 m_nextPageButton
= (wxButton
*) NULL
;
243 m_previousPageButton
= (wxButton
*) NULL
;
244 m_printButton
= (wxButton
*) NULL
;
245 m_zoomControl
= (wxChoice
*) NULL
;
246 m_buttonFlags
= buttons
;
249 wxPreviewControlBar::~wxPreviewControlBar()
253 void wxPreviewControlBar::OnPaint(wxPaintEvent
& WXUNUSED(event
))
259 dc
.SetPen(*wxBLACK_PEN
);
260 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
261 dc
.DrawLine( 0, h
-1, w
, h
-1 );
264 void wxPreviewControlBar::OnWindowClose(wxCommandEvent
& WXUNUSED(event
))
266 wxPreviewFrame
*frame
= (wxPreviewFrame
*)GetParent();
270 void wxPreviewControlBar::OnPrint(wxCommandEvent
& WXUNUSED(event
))
272 wxPrintPreviewBase
*preview
= GetPrintPreview();
273 preview
->Print(TRUE
);
276 void wxPreviewControlBar::OnNext(wxCommandEvent
& WXUNUSED(event
))
278 wxPrintPreviewBase
*preview
= GetPrintPreview();
281 int currentPage
= preview
->GetCurrentPage();
282 if ((preview
->GetMaxPage() > 0) &&
283 (currentPage
< preview
->GetMaxPage()) &&
284 preview
->GetPrintout()->HasPage(currentPage
+ 1))
286 preview
->SetCurrentPage(currentPage
+ 1);
291 void wxPreviewControlBar::OnPrevious(wxCommandEvent
& WXUNUSED(event
))
293 wxPrintPreviewBase
*preview
= GetPrintPreview();
296 int currentPage
= preview
->GetCurrentPage();
297 if ((preview
->GetMinPage() > 0) &&
298 (currentPage
> preview
->GetMinPage()) &&
299 preview
->GetPrintout()->HasPage(currentPage
- 1))
301 preview
->SetCurrentPage(currentPage
- 1);
306 void wxPreviewControlBar::OnZoom(wxCommandEvent
& WXUNUSED(event
))
308 int zoom
= GetZoomControl();
309 if (GetPrintPreview())
310 GetPrintPreview()->SetZoom(zoom
);
313 void wxPreviewControlBar::CreateButtons()
315 SetSize(0, 0, 400, 40);
324 wxFont buttonFont(fontSize, wxSWISS, wxNORMAL, wxBOLD);
328 int buttonWidth
= 65;
330 int buttonHeight
= -1;
332 int buttonHeight
= 24;
344 m_closeButton
= new wxButton(this, wxID_PREVIEW_CLOSE
, _("Close"),
345 wxPoint(x
, y
), wxSize(buttonWidth
, buttonHeight
));
347 x
+= gap
+ buttonWidth
;
349 if (m_buttonFlags
& wxPREVIEW_PRINT
)
351 m_printButton
= new wxButton(this, wxID_PREVIEW_PRINT
, _("Print..."), wxPoint(x
, y
),
352 wxSize(buttonWidth
, buttonHeight
));
353 x
+= gap
+ buttonWidth
;
356 if (m_buttonFlags
& wxPREVIEW_PREVIOUS
)
358 m_previousPageButton
= new wxButton(this, wxID_PREVIEW_PREVIOUS
, "<<", wxPoint(x
, y
),
359 wxSize(buttonWidth
, buttonHeight
));
360 x
+= gap
+ buttonWidth
;
363 if (m_buttonFlags
& wxPREVIEW_NEXT
)
365 m_nextPageButton
= new wxButton(this, wxID_PREVIEW_NEXT
, ">>",
366 wxPoint(x
, y
), wxSize(buttonWidth
, buttonHeight
));
367 x
+= gap
+ buttonWidth
;
370 // Yes, this look stupid, but this is because gcc gives up otherwise.
371 wxString
*choices
= new wxString
[23];
390 choices
[18] = "100%";
391 choices
[19] = "110%";
392 choices
[20] = "120%";
393 choices
[21] = "150%";
394 choices
[22] = "200%";
397 if (m_buttonFlags
& wxPREVIEW_ZOOM
)
399 m_zoomControl
= new wxChoice(this, wxID_PREVIEW_ZOOM
, wxPoint(x
, y
),
400 wxSize(100, -1), n
, (wxString
*)choices
);
401 SetZoomControl(m_printPreview
->GetZoom());
406 // m_closeButton->SetDefault();
409 void wxPreviewControlBar::SetZoomControl(int zoom
)
412 sprintf(buf
, "%d%%", zoom
);
414 m_zoomControl
->SetStringSelection(buf
);
417 int wxPreviewControlBar::GetZoomControl()
420 if (m_zoomControl
&& (m_zoomControl
->GetStringSelection() != ""))
422 strcpy(buf
, m_zoomControl
->GetStringSelection());
423 buf
[strlen(buf
) - 1] = 0;
424 return (int)atoi(buf
);
434 BEGIN_EVENT_TABLE(wxPreviewFrame
, wxFrame
)
435 EVT_CLOSE(wxPreviewFrame::OnCloseWindow
)
438 wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase
*preview
, wxFrame
*parent
, const wxString
& title
,
439 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
):
440 wxFrame(parent
, -1, title
, pos
, size
, style
, name
)
442 m_printPreview
= preview
;
444 m_previewCanvas
= NULL
;
447 wxPreviewFrame::~wxPreviewFrame()
451 void wxPreviewFrame::OnCloseWindow(wxCloseEvent
& event
)
455 // Need to delete the printout and the print preview
456 wxPrintout
*printout
= m_printPreview
->GetPrintout();
460 m_printPreview
->SetPrintout(NULL
);
461 m_printPreview
->SetCanvas(NULL
);
462 m_printPreview
->SetFrame(NULL
);
464 delete m_printPreview
;
469 void wxPreviewFrame::Initialize()
476 m_printPreview
->SetCanvas(m_previewCanvas
);
477 m_printPreview
->SetFrame(this);
479 // Set layout constraints here
481 // Control bar constraints
482 wxLayoutConstraints
*c1
= new wxLayoutConstraints
;
484 // m_controlBar->GetSize(&w, &h);
486 #if (defined(__WXMSW__) || defined(__WXGTK__))
492 c1
->left
.SameAs (this, wxLeft
);
493 c1
->top
.SameAs (this, wxTop
);
494 c1
->right
.SameAs (this, wxRight
);
495 c1
->height
.Absolute (h
);
497 m_controlBar
->SetConstraints(c1
);
499 // Canvas constraints
500 wxLayoutConstraints
*c2
= new wxLayoutConstraints
;
502 c2
->left
.SameAs (this, wxLeft
);
503 c2
->top
.Below (m_controlBar
);
504 c2
->right
.SameAs (this, wxRight
);
505 c2
->bottom
.SameAs (this, wxBottom
);
507 m_previewCanvas
->SetConstraints(c2
);
516 void wxPreviewFrame::CreateCanvas()
518 m_previewCanvas
= new wxPreviewCanvas(m_printPreview
, this);
521 void wxPreviewFrame::CreateControlBar()
523 long buttons
= wxPREVIEW_DEFAULT
;
524 if (m_printPreview
->GetPrintoutForPrinting())
525 buttons
|= wxPREVIEW_PRINT
;
527 m_controlBar
= new wxPreviewControlBar(m_printPreview
, buttons
, this, wxPoint(0, 0), wxSize(400, 40));
528 m_controlBar
->CreateButtons();
535 wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout
*printout
, wxPrintout
*printoutForPrinting
, wxPrintData
*data
)
538 m_previewPrintout
= printout
;
539 if (m_previewPrintout
)
540 m_previewPrintout
->SetIsPreview(TRUE
);
542 m_printPrintout
= printoutForPrinting
;
544 m_printData
= (*data
);
546 m_previewCanvas
= NULL
;
547 m_previewFrame
= NULL
;
548 m_previewBitmap
= NULL
;
556 printout
->OnPreparePrinting();
558 // Get some parameters from the printout, if defined
560 printout
->GetPageInfo(&m_minPage
, &m_maxPage
, &selFrom
, &selTo
);
563 wxPrintPreviewBase::~wxPrintPreviewBase()
565 if (m_previewPrintout
)
566 delete m_previewPrintout
;
568 delete m_previewBitmap
;
570 delete m_printPrintout
;
573 bool wxPrintPreviewBase::SetCurrentPage(int pageNum
)
575 if (m_currentPage
== pageNum
)
578 m_currentPage
= pageNum
;
581 delete m_previewBitmap
;
582 m_previewBitmap
= NULL
;
588 m_previewCanvas
->Refresh();
593 bool wxPrintPreviewBase::PaintPage(wxWindow
*canvas
, wxDC
& dc
)
595 DrawBlankPage(canvas
, dc
);
597 if (!m_previewBitmap
)
598 RenderPage(m_currentPage
);
600 if (!m_previewBitmap
)
606 int canvasWidth
, canvasHeight
;
607 canvas
->GetSize(&canvasWidth
, &canvasHeight
);
609 double zoomScale
= ((float)m_currentZoom
/(float)100);
610 double actualWidth
= (zoomScale
*m_pageWidth
*m_previewScale
);
611 // float actualHeight = (float)(zoomScale*m_pageHeight*m_previewScale);
613 int x
= (int) ((canvasWidth
- actualWidth
)/2.0);
614 if (x
< m_leftMargin
)
619 temp_dc
.SelectObject(*m_previewBitmap
);
621 dc
.Blit(x
, y
, m_previewBitmap
->GetWidth(), m_previewBitmap
->GetHeight(), &temp_dc
, 0, 0);
623 temp_dc
.SelectObject(wxNullBitmap
);
628 bool wxPrintPreviewBase::RenderPage(int pageNum
)
630 int canvasWidth
, canvasHeight
;
632 if (!m_previewCanvas
)
634 wxMessageBox(_("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!"),
635 _("Print Preview Failure"), wxOK
);
638 m_previewCanvas
->GetSize(&canvasWidth
, &canvasHeight
);
640 double zoomScale
= (m_currentZoom
/100.0);
641 int actualWidth
= (int)(zoomScale
*m_pageWidth
*m_previewScale
);
642 int actualHeight
= (int)(zoomScale
*m_pageHeight
*m_previewScale
);
644 int x
= (int)((canvasWidth
- actualWidth
)/2.0);
645 if (x
< m_leftMargin
)
647 // int y = m_topMargin;
650 if (!m_previewBitmap
)
652 m_previewBitmap
= new wxBitmap((int)actualWidth
, (int)actualHeight
);
653 if (!m_previewBitmap
|| !m_previewBitmap
->Ok())
656 delete m_previewBitmap
;
657 wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK
);
663 memoryDC
.SelectObject(*m_previewBitmap
);
667 m_previewPrintout
->SetDC(&memoryDC
);
668 m_previewPrintout
->SetPageSizePixels(m_pageWidth
, m_pageHeight
);
670 m_previewPrintout
->OnBeginPrinting();
673 if (!m_previewPrintout
->OnBeginDocument(m_printData
.GetFromPage(), m_printData
.GetToPage()))
675 wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK
);
677 memoryDC
.SelectObject(wxNullBitmap
);
679 delete m_previewBitmap
;
683 m_previewPrintout
->OnPrintPage(pageNum
);
684 m_previewPrintout
->OnEndDocument();
685 m_previewPrintout
->OnEndPrinting();
687 m_previewPrintout
->SetDC(NULL
);
689 memoryDC
.SelectObject(wxNullBitmap
);
693 sprintf(buf
, _("Page %d of %d"), pageNum
, m_maxPage
);
695 sprintf(buf
, _("Page %d"), pageNum
);
698 m_previewFrame
->SetStatusText(buf
);
704 bool wxPrintPreviewBase::DrawBlankPage(wxWindow
*canvas
, wxDC
& dc
)
706 int canvasWidth
, canvasHeight
;
707 canvas
->GetSize(&canvasWidth
, &canvasHeight
);
709 float zoomScale
= (float)((float)m_currentZoom
/(float)100);
710 float actualWidth
= zoomScale
*m_pageWidth
*m_previewScale
;
711 float actualHeight
= zoomScale
*m_pageHeight
*m_previewScale
;
713 float x
= (float)((canvasWidth
- actualWidth
)/2.0);
714 if (x
< m_leftMargin
)
715 x
= (float)m_leftMargin
;
716 float y
= (float)m_topMargin
;
718 // Draw shadow, allowing for 1-pixel border AROUND the actual page
719 int shadowOffset
= 4;
720 dc
.SetPen(*wxBLACK_PEN
);
721 dc
.SetBrush(*wxBLACK_BRUSH
);
723 dc.DrawRectangle((int)(x-1 + shadowOffset), (int)(y-1 + shadowOffset), (int)(actualWidth+2), (int)(actualHeight+2));
725 dc
.DrawRectangle((int)(x
+ shadowOffset
), (int)(y
+ actualHeight
+1), (int)(actualWidth
), shadowOffset
);
726 dc
.DrawRectangle((int)(x
+ actualWidth
), (int)(y
+ shadowOffset
), shadowOffset
, (int)(actualHeight
));
728 // Draw blank page allowing for 1-pixel border AROUND the actual page
729 dc
.SetPen(*wxBLACK_PEN
);
730 dc
.SetBrush(*wxWHITE_BRUSH
);
733 wxRegion update_region = canvas->GetUpdateRegion();
734 wxRect r = update_region.GetBox();
736 printf( "x: %d y: %d w: %d h: %d.\n", (int)r.x, (int)r.y, (int)r.width, (int)r.height );
739 dc
.DrawRectangle((int)(x
-2), (int)(y
-1), (int)(actualWidth
+3), (int)(actualHeight
+2));
744 void wxPrintPreviewBase::SetZoom(int percent
)
746 if (m_currentZoom
== percent
)
749 m_currentZoom
= percent
;
752 delete m_previewBitmap
;
753 m_previewBitmap
= NULL
;
755 RenderPage(m_currentPage
);
759 m_previewCanvas
->Clear();
760 m_previewCanvas
->Refresh();
765 * Paper size database for PostScript or where the generic page setup dialog is
769 wxPrintPaperType::wxPrintPaperType(const char *name
, int wmm
, int hmm
, int wp
, int hp
)
775 pageName
= copystring(name
);
778 wxPrintPaperType::~wxPrintPaperType()
784 * Print paper database for PostScript
787 wxPrintPaperDatabase
* wxThePrintPaperDatabase
= (wxPrintPaperDatabase
*) NULL
;
789 #if !USE_SHARED_LIBRARIES
790 IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperDatabase
, wxList
)
793 wxPrintPaperDatabase::wxPrintPaperDatabase():wxList(wxKEY_STRING
)
795 DeleteContents(TRUE
);
798 wxPrintPaperDatabase::~wxPrintPaperDatabase()
802 void wxPrintPaperDatabase::CreateDatabase()
804 // Need correct values for page size in pixels.
805 // Each unit is one 'point' = 1/72 of an inch.
806 // NOTE: WE NEED ALSO TO MAKE ADJUSTMENTS WHEN TRANSLATING
807 // in wxPostScriptDC code, so we can start from top left.
808 // So access this database and translate by appropriate number
809 // of points for this paper size. OR IS IT OK ALREADY?
810 // Can't remember where the PostScript origin is by default.
811 // Heck, someone will know how to make it hunky-dory...
814 AddPaperType(_("A4 210 x 297 mm"), 210, 297, 595, 842);
815 AddPaperType(_("A3 297 x 420 mm"), 297, 420, 842, 1191);
816 AddPaperType(_("Letter 8 1/2 x 11 in"), 216, 279, 612, 791);
817 AddPaperType(_("Legal 8 1/2 x 14 in"), 216, 356, 612, 1009);
822 AddPaperType(_("A4 210 x 297 mm"), 210, 297, 210*4, 297*4 );
823 AddPaperType(_("A3 297 x 420 mm"), 297, 420, 297*4, 420*4 );
824 AddPaperType(_("Letter 8 1/2 x 11 in"), 216, 279, 216*4, 279*4 );
825 AddPaperType(_("Legal 8 1/2 x 14 in"), 216, 356, 216*4, 356*4 );
829 void wxPrintPaperDatabase::ClearDatabase()
834 void wxPrintPaperDatabase::AddPaperType(const char *name
, int wmm
, int hmm
, int wp
, int hp
)
836 Append(name
, new wxPrintPaperType(name
, wmm
, hmm
, wp
, hp
));
839 wxPrintPaperType
*wxPrintPaperDatabase::FindPaperType(const char *name
)
841 wxNode
*node
= Find(name
);
843 return (wxPrintPaperType
*)node
->Data();
845 return (wxPrintPaperType
*) NULL
;
848 // A module to allow initialization/cleanup of print paper
849 // things without calling these functions from app.cpp.
851 class WXDLLEXPORT wxPrintBaseModule
: public wxModule
853 DECLARE_DYNAMIC_CLASS(wxPrintBaseModule
)
855 wxPrintBaseModule() {}
860 IMPLEMENT_DYNAMIC_CLASS(wxPrintBaseModule
, wxModule
)
863 * Initialization/cleanup module
866 bool wxPrintBaseModule::OnInit()
868 wxThePrintPaperDatabase
= new wxPrintPaperDatabase
;
869 wxThePrintPaperDatabase
->CreateDatabase();
874 void wxPrintBaseModule::OnExit()
876 delete wxThePrintPaperDatabase
;
877 wxThePrintPaperDatabase
= NULL
;