1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        samples/printing.cpp 
   3 // Purpose:     Printing demo for wxWidgets 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx/wx.h". 
  13 #include "wx/wxprec.h" 
  23 #if !wxUSE_PRINTING_ARCHITECTURE 
  24 #error "You must set wxUSE_PRINTING_ARCHITECTURE to 1 in setup.h, and recompile the library." 
  27 // Set this to 1 if you want to test PostScript printing under MSW. 
  28 // However, you'll also need to edit src/msw/makefile.nt. 
  29 #define wxTEST_POSTSCRIPT_IN_MSW 0 
  32 #include "wx/metafile.h" 
  34 #include "wx/printdlg.h" 
  38 #if wxTEST_POSTSCRIPT_IN_MSW 
  39 #include "wx/generic/printps.h" 
  40 #include "wx/generic/prntdlgg.h" 
  44 #include "wx/mac/printdlg.h" 
  50 #include "mondrian.xpm" 
  53 #if wxUSE_LIBGNOMEPRINT 
  54 #include "wx/html/forcelnk.h" 
  55 FORCE_LINK(gnome_print
) 
  60 MyFrame   
*frame 
= (MyFrame 
*) NULL
; 
  61 // int orientation = wxPORTRAIT; 
  63 // Global print data, to remember settings during the session 
  64 wxPrintData 
*g_printData 
= (wxPrintData
*) NULL 
; 
  66 // Global page setup data 
  67 wxPageSetupDialogData
* g_pageSetupData 
= (wxPageSetupDialogData
*) NULL
; 
  72 // Writes a header on a page. Margin units are in millimetres. 
  73 bool WritePageHeader(wxPrintout 
*printout
, wxDC 
*dc
, const wxChar 
*text
, float mmToLogical
); 
  75 // The `main program' equivalent, creating the windows and returning the 
  78 bool MyApp::OnInit(void) 
  80     if ( !wxApp::OnInit() ) 
  83     wxInitAllImageHandlers(); 
  85     m_testFont
.Create(10, wxSWISS
, wxNORMAL
, wxNORMAL
); 
  87     g_printData 
= new wxPrintData
; 
  88     // You could set an initial paper size here 
  89 //    g_printData->SetPaperId(wxPAPER_LETTER); // for Americans 
  90 //    g_printData->SetPaperId(wxPAPER_A4);    // for everyone else     
  92     g_pageSetupData 
= new wxPageSetupDialogData
; 
  93     // copy over initial paper size from print record 
  94     (*g_pageSetupData
) = *g_printData
; 
  95     // Set some initial page margins in mm.  
  96     g_pageSetupData
->SetMarginTopLeft(wxPoint(15, 15)); 
  97     g_pageSetupData
->SetMarginBottomRight(wxPoint(15, 15)); 
  99     // Create the main frame window 
 100     frame 
= new MyFrame((wxFrame 
*) NULL
, _T("wxWidgets Printing Demo"),  
 101         wxPoint(0, 0), wxSize(400, 400)); 
 104     // Give it a status line 
 105     frame
->CreateStatusBar(2); 
 106 #endif // wxUSE_STATUSBAR 
 108     // Load icon and bitmap 
 109     frame
->SetIcon( wxICON( mondrian
) ); 
 112     wxMenu 
*file_menu 
= new wxMenu
; 
 114     file_menu
->Append(WXPRINT_PRINT
, _T("&Print..."),              _T("Print")); 
 115     file_menu
->Append(WXPRINT_PAGE_SETUP
, _T("Page Set&up..."),              _T("Page setup")); 
 117     file_menu
->Append(WXPRINT_PAGE_MARGINS
, _T("Page Margins..."), _T("Page margins")); 
 119     file_menu
->Append(WXPRINT_PREVIEW
, _T("Print Pre&view"),              _T("Preview")); 
 123     wxAcceleratorEntry entries
[1]; 
 124     entries
