KiCad PCB EDA Suite
pcbnew/dialogs/dialog_print_using_printer.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2010-2016 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr
5  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 // Set this to 1 if you want to test PostScript printing under MSW.
26 //#define wxTEST_POSTSCRIPT_IN_MSW 1
27 
28 #include <fctsys.h>
29 #include <kiface_i.h>
30 #include <class_drawpanel.h>
31 #include <confirm.h>
32 #include <pcb_edit_frame.h>
33 #include <base_units.h>
34 
35 #include <printout_controler.h>
36 #include <pcbnew.h>
37 #include <pcbplot.h>
38 
39 #include <class_board.h>
40 
42 #include <enabler.h>
43 
44 
45 #define PEN_WIDTH_MAX_VALUE ( KiROUND( 5 * IU_PER_MM ) )
46 #define PEN_WIDTH_MIN_VALUE ( KiROUND( 0.005 * IU_PER_MM ) )
47 
48 
50 
51 // Local variables
52 static double s_ScaleList[] =
53 { 0, 0.5, 0.7, 0.999, 1.0, 1.4, 2.0, 3.0, 4.0 };
54 
55 // Define min et max reasonable values for print scale
56 #define MIN_SCALE 0.01
57 #define MAX_SCALE 100.0
58 
59 // static print data and page setup data, to remember settings during the session
60 static wxPrintData* s_PrintData;
61 static wxPageSetupDialogData* s_pageSetupData = (wxPageSetupDialogData*) NULL;
62 
64 
65 
71 {
72 public:
74 
75  bool IsMirrored() { return m_Print_Mirror->IsChecked(); }
76  bool ExcludeEdges() { return m_Exclude_Edges_Pcb->IsChecked(); }
77  bool PrintUsingSinglePage() { return m_PagesOption->GetSelection(); }
79 
80 
81 private:
82 
84  wxConfigBase* m_config;
85  // the list of existing board layers in wxCheckListBox, with the
86  // board layers id:
87  std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
88  static bool m_ExcludeEdgeLayer;
89 
90  void OnCloseWindow( wxCloseEvent& event ) override;
91  void OnPageSetup( wxCommandEvent& event ) override;
92  void OnPrintPreview( wxCommandEvent& event ) override;
93  void OnPrintButtonClick( wxCommandEvent& event ) override;
94  void OnScaleSelectionClick( wxCommandEvent& event ) override;
95 
96  void OnButtonCancelClick( wxCommandEvent& event ) override { Close(); }
97 
98  void OnInitDlg( wxInitDialogEvent& event ) override
99  {
100  // Call the default wxDialog handler of a wxInitDialogEvent
101  TransferDataToWindow();
102 
103  // Now all widgets have the size fixed, call FinishDialogSettings
105  }
106 
107  void SetPrintParameters();
108  void SetPenWidth();
109  void initValues();
110 };
111 
112 
114 
115 
116 void PCB_EDIT_FRAME::ToPrinter( wxCommandEvent& event )
117 {
118  const PAGE_INFO& pageInfo = GetPageSettings();
119 
120  if( s_PrintData == NULL ) // First print
121  {
122  s_PrintData = new wxPrintData();
123 
124  if( !s_PrintData->Ok() )
125  {
126  DisplayError( this, _( "Error Init Printer info" ) );
127  }
128  s_PrintData->SetQuality( wxPRINT_QUALITY_HIGH ); // Default resolution = HIGH;
129  }
130 
131  if( s_pageSetupData == NULL )
132  s_pageSetupData = new wxPageSetupDialogData( *s_PrintData );
133 
134  s_pageSetupData->SetPaperId( pageInfo.GetPaperId() );
135  s_pageSetupData->GetPrintData().SetOrientation( pageInfo.GetWxOrientation() );
136 
137  if( pageInfo.IsCustom() )
138  {
139  if( pageInfo.IsPortrait() )
140  s_pageSetupData->SetPaperSize( wxSize( Mils2mm( pageInfo.GetWidthMils() ),
141  Mils2mm( pageInfo.GetHeightMils() ) ) );
142  else
143  s_pageSetupData->SetPaperSize( wxSize( Mils2mm( pageInfo.GetHeightMils() ),
144  Mils2mm( pageInfo.GetWidthMils() ) ) );
145  }
146 
147  *s_PrintData = s_pageSetupData->GetPrintData();
148 
149  DIALOG_PRINT_USING_PRINTER dlg( this );
150 
151  dlg.ShowModal();
152 }
153 
154 
157 {
158  m_parent = parent;
160  memset( m_boxSelectLayer, 0, sizeof( m_boxSelectLayer ) );
161 
162  initValues( );
163 #ifdef __WXMAC__
164  /* Problems with modal on wx-2.9 - Anyway preview is standard for OSX */
165  m_buttonPreview->Hide();
166 #endif
167 }
168 
169 
171 {
172  wxString msg;
173  BOARD* board = m_parent->GetBoard();
174 
175  s_Parameters.m_PageSetupData = s_pageSetupData;
176 
177  // Create layer list.
178  LSEQ seq = board->GetEnabledLayers().UIOrder();
179 
180  for( ; seq; ++seq )
181  {
182  PCB_LAYER_ID layer = *seq;
183  int checkIndex;
184 
185  if( IsCopperLayer( layer ) )
186  {
187  checkIndex = m_CopperLayersList->Append( board->GetLayerName( layer ) );
188  m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
189  }
190  else
191  {
192  checkIndex = m_TechnicalLayersList->Append( board->GetLayerName( layer ) );
193  m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
194  }
195 
196  if( m_config )
197  {
198  wxString layerKey;
199  layerKey.Printf( OPTKEY_LAYERBASE, layer );
200  bool option;
201 
202  if( m_config->Read( layerKey, &option ) )
203  m_boxSelectLayer[layer].first->Check( checkIndex, option );
204  }
205  }
206 
207  // Option for excluding contents of "Edges Pcb" layer
208  m_Exclude_Edges_Pcb->Show( true );
209 
210  // Read the scale adjust option
211  int scale_idx = 4; // default selected scale = ScaleList[4] = 1.000
212 
213  if( m_config )
214  {
215  m_config->Read( OPTKEY_PRINT_X_FINESCALE_ADJ, &s_Parameters.m_XScaleAdjust );
216  m_config->Read( OPTKEY_PRINT_Y_FINESCALE_ADJ, &s_Parameters.m_YScaleAdjust );
217  m_config->Read( OPTKEY_PRINT_SCALE, &scale_idx );
218  m_config->Read( OPTKEY_PRINT_PAGE_FRAME, &s_Parameters.m_Print_Sheet_Ref, 1);
220  m_config->Read( OPTKEY_PRINT_PAGE_PER_LAYER, &s_Parameters.m_OptionPrintPage, 0);
221  int tmp;
224 
225  // Test for a reasonable scale value. Set to 1 if problem
226  if( s_Parameters.m_XScaleAdjust < MIN_SCALE ||
227  s_Parameters.m_YScaleAdjust < MIN_SCALE ||
228  s_Parameters.m_XScaleAdjust > MAX_SCALE ||
229  s_Parameters.m_YScaleAdjust > MAX_SCALE )
230  s_Parameters.m_XScaleAdjust = s_Parameters.m_YScaleAdjust = 1.0;
231  }
232 
233  m_ScaleOption->SetSelection( scale_idx );
234  scale_idx = m_ScaleOption->GetSelection();
235  s_Parameters.m_PrintScale = s_ScaleList[scale_idx];
236  m_Print_Mirror->SetValue(s_Parameters.m_PrintMirror);
238  m_Print_Sheet_Ref->SetValue( s_Parameters.m_Print_Sheet_Ref );
239 
240  // Options to plot pads and vias holes
241  m_Drill_Shape_Opt->SetSelection( s_Parameters.m_DrillShapeOpt );
242 
243  if( s_Parameters.m_Print_Black_and_White )
244  m_ModeColorOption->SetSelection( 1 );
245  else
246  m_ModeColorOption->SetSelection( 0 );
247 
248  m_PagesOption->SetSelection(s_Parameters.m_OptionPrintPage);
251  m_DialogPenWidth->SetValue(
252  StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) );
253 
254  // Create scale adjust option
255  msg.Printf( wxT( "%f" ), s_Parameters.m_XScaleAdjust );
256  m_FineAdjustXscaleOpt->SetValue( msg );
257 
258  msg.Printf( wxT( "%f" ), s_Parameters.m_YScaleAdjust );
259  m_FineAdjustYscaleOpt->SetValue( msg );
260 
261  bool enable = (s_Parameters.m_PrintScale == 1.0);
262  m_FineAdjustXscaleOpt->Enable(enable);
263  m_FineAdjustYscaleOpt->Enable(enable);
264 }
265 
266 
268 {
269  int page_count = 0;
270 
271  s_Parameters.m_PrintMaskLayer = LSET();
272 
273  for( unsigned ii = 0; ii < DIM(m_boxSelectLayer); ++ii )
274  {
275  if( !m_boxSelectLayer[ii].first )
276  continue;
277 
278  if( m_boxSelectLayer[ii].first->IsChecked( m_boxSelectLayer[ii].second ) )
279  {
280  page_count++;
281  s_Parameters.m_PrintMaskLayer.set( ii );
282  }
283  }
284 
285  // In Pcbnew force the EDGE layer to be printed or not with the other layers
287  if( m_ExcludeEdgeLayer )
288  s_Parameters.m_Flags = 0;
289  else
290  s_Parameters.m_Flags = 1;
291 
292  if( PrintUsingSinglePage() )
293  page_count = 1;
294 
295  s_Parameters.m_PageCount = page_count;
296 
297  return page_count;
298 }
299 
300 
301 void DIALOG_PRINT_USING_PRINTER::OnCloseWindow( wxCloseEvent& event )
302 {
304 
305  if( m_config )
306  {
308  s_Parameters.m_XScaleAdjust );
310  s_Parameters.m_YScaleAdjust );
311  m_config->Write( OPTKEY_PRINT_SCALE, m_ScaleOption->GetSelection() );
312  m_config->Write( OPTKEY_PRINT_PAGE_FRAME, s_Parameters.m_Print_Sheet_Ref);
315  m_config->Write( OPTKEY_PRINT_PADS_DRILL, (long) s_Parameters.m_DrillShapeOpt );
316  wxString layerKey;
317 
318  for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer )
319  {
320  if( !m_boxSelectLayer[layer].first )
321  continue;
322 
323  layerKey.Printf( OPTKEY_LAYERBASE, layer );
324  m_config->Write( layerKey,
325  m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) );
326  }
327  }
328 
329  EndModal( 0 );
330 }
331 
332 
334 {
336 
337  s_Parameters.m_PrintMirror = m_Print_Mirror->GetValue();
338  s_Parameters.m_Print_Sheet_Ref = m_Print_Sheet_Ref->GetValue();
339  s_Parameters.m_Print_Black_and_White =
340  m_ModeColorOption->GetSelection() != 0;
341 
342  s_Parameters.m_DrillShapeOpt =
344 
345  s_Parameters.m_OptionPrintPage = m_PagesOption->GetSelection() != 0;
346 
348 
349  int idx = m_ScaleOption->GetSelection();
350  s_Parameters.m_PrintScale = s_ScaleList[idx];
351  plot_opts.SetScale( s_Parameters.m_PrintScale );
352 
354  {
355  if( s_Parameters.m_XScaleAdjust > MAX_SCALE ||
356  s_Parameters.m_YScaleAdjust > MAX_SCALE )
357  DisplayInfoMessage( NULL, _( "Warning: Scale option set to a very large value" ) );
358 
359  m_FineAdjustXscaleOpt->GetValue().ToDouble( &s_Parameters.m_XScaleAdjust );
360  }
361 
363  {
364  // Test for a reasonable scale value
365  if( s_Parameters.m_XScaleAdjust < MIN_SCALE ||
366  s_Parameters.m_YScaleAdjust < MIN_SCALE )
367  DisplayInfoMessage( NULL, _( "Warning: Scale option set to a very small value" ) );
368 
369  m_FineAdjustYscaleOpt->GetValue().ToDouble( &s_Parameters.m_YScaleAdjust );
370  }
371 
372  plot_opts.SetFineScaleAdjustX( s_Parameters.m_XScaleAdjust );
373  plot_opts.SetFineScaleAdjustY( s_Parameters.m_YScaleAdjust );
374 
375  m_parent->SetPlotSettings( plot_opts );
376 
377  SetPenWidth();
378 }
379 
380 
382 {
383  // Get the new pen width value, and verify min et max value
384  // NOTE: s_Parameters.m_PenDefaultSize is in internal units
385 
387 
388  if( s_Parameters.m_PenDefaultSize > PEN_WIDTH_MAX_VALUE )
389  {
390  s_Parameters.m_PenDefaultSize = PEN_WIDTH_MAX_VALUE;
391  }
392 
393  if( s_Parameters.m_PenDefaultSize < PEN_WIDTH_MIN_VALUE )
394  {
395  s_Parameters.m_PenDefaultSize = PEN_WIDTH_MIN_VALUE;
396  }
397 
399 
400  m_DialogPenWidth->SetValue(
401  StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) );
402 }
403 
405 {
406  double scale = s_ScaleList[m_ScaleOption->GetSelection()];
407  bool enable = (scale == 1.0);
408 
410  m_FineAdjustXscaleOpt->Enable(enable);
412  m_FineAdjustYscaleOpt->Enable(enable);
413 }
414 
415 
416 void DIALOG_PRINT_USING_PRINTER::OnPageSetup( wxCommandEvent& event )
417 {
418  wxPageSetupDialog pageSetupDialog( this, s_pageSetupData );
419  pageSetupDialog.ShowModal();
420 
421  (*s_PrintData) = pageSetupDialog.GetPageSetupDialogData().GetPrintData();
422  (*s_pageSetupData) = pageSetupDialog.GetPageSetupDialogData();
423 }
424 
425 
426 void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event )
427 {
429 
430  // If no layer selected, we have no plot. prompt user if it happens
431  // because he could think there is a bug in Pcbnew:
432  if( s_Parameters.m_PrintMaskLayer == 0 )
433  {
434  DisplayError( this, _( "No layer selected" ) );
435  return;
436  }
437 
438  // Pass two printout objects: for preview, and possible printing.
439  wxString title = _( "Print Preview" );
440  wxPrintPreview* preview =
441  new wxPrintPreview( new BOARD_PRINTOUT_CONTROLLER( s_Parameters, m_parent, title ),
442  new BOARD_PRINTOUT_CONTROLLER( s_Parameters, m_parent, title ),
443  s_PrintData );
444 
445  if( preview == NULL )
446  {
447  DisplayError( this, wxT( "An error occurred attempting to show the print preview window." ) );
448  return;
449  }
450 
451  // Uses the parent position and size.
452  wxPoint WPos = m_parent->GetPosition();
453  wxSize WSize = m_parent->GetSize();
454 
455  preview->SetZoom( 100 );
456 
457  wxPreviewFrame* frame = new wxPreviewFrame( preview, this, title, WPos, WSize );
458  frame->SetMinSize( wxSize( 550, 350 ) );
459  frame->Center();
460 
461  // On wxGTK, set the flag wxTOPLEVEL_EX_DIALOG is mandatory, if we want
462  // close the frame using the X box in caption, when the preview frame is run
463  // from a dialog
464  frame->SetExtraStyle( frame->GetExtraStyle() | wxTOPLEVEL_EX_DIALOG );
465 
466  // We use here wxPreviewFrame_WindowModal option to make the wxPrintPreview frame
467  // modal for its caller only.
468  // An other reason is the fact when closing the frame without this option,
469  // all top level frames are reenabled.
470  // With this option, only the parent is reenabled.
471  // Reenabling all top level frames should be made by the parent dialog.
472  frame->InitializeWithModality( wxPreviewFrame_WindowModal );
473 
474  frame->Raise(); // Needed on Ubuntu/Unity to display the frame
475  frame->Show( true );
476 }
477 
478 
480 {
482 
483  // If no layer selected, we have no plot. prompt user if it happens
484  // because he could think there is a bug in Pcbnew:
485  if( s_Parameters.m_PrintMaskLayer == 0 )
486  {
487  DisplayError( this, _( "No layer selected." ) );
488  return;
489  }
490 
491  wxPrintDialogData printDialogData( *s_PrintData );
492  printDialogData.SetMaxPage( s_Parameters.m_PageCount );
493 
494  wxPrinter printer( &printDialogData );
495  wxString title = _( "Print" );
496  BOARD_PRINTOUT_CONTROLLER printout( s_Parameters, m_parent, title );
497 
498  // Disable 'Print' button to prevent issuing another print
499  // command before the previous one is finished (causes problems on Windows)
500  ENABLER printBtnDisable( *m_buttonPrint, false );
501 
502  if( !printer.Print( this, &printout, true ) )
503  {
504  if( wxPrinter::GetLastError() == wxPRINTER_ERROR )
505  DisplayError( this, _( "There was a problem printing." ) );
506  }
507  else
508  {
509  *s_PrintData = printer.GetPrintDialogData().GetPrintData();
510  }
511 }
#define DIM(x)
of elements in an array
Definition: macros.h:98
void OnButtonCancelClick(wxCommandEvent &event) override
#define OPTKEY_PRINT_MONOCHROME_MODE
Definition: pcbplot.h:58
#define OPTKEY_LAYERBASE
Definition: pcbplot.h:52
Board print handler definition file.
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
void ToPrinter(wxCommandEvent &event)
Function ToPrinter Install the print dialog.
Class BOARD to handle a board.
wxString StringFromValue(EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol)
Function StringFromValue returns the string from aValue according to units (inch, mm ...
Definition: base_units.cpp:205
#define OPTKEY_PRINT_SCALE
Definition: pcbplot.h:55
Class PRINT_PARAMETERS handles the parameters used to print a board drawing.
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void OnScaleSelectionClick(wxCommandEvent &event) override
BOARD * GetBoard() const
#define OPTKEY_PRINT_PAGE_FRAME
Definition: pcbplot.h:57
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
virtual const PCB_PLOT_PARAMS & GetPlotSettings() const
Function GetPlotSettings returns the PCB_PLOT_PARAMS for the BOARD owned by this frame.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
#define OPTKEY_PRINT_Y_FINESCALE_ADJ
Definition: pcbplot.h:54
Board plot function definition file.
void OnPrintButtonClick(wxCommandEvent &event) override
static wxPrintData * s_PrintData
PCB_LAYER_ID
A quick note on layer IDs:
bool IsPortrait() const
Definition: page_info.h:116
Class LSET is a set of PCB_LAYER_IDs.
std::pair< wxCheckListBox *, int > m_boxSelectLayer[PCB_LAYER_ID_COUNT]
static PRINT_PARAMETERS s_Parameters
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
Definition: page_info.h:49
int Mils2mm(double x)
Convert mils to mm.
Definition: base_units.h:44
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
virtual void SetPlotSettings(const PCB_PLOT_PARAMS &aSettings)
DrillShapeOptT m_DrillShapeOpt
int g_DrawDefaultLineThickness
Default line thickness in internal units used to draw or plot items using a default thickness line va...
Class PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board...
int ValueFromTextCtrl(const wxTextCtrl &aTextCtr)
Convert the number Value in a string according to the internal units and the selected unit (g_UserUni...
Definition: base_units.cpp:386
int GetWidthMils() const
Definition: page_info.h:132
void SetScale(double aVal)
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
void OnPageSetup(wxCommandEvent &event) override
wxPageSetupDialogData * m_PageSetupData
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:57
void SetFineScaleAdjustX(double aVal)
void ConfigBaseWriteDouble(wxConfigBase *aConfig, const wxString &aKey, double aValue)
Function ConfigBaseWriteDouble This is a helper function to write doubles in config We cannot use wxC...
void OnInitDlg(wxInitDialogEvent &event) override
bool IsCustom() const
Function IsCustom returns true if the type is Custom.
Definition: page_info.cpp:176
#define OPTKEY_PRINT_X_FINESCALE_ADJ
Definition: pcbplot.h:53
const int scale
wxPaperSize GetPaperId() const
Function GetPaperId.
Definition: page_info.h:129
void AddUnitSymbol(wxStaticText &Stext, EDA_UNITS_T aUnit)
Definition: base_units.cpp:515
#define OPTKEY_PRINT_PADS_DRILL
Definition: pcbplot.h:60
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
Class BOARD_PRINTOUT_CONTROLLER is a class derived from wxPrintout to handle the necessary informatio...
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
#define OPTKEY_PRINT_PAGE_PER_LAYER
Definition: pcbplot.h:59
void SetFineScaleAdjustY(double aVal)
void OnPrintPreview(wxCommandEvent &event) override
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
void OnCloseWindow(wxCloseEvent &event) override
wxPrintOrientation GetWxOrientation() const
Function GetWxOrientation.
Definition: page_info.h:122
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:216
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:185
int GetHeightMils() const
Definition: page_info.h:135
Simple class to automatically enable/disable widgets.
Definition: enabler.h:29
LSEQ UIOrder() const
Definition: lset.cpp:786
static wxPageSetupDialogData * s_pageSetupData