From d9c7fdc28edd482acc9011162006036d2241725d Mon Sep 17 00:00:00 2001
From: Dominik Sliwa <dominik@sliwa.io>
Date: Tue, 20 Jul 2021 10:23:21 +0200
Subject: [PATCH] Pcbnew add SMD only option to component placement export

Add option to only use footprints flagged as SMD
when creating a componenet placement files.

Signed-off-by: Dominik Sliwa <dominik@sliwa.io>
---
 ...ialog_gen_footprint_position_file_base.cpp |  5 ++
 ...ialog_gen_footprint_position_file_base.fbp | 65 +++++++++++++++++++
 .../dialog_gen_footprint_position_file_base.h |  2 +
 .../exporters/export_footprints_placefile.cpp | 10 ++-
 .../exporters/export_footprints_placefile.h   | 11 ++--
 pcbnew/exporters/gen_footprints_placefile.cpp | 35 +++++++---
 pcbnew/pcb_edit_frame.h                       | 10 +--
 7 files changed, 119 insertions(+), 19 deletions(-)

diff --git a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.cpp b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.cpp
index 8db888adda..ee90cfb635 100644
--- a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.cpp
+++ b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.cpp
@@ -71,6 +71,9 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
 	wxBoxSizer* bSizerLower;
 	bSizerLower = new wxBoxSizer( wxVERTICAL );
 
+	m_onlySMD = new wxCheckBox( this, wxID_ANY, _("Include only SMD footprints"), wxDefaultPosition, wxDefaultSize, 0 );
+	bSizerLower->Add( m_onlySMD, 0, wxALL, 5 );
+
 	m_excludeTH = new wxCheckBox( this, wxID_ANY, _("Exclude all footprints with through hole pads"), wxDefaultPosition, wxDefaultSize, 0 );
 	bSizerLower->Add( m_excludeTH, 0, wxALL, 5 );
 
@@ -112,6 +115,7 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::DIALOG_GEN_FOOTPRINT_POSITION_BASE( wxWindow
 	m_rbFormat->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onSelectFormat ), NULL, this );
 	m_radioBoxUnits->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIUnits ), NULL, this );
 	m_radioBoxFilesCount->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIFileOpt ), NULL, this );
+	m_onlySMD->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIOnlySMD ), NULL, this );
 	m_excludeTH->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIExcludeTH ), NULL, this );
 	m_cbIncludeBoardEdge->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIincludeBoardEdge ), NULL, this );
 	m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::OnGenerate ), NULL, this );
@@ -124,6 +128,7 @@ DIALOG_GEN_FOOTPRINT_POSITION_BASE::~DIALOG_GEN_FOOTPRINT_POSITION_BASE()
 	m_rbFormat->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onSelectFormat ), NULL, this );
 	m_radioBoxUnits->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIUnits ), NULL, this );
 	m_radioBoxFilesCount->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIFileOpt ), NULL, this );
+	m_onlySMD->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIOnlySMD ), NULL, this );
 	m_excludeTH->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIExcludeTH ), NULL, this );
 	m_cbIncludeBoardEdge->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::onUpdateUIincludeBoardEdge ), NULL, this );
 	m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_GEN_FOOTPRINT_POSITION_BASE::OnGenerate ), NULL, this );
diff --git a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.fbp b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.fbp
index f2c1db101a..e53b6448cd 100644
--- a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.fbp
+++ b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.fbp
@@ -499,6 +499,71 @@
                         <property name="name">bSizerLower</property>
                         <property name="orient">wxVERTICAL</property>
                         <property name="permission">none</property>
