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, see <https://www.gnu.org/licenses/>.
19 */
20
22
24#include <dialog_map_layers.h>
26#include <base_units.h>
27#include <board.h>
28#include <kiface_base.h>
29#include <locale_io.h>
32#include <bitmaps.h>
34#include <footprint.h>
35#include <wx/filedlg.h>
36#include <wx/msgdlg.h>
37#include <kiplatform/ui.h>
38
39#include <memory>
40
42
43
44static PCB_LAYER_ID getAutoMappedLayer( const wxString& aSourceLayer, const LSET& aPermittedLayers )
45{
46 for( PCB_LAYER_ID layer : aPermittedLayers.UIOrder() )
47 {
48 if( aSourceLayer == LayerName( layer ) || aSourceLayer == LSET::Name( layer ) )
49 return layer;
50 }
51
53}
54
55
56static std::vector<INPUT_LAYER_DESC> buildDxfLayerDescriptions( const std::vector<wxString>& aSourceLayers,
57 const LSET& aPermittedLayers )
58{
59 std::vector<INPUT_LAYER_DESC> layerDescriptions;
60
61 for( const wxString& sourceLayer : aSourceLayers )
62 {
64 desc.Name = sourceLayer;
65 desc.PermittedLayers = aPermittedLayers;
66 desc.AutoMapLayer = getAutoMappedLayer( sourceLayer, aPermittedLayers );
67 desc.Required = false;
68
69 layerDescriptions.push_back( desc );
70 }
71
72 return layerDescriptions;
73}
74
75
77{
78 if( aFrame && aFrame->GetBoard() )
79 return aFrame->GetBoard()->GetEnabledLayers();
80
81 return LSET::AllLayersMask();
82}
83
84
87 m_parent( aParent ),
88 m_xOrigin( aParent, nullptr, m_xCtrl, nullptr ),
89 m_yOrigin( aParent, m_yLabel, m_yCtrl, m_yUnits ),
92{
93 // The SVG import has currently a flaw: all SVG shapes are imported as curves and
94 // converted to a lot of segments. A better approach is to convert to polylines
95 // (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
96 // possible with tinysvg library).
97
98 m_importer = std::make_unique<GRAPHICS_IMPORTER_PCBNEW>( aParent->GetModel() );
99 m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>();
100
101 // Configure the layers list selector
102 m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
103 m_SelLayerBox->SetBoardFrame( m_parent );
104 m_SelLayerBox->Resync();
105
107
109
110 wxCommandEvent dummy;
111 onFilename( dummy );
112
115
116 GetSizer()->Fit( this );
117 GetSizer()->SetSizeHints( this );
118 Centre();
119
120 m_textCtrlFileName->Connect( wxEVT_COMMAND_TEXT_UPDATED,
121 wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
122 nullptr, this );
123}
124
125
127{
128 m_textCtrlFileName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
129 wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
130 nullptr, this );
131}
132
133
134void DIALOG_IMPORT_GRAPHICS::SetFilenameOverride( const wxString& aFilenameOverride )
135{
136 m_filenameOverride = aFilenameOverride;
137}
138
139
141{
142 DIALOG_SHIM::TransferDataToWindow();
143
144 // We have to set the filename field value here, otherwise it gets overwritten by state loading
145 if( !m_filenameOverride.IsEmpty() )
147
148 return true;
149}
150
151
152void DIALOG_IMPORT_GRAPHICS::onFilename( wxCommandEvent& event )
153{
154 bool enableDXFControls = true;
155 wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
156
157 if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
158 enableDXFControls = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) != nullptr;
159
160 m_defaultLineWidth.Enable( enableDXFControls );
161
162 m_dxfUnitsLabel->Enable( enableDXFControls );
163 m_dxfUnitsChoice->Enable( enableDXFControls );
164
165 m_radioBtnMapLayers->Enable( enableDXFControls );
166
167 if( !enableDXFControls && m_radioBtnMapLayers->GetValue() )
168 m_radioBtnSingleLayer->SetValue( true );
169}
170
171
172void DIALOG_IMPORT_GRAPHICS::onBrowseFiles( wxCommandEvent& event )
173{
174 wxString path;
175 wxString filename = m_textCtrlFileName->GetValue();
176
177 if( !filename.IsEmpty() )
178 {
179 wxFileName fn( filename );
180 path = fn.GetPath();
181 filename = fn.GetFullName();
182 }
183
184 // Generate the list of handled file formats
185 wxString wildcardsDesc;
186 wxString allWildcards;
187
188 for( GRAPHICS_IMPORT_MGR::GFX_FILE_T pluginType : m_gfxImportMgr->GetImportableFileTypes() )
189 {
190 std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPlugin( pluginType );
191 const std::vector<std::string> extensions = plugin->GetFileExtensions();
192
193 wildcardsDesc += wxT( "|" ) + plugin->GetName() + AddFileExtListToFilter( extensions );
194 allWildcards += plugin->GetWildcards() + wxT( ";" );
195 }
196
197 wildcardsDesc = _( "All supported formats" ) + wxT( "|" ) + allWildcards + wildcardsDesc;
198
199 wxFileDialog dlg( m_parent, _( "Import Graphics" ), path, filename, wildcardsDesc,
200 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
201
203
204 if( dlg.ShowModal() == wxID_OK && !dlg.GetPath().IsEmpty() )
205 m_textCtrlFileName->SetValue( dlg.GetPath() );
206}
207
208
210{
211 if( !wxDialog::TransferDataFromWindow() )
212 return false;
213
214 if( m_textCtrlFileName->GetValue().IsEmpty() )
215 {
216 wxMessageBox( _( "Please select a file to import." ) );
217 return false;
218 }
219
220 bool useDxfLayerMapping = m_radioBtnMapLayers->IsEnabled() && m_radioBtnMapLayers->GetValue();
221 bool useSingleLayer = m_radioBtnSingleLayer->GetValue();
222
223 if( useSingleLayer && m_SelLayerBox->GetLayerSelection() < 0 )
224 {
225 wxMessageBox( _( "Please select a valid layer." ) );
226 return false;
227 }
228
229 PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
230 wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
232
233 if( scale <= 0.0 )
234 {
235 wxMessageBox( _( "Import scale must be a positive number." ) );
236 return false;
237 }
238
239 double xscale = scale;
240 double yscale = scale;
241
243 xscale *= -1.0;
244
246 yscale *= -1.0;
247
248 VECTOR2D origin( m_xOrigin.GetDoubleValue() / xscale, m_yOrigin.GetDoubleValue() / yscale );
249
250 switch( m_originCtrl->GetSelection() )
251 {
252 case 0: break;
253 case 1: origin += m_parent->GetAuxOrigin(); break; // Drill/place file origin
254 case 2: origin += m_parent->GetGridOrigin(); break;
255 case 3: origin += m_parent->GetUserOrigin(); break;
256 }
257
258 if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
259 {
260 DXF_IMPORT_PLUGIN* dxfPlugin = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() );
261
262 if( dxfPlugin )
263 {
264 dxfPlugin->SetUnit( DxfImportUnitFromChoice( m_dxfUnitsChoice->GetSelection() ) );
265 m_importer->SetLineWidthMM( pcbIUScale.IUTomm( m_defaultLineWidth.GetIntValue() ) );
266 }
267 else
268 {
269 m_importer->SetLineWidthMM( 0.0 );
270 }
271
272 m_importer->SetPlugin( std::move( plugin ) );
273 m_importer->ClearLayerMap();
274
275 if( useSingleLayer )
276 m_importer->SetLayer( PCB_LAYER_ID( m_SelLayerBox->GetLayerSelection() ) );
277 else
278 m_importer->SetLayer( m_parent->GetActiveLayer() );
279
280 m_importer->SetImportOffsetMM( origin * pcbIUScale.IUTomm( 1 ) );
281
282 LOCALE_IO dummy; // Ensure floats can be read.
283
284 if( m_importer->Load( m_textCtrlFileName->GetValue() ) )
285 {
286 if( useDxfLayerMapping && dxfPlugin )
287 {
288 std::vector<wxString> sourceLayers = dxfPlugin->GetSourceLayers();
289
290 if( !sourceLayers.empty() )
291 {
292 LSET permittedLayers = getPermittedImportLayers( m_parent );
294 this, buildDxfLayerDescriptions( sourceLayers, permittedLayers ) ) );
295 }
296 }
297
298 m_importer->Import( VECTOR2D( scale, scale ) );
299 }
300
301 // Get warning messages:
302 wxString warnings = m_importer->GetMessages();
303
304 // This isn't a fatal error so allow the dialog to close with wxID_OK.
305 if( !warnings.empty() )
306 {
307 HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
308 dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
309 warnings.Replace( wxT( "\n" ), wxT( "<br/>" ) );
310 dlg.AddHTML_Text( warnings );
311 dlg.ShowModal();
312 }
313
314 return true;
315 }
316 else
317 {
318 wxMessageBox( _( "There is no plugin to handle this file type." ) );
319 return false;
320 }
321}
322
323
324void DIALOG_IMPORT_GRAPHICS::onUpdateUI( wxUpdateUIEvent& event )
325{
326 m_xOrigin.Enable( m_placeAtCheckbox->GetValue() );
327 m_yOrigin.Enable( m_placeAtCheckbox->GetValue() );
328 m_originLabel->Enable( m_placeAtCheckbox->GetValue() );
329 m_originCtrl->Enable( m_placeAtCheckbox->GetValue() );
330
331 m_tolerance.Enable( m_rbFixDiscontinuities->GetValue() );
332
333 m_SelLayerBox->Enable( m_radioBtnSingleLayer->GetValue() );
334}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1183
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:94
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:37
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:739
static const LSET & AllLayersMask()
Definition lset.cpp:637
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
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
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)
wxArrayString GetDxfImportUnitChoices()
DXF_IMPORT_UNITS DxfImportUnitFromChoice(int aSelection)
#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:56
@ UNDEFINED_LAYER
Definition layer_ids.h:57
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:521
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:682
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.