KiCad PCB EDA Suite
dialog_SVG_print.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
9  * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 
30 #include <fctsys.h>
31 #include <kiface_i.h>
32 #include <common.h>
33 #include <pcb_base_frame.h>
34 //#include <pcb_screen.h>
35 #include <base_units.h>
36 #include <convert_to_biu.h>
38 #include <macros.h>
39 #include <reporter.h>
40 #include <confirm.h>
41 
42 #include <pcbnew.h>
43 #include <pcbplot.h>
44 #include <printout_controler.h>
45 #include <class_board.h>
46 #include <dialog_SVG_print_base.h>
47 #include <invoke_pcb_dialog.h>
48 #include <wx_html_report_panel.h>
49 
50 
52 {
53 public:
54  DIALOG_SVG_PRINT( wxTopLevelWindow* aParent, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings );
55 
56 private:
60  wxConfigBase* m_config;
62  // the list of existing board layers in wxCheckListBox, with the
63  // board layers id:
64  std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
65  bool m_printBW;
69 
70  void initDialog();
71 
72  void OnCloseWindow( wxCloseEvent& event ) override;
73  void OnButtonPlot( wxCommandEvent& event ) override;
74 
75  void OnButtonCloseClick( wxCommandEvent& event ) override;
76 
77  void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
78  void SetPenWidth();
79  void ExportSVGFile( bool aOnlyOneFile );
80 
82  {
83  return m_rbSvgPageSizeOpt->GetSelection() == 2;
84  }
85 
86  bool PrintPageRef()
87  {
88  return m_rbSvgPageSizeOpt->GetSelection() == 0;
89  }
90 
91  bool CreateSVGFile( const wxString& FullFileName, bool aOnlyOneFile );
92 
94 };
95 
96 
97 
98 // Keys for configuration
99 #define PLOTSVGMODECOLOR_KEY wxT( "PlotSVGModeColor" )
100 #define PLOTSVGMODEMIRROR_KEY wxT( "PlotSVGModeMirror" )
101 #define PLOTSVGMODEONEFILE_KEY wxT( "PlotSVGModeOneFile" )
102 #define PLOTSVGPAGESIZEOPT_KEY wxT( "PlotSVGPageOpt" )
103 #define PLOTSVGPLOT_BRD_EDGE_KEY wxT( "PlotSVGBrdEdge" )
104 
105 // reasonable values for default pen width
106 #define WIDTH_MAX_VALUE (2 * IU_PER_MM)
107 #define WIDTH_MIN_VALUE (0.05 * IU_PER_MM)
108 
109 // Local variables:
110 static LSET s_SelectedLayers( 4, B_Cu, F_Cu, F_SilkS, B_SilkS );
111 
112 /*
113  * DIALOG_SVG_PRINT functions
114  */
115 DIALOG_SVG_PRINT::DIALOG_SVG_PRINT( wxTopLevelWindow* aParent, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings ) :
116  DIALOG_SVG_PRINT_base( aParent ),
117  m_did_print( false ),
118  m_callers_params( aSettings )
119 {
120  m_board = aBoard;
122 
123  memset( m_boxSelectLayer, 0, sizeof( m_boxSelectLayer ) );
124 
125  initDialog();
126 
127  GetSizer()->Fit( this );
128  GetSizer()->SetSizeHints( this );
129  Centre();
130 }
131 
132 
134 {
135  if( m_config )
136  {
137  m_config->Read( PLOTSVGMODECOLOR_KEY, &m_printBW, false );
138  long ltmp;
139  m_config->Read( PLOTSVGPAGESIZEOPT_KEY, &ltmp, 0 );
140  m_config->Read( PLOTSVGMODEMIRROR_KEY, &m_printMirror, false );
142  m_rbSvgPageSizeOpt->SetSelection( ltmp );
143  m_config->Read( PLOTSVGPLOT_BRD_EDGE_KEY, &ltmp, 1 );
144  m_PrintBoardEdgesCtrl->SetValue( ltmp );
145  }
146 
149 
150  m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
151  m_printMirrorOpt->SetValue( m_printMirror );
152  m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );
153 
155 
157 
159 
160  for( ; seq; ++seq )
161  {
162  PCB_LAYER_ID layer = *seq;
163  int checkIndex;
164 
165  if( IsCopperLayer( layer ) )
166  {
167  checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
168  m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
169  }
170  else
171  {
172  checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
173  m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
174  }
175 
176  if( m_config )
177  {
178  wxString layerKey;
179  layerKey.Printf( OPTKEY_LAYERBASE, layer );
180  bool option;
181 
182  if( m_config && m_config->Read( layerKey, &option ) )
183  m_boxSelectLayer[layer].first->Check( checkIndex, option );
184  }
185  }
186 }
187 
188 
190 {
191  LSET ret;
192 
193  for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer )
194  {
195  if( !m_boxSelectLayer[layer].first )
196  continue;
197 
198  if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
199  ret.set( layer );
200  }
201 
202  return ret;
203 }
204 
205 
207 {
208  // Build the absolute path of current output plot directory
209  // to preselect it when opening the dialog.
210  wxFileName fn( m_outputDirectoryName->GetValue() );
211  wxString path = Prj().AbsolutePath( m_outputDirectoryName->GetValue() );
212 
213  wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
214 
215  if( dirDialog.ShowModal() == wxID_CANCEL )
216  return;
217 
218  wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
219 
220  wxMessageDialog dialog( this, _( "Use a relative path?" ),
221  _( "Plot Output Directory" ),
222  wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
223 
224  if( dialog.ShowModal() == wxID_YES )
225  {
226  wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
227 
228  boardFilePath = wxPathOnly( boardFilePath );
229 
230  if( !dirName.MakeRelativeTo( boardFilePath ) )
231  wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ),
232  _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
233  }
234 
235  m_outputDirectoryName->SetValue( dirName.GetFullPath() );
237 }
238 
239 
241 {
242  int pensize = ValueFromTextCtrl( *m_DialogDefaultPenSize );
243 
244  if( pensize > WIDTH_MAX_VALUE )
245  {
246  pensize = WIDTH_MAX_VALUE;
247  }
248 
249  if( pensize < WIDTH_MIN_VALUE )
250  {
251  pensize = WIDTH_MIN_VALUE;
252  }
253 
254  g_DrawDefaultLineThickness = pensize;
255  m_DialogDefaultPenSize->SetValue( StringFromValue( g_UserUnit, pensize ) );
256 }
257 
258 
259 void DIALOG_SVG_PRINT::ExportSVGFile( bool aOnlyOneFile )
260 {
262 
263  // Create output directory if it does not exist (also transform it in
264  // absolute form). Bail if it fails
265  wxFileName outputDir = wxFileName::DirName( m_outputDirectory );
266  wxString boardFilename = m_board->GetFileName();
267 
268  REPORTER& reporter = m_messagesPanel->Reporter();
269 
270  if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
271  {
272  wxString msg = wxString::Format(
273  _( "Could not write plot files to folder \"%s\"." ),
274  GetChars( outputDir.GetPath() )
275  );
276  DisplayError( this, msg );
277  return;
278  }
279 
280  m_printMirror = m_printMirrorOpt->GetValue();
281  m_printBW = m_ModeColorOption->GetSelection();
282  SetPenWidth();
283 
284  LSET all_selected = getCheckBoxSelectedLayers();
285 
286  for( LSEQ seq = all_selected.Seq(); seq; ++seq )
287  {
288  PCB_LAYER_ID layer = *seq;
289 
290  wxFileName fn( boardFilename );
291 
292  wxString suffix = aOnlyOneFile ? wxT( "brd" ) : m_board->GetStandardLayerName( layer );
293 
294  BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
295 
296  m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
297 
298  if( m_PrintBoardEdgesCtrl->IsChecked() )
299  m_printMaskLayer.set( Edge_Cuts );
300 
301  if( CreateSVGFile( fn.GetFullPath(), aOnlyOneFile ) )
302  {
303  reporter.Report (
304  wxString::Format( _( "Plot: \"%s\" OK." ), GetChars( fn.GetFullPath() ) ),
306  }
307  else // Error
308  {
309  reporter.Report (
310  wxString::Format( _( "Unable to create file \"%s\"." ), GetChars( fn.GetFullPath() ) ),
312  }
313 
314  if( aOnlyOneFile )
315  break;
316  }
317 }
318 
319 
320 // Actual SVG file export function.
321 bool DIALOG_SVG_PRINT::CreateSVGFile( const wxString& aFullFileName, bool aOnlyOneFile )
322 {
323  PCB_PLOT_PARAMS plot_opts;
324 
325  plot_opts.SetPlotFrameRef( PrintPageRef() );
326 
327  // Adding drill marks, for copper layers
328  if( ( m_printMaskLayer & LSET::AllCuMask() ).any() )
330  else
332 
333  plot_opts.SetSkipPlotNPTH_Pads( false );
334 
335  plot_opts.SetMirror( m_printMirror );
336  plot_opts.SetFormat( PLOT_FORMAT_SVG );
337 
338  PAGE_INFO pageInfo = m_board->GetPageSettings();
339  wxPoint axisorigin = m_board->GetAuxOrigin();
340 
342  {
344  PAGE_INFO currpageInfo = m_board->GetPageSettings();
345 
346  currpageInfo.SetWidthMils( bbox.GetWidth() / IU_PER_MILS );
347  currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
348  m_board->SetPageSettings( currpageInfo );
349  plot_opts.SetUseAuxOrigin( true );
350  wxPoint origin = bbox.GetOrigin();
351  m_board->SetAuxOrigin( origin );
352  }
353 
354  LOCALE_IO toggle;
355 
357  &plot_opts, UNDEFINED_LAYER, aFullFileName, wxEmptyString );
358 
359  if( plotter )
360  {
361  plotter->SetColorMode( !m_printBW );
362  if( aOnlyOneFile )
363  {
364  for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq )
365  PlotOneBoardLayer( m_board, plotter, *seq, plot_opts );
366  }
367  else
368  {
369  PlotStandardLayer( m_board, plotter, m_printMaskLayer, plot_opts );
370  }
371  plotter->EndPlot();
372  }
373 
374  delete plotter;
375 
376  m_board->SetAuxOrigin( axisorigin ); // reset to the values saved earlier
377  m_board->SetPageSettings( pageInfo );
378 
379  return true;
380 }
381 
382 
383 void DIALOG_SVG_PRINT::OnButtonPlot( wxCommandEvent& event )
384 {
385  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
387 
388  m_did_print = true;
389 }
390 
391 
392 void DIALOG_SVG_PRINT::OnButtonCloseClick( wxCommandEvent& event )
393 {
394  Close();
395 }
396 
397 
398 void DIALOG_SVG_PRINT::OnCloseWindow( wxCloseEvent& event )
399 {
400  if( m_did_print ) // unless output was created, this is tantamount to a cancel.
401  {
402  SetPenWidth();
403  m_printBW = m_ModeColorOption->GetSelection();
404  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
405 
406  // Why are SVG layer choices co-mingled with other plot layer choices in the config file?
407  // The string OPTKEY_LAYERBASE is used in multiple places.
408  // fix this.
409 
410  wxString dirStr = m_outputDirectoryName->GetValue();
411  dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
412 
414 
415  if( m_config )
416  {
420  m_config->Write( PLOTSVGPAGESIZEOPT_KEY, m_rbSvgPageSizeOpt->GetSelection() );
422 
423  wxString layerKey;
424 
425  for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer )
426  {
427  if( !m_boxSelectLayer[layer].first )
428  continue;
429 
430  layerKey.Printf( OPTKEY_LAYERBASE, layer );
431  m_config->Write( layerKey,
432  m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) );
433  }
434  }
435  }
436 
437  EndModal( m_did_print ? wxID_OK : wxID_CANCEL );
438 }
439 
440 
441 bool InvokeSVGPrint( wxTopLevelWindow* aCaller, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings )
442 {
443  DIALOG_SVG_PRINT dlg( aCaller, aBoard, aSettings );
444 
445  return dlg.ShowModal() == wxID_OK;
446 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:673
#define DIM(x)
of elements in an array
Definition: macros.h:98
void OnButtonPlot(wxCommandEvent &event) override
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
void OnCloseWindow(wxCloseEvent &event) override
#define OPTKEY_LAYERBASE
Definition: pcbplot.h:52
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
Board print handler definition file.
void SetUseAuxOrigin(bool aAux)
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
void ExportSVGFile(bool aOnlyOneFile)
const wxString SVGFileExtension
DIALOG_SVG_PRINT(wxTopLevelWindow *aParent, BOARD *aBoard, PCB_PLOT_PARAMS *aSettings)
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
void PlotOneBoardLayer(BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, const PCB_PLOT_PARAMS &aPlotOpt)
Function PlotOneBoardLayer main function to plot one copper or technical layer.
Class BOARD to handle a board.
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:548
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
void SetFormat(PlotFormat aFormat)
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
int GetHeight() const
Definition: eda_rect.h:118
void SetMirror(bool aFlag)
void SetDrillMarksType(DrillMarksType aVal)
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
#define PLOTSVGPAGESIZEOPT_KEY
void SetAuxOrigin(const wxPoint &aPoint)
Function SetAuxOrigin sets the origin point used for plotting.
Definition: class_board.h:342
LSEQ SeqStackupBottom2Top() const
Function SeqStackBottom2Top returns the sequence that is typical for a bottom-to-top stack-up...
Definition: lset.cpp:412
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
This file contains miscellaneous commonly used macros and functions.
void OnButtonCloseClick(wxCommandEvent &event) override
bool InvokeSVGPrint(wxTopLevelWindow *aCaller, BOARD *aBoard, PCB_PLOT_PARAMS *aSettings)
Function InvokeSVGPrint shows the SVG print dialog.
Classes used in Pcbnew, CvPcb and GerbView.
Board plot function definition file.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:364
virtual bool EndPlot() override
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void SetPlotFrameRef(bool aFlag)
wxString GetOutputDirectory() const
LSET getCheckBoxSelectedLayers() const
PCB_LAYER_ID
A quick note on layer IDs:
Class LSET is a set of PCB_LAYER_IDs.
const wxString & GetFileName() const
Definition: class_board.h:234
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
wxCheckListBox * m_CopperLayersList
void PlotStandardLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Function PlotStandardLayer plot copper or technical layers.
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Helper function EnsureFileDirectoryExists make aTargetFullFileName absolute and creates the path of t...
Definition: common.cpp:282
REPORTER & Reporter()
returns the reporter object that reports to this panel
wxCheckListBox * m_TechnicalLayersList
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project&#39;s directory to be an absolu...
Definition: project.cpp:380
void SetSkipPlotNPTH_Pads(bool aSkip)
The common library.
WX_HTML_REPORT_PANEL * m_messagesPanel
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
int g_DrawDefaultLineThickness
Default line thickness in internal units used to draw or plot items using a default thickness line va...
static LSET s_SelectedLayers(4, B_Cu, F_Cu, F_SilkS, B_SilkS)
void SetOutputDirectory(wxString aDir)
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
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
const PAGE_INFO & GetPageSettings() const
Definition: class_board.h:547
PCB_PLOT_PARAMS * m_callers_params
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:57
const wxPoint & GetAuxOrigin() const
Definition: class_board.h:343
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Function BuildPlotFileName (helper function) Complete a plot filename: forces the output directory...
Definition: pcbplot.cpp:484
#define WIDTH_MIN_VALUE
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
void AddUnitSymbol(wxStaticText &Stext, EDA_UNITS_T aUnit)
Definition: base_units.cpp:515
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
#define PLOTSVGMODEONEFILE_KEY
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
The common library.
int GetWidth() const
Definition: eda_rect.h:117
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
PLOTTER * StartPlotBoard(BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aFullFileName, const wxString &aSheetDesc)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
#define PLOTSVGPLOT_BRD_EDGE_KEY
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:185
wxConfigBase * m_config
virtual void SetColorMode(bool _color_mode)
Definition: plotter.h:125
bool CreateSVGFile(const wxString &FullFileName, bool aOnlyOneFile)
#define PLOTSVGMODECOLOR_KEY
#define WIDTH_MAX_VALUE
Class DIALOG_SVG_PRINT_base.
std::pair< wxCheckListBox *, int > m_boxSelectLayer[PCB_LAYER_ID_COUNT]
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Function GetStandardLayerName returns an "English Standard" name of a PCB layer when given aLayerNumb...
Definition: class_board.h:647
LSEQ UIOrder() const
Definition: lset.cpp:786
#define PLOTSVGMODEMIRROR_KEY