Added a sort-order dropdown to lib-tree filters.
Also simplifies the scoring algorithm so that it only differentiates between exact-match, match-at-start and any-match. The rest of the position-based matching stuff is gone, as is the knowledge of the name vs the keywords vs the description. All that is left to the provider of the weighted search terms array.
This commit is contained in:
parent
04a53ea40d
commit
df7d62fdd3
|
@ -445,6 +445,38 @@ bool EDA_COMBINED_MATCHER::StartsWith( const wxString& aTerm )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int EDA_COMBINED_MATCHER::ScoreTerms( std::vector<SEARCH_TERM>& aWeightedTerms )
|
||||||
|
{
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
for( SEARCH_TERM& term : aWeightedTerms )
|
||||||
|
{
|
||||||
|
if( !term.Normalized )
|
||||||
|
{
|
||||||
|
term.Text = term.Text.MakeLower().Trim( false ).Trim( true );
|
||||||
|
term.Normalized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int found_pos = EDA_PATTERN_NOT_FOUND;
|
||||||
|
int matchers_fired = 0;
|
||||||
|
|
||||||
|
if( GetPattern() == term.Text )
|
||||||
|
{
|
||||||
|
score += 8 * term.Score;
|
||||||
|
}
|
||||||
|
else if( Find( term.Text, matchers_fired, found_pos ) )
|
||||||
|
{
|
||||||
|
if( found_pos == 0 )
|
||||||
|
score += 2 * term.Score;
|
||||||
|
else
|
||||||
|
score += term.Score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString const& EDA_COMBINED_MATCHER::GetPattern() const
|
wxString const& EDA_COMBINED_MATCHER::GetPattern() const
|
||||||
{
|
{
|
||||||
return m_pattern;
|
return m_pattern;
|
||||||
|
|
|
@ -82,15 +82,13 @@ void FOOTPRINT_FILTER_IT::increment()
|
||||||
|
|
||||||
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_TEXT_PATTERN ) )
|
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_TEXT_PATTERN ) )
|
||||||
{
|
{
|
||||||
wxString searchStr = wxString::Format( wxT( "%s:%s %s" ),
|
|
||||||
candidate.GetLibNickname(),
|
|
||||||
candidate.GetFootprintName(),
|
|
||||||
candidate.GetSearchText() );
|
|
||||||
bool exclude = false;
|
bool exclude = false;
|
||||||
|
|
||||||
for( std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : m_filter->m_pattern_filters )
|
for( std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : m_filter->m_pattern_filters )
|
||||||
{
|
{
|
||||||
if( !matcher->Find( searchStr.Lower() ) )
|
std::vector<SEARCH_TERM> searchTerms = candidate.GetSearchTerms();
|
||||||
|
|
||||||
|
if( !matcher->ScoreTerms( searchTerms ) )
|
||||||
{
|
{
|
||||||
exclude = true;
|
exclude = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <lib_id.h>
|
#include <lib_id.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <wx/tokenzr.h>
|
||||||
#include <kiface_base.h>
|
#include <kiface_base.h>
|
||||||
|
|
||||||
FOOTPRINT_INFO* FOOTPRINT_LIST::GetFootprintInfo( const wxString& aLibNickname,
|
FOOTPRINT_INFO* FOOTPRINT_LIST::GetFootprintInfo( const wxString& aLibNickname,
|
||||||
|
@ -69,6 +70,25 @@ FOOTPRINT_INFO* FOOTPRINT_LIST::GetFootprintInfo( const wxString& aFootprintName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<SEARCH_TERM> FOOTPRINT_INFO::GetSearchTerms()
|
||||||
|
{
|
||||||
|
std::vector<SEARCH_TERM> terms;
|
||||||
|
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetName(), 8 ) );
|
||||||
|
|
||||||
|
wxStringTokenizer keywordTokenizer( GetKeywords(), wxS( " " ), wxTOKEN_STRTOK );
|
||||||
|
|
||||||
|
while( keywordTokenizer.HasMoreTokens() )
|
||||||
|
terms.emplace_back( SEARCH_TERM( keywordTokenizer.GetNextToken(), 4 ) );
|
||||||
|
|
||||||
|
// Also include keywords as one long string, just in case
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetKeywords(), 1 ) );
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetDescription(), 1 ) );
|
||||||
|
|
||||||
|
return terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const
|
bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const
|
||||||
{
|
{
|
||||||
return aLibrary == m_nickname;
|
return aLibrary == m_nickname;
|
||||||
|
|
|
@ -34,20 +34,6 @@
|
||||||
static const unsigned kLowestDefaultScore = 1;
|
static const unsigned kLowestDefaultScore = 1;
|
||||||
|
|
||||||
|
|
||||||
// Creates a score depending on the position of a string match. If the position
|
|
||||||
// is 0 (= prefix match), this returns the maximum score. This degrades until
|
|
||||||
// pos == max, which returns a score of 0; Evertyhing else beyond that is just
|
|
||||||
// 0. Only values >= 0 allowed for position and max.
|
|
||||||
//
|
|
||||||
// @param aPosition is the position a string has been found in a substring.
|
|
||||||
// @param aMaximum is the maximum score this function returns.
|
|
||||||
// @return position dependent score.
|
|
||||||
static int matchPosScore(int aPosition, int aMaximum)
|
|
||||||
{
|
|
||||||
return ( aPosition < aMaximum ) ? aMaximum - aPosition : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LIB_TREE_NODE::ResetScore()
|
void LIB_TREE_NODE::ResetScore()
|
||||||
{
|
{
|
||||||
for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
|
for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
|
||||||
|
@ -85,20 +71,21 @@ void LIB_TREE_NODE::AssignIntrinsicRanks( bool presorted )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LIB_TREE_NODE::SortNodes()
|
void LIB_TREE_NODE::SortNodes( bool aUseScores )
|
||||||
{
|
{
|
||||||
std::sort( m_Children.begin(), m_Children.end(),
|
std::sort( m_Children.begin(), m_Children.end(),
|
||||||
[]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
|
[&]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
|
||||||
{
|
{
|
||||||
return Compare( *a, *b );
|
return Compare( *a, *b, aUseScores );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
|
for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
|
||||||
node->SortNodes();
|
node->SortNodes( aUseScores );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2 )
|
bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2,
|
||||||
|
bool aUseScores )
|
||||||
{
|
{
|
||||||
if( aNode1.m_Type != aNode2.m_Type )
|
if( aNode1.m_Type != aNode2.m_Type )
|
||||||
return aNode1.m_Type < aNode2.m_Type;
|
return aNode1.m_Type < aNode2.m_Type;
|
||||||
|
@ -126,6 +113,9 @@ bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& a
|
||||||
else if( aNode2.m_Pinned && !aNode1.m_Pinned )
|
else if( aNode2.m_Pinned && !aNode1.m_Pinned )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if( aUseScores && aNode1.m_Score != aNode2.m_Score )
|
||||||
|
return aNode1.m_Score > aNode2.m_Score;
|
||||||
|
|
||||||
if( aNode1.m_IntrinsicRank != aNode2.m_IntrinsicRank )
|
if( aNode1.m_IntrinsicRank != aNode2.m_IntrinsicRank )
|
||||||
return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
|
return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
|
||||||
|
|
||||||
|
@ -139,7 +129,6 @@ LIB_TREE_NODE::LIB_TREE_NODE()
|
||||||
m_IntrinsicRank( 0 ),
|
m_IntrinsicRank( 0 ),
|
||||||
m_Score( kLowestDefaultScore ),
|
m_Score( kLowestDefaultScore ),
|
||||||
m_Pinned( false ),
|
m_Pinned( false ),
|
||||||
m_Normalized( false ),
|
|
||||||
m_Unit( 0 ),
|
m_Unit( 0 ),
|
||||||
m_IsRoot( false )
|
m_IsRoot( false )
|
||||||
{}
|
{}
|
||||||
|
@ -167,15 +156,9 @@ LIB_TREE_NODE_UNIT::LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* a
|
||||||
m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
|
m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
|
||||||
|
|
||||||
if( aItem->HasUnitDisplayName( aUnit ) )
|
if( aItem->HasUnitDisplayName( aUnit ) )
|
||||||
{
|
|
||||||
m_Desc = aItem->GetUnitDisplayName( aUnit );
|
m_Desc = aItem->GetUnitDisplayName( aUnit );
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
m_Desc = wxEmptyString;
|
m_Desc = wxEmptyString;
|
||||||
}
|
|
||||||
|
|
||||||
m_MatchName = wxEmptyString;
|
|
||||||
|
|
||||||
m_IntrinsicRank = -aUnit;
|
m_IntrinsicRank = -aUnit;
|
||||||
}
|
}
|
||||||
|
@ -195,9 +178,7 @@ LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITE
|
||||||
|
|
||||||
aItem->GetChooserFields( m_Fields );
|
aItem->GetChooserFields( m_Fields );
|
||||||
|
|
||||||
m_MatchName = aItem->GetName();
|
m_SearchTerms = aItem->GetSearchTerms();
|
||||||
m_SearchText = aItem->GetSearchText();
|
|
||||||
m_Normalized = false;
|
|
||||||
|
|
||||||
m_IsRoot = aItem->IsRoot();
|
m_IsRoot = aItem->IsRoot();
|
||||||
|
|
||||||
|
@ -224,12 +205,10 @@ void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
|
||||||
|
|
||||||
m_Name = aItem->GetName();
|
m_Name = aItem->GetName();
|
||||||
m_Desc = aItem->GetDescription();
|
m_Desc = aItem->GetDescription();
|
||||||
m_MatchName = aItem->GetName();
|
|
||||||
|
|
||||||
aItem->GetChooserFields( m_Fields );
|
aItem->GetChooserFields( m_Fields );
|
||||||
|
|
||||||
m_SearchText = aItem->GetSearchText();
|
m_SearchTerms = aItem->GetSearchTerms();
|
||||||
m_Normalized = false;
|
|
||||||
|
|
||||||
m_IsRoot = aItem->IsRoot();
|
m_IsRoot = aItem->IsRoot();
|
||||||
m_Children.clear();
|
m_Children.clear();
|
||||||
|
@ -244,59 +223,13 @@ void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wx
|
||||||
if( m_Score <= 0 )
|
if( m_Score <= 0 )
|
||||||
return; // Leaf nodes without scores are out of the game.
|
return; // Leaf nodes without scores are out of the game.
|
||||||
|
|
||||||
if( !m_Normalized )
|
if( !aLib.IsEmpty() && m_Parent->m_Name.Lower() != aLib )
|
||||||
{
|
|
||||||
m_MatchName = UnescapeString( m_MatchName ).Lower();
|
|
||||||
m_SearchText = m_SearchText.Lower();
|
|
||||||
m_Normalized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !aLib.IsEmpty() && m_Parent->m_MatchName != aLib )
|
|
||||||
{
|
{
|
||||||
m_Score = 0;
|
m_Score = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keywords and description we only count if the match string is at
|
m_Score = aMatcher.ScoreTerms( m_SearchTerms );
|
||||||
// least two characters long. That avoids spurious, low quality
|
|
||||||
// matches. Most abbreviations are at three characters long.
|
|
||||||
int found_pos = EDA_PATTERN_NOT_FOUND;
|
|
||||||
int matchers_fired = 0;
|
|
||||||
|
|
||||||
if( aMatcher.GetPattern() == m_MatchName )
|
|
||||||
{
|
|
||||||
m_Score += 1000; // exact match. High score :)
|
|
||||||
}
|
|
||||||
else if( aMatcher.Find( m_MatchName, matchers_fired, found_pos ) )
|
|
||||||
{
|
|
||||||
// Substring match. The earlier in the string the better.
|
|
||||||
m_Score += matchPosScore( found_pos, 20 ) + 20;
|
|
||||||
}
|
|
||||||
else if( aMatcher.Find( m_Parent->m_MatchName, matchers_fired, found_pos ) )
|
|
||||||
{
|
|
||||||
m_Score += 19; // parent name matches. score += 19
|
|
||||||
}
|
|
||||||
else if( aMatcher.Find( m_SearchText, matchers_fired, found_pos ) )
|
|
||||||
{
|
|
||||||
// If we have a very short search term (like one or two letters),
|
|
||||||
// we don't want to accumulate scores if they just happen to be in
|
|
||||||
// keywords or description as almost any one or two-letter
|
|
||||||
// combination shows up in there.
|
|
||||||
if( aMatcher.GetPattern().length() >= 2 )
|
|
||||||
{
|
|
||||||
// For longer terms, we add scores 1..18 for positional match
|
|
||||||
// (higher in the front, where the keywords are).
|
|
||||||
m_Score += matchPosScore( found_pos, 17 ) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No match. That's it for this item.
|
|
||||||
m_Score = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// More matchers = better match
|
|
||||||
m_Score += 2 * matchers_fired;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -305,7 +238,6 @@ LIB_TREE_NODE_LIB::LIB_TREE_NODE_LIB( LIB_TREE_NODE* aParent, wxString const& aN
|
||||||
{
|
{
|
||||||
m_Type = LIB;
|
m_Type = LIB;
|
||||||
m_Name = aName;
|
m_Name = aName;
|
||||||
m_MatchName = aName.Lower();
|
|
||||||
m_Desc = aDesc;
|
m_Desc = aDesc;
|
||||||
m_Parent = aParent;
|
m_Parent = aParent;
|
||||||
m_LibId.SetLibNickname( aName );
|
m_LibId.SetLibNickname( aName );
|
||||||
|
@ -338,27 +270,7 @@ void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxStr
|
||||||
{
|
{
|
||||||
// No children; we are a leaf.
|
// No children; we are a leaf.
|
||||||
|
|
||||||
if( !aLib.IsEmpty() )
|
m_Score = aMatcher.ScoreTerms( m_SearchTerms );
|
||||||
{
|
|
||||||
m_Score = m_MatchName == aLib ? 1000 : 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int found_pos = EDA_PATTERN_NOT_FOUND;
|
|
||||||
int matchers_fired = 0;
|
|
||||||
|
|
||||||
if( aMatcher.GetPattern() == m_MatchName )
|
|
||||||
{
|
|
||||||
m_Score += 1000; // exact match. High score :)
|
|
||||||
}
|
|
||||||
else if( aMatcher.Find( m_MatchName, matchers_fired, found_pos ) )
|
|
||||||
{
|
|
||||||
// Substring match. The earlier in the string the better.
|
|
||||||
m_Score += matchPosScore( found_pos, 20 ) + 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
// More matchers = better match
|
|
||||||
m_Score += 2 * matchers_fired;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ LIB_TREE_MODEL_ADAPTER::LIB_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent,
|
||||||
const wxString& aPinnedKey ) :
|
const wxString& aPinnedKey ) :
|
||||||
m_parent( aParent ),
|
m_parent( aParent ),
|
||||||
m_filter( SYM_FILTER_NONE ),
|
m_filter( SYM_FILTER_NONE ),
|
||||||
|
m_sort_mode( BEST_MATCH ),
|
||||||
m_show_units( true ),
|
m_show_units( true ),
|
||||||
m_preselect_unit( 0 ),
|
m_preselect_unit( 0 ),
|
||||||
m_freeze( 0 ),
|
m_freeze( 0 ),
|
||||||
|
@ -208,7 +209,7 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
|
||||||
m_tree.UpdateScore( matcher, lib );
|
m_tree.UpdateScore( matcher, lib );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tree.SortNodes();
|
m_tree.SortNodes( m_sort_mode == BEST_MATCH );
|
||||||
AfterReset();
|
AfterReset();
|
||||||
Thaw();
|
Thaw();
|
||||||
}
|
}
|
||||||
|
@ -273,7 +274,7 @@ void LIB_TREE_MODEL_ADAPTER::resortTree()
|
||||||
Freeze();
|
Freeze();
|
||||||
BeforeReset();
|
BeforeReset();
|
||||||
|
|
||||||
m_tree.SortNodes();
|
m_tree.SortNodes( m_sort_mode == BEST_MATCH );
|
||||||
|
|
||||||
AfterReset();
|
AfterReset();
|
||||||
Thaw();
|
Thaw();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||||
* Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -23,8 +23,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <widgets/lib_tree.h>
|
#include <widgets/lib_tree.h>
|
||||||
|
#include <widgets/std_bitmap_button.h>
|
||||||
#include <core/kicad_algo.h>
|
#include <core/kicad_algo.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
#include <bitmaps.h>
|
||||||
#include <dialogs/eda_reorderable_list_dialog.h>
|
#include <dialogs/eda_reorderable_list_dialog.h>
|
||||||
#include <tool/tool_interactive.h>
|
#include <tool/tool_interactive.h>
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
|
@ -46,7 +48,9 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, const wxString& aRecentSearchesKey, LIB_T
|
||||||
HTML_WINDOW* aDetails ) :
|
HTML_WINDOW* aDetails ) :
|
||||||
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||||
wxWANTS_CHARS | wxTAB_TRAVERSAL | wxNO_BORDER ),
|
wxWANTS_CHARS | wxTAB_TRAVERSAL | wxNO_BORDER ),
|
||||||
m_lib_table( aLibTable ), m_adapter( aAdapter ), m_query_ctrl( nullptr ),
|
m_adapter( aAdapter ),
|
||||||
|
m_query_ctrl( nullptr ),
|
||||||
|
m_sort_ctrl( nullptr ),
|
||||||
m_details_ctrl( nullptr ),
|
m_details_ctrl( nullptr ),
|
||||||
m_inTimerEvent( false ),
|
m_inTimerEvent( false ),
|
||||||
m_recentSearchesKey( aRecentSearchesKey ),
|
m_recentSearchesKey( aRecentSearchesKey ),
|
||||||
|
@ -73,6 +77,36 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, const wxString& aRecentSearchesKey, LIB_T
|
||||||
|
|
||||||
search_sizer->Add( m_query_ctrl, 1, wxEXPAND, 5 );
|
search_sizer->Add( m_query_ctrl, 1, wxEXPAND, 5 );
|
||||||
|
|
||||||
|
m_sort_ctrl = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition,
|
||||||
|
wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||||
|
m_sort_ctrl->SetBitmap( KiBitmap( BITMAPS::small_sort_desc ) );
|
||||||
|
m_sort_ctrl->Bind( wxEVT_LEFT_DOWN,
|
||||||
|
[&]( wxMouseEvent& aEvent )
|
||||||
|
{
|
||||||
|
wxMenu menu;
|
||||||
|
|
||||||
|
menu.Append( 4201, _( "Sort by Best Match" ), wxEmptyString, wxITEM_CHECK );
|
||||||
|
menu.Append( 4202, _( "Sort Alphabetically" ), wxEmptyString, wxITEM_CHECK );
|
||||||
|
|
||||||
|
if( m_adapter->GetSortMode() == LIB_TREE_MODEL_ADAPTER::BEST_MATCH )
|
||||||
|
menu.Check( 4201, true );
|
||||||
|
else
|
||||||
|
menu.Check( 4202, true );
|
||||||
|
|
||||||
|
if( m_sort_ctrl->GetPopupMenuSelectionFromUser( menu ) == 0 )
|
||||||
|
{
|
||||||
|
m_adapter->SetSortMode( LIB_TREE_MODEL_ADAPTER::BEST_MATCH );
|
||||||
|
Regenerate( true );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_adapter->SetSortMode( LIB_TREE_MODEL_ADAPTER::ALPHABETIC );
|
||||||
|
Regenerate( true );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
search_sizer->Add( m_sort_ctrl, 0, wxEXPAND|wxALL, 1 );
|
||||||
|
|
||||||
sizer->Add( search_sizer, 0, wxEXPAND, 5 );
|
sizer->Add( search_sizer, 0, wxEXPAND, 5 );
|
||||||
|
|
||||||
m_query_ctrl->Bind( wxEVT_TEXT, &LIB_TREE::onQueryText, this );
|
m_query_ctrl->Bind( wxEVT_TEXT, &LIB_TREE::onQueryText, this );
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||||
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -203,6 +203,8 @@ DIALOG_CHOOSE_SYMBOL::DIALOG_CHOOSE_SYMBOL( SCH_BASE_FRAME* aParent, const wxStr
|
||||||
wxSize dlgSize( panelCfg.width > 0 ? panelCfg.width : horizPixelsFromDU( 390 ),
|
wxSize dlgSize( panelCfg.width > 0 ? panelCfg.width : horizPixelsFromDU( 390 ),
|
||||||
panelCfg.height > 0 ? panelCfg.height : vertPixelsFromDU( 300 ) );
|
panelCfg.height > 0 ? panelCfg.height : vertPixelsFromDU( 300 ) );
|
||||||
SetSize( dlgSize );
|
SetSize( dlgSize );
|
||||||
|
|
||||||
|
aAdapter->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) cfg->m_SymChooserPanel.sort_mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
SetInitialFocus( m_tree->GetFocusTarget() );
|
SetInitialFocus( m_tree->GetFocusTarget() );
|
||||||
|
@ -280,6 +282,8 @@ DIALOG_CHOOSE_SYMBOL::~DIALOG_CHOOSE_SYMBOL()
|
||||||
|
|
||||||
if( m_vsplitter )
|
if( m_vsplitter )
|
||||||
cfg->m_SymChooserPanel.sash_pos_v = m_vsplitter->GetSashPosition();
|
cfg->m_SymChooserPanel.sash_pos_v = m_vsplitter->GetSashPosition();
|
||||||
|
|
||||||
|
cfg->m_SymChooserPanel.sort_mode = m_tree->GetSortMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,6 +446,9 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
|
||||||
m_params.emplace_back( new PARAM<int>( "symbol_chooser.height",
|
m_params.emplace_back( new PARAM<int>( "symbol_chooser.height",
|
||||||
&m_SymChooserPanel.height, -1 ) );
|
&m_SymChooserPanel.height, -1 ) );
|
||||||
|
|
||||||
|
m_params.emplace_back( new PARAM<int>( "symbol_chooser.sort_mode",
|
||||||
|
&m_SymChooserPanel.sort_mode, 0 ) );
|
||||||
|
|
||||||
m_params.emplace_back( new PARAM<bool>( "symbol_chooser.keep_symbol",
|
m_params.emplace_back( new PARAM<bool>( "symbol_chooser.keep_symbol",
|
||||||
&m_SymChooserPanel.keep_symbol, false ) );
|
&m_SymChooserPanel.keep_symbol, false ) );
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,7 @@ public:
|
||||||
int sash_pos_v;
|
int sash_pos_v;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
int sort_mode;
|
||||||
bool keep_symbol;
|
bool keep_symbol;
|
||||||
bool place_all_units;
|
bool place_all_units;
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,28 +45,34 @@ int LIB_SYMBOL::m_subpartIdSeparator = 0;
|
||||||
int LIB_SYMBOL::m_subpartFirstId = 'A';
|
int LIB_SYMBOL::m_subpartFirstId = 'A';
|
||||||
|
|
||||||
|
|
||||||
wxString LIB_SYMBOL::GetSearchText()
|
std::vector<SEARCH_TERM> LIB_SYMBOL::GetSearchTerms()
|
||||||
{
|
{
|
||||||
// Matches are scored by offset from front of string, so inclusion of this spacer
|
std::vector<SEARCH_TERM> terms;
|
||||||
// discounts matches found after it.
|
|
||||||
static const wxString discount( wxT( " " ) );
|
|
||||||
|
|
||||||
wxString text = GetKeyWords() + discount + GetDescription();
|
terms.emplace_back( SEARCH_TERM( GetName(), 8 ) );
|
||||||
wxString footprint = GetFootprintField().GetText();
|
|
||||||
|
|
||||||
if( !footprint.IsEmpty() )
|
wxStringTokenizer keywordTokenizer( GetKeyWords(), wxS( " " ), wxTOKEN_STRTOK );
|
||||||
{
|
|
||||||
text += discount + footprint;
|
while( keywordTokenizer.HasMoreTokens() )
|
||||||
}
|
terms.emplace_back( SEARCH_TERM( keywordTokenizer.GetNextToken(), 4 ) );
|
||||||
|
|
||||||
// TODO(JE) rework this later so we can highlight matches in their column
|
// TODO(JE) rework this later so we can highlight matches in their column
|
||||||
std::map<wxString, wxString> fields;
|
std::map<wxString, wxString> fields;
|
||||||
GetChooserFields( fields );
|
GetChooserFields( fields );
|
||||||
|
|
||||||
for( const auto& it : fields )
|
for( const auto& [ name, text ] : fields )
|
||||||
text += discount + it.second;
|
terms.emplace_back( SEARCH_TERM( text, 4 ) );
|
||||||
|
|
||||||
return text;
|
// Also include keywords as one long string, just in case
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetKeyWords(), 1 ) );
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetDescription(), 1 ) );
|
||||||
|
|
||||||
|
wxString footprint = GetFootprintField().GetText();
|
||||||
|
|
||||||
|
if( !footprint.IsEmpty() )
|
||||||
|
terms.emplace_back( SEARCH_TERM( GetFootprintField().GetText(), 1 ) );
|
||||||
|
|
||||||
|
return terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +83,7 @@ void LIB_SYMBOL::GetChooserFields( std::map<wxString , wxString>& aColumnMap )
|
||||||
LIB_FIELD* field = static_cast<LIB_FIELD*>( &item );
|
LIB_FIELD* field = static_cast<LIB_FIELD*>( &item );
|
||||||
|
|
||||||
if( field->ShowInChooser() )
|
if( field->ShowInChooser() )
|
||||||
aColumnMap[field->GetName()] = field->EDA_TEXT::GetShownText();
|
aColumnMap[field->GetName()] = field->EDA_TEXT::GetShownText( false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ public:
|
||||||
return m_keyWords;
|
return m_keyWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString GetSearchText() override;
|
std::vector<SEARCH_TERM> GetSearchTerms() override;
|
||||||
|
|
||||||
wxString GetFootprint() override
|
wxString GetFootprint() override
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,7 +152,7 @@ SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchem
|
||||||
if( m_path.IsEmpty() )
|
if( m_path.IsEmpty() )
|
||||||
m_path = aSchematic->Prj().GetProjectPath();
|
m_path = aSchematic->Prj().GetProjectPath();
|
||||||
|
|
||||||
wxLogTrace( traceSchLegacyPlugin, "m_Normalized append path \"%s\".", m_path );
|
wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -142,6 +142,7 @@ SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||||
|
|
||||||
SyncLibraries( false, loadingCancelled );
|
SyncLibraries( false, loadingCancelled );
|
||||||
m_treePane = new SYMBOL_TREE_PANE( this, m_libMgr );
|
m_treePane = new SYMBOL_TREE_PANE( this, m_libMgr );
|
||||||
|
m_treePane->GetLibTree()->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) m_settings->m_LibrarySortMode );
|
||||||
|
|
||||||
resolveCanvasType();
|
resolveCanvasType();
|
||||||
SwitchCanvas( m_canvasType );
|
SwitchCanvas( m_canvasType );
|
||||||
|
@ -304,6 +305,8 @@ void SYMBOL_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
|
||||||
|
|
||||||
m_settings->m_ShowPinElectricalType = GetRenderSettings()->m_ShowPinsElectricalType;
|
m_settings->m_ShowPinElectricalType = GetRenderSettings()->m_ShowPinsElectricalType;
|
||||||
m_settings->m_LibWidth = m_treePane->GetSize().x;
|
m_settings->m_LibWidth = m_treePane->GetSize().x;
|
||||||
|
|
||||||
|
m_settings->m_LibrarySortMode = m_treePane->GetLibTree()->GetSortMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -73,6 +73,9 @@ SYMBOL_EDITOR_SETTINGS::SYMBOL_EDITOR_SETTINGS() :
|
||||||
m_params.emplace_back( new PARAM<int>( "lib_table_width",
|
m_params.emplace_back( new PARAM<int>( "lib_table_width",
|
||||||
&m_LibWidth, 250 ) );
|
&m_LibWidth, 250 ) );
|
||||||
|
|
||||||
|
m_params.emplace_back( new PARAM<int>( "library.sort_mode",
|
||||||
|
&m_LibrarySortMode, 0 ) );
|
||||||
|
|
||||||
m_params.emplace_back( new PARAM<wxString>( "edit_symbol_visible_columns",
|
m_params.emplace_back( new PARAM<wxString>( "edit_symbol_visible_columns",
|
||||||
&m_EditSymbolVisibleColumns, "0 1 2 3 4 5 6 7" ) );
|
&m_EditSymbolVisibleColumns, "0 1 2 3 4 5 6 7" ) );
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -60,6 +60,8 @@ public:
|
||||||
|
|
||||||
int m_LibWidth;
|
int m_LibWidth;
|
||||||
|
|
||||||
|
int m_LibrarySortMode;
|
||||||
|
|
||||||
wxString m_EditSymbolVisibleColumns;
|
wxString m_EditSymbolVisibleColumns;
|
||||||
|
|
||||||
wxString m_PinTableVisibleColumns;
|
wxString m_PinTableVisibleColumns;
|
||||||
|
|
|
@ -795,16 +795,16 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
|
||||||
|
|
||||||
while( tokenizer.HasMoreTokens() )
|
while( tokenizer.HasMoreTokens() )
|
||||||
{
|
{
|
||||||
const wxString term = tokenizer.GetNextToken().Lower();
|
const wxString filterTerm = tokenizer.GetNextToken().Lower();
|
||||||
EDA_COMBINED_MATCHER matcher( term, CTX_LIBITEM );
|
EDA_COMBINED_MATCHER matcher( filterTerm, CTX_LIBITEM );
|
||||||
|
|
||||||
for( LIB_SYMBOL* symbol : symbols )
|
for( LIB_SYMBOL* symbol : symbols )
|
||||||
{
|
{
|
||||||
wxString search = symbol->GetName() + wxS( " " ) + symbol->GetSearchText();
|
std::vector<SEARCH_TERM> searchTerms = symbol->GetSearchTerms();
|
||||||
bool matched = matcher.Find( search.Lower() );
|
int matched = matcher.ScoreTerms( searchTerms );
|
||||||
|
|
||||||
if( !matched && term.IsNumber() )
|
if( filterTerm.IsNumber() && wxAtoi( filterTerm ) == (int)symbol->GetPinCount() )
|
||||||
matched = ( wxAtoi( term ) == (int)symbol->GetPinCount() );
|
matched++;
|
||||||
|
|
||||||
if( !matched )
|
if( !matched )
|
||||||
excludes.insert( symbol->GetName() );
|
excludes.insert( symbol->GetName() );
|
||||||
|
|
|
@ -37,6 +37,26 @@
|
||||||
|
|
||||||
static const int EDA_PATTERN_NOT_FOUND = wxNOT_FOUND;
|
static const int EDA_PATTERN_NOT_FOUND = wxNOT_FOUND;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A structure for storing weighted search terms.
|
||||||
|
*
|
||||||
|
* NOTE: an exact match is scored at 8 * Score while a match at the start of the text is scored
|
||||||
|
* at 2 * Score.
|
||||||
|
*/
|
||||||
|
struct SEARCH_TERM
|
||||||
|
{
|
||||||
|
SEARCH_TERM( const wxString& aText, int aScore ) :
|
||||||
|
Text( aText ),
|
||||||
|
Score( aScore ),
|
||||||
|
Normalized( false )
|
||||||
|
{}
|
||||||
|
|
||||||
|
wxString Text;
|
||||||
|
int Score;
|
||||||
|
bool Normalized;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interface for a pattern matcher, for which there are several implementations
|
* Interface for a pattern matcher, for which there are several implementations
|
||||||
*/
|
*/
|
||||||
|
@ -205,6 +225,8 @@ public:
|
||||||
|
|
||||||
const wxString& GetPattern() const;
|
const wxString& GetPattern() const;
|
||||||
|
|
||||||
|
int ScoreTerms( std::vector<SEARCH_TERM>& aWeightedTerms );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Add matcher if it can compile the pattern.
|
// Add matcher if it can compile the pattern.
|
||||||
void AddMatcher( const wxString& aPattern, std::unique_ptr<EDA_PATTERN_MATCH> aMatcher );
|
void AddMatcher( const wxString& aPattern, std::unique_ptr<EDA_PATTERN_MATCH> aMatcher );
|
||||||
|
|
|
@ -64,6 +64,8 @@ public:
|
||||||
|
|
||||||
AUI_PANELS m_AuiPanels;
|
AUI_PANELS m_AuiPanels;
|
||||||
|
|
||||||
|
int m_LibrarySortMode;
|
||||||
|
|
||||||
USER_GRID m_UserGrid;
|
USER_GRID m_UserGrid;
|
||||||
|
|
||||||
bool m_PolarCoords;
|
bool m_PolarCoords;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Jean-Pierre Charras, <jp.charras@wanadoo.fr>
|
* Copyright (C) 2011 Jean-Pierre Charras, <jp.charras@wanadoo.fr>
|
||||||
* Copyright (C) 1992-2021 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -89,14 +89,7 @@ public:
|
||||||
return m_keywords;
|
return m_keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString GetSearchText() override
|
std::vector<SEARCH_TERM> GetSearchTerms() override;
|
||||||
{
|
|
||||||
// Matches are scored by offset from front of string, so inclusion of this spacer
|
|
||||||
// discounts matches found after it.
|
|
||||||
static const wxString discount( wxT( " " ) );
|
|
||||||
|
|
||||||
return GetKeywords() + discount + GetDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned GetPadCount()
|
unsigned GetPadCount()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 KiCad Developers, see change_log.txt for contributors.
|
* Copyright (C) 2018-2023 KiCad Developers, see change_log.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <lib_id.h>
|
#include <lib_id.h>
|
||||||
#include <import_export.h>
|
#include <import_export.h>
|
||||||
|
#include <eda_pattern_match.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mix-in to provide polymorphism between items stored in libraries (symbols, aliases
|
* A mix-in to provide polymorphism between items stored in libraries (symbols, aliases
|
||||||
|
@ -55,7 +56,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void GetChooserFields( std::map<wxString , wxString>& aColumnMap ) {}
|
virtual void GetChooserFields( std::map<wxString , wxString>& aColumnMap ) {}
|
||||||
|
|
||||||
virtual wxString GetSearchText() { return wxEmptyString; }
|
virtual std::vector<SEARCH_TERM> GetSearchTerms() { return std::vector<SEARCH_TERM>(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For items having aliases, IsRoot() indicates the principal item.
|
* For items having aliases, IsRoot() indicates the principal item.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||||
* Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
@ -26,12 +26,10 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
|
#include <eda_pattern_match.h>
|
||||||
#include <lib_tree_item.h>
|
#include <lib_tree_item.h>
|
||||||
|
|
||||||
|
|
||||||
class EDA_COMBINED_MATCHER;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model class in the component selector Model-View-Adapter (mediated MVC)
|
* Model class in the component selector Model-View-Adapter (mediated MVC)
|
||||||
* architecture. The other pieces are in:
|
* architecture. The other pieces are in:
|
||||||
|
@ -98,18 +96,24 @@ public:
|
||||||
/**
|
/**
|
||||||
* Sort child nodes quickly and recursively (IntrinsicRanks must have been set).
|
* Sort child nodes quickly and recursively (IntrinsicRanks must have been set).
|
||||||
*/
|
*/
|
||||||
void SortNodes();
|
void SortNodes( bool aUseScores );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two nodes. Returns true if aNode1 < aNode2.
|
* Compare two nodes. Returns true if aNode1 < aNode2.
|
||||||
*/
|
*/
|
||||||
static bool Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2 );
|
static bool Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2,
|
||||||
|
bool aUseScores );
|
||||||
|
|
||||||
LIB_TREE_NODE();
|
LIB_TREE_NODE();
|
||||||
virtual ~LIB_TREE_NODE() {}
|
virtual ~LIB_TREE_NODE() {}
|
||||||
|
|
||||||
enum TYPE {
|
enum TYPE
|
||||||
ROOT, LIB, LIBID, UNIT, INVALID
|
{
|
||||||
|
ROOT,
|
||||||
|
LIB,
|
||||||
|
LIBID,
|
||||||
|
UNIT,
|
||||||
|
INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<std::unique_ptr<LIB_TREE_NODE>> PTR_VECTOR;
|
typedef std::vector<std::unique_ptr<LIB_TREE_NODE>> PTR_VECTOR;
|
||||||
|
@ -131,12 +135,9 @@ public:
|
||||||
wxString m_Name; // Actual name of the part
|
wxString m_Name; // Actual name of the part
|
||||||
wxString m_Desc; // Description to be displayed
|
wxString m_Desc; // Description to be displayed
|
||||||
wxString m_Footprint; // Footprint ID as a string (ie: the footprint field text)
|
wxString m_Footprint; // Footprint ID as a string (ie: the footprint field text)
|
||||||
wxString m_MatchName; // Normalized name for matching
|
|
||||||
wxString m_SearchText; // Descriptive text to search
|
|
||||||
bool m_Normalized; // Support for lazy normalization.
|
|
||||||
|
|
||||||
/// @see LIB_TREE_ITEMS::GetChooserFields
|
std::vector<SEARCH_TERM> m_SearchTerms; /// List of weighted search terms
|
||||||
std::map<wxString, wxString> m_Fields;
|
std::map<wxString, wxString> m_Fields; /// @see LIB_TREE_ITEMS::GetChooserFields
|
||||||
|
|
||||||
LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name.
|
LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name.
|
||||||
int m_Unit; // Actual unit, or zero
|
int m_Unit; // Actual unit, or zero
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||||
* Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
@ -133,6 +133,11 @@ public:
|
||||||
NUM_COLS ///< The number of default tree columns
|
NUM_COLS ///< The number of default tree columns
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SORT_MODE
|
||||||
|
{
|
||||||
|
BEST_MATCH = 0,
|
||||||
|
ALPHABETIC
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the column widths to the config file. This requires the tree view to still be
|
* Save the column widths to the config file. This requires the tree view to still be
|
||||||
|
@ -152,6 +157,9 @@ public:
|
||||||
*/
|
*/
|
||||||
SYM_FILTER_TYPE GetFilter() const { return m_filter; }
|
SYM_FILTER_TYPE GetFilter() const { return m_filter; }
|
||||||
|
|
||||||
|
void SetSortMode( SORT_MODE aMode ) { m_sort_mode = aMode; }
|
||||||
|
SORT_MODE GetSortMode() const { return m_sort_mode; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to show units. May be set at any time; updates at the next
|
* Whether or not to show units. May be set at any time; updates at the next
|
||||||
* UpdateSearchString()
|
* UpdateSearchString()
|
||||||
|
@ -415,6 +423,7 @@ private:
|
||||||
EDA_BASE_FRAME* m_parent;
|
EDA_BASE_FRAME* m_parent;
|
||||||
|
|
||||||
SYM_FILTER_TYPE m_filter;
|
SYM_FILTER_TYPE m_filter;
|
||||||
|
SORT_MODE m_sort_mode;
|
||||||
bool m_show_units;
|
bool m_show_units;
|
||||||
LIB_ID m_preselect_lib_id;
|
LIB_ID m_preselect_lib_id;
|
||||||
int m_preselect_unit;
|
int m_preselect_unit;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||||
* Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -35,6 +35,7 @@ class wxHtmlLinkEvent;
|
||||||
class wxSearchCtrl;
|
class wxSearchCtrl;
|
||||||
class wxTimer;
|
class wxTimer;
|
||||||
class wxTimerEvent;
|
class wxTimerEvent;
|
||||||
|
class STD_BITMAP_BUTTON;
|
||||||
class ACTION_MENU;
|
class ACTION_MENU;
|
||||||
class LIB_ID;
|
class LIB_ID;
|
||||||
class LIB_TABLE;
|
class LIB_TABLE;
|
||||||
|
@ -127,6 +128,12 @@ public:
|
||||||
void SetSearchString( const wxString& aSearchString );
|
void SetSearchString( const wxString& aSearchString );
|
||||||
wxString GetSearchString() const;
|
wxString GetSearchString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save/restore the sorting mode.
|
||||||
|
*/
|
||||||
|
void SetSortMode( LIB_TREE_MODEL_ADAPTER::SORT_MODE aMode ) { m_adapter->SetSortMode( aMode ); }
|
||||||
|
LIB_TREE_MODEL_ADAPTER::SORT_MODE GetSortMode() const { return m_adapter->GetSortMode(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate the tree.
|
* Regenerate the tree.
|
||||||
*/
|
*/
|
||||||
|
@ -214,20 +221,19 @@ protected:
|
||||||
void onDebounceTimer( wxTimerEvent& aEvent );
|
void onDebounceTimer( wxTimerEvent& aEvent );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LIB_TABLE* m_lib_table;
|
|
||||||
|
|
||||||
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> m_adapter;
|
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> m_adapter;
|
||||||
|
|
||||||
wxSearchCtrl* m_query_ctrl;
|
wxSearchCtrl* m_query_ctrl;
|
||||||
WX_DATAVIEWCTRL* m_tree_ctrl;
|
STD_BITMAP_BUTTON* m_sort_ctrl;
|
||||||
HTML_WINDOW* m_details_ctrl;
|
WX_DATAVIEWCTRL* m_tree_ctrl;
|
||||||
wxTimer* m_debounceTimer;
|
HTML_WINDOW* m_details_ctrl;
|
||||||
bool m_inTimerEvent;
|
wxTimer* m_debounceTimer;
|
||||||
|
bool m_inTimerEvent;
|
||||||
|
|
||||||
LIB_ID m_last_libid;
|
LIB_ID m_last_libid;
|
||||||
wxString m_recentSearchesKey;
|
wxString m_recentSearchesKey;
|
||||||
|
|
||||||
bool m_skipNextRightClick;
|
bool m_skipNextRightClick;
|
||||||
};
|
};
|
||||||
|
|
||||||
///< Custom event sent when a new symbol is preselected
|
///< Custom event sent when a new symbol is preselected
|
||||||
|
|
|
@ -119,26 +119,29 @@ DIALOG_CHOOSE_FOOTPRINT::DIALOG_CHOOSE_FOOTPRINT( PCB_BASE_FRAME* aParent,
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
|
|
||||||
auto cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
|
if( PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>() )
|
||||||
|
{
|
||||||
|
// We specify the width of the right window (m_symbol_view_panel), because specify
|
||||||
|
// the width of the left window does not work as expected when SetSashGravity() is called
|
||||||
|
if( cfg->m_FootprintChooser.sash_h < 0 )
|
||||||
|
cfg->m_FootprintChooser.sash_h = horizPixelsFromDU( 220 );
|
||||||
|
|
||||||
// We specify the width of the right window (m_symbol_view_panel), because specify
|
m_hsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_h );
|
||||||
// the width of the left window does not work as expected when SetSashGravity() is called
|
|
||||||
if( cfg->m_FootprintChooser.sash_h < 0 )
|
|
||||||
cfg->m_FootprintChooser.sash_h = horizPixelsFromDU( 220 );
|
|
||||||
|
|
||||||
m_hsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_h );
|
if( cfg->m_FootprintChooser.sash_v < 0 )
|
||||||
|
cfg->m_FootprintChooser.sash_v = horizPixelsFromDU( 230 );
|
||||||
|
|
||||||
if( cfg->m_FootprintChooser.sash_v < 0 )
|
if( m_vsplitter )
|
||||||
cfg->m_FootprintChooser.sash_v = horizPixelsFromDU( 230 );
|
m_vsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_v );
|
||||||
|
|
||||||
if( m_vsplitter )
|
int w = cfg->m_FootprintChooser.width < 0 ?
|
||||||
m_vsplitter->SetSashPosition( cfg->m_FootprintChooser.sash_v );
|
horizPixelsFromDU( 440 ) : cfg->m_FootprintChooser.width;
|
||||||
|
int h = cfg->m_FootprintChooser.height < 0 ?
|
||||||
|
horizPixelsFromDU( 340 ) : cfg->m_FootprintChooser.height;
|
||||||
|
SetSize( wxSize( w, h ) );
|
||||||
|
|
||||||
int w = cfg->m_FootprintChooser.width < 0 ?
|
aAdapter->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) cfg->m_FootprintChooser.sort_mode );
|
||||||
horizPixelsFromDU( 440 ) : cfg->m_FootprintChooser.width;
|
}
|
||||||
int h = cfg->m_FootprintChooser.height < 0 ?
|
|
||||||
horizPixelsFromDU( 340 ) : cfg->m_FootprintChooser.height;
|
|
||||||
SetSize( wxSize( w, h ) );
|
|
||||||
|
|
||||||
SetInitialFocus( m_tree->GetFocusTarget() );
|
SetInitialFocus( m_tree->GetFocusTarget() );
|
||||||
}
|
}
|
||||||
|
@ -157,14 +160,17 @@ DIALOG_CHOOSE_FOOTPRINT::~DIALOG_CHOOSE_FOOTPRINT()
|
||||||
m_dbl_click_timer->Stop();
|
m_dbl_click_timer->Stop();
|
||||||
delete m_dbl_click_timer;
|
delete m_dbl_click_timer;
|
||||||
|
|
||||||
auto cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
|
if( PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>() )
|
||||||
|
{
|
||||||
|
cfg->m_FootprintChooser.width = GetSize().x;
|
||||||
|
cfg->m_FootprintChooser.height = GetSize().y;
|
||||||
|
cfg->m_FootprintChooser.sash_h = m_hsplitter->GetSashPosition();
|
||||||
|
|
||||||
cfg->m_FootprintChooser.width = GetSize().x;
|
if( m_vsplitter )
|
||||||
cfg->m_FootprintChooser.height = GetSize().y;
|
cfg->m_FootprintChooser.sash_v = m_vsplitter->GetSashPosition();
|
||||||
cfg->m_FootprintChooser.sash_h = m_hsplitter->GetSashPosition();
|
|
||||||
|
|
||||||
if( m_vsplitter )
|
cfg->m_FootprintChooser.sort_mode = m_tree->GetSortMode();
|
||||||
cfg->m_FootprintChooser.sash_v = m_vsplitter->GetSashPosition();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -626,6 +626,8 @@ void FOOTPRINT_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
|
||||||
|
|
||||||
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetFilter() = cfg->m_SelectionFilter;
|
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetFilter() = cfg->m_SelectionFilter;
|
||||||
m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );
|
m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );
|
||||||
|
|
||||||
|
m_treePane->GetLibTree()->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) cfg->m_LibrarySortMode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,6 +660,8 @@ void FOOTPRINT_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
|
||||||
|
|
||||||
cfg->m_AuiPanels.properties_splitter_proportion =
|
cfg->m_AuiPanels.properties_splitter_proportion =
|
||||||
m_propertiesPanel->SplitterProportion();
|
m_propertiesPanel->SplitterProportion();
|
||||||
|
|
||||||
|
cfg->m_LibrarySortMode = m_treePane->GetLibTree()->GetSortMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() :
|
||||||
m_params.emplace_back( new PARAM<bool>( "aui.show_properties",
|
m_params.emplace_back( new PARAM<bool>( "aui.show_properties",
|
||||||
&m_AuiPanels.show_properties, false ) );
|
&m_AuiPanels.show_properties, false ) );
|
||||||
|
|
||||||
|
m_params.emplace_back( new PARAM<int>( "library.sort_mode",
|
||||||
|
&m_LibrarySortMode, 0 ) );
|
||||||
|
|
||||||
m_params.emplace_back( new PARAM<wxString>( "system.last_import_export_path",
|
m_params.emplace_back( new PARAM<wxString>( "system.last_import_export_path",
|
||||||
&m_LastImportExportPath, "" ) );
|
&m_LastImportExportPath, "" ) );
|
||||||
|
|
||||||
|
|
|
@ -567,16 +567,16 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateFootprintList()
|
||||||
|
|
||||||
while( tokenizer.HasMoreTokens() )
|
while( tokenizer.HasMoreTokens() )
|
||||||
{
|
{
|
||||||
const wxString term = tokenizer.GetNextToken().Lower();
|
const wxString filterTerm = tokenizer.GetNextToken().Lower();
|
||||||
EDA_COMBINED_MATCHER matcher( term, CTX_LIBITEM );
|
EDA_COMBINED_MATCHER matcher( filterTerm, CTX_LIBITEM );
|
||||||
|
|
||||||
for( const std::unique_ptr<FOOTPRINT_INFO>& footprint : fp_info_list->GetList() )
|
for( const std::unique_ptr<FOOTPRINT_INFO>& footprint : fp_info_list->GetList() )
|
||||||
{
|
{
|
||||||
wxString search = footprint->GetFootprintName() + wxS( " " ) + footprint->GetSearchText();
|
std::vector<SEARCH_TERM> searchTerms = footprint->GetSearchTerms();
|
||||||
bool matched = matcher.Find( search.Lower() );
|
int matched = matcher.ScoreTerms( searchTerms );
|
||||||
|
|
||||||
if( !matched && term.IsNumber() )
|
if( filterTerm.IsNumber() && wxAtoi( filterTerm ) == (int)footprint->GetPadCount() )
|
||||||
matched = ( wxAtoi( term ) == (int)footprint->GetPadCount() );
|
matched++;
|
||||||
|
|
||||||
if( !matched )
|
if( !matched )
|
||||||
excludes.insert( footprint->GetFootprintName() );
|
excludes.insert( footprint->GetFootprintName() );
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -130,6 +130,9 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
|
||||||
m_params.emplace_back( new PARAM<int>( "footprint_chooser.sash_v",
|
m_params.emplace_back( new PARAM<int>( "footprint_chooser.sash_v",
|
||||||
&m_FootprintChooser.sash_v, -1 ) );
|
&m_FootprintChooser.sash_v, -1 ) );
|
||||||
|
|
||||||
|
m_params.emplace_back( new PARAM<int>( "footprint_chooser.sort_mode",
|
||||||
|
&m_FootprintChooser.sort_mode, 0 ) );
|
||||||
|
|
||||||
m_params.emplace_back( new PARAM<bool>( "editing.flip_left_right",
|
m_params.emplace_back( new PARAM<bool>( "editing.flip_left_right",
|
||||||
&m_FlipLeftRight, true ) );
|
&m_FlipLeftRight, true ) );
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
@ -296,6 +296,7 @@ public:
|
||||||
int height;
|
int height;
|
||||||
int sash_h;
|
int sash_h;
|
||||||
int sash_v;
|
int sash_v;
|
||||||
|
int sort_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ZONES
|
struct ZONES
|
||||||
|
|
Loading…
Reference in New Issue