[0].Set(wxACCEL_CTRL
, (int) 'V', WXPRINT_PREVIEW
); 
 125     wxAcceleratorTable 
accel(1, entries
); 
 126     frame
->SetAcceleratorTable(accel
); 
 129 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW 
 130     file_menu
->AppendSeparator(); 
 131     file_menu
->Append(WXPRINT_PRINT_PS
, _T("Print PostScript..."),              _T("Print (PostScript)")); 
 132     file_menu
->Append(WXPRINT_PAGE_SETUP_PS
, _T("Page Setup PostScript..."),              _T("Page setup (PostScript)")); 
 133     file_menu
->Append(WXPRINT_PREVIEW_PS
, _T("Print Preview PostScript"),              _T("Preview (PostScript)")); 
 136     file_menu
->AppendSeparator(); 
 137     file_menu
->Append(WXPRINT_ANGLEUP
, _T("Angle up\tAlt-U"),                _T("Raise rotated text angle")); 
 138     file_menu
->Append(WXPRINT_ANGLEDOWN
, _T("Angle down\tAlt-D"),            _T("Lower rotated text angle")); 
 139     file_menu
->AppendSeparator(); 
 140     file_menu
->Append(WXPRINT_QUIT
, _T("E&xit"),                _T("Exit program")); 
 142     wxMenu 
*help_menu 
= new wxMenu
; 
 143     help_menu
->Append(WXPRINT_ABOUT
, _T("&About"),              _T("About this demo")); 
 145     wxMenuBar 
*menu_bar 
= new wxMenuBar
; 
 147     menu_bar
->Append(file_menu
, _T("&File")); 
 148     menu_bar
->Append(help_menu
, _T("&Help")); 
 150     // Associate the menu bar with the frame 
 151     frame
->SetMenuBar(menu_bar
); 
 153     MyCanvas 
*canvas 
= new MyCanvas(frame
, wxPoint(0, 0), wxSize(100, 100), wxRETAINED
|wxHSCROLL
|wxVSCROLL
); 
 155     // Give it scrollbars: the virtual canvas is 20 * 50 = 1000 pixels in each direction 
 156     canvas
->SetScrollbars(20, 20, 50, 50); 
 158     frame
->canvas 
= canvas
; 
 160     frame
->Centre(wxBOTH
); 
 164     frame
->SetStatusText(_T("Printing demo")); 
 165 #endif // wxUSE_STATUSBAR 
 175     delete g_pageSetupData
; 
 179 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
) 
 180 EVT_MENU(WXPRINT_QUIT
, MyFrame::OnExit
) 
 181 EVT_MENU(WXPRINT_PRINT
, MyFrame::OnPrint
) 
 182 EVT_MENU(WXPRINT_PREVIEW
, MyFrame::OnPrintPreview
) 
 183 EVT_MENU(WXPRINT_PAGE_SETUP
, MyFrame::OnPageSetup
) 
 184 EVT_MENU(WXPRINT_ABOUT
, MyFrame::OnPrintAbout
) 
 185 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW 
 186 EVT_MENU(WXPRINT_PRINT_PS
, MyFrame::OnPrintPS
) 
 187 EVT_MENU(WXPRINT_PREVIEW_PS
, MyFrame::OnPrintPreviewPS
) 
 188 EVT_MENU(WXPRINT_PAGE_SETUP_PS
, MyFrame::OnPageSetupPS
) 
 191 EVT_MENU(WXPRINT_PAGE_MARGINS
, MyFrame::OnPageMargins
) 
 193 EVT_MENU(WXPRINT_ANGLEUP
, MyFrame::OnAngleUp
) 
 194 EVT_MENU(WXPRINT_ANGLEDOWN
, MyFrame::OnAngleDown
) 
 197 // Define my frame constructor 
 198 MyFrame::MyFrame(wxFrame 
*frame
, const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
): 
 199 wxFrame(frame
, wxID_ANY
, title
, pos
, size
) 
 204     wxImage 
