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_edit_frame.h>
30 #include <pcbnew_settings.h>
32 #include <reporter.h>
33 #include <confirm.h>
34 
35 #include <pcbnew.h>
36 #include <pcbplot.h>
37 #include <class_board.h>
38 #include <dialog_export_svg_base.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_EDIT_FRAME* aParent, BOARD* aBoard );
47  ~DIALOG_EXPORT_SVG() override;
48 
49 private:
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 /*
76  * DIALOG_EXPORT_SVG functions
77  */
79  DIALOG_EXPORT_SVG_BASE( aParent ),
80  m_board( aBoard ),
81  m_parent( aParent ),
82  m_printBW( false ),
83  m_printMirror( false ),
84  m_oneFileOnly( false ),
85  m_lineWidth( aParent, m_penWidthLabel, m_penWidthCtrl, m_penWidthUnits, true )
86 {
87  m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
88 
89  initDialog();
90 
91  // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
92  // that requires us to correct the button labels here.
93  m_sdbSizer1OK->SetLabel( _( "Export" ) );
94  m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
95  m_sdbSizer1->Layout();
96 
98 }
99 
100 
102 {
104  m_printBW = m_ModeColorOption->GetSelection();
105  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
107  m_outputDirectory.Replace( wxT( "\\" ), wxT( "/" ) );
108 
109  auto cfg = m_parent->GetPcbNewSettings();
110 
112  cfg->m_ExportSvg.mirror = m_printMirror;
113  cfg->m_ExportSvg.one_file = m_oneFileOnly;
114  cfg->m_ExportSvg.plot_board_edges = m_PrintBoardEdgesCtrl->GetValue();
115  cfg->m_ExportSvg.page_size = m_rbSvgPageSizeOpt->GetSelection();
116  cfg->m_ExportSvg.output_dir = m_outputDirectory.ToStdString();
117 
118  cfg->m_ExportSvg.layers.clear();
119 
120  for( unsigned layer = 0; layer < arrayDim( m_boxSelectLayer ); ++layer )
121  {
122  if( !m_boxSelectLayer[layer].first )
123  continue;
124 
125  if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
126  cfg->m_ExportSvg.layers.push_back( m_boxSelectLayer[layer].second );
127  }
128 }
129 
130 
132 {
133  auto cfg = m_parent->GetPcbNewSettings();
134 
135  m_printBW = cfg->m_ExportSvg.black_and_white;
136  m_printMirror = cfg->m_ExportSvg.mirror;
137  m_oneFileOnly = cfg->m_ExportSvg.one_file;
138  m_outputDirectory = cfg->m_ExportSvg.output_dir;
139 
140  m_rbSvgPageSizeOpt->SetSelection( cfg->m_ExportSvg.page_size );
141  m_PrintBoardEdgesCtrl->SetValue( cfg->m_ExportSvg.plot_board_edges );
142 
144 
145  m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
146  m_printMirrorOpt->SetValue( m_printMirror );
147  m_rbFileOpt->SetSelection( m_oneFileOnly ? 1 : 0 );
148 
150 
151  for( LSEQ seq = m_board->GetEnabledLayers().UIOrder(); seq; ++seq )
152  {
153  PCB_LAYER_ID layer = *seq;
154  int checkIndex;
155 
156  if( IsCopperLayer( layer ) )
157  {
158  checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
159  m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
160  }
161  else
162  {
163  checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
164  m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
165  }
166 
167  if( std::find( cfg->m_ExportSvg.layers.begin(), cfg->m_ExportSvg.layers.end(), layer ) !=
168  cfg->m_ExportSvg.layers.end() )
169  m_boxSelectLayer[layer].first->Check( checkIndex, true );
170  }
171 }
172 
173 
175 {
176  LSET ret;
177 
178  for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
179  {
180  if( !m_boxSelectLayer[layer].first )
181  continue;
182 
183  if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
184  ret.set( layer );
185  }
186 
187  return ret;
188 }
189 
190 
192 {
193  // Build the absolute path of current output directory to preselect it in the file browser.
194  wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
195  path = Prj().AbsolutePath( path );
196 
197  wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
198 
199  if( dirDialog.ShowModal() == wxID_CANCEL )
200  return;
201 
202  wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
203 
204  wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
205  wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
206 
207  if( dialog.ShowModal() == wxID_YES )
208  {
209  wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
210 
211  boardFilePath = wxPathOnly( boardFilePath );
212 
213  if( !dirName.MakeRelativeTo( boardFilePath ) )
214  wxMessageBox( _( "Cannot make path relative (target volume different from board file volume)!" ),
215  _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
216  }
217 
218  m_outputDirectoryName->SetValue( dirName.GetFullPath() );
220 }
221 
222 
223 void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
224 {
226 
227  // Create output directory if it does not exist (also transform it in
228  // absolute form). Bail if it fails
229  wxString path = ExpandEnvVarSubstitutions( m_outputDirectory, &Prj() );
230  wxFileName outputDir = wxFileName::DirName( path );
231  wxString boardFilename = m_board->GetFileName();
232 
233  REPORTER& reporter = m_messagesPanel->Reporter();
234 
235  if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
236  {
237  wxString msg = wxString::Format( _( "Could not write plot files to folder \"%s\"." ),
238  outputDir.GetPath() );
239  DisplayError( this, msg );
240  return;
241  }
242 
243  m_printMirror = m_printMirrorOpt->GetValue();
244  m_printBW = m_ModeColorOption->GetSelection();
246 
247  LSET all_selected = getCheckBoxSelectedLayers();
248 
249  for( LSEQ seq = all_selected.Seq(); seq; ++seq )
250  {
251  PCB_LAYER_ID layer = *seq;
252  wxFileName fn( boardFilename );
253  wxString suffix = aOnlyOneFile ? wxT( "brd" ) : m_board->GetStandardLayerName( layer );
254 
255  BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
256  wxString svgPath = fn.GetFullPath();
257 
258  m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
259 
260  if( m_PrintBoardEdgesCtrl->IsChecked() )
262 
263  if( CreateSVGFile( svgPath ) )
264  {
265  reporter.Report( wxString::Format( _( "Exported \"%s\"." ), svgPath ), RPT_SEVERITY_ACTION );
266  }
267  else // Error
268  {
269  reporter.Report( wxString::Format( _( "Unable to create file \"%s\"." ), svgPath ),
271  }
272 
273  if( aOnlyOneFile )
274  break;
275  }
276 }
277 
278 
279 // Actual SVG file export function.
280 bool DIALOG_EXPORT_SVG::CreateSVGFile( const wxString& aFullFileName )
281 {
282  PCB_PLOT_PARAMS plot_opts;
283 
284  plot_opts.SetPlotFrameRef( m_rbSvgPageSizeOpt->GetSelection() == 0 );
285 
286  // Adding drill marks, for copper layers
287  if( ( m_printMaskLayer & LSET::AllCuMask() ).any() )
289  else
291 
292  plot_opts.SetSkipPlotNPTH_Pads( false );
293 
294  plot_opts.SetMirror( m_printMirror );
295  plot_opts.SetFormat( PLOT_FORMAT::SVG );
296 
297  PAGE_INFO savedPageInfo = m_board->GetPageSettings();
298  wxPoint savedAuxOrigin = m_board->GetDesignSettings().m_AuxOrigin;
299 
300  if( m_rbSvgPageSizeOpt->GetSelection() == 2 ) // Page is board boundary size
301  {
303  PAGE_INFO currpageInfo = m_board->GetPageSettings();
304 
305  currpageInfo.SetWidthMils( bbox.GetWidth() / IU_PER_MILS );
306  currpageInfo.SetHeightMils( bbox.GetHeight() / IU_PER_MILS );
307  m_board->SetPageSettings( currpageInfo );
308  plot_opts.SetUseAuxOrigin( true );
309  wxPoint origin = bbox.GetOrigin();
311  }
312 
313  SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
315 
316  plot_opts.SetColorSettings( mgr.GetColorSettings( cfg->m_ColorTheme ) );
317 
318  LOCALE_IO toggle;
319 
320  SVG_PLOTTER* plotter = (SVG_PLOTTER*) StartPlotBoard( m_board, &plot_opts, UNDEFINED_LAYER,
321  aFullFileName, wxEmptyString );
322 
323  if( plotter )
324  {
325  plotter->SetColorMode( !m_printBW );
326 
327  for( LSEQ seq = m_printMaskLayer.SeqStackupBottom2Top(); seq; ++seq )
328  PlotOneBoardLayer( m_board, plotter, *seq, plot_opts );
329 
330  plotter->EndPlot();
331  }
332 
333  delete plotter;
334 
335  // reset to the values saved earlier
336  m_board->GetDesignSettings().m_AuxOrigin = savedAuxOrigin;
337  m_board->SetPageSettings( savedPageInfo );
338 
339  return true;
340 }
341 
342 
343 void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
344 {
345  m_oneFileOnly = m_rbFileOpt->GetSelection() == 1;
347 }
348 
349 
350 bool InvokeExportSVG( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
351 {
352  DIALOG_EXPORT_SVG dlg( aCaller, aBoard );
353 
354  dlg.ShowModal();
355 
356  return true;
357 }
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:712
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
const BITMAP_OPAQUE folder_xpm[1]
Definition: folder.cpp:20
const PAGE_INFO & GetPageSettings() const
Definition: class_board.h:572
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
void SetUseAuxOrigin(bool aAux)
wxCheckListBox * m_CopperLayersList
This file is part of the common library.
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.
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition: plotter.h:143
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:573
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...
int GetWidth() const
Definition: eda_rect.h:119
void SetMirror(bool aFlag)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
LSEQ SeqStackupBottom2Top() const
Function SeqStackBottom2Top returns the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:425
void SetDrillMarksType(DrillMarksType aVal)
PCBNEW_SETTINGS * GetPcbNewSettings()
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:574
REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
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:377
const wxString & GetFileName() const
Definition: class_board.h:255
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
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:270
Board plot function definition file.
virtual bool EndPlot() override
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
void SetPlotFrameRef(bool aFlag)
PCB_LAYER_ID
A quick note on layer IDs:
DIALOG_EXPORT_SVG m_ExportSvg
LSET is a set of PCB_LAYER_IDs.
wxCheckListBox * m_TechnicalLayersList
DIALOG_EXPORT_SVG(PCB_EDIT_FRAME *aParent, BOARD *aBoard)
void OnButtonPlot(wxCommandEvent &event) override
void SetColorSettings(COLOR_SETTINGS *aSettings)
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
PAGE_INFO describes the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
bool EnsureFileDirectoryExists(wxFileName *aTargetFullFileName, const wxString &aBaseFilename, REPORTER *aReporter)
Make aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.
Definition: common.cpp:602
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...
void SetSkipPlotNPTH_Pads(bool aSkip)
Definition of file extensions used in Kicad.
AppSettings * GetAppSettings(bool aLoadNow=true)
Returns a handle to the a given settings by type If the settings have already been loaded,...
LSET getCheckBoxSelectedLayers() const
void SetFormat(PLOT_FORMAT aFormat)
PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board.
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
int GetHeight() const
Definition: eda_rect.h:120
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
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:373
Class DIALOG_EXPORT_SVG_BASE.
COLOR_SETTINGS * GetColorSettings(const wxString &aName="user")
Retrieves a color settings object that applications can read colors from.
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
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
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
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
PCB_EDIT_FRAME is the main frame for Pcbnew.
const std::string SVGFileExtension
#define IU_PER_MILS
Definition: plotter.cpp:138
The common library.
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
bool InvokeExportSVG(PCB_EDIT_FRAME *aCaller, BOARD *aBoard)
Function InvokeExportSVG shows the Export SVG dialog.
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
PCB_EDIT_FRAME * m_parent
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...
LSEQ UIOrder() const
Definition: lset.cpp:839
wxPoint m_AuxOrigin
origin for plot exports
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:648
wxString m_ColorTheme
Active color theme name.
Definition: app_settings.h:156