]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextprint.cpp
Ensure there is valid context for DrawRectangle
[wxWidgets.git] / src / richtext / richtextprint.cpp
index 73876d11fe8712c6e8885081ca8a8eab978e09ea..59c331d02fc940b570ed949db53b3ccc7b3d7792 100644 (file)
@@ -54,9 +54,10 @@ void wxRichTextPrintout::OnPreparePrinting()
 
     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,72 +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;
-                
-                // 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);
     }
 }
 
@@ -173,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
@@ -181,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);
@@ -204,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);
@@ -232,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);
@@ -270,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)
@@ -304,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);
@@ -312,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() ||
@@ -340,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);
@@ -365,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;
@@ -414,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;
@@ -438,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)
 {
@@ -470,7 +517,7 @@ bool wxRichTextPrinting::PreviewFile(const wxString& richTextFile)
     }
     else
         SetRichTextBufferPrinting(new wxRichTextBuffer(*m_richTextBufferPreview));
-    
+
     wxRichTextPrintout *p1 = CreatePrintout();
     p1->SetRichTextBuffer(m_richTextBufferPreview);
 
@@ -486,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);
 
@@ -506,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;
 }
@@ -528,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;
@@ -543,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;
     }
@@ -559,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;