image( wxT("test.jpg") ); 
 207     for (i 
= 0; i 
< image
.GetWidth(); i
++) 
 208        for (j 
= 0; j 
< image
.GetHeight(); j
++) 
 209           image
.SetAlpha( i
, j
, 50 ); 
 214 void MyFrame::OnExit(wxCommandEvent
& WXUNUSED(event
)) 
 216     Close(true /*force closing*/); 
 219 void MyFrame::OnPrint(wxCommandEvent
& WXUNUSED(event
)) 
 221     wxPrintDialogData 
printDialogData(* g_printData
); 
 223     wxPrinter 
printer(& printDialogData
); 
 224     MyPrintout 
printout(_T("My printout")); 
 225     if (!printer
.Print(this, &printout
, true /*prompt*/)) 
 227         if (wxPrinter::GetLastError() == wxPRINTER_ERROR
) 
 228             wxMessageBox(_T("There was a problem printing.\nPerhaps your current printer is not set correctly?"), _T("Printing"), wxOK
); 
 230             wxMessageBox(_T("You canceled printing"), _T("Printing"), wxOK
); 
 234         (*g_printData
) = printer
.GetPrintDialogData().GetPrintData(); 
 238 void MyFrame::OnPrintPreview(wxCommandEvent
& WXUNUSED(event
)) 
 240     // Pass two printout objects: for preview, and possible printing. 
 241     wxPrintDialogData 
printDialogData(* g_printData
); 
 242     wxPrintPreview 
*preview 
= new wxPrintPreview(new MyPrintout
, new MyPrintout
, & printDialogData
); 
 246         wxMessageBox(_T("There was a problem previewing.\nPerhaps your current printer is not set correctly?"), _T("Previewing"), wxOK
); 
 250     wxPreviewFrame 
*frame 
= new wxPreviewFrame(preview
, this, _T("Demo Print Preview"), wxPoint(100, 100), wxSize(600, 650)); 
 251     frame
->Centre(wxBOTH
); 
 256 void MyFrame::OnPageSetup(wxCommandEvent
& WXUNUSED(event
)) 
 258     (*g_pageSetupData
) = *g_printData
; 
 260     wxPageSetupDialog 
pageSetupDialog(this, g_pageSetupData
); 
 261     pageSetupDialog
.ShowModal(); 
 263     (*g_printData
) = pageSetupDialog
.GetPageSetupDialogData().GetPrintData(); 
 264     (*g_pageSetupData
) = pageSetupDialog
.GetPageSetupDialogData(); 
 267 #if defined(__WXMSW__) && wxTEST_POSTSCRIPT_IN_MSW 
 268 void MyFrame::OnPrintPS(wxCommandEvent
& WXUNUSED(event
)) 
 270     wxPostScriptPrinter 
printer(g_printData
); 
 271     MyPrintout 
printout(_T("My printout")); 
 272     printer
.Print(this, &printout
, true/*prompt*/); 
 274     (*g_printData
) = printer
.GetPrintData(); 
 277 void MyFrame::OnPrintPreviewPS(wxCommandEvent
& WXUNUSED(event
)) 
 279     // Pass two printout objects: for preview, and possible printing. 
 280     wxPrintDialogData 
printDialogData(* g_printData
); 
 281     wxPrintPreview 
*preview 
= new wxPrintPreview(new MyPrintout
, new MyPrintout
, & printDialogData
); 
 282     wxPreviewFrame 
*frame 
= new wxPreviewFrame(preview
, this, _T("Demo Print Preview"), wxPoint(100, 100), wxSize(600, 650)); 
 283     frame
->Centre(wxBOTH
); 
 288 void MyFrame::OnPageSetupPS(wxCommandEvent
& WXUNUSED(event
)) 
 290     (*g_pageSetupData
) = * g_printData
; 
 292     wxGenericPageSetupDialog 
pageSetupDialog(this, g_pageSetupData
); 
 293     pageSetupDialog