+                        <object class="sizeritem" expanded="1">
+                            <property name="border">5</property>
+                            <property name="flag">wxALL</property>
+                            <property name="proportion">0</property>
+                            <object class="wxCheckBox" expanded="1">
+                                <property name="BottomDockable">1</property>
+                                <property name="LeftDockable">1</property>
+                                <property name="RightDockable">1</property>
+                                <property name="TopDockable">1</property>
+                                <property name="aui_layer"></property>
+                                <property name="aui_name"></property>
+                                <property name="aui_position"></property>
+                                <property name="aui_row"></property>
+                                <property name="best_size"></property>
+                                <property name="bg"></property>
+                                <property name="caption"></property>
+                                <property name="caption_visible">1</property>
+                                <property name="center_pane">0</property>
+                                <property name="checked">0</property>
+                                <property name="close_button">1</property>
+                                <property name="context_help"></property>
+                                <property name="context_menu">1</property>
+                                <property name="default_pane">0</property>
+                                <property name="dock">Dock</property>
+                                <property name="dock_fixed">0</property>
+                                <property name="docking">Left</property>
+                                <property name="enabled">1</property>
+                                <property name="fg"></property>
+                                <property name="floatable">1</property>
+                                <property name="font"></property>
+                                <property name="gripper">0</property>
+                                <property name="hidden">0</property>
+                                <property name="id">wxID_ANY</property>
+                                <property name="label">Include only SMD footprints</property>
+                                <property name="max_size"></property>
+                                <property name="maximize_button">0</property>
+                                <property name="maximum_size"></property>
+                                <property name="min_size"></property>
+                                <property name="minimize_button">0</property>
+                                <property name="minimum_size"></property>
+                                <property name="moveable">1</property>
+                                <property name="name">m_onlySMD</property>
+                                <property name="pane_border">1</property>
+                                <property name="pane_position"></property>
+                                <property name="pane_size"></property>
+                                <property name="permission">protected</property>
+                                <property name="pin_button">1</property>
+                                <property name="pos"></property>
+                                <property name="resize">Resizable</property>
+                                <property name="show">1</property>
+                                <property name="size"></property>
+                                <property name="style"></property>
+                                <property name="subclass">; forward_declare</property>
+                                <property name="toolbar_pane">0</property>
+                                <property name="tooltip"></property>
+                                <property name="validator_data_type"></property>
+                                <property name="validator_style">wxFILTER_NONE</property>
+                                <property name="validator_type">wxDefaultValidator</property>
+                                <property name="validator_variable"></property>
+                                <property name="window_extra_style"></property>
+                                <property name="window_name"></property>
+                                <property name="window_style"></property>
+                                <event name="OnUpdateUI">onUpdateUIOnlySMD</event>
+                            </object>
+                        </object>
                         <object class="sizeritem" expanded="1">
                             <property name="border">5</property>
                             <property name="flag">wxALL</property>
diff --git a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.h b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.h
index 8e133caba3..c8cda4d463 100644
--- a/pcbnew/dialogs/dialog_gen_footprint_position_file_base.h
+++ b/pcbnew/dialogs/dialog_gen_footprint_position_file_base.h
@@ -49,6 +49,7 @@ class DIALOG_GEN_FOOTPRINT_POSITION_BASE : public DIALOG_SHIM
 		wxRadioBox* m_rbFormat;
 		wxRadioBox* m_radioBoxUnits;
 		wxRadioBox* m_radioBoxFilesCount;
+		wxCheckBox* m_onlySMD;
 		wxCheckBox* m_excludeTH;
 		wxCheckBox* m_cbIncludeBoardEdge;
 		wxCheckBox* m_useDrillPlaceOrigin;
@@ -63,6 +64,7 @@ class DIALOG_GEN_FOOTPRINT_POSITION_BASE : public DIALOG_SHIM
 		virtual void onSelectFormat( wxCommandEvent& event ) { event.Skip(); }
 		virtual void onUpdateUIUnits( wxUpdateUIEvent& event ) { event.Skip(); }
 		virtual void onUpdateUIFileOpt( wxUpdateUIEvent& event ) { event.Skip(); }
+		virtual void onUpdateUIOnlySMD( wxUpdateUIEvent& event ) { event.Skip(); }
 		virtual void onUpdateUIExcludeTH( wxUpdateUIEvent& event ) { event.Skip(); }
 		virtual void onUpdateUIincludeBoardEdge( wxUpdateUIEvent& event ) { event.Skip(); }
 		virtual void OnGenerate( wxCommandEvent& event ) { event.Skip(); }
diff --git a/pcbnew/exporters/export_footprints_placefile.cpp b/pcbnew/exporters/export_footprints_placefile.cpp
index 74c985a83f..a8bb90eaf1 100644
--- a/pcbnew/exporters/export_footprints_placefile.cpp
+++ b/pcbnew/exporters/export_footprints_placefile.cpp
@@ -73,12 +73,13 @@ enum SELECT_SIDE
     PCB_BOTH_SIDES
 };
 
