You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
9.0 KiB

7 months ago
6 years ago
  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. #include <dialogs/html_message_box.h>
  25. #include "dialog_import_graphics.h"
  26. #include <import_gfx/dxf_import_plugin.h>
  27. #include <base_units.h>
  28. #include <kiface_base.h>
  29. #include <locale_io.h>
  30. #include <pcb_layer_box_selector.h>
  31. #include <wildcards_and_files_ext.h>
  32. #include <bitmaps.h>
  33. #include <widgets/std_bitmap_button.h>
  34. #include <map>
  35. #include <footprint.h>
  36. #include <wx/filedlg.h>
  37. #include <wx/msgdlg.h>
  38. #include <memory>
  39. const std::map<DXF_IMPORT_UNITS, wxString> dxfUnitsMap = {
  40. { DXF_IMPORT_UNITS::INCH, _( "Inches" ) },
  41. { DXF_IMPORT_UNITS::MM, _( "Millimeters" ) },
  42. { DXF_IMPORT_UNITS::MILS, _( "Mils" ) },
  43. { DXF_IMPORT_UNITS::CM, _( "Centimeter" ) },
  44. { DXF_IMPORT_UNITS::FEET, _( "Feet" ) },
  45. };
  46. DIALOG_IMPORT_GRAPHICS::DIALOG_IMPORT_GRAPHICS( PCB_BASE_FRAME* aParent ) :
  47. DIALOG_IMPORT_GRAPHICS_BASE( aParent ),
  48. m_parent( aParent ),
  49. m_xOrigin( aParent, nullptr, m_xCtrl, nullptr ),
  50. m_yOrigin( aParent, m_yLabel, m_yCtrl, m_yUnits ),
  51. m_defaultLineWidth( aParent, m_lineWidthLabel, m_lineWidthCtrl, m_lineWidthUnits ),
  52. m_tolerance( aParent, m_toleranceLabel, m_toleranceCtrl, m_toleranceUnits )
  53. {
  54. // The SVG import has currently a flaw: all SVG shapes are imported as curves and
  55. // converted to a lot of segments. A better approach is to convert to polylines
  56. // (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
  57. // possible with tinysvg library).
  58. m_importer = std::make_unique<GRAPHICS_IMPORTER_PCBNEW>( aParent->GetModel() );
  59. m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>();
  60. // Configure the layers list selector
  61. m_SelLayerBox->SetLayersHotkeys( false ); // Do not display hotkeys
  62. m_SelLayerBox->SetBoardFrame( m_parent );
  63. m_SelLayerBox->Resync();
  64. for( const std::pair<const DXF_IMPORT_UNITS, wxString>& unitEntry : dxfUnitsMap )
  65. m_dxfUnitsChoice->Append( unitEntry.second );
  66. m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
  67. wxCommandEvent dummy;
  68. onFilename( dummy );
  69. SetInitialFocus( m_textCtrlFileName );
  70. SetupStandardButtons();
  71. GetSizer()->Fit( this );
  72. GetSizer()->SetSizeHints( this );
  73. Centre();
  74. m_textCtrlFileName->Connect( wxEVT_COMMAND_TEXT_UPDATED,
  75. wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
  76. nullptr, this );
  77. }
  78. DIALOG_IMPORT_GRAPHICS::~DIALOG_IMPORT_GRAPHICS()
  79. {
  80. m_textCtrlFileName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
  81. wxCommandEventHandler( DIALOG_IMPORT_GRAPHICS::onFilename ),
  82. nullptr, this );
  83. }
  84. void DIALOG_IMPORT_GRAPHICS::SetFilenameOverride( const wxString& aFilenameOverride )
  85. {
  86. m_filenameOverride = aFilenameOverride;
  87. }
  88. bool DIALOG_IMPORT_GRAPHICS::TransferDataToWindow()
  89. {
  90. DIALOG_SHIM::TransferDataToWindow();
  91. // We have to set the filename field value here, otherwise it gets overwritten by state loading
  92. if( !m_filenameOverride.IsEmpty() )
  93. m_textCtrlFileName->SetValue( m_filenameOverride );
  94. return true;
  95. }
  96. void DIALOG_IMPORT_GRAPHICS::onFilename( wxCommandEvent& event )
  97. {
  98. bool enableDXFControls = true;
  99. wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
  100. if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
  101. enableDXFControls = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) != nullptr;
  102. m_defaultLineWidth.Enable( enableDXFControls );
  103. m_dxfUnitsLabel->Enable( enableDXFControls );
  104. m_dxfUnitsChoice->Enable( enableDXFControls );
  105. }
  106. void DIALOG_IMPORT_GRAPHICS::onBrowseFiles( wxCommandEvent& event )
  107. {
  108. wxString path;
  109. wxString filename = m_textCtrlFileName->GetValue();
  110. if( !filename.IsEmpty() )
  111. {
  112. wxFileName fn( filename );
  113. path = fn.GetPath();
  114. filename = fn.GetFullName();
  115. }
  116. // Generate the list of handled file formats
  117. wxString wildcardsDesc;
  118. wxString allWildcards;
  119. for( GRAPHICS_IMPORT_MGR::GFX_FILE_T pluginType : m_gfxImportMgr->GetImportableFileTypes() )
  120. {
  121. std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPlugin( pluginType );
  122. const std::vector<std::string> extensions = plugin->GetFileExtensions();
  123. wildcardsDesc += wxT( "|" ) + plugin->GetName() + AddFileExtListToFilter( extensions );
  124. allWildcards += plugin->GetWildcards() + wxT( ";" );
  125. }
  126. wildcardsDesc = _( "All supported formats" ) + wxT( "|" ) + allWildcards + wildcardsDesc;
  127. wxFileDialog dlg( m_parent, _( "Import Graphics" ), path, filename, wildcardsDesc,
  128. wxFD_OPEN | wxFD_FILE_MUST_EXIST );
  129. if( dlg.ShowModal() == wxID_OK && !dlg.GetPath().IsEmpty() )
  130. m_textCtrlFileName->SetValue( dlg.GetPath() );
  131. }
  132. bool DIALOG_IMPORT_GRAPHICS::TransferDataFromWindow()
  133. {
  134. if( !wxDialog::TransferDataFromWindow() )
  135. return false;
  136. if( m_textCtrlFileName->GetValue().IsEmpty() )
  137. {
  138. wxMessageBox( _( "Please select a file to import." ) );
  139. return false;
  140. }
  141. if( m_setLayerCheckbox->GetValue() && m_SelLayerBox->GetLayerSelection() < 0 )
  142. {
  143. wxMessageBox( _( "Please select a valid layer." ) );
  144. return false;
  145. }
  146. PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
  147. wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
  148. double scale = EDA_UNIT_UTILS::UI::DoubleValueFromString( m_importScaleCtrl->GetValue() );
  149. double xscale = scale;
  150. double yscale = scale;
  151. if( cfg->m_Display.m_DisplayInvertXAxis )
  152. xscale *= -1.0;
  153. if( cfg->m_Display.m_DisplayInvertYAxis )
  154. yscale *= -1.0;
  155. VECTOR2D origin( m_xOrigin.GetDoubleValue() / xscale, m_yOrigin.GetDoubleValue() / yscale );
  156. if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
  157. {
  158. if( DXF_IMPORT_PLUGIN* dxfPlugin = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) )
  159. {
  160. auto it = dxfUnitsMap.begin();
  161. std::advance( it, m_dxfUnitsChoice->GetSelection() );
  162. if( it == dxfUnitsMap.end() )
  163. dxfPlugin->SetUnit( DXF_IMPORT_UNITS::DEFAULT );
  164. else
  165. dxfPlugin->SetUnit( it->first );
  166. m_importer->SetLineWidthMM( pcbIUScale.IUTomm( m_defaultLineWidth.GetIntValue() ) );
  167. }
  168. else
  169. {
  170. m_importer->SetLineWidthMM( 0.0 );
  171. }
  172. m_importer->SetPlugin( std::move( plugin ) );
  173. if( m_setLayerCheckbox->GetValue() )
  174. m_importer->SetLayer( PCB_LAYER_ID( m_SelLayerBox->GetLayerSelection() ) );
  175. else
  176. m_importer->SetLayer( m_parent->GetActiveLayer() );
  177. m_importer->SetImportOffsetMM( origin * pcbIUScale.IUTomm( 1 ) );
  178. LOCALE_IO dummy; // Ensure floats can be read.
  179. if( m_importer->Load( m_textCtrlFileName->GetValue() ) )
  180. m_importer->Import( VECTOR2D( scale, scale ) );
  181. // Get warning messages:
  182. wxString warnings = m_importer->GetMessages();
  183. // This isn't a fatal error so allow the dialog to close with wxID_OK.
  184. if( !warnings.empty() )
  185. {
  186. HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
  187. dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
  188. warnings.Replace( wxT( "\n" ), wxT( "<br/>" ) );
  189. dlg.AddHTML_Text( warnings );
  190. dlg.ShowModal();
  191. }
  192. return true;
  193. }
  194. else
  195. {
  196. wxMessageBox( _( "There is no plugin to handle this file type." ) );
  197. return false;
  198. }
  199. }
  200. void DIALOG_IMPORT_GRAPHICS::onUpdateUI( wxUpdateUIEvent& event )
  201. {
  202. m_xOrigin.Enable( m_placeAtCheckbox->GetValue() );
  203. m_yOrigin.Enable( m_placeAtCheckbox->GetValue() );
  204. m_tolerance.Enable( m_rbFixDiscontinuities->GetValue() );
  205. m_SelLayerBox->Enable( m_setLayerCheckbox->GetValue() );
  206. }