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>
34#include <dialog_export_svg.h>
35#include <bitmaps.h>
39#include <wx/dirdlg.h>
40#include <wx/msgdlg.h>
41#include <pgm_base.h>
45
46
47DIALOG_EXPORT_SVG::DIALOG_EXPORT_SVG( PCB_EDIT_FRAME* aEditFrame, BOARD* aBoard, wxWindow* aParent ) :
48 DIALOG_EXPORT_SVG_BASE( aParent ),
49 m_board( aBoard ),
50 m_editFrame( aEditFrame ),
51 m_printBW( false ),
52 m_printMirror( false ),
53 m_oneFileOnly( false )
54{
55 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
56
57 m_messagesPanel->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
58
59 initDialog();
60
61 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
62 { wxID_CANCEL, _( "Close" ) } } );
63
65 m_cbUsedBoardTheme->SetValue( !cfg->m_ExportSvg.use_selected_theme );
66
67 // Build color theme list, and select the previoulsy selected theme
68 wxString theme_old_selection = cfg->m_ExportSvg.color_theme;
69
71 {
72 int pos = m_colorTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
73
74 if( settings->GetName() == theme_old_selection )
75 m_colorTheme->SetSelection( pos );
76 }
77
79}
80
81
83 wxWindow* aParent ) :
84 DIALOG_EXPORT_SVG( aEditFrame, aEditFrame->GetBoard(), aParent )
85{
86 m_job = aJob;
87
88 SetupStandardButtons( { { wxID_OK, _( "Save" ) },
89 { wxID_CANCEL, _( "Close" ) } } );
90}
91
92
94{
95 m_printBW = m_ModeColorOption->GetSelection();
98 m_outputDirectory.Replace( wxT( "\\" ), wxT( "/" ) );
99
101
102 PCBNEW_SETTINGS* cfg = nullptr;
103
104 try
105 {
107 }
108 catch( const std::runtime_error& e )
109 {
110 wxFAIL_MSG( e.what() );
111 }
112
113 if( cfg )
114 {
118 cfg->m_ExportSvg.page_size = m_rbSvgPageSizeOpt->GetSelection();
119 cfg->m_ExportSvg.output_dir = m_outputDirectory.ToStdString();
121 cfg->m_ExportSvg.color_theme = m_colorTheme->GetStringSelection();
122 }
123
124 if( m_checkboxPagePerLayer->GetValue() )
125 {
126 m_oneFileOnly = false;
127
128 if( cfg )
130 }
131 else
132 {
133 m_oneFileOnly = true;
134 }
135
136 if( cfg )
137 cfg->m_ExportSvg.layers.clear();
138
139 for( unsigned layer = 0; layer < arrayDim( m_boxSelectLayer ); ++layer )
140 {
141 if( !m_boxSelectLayer[layer].first )
142 continue;
143
144 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
145 {
146 if( cfg )
147 cfg->m_ExportSvg.layers.push_back( layer );
148 }
149 }
150}
151
152
154{
155 PROJECT_FILE& projectFile = m_editFrame->Prj().GetProjectFile();
157
161
162 if( !projectFile.m_PcbLastPath[ LAST_PATH_SVG ].IsEmpty() )
164 else
166
167 m_rbSvgPageSizeOpt->SetSelection( cfg->m_ExportSvg.page_size );
169
170 wxCommandEvent dummy;
172
174
175 m_ModeColorOption->SetSelection( m_printBW ? 1 : 0 );
176 m_printMirrorOpt->SetValue( m_printMirror );
177
178 for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().UIOrder() )
179 {
180 int checkIndex;
181
182 if( IsCopperLayer( layer ) )
183 {
184 checkIndex = m_CopperLayersList->Append( m_board->GetLayerName( layer ) );
185 m_boxSelectLayer[layer] = std::make_pair( m_CopperLayersList, checkIndex );
186 }
187 else
188 {
189 checkIndex = m_TechnicalLayersList->Append( m_board->GetLayerName( layer ) );
190 m_boxSelectLayer[layer] = std::make_pair( m_TechnicalLayersList, checkIndex );
191 }
192
193 if( alg::contains( cfg->m_ExportSvg.layers, layer ) )
194 m_boxSelectLayer[layer].first->Check( checkIndex, true );
195 }
196}
197
198
200{
201 LSET ret;
202
203 for( unsigned layer = 0; layer < arrayDim(m_boxSelectLayer); ++layer )
204 {
205 if( !m_boxSelectLayer[layer].first )
206 continue;
207
208 if( m_boxSelectLayer[layer].first->IsChecked( m_boxSelectLayer[layer].second ) )
209 ret.set( layer );
210 }
211
212 return ret;
213}
214
215
217{
218 // Build the absolute path of current output directory to preselect it in the file browser.
219 wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
220 path = Prj().AbsolutePath( path );
221
222 wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
223
224 if( dirDialog.ShowModal() == wxID_CANCEL )
225 return;
226
227 wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
228
229 wxMessageDialog dialog( this, _( "Use a relative path?" ), _( "Plot Output Directory" ),
230 wxYES_NO | wxICON_QUESTION | wxYES_DEFAULT );
231
232 if( dialog.ShowModal() == wxID_YES )
233 {
234 wxString boardFilePath = Prj().AbsolutePath( m_board->GetFileName() );
235
236 boardFilePath = wxPathOnly( boardFilePath );
237
238 if( !dirName.MakeRelativeTo( boardFilePath ) )
239 wxMessageBox( _( "Cannot make path relative (target volume different from board "
240 "file volume)!" ),
241 _( "Plot Output Directory" ), wxOK | wxICON_ERROR );
242 }
243
244 m_outputDirectoryName->SetValue( dirName.GetFullPath() );
246}
247
248
249void DIALOG_EXPORT_SVG::onPagePerLayerClicked( wxCommandEvent& event )
250{
252
253 if( m_checkboxPagePerLayer->GetValue() )
254 {
255 m_checkboxEdgesOnAllPages->Enable( true );
257 }
258 else
259 {
260 m_checkboxEdgesOnAllPages->Enable( false );
261 m_checkboxEdgesOnAllPages->SetValue( false );
262 }
263}
264
265
266void DIALOG_EXPORT_SVG::ExportSVGFile( bool aOnlyOneFile )
267{
269
270 // Create output directory if it does not exist (also transform it in absolute form).
271 // Bail if it fails.
272
273 std::function<bool( wxString* )> textResolver =
274 [&]( wxString* token ) -> bool
275 {
276 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
277 return m_board->ResolveTextVar( token, 0 );
278 };
279
280 wxString path = m_outputDirectory;
281 path = ExpandTextVars( path, &textResolver );
282 path = ExpandEnvVarSubstitutions( path, nullptr );
283
284 wxFileName outputDir = wxFileName::DirName( path );
285 wxString boardFilename = m_board->GetFileName();
286
287 REPORTER& reporter = m_messagesPanel->Reporter();
288
289 if( !EnsureFileDirectoryExists( &outputDir, boardFilename, &reporter ) )
290 {
291 wxString msg = wxString::Format( _( "Could not write plot files to folder '%s'." ),
292 outputDir.GetPath() );
293 DisplayError( this, msg );
294 return;
295 }
296
297 m_printMirror = m_printMirrorOpt->GetValue();
298 m_printBW = m_ModeColorOption->GetSelection();
299
300 LSET all_selected = getCheckBoxSelectedLayers();
301
302 PCB_PLOT_SVG_OPTIONS svgPlotOptions;
303 svgPlotOptions.m_negative = false;
304 svgPlotOptions.m_blackAndWhite = m_printBW;
305 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
306 svgPlotOptions.m_sketchPadsOnFabLayers = false;
307 svgPlotOptions.m_hideDNPFPsOnFabLayers = false;
308 svgPlotOptions.m_sketchDNPFPsOnFabLayers = true;
309 svgPlotOptions.m_crossoutDNPFPsOnFabLayers = true;
310 svgPlotOptions.m_pageSizeMode = m_rbSvgPageSizeOpt->GetSelection();
311
313 wxString export_theme = m_cbUsedBoardTheme->GetValue()
314 ? cfg->m_ColorTheme
315 : m_colorTheme->GetStringSelection();
316
317 svgPlotOptions.m_colorTheme = export_theme;
318
319 svgPlotOptions.m_mirror = m_printMirror;
320 svgPlotOptions.m_plotFrame = svgPlotOptions.m_pageSizeMode == 0;
321 svgPlotOptions.m_drillShapeOption = 2; // actual size hole.
322
323 for( PCB_LAYER_ID layer : all_selected.Seq() )
324 {
325 wxFileName fn( boardFilename );
326 wxString suffix = aOnlyOneFile ? wxString( wxT( "brd" ) ) : m_board->GetStandardLayerName( layer );
327
328 BuildPlotFileName( &fn, outputDir.GetPath(), suffix, FILEEXT::SVGFileExtension );
329 wxString svgPath = fn.GetFullPath();
330
331 m_printMaskLayer = aOnlyOneFile ? all_selected.SeqStackupForPlotting() : LSEQ( { layer } );
332
333 if( m_checkboxEdgesOnAllPages->GetValue() )
334 m_printMaskLayer.push_back( Edge_Cuts );
335
336 svgPlotOptions.m_outputFile = svgPath;
337 svgPlotOptions.m_printMaskLayer = m_printMaskLayer;
338
339 if( EXPORT_SVG::Plot(m_board, svgPlotOptions ) )
340 {
341 reporter.Report( wxString::Format( _( "Exported '%s'." ), svgPath ),
343 }
344 else // Error
345 {
346 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), svgPath ),
348 }
349
350 if( aOnlyOneFile )
351 break;
352 }
353}
354
355
356void DIALOG_EXPORT_SVG::OnButtonPlot( wxCommandEvent& event )
357{
360}
361
362
363bool InvokeExportSVG( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
364{
365 DIALOG_EXPORT_SVG dlg( aCaller, aBoard, aCaller );
366
367 dlg.ShowModal();
368
369 return true;
370}
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:189
BASE_SET & set(size_t pos)
Definition: base_set.h:115
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:775
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition: board.h:786
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:433
const wxString & GetFileName() const
Definition: board.h:327
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:579
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() override
PCB_EDIT_FRAME * m_editFrame
void OnOutputDirectoryBrowseClicked(wxCommandEvent &event) override
JOB_EXPORT_PCB_SVG * m_job
void OnButtonPlot(wxCommandEvent &event) override
DIALOG_EXPORT_SVG(JOB_EXPORT_PCB_SVG *aJob, PCB_EDIT_FRAME *aEditFrame, wxWindow *aParent)
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...
int ShowModal() override
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:36
LSEQ UIOrder() const
Returns the copper, technical and user layers in the order shown in layer widget.
Definition: lset.cpp:799
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:500
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
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:72
wxString m_PcbLastPath[LAST_PATH_SIZE]
MRU path storage.
Definition: project_file.h:162
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:200
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:359
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
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:348
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:369
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:112
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
BOARD * GetBoard()
void BuildPlotFileName(wxFileName *aFilename, const wxString &aOutputDir, const wxString &aSuffix, const wxString &aExtension)
Complete a plot filename.
Definition: pcbplot.cpp:379
see class PGM_BASE
Plotting engines similar to ps (PostScript, Gerber, svg)
@ LAST_PATH_SVG
Definition: project_file.h:57
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
bool m_sketchPadsOnFabLayers
Definition: export_svg.h:37
bool m_sketchDNPFPsOnFabLayers
Definition: export_svg.h:39
wxString m_colorTheme
Definition: export_svg.h:27
wxString m_outputFile
Definition: export_svg.h:26
bool m_crossoutDNPFPsOnFabLayers
Definition: export_svg.h:40
bool m_hideDNPFPsOnFabLayers
Definition: export_svg.h:38
Definition of file extensions used in Kicad.