1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: steprint.cpp
3 // Purpose: wxSTEditorPrintout
4 // Author: John Labenski, parts taken from wxGuide by Otto Wyss
5 // Modified by:
6 // Created: 11/05/2002
7 // RCS-ID:
8 // Copyright: (c) John Labenski, Otto Wyss
9 // Licence: wxWidgets licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #include "precomp.h"
13
14 #include "wx/stedit/steprint.h"
15 #include "wx/stedit/stedit.h"
16 #include "wx/stedit/steart.h"
17 #include "wx/stedit/stemenum.h"
18 #include "stedlgs_wdr.h"
19
20 #include <wx/progdlg.h> // wxProgressDialog
21
22 #if wxUSE_PRINTING_ARCHITECTURE
23
24 //-----------------------------------------------------------------------------
25 // wxSTEditorModule - setup anything after init and delete before closing
26 //-----------------------------------------------------------------------------
27
28 class wxSTEditorModule : public wxModule
29 {
30 DECLARE_DYNAMIC_CLASS(wxSTEditorModule)
31 public:
wxSTEditorModule()32 wxSTEditorModule() : wxModule() {}
OnInit()33 bool OnInit()
34 {
35 wxArtProvider::Push(new wxSTEditorArtProvider);
36 return true;
37 }
OnExit()38 void OnExit()
39 {
40 #if wxUSE_PRINTING_ARCHITECTURE
41 wxSTEditorPrintout::SetPrintData(NULL, false);
42 wxSTEditorPrintout::SetPageSetupData(NULL, false);
43 #endif // wxUSE_PRINTING_ARCHITECTURE
44 }
45 };
46
47 IMPLEMENT_DYNAMIC_CLASS(wxSTEditorModule, wxModule)
48
49 //----------------------------------------------------------------------------
50 // wxSTEditorPrintout
51 //----------------------------------------------------------------------------
52
53 IMPLEMENT_ABSTRACT_CLASS(wxSTEditorPrintout, wxPrintout)
54
55 wxPrintData *wxSTEditorPrintout::sm_STE_printData = NULL;
56 wxPageSetupData *wxSTEditorPrintout::sm_STE_pageSetupData = NULL;
57 bool wxSTEditorPrintout::sm_STE_printdata_static = false;
58 bool wxSTEditorPrintout::sm_STE_pagesetupdata_static = false;
59 bool wxSTEditorPrintout::sm_warn_on_font_scale = true;
60
GetPrintData(bool create_on_demand)61 wxPrintData *wxSTEditorPrintout::GetPrintData(bool create_on_demand)
62 {
63 if (create_on_demand && (sm_STE_printData == NULL))
64 {
65 wxPrintData *printData = new wxPrintData;
66 printData->SetPaperId(wxPAPER_LETTER);
67 SetPrintData(printData, false);
68 }
69
70 return sm_STE_printData;
71 }
GetPageSetupData(bool create_on_demand)72 wxPageSetupData *wxSTEditorPrintout::GetPageSetupData(bool create_on_demand)
73 {
74 if (create_on_demand && (sm_STE_pageSetupData == NULL))
75 {
76 wxPageSetupData *pageSetupData = new wxPageSetupData;
77 pageSetupData->SetPaperSize(wxPAPER_LETTER);
78 pageSetupData->SetMarginTopLeft(wxPoint(20, 20));
79 pageSetupData->SetMarginBottomRight(wxPoint(20, 20));
80 SetPageSetupData(pageSetupData, false);
81 }
82
83 return sm_STE_pageSetupData;
84 }
85
GetPrintDataStatic()86 bool wxSTEditorPrintout::GetPrintDataStatic() { return sm_STE_printdata_static; }
GetPageSetupDataStatic()87 bool wxSTEditorPrintout::GetPageSetupDataStatic() { return sm_STE_pagesetupdata_static; }
88
SetPrintData(wxPrintData * printData,bool is_static)89 void wxSTEditorPrintout::SetPrintData( wxPrintData *printData, bool is_static )
90 {
91 if (sm_STE_printData && !sm_STE_printdata_static)
92 delete sm_STE_printData;
93
94 sm_STE_printData = printData;
95 sm_STE_printdata_static = is_static;
96 }
SetPageSetupData(wxPageSetupData * pageSetupData,bool is_static)97 void wxSTEditorPrintout::SetPageSetupData( wxPageSetupData *pageSetupData, bool is_static )
98 {
99 if (sm_STE_pageSetupData && !sm_STE_pagesetupdata_static)
100 delete sm_STE_pageSetupData;
101
102 sm_STE_pageSetupData = pageSetupData;
103 sm_STE_pagesetupdata_static = is_static;
104 }
105
wxSTEditorPrintout(wxSTEditor * editor,const wxString & title)106 wxSTEditorPrintout::wxSTEditorPrintout(wxSTEditor *editor,
107 const wxString& title)
108 :wxPrintout(title), m_editor(editor),
109 m_margin0_width(-1), m_margin1_width(-1), m_margin2_width(-1),
110 m_edge_mode(-1)
111 {
112 wxCHECK_RET(m_editor, wxT("Invalid editor in wxSTEditorPrintout"));
113
114 // This is a simple check to see if the font can be scaled. Otherwise
115 // the user will be confused and disappointed by the output.
116
117 // You cannot show this dialog later if this is used in a wxPrintPreview.
118 // It leads to a crash in MSW in the paint handler for the preview,
119 // probably something to do with having two modal dialogs.
120 if (sm_warn_on_font_scale && m_editor->GetEditorStyles().IsOk())
121 {
122 wxClientDC dc(m_editor);
123 wxFont font = m_editor->GetEditorStyles().GetFont(STE_STYLE_DEFAULT);
124 int font_width = 0, font_height = 0;
125 dc.SetUserScale(1.0, 1.0);
126 dc.GetTextExtent(wxT("W"), &font_width, &font_height, NULL, NULL, &font);
127 int font_width_2 = 0, font_height_2 = 0;
128 dc.SetUserScale(0.5, 0.5);
129 dc.GetTextExtent(wxT("W"), &font_width_2, &font_height_2, NULL, NULL, &font);
130
131 if (!(font_height_2 < font_height))
132 {
133 int ret = wxMessageBox(_("The font cannot be properly scaled for the printout\nand the output may be corrupted.\nPress cancel to not see this warning again."),
134 _("Unscalable font"),
135 wxOK|wxCANCEL|wxCENTRE|wxICON_INFORMATION, m_editor);
136
137 if (ret == wxCANCEL)
138 sm_warn_on_font_scale = false;
139 }
140 }
141 }
142
OnBeginDocument(int startPage,int endPage)143 bool wxSTEditorPrintout::OnBeginDocument(int startPage, int endPage)
144 {
145 if (!m_editor)
146 return false;
147
148 // save the original values for edge mode and margin widths
149 m_edge_mode = m_editor->GetEdgeMode(); // nobody wants to see this?
150 m_editor->SetEdgeMode(wxSTC_EDGE_NONE);
151
152 wxSTEditorPrefs prefs = m_editor->GetEditorPrefs();
153
154 m_margin0_width = m_editor->GetMarginWidth(STE_MARGIN_0);
155 m_margin1_width = m_editor->GetMarginWidth(STE_MARGIN_1);
156 m_margin2_width = m_editor->GetMarginWidth(STE_MARGIN_2);
157
158 // this defaults to wysiwyg for linenumbers if no prefs
159 bool has_linenums = (m_margin0_width != 0) && (m_editor->GetMarginType(STE_MARGIN_0) == wxSTC_MARGIN_NUMBER);
160 bool linenums_never = prefs.IsOk() && (prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS) == STE_PRINT_LINENUMBERS_NEVER);
161 bool linenums_always = prefs.IsOk() && (prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS) == STE_PRINT_LINENUMBERS_ALWAYS);
162
163 if (!linenums_never && (has_linenums || linenums_always))
164 {
165 // calculate the smallest line number width to save space
166 int line_count = m_editor->GetLineCount(); line_count = wxMax(line_count, 1);
167 wxString lineStr((int)log10((double)line_count)+1, wxT('5'));
168
169 int line_margin_width = m_editor->TextWidth(wxSTC_STYLE_LINENUMBER, lineStr);
170 m_editor->SetMarginWidth(STE_MARGIN_0, line_margin_width);
171 }
172 else
173 {
174 m_editor->SetMarginWidth(STE_MARGIN_0, 0);
175 }
176
177 // the markers are not drawn by scintilla anyway so set margin widths to 0
178 m_editor->SetMarginWidth(STE_MARGIN_1, 0);
179 m_editor->SetMarginWidth(STE_MARGIN_2, 0);
180
181 return wxPrintout::OnBeginDocument(startPage, endPage);
182 }
183
OnEndDocument()184 void wxSTEditorPrintout::OnEndDocument()
185 {
186 if (m_editor)
187 {
188 // restore the original values for edge mode and margin widths
189 if (m_edge_mode >= 0)
190 m_editor->SetEdgeMode(m_edge_mode);
191
192 if (m_margin0_width >= 0)
193 m_editor->SetMarginWidth(STE_MARGIN_0, m_margin0_width);
194 if (m_margin1_width >= 0)
195 m_editor->SetMarginWidth(STE_MARGIN_1, m_margin1_width);
196 if (m_margin2_width >= 0)
197 m_editor->SetMarginWidth(STE_MARGIN_2, m_margin2_width);
198 }
199
200 wxPrintout::OnEndDocument();
201 }
202
HasPage(int page)203 bool wxSTEditorPrintout::HasPage(int page)
204 {
205 return (page > 0) && (page-1 < int(m_pages.GetCount())); // pages start at 1
206 }
207
OnPrintPage(int page)208 bool wxSTEditorPrintout::OnPrintPage(int page)
209 {
210 wxDC *dc = GetDC();
211 if (!m_editor || !HasPage(page) || !dc)
212 return false;
213
214 PrintScaling(dc); // scale DC for preview
215
216 #if 0 // FIXME test code for visualizing the rectangles
217 //dc->SetBrush(*wxTRANSPARENT_BRUSH);
218 dc->SetBrush(*wxGREEN_BRUSH);
219 dc->SetPen(wxPen(wxColour(255,0,0), 2, wxSOLID));
220 dc->DrawRectangle(m_pageRect); dc->DrawRectangle(m_pageRect.Inflate(-20, -20));
221 dc->SetPen(wxPen(wxColour(255,0,0), 2, wxSOLID));
222 dc->SetBrush(*wxBLUE_BRUSH);
223 dc->DrawRectangle(m_printRect);
224 #endif // test for visualizing printout
225
226 m_editor->FormatRange(true,
227 m_pages[page-1],
228 (int(m_pages.GetCount()) > page) ? m_pages[page] : m_editor->GetLength(),
229 dc, dc,
230 m_printRect, m_pageRect);
231
232 return true;
233 }
234
GetPageInfo(int * minPage,int * maxPage,int * pageFrom,int * pageTo)235 void wxSTEditorPrintout::GetPageInfo(int *minPage, int *maxPage,
236 int *pageFrom, int *pageTo)
237 {
238 wxCHECK_RET(m_editor && minPage && maxPage && pageFrom && pageTo,
239 wxT("Null value in wxSTEditorPrintout::GetPageInfo"));
240
241 // initialize values
242 *minPage = 0;
243 *maxPage = 0;
244 *pageFrom = 0;
245 *pageTo = 0;
246
247 // scale DC if possible
248 wxDC *dc = GetDC();
249 if (!dc) return;
250 PrintScaling(dc);
251
252 // count pages
253 int length = m_editor->GetLength();
254 int lines = m_editor->GetLineCount();
255 int pages = 1;
256 m_pages.Clear();
257
258 wxWindow* parent = wxGetTopLevelParent(wxWindow::FindFocus()); // find wxPreviewFrame
259
260 // Using the default wxPD_APP_MODAL flag, or using the frame window or NULL as parent, will mess up the z-order when displaying wxPreviewFrame
261 wxProgressDialog progDialog(_("Formatting printout"), _("Page 1 of ?"), 100, parent, wxPD_AUTO_HIDE);
262 #if (wxVERSION_NUMBER < 2900)
263 progDialog.SetFocus(); // grab focus from wxPreviewFrame
264 #endif
265
266 for (int pos = 0; pos < length; )
267 {
268 if (*maxPage >= (int)m_pages.GetCount())
269 m_pages.Add(pos);
270 else
271 m_pages[*maxPage] = pos;
272
273 pos = m_editor->FormatRange(false,
274 pos,
275 length,
276 dc, dc,
277 m_printRect, m_pageRect);
278 *maxPage += 1;
279
280 int current_line = m_editor->LineFromPosition(wxMax(pos-1, 0));
281 current_line = wxMax(current_line, 1);
282 pages = 1+(*maxPage)*lines/current_line;
283 progDialog.Update(int(pos*100.0/length),
284 wxString::Format(_("Page %d of %d"), *maxPage, pages));
285 }
286
287 if (*maxPage > 0)
288 *minPage = 1;
289
290 *pageFrom = *minPage;
291 *pageTo = *maxPage;
292 }
293
PrintScaling(wxDC * dc)294 bool wxSTEditorPrintout::PrintScaling(wxDC *dc)
295 {
296 if (!dc)
297 return false;
298
299 // Get the whole size of the page in mm
300 wxSize pageMMSize;
301 GetPageSizeMM(&pageMMSize.x, &pageMMSize.y);
302
303 // Get the ppi of the screen and printer
304 wxSize ppiScr,ppiPrn;
305 GetPPIScreen( &ppiScr.x, &ppiScr.y);
306 GetPPIPrinter(&ppiPrn.x, &ppiPrn.y);
307
308 float ppi_scale_x = float(ppiPrn.x)/float(ppiScr.x);
309 float ppi_scale_y = float(ppiPrn.y)/float(ppiScr.y);
310
311 // Get the size of DC in pixels and the number of pixels in the page
312 wxSize dcSize, pagePixSize;
313 dc->GetSize(&dcSize.x, &dcSize.y);
314 GetPageSizePixels(&pagePixSize.x, &pagePixSize.y);
315
316 float dc_pagepix_scale_x = float(dcSize.x)/float(pagePixSize.x);
317 float dc_pagepix_scale_y = float(dcSize.y)/float(pagePixSize.y);
318
319 // the actual ppi using the size of the dc or page in pixels
320 //wxSize pixelSize = IsPreview() ? dcSize : pagePixSize;
321 //float page_ppi_x = float(pixelSize.x) * (25.4 / float(pageMMSize.x));
322 //float page_ppi_y = float(pixelSize.y) * (25.4 / float(pageMMSize.y));
323
324 // If printer pageWidth == current DC width, then this doesn't
325 // change. But w might be the preview bitmap width, so scale down.
326 float dc_scale_x = ppi_scale_x * dc_pagepix_scale_x;
327 float dc_scale_y = ppi_scale_y * dc_pagepix_scale_y;
328
329 // calculate the pixels / mm (25.4 mm = 1 inch)
330 float ppmm_x = float(ppiScr.x) / 25.4;
331 float ppmm_y = float(ppiScr.y) / 25.4;
332
333 // Adjust the page size for the pixels / mm scaling factor
334 //wxSize paperSize = GetPageSetupData(true)->GetPaperSize();
335 wxSize page = pageMMSize;
336 page.x = int(page.x * ppmm_x);
337 page.y = int(page.y * ppmm_y);
338 m_pageRect = wxRect(0, 0, page.x, page.y);
339
340 // get margins informations and convert to printer pixels
341 wxPoint topLeft = GetPageSetupData(true)->GetMarginTopLeft();
342 wxPoint bottomRight = GetPageSetupData(true)->GetMarginBottomRight();
343
344 int top = int(topLeft.y * ppmm_y);
345 int bottom = int(bottomRight.y * ppmm_y);
346 int left = int(topLeft.x * ppmm_x);
347 int right = int(bottomRight.x * ppmm_x);
348
349 m_printRect = wxRect(left, top, page.x-(left+right), page.y-(top+bottom));
350
351 dc->SetUserScale(dc_scale_x, dc_scale_y);
352
353 //wxPrintf(wxT("GetPageInfo ppiScr %d %d, ppiPrn %d %d, paperSize %d %d page %d %d, preview %d\n"), ppiScr.x, ppiScr.y, ppiPrn.x, ppiPrn.y, paperSize.x, paperSize.y, page.x, page.y, IsPreview());
354 //wxPrintf(wxT("GetPageInfo m_pageRect x%d y%d w%d h%d m_printRect x%d y%d w%d h%d\n"), m_pageRect.x, m_pageRect.y, m_pageRect.width, m_pageRect.height,
355 // m_printRect.x, m_printRect.y, m_printRect.width, m_printRect.height);
356 //wxPrintf(wxT("PrintScaling dc size %d %d, page pixels %d %d, dc_scale %g %g ppmm %g %g\n"), dcSize.x, dcSize.y, pagePixSize.x, pagePixSize.y, dc_scale_x, dc_scale_y, ppmm_x, ppmm_y);
357 //wxPrintf(wxT("ppi_scale %g %g, dc_pagepix_scale %g %g\n\n"), ppi_scale_x, ppi_scale_y, dc_pagepix_scale_x, dc_pagepix_scale_y);
358 //fflush(stdout);
359
360 return true;
361 }
362
363 #endif // wxUSE_PRINTING_ARCHITECTURE
364
365 //-----------------------------------------------------------------------------
366 // wxSTEditorPrintOptionsDialog - display STC printer options
367 //-----------------------------------------------------------------------------
368 IMPLEMENT_ABSTRACT_CLASS(wxSTEditorPrintOptionsDialog, wxDialog);
369
wxSTEditorPrintOptionsDialog(wxWindow * parent)370 wxSTEditorPrintOptionsDialog::wxSTEditorPrintOptionsDialog(wxWindow *parent)
371 :wxDialog(parent, wxID_ANY, _("Printer options"),
372 wxDefaultPosition, wxDefaultSize,
373 wxDEFAULT_DIALOG_STYLE_RESIZE)
374 {
375 SetIcons(wxSTEditorArtProvider::GetDialogIconBundle());
376 wxSTEditorPrintPrefsSizer(this, false, true);
377 wxSTEditorStdDialogButtonSizer(this, wxOK|wxCANCEL);
378 GetSizer()->SetSizeHints( this );
379
380 if (wxDynamicCast(parent, wxSTEditor))
381 {
382 wxSTEditor *edit = wxStaticCast(parent, wxSTEditor);
383 SetPrintMagnification(edit->GetPrintMagnification());
384 SetPrintColourMode(edit->GetPrintColourMode());
385 SetPrintWrapMode(edit->GetPrintWrapMode() == wxSTC_WRAP_WORD);
386 wxSTEditorPrefs prefs = edit->GetEditorPrefs();
387 if (prefs.IsOk())
388 SetPrintLinenumbers(prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS));
389 else
390 SetPrintLinenumbers(STE_PRINT_LINENUMBERS_DEFAULT);
391 }
392 else
393 {
394 SetPrintMagnification(-2);
395 SetPrintColourMode(wxSTC_PRINT_COLOURONWHITE);
396 SetPrintWrapMode(false);
397 SetPrintLinenumbers(STE_PRINT_LINENUMBERS_DEFAULT);
398 }
399 Centre();
400 }
401
SetPrintMagnification(int val)402 void wxSTEditorPrintOptionsDialog::SetPrintMagnification( int val )
403 {
404 wxStaticCast(FindWindow(ID_STEDLG_PRINT_MAGNIFICATION_SPINCTRL), wxSpinCtrl)->SetValue(val);
405 }
406
SetPrintColourMode(int val)407 void wxSTEditorPrintOptionsDialog::SetPrintColourMode( int val )
408 {
409 wxChoice* choice = wxStaticCast(FindWindow(ID_STEDLG_PRINT_COLOURMODE_CHOICE), wxChoice);
410 wxCHECK_RET((val >= 0) && (val < (int)choice->GetCount()),
411 wxT("Invalid selection in wxSTEditorPrintOptionsDialog::SetPrintColourMode"));
412 choice->SetSelection(val);
413 }
SetPrintWrapMode(bool val)414 void wxSTEditorPrintOptionsDialog::SetPrintWrapMode( bool val )
415 {
416 wxStaticCast(FindWindow(ID_STEDLG_PRINT_WRAPMODE_CHECKBOX), wxCheckBox)->SetValue(val);
417 }
SetPrintLinenumbers(int show_linenumbers)418 void wxSTEditorPrintOptionsDialog::SetPrintLinenumbers( int show_linenumbers )
419 {
420 wxCHECK_RET((show_linenumbers >= 0) && (show_linenumbers <= 2), wxT("Invalid value"));
421 wxStaticCast(FindWindow(ID_STEDLG_PRINT_LINENUMBERS_CHOICE), wxChoice)->SetSelection(show_linenumbers);
422 }
423
GetPrintMagnification()424 int wxSTEditorPrintOptionsDialog::GetPrintMagnification()
425 {
426 return wxStaticCast(FindWindow(ID_STEDLG_PRINT_MAGNIFICATION_SPINCTRL), wxSpinCtrl)->GetValue();
427 }
GetPrintColourMode()428 int wxSTEditorPrintOptionsDialog::GetPrintColourMode()
429 {
430 return wxStaticCast(FindWindow(ID_STEDLG_PRINT_COLOURMODE_CHOICE), wxChoice)->GetSelection();
431 }
GetPrintWrapMode()432 bool wxSTEditorPrintOptionsDialog::GetPrintWrapMode()
433 {
434 return wxStaticCast(FindWindow(ID_STEDLG_PRINT_WRAPMODE_CHECKBOX), wxCheckBox)->GetValue();
435 }
GetPrintLinenumbers()436 int wxSTEditorPrintOptionsDialog::GetPrintLinenumbers()
437 {
438 return wxStaticCast(FindWindow(ID_STEDLG_PRINT_LINENUMBERS_CHOICE), wxChoice)->GetSelection();
439 }
440