X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2786b6232c5967dd79278a20d9558d79bebc41f8..4d8209b9070ea7120078e83a648f3627e57bc15a:/src/richtext/richtextprint.cpp diff --git a/src/richtext/richtextprint.cpp b/src/richtext/richtextprint.cpp index 5319131f74..59c331d02f 100644 --- a/src/richtext/richtextprint.cpp +++ b/src/richtext/richtextprint.cpp @@ -50,13 +50,14 @@ void wxRichTextPrintout::OnPreparePrinting() { wxBusyCursor wait; - m_numPages = 0; + m_numPages = 1; 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 @@ -66,69 +67,88 @@ void wxRichTextPrintout::OnPreparePrinting() { 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; - - if ((lineY + line->GetSize().y) > rect.GetBottom()) + 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_numPages ++; - } + m_pageBreaksStart.Add(lastStartPos); + m_pageBreaksEnd.Add(GetRichTextBuffer()->GetOwnRange().GetEnd()); + m_pageYOffsets.Add(yOffset); } } @@ -170,7 +190,7 @@ void wxRichTextPrintout::RenderPage(wxDC *dc, int page) return; wxBusyCursor wait; - + wxRect textRect, headerRect, footerRect; /// Sets the DC scaling and returns important page rectangles @@ -178,17 +198,17 @@ void wxRichTextPrintout::RenderPage(wxDC *dc, int page) 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); @@ -201,7 +221,7 @@ void wxRichTextPrintout::RenderPage(wxDC *dc, int page) //int tx, ty; //dc->GetTextExtent(headerTextLeft, & tx, & ty); - + int x = headerRect.GetLeft(); int y = headerRect.GetX(); dc->DrawText(headerTextLeft, x, y); @@ -229,7 +249,7 @@ void wxRichTextPrintout::RenderPage(wxDC *dc, int page) 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); @@ -267,11 +287,30 @@ void wxRichTextPrintout::RenderPage(wxDC *dc, int page) 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) @@ -301,7 +340,7 @@ void wxRichTextPrintout::CalculateScaling(wxDC* dc, wxRect& textRect, wxRect& he 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); @@ -309,24 +348,24 @@ void wxRichTextPrintout::CalculateScaling(wxDC* dc, wxRect& textRect, wxRect& he // 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() || @@ -337,19 +376,19 @@ void wxRichTextPrintout::CalculateScaling(wxDC* dc, wxRect& textRect, wxRect& he !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); @@ -362,18 +401,18 @@ void wxRichTextPrintout::CalculateScaling(wxDC* dc, wxRect& textRect, wxRect& he !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; @@ -411,7 +450,7 @@ wxRichTextPrinting::wxRichTextPrinting(const wxString& name, wxWindow *parentWin m_parentWindow = parentWindow; m_title = name; m_printData = NULL; - + m_previewRect = wxRect(wxPoint(100, 100), wxSize(800, 800)); m_pageSetupData = new wxPageSetupDialogData; @@ -435,6 +474,17 @@ wxPrintData *wxRichTextPrinting::GetPrintData() return m_printData; } +/// Set print and page setup data +void wxRichTextPrinting::SetPrintData(const wxPrintData& printData) +{ + (*GetPrintData()) = printData; +} + +void wxRichTextPrinting::SetPageSetupData(const wxPageSetupDialogData& pageSetupData) +{ + (*GetPageSetupData()) = pageSetupData; +} + /// Set the rich text buffer pointer, deleting the existing object if present void wxRichTextPrinting::SetRichTextBufferPrinting(wxRichTextBuffer* buf) { @@ -467,7 +517,7 @@ bool wxRichTextPrinting::PreviewFile(const wxString& richTextFile) } else SetRichTextBufferPrinting(new wxRichTextBuffer(*m_richTextBufferPreview)); - + wxRichTextPrintout *p1 = CreatePrintout(); p1->SetRichTextBuffer(m_richTextBufferPreview); @@ -483,14 +533,14 @@ 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) +bool wxRichTextPrinting::PrintFile(const wxString& richTextFile, bool showPrintDialog) { SetRichTextBufferPrinting(new wxRichTextBuffer); @@ -503,19 +553,19 @@ bool wxRichTextPrinting::PrintFile(const wxString& richTextFile) wxRichTextPrintout *p = CreatePrintout(); p->SetRichTextBuffer(m_richTextBufferPrinting); - bool ret = DoPrint(p); + bool ret = DoPrint(p, showPrintDialog); delete p; return ret; } -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; } @@ -525,7 +575,7 @@ bool wxRichTextPrinting::DoPreview(wxRichTextPrintout *printout1, wxRichTextPrin // 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; @@ -540,12 +590,12 @@ bool wxRichTextPrinting::DoPreview(wxRichTextPrintout *printout1, wxRichTextPrin 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; } @@ -556,7 +606,7 @@ bool wxRichTextPrinting::DoPrint(wxRichTextPrintout *printout) 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;