KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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) 2022-2023 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
26#include <pcb_edit_frame.h>
27#include <pcbnew_settings.h>
29#include <reporter.h>
30#include <confirm.h>
31#include <core/arraydim.h>
32#include <pcbplot.h>
33#include <locale_io.h>
35#include <bitmaps.h>
39#include <wx/dirdlg.h>
40#include <wx/msgdlg.h>
41#include <pgm_base.h>
44
46{
47public:
48 DIALOG_EXPORT_SVG( PCB_EDIT_FRAME* aParent, BOARD* aBoard );
49 ~DIALOG_EXPORT_SVG() override;
50
51private:
55 // the list of existing board layers in wxCheckListBox, with the
56 // board layers id:
57 std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
62
63 void initDialog();
64
65 void OnButtonPlot( wxCommandEvent& event ) override;
66
67 void onPagePerLayerClicked( wxCommandEvent& event ) override;
68 void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
69 void ExportSVGFile( bool aOnlyOneFile );
70
72};
73
74
76 DIALOG_EXPORT_SVG_BASE( aParent ),
77 m_board( aBoard ),
78 m_parent( aParent ),
79 m_printBW( false ),
80 m_printMirror( false ),
81 m_oneFileOnly( false )
82{
83 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
84
85 m_messagesPanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
86
87 initDialog();
88
89 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
90 { wxID_CANCEL, _( "Close" ) } } );
91
93 m_cbUsedBoardTheme->SetValue( !cfg->m_ExportSvg.use_selected_theme );
94
95 // Build color theme list, and select the previoulsy selected theme
96 wxString theme_old_selection = cfg->m_ExportSvg.color_theme;
97
99 {
100 int pos = m_colorTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
101
102 if( settings->GetName() == theme_old_selection )
103 m_colorTheme->SetSelection( pos );
104 }
105
107}
108
109
111{
112 m_printBW = m_ModeColorOption->GetSelection();
115 m_outputDirectory.Replace( wxT( "\\" ), wxT( "/" ) );
116
118
119 PCBNEW_SETTINGS* cfg = nullptr;
120
121 try
122 {
124 }
125 catch( const std::runtime_error& e )
126 {
127 wxFAIL_MSG( e.what() );
128 }
129
130 if( cfg )
131 {
135 cfg->m_ExportSvg.page_size = m_rbSvgPageSizeOpt->GetSelection();
136 cfg->m_ExportSvg.output_dir = m_outputDirectory.ToStdString();
138 cfg->m_ExportSvg.color_theme = m_colorTheme->GetStringSelection();
139 }
140
141 if( m_checkboxPagePerLayer->GetValue() )
142 {
143 m_oneFileOnly = false;
144
145 if( cfg )
147 }
148 else
149 {
150 m_oneFileOnly = true;
151 }
152
153 if( cfg )
154 cfg->m_ExportSvg.layers.clear();
155
156 for( unsigned layer = 0; layer < arrayDim( m_boxSelectLayer ); ++layer )
157 {
158 if( !m_boxSelectLayer[layer].first )
159 continue;
160
161 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
162 {
163 if( cfg )
164 cfg->m_ExportSvg.layers.push_back( layer );
165 }
166 }
167}
168
169
171{
172 PROJECT_FILE& projectFile = m_parent->Prj().GetProjectFile();
174
178
179 if( !projectFile.m_PcbLastPath[ LAST_PATH_SVG ].IsEmpty() )
181 else
183
184 m_rbSvgPageSizeOpt->SetSelection( cfg->m_ExportSvg.page_size );
186
187 wxCommandEvent dummy;
189
191
192 m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
193 m_printMirrorOpt->SetValue( m_printMirror );
194
195 for( LSEQ seq = m_board->GetEnabledLayers().UIOrder(); seq; ++seq )
196 {
197 PCB_LAYER_ID layer = *seq;
198 int checkIndex;
199
200 if( IsCopperLayer( layer ) )
201 {
202 checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
203 m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
204 }
205 else
206 {
207 checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
208 m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
209 }
210
211 if( alg::contains( cfg->m_ExportSvg.layers, layer ) )
212 m_boxSelectLayer[layer].first->Check( checkIndex, true );
213 }
214}
215
216
218{
219 LSET ret;
220
221 for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
222 {
223 if( !m_boxSelectLayer[layer].first )
224 continue;
225
226 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
227 ret.set( layer );
228 }
229
230 return ret;
231}
232
233
235{
236 // Build the absolute path of current output directory to preselect it in the file browser.
237 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
238 path = Prj().AbsolutePath( path );
239
240 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
241
242 if( dirDialog.ShowModal() == wxID_CANCEL )
243 return;
244
245 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
246
247 wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
248 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
249
250 if( dialog.ShowModal() == wxID_YES )
251 {
252 wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
253
254 boardFilePath = wxPathOnly( boardFilePath );
255
256 if( !dirName.MakeRelativeTo( boardFilePath ) )
257 wxMessageBox( _( "Cannot make path relative (target volume different from board "
258 "file volume)!" ),
259 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
260 }
261
262 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
264}
265
266
267void DIALOG_EXPORT_SVG::onPagePerLayerClicked( wxCommandEvent& event )
268{
270
271 if( m_checkboxPagePerLayer->GetValue() )
272 {
273 m_checkboxEdgesOnAllPages->Enable( true );
275 }
276 else
277 {
278 m_checkboxEdgesOnAllPages->Enable( false );
279 m_checkboxEdgesOnAllPages->SetValue( false );
280 }
281}
282
283
284void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
285{
287
288 // Create output directory if it does not exist (also transform it in absolute form).
289 // Bail if it fails.
290
291 std::function<bool( wxString* )> textResolver =
292 [&]( wxString* token ) -> bool
293 {
294 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
295 return m_board->ResolveTextVar( token, 0 );
296 };
297
298 wxString path = m_outputDirectory;
299 path = ExpandTextVars( path, &textResolver );
300 path = ExpandEnvVarSubstitutions( path, nullptr );
301
302 wxFileName outputDir = wxFileName::DirName( path );
303 wxString boardFilename = m_board->GetFileName();
304
305 REPORTER& reporter = m_messagesPanel->Reporter();
306
307 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
308 {
309 wxString msg = wxString::Format( _( "Could not write plot files to folder '%s'." ),
310 outputDir.GetPath() );
311 DisplayError( this, msg );
312 return;
313 }
314
315 m_printMirror = m_printMirrorOpt->GetValue();
316 m_printBW = m_ModeColorOption->GetSelection();
317
318 LSET all_selected = getCheckBoxSelectedLayers();
319
320 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
321 svgPlotOptions.m_negative = false;
322 svgPlotOptions.m_blackAndWhite = m_printBW;
323 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
324 svgPlotOptions.m_pageSizeMode = m_rbSvgPageSizeOpt->GetSelection();
325
327 wxString export_theme = m_cbUsedBoardTheme->GetValue()
328 ? cfg->m_ColorTheme
329 : m_colorTheme->GetStringSelection();
330
331 svgPlotOptions.m_colorTheme = export_theme;
332
333 svgPlotOptions.m_mirror = m_printMirror;
334 svgPlotOptions.m_plotFrame = svgPlotOptions.m_pageSizeMode == 0;
335 svgPlotOptions.m_drillShapeOption = 2; // actual size hole.
336
337 for( LSEQ seq = all_selected.Seq(); seq; ++seq )
338 {
339 PCB_LAYER_ID layer = *seq;
340 wxFileName fn( boardFilename );
341 wxString suffix = aOnlyOneFile ? wxString( wxT( "brd" ) ) : m_board->GetStandardLayerName( layer );
342
343 BuildPlotFileName( &fn, outputDir.GetPath(), suffix, FILEEXT::SVGFileExtension );
344 wxString svgPath = fn.GetFullPath();
345
346 m_printMaskLayer = aOnlyOneFile ? all_selected.SeqStackupForPlotting() : LSEQ( { layer } );
347
348 if( m_checkboxEdgesOnAllPages->GetValue() )
349 m_printMaskLayer.push_back( Edge_Cuts );
350
351 svgPlotOptions.m_outputFile = svgPath;
352 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
353
354 if( EXPORT_SVG::Plot(m_board, svgPlotOptions ) )
355 {
356 reporter.Report( wxString::Format( _( "Exported '%s'." ), svgPath ),
358 }
359 else // Error
360 {
361 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), svgPath ),
363 }
364
365 if( aOnlyOneFile )
366 break;
367 }
368}
369
370
371void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
372{
375}
376
377
378bool InvokeExportSVG( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
379{
380 DIALOG_EXPORT_SVG dlg( aCaller, aBoard );
381
382 dlg.ShowModal();
383
384 return true;
385}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
wxString m_ColorTheme
Active color theme name.
Definition: app_settings.h:175
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:677
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition: board.h:768
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:421
const wxString & GetFileName() const
Definition: board.h:319
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:564
Color settings are a bit different than most of the settings objects in that there can be more than o...
Class DIALOG_EXPORT_SVG_BASE.
wxCheckListBox * m_CopperLayersList
WX_HTML_REPORT_PANEL * m_messagesPanel
STD_BITMAP_BUTTON * m_browseButton
wxCheckListBox * m_TechnicalLayersList
DIALOG_EXPORT_SVG(PCB_EDIT_FRAME *aParent, BOARD *aBoard)
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
PCB_EDIT_FRAME * m_parent
void OnButtonPlot(wxCommandEvent &event) override
void onPagePerLayerClicked(wxCommandEvent &event) override
LSET getCheckBoxSelectedLayers() const
std::pair< wxCheckListBox *, int > m_boxSelectLayer[PCB_LAYER_ID_COUNT]
void ExportSVGFile(bool aOnlyOneFile)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
SETTINGS_MANAGER * GetSettingsManager() const
static bool Plot(BOARD *aBoard, const PCB_PLOT_SVG_OPTIONS &aSvgPlotOptions)
Definition: export_svg.cpp:30
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:521
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
LSEQ UIOrder() const
Definition: lset.cpp:1012
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:563
DIALOG_EXPORT_SVG m_ExportSvg
PCBNEW_SETTINGS * GetPcbNewSettings() const
The main frame for Pcbnew.
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:70
wxString m_PcbLastPath[LAST_PATH_SIZE]
MRU path storage.
Definition: project_file.h:157
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:166
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:320
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
std::vector< COLOR_SETTINGS * > GetColorSettingsList()
void SetBitmap(const wxBitmapBundle &aBmp)
void SetFileName(const wxString &aReportFileName)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:334
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:362
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:58
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:161
This file is part of the common library.
bool InvokeExportSVG(PCB_EDIT_FRAME *aCaller, BOARD *aBoard)
Function InvokeExportSVG shows the Export SVG dialog.
#define _(s)
static const std::string SVGFileExtension
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:881
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Edge_Cuts
Definition: layer_ids.h:113
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:137
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition: pcbplot.cpp:361
see class PGM_BASE
Plotting engines similar to ps (PostScript, Gerber, svg)
@ LAST_PATH_SVG
Definition: project_file.h:56
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
wxString m_colorTheme
Definition: export_svg.h:27
wxString m_outputFile
Definition: export_svg.h:26
Definition of file extensions used in Kicad.