// Purpose: Rich text printing classes
// Author: Julian Smart
// Created: 2006-10-24
-// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
m_pageBreaksStart.Clear();
m_pageBreaksEnd.Clear();
-
+ m_pageYOffsets.Clear();
+
int lastStartPos = 0;
-
+
wxRect rect, headerRect, footerRect;
/// Sets the DC scaling and returns important page rectangles
{
GetRichTextBuffer()->Invalidate(wxRICHTEXT_ALL);
- GetRichTextBuffer()->Layout(*GetDC(), rect, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
-
+ wxRichTextDrawingContext context(GetRichTextBuffer());
+ GetRichTextBuffer()->Layout(*GetDC(), context, rect, rect, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
+
// Now calculate the page breaks
-
+
int yOffset = 0;
-
+
wxRichTextLine* lastLine = NULL;
-
+
wxRichTextObjectList::compatibility_iterator node = GetRichTextBuffer()->GetChildren().GetFirst();
while (node)
{
// child is a paragraph
wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (child != NULL);
-
- wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
- while (node2)
+ if (child)
{
- wxRichTextLine* line = node2->GetData();
-
- // Set the line to the page-adjusted position
- line->SetPosition(wxPoint(line->GetPosition().x, line->GetPosition().y - yOffset));
-
- int lineY = child->GetPosition().y + line->GetPosition().y;
-
- // Break the page if either we're going off the bottom, or this paragraph specifies
- // an explicit page break
-
- if (((lineY + line->GetSize().y) > rect.GetBottom()) ||
- ((node2 == child->GetLines().GetFirst()) && child->GetAttributes().HasPageBreak()))
+ wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
+ while (node2)
{
- // New page starting at this line
- int newY = rect.y;
-
- // We increase the offset by the difference between new and old positions
-
- int increaseOffsetBy = lineY - newY;
- yOffset += increaseOffsetBy;
-
- line->SetPosition(wxPoint(line->GetPosition().x, newY - child->GetPosition().y));
-
- if (!lastLine)
+ wxRichTextLine* line = node2->GetData();
+
+ int lineY = child->GetPosition().y + line->GetPosition().y - yOffset;
+ bool hasHardPageBreak = ((node2 == child->GetLines().GetFirst()) && child->GetAttributes().HasPageBreak());
+
+ // Break the page if either we're going off the bottom, or this paragraph specifies
+ // an explicit page break
+
+ if (((lineY + line->GetSize().y) > rect.GetBottom()) || hasHardPageBreak)
+ {
+ // Only if we're not at the start of the document, and
+ // even then, only if either it's a hard break or if the object
+ // can fit in a whole page (otherwise there's no point in making
+ // the rest of this page blank).
+ if (lastLine && (hasHardPageBreak || (line->GetSize().y <= rect.GetHeight())))
+ {
+ // New page starting at this line
+ int newY = rect.y;
+
+ // We increase the offset by the difference between new and old positions
+
+ int increaseOffsetBy = lineY - newY;
+ yOffset += increaseOffsetBy;
+
+ m_pageBreaksStart.Add(lastStartPos);
+ m_pageBreaksEnd.Add(lastLine->GetAbsoluteRange().GetEnd());
+ m_pageYOffsets.Add(yOffset);
+
+ lastStartPos = line->GetAbsoluteRange().GetStart();
+ m_numPages ++;
+ }
+
lastLine = line;
-
- m_pageBreaksStart.Add(lastStartPos);
- m_pageBreaksEnd.Add(lastLine->GetAbsoluteRange().GetEnd());
-
- lastStartPos = line->GetAbsoluteRange().GetStart();
-
- m_numPages ++;
- }
-
- lastLine = line;
- node2 = node2->GetNext();
+ // Now create page breaks for the rest of the line, if it's larger than the page height
+ int contentLeft = line->GetSize().y - rect.GetHeight();
+ while (contentLeft >= 0)
+ {
+ yOffset += rect.GetHeight();
+ contentLeft -= rect.GetHeight();
+
+ m_pageBreaksStart.Add(lastStartPos);
+ m_pageBreaksEnd.Add(lastLine->GetAbsoluteRange().GetEnd());
+ m_pageYOffsets.Add(yOffset);
+
+ m_numPages ++;
+ }
+ }
+
+ lastLine = line;
+
+ node2 = node2->GetNext();
+ }
}
node = node->GetNext();
}
// Closing page break
- if (m_pageBreaksStart.GetCount() == 0 || (m_pageBreaksEnd[m_pageBreaksEnd.GetCount()-1] < (GetRichTextBuffer()->GetRange().GetEnd()-1)))
- {
- m_pageBreaksStart.Add(lastStartPos);
- m_pageBreaksEnd.Add(GetRichTextBuffer()->GetRange().GetEnd());
- }
+ m_pageBreaksStart.Add(lastStartPos);
+ m_pageBreaksEnd.Add(GetRichTextBuffer()->GetOwnRange().GetEnd());
+ m_pageYOffsets.Add(yOffset);
}
}
return;
wxBusyCursor wait;
-
+
wxRect textRect, headerRect, footerRect;
/// Sets the DC scaling and returns important page rectangles
if (page > 1 || m_headerFooterData.GetShowOnFirstPage())
{
- if (m_headerFooterData.GetFont().Ok())
+ if (m_headerFooterData.GetFont().IsOk())
dc->SetFont(m_headerFooterData.GetFont());
else
dc->SetFont(*wxNORMAL_FONT);
- if (m_headerFooterData.GetTextColour().Ok())
+ if (m_headerFooterData.GetTextColour().IsOk())
dc->SetTextForeground(m_headerFooterData.GetTextColour());
else
dc->SetTextForeground(*wxBLACK);
- dc->SetBackgroundMode(wxTRANSPARENT);
+ dc->SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
- // Draw header, if any
+ // Draw header, if any
wxRichTextOddEvenPage oddEven = ((page % 2) == 1) ? wxRICHTEXT_PAGE_ODD : wxRICHTEXT_PAGE_EVEN;
wxString headerTextCentre = m_headerFooterData.GetHeaderText(oddEven, wxRICHTEXT_PAGE_CENTRE);
//int tx, ty;
//dc->GetTextExtent(headerTextLeft, & tx, & ty);
-
+
int x = headerRect.GetLeft();
int y = headerRect.GetX();
dc->DrawText(headerTextLeft, x, y);
dc->DrawText(headerTextRight, x, y);
}
- // Draw footer, if any
+ // Draw footer, if any
wxString footerTextCentre = m_headerFooterData.GetFooterText(oddEven, wxRICHTEXT_PAGE_CENTRE);
wxString footerTextLeft = m_headerFooterData.GetFooterText(oddEven, wxRICHTEXT_PAGE_LEFT);
wxString footerTextRight = m_headerFooterData.GetFooterText(oddEven, wxRICHTEXT_PAGE_RIGHT);
int y = footerRect.GetBottom() - ty;
dc->DrawText(footerTextRight, x, y);
}
- }
+ }
wxRichTextRange rangeToDraw(m_pageBreaksStart[page-1], m_pageBreaksEnd[page-1]);
- GetRichTextBuffer()->Draw(*dc, rangeToDraw, wxRichTextRange(-1,-1), textRect, 0 /* descent */, wxRICHTEXT_DRAW_IGNORE_CACHE /* flags */);
+ wxPoint oldOrigin = dc->GetLogicalOrigin();
+ double scaleX, scaleY;
+ dc->GetUserScale(& scaleX, & scaleY);
+
+ int yOffset = 0;
+ if (page > 1)
+ yOffset = m_pageYOffsets[page-2];
+
+ if (yOffset != oldOrigin.y)
+ dc->SetLogicalOrigin(oldOrigin.x, oldOrigin.y + yOffset);
+
+ dc->SetClippingRegion(wxRect(textRect.x, textRect.y + yOffset, textRect.width, textRect.height));
+
+ wxRichTextDrawingContext context(GetRichTextBuffer());
+ GetRichTextBuffer()->Draw(*dc, context, rangeToDraw, wxRichTextSelection(), textRect, 0 /* descent */, wxRICHTEXT_DRAW_IGNORE_CACHE|wxRICHTEXT_DRAW_PRINT /* flags */);
+
+ dc->DestroyClippingRegion();
+
+ if (yOffset != oldOrigin.y)
+ dc->SetLogicalOrigin(oldOrigin.x, oldOrigin.y);
}
void wxRichTextPrintout::SetMargins(int top, int bottom, int left, int right)
int w, h;
dc->GetSize(&w, &h);
GetPageSizePixels(&pageWidth, &pageHeight);
-
+
// If printer pageWidth == current DC width, then this doesn't
// change. But w might be the preview bitmap width, so scale down.
float previewScale = (float)(w/(float)pageWidth);
// The dimensions used for indentation etc. have to be unscaled
// during printing to be correct when scaling is applied.
- if (!IsPreview())
- m_richTextBuffer->SetScale(scale);
-
+ // Also, correct the conversions in wxRTC using DC instead of print DC.
+ m_richTextBuffer->SetScale(scale * float(dc->GetPPI().x)/float(ppiPrinterX));
+
// Calculate margins
int marginLeft = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_marginLeft);
int marginTop = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_marginTop);
int marginRight = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_marginRight);
int marginBottom = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_marginBottom);
-
+
// Header and footer margins
int headerMargin = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_headerFooterData.GetHeaderMargin());
int footerMargin = wxRichTextObject::ConvertTenthsMMToPixels(ppiPrinterX, m_headerFooterData.GetFooterMargin());
-
+
dc->SetUserScale(overallScale, overallScale);
wxRect rect((int) (marginLeft/scale), (int) (marginTop/scale),
(int) ((pageWidth - marginLeft - marginRight)/scale), (int)((pageHeight - marginTop - marginBottom)/scale));
-
+
headerRect = wxRect(0, 0, 0, 0);
if (!m_headerFooterData.GetHeaderText(wxRICHTEXT_PAGE_ODD, wxRICHTEXT_PAGE_LEFT).IsEmpty() ||
!m_headerFooterData.GetHeaderText(wxRICHTEXT_PAGE_EVEN, wxRICHTEXT_PAGE_CENTRE).IsEmpty() ||
!m_headerFooterData.GetHeaderText(wxRICHTEXT_PAGE_EVEN, wxRICHTEXT_PAGE_RIGHT).IsEmpty())
{
- if (m_headerFooterData.GetFont().Ok())
+ if (m_headerFooterData.GetFont().IsOk())
dc->SetFont(m_headerFooterData.GetFont());
else
dc->SetFont(*wxNORMAL_FONT);
-
+
int charHeight = dc->GetCharHeight();
-
+
int headerHeight = (int) (charHeight + headerMargin/scale);
headerRect = wxRect(rect.x, rect.y, rect.width, headerHeight);
rect.y += headerHeight;
- rect.height -= headerHeight;
+ rect.height -= headerHeight;
}
footerRect = wxRect(0, 0, 0, 0);
!m_headerFooterData.GetFooterText(wxRICHTEXT_PAGE_EVEN, wxRICHTEXT_PAGE_CENTRE).IsEmpty() ||
!m_headerFooterData.GetFooterText(wxRICHTEXT_PAGE_EVEN, wxRICHTEXT_PAGE_RIGHT).IsEmpty())
{
- if (m_headerFooterData.GetFont().Ok())
+ if (m_headerFooterData.GetFont().IsOk())
dc->SetFont(m_headerFooterData.GetFont());
else
dc->SetFont(*wxNORMAL_FONT);
-
+
int charHeight = dc->GetCharHeight();
-
+
int footerHeight = (int) (charHeight + footerMargin/scale);
footerRect = wxRect(rect.x, rect.y + rect.height, rect.width, footerHeight);
- rect.height -= footerHeight;
+ rect.height -= footerHeight;
}
textRect = rect;
m_parentWindow = parentWindow;
m_title = name;
m_printData = NULL;
-
+
m_previewRect = wxRect(wxPoint(100, 100), wxSize(800, 800));
m_pageSetupData = new wxPageSetupDialogData;
(*GetPrintData()) = printData;
}
-void wxRichTextPrinting::SetPageSetupData(const wxPageSetupData& pageSetupData)
+void wxRichTextPrinting::SetPageSetupData(const wxPageSetupDialogData& pageSetupData)
{
(*GetPageSetupData()) = pageSetupData;
}
m_richTextBufferPreview = buf;
}
+#if wxUSE_FFILE && wxUSE_STREAMS
bool wxRichTextPrinting::PreviewFile(const wxString& richTextFile)
{
SetRichTextBufferPreview(new wxRichTextBuffer);
}
else
SetRichTextBufferPrinting(new wxRichTextBuffer(*m_richTextBufferPreview));
-
+
wxRichTextPrintout *p1 = CreatePrintout();
p1->SetRichTextBuffer(m_richTextBufferPreview);
p2->SetRichTextBuffer(m_richTextBufferPrinting);
return DoPreview(p1, p2);
}
+#endif // wxUSE_FFILE && wxUSE_STREAMS
bool wxRichTextPrinting::PreviewBuffer(const wxRichTextBuffer& buffer)
{
wxRichTextPrintout *p1 = CreatePrintout();
p1->SetRichTextBuffer(m_richTextBufferPreview);
-
+
wxRichTextPrintout *p2 = CreatePrintout();
p2->SetRichTextBuffer(m_richTextBufferPrinting);
return DoPreview(p1, p2);
}
-bool wxRichTextPrinting::PrintFile(const wxString& richTextFile)
+#if wxUSE_FFILE && wxUSE_STREAMS
+bool wxRichTextPrinting::PrintFile(const wxString& richTextFile, bool showPrintDialog)
{
SetRichTextBufferPrinting(new wxRichTextBuffer);
wxRichTextPrintout *p = CreatePrintout();
p->SetRichTextBuffer(m_richTextBufferPrinting);
- bool ret = DoPrint(p);
+ bool ret = DoPrint(p, showPrintDialog);
delete p;
return ret;
}
+#endif // wxUSE_FFILE && wxUSE_STREAMS
-bool wxRichTextPrinting::PrintBuffer(const wxRichTextBuffer& buffer)
+bool wxRichTextPrinting::PrintBuffer(const wxRichTextBuffer& buffer, bool showPrintDialog)
{
SetRichTextBufferPrinting(new wxRichTextBuffer(buffer));
wxRichTextPrintout *p = CreatePrintout();
p->SetRichTextBuffer(m_richTextBufferPrinting);
- bool ret = DoPrint(p);
+ bool ret = DoPrint(p, showPrintDialog);
delete p;
return ret;
}
// Pass two printout objects: for preview, and possible printing.
wxPrintDialogData printDialogData(*GetPrintData());
wxPrintPreview *preview = new wxPrintPreview(printout1, printout2, &printDialogData);
- if (!preview->Ok())
+ if (!preview->IsOk())
{
delete preview;
return false;
return true;
}
-bool wxRichTextPrinting::DoPrint(wxRichTextPrintout *printout)
+bool wxRichTextPrinting::DoPrint(wxRichTextPrintout *printout, bool showPrintDialog)
{
wxPrintDialogData printDialogData(*GetPrintData());
wxPrinter printer(&printDialogData);
- if (!printer.Print(m_parentWindow, printout, true))
+ if (!printer.Print(m_parentWindow, printout, showPrintDialog))
{
return false;
}
void wxRichTextPrinting::PageSetup()
{
- if (!GetPrintData()->Ok())
+ if (!GetPrintData()->IsOk())
{
wxLogError(_("There was a problem during page setup: you may need to set a default printer."));
return;