Moved the wxPageSetupDialogData <-> native conversion
[wxWidgets.git] / samples / printing / printing.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: printing.cpp
3 // Purpose: Printing demo for wxWidgets
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 1995
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #if !wxUSE_PRINTING_ARCHITECTURE
28 #error "You must set wxUSE_PRINTING_ARCHITECTURE to 1 in setup.h, and recompile the library."
29 #endif
30
31 // Set this to 1 if you want to test PostScript printing under MSW.
32 // However, you'll also need to edit src/msw/makefile.nt.
33 #define wxTEST_POSTSCRIPT_IN_MSW 0
34
35 #include <ctype.h>
36 #include "wx/metafile.h"
37 #include "wx/print.h"
38 #include "wx/printdlg.h"
39
40 #include "wx/accel.h"
41
42 #if wxTEST_POSTSCRIPT_IN_MSW
43 #include "wx/generic/printps.h"
44 #include "wx/generic/prntdlgg.h"
45 #endif
46
47 #include "printing.h"
48
49 #ifndef __WXMSW__
50 #include "mondrian.xpm"
51 #endif
52
53 // Declare a frame
54 MyFrame *frame = (MyFrame *) NULL;
55 // int orientation = wxPORTRAIT;
56
57 // Global print data, to remember settings during the session
58 wxPrintData *g_printData = (wxPrintData*) NULL ;
59
60 // Global page setup data
61 wxPageSetupData* g_pageSetupData = (wxPageSetupData*) NULL;
62
63 // Main proc
64 IMPLEMENT_APP(MyApp)
65
66 // Writes a header on a page. Margin units are in millimetres.
67 bool WritePageHeader(wxPrintout *printout, wxDC *dc, wxChar *text, float mmToLogical);
68
69 // The `main program' equivalent, creating the windows and returning the
70 // main frame
71 bool MyApp::OnInit(void)
72 {
73 m_testFont.Create(10, wxSWISS, wxNORMAL, wxNORMAL);
74
75 g_printData = new wxPrintData;
76 g_pageSetupData = new wxPageSetupDialogData;
77
78 // Create the main frame window
79 frame = new MyFrame((wxFrame *) NULL, _T("wxWidgets Printing Demo"), wxPoint(0, 0), wxSize(400, 400));
80
81 #if wxUSE_STATUSBAR
82 // Give it a status line
83 frame->CreateStatusBar(2);
84 #endif // wxUSE_STATUSBAR
85
86 // Load icon and bitmap
87 frame->SetIcon( wxICON( mondrian) );
88
89 // Make a menubar
90 wxMenu *file_menu = new wxMenu;
91
92 file_menu->Append(WXPRINT_PRINT, _T("&Print..."), _T("Print"));
93 file_menu->Append(WXPRINT_PAGE_SETUP, _T("Page Set&up..."), _T("Page setup"));
94 file_menu->Append(WXPRINT_PREVIEW, _T("Print Pre&view"), _T("Preview"));
95
96 #if wxUSE_ACCEL
97 // Accelerators
98 wxAcceleratorEntry entries[1];
99 entries[0].Set(wxACCEL_CTRL, (int) 'V', WXPRINT_PREVIEW);
100 wxAcceleratorTable accel(1, entries);
101 frame->SetAcceleratorTable(accel);
102 #endif
103
104 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW
105 file_menu->AppendSeparator();
106 file_menu->Append(WXPRINT_PRINT_PS, _T("Print PostScript..."), _T("Print (PostScript)"));
107 file_menu->Append(WXPRINT_PAGE_SETUP_PS, _T("Page Setup PostScript..."), _T("Page setup (PostScript)"));
108 file_menu->Append(WXPRINT_PREVIEW_PS, _T("Print Preview PostScript"), _T("Preview (PostScript)"));
109 #endif
110 file_menu->AppendSeparator();
111 file_menu->Append(WXPRINT_QUIT, _T("E&xit"), _T("Exit program"));
112
113 wxMenu *help_menu = new wxMenu;
114 help_menu->Append(WXPRINT_ABOUT, _T("&About"), _T("About this demo"));
115
116 wxMenuBar *menu_bar = new wxMenuBar;
117
118 menu_bar->Append(file_menu, _T("&File"));
119 menu_bar->Append(help_menu, _T("&Help"));
120
121 // Associate the menu bar with the frame
122 frame->SetMenuBar(menu_bar);
123
124 MyCanvas *canvas = new MyCanvas(frame, wxPoint(0, 0), wxSize(100, 100), wxRETAINED|wxHSCROLL|wxVSCROLL);
125
126 // Give it scrollbars: the virtual canvas is 20 * 50 = 1000 pixels in each direction
127 canvas->SetScrollbars(20, 20, 50, 50);
128
129 frame->canvas = canvas;
130
131 frame->Centre(wxBOTH);
132 frame->Show();
133
134 #if wxUSE_STATUSBAR
135 frame->SetStatusText(_T("Printing demo"));
136 #endif // wxUSE_STATUSBAR
137
138 SetTopWindow(frame);
139
140 return true;
141 }
142
143 int MyApp::OnExit()
144 {
145 delete g_printData;
146 delete g_pageSetupData;
147 return 1;
148 }
149
150 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
151 EVT_MENU(WXPRINT_QUIT, MyFrame::OnExit)
152 EVT_MENU(WXPRINT_PRINT, MyFrame::OnPrint)
153 EVT_MENU(WXPRINT_PREVIEW, MyFrame::OnPrintPreview)
154 EVT_MENU(WXPRINT_PAGE_SETUP, MyFrame::OnPageSetup)
155 EVT_MENU(WXPRINT_ABOUT, MyFrame::OnPrintAbout)
156 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW
157 EVT_MENU(WXPRINT_PRINT_PS, MyFrame::OnPrintPS)
158 EVT_MENU(WXPRINT_PREVIEW_PS, MyFrame::OnPrintPreviewPS)
159 EVT_MENU(WXPRINT_PAGE_SETUP_PS, MyFrame::OnPageSetupPS)
160 #endif
161 END_EVENT_TABLE()
162
163 // Define my frame constructor
164 MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size):
165 wxFrame(frame, wxID_ANY, title, pos, size)
166 {
167 canvas = NULL;
168 }
169
170 void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))
171 {
172 Close(true /*force closing*/);
173 }
174
175 void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
176 {
177 wxPrintDialogData printDialogData(* g_printData);
178
179 wxPrinter printer(& printDialogData);
180 MyPrintout printout(_T("My printout"));
181 if (!printer.Print(this, &printout, true /*prompt*/))
182 {
183 if (wxPrinter::GetLastError() == wxPRINTER_ERROR)
184 wxMessageBox(_T("There was a problem printing.\nPerhaps your current printer is not set correctly?"), _T("Printing"), wxOK);
185 else
186 wxMessageBox(_T("You canceled printing"), _T("Printing"), wxOK);
187 }
188 else
189 {
190 (*g_printData) = printer.GetPrintDialogData().GetPrintData();
191 }
192 }
193
194 void MyFrame::OnPrintPreview(wxCommandEvent& WXUNUSED(event))
195 {
196 // Pass two printout objects: for preview, and possible printing.
197 wxPrintDialogData printDialogData(* g_printData);
198 wxPrintPreview *preview = new wxPrintPreview(new MyPrintout, new MyPrintout, & printDialogData);
199 if (!preview->Ok())
200 {
201 delete preview;
202 wxMessageBox(_T("There was a problem previewing.\nPerhaps your current printer is not set correctly?"), _T("Previewing"), wxOK);
203 return;
204 }
205
206 wxPreviewFrame *frame = new wxPreviewFrame(preview, this, _T("Demo Print Preview"), wxPoint(100, 100), wxSize(600, 650));
207 frame->Centre(wxBOTH);
208 frame->Initialize();
209 frame->Show();
210 }
211
212 void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
213 {
214 (*g_pageSetupData) = * g_printData;
215
216 wxPageSetupDialog pageSetupDialog(this, g_pageSetupData);
217 pageSetupDialog.ShowModal();
218
219 (*g_printData) = pageSetupDialog.GetPageSetupData().GetPrintData();
220 (*g_pageSetupData) = pageSetupDialog.GetPageSetupData();
221 }
222
223 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW
224 void MyFrame::OnPrintPS(wxCommandEvent& WXUNUSED(event))
225 {
226 wxPostScriptPrinter printer(g_printData);
227 MyPrintout printout(_T("My printout"));
228 printer.Print(this, &printout, true/*prompt*/);
229
230 (*g_printData) = printer.GetPrintData();
231 }
232
233 void MyFrame::OnPrintPreviewPS(wxCommandEvent& WXUNUSED(event))
234 {
235 // Pass two printout objects: for preview, and possible printing.
236 wxPrintDialogData printDialogData(* g_printData);
237 wxPrintPreview *preview = new wxPrintPreview(new MyPrintout, new MyPrintout, & printDialogData);
238 wxPreviewFrame *frame = new wxPreviewFrame(preview, this, _T("Demo Print Preview"), wxPoint(100, 100), wxSize(600, 650));
239 frame->Centre(wxBOTH);
240 frame->Initialize();
241 frame->Show();
242 }
243
244 void MyFrame::OnPageSetupPS(wxCommandEvent& WXUNUSED(event))
245 {
246 (*g_pageSetupData) = * g_printData;
247
248 wxGenericPageSetupDialog pageSetupDialog(this, g_pageSetupData);
249 pageSetupDialog.ShowModal();
250
251 (*g_printData) = pageSetupDialog.GetPageSetupData().GetPrintData();
252 (*g_pageSetupData) = pageSetupDialog.GetPageSetupData();
253 }
254 #endif
255
256
257 void MyFrame::OnPrintAbout(wxCommandEvent& WXUNUSED(event))
258 {
259 (void)wxMessageBox(_T("wxWidgets printing demo\nAuthor: Julian Smart"),
260 _T("About wxWidgets printing demo"), wxOK|wxCENTRE);
261 }
262
263 void MyFrame::Draw(wxDC& dc)
264 {
265 dc.SetBackground(*wxWHITE_BRUSH);
266 dc.Clear();
267 dc.SetFont(wxGetApp().m_testFont);
268
269 dc.SetBackgroundMode(wxTRANSPARENT);
270
271 dc.SetBrush(* wxCYAN_BRUSH);
272 dc.SetPen(* wxRED_PEN);
273
274 dc.DrawRectangle(0, 30, 200, 100);
275
276 dc.DrawText( wxT("Rectangle 200 by 100"), 40, 40);
277
278 dc.DrawEllipse(50, 140, 100, 50);
279
280 dc.DrawText( wxT("Test message: this is in 10 point text"), 10, 180);
281
282 #if wxUSE_UNICODE
283 char *test = "Hebrew שלום -- Japanese (日本語)";
284 wxString tmp = wxConvUTF8.cMB2WC( test );
285 dc.DrawText( tmp, 10, 200 );
286 #endif
287
288 dc.SetPen(* wxBLACK_PEN);
289 dc.DrawLine(0, 0, 200, 200);
290 dc.DrawLine(200, 0, 0, 200);
291
292 wxIcon my_icon = wxICON(mondrian) ;
293
294 dc.DrawIcon( my_icon, 100, 100);
295 }
296
297 void MyFrame::OnSize(wxSizeEvent& event )
298 {
299 wxFrame::OnSize(event);
300 }
301
302 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
303 EVT_MOUSE_EVENTS(MyCanvas::OnEvent)
304 END_EVENT_TABLE()
305
306 // Define a constructor for my canvas
307 MyCanvas::MyCanvas(wxFrame *frame, const wxPoint& pos, const wxSize& size, long style):
308 wxScrolledWindow(frame, wxID_ANY, pos, size, style)
309 {
310 SetBackgroundColour(* wxWHITE);
311 }
312
313 // Define the repainting behaviour
314 void MyCanvas::OnDraw(wxDC& dc)
315 {
316 frame->Draw(dc);
317 }
318
319 void MyCanvas::OnEvent(wxMouseEvent& WXUNUSED(event))
320 {
321 }
322
323 bool MyPrintout::OnPrintPage(int page)
324 {
325 wxDC *dc = GetDC();
326 if (dc)
327 {
328 if (page == 1)
329 DrawPageOne(dc);
330 else if (page == 2)
331 DrawPageTwo(dc);
332
333 dc->SetDeviceOrigin(0, 0);
334 dc->SetUserScale(1.0, 1.0);
335
336 wxChar buf[200];
337 wxSprintf(buf, wxT("PAGE %d"), page);
338 dc->DrawText(buf, 10, 10);
339
340 return true;
341 }
342 else
343 return false;
344 }
345
346 bool MyPrintout::OnBeginDocument(int startPage, int endPage)
347 {
348 if (!wxPrintout::OnBeginDocument(startPage, endPage))
349 return false;
350
351 return true;
352 }
353
354 void MyPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
355 {
356 *minPage = 1;
357 *maxPage = 2;
358 *selPageFrom = 1;
359 *selPageTo = 2;
360 }
361
362 bool MyPrintout::HasPage(int pageNum)
363 {
364 return (pageNum == 1 || pageNum == 2);
365 }
366
367 void MyPrintout::DrawPageOne(wxDC *dc)
368 {
369 // You might use THIS code if you were scaling
370 // graphics of known size to fit on the page.
371
372 // We know the graphic is 200x200. If we didn't know this,
373 // we'd need to calculate it.
374 float maxX = 200;
375 float maxY = 200;
376
377 // Let's have at least 50 device units margin
378 float marginX = 50;
379 float marginY = 50;
380
381 // Add the margin to the graphic size
382 maxX += (2*marginX);
383 maxY += (2*marginY);
384
385 // Get the size of the DC in pixels
386 int w, h;
387 dc->GetSize(&w, &h);
388
389 // Calculate a suitable scaling factor
390 float scaleX=(float)(w/maxX);
391 float scaleY=(float)(h/maxY);
392
393 // Use x or y scaling factor, whichever fits on the DC
394 float actualScale = wxMin(scaleX,scaleY);
395
396 // Calculate the position on the DC for centring the graphic
397 float posX = (float)((w - (200*actualScale))/2.0);
398 float posY = (float)((h - (200*actualScale))/2.0);
399
400 // Set the scale and origin
401 dc->SetUserScale(actualScale, actualScale);
402 dc->SetDeviceOrigin( (long)posX, (long)posY );
403
404 frame->Draw(*dc);
405 }
406
407 void MyPrintout::DrawPageTwo(wxDC *dc)
408 {
409 // You might use THIS code to set the printer DC to ROUGHLY reflect
410 // the screen text size. This page also draws lines of actual length
411 // 5cm on the page.
412
413 // Get the logical pixels per inch of screen and printer
414 int ppiScreenX, ppiScreenY;
415 GetPPIScreen(&ppiScreenX, &ppiScreenY);
416 int ppiPrinterX, ppiPrinterY;
417 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
418
419 // This scales the DC so that the printout roughly represents the
420 // the screen scaling. The text point size _should_ be the right size
421 // but in fact is too small for some reason. This is a detail that will
422 // need to be addressed at some point but can be fudged for the
423 // moment.
424 float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
425
426 // Now we have to check in case our real page size is reduced
427 // (e.g. because we're drawing to a print preview memory DC)
428 int pageWidth, pageHeight;
429 int w, h;
430 dc->GetSize(&w, &h);
431 GetPageSizePixels(&pageWidth, &pageHeight);
432
433 // If printer pageWidth == current DC width, then this doesn't
434 // change. But w might be the preview bitmap width, so scale down.
435 float overallScale = scale * (float)(w/(float)pageWidth);
436 dc->SetUserScale(overallScale, overallScale);
437
438 // Calculate conversion factor for converting millimetres into
439 // logical units.
440 // There are approx. 25.1 mm to the inch. There are ppi
441 // device units to the inch. Therefore 1 mm corresponds to
442 // ppi/25.1 device units. We also divide by the
443 // screen-to-printer scaling factor, because we need to
444 // unscale to pass logical units to DrawLine.
445
446 // Draw 50 mm by 50 mm L shape
447 float logUnitsFactor = (float)(ppiPrinterX/(scale*25.1));
448 float logUnits = (float)(50*logUnitsFactor);
449 dc->SetPen(* wxBLACK_PEN);
450 dc->DrawLine(50, 250, (long)(50.0 + logUnits), 250);
451 dc->DrawLine(50, 250, 50, (long)(250.0 + logUnits));
452
453 dc->SetBackgroundMode(wxTRANSPARENT);
454
455
456 { // GetTextExtent demo:
457 wxString words[7] = {_T("This "), _T("is "), _T("GetTextExtent "), _T("testing "), _T("string. "), _T("Enjoy "), _T("it!")};
458 long w, h;
459 long x = 200, y= 250;
460 wxFont fnt(15, wxSWISS, wxNORMAL, wxNORMAL);
461
462 dc->SetFont(fnt);
463
464 for (int i = 0; i < 7; i++)
465 {
466 wxString word = words[i];
467 word.Remove( word.Len()-1, 1 );
468 dc->GetTextExtent(word, &w, &h);
469 dc->DrawRectangle(x, y, w, h);
470 dc->GetTextExtent(words[i], &w, &h);
471 dc->DrawText(words[i], x, y);
472 x += w;
473 }
474
475 }
476
477 dc->SetFont(wxGetApp().m_testFont);
478
479 dc->DrawText(_T("Some test text"), 200, 300 );
480
481 // TESTING
482
483 int leftMargin = 20;
484 int rightMargin = 20;
485 int topMargin = 20;
486 int bottomMargin = 20;
487
488 int pageWidthMM, pageHeightMM;
489 GetPageSizeMM(&pageWidthMM, &pageHeightMM);
490
491 float leftMarginLogical = (float)(logUnitsFactor*leftMargin);
492 float topMarginLogical = (float)(logUnitsFactor*topMargin);
493 float bottomMarginLogical = (float)(logUnitsFactor*(pageHeightMM - bottomMargin));
494 float rightMarginLogical = (float)(logUnitsFactor*(pageWidthMM - rightMargin));
495
496 dc->SetPen(* wxRED_PEN);
497 dc->DrawLine( (long)leftMarginLogical, (long)topMarginLogical,
498 (long)rightMarginLogical, (long)topMarginLogical);
499 dc->DrawLine( (long)leftMarginLogical, (long)bottomMarginLogical,
500 (long)rightMarginLogical, (long)bottomMarginLogical);
501
502 WritePageHeader(this, dc, _T("A header"), logUnitsFactor);
503 }
504
505 // Writes a header on a page. Margin units are in millimetres.
506 bool WritePageHeader(wxPrintout *printout, wxDC *dc, wxChar *text, float mmToLogical)
507 {
508 /*
509 static wxFont *headerFont = (wxFont *) NULL;
510 if (!headerFont)
511 {
512 headerFont = wxTheFontList->FindOrCreateFont(16, wxSWISS, wxNORMAL, wxBOLD);
513 }
514 dc->SetFont(headerFont);
515 */
516
517 int pageWidthMM, pageHeightMM;
518
519 printout->GetPageSizeMM(&pageWidthMM, &pageHeightMM);
520 wxUnusedVar(pageHeightMM);
521
522 int leftMargin = 10;
523 int topMargin = 10;
524 int rightMargin = 10;
525
526 float leftMarginLogical = (float)(mmToLogical*leftMargin);
527 float topMarginLogical = (float)(mmToLogical*topMargin);
528 float rightMarginLogical = (float)(mmToLogical*(pageWidthMM - rightMargin));
529
530 long xExtent, yExtent;
531 dc->GetTextExtent(text, &xExtent, &yExtent);
532 float xPos = (float)(((((pageWidthMM - leftMargin - rightMargin)/2.0)+leftMargin)*mmToLogical) - (xExtent/2.0));
533 dc->DrawText(text, (long)xPos, (long)topMarginLogical);
534
535 dc->SetPen(* wxBLACK_PEN);
536 dc->DrawLine( (long)leftMarginLogical, (long)(topMarginLogical+yExtent),
537 (long)rightMarginLogical, (long)topMarginLogical+yExtent );
538
539 return true;
540 }