ADDED support for pin and fp filtering in FOOTPRINT_CHOOSER.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7176
This commit is contained in:
Jeff Young 2023-09-29 17:02:57 +01:00
parent 98685b37ff
commit fa11e9138d
27 changed files with 367 additions and 194 deletions

View File

@ -34,10 +34,10 @@
static const unsigned kLowestDefaultScore = 1;
void LIB_TREE_NODE::ResetScore()
void LIB_TREE_NODE::ResetScore( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
{
for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
child->ResetScore();
child->ResetScore( aFilter );
m_Score = kLowestDefaultScore;
}
@ -175,6 +175,7 @@ LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITE
m_Name = aItem->GetName();
m_Desc = aItem->GetDescription();
m_Footprint = aItem->GetFootprint();
m_PinCount = aItem->GetPinCount();
aItem->GetChooserFields( m_Fields );
@ -218,7 +219,21 @@ void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
}
void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
void LIB_TREE_NODE_LIB_ID::ResetScore( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
{
for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
child->ResetScore( aFilter );
if( !aFilter )
m_Score = kLowestDefaultScore;
else if( (*aFilter)(*this) )
m_Score = kLowestDefaultScore + 1;
else
m_Score = 0;
}
void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib )
{
if( m_Score <= 0 )
return; // Leaf nodes without scores are out of the game.
@ -229,7 +244,8 @@ void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wx
return;
}
m_Score = aMatcher.ScoreTerms( m_SearchTerms );
if( aMatcher )
m_Score = aMatcher->ScoreTerms( m_SearchTerms );
}
@ -252,7 +268,7 @@ LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddItem( LIB_TREE_ITEM* aItem )
}
void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib )
{
m_Score = 0;
@ -266,11 +282,11 @@ void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxStr
m_Score = std::max( m_Score, child->m_Score );
}
}
else
else if( aMatcher )
{
// No children; we are a leaf.
m_Score = aMatcher.ScoreTerms( m_SearchTerms );
m_Score = aMatcher->ScoreTerms( m_SearchTerms );
}
}
@ -289,7 +305,7 @@ LIB_TREE_NODE_LIB& LIB_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString c
}
void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib )
{
for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
child->UpdateScore( aMatcher, aLib );

View File

@ -49,12 +49,12 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ToNode( wxDataViewItem aItem )
LIB_TREE_MODEL_ADAPTER::LIB_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent,
const wxString& aPinnedKey ) :
m_parent( aParent ),
m_filter( SYM_FILTER_NONE ),
m_sort_mode( BEST_MATCH ),
m_show_units( true ),
m_preselect_unit( 0 ),
m_freeze( 0 ),
m_widget( nullptr )
m_widget( nullptr ),
m_filter( nullptr )
{
// Default column widths. Do not translate these names.
m_colWidths[ _HKI( "Item" ) ] = 300;
@ -96,12 +96,6 @@ void LIB_TREE_MODEL_ADAPTER::SaveSettings()
}
void LIB_TREE_MODEL_ADAPTER::SetFilter( SYM_FILTER_TYPE aFilter )
{
m_filter = aFilter;
}
void LIB_TREE_MODEL_ADAPTER::ShowUnits( bool aShow )
{
m_show_units = aShow;
@ -171,24 +165,31 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
Freeze();
BeforeReset();
m_tree.ResetScore();
m_tree.ResetScore( m_filter );
wxStringTokenizer tokenizer( aSearch );
while( tokenizer.HasMoreTokens() )
if( tokenizer.HasMoreTokens() )
{
wxString lib;
wxString term = tokenizer.GetNextToken().Lower();
if( term.Contains( ":" ) )
while( tokenizer.HasMoreTokens() )
{
lib = term.BeforeFirst( ':' );
term = term.AfterFirst( ':' );
wxString lib;
wxString term = tokenizer.GetNextToken().Lower();
if( term.Contains( ":" ) )
{
lib = term.BeforeFirst( ':' );
term = term.AfterFirst( ':' );
}
EDA_COMBINED_MATCHER matcher( term, CTX_LIBITEM );
m_tree.UpdateScore( &matcher, lib );
}
EDA_COMBINED_MATCHER matcher( term, CTX_LIBITEM );
m_tree.UpdateScore( matcher, lib );
}
else
{
m_tree.UpdateScore( nullptr, wxEmptyString );
}
m_tree.SortNodes( m_sort_mode == BEST_MATCH );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 CERN
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -271,7 +271,7 @@ protected:
if( !m_symbolNetlist.empty() )
{
KIWAY_EXPRESS event( FRAME_FOOTPRINT_VIEWER, MAIL_SYMBOL_NETLIST, m_symbolNetlist );
KIWAY_EXPRESS event( FRAME_FOOTPRINT_CHOOSER, MAIL_SYMBOL_NETLIST, m_symbolNetlist );
frame->KiwayMailIn( event );
}
@ -281,17 +281,14 @@ protected:
frame->Destroy();
}
protected:
DIALOG_SHIM* m_dlg;
wxString m_preselect;
/*
* Symbol netlist format:
* library:footprint
* reference
* value
* pinName,netName,pinFunction,pinType
* pinName,netName,pinFunction,pinType
* ...
* pinCount
* fpFilters
*/
std::string m_symbolNetlist;
};

