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 // Configuration path (group) to store entry keys below.
38 #define IMPORT_GFX_GROUP "ImportGraphics"
39 
40 // Entry keys to store setup in config
41 #define IMPORT_GFX_LAYER_OPTION_KEY "BoardLayer"
42 #define IMPORT_GFX_PLACEMENT_INTERACTIVE_KEY "InteractivePlacement"
43 #define IMPORT_GFX_LAST_FILE_KEY "LastFile"
44 #define IMPORT_GFX_POSITION_UNITS_KEY "PositionUnits"
45 #define IMPORT_GFX_POSITION_X_KEY "PositionX"
46 #define IMPORT_GFX_POSITION_Y_KEY "PositionY"
47 #define IMPORT_GFX_LINEWIDTH_UNITS_KEY "LineWidthUnits"
48 #define IMPORT_GFX_LINEWIDTH_KEY "LineWidth"
49 
50 
51 // Static members of DIALOG_IMPORT_GFX, to remember the user's choices during the session
55 double DIALOG_IMPORT_GFX::m_scaleImport = 1.0; // Do not change the imported items size
56 int DIALOG_IMPORT_GFX::m_originUnits = 0; // millimeter
57 int DIALOG_IMPORT_GFX::m_lineWidthUnits = 0; // millimeter
58 
59 
60 DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX( PCB_BASE_FRAME* aParent, bool aImportAsFootprintGraphic )
61  : DIALOG_IMPORT_GFX_BASE( aParent )
62 {
63  m_parent = aParent;
64 
65  if( aImportAsFootprintGraphic )
66  m_importer = std::make_unique<GRAPHICS_IMPORTER_MODULE>( m_parent->GetBoard()->GetFirstModule() );
67  else
68  m_importer = std::make_unique<GRAPHICS_IMPORTER_BOARD>( m_parent->GetBoard() );
69 
70  // construct an import manager with options from config
71  {
73  // Currently: all types are allowed, so the blacklist is empty
74  // (no GFX_FILE_T in the blacklist)
75  // To disable SVG import, enable these 2 lines
76  // if( !ADVANCED_CFG::GetCfg().m_enableSvgImport )
77  // blacklist.push_back( GRAPHICS_IMPORT_MGR::SVG );
78  // The SVG import has currently a flaw: all SVG shapes are imported as curves and
79  // converted to a lot of segments. A better approach is to convert to polylines
80  // (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
81  // possible with tinysvg library).
82 
83  m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>( blacklist );
84  }
85 
87  m_originUnits = 0;
88  m_origin.x = 0.0; // always in mm
89  m_origin.y = 0.0; // always in mm
90  m_lineWidth = 0.2; // always in mm
91  m_lineWidthUnits = 0;
92 
93  if( m_config )
94  {
95  wxString tmp = m_config->GetPath();
96  m_config->SetPath( IMPORT_GFX_GROUP );
99  m_filename = m_config->Read( IMPORT_GFX_LAST_FILE_KEY, wxEmptyString );
105  m_config->SetPath( tmp );
106  }
107 
108  m_choiceUnitLineWidth->SetSelection( m_lineWidthUnits );
110 
111  m_DxfPcbPositionUnits->SetSelection( m_originUnits );
113 
114  m_textCtrlFileName->SetValue( m_filename );
117 
119 
120  // Configure the layers list selector
121  m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
122  m_SelLayerBox->SetNotAllowedLayerSet( LSET::AllCuMask() ); // Do not use copper layers
125 
127  {
128  m_layer = Dwgs_User;
130  }
131 
133  m_sdbSizerOK->SetDefault();
134  GetSizer()->Fit( this );
135  GetSizer()->SetSizeHints( this );
136  Centre();
137 }
138 
139 
141 {
142  if( m_config )
143  {
144  wxString tmp = m_config->GetPath();
145  m_config->SetPath( IMPORT_GFX_GROUP );
149 
153 
156  m_config->SetPath( tmp );
157  }
158 }
159 
160 
161 void DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX::onUnitPositionSelection( wxCommandEvent& event )
162 {
163  // Collect last entered values:
164  updatePcbImportOffsets_mm();
165 
166  m_originUnits = m_DxfPcbPositionUnits->GetSelection();;
167  showPcbImportOffsets();
168 }
169 
170 
172 {
173  double value = DoubleValueFromString( UNSCALED_UNITS, m_textCtrlLineWidth->GetValue() );
174 
175  switch( m_lineWidthUnits )
176  {
177  default:
178  case 0: break; // display units = mm
179  case 1: value *= 25.4 / 1000; break; // display units = mil
180  case 2: value *= 25.4; break; // display units = inch
181  }
182 
183  return value; // value is in mm
184 }
185 
186 
187 void DIALOG_IMPORT_GFX::onUnitWidthSelection( wxCommandEvent& event )
188 {
190 
191  // Switch to new units
192  m_lineWidthUnits = m_choiceUnitLineWidth->GetSelection();
194 }
195 
196 
198 {
199  // Display m_origin value according to the unit selection:
200  VECTOR2D offset = m_origin;
201 
202  if( m_originUnits ) // Units are inches
203  offset = m_origin / 25.4;
204 
205  m_DxfPcbXCoord->SetValue( wxString::Format( "%f", offset.x ) );
206  m_DxfPcbYCoord->SetValue( wxString::Format( "%f", offset.y ) );
207 
208 }
209 
210 
212 {
213  double value;
214 
215  switch( m_lineWidthUnits )
216  {
217  default:
218  case 0: value = m_lineWidth; break; // display units = mm
219  case 1: value = m_lineWidth / 25.4 * 1000; break; // display units = mil
220  case 2: value = m_lineWidth / 25.4; break; // display units = inch
221  }
222 
223  m_textCtrlLineWidth->SetValue( wxString::Format( "%f", value ) );
224 }
225 
226 
227 void DIALOG_IMPORT_GFX::onBrowseFiles( wxCommandEvent& event )
228 {
229  wxString path;
230  wxString filename;
231 
232  if( !m_filename.IsEmpty() )
233  {
234  wxFileName fn( m_filename );
235  path = fn.GetPath();
236  filename = fn.GetFullName();
237  }
238 
239  // Generate the list of handled file formats
240  wxString wildcardsDesc;
241  wxString allWildcards;
242 
243  for( auto pluginType : m_gfxImportMgr->GetImportableFileTypes() )
244  {
245  auto plugin = m_gfxImportMgr->GetPlugin( pluginType );
246  const auto extensions = plugin->GetFileExtensions();
247 
248  wildcardsDesc += "|" + plugin->GetName() + AddFileExtListToFilter( extensions );
249  allWildcards += plugin->GetWildcards() + ";";
250  }
251 
252  wildcardsDesc = _( "All supported formats|" ) + allWildcards + wildcardsDesc;
253 
254  wxFileDialog dlg( m_parent, _( "Open File" ), path, filename, wildcardsDesc,
255  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
256 
257  if( dlg.ShowModal() != wxID_OK )
258  return;
259 
260  wxString fileName = dlg.GetPath();
261 
262  if( fileName.IsEmpty() )
263  return;
264 
265  m_filename = fileName;
266  m_textCtrlFileName->SetValue( fileName );
267 }
268 
269 
271 {
272  if( !wxDialog::TransferDataFromWindow() )
273  return false;
274 
275  m_filename = m_textCtrlFileName->GetValue();
276 
277  if( m_filename.IsEmpty() )
278  {
279  wxMessageBox( _( "No file selected!" ) );
280  return false;
281  }
282 
283  m_originUnits = m_DxfPcbPositionUnits->GetSelection();
284  updatePcbImportOffsets_mm(); // Update m_originX and m_originY;
285 
287 
288  if( m_layer < 0 )
289  {
290  wxMessageBox( _( "Please select a valid layer." ) );
291  return false;
292  }
293 
294  m_lineWidthUnits = m_choiceUnitLineWidth->GetSelection();
296 
297  m_importer->SetLayer( PCB_LAYER_ID( m_layer ) );
298 
299  auto plugin = m_gfxImportMgr->GetPluginByExt( wxFileName( m_filename ).GetExt() );
300 
301  if( plugin )
302  {
303  // Set coordinates offset for import (offset is given in mm)
304  m_importer->SetImportOffsetMM( m_origin );
306 
307  // The line width is meant to be in pcbnew units, so we scale the import width before
308  // applying
309  m_importer->SetLineWidthMM( m_lineWidth * m_scaleImport );
310  m_importer->SetPlugin( std::move( plugin ) );
311 
312  LOCALE_IO dummy; // Ensure floats can be read.
313 
314  if( m_importer->Load( m_filename ) )
315  m_importer->Import( m_scaleImport );
316 
317  // Get warning messages:
318  wxString warnings = m_importer->GetMessages();
319 
320  // This isn't a fatal error so allow the dialog to close with wxID_OK.
321  if( !warnings.empty() )
322  {
323  HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
324  dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
325  warnings.Replace( "\n", "<br/>" );
326  dlg.AddHTML_Text( warnings );
327  dlg.ShowModal();
328  }
329  }
330  else
331  {
332  wxMessageBox( _( "There is no plugin to handle this file type." ) );
333  return false;
334  }
335 
336  return true;
337 }
338 
339 
340 void DIALOG_IMPORT_GFX::originOptionOnUpdateUI( wxUpdateUIEvent& event )
341 {
344 
345  if( m_rbAbsolutePlacement->GetValue() == m_placementInteractive )
347 
349  m_DxfPcbXCoord->Enable( not m_placementInteractive );
350  m_DxfPcbYCoord->Enable( not m_placementInteractive );
351 }
352 
353 
355 {
358 
359  if( m_originUnits ) // Units are inches
360  m_origin = m_origin * 25.4;
361 }
362 
363 
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:676
#define IMPORT_GFX_GROUP
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:154
#define IMPORT_GFX_LINEWIDTH_KEY
void SetNotAllowedLayerSet(LSET aMask)
#define IMPORT_GFX_LINEWIDTH_UNITS_KEY
#define IMPORT_GFX_POSITION_Y_KEY
void originOptionOnUpdateUI(wxUpdateUIEvent &event) override
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
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
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
LAYER_NUM GetLayerSelection() const
PCB_LAYER_ID
A quick note on layer IDs:
Footprint text class description.
#define IMPORT_GFX_PLACEMENT_INTERACTIVE_KEY
double DoubleValueFromString(EDA_UNITS_T aUnits, const wxString &aTextValue, bool aUseMils)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:314
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:276
#define IMPORT_GFX_POSITION_X_KEY
Definition of file extensions used in Kicad.
int SetLayerSelection(LAYER_NUM layer)
#define IMPORT_GFX_LAYER_OPTION_KEY
Class HTML_MESSAGE_BOX.
bool SetLayersHotkeys(bool value)
#define _(s)
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
wxConfigBase * m_config
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
static wxString m_filename
#define IMPORT_GFX_LAST_FILE_KEY
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.
wxRadioButton * m_rbAbsolutePlacement
void AddHTML_Text(const wxString &message)
Add HTML text (without any change) to message list.
#define IMPORT_GFX_POSITION_UNITS_KEY
static bool m_placementInteractive
BOARD * GetBoard() const
EDGE_MODULE class definition.
std::unique_ptr< GRAPHICS_IMPORTER_PCBNEW > m_importer
class 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.