.ShowModal(); 
 295     (*g_printData
) = pageSetupDialog
.GetPageSetupDialogData().GetPrintData(); 
 296     (*g_pageSetupData
) = pageSetupDialog
.GetPageSetupDialogData(); 
 302 void MyFrame::OnPageMargins(wxCommandEvent
& WXUNUSED(event
)) 
 304     (*g_pageSetupData
) = *g_printData
; 
 306     wxMacPageMarginsDialog 
pageMarginsDialog(this, g_pageSetupData
); 
 307     pageMarginsDialog
.ShowModal(); 
 309     (*g_printData
) = pageMarginsDialog
.GetPageSetupDialogData().GetPrintData(); 
 310     (*g_pageSetupData
) = pageMarginsDialog
.GetPageSetupDialogData(); 
 315 void MyFrame::OnPrintAbout(wxCommandEvent
& WXUNUSED(event
)) 
 317     (void)wxMessageBox(_T("wxWidgets printing demo\nAuthor: Julian Smart"), 
 318         _T("About wxWidgets printing demo"), wxOK
|wxCENTRE
); 
 321 void MyFrame::OnAngleUp(wxCommandEvent
& WXUNUSED(event
)) 
 327 void MyFrame::OnAngleDown(wxCommandEvent
& WXUNUSED(event
)) 
 333 void MyFrame::Draw(wxDC
& dc
) 
 335     // This routine just draws a bunch of random stuff on the screen so that we 
 336     // can check that different types of object are being drawn consistently 
 337     // between the screen image, the print preview image (at various zoom 
 338     // levels), and the printed page. 
 339     dc
.SetBackground(*wxWHITE_BRUSH
); 
 341     dc
.SetFont(wxGetApp().m_testFont
); 
 343     dc
.SetBackgroundMode(wxTRANSPARENT
); 
 345     dc
.SetPen(*wxBLACK_PEN
); 
 346     dc
.SetBrush(*wxLIGHT_GREY_BRUSH
); 
 347     dc
.DrawRectangle(0, 0, 230, 350); 
 348     dc
.DrawLine(0, 0, 229, 349); 
 349     dc
.DrawLine(229, 0, 0, 349); 
 350     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
 352     dc
.SetBrush(*wxCYAN_BRUSH
); 
 353     dc
.SetPen(*wxRED_PEN
); 
 355     dc
.DrawRoundedRectangle(0, 20, 200, 80, 20); 
 357     dc
.DrawText( wxT("Rectangle 200 by 80"), 40, 40); 
 359     dc
.SetPen( wxPen(*wxBLACK
,0,wxDOT_DASH
) ); 
 360     dc
.DrawEllipse(50, 140, 100, 50); 
 361     dc
.SetPen(*wxRED_PEN
); 
 363     dc
.DrawText( wxT("Test message: this is in 10 point text"), 10, 180); 
 366     char *test 
= "Hebrew    שלום -- Japanese (日本語)"; 
 367     wxString tmp 
= wxConvUTF8
.cMB2WC( test 
); 
 368     dc
.DrawText( tmp
, 10, 200 ); 
 382     dc
.DrawPolygon( 5, points
, 20, 250, wxODDEVEN_RULE 
); 
 383     dc
.DrawPolygon( 5, points
, 50, 250, wxWINDING_RULE 
); 
 385     dc
.DrawEllipticArc( 80, 250, 60, 30, 0.0, 270.0 ); 
 395     dc
.DrawSpline( 4, points 
); 
 397     dc
.DrawArc( 20,10, 10,10, 25,40 ); 
 401     str
.Printf( wxT("---- Text at angle %d ----"), i 
); 
 402     dc
.DrawRotatedText( str
, 100, 300, i 
); 
 405     str
.Printf( wxT("---- Text at angle %d ----"), i 
); 
 406     dc
.DrawRotatedText( str
, 100, 300, i 
); 
 408     wxIcon my_icon 
