KiCad PCB EDA Suite
dialog_import_gfx.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
10  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include "dialog_import_gfx.h"
31 
32 #include <advanced_config.h>
33 #include <convert_to_biu.h>
34 #include <kiface_i.h>
35 #include <pcb_layer_box_selector.h>
37 
38 #include <class_board.h>
39 #include <class_module.h>
40 #include <class_edge_mod.h>
41 #include <class_text_mod.h>
42 #include <class_pcb_text.h>
43 
44 // Keys to store setup in config
45 #define IMPORT_GFX_LAYER_OPTION_KEY "GfxImportBrdLayer"
46 #define IMPORT_GFX_PLACEMENT_INTERACTIVE_KEY "GfxImportPlacementInteractive"
47 #define IMPORT_GFX_LAST_FILE_KEY "GfxImportLastFile"
48 #define IMPORT_GFX_POSITION_UNITS_KEY "GfxImportPositionUnits"
49 #define IMPORT_GFX_POSITION_X_KEY "GfxImportPositionX"
50 #define IMPORT_GFX_POSITION_Y_KEY "GfxImportPositionY"
51 #define IMPORT_GFX_LINEWIDTH_UNITS_KEY "GfxImportLineWidthUnits"
52 #define IMPORT_GFX_LINEWIDTH_KEY "GfxImportLineWidth"
53 
54 // Static members of DIALOG_IMPORT_GFX, to remember
55 // the user's choices during the session
59 double DIALOG_IMPORT_GFX::m_scaleImport = 1.0; // Do not change the imported items size
60 
61 DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX( PCB_BASE_FRAME* aParent, bool aImportAsFootprintGraphic )
62  : DIALOG_IMPORT_GFX_BASE( aParent )
63 {
64  m_parent = aParent;
65 
66  if( aImportAsFootprintGraphic )
68  else
70 
71  // construct an import manager with options from config
72  {
74 
76  blacklist.push_back( GRAPHICS_IMPORT_MGR::SVG );
77 
78  m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>( blacklist );
79  }
80 
83  m_importOrigin.x = 0.0; // always in mm
84  m_importOrigin.y = 0.0; // always in mm
85  m_default_lineWidth = 0.2; // always in mm
87 
88  if( m_config )
89  {
90  m_layer = m_config->Read( IMPORT_GFX_LAYER_OPTION_KEY, (long)Dwgs_User );
92  m_filename = m_config->Read( IMPORT_GFX_LAST_FILE_KEY, wxEmptyString );
93  m_config->Read( IMPORT_GFX_LINEWIDTH_KEY, &m_default_lineWidth, 0.2 );
95  m_config->Read( IMPORT_GFX_POSITION_X_KEY, &m_importOrigin.x, 0.0 );
96  m_config->Read( IMPORT_GFX_POSITION_Y_KEY, &m_importOrigin.y, 0.0 );
97  }
98 
101 
104 
105  m_textCtrlFileName->SetValue( m_filename );
108 
110 
111  // Configure the layers list selector
112  m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
113  m_SelLayerBox->SetNotAllowedLayerSet( LSET::AllCuMask() ); // Do not use copper layers
116 
118  {
119  m_layer = Dwgs_User;
121  }
122 
123  m_sdbSizerOK->SetDefault();
124  GetSizer()->Fit( this );
125  GetSizer()->SetSizeHints( this );
126  Centre();
127 }
128 
129 
131 {
134 
135  if( m_config )
136  {
140 
144 
148  }
149 }
150 
151 
152 void DIALOG_IMPORT_GFX::DIALOG_IMPORT_GFX::onUnitPositionSelection( wxCommandEvent& event )
153 {
154  // Collect last entered values:
156 
157  m_originImportUnits = m_DxfPcbPositionUnits->GetSelection();;
159 }
160 
161 
163 {
164  double value = DoubleValueFromString( UNSCALED_UNITS, m_textCtrlLineWidth->GetValue() );
165 
166  switch( m_lineWidthImportUnits )
167  {
168  default:
169  case 0: // display units = mm
170  break;
171 
172  case 1: // display units = mil
173  value *= 25.4 / 1000;
174  break;
175 
176  case 2: // display units = inch
177  value *= 25.4;
178  break;
179  }
180 
181  return value; // value is in mm
182 }
183 
184 
185 void DIALOG_IMPORT_GFX::onUnitWidthSelection( wxCommandEvent& event )
186 {
188 
189  // Switch to new units
192 }
193 
194 
196 {
197  // Display m_importOrigin value according to the unit selection:
198  VECTOR2D offset = m_importOrigin;
199 
200  if( m_originImportUnits ) // Units are inches
201  offset = m_importOrigin / 25.4;
202 
203  m_DxfPcbXCoord->SetValue( wxString::Format( "%f", offset.x ) );
204  m_DxfPcbYCoord->SetValue( wxString::Format( "%f", offset.y ) );
205 
206 }
207 
208 
210 {
211  double value;
212 
213  switch( m_lineWidthImportUnits )
214  {
215  default:
216  case 0: // display units = mm
217  value = m_default_lineWidth;
218  break;
219 
220  case 1: // display units = mil
221  value = m_default_lineWidth / 25.4 * 1000;
222  break;
223 
224  case 2: // display units = inch
225  value = m_default_lineWidth / 25.4;
226  break;
227  }
228 
229  m_textCtrlLineWidth->SetValue( wxString::Format( "%f", value ) );
230 }
231 
232 
233 void DIALOG_IMPORT_GFX::onBrowseFiles( wxCommandEvent& event )
234 {
235  wxString path;
236  wxString filename;
237 
238  if( !m_filename.IsEmpty() )
239  {
240  wxFileName fn( m_filename );
241  path = fn.GetPath();
242  filename = fn.GetFullName();
243  }
244 
245  // Generate the list of handled file formats
246  wxString wildcardsDesc;
247  wxString allWildcards;
248 
249  for( auto pluginType : m_gfxImportMgr->GetImportableFileTypes() )
250  {
251  auto plugin = m_gfxImportMgr->GetPlugin( pluginType );
252  const auto wildcards = plugin->GetWildcards();
253 
254  wildcardsDesc += "|" + plugin->GetName() + " (" + wildcards + ")|" + wildcards;
255  allWildcards += wildcards + ";";
256  }
257 
258  wildcardsDesc = "All supported formats|" + allWildcards + wildcardsDesc;
259 
260  wxFileDialog dlg( m_parent, _( "Open File" ), path, filename,
261  wildcardsDesc, wxFD_OPEN|wxFD_FILE_MUST_EXIST );
262 
263  if( dlg.ShowModal() != wxID_OK )
264  return;
265 
266  wxString fileName = dlg.GetPath();
267 
268  if( fileName.IsEmpty() )
269  return;
270 
271  m_filename = fileName;
272  m_textCtrlFileName->SetValue( fileName );
273 }
274 
275 
276 void DIALOG_IMPORT_GFX::onOKClick( wxCommandEvent& event )
277 {
278  m_filename = m_textCtrlFileName->GetValue();
279 
280  if( m_filename.IsEmpty() )
281  {
282  wxMessageBox( _( "Error: No DXF filename!" ) );
283  return;
284  }
285 
286  updatePcbImportOffsets_mm(); // Update m_importOriginX and m_importOriginY;
287 
289 
290  if( m_layer < 0 )
291  {
292  wxMessageBox( _( "Please, select a valid layer" ) );
293  return;
294  }
295 
297 
298  m_importer->SetLayer( PCB_LAYER_ID( m_layer ) );
299 
300  auto plugin = m_gfxImportMgr->GetPluginByExt( wxFileName( m_filename ).GetExt() );
301 
302  if( plugin )
303  {
304  // Set coordinates offset for import (offset is given in mm)
305  m_importer->SetImportOffsetMM( m_importOrigin );
307 
308  m_importer->SetLineWidthMM( m_default_lineWidth );
309  m_importer->SetPlugin( std::move( plugin ) );
310 
311  LOCALE_IO dummy; // Ensure floats can be read.
312 
313  if( m_importer->Load( m_filename ) )
314  m_importer->Import( m_scaleImport );
315 
316  // Get warning messages:
317  const std::string& warnings = m_importer->GetMessages();
318 
319  if( !warnings.empty() )
320  wxMessageBox( warnings.c_str(), _( "Not Handled Items" ) );
321 
322  event.Skip();
323  }
324  else
325  {
326  wxMessageBox( _( "There is no plugin to handle this file type" ) );
327  }
328 }
329 
330 
331 // Used only in legacy canvas by the board editor.
333 {
334  DIALOG_IMPORT_GFX dlg( aCaller );
335 
336  if( dlg.ShowModal() != wxID_OK )
337  return false;
338 
339  auto& list = dlg.GetImportedItems();
340 
341  // Ensure the list is not empty:
342  if( list.empty() )
343  {
344  wxMessageBox( _( "No graphic items found in file to import") );
345  return false;
346  }
347 
348  PICKED_ITEMS_LIST picklist; // the pick list for undo command
349  ITEM_PICKER item_picker( nullptr, UR_NEW );
350  BOARD* board = aCaller->GetBoard();
351 
352  // Now prepare a block move command to place the new items, if interactive placement,
353  // and prepare the undo command.
354  EDA_RECT bbox; // the new items bounding box, for block move if interactive placement.
355  bool bboxInit = true; // true until the bounding box is initialized
356  BLOCK_SELECTOR& blockmove = aCaller->GetScreen()->m_BlockLocate;
357 
358  if( dlg.IsPlacementInteractive() )
359  aCaller->HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) );
360 
361  PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems();
362 
363  for( auto it = list.begin(); it != list.end(); ++it )
364  {
365  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->release() );
366 
367  if( dlg.IsPlacementInteractive() )
368  item->SetFlags( IS_MOVED );
369 
370  board->Add( item );
371 
372  item_picker.SetItem( item );
373  picklist.PushItem( item_picker );
374 
375  if( dlg.IsPlacementInteractive() )
376  {
377  blockitemsList.PushItem( item_picker );
378 
379  if( bboxInit )
380  bbox = item->GetBoundingBox();
381  else
382  bbox.Merge( item->GetBoundingBox() );
383 
384  bboxInit = false;
385  }
386  }
387 
388  aCaller->SaveCopyInUndoList( picklist, UR_NEW, wxPoint( 0, 0 ) );
389  aCaller->OnModify();
390 
391  if( dlg.IsPlacementInteractive() )
392  {
393  // Finish block move command:
394  wxPoint cpos = aCaller->GetNearestGridPosition( bbox.Centre() );
395  blockmove.SetOrigin( bbox.GetOrigin() );
396  blockmove.SetSize( bbox.GetSize() );
397  blockmove.SetLastCursorPosition( cpos );
398  aCaller->HandleBlockEnd( NULL );
399  }
400 
401  return true;
402 }
403 
404 
405 // Used only in legacy canvas by the footprint editor.
407 {
408  if( !aModule )
409  return false;
410 
411  DIALOG_IMPORT_GFX dlg( aCaller, true );
412 
413  if( dlg.ShowModal() != wxID_OK )
414  return false;
415 
416  auto& list = dlg.GetImportedItems();
417 
418  // Ensure the list is not empty:
419  if( list.empty() )
420  {
421  wxMessageBox( _( "No graphic items found in file to import") );
422  return false;
423  }
424 
425  aCaller->SaveCopyInUndoList( aModule, UR_CHANGED );
426 
427  PICKED_ITEMS_LIST picklist; // the pick list for undo command
428  ITEM_PICKER item_picker( nullptr, UR_NEW );
429 
430  // Now prepare a block move command to place the new items, if interactive placement,
431  // and prepare the undo command.
432  EDA_RECT bbox; // the new items bounding box, for block move if interactive placement.
433  bool bboxInit = true; // true until the bounding box is initialized
434  BLOCK_SELECTOR& blockmove = aCaller->GetScreen()->m_BlockLocate;
435 
436  if( dlg.IsPlacementInteractive() )
437  aCaller->HandleBlockBegin( nullptr, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) );
438 
439  PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems();
440 
441  for( auto it = list.begin(); it != list.end(); ++it )
442  {
443  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->release() );
444  aModule->Add( item );
445 
446  if( dlg.IsPlacementInteractive() )
447  {
448  item->SetFlags( IS_MOVED );
449  item_picker.SetItem( item );
450  blockitemsList.PushItem( item_picker );
451 
452  if( bboxInit )
453  bbox = item->GetBoundingBox();
454  else
455  bbox.Merge( item->GetBoundingBox() );
456 
457  bboxInit = false;
458  }
459  }
460 
461  aCaller->OnModify();
462 
463  if( dlg.IsPlacementInteractive() )
464  {
465  // Finish block move command:
466  wxPoint cpos = aCaller->GetNearestGridPosition( bbox.Centre() );
467  blockmove.SetOrigin( bbox.GetOrigin() );
468  blockmove.SetSize( bbox.GetSize() );
469  blockmove.SetLastCursorPosition( cpos );
470  aCaller->HandleBlockEnd( NULL );
471  }
472 
473  return true;
474 }
475 
476 
477 void DIALOG_IMPORT_GFX::originOptionOnUpdateUI( wxUpdateUIEvent& event )
478 {
481 
482  m_DxfPcbPositionUnits->Enable( not m_placementInteractive );
483  m_DxfPcbXCoord->Enable( not m_placementInteractive );
484  m_DxfPcbYCoord->Enable( not m_placementInteractive );
485 }
486 
487 
489 {
492 
493  if( m_originImportUnits ) // Units are inches
494  {
496  }
497 
498  return;
499 }
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
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
BLOCK_SELECTOR m_BlockLocate
Block description for block commands.
Definition: base_screen.h:214
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect...
TEXTE_PCB class definition.
bool InvokeDialogImportGfxModule(PCB_BASE_FRAME *aCaller, MODULE *aModule)
shows the modal DIALOG_IMPORT_GFX for importing a DXF file as footprint outlines. ...
bool InvokeDialogImportGfxBoard(PCB_BASE_FRAME *aCaller)
Shows the modal DIALOG_IMPORT_GFX for importing a DXF file to a board.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:180
void onOKClick(wxCommandEvent &event) override
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
#define IMPORT_GFX_LINEWIDTH_KEY
const wxSize GetSize() const
Definition: eda_rect.h:101
void SetNotAllowedLayerSet(LSET aMask)
#define IMPORT_GFX_LINEWIDTH_UNITS_KEY
Class BOARD to handle a board.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
Function GetImportedItems()
#define IMPORT_GFX_POSITION_Y_KEY
void originOptionOnUpdateUI(wxUpdateUIEvent &event) 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
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
wxRadioButton * m_rbInteractivePlacement
BOARD * GetBoard() const
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
virtual bool HandleBlockBegin(wxDC *aDC, EDA_KEY aKey, const wxPoint &aPosition, int aExplicitCommand=0)
Initialize a block command.
PCB_LAYER_ID
A quick note on layer IDs:
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
>
Footprint text class description.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
#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:302
PCB_LAYER_BOX_SELECTOR * m_SelLayerBox
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
Adds an item to the container.
PCB_BASE_FRAME * m_parent
#define IMPORT_GFX_POSITION_X_KEY
Definition of file extensions used in Kicad.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
int SetLayerSelection(LAYER_NUM layer)
#define IMPORT_GFX_LAYER_OPTION_KEY
wxPoint Centre() const
Definition: eda_rect.h:60
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
void SetItem(EDA_ITEM *aItem)
bool SetLayersHotkeys(bool value)
std::vector< GFX_FILE_T > TYPE_LIST
static LAYER_NUM m_layer
wxConfigBase * m_config
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
virtual bool HandleBlockEnd(wxDC *DC)
Handle the "end" of a block command, i.e.
static wxString m_filename
virtual void OnModify()
Function OnModify Virtual Must be called after a change in order to set the "modify" flag of the curr...
void SetSize(const wxSize &size)
Definition: eda_rect.h:126
wxPoint GetNearestGridPosition(const wxPoint &aPosition, wxRealPoint *aGridSize=NULL) const
Return the nearest aGridSize location to aPosition.
#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 when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:171
DLIST< MODULE > m_Modules
Definition: class_board.h:249
wxRadioButton * m_rbAbsolutePlacement
LAYER_NUM GetLayerSelection() const
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
#define IMPORT_GFX_POSITION_UNITS_KEY
virtual void SaveCopyInUndoList(BOARD_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, const wxPoint &aTransformPoint=wxPoint(0, 0))=0
Function SaveCopyInUndoList (virtual pure) Creates a new entry in undo list of commands.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
PICKED_ITEMS_LIST & GetItems()
static bool m_placementInteractive
static const ADVANCED_CFG & GetCfg()
Get the singleton instance&#39;s config, which is shared by all consumers of advanced config...
Module description (excepted pads)
EDGE_MODULE class definition.
std::unique_ptr< GRAPHICS_IMPORTER_PCBNEW > m_importer
void SetLastCursorPosition(const wxPoint &aPosition)
Function SetLastCursorPosition sets the last cursor position to aPosition.
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
bool m_enableSvgImport
Enable SVG import.
#define IS_MOVED
Item being moved.
Definition: base_struct.h:113