Robert Lang's patch [ 1583183 ] Fixes printing/print preview inconsistencies

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42522 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2006-10-27 13:07:40 +00:00
parent ea28077683
commit f415cab9ef
32 changed files with 1308 additions and 294 deletions

View File

@@ -566,6 +566,219 @@ void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toP
*toPage = 1;
}
void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize)
{
// Set the DC scale and origin so that the given image size fits within the
// entire page and the origin is at the top left corner of the page. Note
// that with most printers, portions of the page will be non-printable. Use
// this if you're managing your own page margins.
if (!m_printoutDC) return;
wxRect paperRect = GetPaperRectPixels();
wxCoord pw, ph;
GetPageSizePixels(&pw, &ph);
wxCoord w, h;
m_printoutDC->GetSize(&w, &h);
float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x));
float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y));
float actualScale = wxMin(scaleX, scaleY);
m_printoutDC->SetUserScale(actualScale, actualScale);
m_printoutDC->SetDeviceOrigin(0, 0);
wxRect logicalPaperRect = GetLogicalPaperRect();
SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y);
}
void wxPrintout::FitThisSizeToPage(const wxSize& imageSize)
{
// Set the DC scale and origin so that the given image size fits within the
// printable area of the page and the origin is at the top left corner of
// the printable area.
if (!m_printoutDC) return;
int w, h;
m_printoutDC->GetSize(&w, &h);
float scaleX = float(w) / imageSize.x;
float scaleY = float(h) / imageSize.y;
float actualScale = wxMin(scaleX, scaleY);
m_printoutDC->SetUserScale(actualScale, actualScale);
m_printoutDC->SetDeviceOrigin(0, 0);
}
void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData)
{
// Set the DC scale and origin so that the given image size fits within the
// page margins defined in the given wxPageSetupDialogData object and the
// origin is at the top left corner of the page margins.
if (!m_printoutDC) return;
wxRect paperRect = GetPaperRectPixels();
wxCoord pw, ph;
GetPageSizePixels(&pw, &ph);
wxPoint topLeft = pageSetupData.GetMarginTopLeft();
wxPoint bottomRight = pageSetupData.GetMarginBottomRight();
wxCoord mw, mh;
GetPageSizeMM(&mw, &mh);
float mmToDeviceX = float(pw) / mw;
float mmToDeviceY = float(ph) / mh;
wxRect pageMarginsRect(paperRect.x + wxCoord(mmToDeviceX * topLeft.x),
paperRect.y + wxCoord(mmToDeviceY * topLeft.y),
paperRect.width - wxCoord(mmToDeviceX * (topLeft.x + bottomRight.x)),
paperRect.height - wxCoord(mmToDeviceY * (topLeft.y + bottomRight.y)));
wxCoord w, h;
m_printoutDC->GetSize(&w, &h);
float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x);
float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y);
float actualScale = wxMin(scaleX, scaleY);
m_printoutDC->SetUserScale(actualScale, actualScale);
m_printoutDC->SetDeviceOrigin(0, 0);
wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData);
SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y);
}
void wxPrintout::MapScreenSizeToPaper()
{
// Set the DC scale so that an image on the screen is the same size on the
// paper and the origin is at the top left of the paper. Note that with most
// printers, portions of the page will be cut off. Use this if you're
// managing your own page margins.
if (!m_printoutDC) return;
MapScreenSizeToPage();
wxRect logicalPaperRect = GetLogicalPaperRect();
SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y);
}
void wxPrintout::MapScreenSizeToPage()
{
// Set the DC scale and origin so that an image on the screen is the same
// size on the paper and the origin is at the top left of the printable area.
if (!m_printoutDC) return;
int ppiScreenX, ppiScreenY;
GetPPIScreen(&ppiScreenX, &ppiScreenY);
int ppiPrinterX, ppiPrinterY;
GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
int w, h;
m_printoutDC->GetSize(&w, &h);
int pageSizePixelsX, pageSizePixelsY;
GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY);
float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX);
float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY);
m_printoutDC->SetUserScale(userScaleX, userScaleY);
m_printoutDC->SetDeviceOrigin(0, 0);
}
void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData)
{
// Set the DC scale so that an image on the screen is the same size on the
// paper and the origin is at the top left of the page margins defined by
// the given wxPageSetupDialogData object.
if (!m_printoutDC) return;
MapScreenSizeToPage();
wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData);
SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y);
}
void wxPrintout::MapScreenSizeToDevice()
{
// Set the DC scale so that a screen pixel is the same size as a device
// pixel and the origin is at the top left of the printable area.
if (!m_printoutDC) return;
int w, h;
m_printoutDC->GetSize(&w, &h);
int pageSizePixelsX, pageSizePixelsY;
GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY);
float userScaleX = float(w) / pageSizePixelsX;
float userScaleY = float(h) / pageSizePixelsY;
m_printoutDC->SetUserScale(userScaleX, userScaleY);
m_printoutDC->SetDeviceOrigin(0, 0);
}
wxRect wxPrintout::GetLogicalPaperRect() const
{
// Return the rectangle in logical units that corresponds to the paper
// rectangle.
wxRect paperRect = GetPaperRectPixels();
wxCoord pw, ph;
GetPageSizePixels(&pw, &ph);
wxCoord w, h;
m_printoutDC->GetSize(&w, &h);
if (w == pw && h == ph) {
// this DC matches the printed page, so no scaling
return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x),
m_printoutDC->DeviceToLogicalY(paperRect.y),
m_printoutDC->DeviceToLogicalXRel(paperRect.width),
m_printoutDC->DeviceToLogicalYRel(paperRect.height));
}
// This DC doesn't match the printed page, so we have to scale.
float scaleX = float(w) / pw;
float scaleY = float(h) / ph;
return wxRect(m_printoutDC->DeviceToLogicalX(wxCoord(paperRect.x * scaleX)),
m_printoutDC->DeviceToLogicalY(wxCoord(paperRect.y * scaleY)),
m_printoutDC->DeviceToLogicalXRel(wxCoord(paperRect.width * scaleX)),
m_printoutDC->DeviceToLogicalYRel(wxCoord(paperRect.height * scaleY)));
}
wxRect wxPrintout::GetLogicalPageRect() const
{
// Return the rectangle in logical units that corresponds to the printable
// area.
int w, h;
m_printoutDC->GetSize(&w, &h);
return wxRect(m_printoutDC->DeviceToLogicalX(0),
m_printoutDC->DeviceToLogicalY(0),
m_printoutDC->DeviceToLogicalXRel(w),
m_printoutDC->DeviceToLogicalYRel(h));
}
wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const
{
// Return the rectangle in logical units that corresponds to the region
// within the page margins as specified by the given wxPageSetupDialogData
// object.
wxRect paperRect = GetPaperRectPixels();
wxCoord pw, ph;
GetPageSizePixels(&pw, &ph);
wxPoint topLeft = pageSetupData.GetMarginTopLeft();
wxPoint bottomRight = pageSetupData.GetMarginBottomRight();
wxCoord mw, mh;
GetPageSizeMM(&mw, &mh);
float mmToDeviceX = float(pw) / mw;
float mmToDeviceY = float(ph) / mh;
wxRect pageMarginsRect(paperRect.x + wxCoord(mmToDeviceX * topLeft.x),
paperRect.y + wxCoord(mmToDeviceY * topLeft.y),
paperRect.width - wxCoord(mmToDeviceX * (topLeft.x + bottomRight.x)),
paperRect.height - wxCoord(mmToDeviceY * (topLeft.y + bottomRight.y)));
wxCoord w, h;
m_printoutDC->GetSize(&w, &h);
if (w == pw && h == ph) {
// this DC matches the printed page, so no scaling
return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x),
m_printoutDC->DeviceToLogicalY(pageMarginsRect.y),
m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width),
m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height));
}
// This DC doesn't match the printed page, so we have to scale.
float scaleX = float(w) / pw;
float scaleY = float(h) / ph;
return wxRect(m_printoutDC->DeviceToLogicalX(wxCoord(pageMarginsRect.x * scaleX)),
m_printoutDC->DeviceToLogicalY(wxCoord(pageMarginsRect.y * scaleY)),
m_printoutDC->DeviceToLogicalXRel(wxCoord(pageMarginsRect.width * scaleX)),
m_printoutDC->DeviceToLogicalYRel(wxCoord(pageMarginsRect.height * scaleY)));
}
void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y)
{
// Set the device origin by specifying a point in logical coordinates.
m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x),
m_printoutDC->LogicalToDeviceY(y));
}
void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff)
{
// Offset the device origin by a specified distance in device coordinates.
wxCoord x = m_printoutDC->LogicalToDeviceX(0);
wxCoord y = m_printoutDC->LogicalToDeviceY(0);
m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff),
y + m_printoutDC->LogicalToDeviceYRel(yoff));
}
//----------------------------------------------------------------------------
// wxPreviewCanvas
//----------------------------------------------------------------------------
@@ -1177,6 +1390,39 @@ wxFrame *wxPrintPreviewBase::GetFrame() const
wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const
{ return m_previewCanvas; }
void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect)
{
// Calculate the rectangles for the printable area of the page and the
// entire paper as they appear on the canvas on-screen.
int canvasWidth, canvasHeight;
canvas->GetSize(&canvasWidth, &canvasHeight);
float zoomScale = float(m_currentZoom) / 100;
float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX;
float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY;
wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels();
wxCoord devicePrintableWidth, devicePrintableHeight;
m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight);
float scaleX = screenPrintableWidth / devicePrintableWidth;
float scaleY = screenPrintableHeight / devicePrintableHeight;
paperRect.width = wxCoord(scaleX * devicePaperRect.width);
paperRect.height = wxCoord(scaleY * devicePaperRect.height);
paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0);
if (paperRect.x < m_leftMargin)
paperRect.x = m_leftMargin;
paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0);
if (paperRect.y < m_topMargin)
paperRect.y = m_topMargin;
pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x);
pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y);
pageRect.width = wxCoord(screenPrintableWidth);
pageRect.height = wxCoord(screenPrintableHeight);
}
bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc)
{
DrawBlankPage(canvas, dc);
@@ -1184,32 +1430,20 @@ bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc)
if (!m_previewBitmap)
if (!RenderPage(m_currentPage))
return false;
if (!m_previewBitmap)
return false;
if (!canvas)
return false;
int canvasWidth, canvasHeight;
canvas->GetSize(&canvasWidth, &canvasHeight);
double zoomScale = ((float)m_currentZoom/(float)100);
double actualWidth = (zoomScale*m_pageWidth*m_previewScale);
// float actualHeight = (float)(zoomScale*m_pageHeight*m_previewScale);
int x = (int) ((canvasWidth - actualWidth)/2.0);
if (x < m_leftMargin)
x = m_leftMargin;
int y = m_topMargin;
wxRect pageRect, paperRect;
CalcRects(canvas, pageRect, paperRect);
wxMemoryDC temp_dc;
temp_dc.SelectObject(*m_previewBitmap);
dc.Blit(x, y, m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0);
dc.Blit(pageRect.x, pageRect.y,
m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0);
temp_dc.SelectObject(wxNullBitmap);
return true;
}
@@ -1219,18 +1453,12 @@ void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas)
if (!canvas)
return ;
int canvasWidth, canvasHeight;
canvas->GetSize(&canvasWidth, &canvasHeight);
double zoomScale = ((float)m_currentZoom/(float)100);
double actualWidth = (zoomScale*m_pageWidth*m_previewScale);
double actualHeight = (zoomScale*m_pageHeight*m_previewScale);
// Set the scrollbars appropriately
int totalWidth = (int)(actualWidth + 2*m_leftMargin);
int totalHeight = (int)(actualHeight + 2*m_topMargin);
int scrollUnitsX = totalWidth/10;
int scrollUnitsY = totalHeight/10;
wxRect pageRect, paperRect;
CalcRects(canvas, pageRect, paperRect);
int totalWidth = paperRect.width + 2 * m_leftMargin;
int totalHeight = paperRect.height + 2 * m_topMargin;
int scrollUnitsX = totalWidth / 10;
int scrollUnitsY = totalHeight / 10;
wxSize virtualSize = canvas->GetVirtualSize();
if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight)
canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true);
@@ -1240,23 +1468,19 @@ bool wxPrintPreviewBase::RenderPage(int pageNum)
{
wxBusyCursor busy;
int canvasWidth, canvasHeight;
if (!m_previewCanvas)
{
wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!"));
return false;
}
m_previewCanvas->GetSize(&canvasWidth, &canvasHeight);
double zoomScale = (m_currentZoom/100.0);
int actualWidth = (int)(zoomScale*m_pageWidth*m_previewScale);
int actualHeight = (int)(zoomScale*m_pageHeight*m_previewScale);
wxRect pageRect, paperRect;
CalcRects(m_previewCanvas, pageRect, paperRect);
if (!m_previewBitmap)
{
m_previewBitmap = new wxBitmap((int)actualWidth, (int)actualHeight);
m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height);
if (!m_previewBitmap || !m_previewBitmap->Ok())
{
if (m_previewBitmap) {
@@ -1320,43 +1544,28 @@ bool wxPrintPreviewBase::RenderPage(int pageNum)
return true;
}
bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc)
{
int canvasWidth, canvasHeight;
canvas->GetSize(&canvasWidth, &canvasHeight);
wxRect pageRect, paperRect;
float zoomScale = (float)((float)m_currentZoom/(float)100);
float actualWidth = zoomScale*m_pageWidth*m_previewScale;
float actualHeight = zoomScale*m_pageHeight*m_previewScale;
CalcRects(canvas, pageRect, paperRect);
float x = (float)((canvasWidth - actualWidth)/2.0);
if (x < m_leftMargin)
x = (float)m_leftMargin;
float y = (float)m_topMargin;
// Draw shadow, allowing for 1-pixel border AROUND the actual paper
wxCoord shadowOffset = 4;
// Draw shadow, allowing for 1-pixel border AROUND the actual page
int shadowOffset = 4;
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
/*
dc.DrawRectangle((int)(x-1 + shadowOffset), (int)(y-1 + shadowOffset), (int)(actualWidth+2), (int)(actualHeight+2));
*/
dc.DrawRectangle((int)(x + shadowOffset), (int)(y + actualHeight+1), (int)(actualWidth), shadowOffset);
dc.DrawRectangle((int)(x + actualWidth), (int)(y + shadowOffset), shadowOffset, (int)(actualHeight));
dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1,
paperRect.width, shadowOffset);
// Draw blank page allowing for 1-pixel border AROUND the actual page
dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset,
shadowOffset, paperRect.height);
// Draw blank page allowing for 1-pixel border AROUND the actual paper
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
/*
wxRegion update_region = canvas->GetUpdateRegion();
wxRect r = update_region.GetBox();
printf( "x: %d y: %d w: %d h: %d.\n", (int)r.x, (int)r.y, (int)r.width, (int)r.height );
*/
dc.DrawRectangle((int)(x-2), (int)(y-1), (int)(actualWidth+3), (int)(actualHeight+2));
dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1,
paperRect.width + 3, paperRect.height + 2);
return true;
}
@@ -1399,6 +1608,7 @@ bool wxPrintPreviewBase::IsOk() const
{ return m_isOk; }
void wxPrintPreviewBase::SetOk(bool ok)
{ m_isOk = ok; }
//----------------------------------------------------------------------------
// wxPrintPreview
//----------------------------------------------------------------------------