= wxICON(mondrian
) ; 
 410     dc
.DrawIcon( my_icon
, 100, 100); 
 413         dc
.DrawBitmap( m_bitmap
, 10, 10 ); 
 416 void MyFrame::OnSize(wxSizeEvent
& event 
) 
 418     wxFrame::OnSize(event
); 
 421 BEGIN_EVENT_TABLE(MyCanvas
, wxScrolledWindow
) 
 422 EVT_MOUSE_EVENTS(MyCanvas::OnEvent
) 
 425 MyCanvas::MyCanvas(wxFrame 
*frame
, const wxPoint
& pos
, const wxSize
& size
, long style
): 
 426     wxScrolledWindow(frame
, wxID_ANY
, pos
, size
, style
) 
 428     SetBackgroundColour(* wxWHITE
); 
 431 void MyCanvas::OnDraw(wxDC
& dc
) 
 436 void MyCanvas::OnEvent(wxMouseEvent
& WXUNUSED(event
)) 
 440 bool MyPrintout::OnPrintPage(int page
) 
 450         // Draw page numbers at top left corner of printable area, sized so that 
 451         // screen size of text matches paper size. 
 452         MapScreenSizeToPage(); 
 454         wxSprintf(buf
, wxT("PAGE %d"), page
); 
 455         dc
->DrawText(buf
, 0, 0); 
 463 bool MyPrintout::OnBeginDocument(int startPage
, int endPage
) 
 465     if (!wxPrintout::OnBeginDocument(startPage
, endPage
)) 
 471 void MyPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
) 
 479 bool MyPrintout::HasPage(int pageNum
) 
 481     return (pageNum 
== 1 || pageNum 
== 2); 
 484 void MyPrintout::DrawPageOne() 
 486     // You might use THIS code if you were scaling graphics of known size to fit 
 487     // on the page. The commented-out code illustrates different ways of scaling 
 490     // We know the graphic is 230x350. If we didn't know this, we'd need to 
 495     // This sets the user scale and origin of the DC so that the image fits 
 496     // within the paper rectangle (but the edges could be cut off by printers 
 497     // that can't print to the edges of the paper -- which is most of them. Use 
 498     // this if your image already has its own margins. 
 499 //    FitThisSizeToPaper(wxSize(maxX, maxY)); 
 500 //    wxRect fitRect = GetLogicalPaperRect(); 
 502     // This sets the user scale and origin of the DC so that the image fits 
 503     // within the page rectangle, which is the printable area on Mac and MSW 
 504     // and is the entire page on other platforms. 
 505 //    FitThisSizeToPage(wxSize(maxX, maxY)); 
 506 //    wxRect fitRect = GetLogicalPageRect(); 
 508     // This sets the user scale and origin of the DC so that the image fits 
 509     // within the page margins as specified by g_PageSetupData, which you can 
 510     // change (on some platforms, at least) in the Page Setup dialog. Note that 
 511     // on Mac, the native Page Setup dialog doesn't let you change the margins 
 512     // of a wxPageSetupDialogData object, so you'll have to write your own dialog or 
 513     // use the Mac-only wxMacPageMarginsDialog, as we do in this program. 
 514     FitThisSizeToPageMargins(wxSize(maxX
, maxY
), *g_pageSetupData
); 
 515     wxRect fitRect 