View File

@ -64,27 +64,19 @@ static wxString netList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH& aSheetPath )
{
/*
* Symbol netlist format:
* library:footprint
* reference
* value
* pinName,netName,pinFunction,pinType
* pinName,netName,pinFunction,pinType
* ...
* pinCount
* fpFilters
*/
wxString netlist;
netlist << EscapeString( aSymbol->GetFootprintFieldText( true, &aSheetPath, false ), CTX_LINE ) << wxS( "\r" );
netlist << EscapeString( aSymbol->GetRef( &aSheetPath ), CTX_LINE ) << wxS( "\r" );
netlist << EscapeString( aSymbol->GetValueFieldText( true, &aSheetPath, false ), CTX_LINE );
netlist << wxString::Format( wxS( "%d\r" ), aSymbol->GetPins().size() );
for( SCH_PIN* pin : aSymbol->GetPins( &aSheetPath ) )
{
netlist << wxS( "\r" );
netlist << EscapeString( pin->GetNumber(), CTX_CSV ) << wxS( "," );
netlist << EscapeString( pin->GetDefaultNetName( aSheetPath ), CTX_CSV ) << wxS( "," );
netlist << EscapeString( pin->GetName(), CTX_CSV ) << wxS( "," );
netlist << EscapeString( pin->GetCanonicalElectricalTypeName(), CTX_CSV );
}
wxArrayString fpFilters = aSymbol->GetLibSymbolRef()->GetFPFilters();
if( !fpFilters.IsEmpty() )
netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
netlist << wxS( "\r" );
return netlist;
}

View File

@ -456,7 +456,7 @@ public:
/**
* @return a count of pins for all units / converts.
*/
size_t GetFullPinCount() { return GetAllLibPins().size(); }
int GetPinCount() override { return GetAllLibPins().size(); }
/**
* Return pin object with the requested pin \a aNumber.

View File

@ -399,6 +399,18 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
xproperty->AddAttribute( wxT( "name" ), wxT( "ki_keywords" ) );
xproperty->AddAttribute( wxT( "value" ), part->GetKeyWords() );
}
if( !part->GetFPFilters().IsEmpty() )
{
wxString filters;
for( const wxString& filter : part->GetFPFilters() )
filters += ' ' + filter;
xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
xproperty->AddAttribute( wxT( "name" ), wxT( "ki_fp_filters" ) );
xproperty->AddAttribute( wxT( "value" ), filters.Trim( false ) );
}
}
XNODE* xsheetpath;

View File

@ -61,7 +61,7 @@ public:
* see SCH_BASE_FRAME::SelectSymbolFromLibrary() for details.
* if aFilter == NULL, remove all filtering.
*/
void SetFilter( const SYMBOL_LIBRARY_FILTER* aFilter );
void SetFilter( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter );
private:
void OnPaint( wxPaintEvent& aEvent );

View File

