KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_import_graphics.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The 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
26
28#include <dialog_map_layers.h>
30#include <base_units.h>
31#include <board.h>
32#include <kiface_base.h>
33#include <locale_io.h>
36#include <bitmaps.h>
38#include <map>
39#include <footprint.h>
40#include <wx/filedlg.h>
41#include <wx/msgdlg.h>
42#include <kiplatform/ui.h>
43
44#include <memory>
45
46
47const std::map<DXF_IMPORT_UNITS, wxString> dxfUnitsMap = {
48 { DXF_IMPORT_UNITS::INCH, _( "Inches" ) },
49 { DXF_IMPORT_UNITS::MM, _( "Millimeters" ) },
50 { DXF_IMPORT_UNITS::MILS, _( "Mils" ) },
51 { DXF_IMPORT_UNITS::CM, _( "Centimeter" ) },
52 { DXF_IMPORT_UNITS::FEET, _( "Feet" ) },
53};
54
55
56static PCB_LAYER_ID getAutoMappedLayer( const wxString& aSourceLayer, const LSET& aPermittedLayers )
57{
58 for( PCB_LAYER_ID layer : aPermittedLayers.UIOrder() )
59 {
60 if( aSourceLayer == LayerName( layer ) || aSourceLayer == LSET::Name( layer ) )
61 return layer;
62 }
63
65}
66
67
68static std::vector<INPUT_LAYER_DESC> buildDxfLayerDescriptions( const std::vector<wxString>& aSourceLayers,
69 const LSET& aPermittedLayers )
70{
71 std::vector<INPUT_LAYER_DESC> layerDescriptions;
72
73 for( const wxString& sourceLayer : aSourceLayers )
74 {
76 desc.Name = sourceLayer;
77 desc.PermittedLayers = aPermittedLayers;
78 desc.AutoMapLayer = getAutoMappedLayer( sourceLayer, aPermittedLayers );
79 desc.Required = false;
80
81 layerDescriptions.push_back( desc );
82 }
83
84 return layerDescriptions;
85}
86
87
89{
90 if( aFrame && aFrame->GetBoard() )
91 return aFrame->GetBoard()->GetEnabledLayers();
92
93 return LSET::AllLayersMask();
94}
95
96
99 m_parent( aParent ),
100 m_xOrigin( aParent, nullptr, m_xCtrl, nullptr ),
101 m_yOrigin( aParent, m_yLabel, m_yCtrl, m_yUnits ),
104{
105 // The SVG import has currently a flaw: all SVG shapes are imported as curves and
106 // converted to a lot of segments. A better approach is to convert to polylines
107 // (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
108 // possible with tinysvg library).
109
110 m_importer = std::make_unique<GRAPHICS_IMPORTER_PCBNEW>( aParent->GetModel() );
111 m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>();
112
113 // Configure the layers list selector
114 m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
115 m_SelLayerBox->SetBoardFrame( m_parent );
116 m_SelLayerBox->Resync();
117
118 for( const std::pair<const DXF_IMPORT_UNITS, wxString>& unitEntry : dxfUnitsMap )
119 m_dxfUnitsChoice->Append( unitEntry.second );
120
122
123 wxCommandEvent dummy;
124 onFilename( dummy );
125
128
129 GetSizer()->Fit( this );
130 GetSizer()->SetSizeHints( this );
131 Centre();
132
133 m_textCtrlFileName->Connect( wxEVT_COMMAND_TEXT_UPDATED,
134 wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
135 nullptr, this );
136}
137
138
140{
141 m_textCtrlFileName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
142 wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
143 nullptr, this );
144}
145
146
147void DIALOG_IMPORT_GRAPHICS::SetFilenameOverride( const wxString& aFilenameOverride )
148{
149 m_filenameOverride = aFilenameOverride;
150}
151
152
154{
155 DIALOG_SHIM::TransferDataToWindow();
156
157 // We have to set the filename field value here, otherwise it gets overwritten by state loading
158 if( !m_filenameOverride.IsEmpty() )
160
161 return true;
162}
163
164
165void DIALOG_IMPORT_GRAPHICS::onFilename( wxCommandEvent& event )
166{
167 bool enableDXFControls = true;
168 wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
169
170 if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
171 enableDXFControls = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) != nullptr;
172
173 m_defaultLineWidth.Enable( enableDXFControls );
174
175 m_dxfUnitsLabel->Enable( enableDXFControls );
176 m_dxfUnitsChoice->Enable( enableDXFControls );
177
178 m_radioBtnMapLayers->Enable( enableDXFControls );
179
180 if( !enableDXFControls && m_radioBtnMapLayers->GetValue() )
181 m_radioBtnSingleLayer->SetValue( true );
182}
183
184
185void DIALOG_IMPORT_GRAPHICS::onBrowseFiles( wxCommandEvent& event )
186{
187 wxString path;
188 wxString filename = m_textCtrlFileName->GetValue();
189
190 if( !filename.IsEmpty() )
191 {
192 wxFileName fn( filename );
193 path = fn.GetPath();
194 filename = fn.GetFullName();
195 }
196
197 // Generate the list of handled file formats
198 wxString wildcardsDesc;
199 wxString allWildcards;
200
201 for( GRAPHICS_IMPORT_MGR::GFX_FILE_T pluginType : m_gfxImportMgr->GetImportableFileTypes() )
202 {
203 std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPlugin( pluginType );
204 const std::vector<std::string> extensions = plugin->GetFileExtensions();
205
206 wildcardsDesc += wxT( "|" ) + plugin->GetName() + AddFileExtListToFilter( extensions );
207 allWildcards += plugin->GetWildcards() + wxT( ";" );
208 }
209
210 wildcardsDesc = _( "All supported formats" ) + wxT( "|" ) + allWildcards + wildcardsDesc;
211
212 wxFileDialog dlg( m_parent, _( "Import Graphics" ), path, filename, wildcardsDesc,
213 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
214
216
217 if( dlg.ShowModal() == wxID_OK && !dlg.GetPath().IsEmpty() )
218 m_textCtrlFileName->SetValue( dlg.GetPath() );
219}
220
221
223{
224 if( !wxDialog::TransferDataFromWindow() )
225 return false;
226
227 if( m_textCtrlFileName->GetValue().IsEmpty() )
228 {
229 wxMessageBox( _( "Please select a file to import." ) );
230 return false;
231 }
232
233 bool useDxfLayerMapping = m_radioBtnMapLayers->IsEnabled() && m_radioBtnMapLayers->GetValue();
234 bool useSingleLayer = m_radioBtnSingleLayer->GetValue();
235
236 if( useSingleLayer && m_SelLayerBox->GetLayerSelection() < 0 )
237 {
238 wxMessageBox( _( "Please select a valid layer." ) );
239 return false;
240 }
241
242 PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
243 wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
245 double xscale = scale;
246 double yscale = scale;
247
249 xscale *= -1.0;
250
252 yscale *= -1.0;
253
254 VECTOR2D origin( m_xOrigin.GetDoubleValue() / xscale, m_yOrigin.GetDoubleValue() / yscale );
255
256 if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
257 {
258 DXF_IMPORT_PLUGIN* dxfPlugin = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() );
259
260 if( dxfPlugin )
261 {
262 auto it = dxfUnitsMap.begin();
263 std::advance( it, m_dxfUnitsChoice->GetSelection() );
264
265 if( it == dxfUnitsMap.end() )
267 else
268 dxfPlugin->SetUnit( it->first );
269
270 m_importer->SetLineWidthMM( pcbIUScale.IUTomm( m_defaultLineWidth.GetIntValue() ) );
271 }
272 else
273 {
274 m_importer->SetLineWidthMM( 0.0 );
275 }
276
277 m_importer->SetPlugin( std::move( plugin ) );
278 m_importer->ClearLayerMap();
279
280 if( useSingleLayer )
281 m_importer->SetLayer( PCB_LAYER_ID( m_SelLayerBox->GetLayerSelection() ) );
282 else
283 m_importer->SetLayer( m_parent->GetActiveLayer() );
284
285 m_importer->SetImportOffsetMM( origin * pcbIUScale.IUTomm( 1 ) );
286
287 LOCALE_IO dummy; // Ensure floats can be read.
288
289 if( m_importer->Load( m_textCtrlFileName->GetValue() ) )
290 {
291 if( useDxfLayerMapping && dxfPlugin )
292 {
293 std::vector<wxString> sourceLayers = dxfPlugin->GetSourceLayers();
294
295 if( !sourceLayers.empty() )
296 {
297 LSET permittedLayers = getPermittedImportLayers( m_parent );
299 this, buildDxfLayerDescriptions( sourceLayers, permittedLayers ) ) );
300 }
301 }
302
303 m_importer->Import( VECTOR2D( scale, scale ) );
304 }
305
306 // Get warning messages:
307 wxString warnings = m_importer->GetMessages();
308
309 // This isn't a fatal error so allow the dialog to close with wxID_OK.
310 if( !warnings.empty() )
311 {
312 HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
313 dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
314 warnings.Replace( wxT( "\n" ), wxT( "<br/>" ) );
315 dlg.AddHTML_Text( warnings );
316 dlg.ShowModal();
317 }
318
319 return true;
320 }
321 else
322 {
323 wxMessageBox( _( "There is no plugin to handle this file type." ) );
324 return false;
325 }
326}
327
328
329void DIALOG_IMPORT_GRAPHICS::onUpdateUI( wxUpdateUIEvent& event )
330{
331 m_xOrigin.Enable( m_placeAtCheckbox->GetValue() );
332 m_yOrigin.Enable( m_placeAtCheckbox->GetValue() );
333
334 m_tolerance.Enable( m_rbFixDiscontinuities->GetValue() );
335
336 m_SelLayerBox->Enable( m_radioBtnSingleLayer->GetValue() );
337}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:986
DIALOG_IMPORT_GRAPHICS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Import Vector Graphics File"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
std::unique_ptr< GRAPHICS_IMPORT_MGR > m_gfxImportMgr
void onFilename(wxCommandEvent &event)
std::unique_ptr< GRAPHICS_IMPORTER_PCBNEW > m_importer
void onBrowseFiles(wxCommandEvent &event) override
void SetFilenameOverride(const wxString &aFilenameOverride)
Set the filename override to be applied in TransferDataToWindow.
void onUpdateUI(wxUpdateUIEvent &event) override
DIALOG_IMPORT_GRAPHICS(PCB_BASE_FRAME *aParent)
static std::map< wxString, PCB_LAYER_ID > RunModal(wxWindow *aParent, const std::vector< INPUT_LAYER_DESC > &aLayerDesc)
Create and show a dialog (modal) and returns the data from it after completion.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:83
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowModal() override
std::vector< wxString > GetSourceLayers() const
void SetUnit(DXF_IMPORT_UNITS aUnit)
Set the default units when importing DXFs.
GFX_FILE_T
List of handled file types.
void MessageSet(const wxString &message)
Add a message (in bold) to message list.
void AddHTML_Text(const wxString &message)
Add HTML text (without any change) to message list.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:743
static const LSET & AllLayersMask()
Definition lset.cpp:641
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
DISPLAY_OPTIONS m_Display
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
BOARD * GetBoard() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
const std::map< DXF_IMPORT_UNITS, wxString > dxfUnitsMap
static LSET getPermittedImportLayers(PCB_BASE_FRAME *aFrame)
static PCB_LAYER_ID getAutoMappedLayer(const wxString &aSourceLayer, const LSET &aPermittedLayers)
static std::vector< INPUT_LAYER_DESC > buildDxfLayerDescriptions(const std::vector< wxString > &aSourceLayers, const LSET &aPermittedLayers)
#define _(s)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
const int scale
std::vector< FAB_LAYER_COLOR > dummy
Describes an imported layer and how it could be mapped to KiCad Layers.
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
bool Required
Should we require the layer to be assigned?
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
wxString Name
Imported layer name as displayed in original application.
std::string path
VECTOR2< double > VECTOR2D
Definition vector2d.h:686
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
Definition of file extensions used in Kicad.