= GetLogicalPageMarginsRect(*g_pageSetupData
); 
 517     // This sets the user scale and origin of the DC so that the image appears 
 518     // on the paper at the same size that it appears on screen (i.e., 10-point 
 519     // type on screen is 10-point on the printed page) and is positioned in the 
 520     // top left corner of the page rectangle (just as the screen image appears 
 521     // in the top left corner of the window). 
 522 //    MapScreenSizeToPage(); 
 523 //    wxRect fitRect = GetLogicalPageRect(); 
 525     // You could also map the screen image to the entire paper at the same size 
 526     // as it appears on screen. 
 527 //    MapScreenSizeToPaper(); 
 528 //    wxRect fitRect = GetLogicalPaperRect(); 
 530     // You might also wish to do you own scaling in order to draw objects at 
 531     // full native device resolution. In this case, you should do the following. 
 532     // Note that you can use the GetLogicalXXXRect() commands to obtain the 
 533     // appropriate rect to scale to. 
 534 //    MapScreenSizeToDevice(); 
 535 //    wxRect fitRect = GetLogicalPageRect(); 
 537     // Each of the preceding Fit or Map routines positions the origin so that 
 538     // the drawn image is positioned at the top left corner of the reference 
 539     // rectangle. You can easily center or right- or bottom-justify the image as 
 542     // This offsets the image so that it is centered within the reference 
 543     // rectangle defined above. 
 544     wxCoord xoff 
= (fitRect
.width 
- maxX
) / 2; 
 545     wxCoord yoff 
= (fitRect
.height 
- maxY
) / 2; 
 546     OffsetLogicalOrigin(xoff
, yoff
); 
 548     // This offsets the image so that it is positioned at the bottom right of 
 549     // the reference rectangle defined above. 
 550 //    wxCoord xoff = (fitRect.width - maxX); 
 551 //    wxCoord yoff = (fitRect.height - maxY); 
 552 //    OffsetLogicalOrigin(xoff, yoff); 
 554     frame
->Draw(*GetDC()); 
 557 void MyPrintout::DrawPageTwo() 
 559     // You might use THIS code to set the printer DC to ROUGHLY reflect 
 560     // the screen text size. This page also draws lines of actual length 
 563     // Compare this to DrawPageOne(), which uses the really convenient routines 
 564     // from wxPrintout to fit the screen image onto the printed page. This page 
 565     // illustrates how to do all the scaling calculations yourself, if you're so 
 570     // Get the logical pixels per inch of screen and printer 
 571     int ppiScreenX
, ppiScreenY
; 
 572     GetPPIScreen(&ppiScreenX
, &ppiScreenY
); 
 573     int ppiPrinterX
, ppiPrinterY
; 
 574     GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
); 
 576     // This scales the DC so that the printout roughly represents the the screen 
 577     // scaling. The text point size _should_ be the right size but in fact is 
 578     // too small for some reason. This is a detail that will need to be 
 579     // addressed at some point but can be fudged for the moment. 
 580     float scale 
= (float)((float)ppiPrinterX
/(float)ppiScreenX
); 
 582     // Now we have to check in case our real page size is reduced (e.g. because 
 583     // we're drawing to a print preview memory DC) 
 584     int pageWidth
, pageHeight
; 
 587     GetPageSizePixels(&pageWidth
, &pageHeight
); 
 589     // If printer pageWidth == current DC width, then this doesn't change. But w 
 590     // might be the preview bitmap width, so scale down. 
 591     float overallScale 
= scale 
* (float)(w
/(float)pageWidth
); 
 592     dc
->SetUserScale(overallScale
, overallScale
); 
 594     // Calculate conversion factor for converting millimetres into logical 
 595     // units. There are approx. 25.4 mm to the inch. There are ppi device units 
 596     // to the inch. Therefore 1 mm corresponds to ppi/25.4 device units. We also 
 597     // divide by the screen-to-printer scaling factor, because we need to 
 598     // unscale to pass logical units to DrawLine. 
 600     // Draw 50 mm by 50 mm L shape 
 601     float logUnitsFactor 
= (float)(ppiPrinterX
/(scale
*25.4)); 
 602     float logUnits 
= (float)(50*logUnitsFactor
); 
 603     dc
->SetPen(* wxBLACK_PEN
); 
 604     dc
->DrawLine(50, 250, (long)(50.0 + logUnits
), 250); 
 605     dc
->DrawLine(50, 250, 50, (long)(250.0 + logUnits
)); 
 607     dc
