KiCad PCB EDA Suite
dialog_export_svg.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) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2012 KiCad Developers, see change_log.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 
26 #include <fctsys.h>
27 #include <kiface_i.h>
28 #include <common.h>
29 #include <pcb_base_frame.h>
31 #include <reporter.h>
32 #include <confirm.h>
33 
34 #include <pcbnew.h>
35 #include <pcbplot.h>
36 #include <class_board.h>
37 #include <dialog_export_svg_base.h>
38 #include <invoke_pcb_dialog.h>
39 #include <wx_html_report_panel.h>
40 #include <bitmaps.h>
41 #include <widgets/unit_binder.h>
42 
44 {
45 public:
46  DIALOG_EXPORT_SVG( PCB_BASE_FRAME* aParent, BOARD* aBoard );
47  ~DIALOG_EXPORT_SVG() override;
48 
49 private:
51  wxConfigBase* m_config;
53  // the list of existing board layers in wxCheckListBox, with the
54  // board layers id:
55  std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
56  bool m_printBW;
61 
62  void initDialog();
63 
64  void OnButtonPlot( wxCommandEvent& event ) override;
65 
66  void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
67  void ExportSVGFile( bool aOnlyOneFile );
68 
69  bool CreateSVGFile( const wxString& FullFileName );
70 
72 };
73 
74 
75 // Keys for configuration
76 #define PLOTSVGMODECOLOR_KEY wxT( "PlotSVGModeColor" )
77 #define PLOTSVGMODEMIRROR_KEY wxT( "PlotSVGModeMirror" )
78 #define PLOTSVGMODEONEFILE_KEY wxT( "PlotSVGModeOneFile" )
79 #define PLOTSVGPAGESIZEOPT_KEY wxT( "PlotSVGPageOpt" )
80 #define PLOTSVGPLOT_BRD_EDGE_KEY wxT( "PlotSVGBrdEdge" )
81 #define PLOTSVG_LAYERBASE wxT( "PlotSVGLayer_%d" )
82 #define PLOTSVG_DIR_KEY wxT( "PlotSVGDirectory" )
83 
84 /*
85  * DIALOG_EXPORT_SVG functions
86  */
88  DIALOG_EXPORT_SVG_BASE( aParent ),
90 {
91  m_board = aBoard;
93 
94  memset( m_boxSelectLayer, 0, sizeof( m_boxSelectLayer ) );
95 
96  m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
97 
98  initDialog();
99 
100  // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
101  // that requires us to correct the button labels here.
102  m_sdbSizer1OK->SetLabel( _( "Export" ) );
103  m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
104  m_sdbSizer1->Layout();
105 
107 }
108 
109 
111 {
113  m_printBW = m_ModeColorOption->GetSelection();
114  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
116  m_outputDirectory.Replace( wxT( "\\" ), wxT( "/" ) );
117 
118  if( m_config )
119  {
124  m_config->Write( PLOTSVGPAGESIZEOPT_KEY, m_rbSvgPageSizeOpt->GetSelection() );
126 
127  wxString layerKey;
128 
129  for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
130  {
131  if( !m_boxSelectLayer[layer].first )
132  continue;
133 
134  layerKey.Printf( PLOTSVG_LAYERBASE, layer );
135  m_config->Write( layerKey, m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) );
136  }
137  }
138 }
139 
140 
142 {
143  if( m_config )
144  {
145  m_config->Read( PLOTSVG_DIR_KEY, &m_outputDirectory, wxEmptyString );
146  m_config->Read( PLOTSVGMODECOLOR_KEY, &m_printBW, false );
147  long ltmp;
148  m_config->Read( PLOTSVGPAGESIZEOPT_KEY, &ltmp, 0 );
149  m_rbSvgPageSizeOpt->SetSelection( ltmp );
150  m_config->Read( PLOTSVGMODEMIRROR_KEY, &m_printMirror, false );
152  m_config->Read( PLOTSVGPLOT_BRD_EDGE_KEY, &ltmp, 1 );
153  m_PrintBoardEdgesCtrl->SetValue( ltmp );
154  }
155 
157 
158  m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
159  m_printMirrorOpt->SetValue( m_printMirror );
160  m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );
161 
163 
164  for( LSEQ seq = m_board->GetEnabledLayers().UIOrder(); seq; ++seq )
165  {
166  PCB_LAYER_ID layer = *seq;
167  int checkIndex;
168 
169  if( IsCopperLayer( layer ) )
170  {
171  checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
172  m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
173  }
174  else
175  {
176  checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
177  m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
178  }
179 
180  if( m_config )
181  {
182  wxString layerKey;
183  layerKey.Printf( PLOTSVG_LAYERBASE, layer );
184  bool option;
185 
186  if( m_config && m_config->Read( layerKey, &option ) )
187  m_boxSelectLayer[layer].first->Check( checkIndex, option );
188  }
189  }
190 }
191 
192 
194 {
195  LSET ret;
196 
197  for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
198  {
199  if( !m_boxSelectLayer[layer].first )
200  continue;
201 
202  if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
203  ret.set( layer );
204  }
205 
206  return ret;
207 }
208 
209 
211 {
212  // Build the absolute path of current output plot directory
213  // to preselect it when opening the dialog.
214  wxFileName fn( m_outputDirectoryName->GetValue() );
215  wxString path = Prj().AbsolutePath( m_outputDirectoryName->GetValue() );
216 
217  wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
218 
219  if( dirDialog.ShowModal() == wxID_CANCEL )
220  return;
221 
222  wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
223 
224  wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
225  wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
226 
227  if( dialog.ShowModal() == wxID_YES )
228  {
229  wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
230 
231  boardFilePath = wxPathOnly( boardFilePath );
232 
233  if( !dirName.MakeRelativeTo( boardFilePath ) )
234  wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ),
235  _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
236  }
237 
238  m_outputDirectoryName->SetValue( dirName.GetFullPath() );
240 }
241 
242 
243 void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
244 {
246 
247  // Create output directory if it does not exist (also transform it in
248  // absolute form). Bail if it fails
249  wxFileName outputDir = wxFileName::DirName( m_outputDirectory );
250  wxString boardFilename = m_board->GetFileName();
251 
252  REPORTER& reporter = m_messagesPanel->Reporter();
253 
254  if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
255  {
256  wxString msg = wxString::Format( _( "Could not write plot files to folder \"%s\"." ),
257  outputDir.GetPath() );
258  DisplayError( this, msg );
259  return;
260  }
261 
262  m_printMirror = m_printMirrorOpt->GetValue();
263  m_printBW = m_ModeColorOption->GetSelection();
265 
266  LSET all_selected = getCheckBoxSelectedLayers();
267 
268  for( LSEQ seq = all_selected.Seq(); seq; ++seq )
269  {
270  PCB_LAYER_ID layer = *seq;
271  wxFileName fn( boardFilename );
272  wxString suffix = aOnlyOneFile ? wxT( "brd" ) : m_board->GetStandardLayerName( layer );
273 
274  BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
275  wxString path = fn.GetFullPath();
276 
277  m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
278 
279  if( m_PrintBoardEdgesCtrl->IsChecked() )
281 
282  if( CreateSVGFile( path ) )
283  {
284  reporter.Report( wxString::Format( _( "Exported \"%s\"." ), path ),
286  }
287  else // Error
288  {
289  reporter.Report( wxString::Format( _( "Unable to create file \"%s\"." ), path ),
291  }
292 
293  if( aOnlyOneFile )
294  break;
295  }
296 }
297 
298 
299 // Actual SVG file export function.
300 bool DIALOG_EXPORT_SVG::CreateSVGFile( const wxString& aFullFileName )
301 {
302  PCB_PLOT_PARAMS plot_opts;
303 
304  plot_opts.SetPlotFrameRef( m_rbSvgPageSizeOpt->GetSelection() == 0 );
305 
306  // Adding drill marks, for copper layers
307  if( ( m_printMaskLayer & LSET::AllCuMask() ).any() )
309  else
311 
312  plot_opts.SetSkipPlotNPTH_Pads( false );
313 
314  plot_opts.SetMirror( m_printMirror );
315  plot_opts.SetFormat( PLOT_FORMAT_SVG );
316 
317  PAGE_INFO pageInfo = m_board->GetPageSettings();
318  wxPoint axisorigin = m_board->GetAuxOrigin();
319 
320  if( m_rbSvgPageSizeOpt->GetSelection() == 2 ) // Page is board boundary size
321  {
323  PAGE_INFO currpageInfo = m_board->GetPageSettings();
324 
325  currpageInfo.SetWidthMils( bbox.GetWidth() / IU_PER_MILS );
326  currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
327  m_board->SetPageSettings( currpageInfo );
328  plot_opts.SetUseAuxOrigin( true );
329  wxPoint origin = bbox.GetOrigin();
330  m_board->SetAuxOrigin( origin );
331  }
332 
333  LOCALE_IO toggle;
334 
335  SVG_PLOTTER* plotter = (SVG_PLOTTER*) StartPlotBoard( m_board, &plot_opts, UNDEFINED_LAYER,
336  aFullFileName, wxEmptyString );
337 
338  if( plotter )
339  {
340  plotter->SetColorMode( !m_printBW );
341 
342  for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq )
343  PlotOneBoardLayer( m_board, plotter, *seq, plot_opts );
344 
345  plotter->EndPlot();
346  }
347 
348  delete plotter;
349 
350  m_board->SetAuxOrigin( axisorigin ); // reset to the values saved earlier
351  m_board->SetPageSettings( pageInfo );
352 
353  return true;
354 }
355 
356 
357 void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
358 {
359  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
361 }
362 
363 
364 bool InvokeExportSVG( PCB_BASE_FRAME* aCaller, BOARD* aBoard )
365 {
366  DIALOG_EXPORT_SVG dlg( aCaller, aBoard );
367 
368  dlg.ShowModal();
369 
370  return true;
371 }
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:676
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
#define PLOTSVGMODEONEFILE_KEY
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:180
DIALOG_EXPORT_SVG(PCB_BASE_FRAME *aParent, BOARD *aBoard)
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
void SetUseAuxOrigin(bool aAux)
wxCheckListBox * m_CopperLayersList
This file is part of the common library.
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.
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition: plotter.h:126
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:555
wxConfigBase * m_config
void SetFormat(PlotFormat aFormat)
bool CreateSVGFile(const wxString &FullFileName)
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
#define PLOTSVG_DIR_KEY
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
#define PLOTSVGPLOT_BRD_EDGE_KEY
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
void SetAuxOrigin(const wxPoint &aPoint)
Function SetAuxOrigin sets the origin point used for plotting.
Definition: class_board.h:349
LSEQ SeqStackupBottom2Top() const
Function SeqStackBottom2Top returns the sequence that is typical for a bottom-to-top stack-up...
Definition: lset.cpp:415
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
Classes used in Pcbnew, CvPcb and GerbView.
Board plot function definition file.
virtual int GetValue()
Function GetValue Returns the current value in Internal Units.
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:367
virtual bool EndPlot() override
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
void SetPlotFrameRef(bool aFlag)
PCB_LAYER_ID
A quick note on layer IDs:
Class LSET is a set of PCB_LAYER_IDs.
wxCheckListBox * m_TechnicalLayersList
void OnButtonPlot(wxCommandEvent &event) override
const wxString & GetFileName() const
Definition: class_board.h:238
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
Definition: page_info.h:54
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn&#39;t yet exist...
Definition: common.cpp:468
REPORTER & Reporter()
returns the reporter object that reports to this panel
int g_DrawDefaultLineThickness
Default line thickness in internal units used to draw or plot items using a default thickness line va...
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)
Definition of file extensions used in Kicad.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
Class PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board...
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:554
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
of elements in an array. This implements type-safe compile time checking
Definition: macros.h:99
LSET getCheckBoxSelectedLayers() const
const wxPoint & GetAuxOrigin() const
Definition: class_board.h:350
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:371
Class DIALOG_EXPORT_SVG_BASE.
#define PLOTSVGMODEMIRROR_KEY
#define PLOTSVG_LAYERBASE
wxStdDialogButtonSizer * m_sdbSizer1
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
bool InvokeExportSVG(PCB_BASE_FRAME *aCaller, BOARD *aBoard)
Function InvokeExportSVG shows the Export SVG dialog.
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:171
WX_HTML_REPORT_PANEL * m_messagesPanel
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
const std::string SVGFileExtension
#define IU_PER_MILS
Definition: plotter.cpp:134
The common library.
int GetWidth() const
Definition: eda_rect.h:117
#define PLOTSVGPAGESIZEOPT_KEY
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.
void ExportSVGFile(bool aOnlyOneFile)
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...
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
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:659
LSEQ UIOrder() const
Definition: lset.cpp:803
#define PLOTSVGMODECOLOR_KEY