@ -80,9 +80,8 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
std::unordered_map<wxString, std::vector<LIB_SYMBOL*>> loadedSymbols;
SYMBOL_ASYNC_LOADER loader( aNicknames, m_libs,
GetFilter() == LIB_TREE_MODEL_ADAPTER::SYM_FILTER_POWER,
&loadedSymbols, progressReporter.get() );
SYMBOL_ASYNC_LOADER loader( aNicknames, m_libs, GetFilter() != nullptr, &loadedSymbols,
progressReporter.get() );
LOCALE_IO toggle;
@ -204,7 +203,7 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
void SYMBOL_TREE_MODEL_ADAPTER::AddLibrary( wxString const& aLibNickname, bool pinned )
{
bool onlyPowerSymbols = ( GetFilter() == SYM_FILTER_POWER );
bool onlyPowerSymbols = ( GetFilter() != nullptr );
std::vector<LIB_SYMBOL*> symbols;
std::vector<LIB_TREE_ITEM*> comp_list;

View File

@ -102,7 +102,17 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
if( aFilter->GetFilterPowerSymbols() )
{
adapter->SetFilter( SYMBOL_TREE_MODEL_ADAPTER::SYM_FILTER_POWER );
// Note: there is only a single filter ever used for symbols (the power filter),
// so the code simply sets a flag based on the filter being non-null. The filter
// is not (at present) actually called.
static std::function<bool( LIB_TREE_NODE& )> powerFilter =
[]( LIB_TREE_NODE& ) -> bool
{
return true;
};
adapter->SetFilter( &powerFilter );
m_showPower = true;
m_show_footprints = false;
}

View File

@ -72,6 +72,8 @@ public:
wxString GetName() const override { return m_fpname; }
int GetPinCount() override { return GetUniquePadCount(); }
LIB_ID GetLibId() const override
{
return LIB_ID( m_nickname, m_fpname );

View File

@ -68,6 +68,11 @@ public:
*/
virtual wxString GetFootprint() { return wxEmptyString; }
/**
* The pin count for symbols or the unique pad count for footprints.
*/
virtual int GetPinCount() { return 0; }
/**
* For items with units, return the number of units.
*/

View File

@ -80,12 +80,12 @@ public:
*
* @param aMatcher an EDA_COMBINED_MATCHER initialized with the search term
*/
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) = 0;
virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib ) = 0;
/**
* Initialize score to kLowestDefaultScore, recursively.
*/
void ResetScore();
virtual void ResetScore( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter );
/**
* Store intrinsic ranks on all children of this node. See m_IntrinsicRank
@ -135,6 +135,7 @@ public:
wxString m_Name; // Actual name of the part
wxString m_Desc; // Description to be displayed
wxString m_Footprint; // Footprint ID as a string (ie: the footprint field text)
int m_PinCount; // Pin count from symbol, or unique pad count from footprint
std::vector<SEARCH_TERM> m_SearchTerms; /// List of weighted search terms
std::map<wxString, wxString> m_Fields; /// @see LIB_TREE_ITEMS::GetChooserFields
@ -174,7 +175,7 @@ public:
/**
* Do nothing, units just take the parent's score
*/
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override {}
virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib ) override {}
};
@ -210,10 +211,12 @@ public:
*/
void Update( LIB_TREE_ITEM* aItem );
void ResetScore( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter ) override;
/**
* Perform the actual search.
*/
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override;
virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib ) override;
protected:
/**
@ -254,7 +257,7 @@ public:
*/
LIB_TREE_NODE_LIB_ID& AddItem( LIB_TREE_ITEM* aItem );
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override;
virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib ) override;
};
@ -281,7 +284,7 @@ public:
*/
LIB_TREE_NODE_LIB& AddLib( wxString const& aName, wxString const& aDesc );
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override;
virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib ) override;
};

View File

@ -114,15 +114,6 @@ public:
*/
~LIB_TREE_MODEL_ADAPTER();
/**
* This enum allows a selective filtering of symbols to list
*/
enum SYM_FILTER_TYPE
{
SYM_FILTER_NONE, ///< no filtering
SYM_FILTER_POWER, ///< list symbols flagged PWR
};
/**
* This enum defines the order of the default columns in the tree view
*/
@ -150,12 +141,12 @@ public:
*
* @param aFilter if SYM_FILTER_POWER, only power parts are loaded
*/
void SetFilter( SYM_FILTER_TYPE aFilter );
void SetFilter( std::function<bool( LIB_TREE_NODE& aNode )>* aFilter ) { m_filter = aFilter; }
/**
* Return the active filter.
*/
SYM_FILTER_TYPE GetFilter() const { return m_filter; }
std::function<bool( LIB_TREE_NODE& aNode )>* GetFilter() const { return m_filter; }
void SetSortMode( SORT_MODE aMode ) { m_sort_mode = aMode; }
SORT_MODE GetSortMode() const { return m_sort_mode; }
@ -397,11 +388,6 @@ protected:
void resortTree();
private:
/**
* Find any results worth highlighting and expand them.
*/
void Find( LIB_TREE_NODE& aNode, std::function<bool( const LIB_TREE_NODE* )> aFunc );
/**
* Find and expand successful search results. Return the best match (if any).
*/
@ -419,21 +405,22 @@ protected:
std::vector<wxString> m_availableColumns;
private:
EDA_BASE_FRAME* m_parent;
EDA_BASE_FRAME* m_parent;
SYM_FILTER_TYPE m_filter;
SORT_MODE m_sort_mode;
bool m_show_units;
LIB_ID m_preselect_lib_id;
int m_preselect_unit;
int m_freeze;
SORT_MODE m_sort_mode;
bool m_show_units;
LIB_ID m_preselect_lib_id;
int m_preselect_unit;
int m_freeze;
wxDataViewCtrl* m_widget;
wxDataViewCtrl* m_widget;
std::vector<wxDataViewColumn*> m_columns;
std::map<wxString, wxDataViewColumn*> m_colNameMap;
std::map<wxString, int> m_colWidths;
std::vector<wxString> m_shownColumns; // Stored in display order
std::function<bool( LIB_TREE_NODE& aNode )>* m_filter;
std::vector<wxDataViewColumn*> m_columns;
std::map<wxString, wxDataViewColumn*> m_colNameMap;
std::map<wxString, int> m_colWidths;
std::vector<wxString> m_shownColumns; // Stored in display order
};
#endif // LIB_TREE_MODEL_ADAPTER_H

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 CERN
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.TXT for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -42,7 +42,7 @@ enum MAIL_T
MAIL_ASSIGN_FOOTPRINTS, // CVPCB->SCH footprint stuffing
MAIL_SCH_SAVE, // CVPCB->SCH save the schematic
MAIL_EESCHEMA_NETLIST, // SCH->CVPCB netlist immediately after launching CVPCB
MAIL_SYMBOL_NETLIST, // SCH->FP_VIEWER symbol pin information
MAIL_SYMBOL_NETLIST, // SCH->FP_CHOOSER symbol pin & fp_filter information
MAIL_PCB_UPDATE, // SCH->PCB forward update
MAIL_SCH_UPDATE, // PCB->SCH forward update
MAIL_IMPORT_FILE, // Import a different format file

