Add pinned library support to Footprint and Symbol Viewers.

Also includes adding libraray and symbol filters to Symbol Viewer.
This commit is contained in:
Jeff Young 2022-07-09 12:41:03 -06:00
parent 120c5b9ac1
commit 190fb23e88
9 changed files with 446 additions and 109 deletions

View File

@ -201,6 +201,7 @@ set( COMMON_WIDGET_SRCS
widgets/wx_busy_indicator.cpp widgets/wx_busy_indicator.cpp
widgets/wx_ellipsized_static_text.cpp widgets/wx_ellipsized_static_text.cpp
widgets/wx_grid.cpp widgets/wx_grid.cpp
widgets/wx_listbox.cpp
widgets/wx_panel.cpp widgets/wx_panel.cpp
widgets/wx_progress_reporters.cpp widgets/wx_progress_reporters.cpp
widgets/wx_splitter_window.cpp widgets/wx_splitter_window.cpp

View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <widgets/wx_listbox.h>
#include <lib_tree_model_adapter.h>
/*
* A specialization of wxListBox with support for pinned items.
*/
wxString WX_LISTBOX::GetStringSelection() const
{
wxString str = wxListBox::GetStringSelection();
if( str.StartsWith( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() ) )
str = str.substr( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol().length() );
return str;
}
bool WX_LISTBOX::SetStringSelection( const wxString& s )
{
if( wxListBox::SetStringSelection( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + s ) )
return true;
return wxListBox::SetStringSelection( s );
}
bool WX_LISTBOX::SetStringSelection( const wxString& s, bool select )
{
if( wxListBox::SetStringSelection( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + s, select ) )
return true;
return wxListBox::SetStringSelection( s, select );
}
wxString WX_LISTBOX::GetBaseString( int n ) const
{
wxString str = wxListBox::GetString( n );
if( str.StartsWith( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() ) )
str = str.substr( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol().length() );
return str;
}
int WX_LISTBOX::FindString( const wxString& s, bool bCase ) const
{
int retVal = wxListBox::FindString( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + s, bCase );
if( retVal == wxNOT_FOUND )
retVal = wxListBox::FindString( s, bCase );
return retVal;
}

View File

@ -70,7 +70,9 @@ enum id_eeschema_frm
ID_LIBVIEW_NEXT, ID_LIBVIEW_NEXT,
ID_LIBVIEW_PREVIOUS, ID_LIBVIEW_PREVIOUS,
ID_LIBVIEW_SELECT_UNIT_NUMBER, ID_LIBVIEW_SELECT_UNIT_NUMBER,
ID_LIBVIEW_LIB_FILTER,
ID_LIBVIEW_LIB_LIST, ID_LIBVIEW_LIB_LIST,
ID_LIBVIEW_SYM_FILTER,
ID_LIBVIEW_SYM_LIST, ID_LIBVIEW_SYM_LIST,
ID_SIM_RUN, ID_SIM_RUN,

View File

@ -33,11 +33,13 @@
#include <kiway.h> #include <kiway.h>
#include <symbol_viewer_frame.h> #include <symbol_viewer_frame.h>
#include <widgets/msgpanel.h> #include <widgets/msgpanel.h>
#include <widgets/wx_listbox.h>
#include <sch_view.h> #include <sch_view.h>
#include <sch_painter.h> #include <sch_painter.h>
#include <symbol_lib_table.h> #include <symbol_lib_table.h>
#include <symbol_tree_model_adapter.h> #include <symbol_tree_model_adapter.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <project/project_file.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <tool/action_toolbar.h> #include <tool/action_toolbar.h>
#include <tool/common_control.h> #include <tool/common_control.h>
@ -51,10 +53,11 @@
#include <tools/symbol_editor_control.h> #include <tools/symbol_editor_control.h>
#include <tools/ee_inspection_tool.h> #include <tools/ee_inspection_tool.h>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <wx/listbox.h> #include <wx/srchctrl.h>
#include <default_values.h> #include <default_values.h>
#include <string_utils.h> #include <string_utils.h>
#include "eda_pattern_match.h"
// Save previous symbol library viewer state. // Save previous symbol library viewer state.
wxString SYMBOL_VIEWER_FRAME::m_libraryName; wxString SYMBOL_VIEWER_FRAME::m_libraryName;
@ -76,9 +79,11 @@ BEGIN_EVENT_TABLE( SYMBOL_VIEWER_FRAME, EDA_DRAW_FRAME )
EVT_CHOICE( ID_LIBVIEW_SELECT_UNIT_NUMBER, SYMBOL_VIEWER_FRAME::onSelectSymbolUnit ) EVT_CHOICE( ID_LIBVIEW_SELECT_UNIT_NUMBER, SYMBOL_VIEWER_FRAME::onSelectSymbolUnit )
// listbox events // listbox events
EVT_TEXT( ID_LIBVIEW_LIB_FILTER, SYMBOL_VIEWER_FRAME::OnLibFilter )
EVT_LISTBOX( ID_LIBVIEW_LIB_LIST, SYMBOL_VIEWER_FRAME::ClickOnLibList ) EVT_LISTBOX( ID_LIBVIEW_LIB_LIST, SYMBOL_VIEWER_FRAME::ClickOnLibList )
EVT_LISTBOX( ID_LIBVIEW_SYM_LIST, SYMBOL_VIEWER_FRAME::ClickOnCmpList ) EVT_TEXT( ID_LIBVIEW_SYM_FILTER, SYMBOL_VIEWER_FRAME::OnSymFilter )
EVT_LISTBOX_DCLICK( ID_LIBVIEW_SYM_LIST, SYMBOL_VIEWER_FRAME::DClickOnCmpList ) EVT_LISTBOX( ID_LIBVIEW_SYM_LIST, SYMBOL_VIEWER_FRAME::ClickOnSymbolList )
EVT_LISTBOX_DCLICK( ID_LIBVIEW_SYM_LIST, SYMBOL_VIEWER_FRAME::DClickOnSymbolList )
// Menu (and/or hotkey) events // Menu (and/or hotkey) events
EVT_MENU( wxID_CLOSE, SYMBOL_VIEWER_FRAME::CloseLibraryViewer ) EVT_MENU( wxID_CLOSE, SYMBOL_VIEWER_FRAME::CloseLibraryViewer )
@ -150,11 +155,46 @@ SYMBOL_VIEWER_FRAME::SYMBOL_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAM
ReCreateVToolbar(); ReCreateVToolbar();
ReCreateMenuBar(); ReCreateMenuBar();
m_libList = new wxListBox( this, ID_LIBVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize, wxPanel* libPanel = new wxPanel( this );
0, nullptr, wxLB_HSCROLL | wxNO_BORDER ); wxSizer* libSizer = new wxBoxSizer( wxVERTICAL );
m_symbolList = new wxListBox( this, ID_LIBVIEW_SYM_LIST, wxDefaultPosition, wxDefaultSize, m_libFilter = new wxSearchCtrl( libPanel, ID_LIBVIEW_LIB_FILTER, wxEmptyString,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER ); wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_libFilter->SetDescriptiveText( _( "Filter" ) );
libSizer->Add( m_libFilter, 0, wxEXPAND, 5 );
m_libList = new WX_LISTBOX( libPanel, ID_LIBVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
libSizer->Add( m_libList, 1, wxEXPAND, 5 );
libPanel->SetSizer( libSizer );
libPanel->Fit();
wxPanel* symbolPanel = new wxPanel( this );
wxSizer* symbolSizer = new wxBoxSizer( wxVERTICAL );
m_symbolFilter = new wxSearchCtrl( symbolPanel, ID_LIBVIEW_SYM_FILTER, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_symbolFilter->SetDescriptiveText( _( "Filter" ) );
m_symbolFilter->SetToolTip(
_( "Filter on symbol name, keywords, description and pin count.\n"
"Search terms are separated by spaces. All search terms must match.\n"
"A term which is a number will also match against the pin count." ) );
symbolSizer->Add( m_symbolFilter, 0, wxEXPAND, 5 );
#ifdef __WXGTK__
// wxSearchCtrl vertical height is not calculated correctly on some GTK setups
// See https://gitlab.com/kicad/code/kicad/-/issues/9019
m_libFilter->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) );
m_symbolFilter->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) );
#endif
m_symbolList = new WX_LISTBOX( symbolPanel, ID_LIBVIEW_SYM_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
symbolSizer->Add( m_symbolList, 1, wxEXPAND, 5 );
symbolPanel->SetSizer( symbolSizer );
symbolPanel->Fit();
if( aLibraryName.empty() ) if( aLibraryName.empty() )
{ {
@ -175,19 +215,17 @@ SYMBOL_VIEWER_FRAME::SYMBOL_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAM
m_auimgr.SetManagedWindow( this ); m_auimgr.SetManagedWindow( this );
// Manage main toolbar // Manage main toolbar
m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" ).Top().Layer( 6 ) ); m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" ).Top().Layer(6) );
m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" ) m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" ) .Bottom().Layer(6) );
.Bottom().Layer( 6 ) );
m_auimgr.AddPane( m_libList, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(3) m_auimgr.AddPane( libPanel, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(2)
.CaptionVisible( false ).MinSize( 80, -1 ).BestSize( m_libListWidth, -1 ) ); .CaptionVisible( false ).MinSize( 100, -1 ).BestSize( m_libListWidth, -1 ) );
m_auimgr.AddPane( m_symbolList, EDA_PANE().Palette().Name( "Symbols" ).Left().Layer(1) m_auimgr.AddPane( symbolPanel, EDA_PANE().Palette().Name( "Symbols" ).Left().Layer(1)
.CaptionVisible( false ).MinSize( 80, -1 ) .CaptionVisible( false ).MinSize( 100, -1 ).BestSize( m_symbolListWidth, -1 ) );
.BestSize( m_symbolListWidth, -1 ) );
m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() ); m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() );
m_auimgr.GetPane( m_libList ).Show( aLibraryName.empty() ); m_auimgr.GetPane( libPanel ).Show( aLibraryName.empty() );
m_auimgr.Update(); m_auimgr.Update();
@ -408,6 +446,7 @@ bool SYMBOL_VIEWER_FRAME::ShowModal( wxString* aSymbol, wxWindow* aParent )
} }
} }
m_libFilter->SetFocus();
return KIWAY_PLAYER::ShowModal( aSymbol, aParent ); return KIWAY_PLAYER::ShowModal( aSymbol, aParent );
} }
@ -483,45 +522,69 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
m_libList->Clear(); m_libList->Clear();
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
std::vector<wxString> libs = Prj().SchSymbolLibTable()->GetLogicalLibs(); std::vector<wxString> libs = Prj().SchSymbolLibTable()->GetLogicalLibs();
std::set<wxString> pinnedMatches;
std::set<wxString> otherMatches;
// Remove not allowed libs from main list, if the allowed lib list is not empty auto process =
if( m_allowedLibs.GetCount() ) [&]( const wxString& aLib )
{
// Remove not allowed libs, if the allowed lib list is not empty
if( m_allowedLibs.GetCount() )
{
if( m_allowedLibs.Index( aLib ) == wxNOT_FOUND )
return;
}
// Remove libs which have no power symbols, if this filter is activated
if( m_listPowerOnly )
{
wxArrayString aliasNames;
Prj().SchSymbolLibTable()->EnumerateSymbolLib( aLib, aliasNames, true );
if( aliasNames.IsEmpty() )
return;
}
if( alg::contains( project.m_PinnedSymbolLibs, aLib ) )
pinnedMatches.insert( aLib );
else
otherMatches.insert( aLib );
};
if( m_libFilter->GetValue().IsEmpty() )
{ {
for( unsigned ii = 0; ii < libs.size(); ) for( const wxString& lib : libs )
{ process( lib );
if( m_allowedLibs.Index( libs[ii] ) == wxNOT_FOUND )
libs.erase( libs.begin() + ii );
else
ii++;
}
} }
else
// Remove libs which have no power symbols, if this filter is activated
if( m_listPowerOnly )
{ {
for( unsigned ii = 0; ii < libs.size(); ) wxStringTokenizer tokenizer( m_libFilter->GetValue() );
while( tokenizer.HasMoreTokens() )
{ {
wxArrayString aliasNames; const wxString term = tokenizer.GetNextToken().Lower();
EDA_COMBINED_MATCHER matcher( term );
int matches, position;
Prj().SchSymbolLibTable()->EnumerateSymbolLib( libs[ii], aliasNames, true ); for( const wxString& lib : libs )
{
if( aliasNames.IsEmpty() ) if( matcher.Find( lib.Lower(), matches, position ) )
libs.erase( libs.begin() + ii ); process( lib );
else }
ii++;
} }
} }
if( libs.empty() ) if( libs.empty() )
return true; return true;
wxArrayString libNames; for( const wxString& name : pinnedMatches )
m_libList->Append( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + UnescapeString( name ) );
for( const auto& name : libs ) for( const wxString& name : otherMatches )
libNames.Add( UnescapeString( name ) ); m_libList->Append( UnescapeString( name ) );
m_libList->Append( libNames );
// Search for a previous selection: // Search for a previous selection:
int index = m_libList->FindString( UnescapeString( m_libraryName ) ); int index = m_libList->FindString( UnescapeString( m_libraryName ) );
@ -534,7 +597,7 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
{ {
// If not found, clear current library selection because it can be // If not found, clear current library selection because it can be
// deleted after a config change. // deleted after a config change.
m_libraryName = libs[0]; m_libraryName = m_libList->GetBaseString( 0 );
m_entryName = wxEmptyString; m_entryName = wxEmptyString;
m_unit = 1; m_unit = 1;
m_convert = LIB_ITEM::LIB_CONVERT::BASE; m_convert = LIB_ITEM::LIB_CONVERT::BASE;
@ -553,18 +616,53 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
if( m_symbolList == nullptr ) if( m_symbolList == nullptr )
return false; return false;
wxArrayString aliasNames; m_symbolList->Clear();
if( m_libraryName.IsEmpty() )
return false;
std::vector<LIB_SYMBOL*> symbols;
try try
{ {
Prj().SchSymbolLibTable()->EnumerateSymbolLib( m_libraryName, aliasNames, if( Prj().SchSymbolLibTable()->FindRow( m_libraryName ) )
m_listPowerOnly ); Prj().SchSymbolLibTable()->LoadSymbolLib( symbols, m_libraryName, m_listPowerOnly );
} }
catch( const IO_ERROR& ) {} // ignore, it is handled below catch( const IO_ERROR& ) {} // ignore, it is handled below
m_symbolList->Clear(); std::set<wxString> excludes;
if( aliasNames.IsEmpty() ) if( !m_symbolFilter->GetValue().IsEmpty() )
{
wxStringTokenizer tokenizer( m_symbolFilter->GetValue() );
while( tokenizer.HasMoreTokens() )
{
const wxString term = tokenizer.GetNextToken().Lower();
EDA_COMBINED_MATCHER matcher( term );
int matches, position;
for( LIB_SYMBOL* symbol : symbols )
{
wxString search = symbol->GetName() + wxS( " " ) + symbol->GetSearchText();
bool matched = matcher.Find( search.Lower(), matches, position );
if( !matched && term.IsNumber() )
matched = ( wxAtoi( term ) == (int)symbol->GetPinCount() );
if( !matched )
excludes.insert( symbol->GetName() );
}
}
}
for( const LIB_SYMBOL* symbol : symbols )
{
if( !excludes.count( symbol->GetName() ) )
m_symbolList->Append( UnescapeString( symbol->GetName() ) );
}
if( m_symbolList->IsEmpty() )
{ {
m_libraryName = wxEmptyString; m_libraryName = wxEmptyString;
m_entryName = wxEmptyString; m_entryName = wxEmptyString;
@ -573,13 +671,6 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
return true; return true;
} }
wxArrayString unescapedNames;
for( const wxString& name : aliasNames )
unescapedNames.Add( UnescapeString( name ) );
m_symbolList->Append( unescapedNames );
int index = m_symbolList->FindString( UnescapeString( m_entryName ) ); int index = m_symbolList->FindString( UnescapeString( m_entryName ) );
bool changed = false; bool changed = false;
@ -596,9 +687,6 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
m_symbolList->SetSelection( index, true ); m_symbolList->SetSelection( index, true );
wxCommandEvent evt( wxEVT_COMMAND_LISTBOX_SELECTED, ID_LIBVIEW_SYM_LIST );
ProcessEvent( evt );
return changed; return changed;
} }
@ -612,7 +700,7 @@ void SYMBOL_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& event )
m_selection_changed = true; m_selection_changed = true;
SetSelectedLibrary( EscapeString( m_libList->GetString( ii ), CTX_LIBID ) ); SetSelectedLibrary( EscapeString( m_libList->GetBaseString( ii ), CTX_LIBID ) );
} }
@ -639,7 +727,7 @@ void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName )
} }
void SYMBOL_VIEWER_FRAME::ClickOnCmpList( wxCommandEvent& event ) void SYMBOL_VIEWER_FRAME::ClickOnSymbolList( wxCommandEvent& event )
{ {
int ii = m_symbolList->GetSelection(); int ii = m_symbolList->GetSelection();
@ -648,7 +736,7 @@ void SYMBOL_VIEWER_FRAME::ClickOnCmpList( wxCommandEvent& event )
m_selection_changed = true; m_selection_changed = true;
SetSelectedSymbol( EscapeString( m_symbolList->GetString( ii ), CTX_LIBID ) ); SetSelectedSymbol( EscapeString( m_symbolList->GetBaseString( ii ), CTX_LIBID ) );
// The m_symbolList has now the focus, in order to be able to use arrow keys // The m_symbolList has now the focus, in order to be able to use arrow keys
// to navigate inside the list. // to navigate inside the list.
@ -666,7 +754,7 @@ void SYMBOL_VIEWER_FRAME::SetSelectedSymbol( const wxString& aSymbolName )
// Ensure the corresponding line in m_symbolList is selected // Ensure the corresponding line in m_symbolList is selected
// (which is not necessarily the case if SetSelectedSymbol is called // (which is not necessarily the case if SetSelectedSymbol is called
// by another caller than ClickOnCmpList. // by another caller than ClickOnSymbolList.
m_symbolList->SetStringSelection( UnescapeString( aSymbolName ), true ); m_symbolList->SetStringSelection( UnescapeString( aSymbolName ), true );
DisplayLibInfos(); DisplayLibInfos();
@ -682,7 +770,7 @@ void SYMBOL_VIEWER_FRAME::SetSelectedSymbol( const wxString& aSymbolName )
} }
void SYMBOL_VIEWER_FRAME::DClickOnCmpList( wxCommandEvent& event ) void SYMBOL_VIEWER_FRAME::DClickOnSymbolList( wxCommandEvent& event )
{ {
m_toolManager->RunAction( EE_ACTIONS::addSymbolToSchematic, true ); m_toolManager->RunAction( EE_ACTIONS::addSymbolToSchematic, true );
} }
@ -881,6 +969,96 @@ void SYMBOL_VIEWER_FRAME::OnSelectSymbol( wxCommandEvent& aEvent )
} }
void SYMBOL_VIEWER_FRAME::OnLibFilter( wxCommandEvent& aEvent )
{
ReCreateLibList();
// Required to avoid interaction with SetHint()
// See documentation for wxTextEntry::SetHint
aEvent.Skip();
}
void SYMBOL_VIEWER_FRAME::OnSymFilter( wxCommandEvent& aEvent )
{
ReCreateSymbolList();
// Required to avoid interaction with SetHint()
// See documentation for wxTextEntry::SetHint
aEvent.Skip();
}
void SYMBOL_VIEWER_FRAME::OnCharHook( wxKeyEvent& aEvent )
{
if( aEvent.GetKeyCode() == WXK_UP )
{
if( m_libFilter->HasFocus() || m_libList->HasFocus() )
{
int prev = m_libList->GetSelection() - 1;
if( prev >= 0 )
{
m_libList->SetSelection( prev );
m_libList->EnsureVisible( prev );
wxCommandEvent dummy;
ClickOnLibList( dummy );
}
}
else
{
wxCommandEvent dummy;
onSelectPreviousSymbol( dummy );
}
}
else if( aEvent.GetKeyCode() == WXK_DOWN )
{
if( m_libFilter->HasFocus() || m_libList->HasFocus() )
{
int next = m_libList->GetSelection() + 1;
if( next < (int)m_libList->GetCount() )
{
m_libList->SetSelection( next );
m_libList->EnsureVisible( next );
wxCommandEvent dummy;
ClickOnLibList( dummy );
}
}
else
{
wxCommandEvent dummy;
onSelectNextSymbol( dummy );
}
}
else if( aEvent.GetKeyCode() == WXK_TAB && m_libFilter->HasFocus() )
{
if( !aEvent.ShiftDown() )
m_symbolFilter->SetFocus();
else
aEvent.Skip();
}
else if( aEvent.GetKeyCode() == WXK_TAB && m_symbolFilter->HasFocus() )
{
if( aEvent.ShiftDown() )
m_libFilter->SetFocus();
else
aEvent.Skip();
}
else if( aEvent.GetKeyCode() == WXK_RETURN && m_symbolList->GetSelection() >= 0 )
{
wxCommandEvent dummy;
DClickOnSymbolList( dummy );
}
else
{
aEvent.Skip();
}
}
void SYMBOL_VIEWER_FRAME::onSelectNextSymbol( wxCommandEvent& aEvent ) void SYMBOL_VIEWER_FRAME::onSelectNextSymbol( wxCommandEvent& aEvent )
{ {
wxCommandEvent evt( wxEVT_COMMAND_LISTBOX_SELECTED, ID_LIBVIEW_SYM_LIST ); wxCommandEvent evt( wxEVT_COMMAND_LISTBOX_SELECTED, ID_LIBVIEW_SYM_LIST );

View File

@ -31,7 +31,8 @@
#include <sch_screen.h> #include <sch_screen.h>
#include <tool/selection.h> #include <tool/selection.h>
class wxListBox; class WX_LISTBOX;
class wxSearchCtrl;
class SYMBOL_LIBRARY_FILTER; class SYMBOL_LIBRARY_FILTER;
class LIB_SYMBOL; class LIB_SYMBOL;
class SYMBOL_LIB_TABLE_ROW; class SYMBOL_LIB_TABLE_ROW;
@ -95,7 +96,7 @@ public:
void ReCreateMenuBar() override; void ReCreateMenuBar() override;
void ClickOnLibList( wxCommandEvent& event ); void ClickOnLibList( wxCommandEvent& event );
void ClickOnCmpList( wxCommandEvent& event ); void ClickOnSymbolList( wxCommandEvent& event );
void OnSelectSymbol( wxCommandEvent& aEvent ); void OnSelectSymbol( wxCommandEvent& aEvent );
void LoadSettings( APP_SETTINGS_BASE* aCfg ) override; void LoadSettings( APP_SETTINGS_BASE* aCfg ) override;
@ -154,10 +155,14 @@ private:
*/ */
void OnActivate( wxActivateEvent& event ); void OnActivate( wxActivateEvent& event );
void DClickOnCmpList( wxCommandEvent& event ); void DClickOnSymbolList( wxCommandEvent& event );
void onUpdateUnitChoice( wxUpdateUIEvent& aEvent ); void onUpdateUnitChoice( wxUpdateUIEvent& aEvent );
void OnLibFilter( wxCommandEvent& aEvent );
void OnSymFilter( wxCommandEvent& aEvent );
void OnCharHook( wxKeyEvent& aEvent ) override;
void onSelectNextSymbol( wxCommandEvent& aEvent ); void onSelectNextSymbol( wxCommandEvent& aEvent );
void onSelectPreviousSymbol( wxCommandEvent& aEvent ); void onSelectPreviousSymbol( wxCommandEvent& aEvent );
void onSelectSymbolUnit( wxCommandEvent& aEvent ); void onSelectSymbolUnit( wxCommandEvent& aEvent );
@ -167,10 +172,12 @@ private:
private: private:
wxChoice* m_unitChoice; wxChoice* m_unitChoice;
wxListBox* m_libList; // The list of libraries. wxSearchCtrl* m_libFilter;
WX_LISTBOX* m_libList; // The list of libraries.
int m_libListWidth; // Last width of the window. int m_libListWidth; // Last width of the window.
wxListBox* m_symbolList; // The list of symbols. wxSearchCtrl* m_symbolFilter;
WX_LISTBOX* m_symbolList; // The list of symbols.
int m_symbolListWidth; // Last width of the window. int m_symbolListWidth; // Last width of the window.
// Filters to build list of libs/list of symbols. // Filters to build list of libs/list of symbols.

View File

@ -96,6 +96,16 @@ class EDA_BASE_FRAME;
class LIB_TREE_MODEL_ADAPTER: public wxDataViewModel class LIB_TREE_MODEL_ADAPTER: public wxDataViewModel
{ {
public:
/**
* @return a unicode string to mark a node name like a pinned library name.
* This is not an ASCII7 char, but a unicode char.
*/
static const wxString GetPinningSymbol()
{
return wxString::FromUTF8( "" );
}
public: public:
/** /**
* Destructor. Do NOT delete this class manually; it is reference-counted * Destructor. Do NOT delete this class manually; it is reference-counted
@ -354,16 +364,6 @@ protected:
unsigned int aCol, unsigned int aCol,
wxDataViewItemAttr& aAttr ) const override; wxDataViewItemAttr& aAttr ) const override;
/**
* @return a unicode string to mark a node name like
* a pinned library name
* This is not an ASCII7 char, but a unicode char
*/
const wxString GetPinningSymbol() const
{
return wxString::FromUTF8( "" );
}
private: private:
/** /**
* Find any results worth highlighting and expand them, according to given criteria * Find any results worth highlighting and expand them, according to given criteria

View File

@ -0,0 +1,47 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef KICAD_WX_LISTBOX_H
#define KICAD_WX_LISTBOX_H
#include <wx/listbox.h>
class WX_LISTBOX : public wxListBox
{
public:
WX_LISTBOX( wxWindow *parent, wxWindowID winid, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, int n = 0, const wxString choices[] = NULL,
long style = 0 ) :
wxListBox( parent, winid, pos, size, n, choices, style )
{ }
wxString GetStringSelection() const override;
bool SetStringSelection( const wxString& s ) override;
bool SetStringSelection( const wxString& s, bool select ) override;
wxString GetBaseString( int n ) const;
int FindString( const wxString& s, bool bCase = false ) const override;
};
#endif //KICAD_WX_LISTBOX_H

View File

@ -35,11 +35,13 @@
#include <fp_lib_table.h> #include <fp_lib_table.h>
#include <kiway.h> #include <kiway.h>
#include <widgets/msgpanel.h> #include <widgets/msgpanel.h>
#include <widgets/wx_listbox.h>
#include <pcb_draw_panel_gal.h> #include <pcb_draw_panel_gal.h>
#include <pcb_painter.h> #include <pcb_painter.h>
#include <pcbnew_id.h> #include <pcbnew_id.h>
#include <footprint_editor_settings.h> #include <footprint_editor_settings.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <project/project_file.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <tool/action_toolbar.h> #include <tool/action_toolbar.h>
#include <tool/common_control.h> #include <tool/common_control.h>
@ -56,7 +58,7 @@
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <tools/board_editor_control.h> #include <tools/board_editor_control.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <wx/listbox.h> #include <lib_tree_model_adapter.h>
#include <wx/srchctrl.h> #include <wx/srchctrl.h>
#include <wx/tokenzr.h> #include <wx/tokenzr.h>
#include <wx/choice.h> #include <wx/choice.h>
@ -143,8 +145,8 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
m_libFilter->SetDescriptiveText( _( "Filter" ) ); m_libFilter->SetDescriptiveText( _( "Filter" ) );
libSizer->Add( m_libFilter, 0, wxEXPAND, 5 ); libSizer->Add( m_libFilter, 0, wxEXPAND, 5 );
m_libList = new wxListBox( libPanel, ID_MODVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize, m_libList = new WX_LISTBOX( libPanel, ID_MODVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER ); 0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
libSizer->Add( m_libList, 1, wxEXPAND, 5 ); libSizer->Add( m_libList, 1, wxEXPAND, 5 );
libPanel->SetSizer( libSizer ); libPanel->SetSizer( libSizer );
@ -169,8 +171,8 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
m_fpFilter->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) ); m_fpFilter->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) );
#endif #endif
m_fpList = new wxListBox( fpPanel, ID_MODVIEW_FOOTPRINT_LIST, wxDefaultPosition, wxDefaultSize, m_fpList = new WX_LISTBOX( fpPanel, ID_MODVIEW_FOOTPRINT_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER ); 0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
m_fpList->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( FOOTPRINT_VIEWER_FRAME::DClickOnFootprintList ), nullptr, this ); m_fpList->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( FOOTPRINT_VIEWER_FRAME::DClickOnFootprintList ), nullptr, this );
fpSizer->Add( m_fpList, 1, wxEXPAND, 5 ); fpSizer->Add( m_fpList, 1, wxEXPAND, 5 );
@ -266,7 +268,7 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
// Vertical items; layers 1 - 3 // Vertical items; layers 1 - 3
m_auimgr.AddPane( libPanel, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(2) m_auimgr.AddPane( libPanel, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(2)
.CaptionVisible( false ).MinSize( 100, -1 ).BestSize( 200, -1 ) ); .CaptionVisible( false ).MinSize( 100, -1 ).BestSize( 200, -1 ) );
m_auimgr.AddPane( fpPanel, EDA_PANE().Palette().Name( "Footprints" ).Left().Layer( 1) m_auimgr.AddPane( fpPanel, EDA_PANE().Palette().Name( "Footprints" ).Left().Layer(1)
.CaptionVisible( false ).MinSize( 100, -1 ).BestSize( 300, -1 ) ); .CaptionVisible( false ).MinSize( 100, -1 ).BestSize( 300, -1 ) );
m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() ); m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() );
@ -398,10 +400,26 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateLibraryList()
{ {
m_libList->Clear(); m_libList->Clear();
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
std::vector<wxString> nicknames = Prj().PcbFootprintLibs()->GetLogicalLibs(); std::vector<wxString> nicknames = Prj().PcbFootprintLibs()->GetLogicalLibs();
std::set<wxString> excludes; std::set<wxString> pinnedMatches;
std::set<wxString> otherMatches;
if( !m_libFilter->GetValue().IsEmpty() ) auto process =
[&]( const wxString& aNickname )
{
if( alg::contains( project.m_PinnedFootprintLibs, aNickname ) )
pinnedMatches.insert( aNickname );
else
otherMatches.insert( aNickname );
};
if( m_libFilter->GetValue().IsEmpty() )
{
for( const wxString& nickname : nicknames )
process( nickname );
}
else
{ {
wxStringTokenizer tokenizer( m_libFilter->GetValue() ); wxStringTokenizer tokenizer( m_libFilter->GetValue() );
@ -413,17 +431,17 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateLibraryList()
for( const wxString& nickname : nicknames ) for( const wxString& nickname : nicknames )
{ {
if( !matcher.Find( nickname.Lower(), matches, position ) ) if( matcher.Find( nickname.Lower(), matches, position ) )
excludes.insert( nickname ); process( nickname );
} }
} }
} }
for( const wxString& nickname : nicknames ) for( const wxString& nickname : pinnedMatches )
{ m_libList->Append( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + nickname );
if( !excludes.count( nickname ) )
m_libList->Append( nickname ); for( const wxString& nickname : otherMatches )
} m_libList->Append( nickname );
// Search for a previous selection: // Search for a previous selection:
int index = m_libList->FindString( getCurNickname(), true ); int index = m_libList->FindString( getCurNickname(), true );
@ -595,7 +613,7 @@ void FOOTPRINT_VIEWER_FRAME::OnCharHook( wxKeyEvent& aEvent )
} }
void FOOTPRINT_VIEWER_FRAME::selectPrev( wxListBox* aListBox ) void FOOTPRINT_VIEWER_FRAME::selectPrev( WX_LISTBOX* aListBox )
{ {
int prev = aListBox->GetSelection() - 1; int prev = aListBox->GetSelection() - 1;
@ -614,7 +632,7 @@ void FOOTPRINT_VIEWER_FRAME::selectPrev( wxListBox* aListBox )
} }
void FOOTPRINT_VIEWER_FRAME::selectNext( wxListBox* aListBox ) void FOOTPRINT_VIEWER_FRAME::selectNext( WX_LISTBOX* aListBox )
{ {
int next = aListBox->GetSelection() + 1; int next = aListBox->GetSelection() + 1;
@ -640,7 +658,7 @@ void FOOTPRINT_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& aEvent )
if( ii < 0 ) if( ii < 0 )
return; return;
wxString name = m_libList->GetString( ii ); wxString name = m_libList->GetBaseString( ii );
if( getCurNickname() == name ) if( getCurNickname() == name )
return; return;
@ -662,7 +680,7 @@ void FOOTPRINT_VIEWER_FRAME::ClickOnFootprintList( wxCommandEvent& aEvent )
if( ii < 0 ) if( ii < 0 )
return; return;
wxString name = m_fpList->GetString( ii ); wxString name = m_fpList->GetBaseString( ii );
if( getCurFootprintName().CmpNoCase( name ) != 0 ) if( getCurFootprintName().CmpNoCase( name ) != 0 )
{ {
@ -888,7 +906,7 @@ void FOOTPRINT_VIEWER_FRAME::OnActivate( wxActivateEvent& event )
{ {
for( unsigned ii = 0; ii < libNicknames.size(); ii++ ) for( unsigned ii = 0; ii < libNicknames.size(); ii++ )
{ {
if( libNicknames[ii] != m_libList->GetString( ii ) ) if( libNicknames[ii] != m_libList->GetBaseString( ii ) )
{ {
stale = true; stale = true;
break; break;
@ -1002,13 +1020,17 @@ void FOOTPRINT_VIEWER_FRAME::UpdateTitle()
if( !getCurNickname().IsEmpty() ) if( !getCurNickname().IsEmpty() )
{ {
title = getCurNickname(); try
{
FP_LIB_TABLE* libtable = Prj().PcbFootprintLibs();
const LIB_TABLE_ROW* row = libtable->FindRow( getCurNickname() );
FP_LIB_TABLE* libtable = Prj().PcbFootprintLibs(); title = getCurNickname() + wxT( " \u2014 " ) + row->GetFullURI( true );
const LIB_TABLE_ROW* row = libtable->FindRow( getCurNickname() ); }
catch( ... )
if( row ) {
title += wxT( " \u2014 " ) + row->GetFullURI( true ); title = _( "[no library selected]" );
}
} }
else else
{ {
@ -1045,7 +1067,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectAndViewFootprint( int aMode )
m_fpList->SetSelection( selection ); m_fpList->SetSelection( selection );
m_fpList->EnsureVisible( selection ); m_fpList->EnsureVisible( selection );
setCurFootprintName( m_fpList->GetString((unsigned) selection ) ); setCurFootprintName( m_fpList->GetBaseString( selection ) );
// Delete the current footprint // Delete the current footprint
GetBoard()->DeleteAllFootprints(); GetBoard()->DeleteAllFootprints();

View File

@ -31,7 +31,7 @@
#include <pcbnew_settings.h> #include <pcbnew_settings.h>
class wxSashLayoutWindow; class wxSashLayoutWindow;
class wxListBox; class WX_LISTBOX;
class wxSearchCtrl; class wxSearchCtrl;
class FP_LIB_TABLE; class FP_LIB_TABLE;
class BOARD_ITEM; class BOARD_ITEM;
@ -118,8 +118,8 @@ private:
void OnFPFilter( wxCommandEvent& aEvent ); void OnFPFilter( wxCommandEvent& aEvent );
void OnCharHook( wxKeyEvent& aEvent ) override; void OnCharHook( wxKeyEvent& aEvent ) override;
void selectPrev( wxListBox* aListBox ); void selectPrev( WX_LISTBOX* aListBox );
void selectNext( wxListBox* aListBox ); void selectNext( WX_LISTBOX* aListBox );
void ClickOnLibList( wxCommandEvent& aEvent ); void ClickOnLibList( wxCommandEvent& aEvent );
void ClickOnFootprintList( wxCommandEvent& aEvent ); void ClickOnFootprintList( wxCommandEvent& aEvent );
void DClickOnFootprintList( wxMouseEvent& aEvent ); void DClickOnFootprintList( wxMouseEvent& aEvent );
@ -166,9 +166,9 @@ private:
friend struct PCB::IFACE; // constructor called from here only friend struct PCB::IFACE; // constructor called from here only
wxSearchCtrl* m_libFilter; wxSearchCtrl* m_libFilter;
wxListBox* m_libList; // The list of library names. WX_LISTBOX* m_libList; // The list of library names.
wxSearchCtrl* m_fpFilter; wxSearchCtrl* m_fpFilter;
wxListBox* m_fpList; // The list of footprint names. WX_LISTBOX* m_fpList; // The list of footprint names.
bool m_autoZoom; bool m_autoZoom;
double m_lastZoom; double m_lastZoom;