->SetBackgroundMode(wxTRANSPARENT
); 
 608     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
 610     { // GetTextExtent demo: 
 611         wxString words
[7] = {_T("This "), _T("is "), _T("GetTextExtent "), _T("testing "), _T("string. "), _T("Enjoy "), _T("it!")}; 
 613         long x 
= 200, y
= 250; 
 614         wxFont 
fnt(15, wxSWISS
, wxNORMAL
, wxNORMAL
); 
 618         for (int i 
= 0; i 
< 7; i
++) 
 620             wxString word 
= words
[i
]; 
 621             word
.Remove( word
.Len()-1, 1 ); 
 622             dc
->GetTextExtent(word
, &w
, &h
); 
 623             dc
->DrawRectangle(x
, y
, w
, h
); 
 624             dc
->GetTextExtent(words
[i
], &w
, &h
); 
 625             dc
->DrawText(words
[i
], x
, y
); 
 631     dc
->SetFont(wxGetApp().m_testFont
); 
 633     dc
->DrawText(_T("Some test text"), 200, 300 ); 
 638     int rightMargin 
= 20; 
 640     int bottomMargin 
= 20; 
 642     int pageWidthMM
, pageHeightMM
; 
 643     GetPageSizeMM(&pageWidthMM
, &pageHeightMM
); 
 645     float leftMarginLogical 
= (float)(logUnitsFactor
*leftMargin
); 
 646     float topMarginLogical 
= (float)(logUnitsFactor
*topMargin
); 
 647     float bottomMarginLogical 
= (float)(logUnitsFactor
*(pageHeightMM 
- bottomMargin
)); 
 648     float rightMarginLogical 
= (float)(logUnitsFactor
*(pageWidthMM 
- rightMargin
)); 
 650     dc
->SetPen(* wxRED_PEN
); 
 651     dc
->DrawLine( (long)leftMarginLogical
, (long)topMarginLogical
, 
 652         (long)rightMarginLogical
, (long)topMarginLogical
); 
 653     dc
->DrawLine( (long)leftMarginLogical
, (long)bottomMarginLogical
, 
 654         (long)rightMarginLogical
,  (long)bottomMarginLogical
); 
 656     WritePageHeader(this, dc
, _T("A header"), logUnitsFactor
); 
 659 // Writes a header on a page. Margin units are in millimetres. 
 660 bool WritePageHeader(wxPrintout 
*printout
, wxDC 
*dc
, const wxChar 
*text
, float mmToLogical
) 
 663 static wxFont *headerFont = (wxFont *) NULL; 
 666 headerFont = wxTheFontList->FindOrCreateFont(16, wxSWISS, wxNORMAL, wxBOLD); 
 668 dc->SetFont(headerFont); 
 671     int pageWidthMM
, pageHeightMM
; 
 673     printout
->GetPageSizeMM(&pageWidthMM
, &pageHeightMM
); 
 674     wxUnusedVar(pageHeightMM
); 
 678     int rightMargin 
= 10; 
 680     float leftMarginLogical 
= (float)(mmToLogical
*leftMargin
); 
 681     float topMarginLogical 
= (float)(mmToLogical
*topMargin
); 
 682     float rightMarginLogical 
= (float)(mmToLogical
*(pageWidthMM 
- rightMargin
)); 
 684     wxCoord xExtent
, yExtent
; 
 685     dc
->GetTextExtent(text
, &xExtent
, &yExtent
); 
 686     float xPos 
= (float)(((((pageWidthMM 
- leftMargin 
- rightMargin
)/2.0)+leftMargin
)*mmToLogical
) - (xExtent
/2.0)); 
 687     dc
->DrawText(text
, (long)xPos
, (long)topMarginLogical
); 
 689     dc
->SetPen(* wxBLACK_PEN
); 
 690     dc
->DrawLine( (long)leftMarginLogical
, (long)(topMarginLogical
+yExtent
), 
 691         (long)rightMarginLogical
, (long)topMarginLogical
+yExtent 
);