Experiment with loading recent searches into the search menu.

Fixes https://gitlab.com/kicad/code/kicad/issues/11743
This commit is contained in:
Jeff Young 2022-09-15 14:32:27 +01:00
parent 83fb06ff75
commit a21d24a4c8
6 changed files with 83 additions and 12 deletions

View File

@ -23,6 +23,7 @@
*/
#include <widgets/lib_tree.h>
#include <core/kicad_algo.h>
#include <macros.h>
#include <wxdataviewctrl_helpers.h>
#include <wx/sizer.h>
@ -33,13 +34,20 @@
#include <wx/timer.h>
LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable,
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>& aAdapter, FLAGS aFlags,
constexpr int RECENT_SEARCHES_MAX = 10;
std::map<wxString, std::vector<wxString>> g_recentSearches;
LIB_TREE::LIB_TREE( wxWindow* aParent, const wxString& aRecentSearchesKey, LIB_TABLE* aLibTable,
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>& aAdapter, int aFlags,
HTML_WINDOW* aDetails ) :
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxWANTS_CHARS | wxTAB_TRAVERSAL | wxNO_BORDER ),
m_lib_table( aLibTable ), m_adapter( aAdapter ), m_query_ctrl( nullptr ),
m_details_ctrl( nullptr )
m_details_ctrl( nullptr ),
m_inTimerEvent( false ),
m_recentSearchesKey( aRecentSearchesKey )
{
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
@ -76,6 +84,17 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable,
m_query_ctrl->Bind( wxEVT_CHAR_HOOK, &LIB_TREE::onQueryCharHook, this );
m_query_ctrl->Bind( wxEVT_MOTION, &LIB_TREE::onQueryMouseMoved, this );
m_query_ctrl->Bind( wxEVT_MENU,
[this]( wxCommandEvent& aEvent )
{
wxString search;
size_t idx = aEvent.GetId() - 1;
if( idx < g_recentSearches[ m_recentSearchesKey ].size() )
m_query_ctrl->SetValue( g_recentSearches[ m_recentSearchesKey ][idx] );
},
1, RECENT_SEARCHES_MAX );
Bind( wxEVT_TIMER, &LIB_TREE::onDebounceTimer, this, m_debounceTimer->GetId() );
}
@ -124,6 +143,7 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable,
m_query_ctrl->SetDescriptiveText( _( "Filter" ) );
m_query_ctrl->SetFocus();
m_query_ctrl->SetValue( wxEmptyString );
updateRecentSearchMenu();
// Force an update of the adapter with the empty text to ensure preselect is done
Regenerate( false );
@ -235,6 +255,35 @@ wxString LIB_TREE::GetSearchString() const
}
void LIB_TREE::updateRecentSearchMenu()
{
wxString newEntry = GetSearchString();
std::vector<wxString>& recents = g_recentSearches[ m_recentSearchesKey ];
if( !newEntry.IsEmpty() )
{
if( alg::contains( recents, newEntry ) )
alg::delete_matching( recents, newEntry );
if( recents.size() >= RECENT_SEARCHES_MAX )
recents.pop_back();
recents.insert( recents.begin(), newEntry );
}
wxMenu* menu = new wxMenu();
for( const wxString& recent : recents )
menu->Append( menu->GetMenuItemCount() + 1, recent );
if( recents.empty() )
menu->Append( wxID_ANY, _( "recent searches" ) );
m_query_ctrl->SetMenu( menu );
}
void LIB_TREE::Regenerate( bool aKeepState )
{
STATE current;
@ -406,6 +455,8 @@ void LIB_TREE::onQueryText( wxCommandEvent& aEvent )
void LIB_TREE::onQueryEnter( wxCommandEvent& aEvent )
{
updateRecentSearchMenu();
if( GetSelectedLibId().IsValid() )
postSelectEvent();
}
@ -413,7 +464,9 @@ void LIB_TREE::onQueryEnter( wxCommandEvent& aEvent )
void LIB_TREE::onDebounceTimer( wxTimerEvent& aEvent )
{
m_inTimerEvent = true;
Regenerate( false );
m_inTimerEvent = false;
}
@ -425,26 +478,34 @@ void LIB_TREE::onQueryCharHook( wxKeyEvent& aKeyStroke )
switch( aKeyStroke.GetKeyCode() )
{
case WXK_UP:
updateRecentSearchMenu();
selectIfValid( GetPrevItem( *m_tree_ctrl, sel ) );
break;
case WXK_DOWN:
updateRecentSearchMenu();
selectIfValid( GetNextItem( *m_tree_ctrl, sel ) );
break;
case WXK_ADD:
updateRecentSearchMenu();
if( type == LIB_TREE_NODE::LIB )
m_tree_ctrl->Expand( sel );
break;
case WXK_SUBTRACT:
updateRecentSearchMenu();
if( type == LIB_TREE_NODE::LIB )
m_tree_ctrl->Collapse( sel );
break;
case WXK_RETURN:
updateRecentSearchMenu();
if( type == LIB_TREE_NODE::LIB )
toggleExpand( sel );
else
@ -476,6 +537,9 @@ void LIB_TREE::onQueryMouseMoved( wxMouseEvent& aEvent )
void LIB_TREE::onTreeSelect( wxDataViewEvent& aEvent )
{
if( !m_inTimerEvent )
updateRecentSearchMenu();
if( !m_tree_ctrl->IsFrozen() )
postPreselectEvent();
}

View File

@ -126,8 +126,9 @@ DIALOG_CHOOSE_SYMBOL::DIALOG_CHOOSE_SYMBOL( SCH_BASE_FRAME* aParent, const wxStr
wxBoxSizer* treeSizer = new wxBoxSizer( wxVERTICAL );
treePanel->SetSizer( treeSizer );
m_tree = new LIB_TREE( treePanel, Prj().SchSymbolLibTable(), aAdapter,
LIB_TREE::FLAGS::ALL_WIDGETS, m_details );
m_tree = new LIB_TREE( treePanel, m_showPower ? wxT( "power" ) : wxT( "symbols" ),
Prj().SchSymbolLibTable(), aAdapter, LIB_TREE::FLAGS::ALL_WIDGETS,
m_details );
treeSizer->Add( m_tree, 1, wxEXPAND | wxALL, 5 );
treePanel->Layout();

View File

@ -39,9 +39,8 @@ SYMBOL_TREE_PANE::SYMBOL_TREE_PANE( SYMBOL_EDIT_FRAME* aParent, SYMBOL_LIBRARY_M
{
// Create widgets
wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
m_tree = new LIB_TREE( this, &SYMBOL_LIB_TABLE::GetGlobalLibTable(), m_libMgr->GetAdapter(),
static_cast<LIB_TREE::FLAGS>( LIB_TREE::SEARCH |
LIB_TREE::MULTISELECT ) );
m_tree = new LIB_TREE( this, wxT( "symbols" ), &SYMBOL_LIB_TABLE::GetGlobalLibTable(),
m_libMgr->GetAdapter(), LIB_TREE::SEARCH | LIB_TREE::MULTISELECT );
boxSizer->Add( m_tree, 1, wxEXPAND, 5 );
SetSizer( boxSizer ); // should remove the previous sizer according to wxWidgets docs

View File

@ -59,14 +59,16 @@ public:
* Construct a symbol tree.
*
* @param aParent parent window containing this tree widget
* @param aRecentSearchesKey a key into a global map storing recent searches (usually "power",
* "symbols", or "footprints", but could be further differentiated)
* @param aLibTable table containing libraries and items to display
* @param aAdapter a LIB_TREE_MODEL_ADAPTER instance to use
* @param aFlags selection of sub-widgets to include and other options
* @param aDetails if not null, a custom HTML_WINDOW to hold symbol details. If null this
* will be created inside the LIB_TREE.
*/
LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable,
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>& aAdapter, FLAGS aFlags = ALL_WIDGETS,
LIB_TREE( wxWindow* aParent, const wxString& aRecentSearchesKey, LIB_TABLE* aLibTable,
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>& aAdapter, int aFlags = ALL_WIDGETS,
HTML_WINDOW* aDetails = nullptr );
~LIB_TREE() override;
@ -186,6 +188,8 @@ protected:
*/
void setState( const STATE& aState );
void updateRecentSearchMenu();
void onQueryText( wxCommandEvent& aEvent );
void onQueryEnter( wxCommandEvent& aEvent );
void onQueryCharHook( wxKeyEvent& aEvent );
@ -210,8 +214,10 @@ protected:
wxDataViewCtrl* m_tree_ctrl;
HTML_WINDOW* m_details_ctrl;
wxTimer* m_debounceTimer;
bool m_inTimerEvent;
LIB_ID m_last_libid;
wxString m_recentSearchesKey;
};
///< Custom event sent when a new symbol is preselected

View File

@ -81,7 +81,7 @@ DIALOG_CHOOSE_FOOTPRINT::DIALOG_CHOOSE_FOOTPRINT( PCB_BASE_FRAME* aParent,
sizer->Add( m_vsplitter, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
m_tree = new LIB_TREE( m_hsplitter, Prj().PcbFootprintLibs(), aAdapter,
m_tree = new LIB_TREE( m_hsplitter, wxT( "footprints" ), Prj().PcbFootprintLibs(), aAdapter,
LIB_TREE::FLAGS::ALL_WIDGETS, details );
m_hsplitter->SetSashGravity( 0.8 );

View File

@ -34,7 +34,8 @@ FOOTPRINT_TREE_PANE::FOOTPRINT_TREE_PANE( FOOTPRINT_EDIT_FRAME* aParent )
{
// Create widgets
wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
m_tree = new LIB_TREE( this, &GFootprintTable, m_frame->GetLibTreeAdapter(), LIB_TREE::SEARCH );
m_tree = new LIB_TREE( this, wxT( "footprints" ), &GFootprintTable,
m_frame->GetLibTreeAdapter(), LIB_TREE::SEARCH );
boxSizer->Add( m_tree, 1, wxEXPAND, 5 );
SetSizer( boxSizer ); // should remove the previous sizer according to wxWidgets docs