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 <pgm_base.h>
43
45{
46public:
47 DIALOG_EXPORT_SVG( PCB_EDIT_FRAME* aParent, BOARD* aBoard );
48 ~DIALOG_EXPORT_SVG() override;
49
50private:
54 // the list of existing board layers in wxCheckListBox, with the
55 // board layers id:
56 std::pair<wxCheckListBox*, int> m_boxSelectLayer[PCB_LAYER_ID_COUNT];
61
62 void initDialog();
63
64 void OnButtonPlot( wxCommandEvent& event ) override;
65
66 void onPagePerLayerClicked( wxCommandEvent& event ) override;
67 void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) override;
68 void ExportSVGFile( bool aOnlyOneFile );
69
71};
72
73
74/* DIALOG_EXPORT_SVG functions
75*/
77 DIALOG_EXPORT_SVG_BASE( aParent ),
78 m_board( aBoard ),
79 m_parent( aParent ),
80 m_printBW( false ),
81 m_printMirror( false ),
82 m_oneFileOnly( false )
83{
84 m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
85
86 m_messagesPanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
87
88 initDialog();
89
90 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
91 { wxID_CANCEL, _( "Close" ) } } );
92
94 m_cbUsedBoardTheme->SetValue( !cfg->m_ExportSvg.use_selected_theme );
95
96 // Build color theme list, and select the previoulsy selected theme
97 wxString theme_old_selection = cfg->m_ExportSvg.color_theme;
98
100 {
101 int pos = m_colorTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
102
103 if( settings->GetName() == theme_old_selection )
104 m_colorTheme->SetSelection( pos );
105 }
106
108}
109
110
112{
113 m_printBW = m_ModeColorOption->GetSelection();
116 m_outputDirectory.Replace( wxT( "\\" ), wxT( "/" ) );
117
119
120 auto cfg = m_parent->GetPcbNewSettings();
121
123 cfg->m_ExportSvg.mirror = m_printMirror;
124 cfg->m_ExportSvg.one_file = m_oneFileOnly;
125 cfg->m_ExportSvg.page_size = m_rbSvgPageSizeOpt->GetSelection();
126 cfg->m_ExportSvg.output_dir = m_outputDirectory.ToStdString();
127
128 cfg->m_ExportSvg.use_selected_theme = !m_cbUsedBoardTheme->GetValue();
129 cfg->m_ExportSvg.color_theme = m_colorTheme->GetStringSelection();
130
131 if( m_checkboxPagePerLayer->GetValue() )
132 {
133 m_oneFileOnly = false;
134 cfg->m_ExportSvg.plot_board_edges = m_checkboxEdgesOnAllPages->GetValue();
135 }
136 else
137 {
138 m_oneFileOnly = true;
139 }
140
141 cfg->m_ExportSvg.layers.clear();
142
143 for( unsigned layer = 0; layer < arrayDim( m_boxSelectLayer ); ++layer )
144 {
145 if( !m_boxSelectLayer[layer].first )
146 continue;
147
148 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
149 cfg->m_ExportSvg.layers.push_back( layer );
150 }
151}
152
153
155{
156 PROJECT_FILE& projectFile = m_parent->Prj().GetProjectFile();
158
162
163 if( !projectFile.m_PcbLastPath[ LAST_PATH_SVG ].IsEmpty() )
165 else
167
168 m_rbSvgPageSizeOpt->SetSelection( cfg->m_ExportSvg.page_size );
170
171 wxCommandEvent dummy;
173
175
176 m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
177 m_printMirrorOpt->SetValue( m_printMirror );
178
179 for( LSEQ seq = m_board->GetEnabledLayers().UIOrder(); seq; ++seq )
180 {
181 PCB_LAYER_ID layer = *seq;
182 int checkIndex;
183
184 if( IsCopperLayer( layer ) )
185 {
186 checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
187 m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
188 }
189 else
190 {
191 checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
192 m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
193 }
194
195 if( alg::contains( cfg->m_ExportSvg.layers, layer ) )
196 m_boxSelectLayer[layer].first->Check( checkIndex, true );
197 }
198}
199
200
202{
203 LSET ret;
204
205 for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
206 {
207 if( !m_boxSelectLayer[layer].first )
208 continue;
209
210 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
211 ret.set( layer );
212 }
213
214 return ret;
215}
216
217
219{
220 // Build the absolute path of current output directory to preselect it in the file browser.
221 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
222 path = Prj().AbsolutePath( path );
223
224 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
225
226 if( dirDialog.ShowModal() == wxID_CANCEL )
227 return;
228
229 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
230
231 wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
232 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
233
234 if( dialog.ShowModal() == wxID_YES )
235 {
236 wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
237
238 boardFilePath = wxPathOnly( boardFilePath );
239
240 if( !dirName.MakeRelativeTo( boardFilePath ) )
241 wxMessageBox( _( "Cannot make path relative (target volume different from board "
242 "file volume)!" ),
243 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
244 }
245
246 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
248}
249
250
251void DIALOG_EXPORT_SVG::onPagePerLayerClicked( wxCommandEvent& event )
252{
254
255 if( m_checkboxPagePerLayer->GetValue() )
256 {
257 m_checkboxEdgesOnAllPages->Enable( true );
259 }
260 else
261 {
262 m_checkboxEdgesOnAllPages->Enable( false );
263 m_checkboxEdgesOnAllPages->SetValue( false );
264 }
265}
266
267
268void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
269{
271
272 // Create output directory if it does not exist (also transform it in absolute form).
273 // Bail if it fails.
274
275 std::function<bool( wxString* )> textResolver =
276 [&]( wxString* token ) -> bool
277 {
278 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
279 return m_board->ResolveTextVar( token, 0 );
280 };
281
282 wxString path = m_outputDirectory;
283 path = ExpandTextVars( path, &textResolver );
284 path = ExpandEnvVarSubstitutions( path, nullptr );
285
286 wxFileName outputDir = wxFileName::DirName( path );
287 wxString boardFilename = m_board->GetFileName();
288
289 REPORTER& reporter = m_messagesPanel->Reporter();
290
291 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
292 {
293 wxString msg = wxString::Format( _( "Could not write plot files to folder '%s'." ),
294 outputDir.GetPath() );
295 DisplayError( this, msg );
296 return;
297 }
298
299 m_printMirror = m_printMirrorOpt->GetValue();
300 m_printBW = m_ModeColorOption->GetSelection();
301
302 LSET all_selected = getCheckBoxSelectedLayers();
303
304 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
305 svgPlotOptions.m_blackAndWhite = m_printBW;
306 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
307 svgPlotOptions.m_pageSizeMode = m_rbSvgPageSizeOpt->GetSelection();
308
310 wxString export_theme = m_cbUsedBoardTheme->GetValue()
311 ? cfg->m_ColorTheme
312 : m_colorTheme->GetStringSelection();
313
314 svgPlotOptions.m_colorTheme = export_theme;
315
316 svgPlotOptions.m_mirror = m_printMirror;
317 svgPlotOptions.m_plotFrame = svgPlotOptions.m_pageSizeMode == 0;
318 svgPlotOptions.m_drillShapeOption = 2; // actual size hole.
319
320 for( LSEQ seq = all_selected.Seq(); seq; ++seq )
321 {
322 PCB_LAYER_ID layer = *seq;
323 wxFileName fn( boardFilename );
324 wxString suffix = aOnlyOneFile ? wxString( wxT( "brd" ) ) : m_board->GetStandardLayerName( layer );
325
326 BuildPlotFileName( &fn, outputDir.GetPath(), suffix, SVGFileExtension );
327 wxString svgPath = fn.GetFullPath();
328
329 m_printMaskLayer = aOnlyOneFile ? all_selected : LSET( layer );
330
331 if( m_checkboxEdgesOnAllPages->GetValue() )
333
334 svgPlotOptions.m_outputFile = svgPath;
335 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
336
337 if( EXPORT_SVG::Plot(m_board, svgPlotOptions ) )
338 {
339 reporter.Report( wxString::Format( _( "Exported '%s'." ), svgPath ),
341 }
342 else // Error
343 {
344 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), svgPath ),
346 }
347
348 if( aOnlyOneFile )
349 break;
350 }
351}
352
353
354void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
355{
358}
359
360
361bool InvokeExportSVG( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
362{
363 DIALOG_EXPORT_SVG dlg( aCaller, aBoard );
364
365 dlg.ShowModal();
366
367 return true;
368}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:106
wxString m_ColorTheme
Active color theme name.
Definition: app_settings.h:172
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:271
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:614
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition: board.h:734
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:376
const wxString & GetFileName() const
Definition: board.h:308
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:501
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:513
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:552
LSEQ UIOrder() const
Definition: lset.cpp:922
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:411
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:69
wxString m_PcbLastPath[LAST_PATH_SIZE]
MRU path storage.
Definition: project_file.h:156
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:328
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:317
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:345
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:280
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)
const std::string SVGFileExtension
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:847
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Edge_Cuts
Definition: layer_ids.h:114
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:138
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
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.