diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index ce0b104b0a..844cb65e8f 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -89,6 +89,7 @@ set( PCBNEW_DIALOGS dialogs/dialog_fp_plugin_options.cpp dialogs/dialog_freeroute_exchange.cpp dialogs/dialog_freeroute_exchange_base.cpp + dialogs/dialog_gencad_export_options.cpp dialogs/dialog_gendrill.cpp dialogs/dialog_gendrill_base.cpp dialogs/dialog_gen_module_position_file_base.cpp diff --git a/pcbnew/dialogs/dialog_gencad_export_options.cpp b/pcbnew/dialogs/dialog_gencad_export_options.cpp new file mode 100644 index 0000000000..7aa2f9ac7a --- /dev/null +++ b/pcbnew/dialogs/dialog_gencad_export_options.cpp @@ -0,0 +1,154 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "dialog_gencad_export_options.h" + +#include +#include +#include +#include + +#include +#include + +DIALOG_GENCAD_EXPORT_OPTIONS::DIALOG_GENCAD_EXPORT_OPTIONS( PCB_EDIT_FRAME* aParent ) + : DIALOG_SHIM( aParent, wxID_ANY, _( "Export to GenCAD settings" ) ) +{ + // Obtain a potential filename for the exported file + wxFileName fn = aParent->GetBoard()->GetFileName(); + fn.SetExt( "cad" ); + + // Create widgets + SetSizeHints( wxSize( 500, 200 ), wxDefaultSize ); + + wxBoxSizer* m_mainSizer= new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* m_fileSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_filePath = new wxTextCtrl( this, wxID_ANY, fn.GetFullPath() ); + m_fileSizer->Add( m_filePath, 1, wxALL, 5 ); + + wxButton* m_browseBtn = new wxButton( this, wxID_ANY, _( "Browse" ) ); + m_browseBtn->Connect( wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler( DIALOG_GENCAD_EXPORT_OPTIONS::onBrowse ), NULL, this ); + m_fileSizer->Add( m_browseBtn, 0, wxALL, 5 ); + + m_mainSizer->Add( m_fileSizer, 0, wxEXPAND, 5 ); + + + m_optsSizer = new wxGridSizer( 0, 1, 0, 0 ); + createOptCheckboxes(); + m_mainSizer->Add( m_optsSizer, 1, wxEXPAND, 5 ); + + + wxSizer* stdButtons = CreateSeparatedButtonSizer( wxOK | wxCANCEL ); + m_mainSizer->Add( stdButtons, 0, wxEXPAND, 5 ); + + SetSizer( m_mainSizer ); + Layout(); + m_mainSizer->Fit( this ); + + Centre( wxBOTH ); +} + + +DIALOG_GENCAD_EXPORT_OPTIONS::~DIALOG_GENCAD_EXPORT_OPTIONS() +{ +} + + +bool DIALOG_GENCAD_EXPORT_OPTIONS::GetOption( GENCAD_EXPORT_OPT aOption ) const +{ + auto it = m_options.find( aOption ); + + if( it == m_options.end() ) + { + wxASSERT_MSG( false, "Missing checkbox for an option" ); + return false; + } + + return it->second->IsChecked(); +} + + +std::map DIALOG_GENCAD_EXPORT_OPTIONS::GetAllOptions() const +{ + std::map retVal; + + for( const auto& option : m_options ) + retVal[option.first] = option.second->IsChecked(); + + return retVal; +} + + +wxString DIALOG_GENCAD_EXPORT_OPTIONS::GetFileName() const +{ + return m_filePath->GetValue(); +} + + +bool DIALOG_GENCAD_EXPORT_OPTIONS::TransferDataFromWindow() +{ + if( !wxDialog::TransferDataFromWindow() ) + return false; + + wxString fn = GetFileName(); + + if( wxFile::Exists( fn ) ) + return IsOK( this, wxString::Format( _( "File %s already exists. Overwrite?" ), fn ) ); + + return true; +} + + +void DIALOG_GENCAD_EXPORT_OPTIONS::createOptCheckboxes() +{ + std::map opts = + { + { FLIP_BOTTOM_LAYERS, _( "Flip layer stack for bottom components" ) } + }; + + for( const auto& option : opts ) + { + wxCheckBox* chkbox = new wxCheckBox( this, wxID_ANY, option.second ); + m_options[option.first] = chkbox; + m_optsSizer->Add( chkbox, 0, wxALL, 5 ); + } +} + + +void DIALOG_GENCAD_EXPORT_OPTIONS::onBrowse( wxCommandEvent& aEvent ) +{ + wxFileDialog dlg( this, _( "Save GenCAD Board File" ), + wxPathOnly( Prj().GetProjectFullName() ), + m_filePath->GetValue(), + _( "GenCAD 1.4 board files (.cad)|*.cad" ), + wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + m_filePath->SetValue( dlg.GetPath() ); +} diff --git a/pcbnew/dialogs/dialog_gencad_export_options.h b/pcbnew/dialogs/dialog_gencad_export_options.h new file mode 100644 index 0000000000..391091b097 --- /dev/null +++ b/pcbnew/dialogs/dialog_gencad_export_options.h @@ -0,0 +1,71 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __DIALOG_GENCAD_EXPORT_OPTIONS_H__ +#define __DIALOG_GENCAD_EXPORT_OPTIONS_H__ + +#include + +class PCB_EDIT_FRAME; +class wxTextCtrl; + +///> Settings for GenCAD exporter +enum GENCAD_EXPORT_OPT +{ + FLIP_BOTTOM_LAYERS // invert layer stack for bottom components +}; + + +class DIALOG_GENCAD_EXPORT_OPTIONS : public DIALOG_SHIM +{ + public: + DIALOG_GENCAD_EXPORT_OPTIONS( PCB_EDIT_FRAME* aParent ); + ~DIALOG_GENCAD_EXPORT_OPTIONS(); + + ///> Checks whether an option has been selected + bool GetOption( GENCAD_EXPORT_OPT aOption ) const; + + ///> Returns all export settings + std::map GetAllOptions() const; + + ///> Returns the selected file path + wxString GetFileName() const; + + protected: + bool TransferDataFromWindow() override; + + ///> Creates checkboxes for GenCAD export options + void createOptCheckboxes(); + + ///> Browse output file event handler + void onBrowse( wxCommandEvent& aEvent ); + + std::map m_options; + + // Widgets + wxGridSizer* m_optsSizer; + wxTextCtrl* m_filePath; +}; + +#endif //__DIALOG_GENCAD_EXPORT_OPTIONS_H__ diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index 1bf11f8c57..fb8f505bcf 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -223,6 +224,8 @@ static int GencadOffsetX, GencadOffsetY; // GerbTool chokes on units different than INCH so this is the conversion factor const static double SCALE_FACTOR = 1000.0 * IU_PER_MILS; +// Export options +bool flipBottomLayers; /* Two helper functions to calculate coordinates of modules in gencad values * (GenCAD Y axis from bottom to top) @@ -242,31 +245,23 @@ static double MapYTo( int aY ) /* Driver function: processing starts here */ void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent ) { - wxFileName fn = GetBoard()->GetFileName(); - FILE* file; + DIALOG_GENCAD_EXPORT_OPTIONS optionsDialog( this ); - wxString ext = wxT( "cad" ); - wxString wildcard = _( "GenCAD 1.4 board files (.cad)|*.cad" ); - - fn.SetExt( ext ); - - wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); - - wxFileDialog dlg( this, _( "Save GenCAD Board File" ), pro_dir, - fn.GetFullName(), wildcard, - wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - - if( dlg.ShowModal() == wxID_CANCEL ) + if( optionsDialog.ShowModal() == wxID_CANCEL ) return; - if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL ) - { - wxString msg; + FILE* file = wxFopen( optionsDialog.GetFileName(), "wt" ); - msg.Printf( _( "Unable to create <%s>" ), GetChars( dlg.GetPath() ) ); - DisplayError( this, msg ); return; + if( !file ) + { + DisplayError( this, wxString::Format( _( "Unable to create <%s>" ), + GetChars( optionsDialog.GetFileName() ) ) ); + return; } + // Get options + flipBottomLayers = optionsDialog.GetOption( FLIP_BOTTOM_LAYERS ); + // Switch the locale to standard C (needed to print floating point numbers) LOCALE_IO toggle; @@ -606,14 +601,17 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb ) } // Flipped padstack - fprintf( aFile, "PADSTACK PAD%uF %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR ); - - // the normal PCB_LAYER_ID sequence is inverted from gc_seq[] - for( LSEQ seq = pad_set.Seq(); seq; ++seq ) + if( flipBottomLayers ) { - PCB_LAYER_ID layer = *seq; + fprintf( aFile, "PADSTACK PAD%uF %g\n", i, pad->GetDrillSize().x / SCALE_FACTOR ); - fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerNameFlipped( cu_count, layer ).c_str() ); + // the normal PCB_LAYER_ID sequence is inverted from gc_seq[] + for( LSEQ seq = pad_set.Seq(); seq; ++seq ) + { + PCB_LAYER_ID layer = *seq; + + fprintf( aFile, "PAD P%u %s 0 0\n", i, GenCADLayerNameFlipped( cu_count, layer ).c_str() ); + } } } @@ -652,11 +650,11 @@ static void CreateShapesSection( FILE* aFile, BOARD* aPcb ) if( ( pad->GetLayerSet() & all_cu ) == LSET( B_Cu ) ) { - layer = module->GetLayer() == B_Cu ? "TOP" : "BOTTOM"; + layer = flipBottomLayers && module->GetLayer() == B_Cu ? "TOP" : "BOTTOM"; } else if( ( pad->GetLayerSet() & all_cu ) == LSET( F_Cu ) ) { - layer = module->GetLayer() == B_Cu ? "BOTTOM" : "TOP"; + layer = flipBottomLayers && module->GetLayer() == B_Cu ? "BOTTOM" : "TOP"; } pinname = pad->GetName(); @@ -668,7 +666,7 @@ static void CreateShapesSection( FILE* aFile, BOARD* aPcb ) NORMALIZE_ANGLE_POS( orient ); // Bottom side modules use the flipped padstack - fprintf( aFile, (module->GetLayer() == B_Cu) ? + fprintf( aFile, ( flipBottomLayers && module->GetLayer() == B_Cu ) ? "PIN %s PAD%dF %g %g %s %g %s\n" : "PIN %s PAD%d %g %g %s %g %s\n", TO_UTF8( pinname ), pad->GetSubRatsnest(), @@ -733,7 +731,8 @@ static void CreateComponentsSection( FILE* aFile, BOARD* aPcb ) for( int ii = 0; ii < 2; ii++ ) { double txt_orient = textmod->GetTextAngle(); - std::string layer = GenCADLayerName( cu_count, module->GetLayer() == B_Cu ? B_SilkS : F_SilkS ); + std::string layer = GenCADLayerName( cu_count, + flipBottomLayers && module->GetLayer() == B_Cu ? B_SilkS : F_SilkS ); fprintf( aFile, "TEXT %g %g %g %g %s %s \"%s\"", textmod->GetPos0().x / SCALE_FACTOR,