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 <class_drawpanel.h>
34 #include <wxBasePcbFrame.h>
35 #include <class_pcb_screen.h>
36 #include <base_units.h>
37 #include <convert_to_biu.h>
39 #include <macros.h>
40 #include <reporter.h>
41 #include <confirm.h>
42 
43 #include <pcbnew.h>
44 #include <pcbplot.h>
45 #include <printout_controler.h>
46 #include <class_board.h>
47 #include <dialog_SVG_print_base.h>
48 #include <invoke_pcb_dialog.h>
49 #include <wx_html_report_panel.h>
50 
51 
53 {
54 public:
55  DIALOG_SVG_PRINT( wxTopLevelWindow* aParent, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings );
56 
57 private:
61  wxConfigBase* m_config;
63  // the list of existing board layers in wxCheckListBox, with the
64  // board layers id:
65  std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
66  bool m_printBW;
70 
71  void initDialog();
72 
73  void OnCloseWindow( wxCloseEvent& event ) override;
74  void OnButtonPlot( wxCommandEvent& event ) override;
75 
76  void OnButtonCloseClick( wxCommandEvent& event ) override;
77 
78  void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
79  void SetPenWidth();
80  void ExportSVGFile( bool aOnlyOneFile );
81 
83  {
84  return m_rbSvgPageSizeOpt->GetSelection() == 2;
85  }
86 
87  bool PrintPageRef()
88  {
89  return m_rbSvgPageSizeOpt->GetSelection() == 0;
90  }
91 
92  bool CreateSVGFile( const wxString& FullFileName, bool aOnlyOneFile );
93 
95 };
96 
97 
98 
99 // Keys for configuration
100 #define PLOTSVGMODECOLOR_KEY wxT( "PlotSVGModeColor" )
101 #define PLOTSVGMODEMIRROR_KEY wxT( "PlotSVGModeMirror" )
102 #define PLOTSVGMODEONEFILE_KEY wxT( "PlotSVGModeOneFile" )
103 #define PLOTSVGPAGESIZEOPT_KEY wxT( "PlotSVGPageOpt" )
104 #define PLOTSVGPLOT_BRD_EDGE_KEY wxT( "PlotSVGBrdEdge" )
105 
106 // reasonable values for default pen width
107 #define WIDTH_MAX_VALUE (2 * IU_PER_MM)
108 #define WIDTH_MIN_VALUE (0.05 * IU_PER_MM)
109 
110 // Local variables:
111 static LSET s_SelectedLayers( 4, B_Cu, F_Cu, F_SilkS, B_SilkS );
112 
113 /*
114  * DIALOG_SVG_PRINT functions
115  */
116 DIALOG_SVG_PRINT::DIALOG_SVG_PRINT( wxTopLevelWindow* aParent, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings ) :
117  DIALOG_SVG_PRINT_base( aParent ),
118  m_did_print( false ),
119  m_callers_params( aSettings )
120 {
121  m_board = aBoard;
123 
124  memset( m_boxSelectLayer, 0, sizeof( m_boxSelectLayer ) );
125 
126  initDialog();
127 
128  GetSizer()->Fit( this );
129  GetSizer()->SetSizeHints( this );
130  Centre();
131 }
132 
133 
135 {
136  if( m_config )
137  {
138  m_config->Read( PLOTSVGMODECOLOR_KEY, &m_printBW, false );
139  long ltmp;
140  m_config->Read( PLOTSVGPAGESIZEOPT_KEY, &ltmp, 0 );
141  m_config->Read( PLOTSVGMODEMIRROR_KEY, &m_printMirror, false );
143  m_rbSvgPageSizeOpt->SetSelection( ltmp );
144  m_config->Read( PLOTSVGPLOT_BRD_EDGE_KEY, &ltmp, 1 );
145  m_PrintBoardEdgesCtrl->SetValue( ltmp );
146  }
147 
150 
151  m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
152  m_printMirrorOpt->SetValue( m_printMirror );
153  m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );
154 
156 
158 
160 
161  for( ; seq; ++seq )
162  {
163  PCB_LAYER_ID layer = *seq;
164  int checkIndex;
165 
166  if( IsCopperLayer( layer ) )
167  {
168  checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
169  m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
170  }
171  else
172  {
173  checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
174  m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
175  }
176 
177  if( m_config )
178  {
179  wxString layerKey;
180  layerKey.Printf( OPTKEY_LAYERBASE, layer );
181  bool option;
182 
183  if( m_config && m_config->Read( layerKey, &option ) )
184  m_boxSelectLayer[layer].first->Check( checkIndex, option );
185  }
186  }
187 }
188 
189 
191 {
192  LSET ret;
193 
194  for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer )
195  {
196  if( !m_boxSelectLayer[layer].first )
197  continue;
198 
199  if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
200  ret.set( layer );
201  }
202 
203  return ret;
204 }
205 
206 
208 {
209  // Build the absolute path of current output plot directory
210  // to preselect it when opening the dialog.
211  wxFileName fn( m_outputDirectoryName->GetValue() );
212  wxString path = Prj().AbsolutePath( m_outputDirectoryName->GetValue() );
213 
214  wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
215 
216  if( dirDialog.ShowModal() == wxID_CANCEL )
217  return;
218 
219  wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
220 
221  wxMessageDialog dialog( this, _( "Use a relative path?" ),
222  _( "Plot Output Directory" ),
223  wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
224 
225  if( dialog.ShowModal() == wxID_YES )
226  {
227  wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
228 
229  boardFilePath = wxPathOnly( boardFilePath );
230 
231  if( !dirName.MakeRelativeTo( boardFilePath ) )
232  wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ),
233  _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
234  }
235 
236  m_outputDirectoryName->SetValue( dirName.GetFullPath() );
238 }
239 
240 
242 {
243  int pensize = ValueFromTextCtrl( *m_DialogDefaultPenSize );
244 
245  if( pensize > WIDTH_MAX_VALUE )
246  {
247  pensize = WIDTH_MAX_VALUE;
248  }
249 
250  if( pensize < WIDTH_MIN_VALUE )
251  {
252  pensize = WIDTH_MIN_VALUE;
253  }
254 
255  g_DrawDefaultLineThickness = pensize;
256  m_DialogDefaultPenSize->SetValue( StringFromValue( g_UserUnit, pensize ) );
257 }
258 
259 
260 void DIALOG_SVG_PRINT::ExportSVGFile( bool aOnlyOneFile )
261 {
263 
264  // Create output directory if it does not exist (also transform it in
265  // absolute form). Bail if it fails
266  wxFileName outputDir = wxFileName::DirName( m_outputDirectory );
267  wxString boardFilename = m_board->GetFileName();
268 
269  REPORTER& reporter = m_messagesPanel->Reporter();
270 
271  if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
272  {
273  wxString msg = wxString::Format(
274  _( "Could not write plot files to folder '%s'." ),
275  GetChars( outputDir.GetPath() )
276  );
277  DisplayError( this, msg );
278  return;
279  }
280 
281  m_printMirror = m_printMirrorOpt->GetValue();
282  m_printBW = m_ModeColorOption->GetSelection();
283  SetPenWidth();
284 
285  LSET all_selected = getCheckBoxSelectedLayers();
286 
287  for( LSEQ seq = all_selected.Seq(); seq; ++seq )
288  {
289  PCB_LAYER_ID layer = *seq;
290 
291  wxFileName fn( boardFilename );
292 
293  wxString suffix = aOnlyOneFile ? wxT( "brd" ) : m_board->GetStandardLayerName( layer );
294 
295  BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
296 
297  m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
298 
299  if( m_PrintBoardEdgesCtrl->IsChecked() )
300  m_printMaskLayer.set( Edge_Cuts );
301 
302  if( CreateSVGFile( fn.GetFullPath(), aOnlyOneFile ) )
303  {
304  reporter.Report (
305  wxString::Format( _( "Plot: '%s' OK." ), GetChars( fn.GetFullPath() ) ),
307  }
308  else // Error
309  {
310  reporter.Report (
311  wxString::Format( _( "Unable to create file '%s'." ), GetChars( fn.GetFullPath() ) ),
313  }
314 
315  if( aOnlyOneFile )
316  break;
317  }
318 }
319 
320 
321 // Actual SVG file export function.
322 bool DIALOG_SVG_PRINT::CreateSVGFile( const wxString& aFullFileName, bool aOnlyOneFile )
323 {
324  PCB_PLOT_PARAMS plot_opts;
325 
326  plot_opts.SetPlotFrameRef( PrintPageRef() );
327 
328  // Adding drill marks, for copper layers
329  if( ( m_printMaskLayer & LSET::AllCuMask() ).any() )
331  else
333 
334  plot_opts.SetSkipPlotNPTH_Pads( false );
335 
336  plot_opts.SetMirror( m_printMirror );
337  plot_opts.SetFormat( PLOT_FORMAT_SVG );
338 
339  PAGE_INFO pageInfo = m_board->GetPageSettings();
340  wxPoint axisorigin = m_board->GetAuxOrigin();
341 
343  {
345  PAGE_INFO currpageInfo = m_board->GetPageSettings();
346 
347  currpageInfo.SetWidthMils( bbox.GetWidth() / IU_PER_MILS );
348  currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
349  m_board->SetPageSettings( currpageInfo );
350  plot_opts.SetUseAuxOrigin( true );
351  wxPoint origin = bbox.GetOrigin();
352  m_board->SetAuxOrigin( origin );
353  }
354 
355  LOCALE_IO toggle;
356 
358  &plot_opts, UNDEFINED_LAYER, aFullFileName, wxEmptyString );
359 
360  if( plotter )
361  {
362  plotter->SetColorMode( !m_printBW );
363  if( aOnlyOneFile )
364  {
365  for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq )
366  PlotOneBoardLayer( m_board, plotter, *seq, plot_opts );
367  }
368  else
369  {
370  PlotStandardLayer( m_board, plotter, m_printMaskLayer, plot_opts );
371  }
372  plotter->EndPlot();
373  }
374 
375  delete plotter;
376 
377  m_board->SetAuxOrigin( axisorigin ); // reset to the values saved earlier
378  m_board->SetPageSettings( pageInfo );
379 
380  return true;
381 }
382 
383 
384 void DIALOG_SVG_PRINT::OnButtonPlot( wxCommandEvent& event )
385 {
386  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
388 
389  m_did_print = true;
390 }
391 
392 
393 void DIALOG_SVG_PRINT::OnButtonCloseClick( wxCommandEvent& event )
394 {
395  Close();
396 }
397 
398 
399 void DIALOG_SVG_PRINT::OnCloseWindow( wxCloseEvent& event )
400 {
401  if( m_did_print ) // unless output was created, this is tantamount to a cancel.
402  {
403  SetPenWidth();
404  m_printBW = m_ModeColorOption->GetSelection();
405  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
406 
407  // Why are SVG layer choices co-mingled with other plot layer choices in the config file?
408  // The string OPTKEY_LAYERBASE is used in multiple places.
409  // fix this.
410 
411  wxString dirStr = m_outputDirectoryName->GetValue();
412  dirStr.Replace( wxT( "\\" ), wxT( "/" ) );
413 
415 
416  if( m_config )
417  {
421  m_config->Write( PLOTSVGPAGESIZEOPT_KEY, m_rbSvgPageSizeOpt->GetSelection() );
423 
424  wxString layerKey;
425 
426  for( unsigned layer = 0; layer < DIM(m_boxSelectLayer); ++layer )
427  {
428  if( !m_boxSelectLayer[layer].first )
429  continue;
430 
431  layerKey.Printf( OPTKEY_LAYERBASE, layer );
432  m_config->Write( layerKey,
433  m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) );
434  }
435  }
436  }
437 
438  EndModal( m_did_print ? wxID_OK : wxID_CANCEL );
439 }
440 
441 
442 bool InvokeSVGPrint( wxTopLevelWindow* aCaller, BOARD* aBoard, PCB_PLOT_PARAMS* aSettings )
443 {
444  DIALOG_SVG_PRINT dlg( aCaller, aBoard, aSettings );
445 
446  return dlg.ShowModal() == wxID_OK;
447 }
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:646
#define DIM(x)
of elements in an array
Definition: macros.h:98
void OnButtonPlot(wxCommandEvent &event) override
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)
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:203
void SetFormat(PlotFormat aFormat)
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
int GetHeight() const
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:385
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.
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:337
const wxPoint & GetOrigin() const
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.
Classes used in Pcbnew, CvPcb and GerbView.
const wxString SVGFileExtension
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...
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:267
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's directory to be an absolu...
Definition: project.cpp:371
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:384
void SetHeightMils(int aHeightInMils)
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:56
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:485
#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:509
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)
Class EDA_RECT handles the component boundary box.
The common library.
int GetWidth() const
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:71
wxConfigBase * m_config
virtual void SetColorMode(bool _color_mode)
Definition: plot_common.h:116
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:759
#define PLOTSVGMODEMIRROR_KEY