KiCad PCB EDA Suite
dialog_import_gfx.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 (C) 1992-2019 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 #include <html_messagebox.h>
26 
27 #include "dialog_import_gfx.h"
28 #include <kiface_i.h>
29 #include <pcb_layer_box_selector.h>
31 #include <class_board.h>
32 #include <class_edge_mod.h>
33 #include <class_text_mod.h>
34 
35 #include <memory>
36 
37 // Static members of DIALOG_IMPORT_GFX, to remember the user's choices during the session
41 double DIALOG_IMPORT_GFX::m_scaleImport = 1.0; // Do not change the imported items size
42 int DIALOG_IMPORT_GFX::m_originUnits = 0; // millimeter
43 int DIALOG_IMPORT_GFX::m_lineWidthUnits = 0; // millimeter
44 
45 
46 DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX( PCB_BASE_FRAME* aParent, bool aImportAsFootprintGraphic )
47  : DIALOG_IMPORT_GFX_BASE( aParent )
48 {
49  m_parent = aParent;
50 
51  if( aImportAsFootprintGraphic )
52  m_importer = std::make_unique<GRAPHICS_IMPORTER_MODULE>( m_parent->GetBoard()->GetFirstModule() );
53  else
54  m_importer = std::make_unique<GRAPHICS_IMPORTER_BOARD>( m_parent->GetBoard() );
55 
56  // construct an import manager with options from config
57  {
59  // Currently: all types are allowed, so the blacklist is empty
60  // (no GFX_FILE_T in the blacklist)
61  // To disable SVG import, enable these 2 lines
62  // if( !ADVANCED_CFG::GetCfg().m_enableSvgImport )
63  // blacklist.push_back( GRAPHICS_IMPORT_MGR::SVG );
64  // The SVG import has currently a flaw: all SVG shapes are imported as curves and
65  // converted to a lot of segments. A better approach is to convert to polylines
66  // (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
67  // possible with tinysvg library).
68 
69  m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>( blacklist );
70  }
71 
72  m_originUnits = 0;
73  m_origin.x = 0.0; // always in mm
74  m_origin.y = 0.0; // always in mm
75  m_lineWidth = 0.2; // always in mm
76  m_lineWidthUnits = 0;
77 
78  auto cfg = m_parent->GetSettings();
79 
80  m_layer = cfg->m_ImportGraphics.layer;
81  m_placementInteractive = cfg->m_ImportGraphics.interactive_placement;
82  m_filename = cfg->m_ImportGraphics.last_file;
83  m_lineWidth = cfg->m_ImportGraphics.line_width;
84  m_lineWidthUnits = cfg->m_ImportGraphics.line_width_units;
85  m_originUnits = cfg->m_ImportGraphics.origin_units;
86  m_origin.x = cfg->m_ImportGraphics.origin_x;
87  m_origin.y = cfg->m_ImportGraphics.origin_y;
88 
89  m_choiceUnitLineWidth->SetSelection( m_lineWidthUnits );
91 
92  m_DxfPcbPositionUnits->SetSelection( m_originUnits );
94 
95  m_textCtrlFileName->SetValue( m_filename );
98 
100 
101  // Configure the layers list selector
102  m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
103  m_SelLayerBox->SetNotAllowedLayerSet( LSET::AllCuMask() ); // Do not use copper layers
106 
108  {
109  m_layer = Dwgs_User;
111  }
112 
114  m_sdbSizerOK->SetDefault();
115  GetSizer()->Fit( this );
116  GetSizer()->SetSizeHints( this );
117  Centre();
118 }
119 
120 
122 {
123  auto cfg = m_parent->GetSettings();
124 
126  cfg->m_ImportGraphics.interactive_placement = m_placementInteractive;
127  cfg->m_ImportGraphics.last_file = m_filename;
128  cfg->m_ImportGraphics.line_width = m_lineWidth;
129  cfg->m_ImportGraphics.line_width_units = m_lineWidthUnits;
130  cfg->m_ImportGraphics.origin_units = m_originUnits;
131  cfg->m_ImportGraphics.origin_x = m_origin.x;
132  cfg->m_ImportGraphics.origin_y = m_origin.y;
133 }
134 
135 
136 void DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX::onUnitPositionSelection( wxCommandEvent& event )
137 {
138  // Collect last entered values:
139  updatePcbImportOffsets_mm();
140 
141  m_originUnits = m_DxfPcbPositionUnits->GetSelection();;
142  showPcbImportOffsets();
143 }
144 
145 
147 {
148  double value = DoubleValueFromString( EDA_UNITS::UNSCALED, m_textCtrlLineWidth->GetValue() );
149 
150  switch( m_lineWidthUnits )
151  {
152  default:
153  case 0: break; // display units = mm
154  case 1: value *= 25.4 / 1000; break; // display units = mil
155  case 2: value *= 25.4; break; // display units = inch
156  }
157 
158  return value; // value is in mm
159 }
160 
161 
162 void DIALOG_IMPORT_GFX::onUnitWidthSelection( wxCommandEvent& event )
163 {
165 
166  // Switch to new units
167  m_lineWidthUnits = m_choiceUnitLineWidth->GetSelection();
169 }
170 
171 
173 {
174  // Display m_origin value according to the unit selection:
175  VECTOR2D offset = m_origin;
176 
177  if( m_originUnits ) // Units are inches
178  offset = m_origin / 25.4;
179 
180  m_DxfPcbXCoord->SetValue( wxString::Format( "%f", offset.x ) );
181  m_DxfPcbYCoord->SetValue( wxString::Format( "%f", offset.y ) );
182 
183 }
184 
185 
187 {
188  double value;
189 
190  switch( m_lineWidthUnits )
191  {
192  default:
193  case 0: value = m_lineWidth; break; // display units = mm
194  case 1: value = m_lineWidth / 25.4 * 1000; break; // display units = mil
195  case 2: value = m_lineWidth / 25.4; break; // display units = inch
196  }
197 
198  m_textCtrlLineWidth->SetValue( wxString::Format( "%f", value ) );
199 }
200 
201 
202 void DIALOG_IMPORT_GFX::onBrowseFiles( wxCommandEvent& event )
203 {
204  wxString path;
205  wxString filename;
206 
207  if( !m_filename.IsEmpty() )
208  {
209  wxFileName fn( m_filename );
210  path = fn.GetPath();
211  filename = fn.GetFullName();
212  }
213 
214  // Generate the list of handled file formats
215  wxString wildcardsDesc;
216  wxString allWildcards;
217 
218  for( auto pluginType : m_gfxImportMgr->GetImportableFileTypes() )
219  {
220  auto plugin = m_gfxImportMgr->GetPlugin( pluginType );
221  const auto extensions = plugin->GetFileExtensions();
222 
223  wildcardsDesc += "|" + plugin->GetName() + AddFileExtListToFilter( extensions );
224  allWildcards += plugin->GetWildcards() + ";";
225  }
226 
227  wildcardsDesc = _( "All supported formats|" ) + allWildcards + wildcardsDesc;
228 
229  wxFileDialog dlg( m_parent, _( "Open File" ), path, filename, wildcardsDesc,
230  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
231 
232  if( dlg.ShowModal() != wxID_OK )
233  return;
234 
235  wxString fileName = dlg.GetPath();
236 
237  if( fileName.IsEmpty() )
238  return;
239 
240  m_filename = fileName;
241  m_textCtrlFileName->SetValue( fileName );
242 }
243 
244 
246 {
247  if( !wxDialog::TransferDataFromWindow() )
248  return false;
249 
250  m_filename = m_textCtrlFileName->GetValue();
251 
252  if( m_filename.IsEmpty() )
253  {
254  wxMessageBox( _( "No file selected!" ) );
255  return false;
256  }
257 
258  m_originUnits = m_DxfPcbPositionUnits->GetSelection();
259  updatePcbImportOffsets_mm(); // Update m_originX and m_originY;
260 
262 
263  if( m_layer < 0 )
264  {
265  wxMessageBox( _( "Please select a valid layer." ) );
266  return false;
267  }
268 
269  m_lineWidthUnits = m_choiceUnitLineWidth->GetSelection();
271 
272  m_importer->SetLayer( PCB_LAYER_ID( m_layer ) );
273 
274  auto plugin = m_gfxImportMgr->GetPluginByExt( wxFileName( m_filename ).GetExt() );
275 
276  if( plugin )
277  {
278  // Set coordinates offset for import (offset is given in mm)
279  m_importer->SetImportOffsetMM( m_origin );
280  m_scaleImport =
282 
283  // The line width is meant to be in pcbnew units, so we scale the import width before
284  // applying
285  m_importer->SetLineWidthMM( m_lineWidth * m_scaleImport );
286  m_importer->SetPlugin( std::move( plugin ) );
287 
288  LOCALE_IO dummy; // Ensure floats can be read.
289 
290  if( m_importer->Load( m_filename ) )
291  m_importer->Import( m_scaleImport );
292 
293  // Get warning messages:
294  wxString warnings = m_importer->GetMessages();
295 
296  // This isn't a fatal error so allow the dialog to close with wxID_OK.
297  if( !warnings.empty() )
298  {
299  HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
300  dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
301  warnings.Replace( "\n", "<br/>" );
302  dlg.AddHTML_Text( warnings );
303  dlg.ShowModal();
304  }
305  }
306  else
307  {
308  wxMessageBox( _( "There is no plugin to handle this file type." ) );
309  return false;
310  }
311 
312  return true;
313 }
314 
315 
316 void DIALOG_IMPORT_GFX::originOptionOnUpdateUI( wxUpdateUIEvent& event )
317 {
320 
321  if( m_rbAbsolutePlacement->GetValue() == m_placementInteractive )
323 
325  m_DxfPcbXCoord->Enable( not m_placementInteractive );
326  m_DxfPcbYCoord->Enable( not m_placementInteractive );
327 }
328 
329 
331 {
334 
335  if( m_originUnits ) // Units are inches
336  m_origin = m_origin * 25.4;
337 }
338 
339 
std::unique_ptr< GRAPHICS_IMPORT_MGR > m_gfxImportMgr
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:686
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:202
void SetNotAllowedLayerSet(LSET aMask)
void originOptionOnUpdateUI(wxUpdateUIEvent &event) override
bool TransferDataFromWindow() override
Class DIALOG_IMPORT_GFX_BASE.
DIALOG_IMPORT_GFX(PCB_BASE_FRAME *aParent, bool aUseModuleItems=false)
void onBrowseFiles(wxCommandEvent &event) override
void onUnitWidthSelection(wxCommandEvent &event) override
wxRadioButton * m_rbInteractivePlacement
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:115
LAYER_NUM GetLayerSelection() const
PCB_LAYER_ID
A quick note on layer IDs:
Footprint text class description.
PCB_LAYER_BOX_SELECTOR * m_SelLayerBox
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
static int m_lineWidthUnits
static int m_originUnits
PCB_BASE_FRAME * m_parent
MODULE * GetFirstModule() const
Gets the first module in the list (used in footprint viewer/editor) or NULL if none.
Definition: class_board.h:283
Definition of file extensions used in Kicad.
int SetLayerSelection(LAYER_NUM layer)
HTML_MESSAGE_BOX.
bool SetLayersHotkeys(bool value)
std::vector< GFX_FILE_T > TYPE_LIST
void MessageSet(const wxString &message)
Add a message (in bold) to message list.
static LAYER_NUM m_layer
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
static wxString m_filename
static double m_scaleImport
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
#define _(s)
Definition: 3d_actions.cpp:33
wxRadioButton * m_rbAbsolutePlacement
void AddHTML_Text(const wxString &message)
Add HTML text (without any change) to message list.
static bool m_placementInteractive
DIALOG_IMPORT_GRAPHICS m_ImportGraphics
BOARD * GetBoard() const
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:331
EDGE_MODULE class definition.
std::unique_ptr< GRAPHICS_IMPORTER_PCBNEW > m_importer
PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
PCBNEW_SETTINGS * GetSettings()