View File

@ -4,7 +4,7 @@
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,6 +30,7 @@
#include <dialog_exchange_footprints.h>
#include <string_utils.h>
#include <kiway.h>
#include <kiway_express.h>
#include <macros.h>
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
@ -403,6 +404,23 @@ void DIALOG_EXCHANGE_FOOTPRINTS::ViewAndSelectFootprint( wxCommandEvent& event )
KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true );
if( m_currentFootprint )
{
/*
* Symbol netlist format:
* pinCount
* fpFilters
*/
wxString netlist;
netlist << wxString::Format( wxS( "%ld\r" ), m_currentFootprint->Pads().size() );
netlist << EscapeString( m_currentFootprint->GetFilters(), CTX_LINE ) << wxS( "\r" );
std::string payload( netlist.ToStdString() );
KIWAY_EXPRESS mail( FRAME_FOOTPRINT_CHOOSER, MAIL_SYMBOL_NETLIST, payload );
frame->KiwayMailIn( mail );
}
if( frame->ShowModal( &newname, this ) )
{
if( event.GetEventObject() == m_newIDBrowseButton )

View File

@ -36,10 +36,16 @@ DIALOG_FOOTPRINT_CHOOSER::DIALOG_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aParent,
{
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
m_chooserPanel = new PANEL_FOOTPRINT_CHOOSER( aParent, this, aFootprintHistoryList,
[this]()
{
EndModal( wxID_OK );
} );
// Filter
[]( LIB_TREE_NODE& aNode ) -> bool
{
return true;
},
// Close handler
[this]()
{
EndModal( wxID_OK );
} );
sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 );

View File

@ -248,6 +248,9 @@ public:
wxString GetSheetfile() const { return m_sheetfile; }
void SetSheetfile( const wxString& aSheetfile ) { m_sheetfile = aSheetfile; }
wxString GetFilters() const { return m_filters; }
void SetFilters( const wxString& aFilters ) { m_filters = aFilters; }
int GetLocalSolderMaskMargin() const { return m_localSolderMaskMargin; }
void SetLocalSolderMaskMargin( int aMargin ) { m_localSolderMaskMargin = aMargin; }
@ -983,6 +986,7 @@ private:
KIID_PATH m_path; // Path to associated symbol ([sheetUUID, .., symbolUUID]).
wxString m_sheetname; // Name of the sheet containing the symbol for this footprint
wxString m_sheetfile; // File of the sheet containing the symbol for this footprint
wxString m_filters; // Footprint filters from symbol
timestamp_t m_lastEditTime;
int m_arflag; // Use to trace ratsnest and auto routing.
KIID m_link; // Temporary logical link used during editing

View File

