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_ellipsized_static_text.cpp
widgets/wx_grid.cpp
widgets/wx_listbox.cpp
widgets/wx_panel.cpp
widgets/wx_progress_reporters.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_PREVIOUS,
ID_LIBVIEW_SELECT_UNIT_NUMBER,
ID_LIBVIEW_LIB_FILTER,
ID_LIBVIEW_LIB_LIST,
ID_LIBVIEW_SYM_FILTER,
ID_LIBVIEW_SYM_LIST,
ID_SIM_RUN,

View File

@ -33,11 +33,13 @@
#include <kiway.h>
#include <symbol_viewer_frame.h>
#include <widgets/msgpanel.h>
#include <widgets/wx_listbox.h>
#include <sch_view.h>
#include <sch_painter.h>
#include <symbol_lib_table.h>
#include <symbol_tree_model_adapter.h>
#include <pgm_base.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <tool/action_toolbar.h>
#include <tool/common_control.h>
@ -51,10 +53,11 @@
#include <tools/symbol_editor_control.h>
#include <tools/ee_inspection_tool.h>
#include <view/view_controls.h>
#include <wx/listbox.h>
#include <wx/srchctrl.h>
#include <default_values.h>
#include <string_utils.h>
#include "eda_pattern_match.h"
// Save previous symbol library viewer state.
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 )
// 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_SYM_LIST, SYMBOL_VIEWER_FRAME::ClickOnCmpList )
EVT_LISTBOX_DCLICK( ID_LIBVIEW_SYM_LIST, SYMBOL_VIEWER_FRAME::DClickOnCmpList )
EVT_TEXT( ID_LIBVIEW_SYM_FILTER, SYMBOL_VIEWER_FRAME::OnSymFilter )
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
EVT_MENU( wxID_CLOSE, SYMBOL_VIEWER_FRAME::CloseLibraryViewer )
@ -150,11 +155,46 @@ SYMBOL_VIEWER_FRAME::SYMBOL_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAM
ReCreateVToolbar();
ReCreateMenuBar();
m_libList = new wxListBox( this, ID_LIBVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
wxPanel* libPanel = new wxPanel( this );
wxSizer* libSizer = new wxBoxSizer( wxVERTICAL );
m_symbolList = new wxListBox( this, ID_LIBVIEW_SYM_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
m_libFilter = new wxSearchCtrl( libPanel, ID_LIBVIEW_LIB_FILTER, wxEmptyString,
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() )
{
@ -175,19 +215,17 @@ SYMBOL_VIEWER_FRAME::SYMBOL_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAM
m_auimgr.SetManagedWindow( this );
// Manage main toolbar
m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" ).Top().Layer( 6 ) );
m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
.Bottom().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" ) .Bottom().Layer(6) );
m_auimgr.AddPane( m_libList, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(3)
.CaptionVisible( false ).MinSize( 80, -1 ).BestSize( m_libListWidth, -1 ) );
m_auimgr.AddPane( m_symbolList, EDA_PANE().Palette().Name( "Symbols" ).Left().Layer(1)
.CaptionVisible( false ).MinSize( 80, -1 )
.BestSize( m_symbolListWidth, -1 ) );
m_auimgr.AddPane( libPanel, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(2)
.CaptionVisible( false ).MinSize( 100, -1 ).BestSize( m_libListWidth, -1 ) );
m_auimgr.AddPane( symbolPanel, EDA_PANE().Palette().Name( "Symbols" ).Left().Layer(1)
.CaptionVisible( false ).MinSize( 100, -1 ).BestSize( m_symbolListWidth, -1 ) );
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();
@ -408,6 +446,7 @@ bool SYMBOL_VIEWER_FRAME::ShowModal( wxString* aSymbol, wxWindow* aParent )
}
}
m_libFilter->SetFocus();
return KIWAY_PLAYER::ShowModal( aSymbol, aParent );
}
@ -483,45 +522,69 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
m_libList->Clear();
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
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
if( m_allowedLibs.GetCount() )
auto process =
[&]( 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(); )
{
if( m_allowedLibs.Index( libs[ii] ) == wxNOT_FOUND )
libs.erase( libs.begin() + ii );
else
ii++;
}
for( const wxString& lib : libs )
process( lib );
}
// Remove libs which have no power symbols, if this filter is activated
if( m_listPowerOnly )
else
{
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 );
if( aliasNames.IsEmpty() )
libs.erase( libs.begin() + ii );
else
ii++;
for( const wxString& lib : libs )
{
if( matcher.Find( lib.Lower(), matches, position ) )
process( lib );
}
}
}
if( libs.empty() )
return true;
wxArrayString libNames;
for( const wxString& name : pinnedMatches )
m_libList->Append( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + UnescapeString( name ) );
for( const auto& name : libs )
libNames.Add( UnescapeString( name ) );
m_libList->Append( libNames );
for( const wxString& name : otherMatches )
m_libList->Append( UnescapeString( name ) );
// Search for a previous selection:
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
// deleted after a config change.
m_libraryName = libs[0];
m_libraryName = m_libList->GetBaseString( 0 );
m_entryName = wxEmptyString;
m_unit = 1;
m_convert = LIB_ITEM::LIB_CONVERT::BASE;
@ -553,18 +616,53 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
if( m_symbolList == nullptr )
return false;
wxArrayString aliasNames;
m_symbolList->Clear();
if( m_libraryName.IsEmpty() )
return false;
std::vector<LIB_SYMBOL*> symbols;
try
{
Prj().SchSymbolLibTable()->EnumerateSymbolLib( m_libraryName, aliasNames,
m_listPowerOnly );
if( Prj().SchSymbolLibTable()->FindRow( m_libraryName ) )
Prj().SchSymbolLibTable()->LoadSymbolLib( symbols, m_libraryName, m_listPowerOnly );
}
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_entryName = wxEmptyString;
@ -573,13 +671,6 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
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 ) );
bool changed = false;
@ -596,9 +687,6 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
m_symbolList->SetSelection( index, true );
wxCommandEvent evt( wxEVT_COMMAND_LISTBOX_SELECTED, ID_LIBVIEW_SYM_LIST );
ProcessEvent( evt );
return changed;
}
@ -612,7 +700,7 @@ void SYMBOL_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& event )
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();
@ -648,7 +736,7 @@ void SYMBOL_VIEWER_FRAME::ClickOnCmpList( wxCommandEvent& event )
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
// 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
// (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 );
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 );
}
@ -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 )
{
wxCommandEvent evt( wxEVT_COMMAND_LISTBOX_SELECTED, ID_LIBVIEW_SYM_LIST );

View File

@ -31,7 +31,8 @@
#include <sch_screen.h>
#include <tool/selection.h>
class wxListBox;
class WX_LISTBOX;
class wxSearchCtrl;
class SYMBOL_LIBRARY_FILTER;
class LIB_SYMBOL;
class SYMBOL_LIB_TABLE_ROW;
@ -95,7 +96,7 @@ public:
void ReCreateMenuBar() override;
void ClickOnLibList( wxCommandEvent& event );
void ClickOnCmpList( wxCommandEvent& event );
void ClickOnSymbolList( wxCommandEvent& event );
void OnSelectSymbol( wxCommandEvent& aEvent );
void LoadSettings( APP_SETTINGS_BASE* aCfg ) override;
@ -154,10 +155,14 @@ private:
*/
void OnActivate( wxActivateEvent& event );
void DClickOnCmpList( wxCommandEvent& event );
void DClickOnSymbolList( wxCommandEvent& event );
void onUpdateUnitChoice( wxUpdateUIEvent& aEvent );
void OnLibFilter( wxCommandEvent& aEvent );
void OnSymFilter( wxCommandEvent& aEvent );
void OnCharHook( wxKeyEvent& aEvent ) override;
void onSelectNextSymbol( wxCommandEvent& aEvent );
void onSelectPreviousSymbol( wxCommandEvent& aEvent );
void onSelectSymbolUnit( wxCommandEvent& aEvent );
@ -167,10 +172,12 @@ private:
private:
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.
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.
// 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
{
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:
/**
* Destructor. Do NOT delete this class manually; it is reference-counted
@ -354,16 +364,6 @@ protected:
unsigned int aCol,
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:
/**
* 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 <kiway.h>
#include <widgets/msgpanel.h>
#include <widgets/wx_listbox.h>
#include <pcb_draw_panel_gal.h>
#include <pcb_painter.h>
#include <pcbnew_id.h>
#include <footprint_editor_settings.h>
#include <pgm_base.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <tool/action_toolbar.h>
#include <tool/common_control.h>
@ -56,7 +58,7 @@
#include <tools/pcb_selection_tool.h>
#include <tools/board_editor_control.h>
#include <wildcards_and_files_ext.h>
#include <wx/listbox.h>
#include <lib_tree_model_adapter.h>
#include <wx/srchctrl.h>
#include <wx/tokenzr.h>
#include <wx/choice.h>
@ -143,8 +145,8 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
m_libFilter->SetDescriptiveText( _( "Filter" ) );
libSizer->Add( m_libFilter, 0, wxEXPAND, 5 );
m_libList = new wxListBox( libPanel, ID_MODVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
m_libList = new WX_LISTBOX( libPanel, ID_MODVIEW_LIB_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
libSizer->Add( m_libList, 1, wxEXPAND, 5 );
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 ) );
#endif
m_fpList = new wxListBox( fpPanel, ID_MODVIEW_FOOTPRINT_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
m_fpList = new WX_LISTBOX( fpPanel, ID_MODVIEW_FOOTPRINT_LIST, wxDefaultPosition, wxDefaultSize,
0, nullptr, wxLB_HSCROLL | wxNO_BORDER );
m_fpList->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( FOOTPRINT_VIEWER_FRAME::DClickOnFootprintList ), nullptr, this );
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
m_auimgr.AddPane( libPanel, EDA_PANE().Palette().Name( "Libraries" ).Left().Layer(2)
.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 ) );
m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() );
@ -398,10 +400,26 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateLibraryList()
{
m_libList->Clear();
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
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() );
@ -413,17 +431,17 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateLibraryList()
for( const wxString& nickname : nicknames )
{
if( !matcher.Find( nickname.Lower(), matches, position ) )
excludes.insert( nickname );
if( matcher.Find( nickname.Lower(), matches, position ) )
process( nickname );
}
}
}
for( const wxString& nickname : nicknames )
{
if( !excludes.count( nickname ) )
m_libList->Append( nickname );
}
for( const wxString& nickname : pinnedMatches )
m_libList->Append( LIB_TREE_MODEL_ADAPTER::GetPinningSymbol() + nickname );
for( const wxString& nickname : otherMatches )
m_libList->Append( nickname );
// Search for a previous selection:
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;
@ -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;
@ -640,7 +658,7 @@ void FOOTPRINT_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& aEvent )
if( ii < 0 )
return;
wxString name = m_libList->GetString( ii );
wxString name = m_libList->GetBaseString( ii );
if( getCurNickname() == name )
return;
@ -662,7 +680,7 @@ void FOOTPRINT_VIEWER_FRAME::ClickOnFootprintList( wxCommandEvent& aEvent )
if( ii < 0 )
return;
wxString name = m_fpList->GetString( ii );
wxString name = m_fpList->GetBaseString( ii );
if( getCurFootprintName().CmpNoCase( name ) != 0 )
{
@ -888,7 +906,7 @@ void FOOTPRINT_VIEWER_FRAME::OnActivate( wxActivateEvent& event )
{
for( unsigned ii = 0; ii < libNicknames.size(); ii++ )
{
if( libNicknames[ii] != m_libList->GetString( ii ) )
if( libNicknames[ii] != m_libList->GetBaseString( ii ) )
{
stale = true;
break;
@ -1002,13 +1020,17 @@ void FOOTPRINT_VIEWER_FRAME::UpdateTitle()
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();
const LIB_TABLE_ROW* row = libtable->FindRow( getCurNickname() );
if( row )
title += wxT( " \u2014 " ) + row->GetFullURI( true );
title = getCurNickname() + wxT( " \u2014 " ) + row->GetFullURI( true );
}
catch( ... )
{
title = _( "[no library selected]" );
}
}
else
{
@ -1045,7 +1067,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectAndViewFootprint( int aMode )
m_fpList->SetSelection( selection );
m_fpList->EnsureVisible( selection );
setCurFootprintName( m_fpList->GetString((unsigned) selection ) );
setCurFootprintName( m_fpList->GetBaseString( selection ) );
// Delete the current footprint
GetBoard()->DeleteAllFootprints();

View File

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