-PLACE_FILE_EXPORTER::PLACE_FILE_EXPORTER( BOARD* aBoard, bool aUnitsMM, bool aExcludeAllTH,
-                                          bool aTopSide, bool aBottomSide, bool aFormatCSV,
-                                          bool aUseAuxOrigin )
+PLACE_FILE_EXPORTER::PLACE_FILE_EXPORTER( BOARD* aBoard, bool aUnitsMM, bool aOnlySMD,
+                                          bool aExcludeAllTH, bool aTopSide, bool aBottomSide,
+                                          bool aFormatCSV, bool aUseAuxOrigin )
 {
     m_board        = aBoard;
     m_unitsMM      = aUnitsMM;
+    m_onlySMD      = aOnlySMD;
     m_excludeAllTH = aExcludeAllTH;
     m_fpCount      = 0;
 
@@ -134,6 +135,9 @@ std::string PLACE_FILE_EXPORTER::GenPositionData()
         if( footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
             continue;
 
+        if( m_onlySMD && !( footprint->GetAttributes() & FP_SMD ) )
+            continue;
+
         if( m_excludeAllTH && footprint->HasThroughHolePads() )
             continue;
 
diff --git a/pcbnew/exporters/export_footprints_placefile.h b/pcbnew/exporters/export_footprints_placefile.h
index e55a2b8800..fa523d6af9 100644
--- a/pcbnew/exporters/export_footprints_placefile.h
+++ b/pcbnew/exporters/export_footprints_placefile.h
@@ -55,14 +55,16 @@ public:
     /** Create a PLACE_FILE_EXPORTER
      * @param aBoard is the board
      * @param aUnitsMM is the unit option: true foo mm, false for inches
-     * @param aForceSmdItems true to force not virtual and not flagged smd footprints
-     * but having only smd pads to be in list
+     * @param aOnlySMD true to force only footprints flagged smd to be in the list
+     * @param aExcludeAllTH true to include only footprints with no TH pads no matter
+     *                      the footprint flag
      * @param aTopSide true to generate top side info
      * @param aBottomSide true to generate bottom side info
      * @param aFormatCSV true to generate a csv format info, false to generate a ascii info
+     * @param aUseAuxOrigin true to use auxiliary axis as an origin for the position data
      */
-    PLACE_FILE_EXPORTER( BOARD* aBoard,  bool aUnitsMM, bool aForceSmdItems, bool aTopSide,
-                         bool aBottomSide, bool aFormatCSV, bool useAuxOrigin );
+    PLACE_FILE_EXPORTER( BOARD* aBoard, bool aUnitsMM, bool aOnlySMD, bool aExcludeAllTH,
+                         bool aTopSide, bool aBottomSide, bool aFormatCSV, bool aUseAuxOrigin );
 
     /**
      * build a string filled with the position data
@@ -90,6 +92,7 @@ public:
 private:
     BOARD*  m_board;
     bool    m_unitsMM;        // true for mm, false for inches
+    bool    m_onlySMD;        // Include only SMD components
     bool    m_excludeAllTH;   // Exclude any footprints with through-hole pads
     int     m_side;           // PCB_BACK_SIDE, PCB_FRONT_SIDE, PCB_BOTH_SIDES
     bool    m_formatCSV;      // true for csv format, false for ascii (utf8) format
diff --git a/pcbnew/exporters/gen_footprints_placefile.cpp b/pcbnew/exporters/gen_footprints_placefile.cpp
index b990dedd32..06598745b8 100644
--- a/pcbnew/exporters/gen_footprints_placefile.cpp
+++ b/pcbnew/exporters/gen_footprints_placefile.cpp
@@ -89,6 +89,19 @@ private:
         m_radioBoxFilesCount->Enable( m_rbFormat->GetSelection() != 2 );
     }
 
+	void onUpdateUIOnlySMD( wxUpdateUIEvent& event ) override
+    {
+        if( m_rbFormat->GetSelection() == 2 )
+        {
+            m_onlySMD->SetValue( false );
+            m_onlySMD->Enable( false );
+        }
+        else
+        {
+            m_onlySMD->Enable( true );
+        }
+    }
+
 	void onUpdateUIExcludeTH( wxUpdateUIEvent& event ) override
     {
         if( m_rbFormat->GetSelection() == 2 )
@@ -128,6 +141,11 @@ private:
         return m_radioBoxFilesCount->GetSelection() == 1;
     }
 
+    bool OnlySMD()
+    {
+        return m_onlySMD->GetValue();
+    }
+
     bool ExcludeAllTH()
     {
         return m_excludeTH->GetValue();
@@ -331,8 +349,8 @@ bool DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles()
 
     // Test for any footprint candidate in list.
     {
-        PLACE_FILE_EXPORTER exporter( brd, UnitsMM(), ExcludeAllTH(), topSide, bottomSide,
-                                      useCSVfmt, useAuxOrigin );
+        PLACE_FILE_EXPORTER exporter( brd, UnitsMM(), OnlySMD(), ExcludeAllTH(), topSide,
+                                      bottomSide, useCSVfmt, useAuxOrigin );
         exporter.GenPositionData();
 
         if( exporter.GetFootprintCount() == 0 )
@@ -386,7 +404,7 @@ bool DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles()
         fn.SetExt( FootprintPlaceFileExtension );
     }
 
-    int fpcount = m_parent->DoGenFootprintsPositionFile( fn.GetFullPath(), UnitsMM(),
+    int fpcount = m_parent->DoGenFootprintsPositionFile( fn.GetFullPath(), UnitsMM(), OnlySMD(),
                                                          ExcludeAllTH(), topSide, bottomSide,
                                                          useCSVfmt, useAuxOrigin );
     if( fpcount < 0 )
@@ -431,8 +449,9 @@ bool DIALOG_GEN_FOOTPRINT_POSITION::CreateAsciiFiles()
         fn.SetExt( FootprintPlaceFileExtension );
     }
 
-    fpcount = m_parent->DoGenFootprintsPositionFile( fn.GetFullPath(), UnitsMM(), ExcludeAllTH(),
-                                                     topSide, bottomSide, useCSVfmt, useAuxOrigin );
+    fpcount = m_parent->DoGenFootprintsPositionFile( fn.GetFullPath(), UnitsMM(), OnlySMD(),
+                                                     ExcludeAllTH(), topSide, bottomSide, useCSVfmt,
+                                                     useAuxOrigin );
 
     if( fpcount < 0 )
     {
@@ -476,7 +495,7 @@ int BOARD_EDITOR_CONTROL::GeneratePosFile( const TOOL_EVENT& aEvent )
 
 
 int PCB_EDIT_FRAME::DoGenFootprintsPositionFile( const wxString& aFullFileName, bool aUnitsMM,
-                                                 bool aForceSmdItems, bool aTopSide,
+                                                 bool aOnlySMD, bool aNoTHItems, bool aTopSide,
                                                  bool aBottomSide, bool aFormatCSV,
                                                  bool aUseAuxOrigin )
 {
@@ -491,7 +510,7 @@ int PCB_EDIT_FRAME::DoGenFootprintsPositionFile( const wxString& aFullFileName,
     }
 
     std::string data;
-    PLACE_FILE_EXPORTER exporter( GetBoard(), aUnitsMM, aForceSmdItems, aTopSide, aBottomSide,
+    PLACE_FILE_EXPORTER exporter( GetBoard(), aUnitsMM, aOnlySMD, aNoTHItems, aTopSide, aBottomSide,
                                   aFormatCSV, aUseAuxOrigin );
     data = exporter.GenPositionData();
 
@@ -552,7 +571,7 @@ bool PCB_EDIT_FRAME::DoGenFootprintsReport( const wxString& aFullFilename, bool
         return false;
 
     std::string data;
-    PLACE_FILE_EXPORTER exporter( GetBoard(), aUnitsMM, false, true, true, false, true );
+    PLACE_FILE_EXPORTER exporter( GetBoard(), aUnitsMM, false, false, true, true, false, true );
     data = exporter.GenReportData();
 
     fputs( data.c_str(), rptfile );
diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h
index 00ef3a14b2..b3d8f89e81 100644
--- a/pcbnew/pcb_edit_frame.h
+++ b/pcbnew/pcb_edit_frame.h
@@ -282,16 +282,18 @@ public:
      *
      * @param aFullFileName the full file name of the file to create.
      * @param aUnitsMM false to use inches, true to use mm in coordinates.
-     * @param aForceSmdItems true to force all footprints with smd pads in list,
-     *                       false to put only footprints with option "INSERT" in list
+     * @param aOnlySMD true to force only footprints flagged smd to be in the list
+     * @param aNoTHItems true to include only footprints with no TH pads no matter
+     *                   the footprint flag
      * @param aTopSide true to list footprints on front (top) side.
      * @param aBottomSide true to list footprints on back (bottom) side, if \a aTopSide and
      *                    \a aTopSide are true, list footprints on both sides.
      * @param aFormatCSV true to use a comma separated file (CSV) format; default = false
+     * @param aUseAuxOrigin true to use auxiliary axis as an origin for the position data
      * @return the number of footprints found on aSide side or -1 if the file could not be created.
      */
-    int DoGenFootprintsPositionFile( const wxString& aFullFileName, bool aUnitsMM,
-                                     bool aForceSmdItems, bool aTopSide, bool aBottomSide,
+    int DoGenFootprintsPositionFile( const wxString& aFullFileName, bool aUnitsMM, bool aOnlySMD,
+                                     bool aNoTHItems, bool aTopSide, bool aBottomSide,
                                      bool aFormatCSV, bool aUseAuxOrigin );
 
     /**