@ -22,9 +22,11 @@
*/
#include <pgm_base.h>
#include <kiface_base.h>
#include <kiway.h>
#include <kiway_express.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <kiplatform/ui.h>
#include <widgets/panel_footprint_chooser.h>
#include <settings/settings_manager.h>
@ -38,7 +40,7 @@ static unsigned s_FootprintHistoryMaxCount = 8;
static void AddFootprintToHistory( const wxString& aName )
{
// Remove duplicates
for( int ii = s_FootprintHistoryList.GetCount() - 1; ii >= 0; --ii )
for( int ii = (int) s_FootprintHistoryList.GetCount() - 1; ii >= 0; --ii )
{
if( s_FootprintHistoryList[ ii ] == aName )
s_FootprintHistoryList.RemoveAt( (size_t) ii );
@ -54,9 +56,9 @@ static void AddFootprintToHistory( const wxString& aName )
BEGIN_EVENT_TABLE( FOOTPRINT_CHOOSER_FRAME, PCB_BASE_FRAME )
EVT_MENU( wxID_CLOSE, FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser )
EVT_MENU( wxID_CLOSE, FOOTPRINT_CHOOSER_FRAME::closeFootprintChooser )
EVT_BUTTON( wxID_OK, FOOTPRINT_CHOOSER_FRAME::OnOK )
EVT_BUTTON( wxID_CANCEL, FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser )
EVT_BUTTON( wxID_CANCEL, FOOTPRINT_CHOOSER_FRAME::closeFootprintChooser )
EVT_PAINT( FOOTPRINT_CHOOSER_FRAME::OnPaint )
END_EVENT_TABLE()
@ -68,31 +70,62 @@ END_EVENT_TABLE()
FOOTPRINT_CHOOSER_FRAME::FOOTPRINT_CHOOSER_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
PCB_BASE_FRAME( aKiway, aParent, FRAME_FOOTPRINT_CHOOSER, _( "Footprint Chooser" ),
wxDefaultPosition, wxDefaultSize, aParent ? PARENT_STYLE : MODAL_STYLE,
FOOTPRINT_CHOOSER_FRAME_NAME ),
m_comp( LIB_ID(), wxEmptyString, wxEmptyString, KIID_PATH(), {} )
PCB_BASE_FRAME( aKiway, aParent, FRAME_FOOTPRINT_CHOOSER, _( "Footprint Chooser" ),
wxDefaultPosition, wxDefaultSize, aParent ? PARENT_STYLE : MODAL_STYLE,
FOOTPRINT_CHOOSER_FRAME_NAME ),
m_filterByPinCount( nullptr ),
m_filterByFPFilters( nullptr ),
m_pinCount( 0 )
{
SetModal( true );
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
m_chooserPanel = new PANEL_FOOTPRINT_CHOOSER( this, this, s_FootprintHistoryList,
[this]()
{
wxCommandEvent dummy;
OnOK( dummy );
} );
// Filter
[this]( LIB_TREE_NODE& aNode ) -> bool
{
return filterFootprint( aNode );
},
// Close handler
[this]()
{
wxCommandEvent dummy;
OnOK( dummy );
} );
sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 );
wxBoxSizer* fpFilterSizer = new wxBoxSizer( wxVERTICAL );
m_filterByFPFilters = new wxCheckBox( this, wxID_ANY, _( "Apply footprint filters" ) );
fpFilterSizer->Add( m_filterByFPFilters, 0, wxTOP | wxEXPAND, 8 );
m_filterByFPFilters->Show( false );
sizer->Add( fpFilterSizer, 0, wxEXPAND | wxLEFT, 10 );
wxBoxSizer* buttonsSizer = new wxBoxSizer( wxHORIZONTAL );
m_filterByPinCount = new wxCheckBox( this, wxID_ANY, _( "Filter by pin count" ) );
buttonsSizer->Add( m_filterByPinCount, 0, wxLEFT | wxTOP | wxALIGN_TOP, 5 );
m_filterByPinCount->Show( false );
if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
{
m_filterByFPFilters->SetValue( cfg->m_FootprintChooser.use_fp_filters );
m_filterByPinCount->SetValue( cfg->m_FootprintChooser.filter_on_pin_count );
}
wxStdDialogButtonSizer* sdbSizer = new wxStdDialogButtonSizer();
wxButton* okButton = new wxButton( this, wxID_OK );
wxButton* cancelButton = new wxButton( this, wxID_CANCEL );
sdbSizer->AddButton( okButton );
sdbSizer->AddButton( cancelButton );
sdbSizer->Realize();
sizer->Add( sdbSizer, 0, wxEXPAND | wxALL, 5 );
buttonsSizer->Add( sdbSizer, 1, wxALL, 5 );
sizer->Add( buttonsSizer, 0, wxEXPAND | wxLEFT, 5 );
SetSizer( sizer );
SetTitle( GetTitle() + wxString::Format( _( " (%d items loaded)" ),
@ -100,6 +133,61 @@ FOOTPRINT_CHOOSER_FRAME::FOOTPRINT_CHOOSER_FRAME( KIWAY* aKiway, wxWindow* aPare
Layout();
m_chooserPanel->FinishSetup();
m_filterByPinCount->Bind( wxEVT_CHECKBOX,
[&]( wxCommandEvent& evt )
{
m_chooserPanel->Regenerate();
} );
m_filterByFPFilters->Bind( wxEVT_CHECKBOX,
[&]( wxCommandEvent& evt )
{
m_chooserPanel->Regenerate();
} );
}
FOOTPRINT_CHOOSER_FRAME::~FOOTPRINT_CHOOSER_FRAME()
{
if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
{
cfg->m_FootprintChooser.use_fp_filters = m_filterByFPFilters->GetValue();
cfg->m_FootprintChooser.filter_on_pin_count = m_filterByPinCount->GetValue();
}
}
bool FOOTPRINT_CHOOSER_FRAME::filterFootprint( LIB_TREE_NODE& aNode )
{
if( m_pinCount > 0 && m_filterByPinCount->GetValue() )
{
if( aNode.m_PinCount != m_pinCount )
return false;
}
if( !m_fpFilters.empty() && m_filterByFPFilters->GetValue() )
{
// The matching is case insensitive
wxString name;
for( const std::unique_ptr<EDA_PATTERN_MATCH>& each_filter : m_fpFilters )
{
name.Empty();
// If the filter contains a ':' character, include the library name in the pattern
if( each_filter->GetPattern().Contains( wxS( ":" ) ) )
name = aNode.m_LibId.GetUniStringLibNickname().Lower() + wxS( ":" );
name += aNode.m_LibId.GetUniStringLibItemName().Lower();
if( each_filter->Find( name ) )
return true;
}
return false;
}
return true;
}
@ -136,44 +224,48 @@ COLOR_SETTINGS* FOOTPRINT_CHOOSER_FRAME::GetColorSettings( bool aForceRefresh )
void FOOTPRINT_CHOOSER_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
{
// JEY TODO: don't delete this just yet. We can use it to pass in symbol info so that we
// can filter on footprint filters, symbol pin count, etc.
const std::string& payload = mail.GetPayload();
switch( mail.Command() )
{
case MAIL_SYMBOL_NETLIST:
{
m_pinCount = 0;
m_fpFilters.clear();
/*
* Symbol netlist format:
* library:footprint
* reference
* value
* pinName,netName,pinFunction,pinType
* pinName,netName,pinFunction,pinType
* ...
* pinCount
* fpFilters
*/
std::vector<std::string> strings = split( payload, "\r" );
LIB_ID libid;
if( strings.size() >= 3 )
if( strings.size() >= 1 )
{
libid.Parse( strings[0] );
wxString pinCountStr( strings[0] );
pinCountStr.ToInt( &m_pinCount );
m_comp.SetFPID( libid );
m_comp.SetReference( strings[1] );
m_comp.SetValue( strings[2] );
m_comp.ClearNets();
for( size_t ii = 3; ii < strings.size(); ++ii )
if( m_pinCount > 0 )
{
std::vector<std::string> pinData = split( strings[ii], "," );
m_comp.AddNet( pinData[0], pinData[1], pinData[2], pinData[3] );
m_filterByPinCount->SetLabel( m_filterByPinCount->GetLabel()
+ wxString::Format( wxS( " (%d)" ), m_pinCount ) );
m_filterByPinCount->Show( true );
}
}
if( strings.size() >= 2 && !strings[1].empty() )
{
for( const wxString& filter : wxSplit( strings[1], ' ' ) )
{
m_fpFilters.push_back( std::make_unique<EDA_PATTERN_MATCH_WILDCARD_ANCHORED>() );
m_fpFilters.back()->SetPattern( filter.Lower() );
}
m_filterByFPFilters->SetLabel( m_filterByFPFilters->GetLabel()
+ wxString::Format( wxS( " (%s)" ), strings[1] ) );
m_filterByFPFilters->Show( true );
}
break;
}
@ -231,7 +323,7 @@ void FOOTPRINT_CHOOSER_FRAME::OnOK( wxCommandEvent& aEvent )
}
void FOOTPRINT_CHOOSER_FRAME::CloseFootprintChooser( wxCommandEvent& aEvent )
void FOOTPRINT_CHOOSER_FRAME::closeFootprintChooser( wxCommandEvent& aEvent )
{
Close( false );
}

View File

@ -31,6 +31,7 @@
#include <netlist_reader/pcb_netlist.h>
class PANEL_FOOTPRINT_CHOOSER;
class wxCheckBox;
namespace PCB { struct IFACE; }
@ -38,7 +39,7 @@ namespace PCB { struct IFACE; }
class FOOTPRINT_CHOOSER_FRAME : public PCB_BASE_FRAME
{
public:
~FOOTPRINT_CHOOSER_FRAME() {};
~FOOTPRINT_CHOOSER_FRAME();
///< @copydoc PCB_BASE_FRAME::GetModel()
BOARD_ITEM_CONTAINER* GetModel() const override { return nullptr; }
@ -55,11 +56,13 @@ protected:
FOOTPRINT_CHOOSER_FRAME( KIWAY* aKiway, wxWindow* aParent );
private:
bool filterFootprint( LIB_TREE_NODE& aNode );
void OnPaint( wxPaintEvent& aEvent );
void OnOK( wxCommandEvent& aEvent );
void doCloseWindow() override;
void CloseFootprintChooser( wxCommandEvent& aEvent );
void closeFootprintChooser( wxCommandEvent& aEvent );
WINDOW_SETTINGS* GetWindowSettings( APP_SETTINGS_BASE* aCfg ) override;
COLOR_SETTINGS* GetColorSettings( bool aForceRefresh ) const override;
@ -70,7 +73,11 @@ private:
private:
PANEL_FOOTPRINT_CHOOSER* m_chooserPanel;
COMPONENT m_comp;
wxCheckBox* m_filterByPinCount;
wxCheckBox* m_filterByFPFilters;
int m_pinCount;
std::vector<std::unique_ptr<EDA_PATTERN_MATCH>> m_fpFilters;
// On MacOS (at least) SetFocus() calls made in the constructor will fail because a
// window that isn't yet visible will return false to AcceptsFocus(). So we must delay

View File

@ -954,51 +954,14 @@ void FOOTPRINT_VIEWER_FRAME::ReloadFootprint( FOOTPRINT* aFootprint )
void FOOTPRINT_VIEWER_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
{
const std::string& payload = mail.GetPayload();
switch( mail.Command() )
{
case MAIL_SYMBOL_NETLIST:
{
/*
* Symbol netlist format:
* library:footprint
* reference
* value
* pinName,netName,pinFunction,pinType
* pinName,netName,pinFunction,pinType
* ...
*/
std::vector<std::string> strings = split( payload, "\r" );
LIB_ID libid;
if( strings.size() >= 3 )
{
libid.Parse( strings[0] );
m_comp.SetFPID( libid );
m_comp.SetReference( strings[1] );
m_comp.SetValue( strings[2] );
m_comp.ClearNets();
for( size_t ii = 3; ii < strings.size(); ++ii )
{
std::vector<std::string> pinData = split( strings[ii], "," );
m_comp.AddNet( pinData[0], pinData[1], pinData[2], pinData[3] );
}
}
break;
}
case MAIL_RELOAD_LIB:
{
ReCreateLibraryList();
break;
}
default:
;
break;
}
}

View File

@ -413,6 +413,7 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
wxString sheetname;
wxString sheetfile;
wxString fpFilters;
if( aNetlistComponent->GetProperties().count( wxT( "Sheetname" ) ) > 0 )
sheetname = aNetlistComponent->GetProperties().at( wxT( "Sheetname" ) );
@ -420,15 +421,22 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
if( aNetlistComponent->GetProperties().count( wxT( "Sheetfile" ) ) > 0 )
sheetfile = aNetlistComponent->GetProperties().at( wxT( "Sheetfile" ) );
if( aNetlistComponent->GetProperties().count( wxT( "ki_fp_filters" ) ) > 0 )
fpFilters = aNetlistComponent->GetProperties().at( wxT( "ki_fp_filters" ) );
if( sheetname != aPcbFootprint->GetSheetname() )
{
if( m_isDryRun )
msg.Printf( _( "Update %s sheetname to '%s'." ), aPcbFootprint->GetReference(),
{
msg.Printf( _( "Update %s sheetname to '%s'." ),
aPcbFootprint->GetReference(),
sheetname );
}
else
{
aPcbFootprint->SetSheetname( sheetname );
msg.Printf( _( "Updated %s sheetname to '%s'." ), aPcbFootprint->GetReference(),
msg.Printf( _( "Updated %s sheetname to '%s'." ),
aPcbFootprint->GetReference(),
sheetname );
}
@ -438,18 +446,41 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
if( sheetfile != aPcbFootprint->GetSheetfile() )
{
if( m_isDryRun )
msg.Printf( _( "Update %s sheetfile to '%s'." ), aPcbFootprint->GetReference(),
{
msg.Printf( _( "Update %s sheetfile to '%s'." ),
aPcbFootprint->GetReference(),
sheetfile );
}
else
{
aPcbFootprint->SetSheetfile( sheetfile );
msg.Printf( _( "Updated %s sheetfile to '%s'." ), aPcbFootprint->GetReference(),
msg.Printf( _( "Updated %s sheetfile to '%s'." ),
aPcbFootprint->GetReference(),
sheetfile );
}
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
if( fpFilters != aPcbFootprint->GetFilters() )
{
if( m_isDryRun )
{
msg.Printf( _( "Update %s footprint filters to '%s'." ),
aPcbFootprint->GetReference(),
fpFilters );
}
else
{
aPcbFootprint->SetFilters( fpFilters );
msg.Printf( _( "Updated %s footprint filters to '%s'." ),
aPcbFootprint->GetReference(),
fpFilters );
}
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
if( ( aNetlistComponent->GetProperties().count( wxT( "exclude_from_bom" ) ) > 0 )
!= ( ( aPcbFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) > 0 ) )
{

View File

@ -142,6 +142,12 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
m_params.emplace_back( new PARAM<int>( "footprint_chooser.sort_mode",
&m_FootprintChooser.sort_mode, 0 ) );
m_params.emplace_back( new PARAM<bool>( "footprint_chooser.filter_on_pin_count",
&m_FootprintChooser.filter_on_pin_count, false ) );
m_params.emplace_back( new PARAM<bool>( "footprint_chooser.use_fp_filters",
&m_FootprintChooser.use_fp_filters, false ) );
m_params.emplace_back( new PARAM<bool>( "editing.flip_left_right",
&m_FlipLeftRight, true ) );

View File

@ -298,11 +298,13 @@ public:
struct FOOTPRINT_CHOOSER
{
int width;
int height;
int sash_h;
int sash_v;
int sort_mode;
int width;
int height;
int sash_h;
int sash_v;
int sort_mode;
bool use_fp_filters;
bool filter_on_pin_count;
};
struct ZONES

View File

@ -3853,7 +3853,7 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
// Skip legacy non-field properties sent from symbols that should not be kept
// in footprints.
if( pName == "ki_keywords" || pName == "ki_fp_filters" || pName == "ki_locked" )
if( pName == "ki_keywords" || pName == "ki_locked" )
{
NeedRIGHT();
break;
@ -3868,6 +3868,13 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
break;
}
if( pName == "ki_fp_filters" )
{
footprint->SetFilters( pValue );
NeedRIGHT();
break;
}
// Sheet file and name used to be stored as properties invisible to the user
if( pName == "Sheetfile" || pName == "Sheet file" )
{
@ -3892,8 +3899,8 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
}
else
{
field = footprint->AddField(
PCB_FIELD( footprint.get(), footprint->GetFieldCount(), pName ) );
field = footprint->AddField( PCB_FIELD( footprint.get(), footprint->GetFieldCount(),
pName ) );
field->SetText( pValue );
field->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab );

View File

@ -1154,6 +1154,12 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
m_out->Print( aNestLevel + 1, ")\n" );
}
if( !aFootprint->GetFilters().empty() )
{
m_out->Print( aNestLevel + 1, "(property ki_fp_filters %s)\n",
m_out->Quotew( aFootprint->GetFilters() ).c_str() );
}
if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
{
m_out->Print( aNestLevel+1, "(path %s)\n",

View File

@ -43,11 +43,13 @@
PANEL_FOOTPRINT_CHOOSER::PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopLevelWindow* aParent,
const wxArrayString& aFootprintHistoryList,
std::function<bool( LIB_TREE_NODE& )> aFilter,
std::function<void()> aCloseHandler ) :
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize ),
m_hsplitter( nullptr ),
m_vsplitter( nullptr ),
m_frame( aFrame ),
m_filter( std::move( aFilter ) ),
m_closeHandler( std::move( aCloseHandler ) )
{
FP_LIB_TABLE* fpTable = PROJECT_PCB::PcbFootprintLibs( &aFrame->Prj() );
@ -87,7 +89,8 @@ PANEL_FOOTPRINT_CHOOSER::PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopL
if( historyInfos.size() )
adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 );
adapter->AddLibraries( aFrame );
adapter->SetFilter( &m_filter );
adapter->AddLibraries( m_frame );
// -------------------------------------------------------------------------------------
// Construct the actual panel

View File

@ -46,6 +46,7 @@ public:
*/
PANEL_FOOTPRINT_CHOOSER( PCB_BASE_FRAME* aFrame, wxTopLevelWindow* aParent,
const wxArrayString& aFootprintHistoryList,
std::function<bool( LIB_TREE_NODE& )> aFilter,
std::function<void()> aCloseHandler );
~PANEL_FOOTPRINT_CHOOSER();
@ -65,6 +66,8 @@ public:
wxWindow* GetFocusTarget() const { return m_tree->GetFocusTarget(); }
void Regenerate() { m_tree->Regenerate( true ); }
protected:
static constexpr int DblClickDelay = 100; // milliseconds
@ -87,11 +90,12 @@ protected:
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> m_adapter;
FOOTPRINT_PREVIEW_WIDGET* m_preview_ctrl;
LIB_TREE* m_tree;
FOOTPRINT_PREVIEW_WIDGET* m_preview_ctrl;
LIB_TREE* m_tree;
PCB_BASE_FRAME* m_frame;
std::function<void()> m_closeHandler;
PCB_BASE_FRAME* m_frame;
std::function<bool( LIB_TREE_NODE& )> m_filter;
std::function<void()> m_closeHandler;
};
#endif /* PANEL_FOOTPRINT_CHOOSER_H */