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( PCB_LAYER_ID layer : m_board->GetEnabledLayers().UIOrder() )
196 {
197 int checkIndex;
198
199 if( IsCopperLayer( layer ) )
200 {
201 checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
202 m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
203 }
204 else
205 {
206 checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
207 m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
208 }
209
210 if( alg::contains( cfg->m_ExportSvg.layers, layer ) )
211 m_boxSelectLayer[layer].first->Check( checkIndex, true );
212 }
213}
214
215
217{
218 LSET ret;
219
220 for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
221 {
222 if( !m_boxSelectLayer[layer].first )
223 continue;
224
225 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
226 ret.set( layer );
227 }
228
229 return ret;
230}
231
232
234{
235 // Build the absolute path of current output directory to preselect it in the file browser.
236 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
237 path = Prj().AbsolutePath( path );
238
239 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
240
241 if( dirDialog.ShowModal() == wxID_CANCEL )
242 return;
243
244 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
245
246 wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
247 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
248
249 if( dialog.ShowModal() == wxID_YES )
250 {
251 wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
252
253 boardFilePath = wxPathOnly( boardFilePath );
254
255 if( !dirName.MakeRelativeTo( boardFilePath ) )
256 wxMessageBox( _( "Cannot make path relative (target volume different from board "
257 "file volume)!" ),
258 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
259 }
260
261 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
263}
264
265
266void DIALOG_EXPORT_SVG::onPagePerLayerClicked( wxCommandEvent& event )
267{
269
270 if( m_checkboxPagePerLayer->GetValue() )
271 {
272 m_checkboxEdgesOnAllPages->Enable( true );
274 }
275 else
276 {
277 m_checkboxEdgesOnAllPages->Enable( false );
278 m_checkboxEdgesOnAllPages->SetValue( false );
279 }
280}
281
282
283void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
284{
286
287 // Create output directory if it does not exist (also transform it in absolute form).
288 // Bail if it fails.
289
290 std::function<bool( wxString* )> textResolver =
291 [&]( wxString* token ) -> bool
292 {
293 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
294 return m_board->ResolveTextVar( token, 0 );
295 };
296
297 wxString path = m_outputDirectory;
298 path = ExpandTextVars( path, &textResolver );
299 path = ExpandEnvVarSubstitutions( path, nullptr );
300
301 wxFileName outputDir = wxFileName::DirName( path );
302 wxString boardFilename = m_board->GetFileName();
303
304 REPORTER& reporter = m_messagesPanel->Reporter();
305
306 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
307 {
308 wxString msg = wxString::Format( _( "Could not write plot files to folder '%s'." ),
309 outputDir.GetPath() );
310 DisplayError( this, msg );
311 return;
312 }
313
314 m_printMirror = m_printMirrorOpt->GetValue();
315 m_printBW = m_ModeColorOption->GetSelection();
316
317 LSET all_selected = getCheckBoxSelectedLayers();
318
319 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
320 svgPlotOptions.m_negative = false;
321 svgPlotOptions.m_blackAndWhite = m_printBW;
322 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
323 svgPlotOptions.m_sketchPadsOnFabLayers = false;
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( PCB_LAYER_ID layer : all_selected.Seq() )
338 {
339 wxFileName fn( boardFilename );
340 wxString suffix = aOnlyOneFile ? wxString( wxT( "brd" ) ) : m_board->GetStandardLayerName( layer );
341
342 BuildPlotFileName( &fn, outputDir.GetPath(), suffix, FILEEXT::SVGFileExtension );
343 wxString svgPath = fn.GetFullPath();
344
345 m_printMaskLayer = aOnlyOneFile ? all_selected.SeqStackupForPlotting() : LSEQ( { layer } );
346
347 if( m_checkboxEdgesOnAllPages->GetValue() )
348 m_printMaskLayer.push_back( Edge_Cuts );
349
350 svgPlotOptions.m_outputFile = svgPath;
351 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
352
353 if( EXPORT_SVG::Plot(m_board, svgPlotOptions ) )
354 {
355 reporter.Report( wxString::Format( _( "Exported '%s'." ), svgPath ),
357 }
358 else // Error
359 {
360 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), svgPath ),
362 }
363
364 if( aOnlyOneFile )
365 break;
366 }
367}
368
369
370void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
371{
374}
375
376
377bool InvokeExportSVG( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
378{
379 DIALOG_EXPORT_SVG dlg( aCaller, aBoard );
380
381 dlg.ShowModal();
382
383 return true;
384}
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
BASE_SET & set(size_t pos=std::numeric_limits< size_t >::max(), bool value=true)
Definition: base_set.h:61
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:758
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition: board.h:779
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:431
const wxString & GetFileName() const
Definition: board.h:326
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:575
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:29
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: lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:35
LSEQ UIOrder() const
Definition: lset.cpp:866
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:393
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:538
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:343
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:371
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:59
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
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:531
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:373
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
bool m_sketchPadsOnFabLayers
Definition: export_svg.h:37
wxString m_colorTheme
Definition: export_svg.h:27
wxString m_outputFile
Definition: export_svg.h:26
Definition of file extensions used in Kicad.