7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 11:41:41 +00:00

Add footprint select dropdown to component chooser, serious refactoring

- DIALOG_CHOOSE_COMPONENT has footprint select widget
- FOOTPRINT_SELECT_WIDGET
- FOOTPRINT_CHOICE widget (customized wxComboCtrl)
- FOOTPRINT_FILTER class
- FOOTPRINT_INFO rework:
    - FOOTPRINT_ASYNC_LOADER to load without freezing UI
    - Rewrite loader threads as queue-driven thread pool
    - Make FOOTPRINT_INFO available via kiway
- FP_LIB_TABLE::PrefetchLib
- Access to global fp-lib-table via kiway
- SYNC_QUEUE threadsafe queue template
- Remove KICAD_FOOTPRINT_SELECTOR build option
This commit is contained in:
Chris Pavlina 2017-03-22 20:59:25 -04:00
parent cc7825d00b
commit 849b3c2a4b
46 changed files with 2635 additions and 668 deletions

View File

@ -101,8 +101,6 @@ option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." ON )
option( KICAD_SPICE "Build Kicad with internal Spice simulator." OFF )
option( KICAD_FOOTPRINT_SELECTOR "Build experimental eeschema footprint selector." OFF )
# Global setting: exports are explicit
set( CMAKE_CXX_VISIBILITY_PRESET "hidden" )
set( CMAKE_VISIBILITY_INLINES_HIDDEN ON )
@ -321,10 +319,6 @@ if( KICAD_SPICE )
add_definitions( -DKICAD_SPICE )
endif()
if( KICAD_FOOTPRINT_SELECTOR )
add_definitions( -DKICAD_FOOTPRINT_SELECTOR )
endif()
if( KICAD_USE_SCH_IO_MANAGER )
add_definitions( -DKICAD_USE_SCH_IO_MANAGER )
endif()

View File

@ -171,6 +171,8 @@ set( COMMON_WIDGET_SRCS
widgets/widget_hotkey_list.cpp
widgets/two_column_tree_list.cpp
widgets/footprint_preview_widget.cpp
widgets/footprint_select_widget.cpp
widgets/footprint_choice.cpp
widgets/indicator_icon.cpp
)
@ -243,6 +245,8 @@ set( COMMON_SRCS
exceptions.cpp
executable_names.cpp
filter_reader.cpp
footprint_info.cpp
footprint_filter.cpp
lib_id.cpp
lib_table_keywords.cpp
# findkicadhelppath.cpp.notused deprecated, use searchhelpfilefullpath.cpp
@ -351,7 +355,6 @@ set( PCB_COMMON_SRCS
eda_text.cpp
class_page_info.cpp
lset.cpp
footprint_info.cpp
../pcbnew/basepcbframe.cpp
../pcbnew/class_board.cpp
../pcbnew/class_board_connected_item.cpp

View File

@ -34,6 +34,12 @@ bool EDA_PATTERN_MATCH_SUBSTR::SetPattern( const wxString& aPattern )
}
wxString const& EDA_PATTERN_MATCH_SUBSTR::GetPattern() const
{
return m_pattern;
}
int EDA_PATTERN_MATCH_SUBSTR::Find( const wxString& aCandidate ) const
{
int loc = aCandidate.Find( m_pattern );
@ -75,6 +81,12 @@ bool EDA_PATTERN_MATCH_REGEX::SetPattern( const wxString& aPattern )
}
wxString const& EDA_PATTERN_MATCH_REGEX::GetPattern() const
{
return m_pattern;
}
int EDA_PATTERN_MATCH_REGEX::Find( const wxString& aCandidate ) const
{
if( m_regex.IsValid() )
@ -100,6 +112,8 @@ int EDA_PATTERN_MATCH_REGEX::Find( const wxString& aCandidate ) const
bool EDA_PATTERN_MATCH_WILDCARD::SetPattern( const wxString& aPattern )
{
m_wildcard_pattern = aPattern;
// Compile the wildcard string to a regular expression
wxString regex;
regex.Alloc( 2 * aPattern.Length() ); // no need to keep resizing, we know the size roughly
@ -132,6 +146,12 @@ bool EDA_PATTERN_MATCH_WILDCARD::SetPattern( const wxString& aPattern )
}
wxString const& EDA_PATTERN_MATCH_WILDCARD::GetPattern() const
{
return m_wildcard_pattern;
}
int EDA_PATTERN_MATCH_WILDCARD::Find( const wxString& aCandidate ) const
{
return EDA_PATTERN_MATCH_REGEX::Find( aCandidate );

230
common/footprint_filter.cpp Normal file
View File

@ -0,0 +1,230 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2017 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, see <http://www.gnu.org/licenses/>.
*/
#include <footprint_filter.h>
#include <make_unique.h>
#include <stdexcept>
using FOOTPRINT_FILTER_IT = FOOTPRINT_FILTER::ITERATOR;
FOOTPRINT_FILTER::ITERATOR::ITERATOR() : m_pos( 0 ), m_filter( nullptr )
{
}
FOOTPRINT_FILTER::ITERATOR::ITERATOR( FOOTPRINT_FILTER_IT const& aOther )
: m_pos( aOther.m_pos ), m_filter( aOther.m_filter )
{
}
FOOTPRINT_FILTER::ITERATOR::ITERATOR( FOOTPRINT_FILTER& aFilter )
: m_pos( (size_t) -1 ), m_filter( &aFilter )
{
increment();
}
void FOOTPRINT_FILTER_IT::increment()
{
bool found = false;
if( !m_filter || !m_filter->m_list || m_filter->m_list->GetCount() == 0 )
{
m_pos = 0;
return;
}
auto filter_type = m_filter->m_filter_type;
auto list = m_filter->m_list;
auto& lib_name = m_filter->m_lib_name;
auto& filter_pattern = m_filter->m_filter_pattern;
auto& filter = m_filter->m_filter;
for( ++m_pos; m_pos < list->GetCount() && !found; ++m_pos )
{
found = true;
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_LIBRARY ) && !lib_name.IsEmpty()
&& !list->GetItem( m_pos ).InLibrary( lib_name ) )
found = false;
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_COMPONENT_KEYWORD )
&& !FootprintFilterMatch( list->GetItem( m_pos ) ) )
found = false;
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_PIN_COUNT )
&& !PinCountMatch( list->GetItem( m_pos ) ) )
found = false;
if( ( filter_type & FOOTPRINT_FILTER::FILTERING_BY_NAME ) && !filter_pattern.IsEmpty() )
{
wxString currname;
// If the search string contains a ':' character,
// include the library name in the search string
// e.g. LibName:FootprintName
if( filter_pattern.Contains( ":" ) )
currname = list->GetItem( m_pos ).GetNickname().Lower() + ":";
currname += list->GetItem( m_pos ).GetFootprintName().Lower();
if( filter.Find( currname ) == EDA_PATTERN_NOT_FOUND )
found = false;
}
if( filter_type == FOOTPRINT_FILTER::UNFILTERED_FP_LIST )
{
// override
found = true;
}
}
// for loop will stop one past the correct item
if( found )
--m_pos;
}
bool FOOTPRINT_FILTER_IT::equal( FOOTPRINT_FILTER_IT const& aOther ) const
{
// Invalid iterators are always equal
return ( m_pos == aOther.m_pos ) && ( m_filter == aOther.m_filter || m_pos == (size_t) -1 );
}
FOOTPRINT_INFO& FOOTPRINT_FILTER_IT::dereference() const
{
if( m_filter && m_filter->m_list && m_pos < m_filter->m_list->GetCount() )
return m_filter->m_list->GetItem( m_pos );
else
throw std::out_of_range( "Attempt to dereference past FOOTPRINT_FILTER::end()" );
}
bool FOOTPRINT_FILTER_IT::FootprintFilterMatch( FOOTPRINT_INFO& aItem )
{
if( m_filter->m_footprint_filters.empty() )
return true;
// The matching is case insensitive
wxString name = "";
EDA_PATTERN_MATCH_WILDCARD patternFilter;
for( auto const& each_filter : m_filter->m_footprint_filters )
{
// If the filter contains a ':' character, include the library name in the pattern
if( each_filter->GetPattern().Contains( ":" ) )
{
name = aItem.GetNickname().Lower() + ":";
}
name += aItem.GetFootprintName().Lower();
if( each_filter->Find( name ) != EDA_PATTERN_NOT_FOUND )
{
return true;
}
}
return false;
}
bool FOOTPRINT_FILTER_IT::PinCountMatch( FOOTPRINT_INFO& aItem )
{
return (unsigned) m_filter->m_pin_count == aItem.GetUniquePadCount();
}
FOOTPRINT_FILTER::FOOTPRINT_FILTER( FOOTPRINT_LIST& aList ) : FOOTPRINT_FILTER()
{
SetList( aList );
}
FOOTPRINT_FILTER::FOOTPRINT_FILTER()
: m_list( nullptr ), m_pin_count( -1 ), m_filter_type( UNFILTERED_FP_LIST )
{
}
void FOOTPRINT_FILTER::SetList( FOOTPRINT_LIST& aList )
{
m_list = &aList;
}
void FOOTPRINT_FILTER::ClearFilters()
{
m_filter_type = UNFILTERED_FP_LIST;
}
void FOOTPRINT_FILTER::FilterByLibrary( wxString const& aLibName )
{
m_lib_name = aLibName;
m_filter_type |= FILTERING_BY_LIBRARY;
}
void FOOTPRINT_FILTER::FilterByPinCount( int aPinCount )
{
m_pin_count = aPinCount;
m_filter_type |= FILTERING_BY_PIN_COUNT;
}
void FOOTPRINT_FILTER::FilterByFootprintFilters( wxArrayString const& aFilters )
{
m_footprint_filters.clear();
for( auto const& each_pattern : aFilters )
{
m_footprint_filters.push_back( std::make_unique<EDA_PATTERN_MATCH_WILDCARD>() );
wxASSERT( m_footprint_filters.back()->SetPattern( each_pattern.Lower() ) );
}
m_filter_type |= FILTERING_BY_COMPONENT_KEYWORD;
}
void FOOTPRINT_FILTER::FilterByPattern( wxString const& aPattern )
{
m_filter_pattern = aPattern;
m_filter.SetPattern( aPattern.Lower() );
m_filter_type |= FILTERING_BY_NAME;
}
FOOTPRINT_FILTER_IT FOOTPRINT_FILTER::begin()
{
return FOOTPRINT_FILTER_IT( *this );
}
FOOTPRINT_FILTER_IT FOOTPRINT_FILTER::end()
{
FOOTPRINT_FILTER_IT end_it( *this );
end_it.m_pos = m_list->GetCount();
return end_it;
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2011 Jean-Pierre Charras, <jp.charras@wanadoo.fr>
* Copyright (C) 2013-2016 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -23,242 +23,31 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file footprint_info.cpp
*/
/**
No. concurrent threads doing "http(s) GET". More than 6 is not significantly
faster, less than 6 is likely slower. Main thread is in this count, so if
set to 1 then no temp threads are created.
*/
#define READER_THREADS 6
/*
* Functions to read footprint libraries and fill m_footprints by available footprints names
* and their documentation (comments and keywords)
*/
#include <fctsys.h>
#include <class_module.h>
#include <common.h>
#include <fctsys.h>
#include <footprint_info.h>
#include <fp_lib_table.h>
#include <html_messagebox.h>
#include <io_mgr.h>
#include <kiface_ids.h>
#include <kiway.h>
#include <lib_id.h>
#include <macros.h>
#include <pgm_base.h>
#include <wildcards_and_files_ext.h>
#include <footprint_info.h>
#include <io_mgr.h>
#include <fp_lib_table.h>
#include <lib_id.h>
#include <class_module.h>
#include <thread>
#include <html_messagebox.h>
/*
static wxString ToHTMLFragment( const IO_ERROR* aDerivative )
{
@todo
1) change up IO_ERROR so it keeps linenumbers, source file name and
error message in separate strings.
2) Add a summarizing virtual member like
virtual wxString What()
to combine all portions of an IO_ERROR's text into a single wxString.
3) Do same for PARSE_ERROR.
4) Add a "reason or error category" to IO_ERROR and thereby also PARSE_ERROR?
msg += "
for( int i=0; i<aCount; ++i )
{
wxArrayString* sl = wxStringSplit( aList, wxChar( '\n' ) );
delete sl;
}
wxString msg = wxT( "<ul>" );
for ( unsigned ii = 0; ii < strings_list->GetCount(); ii++ )
{
msg += wxT( "<li>" );
msg += strings_list->Item( ii ) + wxT( "</li>" );
}
msg += wxT( "</ul>" );
m_htmlWindow->AppendToPage( msg );
delete strings_list;
}
*/
void FOOTPRINT_INFO::load()
{
FP_LIB_TABLE* fptable = m_owner->GetTable();
wxASSERT( fptable );
std::unique_ptr<MODULE> footprint( fptable->FootprintLoad( m_nickname, m_fpname ) );
if( footprint.get() == NULL ) // Should happen only with malformed/broken libraries
{
m_pad_count = 0;
m_unique_pad_count = 0;
}
else
{
m_pad_count = footprint->GetPadCount( DO_NOT_INCLUDE_NPTH );
m_unique_pad_count = footprint->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
m_keywords = footprint->GetKeywords();
m_doc = footprint->GetDescription();
// tell ensure_loaded() I'm loaded.
m_loaded = true;
}
}
void FOOTPRINT_LIST::loader_job( const wxString* aNicknameList, int aJobZ )
{
for( int i=0; i<aJobZ; ++i )
{
const wxString& nickname = aNicknameList[i];
try
{
wxArrayString fpnames = m_lib_table->FootprintEnumerate( nickname );
for( unsigned ni=0; ni<fpnames.GetCount(); ++ni )
{
FOOTPRINT_INFO* fpinfo = new FOOTPRINT_INFO( this, nickname, fpnames[ni] );
addItem( fpinfo );
}
}
catch( const PARSE_ERROR& pe )
{
// m_errors.push_back is not thread safe, lock its MUTEX.
MUTLOCK lock( m_errors_lock );
++m_error_count; // modify only under lock
m_errors.push_back( new IO_ERROR( pe ) );
}
catch( const IO_ERROR& ioe )
{
MUTLOCK lock( m_errors_lock );
++m_error_count;
m_errors.push_back( new IO_ERROR( ioe ) );
}
// Catch anything unexpected and map it into the expected.
// Likely even more important since this function runs on GUI-less
// worker threads.
catch( const std::exception& se )
{
// This is a round about way to do this, but who knows what THROW_IO_ERROR()
// may be tricked out to do someday, keep it in the game.
try
{
THROW_IO_ERROR( se.what() );
}
catch( const IO_ERROR& ioe )
{
MUTLOCK lock( m_errors_lock );
++m_error_count;
m_errors.push_back( new IO_ERROR( ioe ) );
}
}
}
}
bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname )
{
bool retv = true;
m_lib_table = aTable;
// Clear data before reading files
m_error_count = 0;
m_errors.clear();
m_list.clear();
if( aNickname )
// single footprint
loader_job( aNickname, 1 );
else
{
std::vector< wxString > nicknames;
// do all of them
nicknames = aTable->GetLogicalLibs();
// Even though the PLUGIN API implementation is the place for the
// locale toggling, in order to keep LOCAL_IO::C_count at 1 or greater
// for the duration of all helper threads, we increment by one here via instantiation.
// Only done here because of the multi-threaded nature of this code.
// Without this C_count skips in and out of "equal to zero" and causes
// needless locale toggling among the threads, based on which of them
// are in a PLUGIN::FootprintLoad() function. And that is occasionally
// none of them.
LOCALE_IO top_most_nesting;
// Something which will not invoke a thread copy constructor, one of many ways obviously:
typedef std::vector< std::thread > MYTHREADS;
MYTHREADS threads;
unsigned jobz = (nicknames.size() + READER_THREADS - 1) / READER_THREADS;
// Give each thread JOBZ nicknames to process. The last portion of, or if the entire
// size() is small, I'll do myself.
for( unsigned i=0; i<nicknames.size(); )
{
if( i + jobz >= nicknames.size() ) // on the last iteration of this for(;;)
{
jobz = nicknames.size() - i;
// Only a little bit to do, I'll do it myself on current thread.
// I am part of the READER_THREADS count.
loader_job( &nicknames[i], jobz );
}
else
{
// Delegate the job to a temporary thread created here.
threads.push_back( std::thread( &FOOTPRINT_LIST::loader_job,
this, &nicknames[i], jobz ) );
}
i += jobz;
}
// Wait for all the worker threads to complete, it does not matter in what order
// we wait for them as long as a full sweep is made. Think of the great race,
// everyone must finish.
for( unsigned i=0; i<threads.size(); ++i )
{
threads[i].join();
}
m_list.sort();
}
// The result of this function can be a blend of successes and failures, whose
// mix is given by the Count()s of the two lists. The return value indicates whether
// an abort occurred, even true does not necessarily mean full success, although
// false definitely means failure.
return retv;
}
#include <wildcards_and_files_ext.h>
FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString& aFootprintName )
@ -266,19 +55,19 @@ FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString& aFootprintName )
if( aFootprintName.IsEmpty() )
return NULL;
for( FOOTPRINT_INFO& fp : m_list )
for( auto& fp : m_list )
{
LIB_ID fpid;
wxCHECK_MSG( fpid.Parse( aFootprintName ) < 0, NULL,
wxString::Format( wxT( "'%s' is not a valid LIB_ID." ),
GetChars( aFootprintName ) ) );
wxString::Format(
wxT( "'%s' is not a valid LIB_ID." ), GetChars( aFootprintName ) ) );
wxString libNickname = fpid.GetLibNickname();
wxString libNickname = fpid.GetLibNickname();
wxString footprintName = fpid.GetLibItemName();
if( libNickname == fp.GetNickname() && footprintName == fp.GetFootprintName() )
return &fp;
if( libNickname == fp->GetNickname() && footprintName == fp->GetFootprintName() )
return &*fp;
}
return NULL;
@ -304,12 +93,119 @@ void FOOTPRINT_LIST::DisplayErrors( wxTopLevelWindow* aWindow )
wxString msg;
for( unsigned i = 0; i<m_errors.size(); ++i )
while( auto error = PopError() )
{
msg += wxT( "<p>" ) + m_errors[i].Problem() + wxT( "</p>" );
msg += wxT( "<p>" ) + error->Problem() + wxT( "</p>" );
}
dlg.AddHTML_Text( msg );
dlg.ShowModal();
}
static std::unique_ptr<FOOTPRINT_LIST> get_instance_from_id( KIWAY& aKiway, int aId )
{
void* ptr = nullptr;
try
{
KIFACE* kiface = aKiway.KiFACE( KIWAY::FACE_PCB );
if( !kiface )
return nullptr;
ptr = kiface->IfaceOrAddress( aId );
if( !ptr )
return nullptr;
}
catch( ... )
{
return nullptr;
}
return std::unique_ptr<FOOTPRINT_LIST>( (FOOTPRINT_LIST*) ( ptr ) );
}
std::unique_ptr<FOOTPRINT_LIST> FOOTPRINT_LIST::GetInstance( KIWAY& aKiway )
{
return get_instance_from_id( aKiway, KIFACE_NEW_FOOTPRINT_LIST );
}
FOOTPRINT_ASYNC_LOADER::FOOTPRINT_ASYNC_LOADER() : m_list( nullptr )
{
}
void FOOTPRINT_ASYNC_LOADER::SetList( FOOTPRINT_LIST* aList )
{
m_list = aList;
}
void FOOTPRINT_ASYNC_LOADER::Start(
FP_LIB_TABLE* aTable, wxString const* aNickname, unsigned aNThreads )
{
m_started = true;
// Capture the FP_LIB_TABLE into m_last_table. Formatting it as a string instead of storing the
// raw data avoids having to pull in the FP-specific parts.
STRING_FORMATTER sof;
aTable->Format( &sof, 0 );
m_last_table = sof.GetString();
m_list->StartWorkers( aTable, aNickname, this, aNThreads );
}
bool FOOTPRINT_ASYNC_LOADER::Join()
{
if( m_list )
{
bool rv = m_list->JoinWorkers();
m_list = nullptr;
return rv;
}
else
return true;
}
int FOOTPRINT_ASYNC_LOADER::GetProgress() const
{
if( !m_started )
return 0;
else if( m_total_libs == 0 || !m_list )
return 100;
else
{
int loaded = m_list->CountFinished();
int prog = ( 100 * loaded ) / m_total_libs;
if( loaded == m_total_libs )
return 100;
else if( loaded < m_total_libs && prog >= 100 )
return 99;
else if( prog <= 0 )
return 1;
else
return prog;
}
}
void FOOTPRINT_ASYNC_LOADER::SetCompletionCallback( std::function<void()> aCallback )
{
m_completion_cb = aCallback;
}
bool FOOTPRINT_ASYNC_LOADER::IsSameTable( FP_LIB_TABLE* aOther )
{
STRING_FORMATTER sof;
aOther->Format( &sof, 0 );
return m_last_table == sof.GetString();
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2016 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2012-2017 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
@ -204,6 +204,14 @@ wxArrayString FP_LIB_TABLE::FootprintEnumerate( const wxString& aNickname )
}
void FP_LIB_TABLE::PrefetchLib( const wxString& aNickname )
{
const FP_LIB_TABLE_ROW* row = FindRow( aNickname );
wxASSERT( (PLUGIN*) row->plugin );
row->plugin->PrefetchLib( row->GetFullURI( true ), row->GetProperties() );
}
const FP_LIB_TABLE_ROW* FP_LIB_TABLE::FindRow( const wxString& aNickname )
throw( IO_ERROR )
{

View File

@ -1,8 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
* Copyright (C) 2014-2017 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
@ -22,7 +21,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wx/stdpaths.h>
#include <fctsys.h>
@ -34,6 +32,9 @@
#include <kicad_string.h>
#include <config_params.h>
#include <wildcards_and_files_ext.h>
#include <fp_lib_table.h>
#include <kiway.h>
#include <kiface_ids.h>
PROJECT::PROJECT()
@ -379,3 +380,41 @@ const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
return fn.GetFullPath();
}
FP_LIB_TABLE* PROJECT::PcbFootprintLibs( KIWAY& aKiway )
{
// This is a lazy loading function, it loads the project specific table when
// that table is asked for, not before.
FP_LIB_TABLE* tbl = (FP_LIB_TABLE*) GetElem( ELEM_FPTBL );
// its gotta be NULL or a FP_LIB_TABLE, or a bug.
wxASSERT( !tbl || dynamic_cast<FP_LIB_TABLE*>( tbl ) );
if( !tbl )
{
// Stack the project specific FP_LIB_TABLE overlay on top of the global table.
// ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may
// stack this way, all using the same global fallback table.
KIFACE* kiface = aKiway.KiFACE( KIWAY::FACE_PCB );
if( kiface )
tbl = (FP_LIB_TABLE*) kiface->IfaceOrAddress( KIFACE_G_FOOTPRINT_TABLE );
wxASSERT( tbl );
SetElem( ELEM_FPTBL, tbl );
wxString projectFpLibTableFileName = FootprintLibTblName();
try
{
tbl->Load( projectFpLibTableFileName );
}
catch( const IO_ERROR& ioe )
{
DisplayError( NULL, ioe.What() );
}
}
return tbl;
}

View File

@ -0,0 +1,262 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 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, see <http://www.gnu.org/licenses/>.
*/
#include <functional>
#include <widgets/footprint_choice.h>
#include <wx/dc.h>
#include <wx/pen.h>
wxDEFINE_EVENT( EVT_INTERACTIVE_CHOICE, wxCommandEvent );
wxColour FOOTPRINT_CHOICE::m_grey( 0x808080 );
FOOTPRINT_CHOICE::FOOTPRINT_CHOICE( wxWindow* aParent, int aId )
: wxOwnerDrawnComboBox( aParent, aId, wxEmptyString, wxDefaultPosition, wxDefaultSize,
/* n */ 0, /* choices */ nullptr, wxCB_READONLY ),
m_last_selection( 0 )
{
}
FOOTPRINT_CHOICE::~FOOTPRINT_CHOICE()
{
}
void FOOTPRINT_CHOICE::DoSetPopupControl( wxComboPopup* aPopup )
{
using namespace std::placeholders;
wxOwnerDrawnComboBox::DoSetPopupControl( aPopup );
// Bind events to intercept selections, so the separator can be made nonselectable.
GetVListBoxComboPopup()->Bind( wxEVT_MOTION, &FOOTPRINT_CHOICE::TryVetoMouse, this );
GetVListBoxComboPopup()->Bind( wxEVT_LEFT_DOWN, &FOOTPRINT_CHOICE::TryVetoMouse, this );
GetVListBoxComboPopup()->Bind( wxEVT_LEFT_UP, &FOOTPRINT_CHOICE::TryVetoMouse, this );
GetVListBoxComboPopup()->Bind( wxEVT_LEFT_UP, &FOOTPRINT_CHOICE::OnMouseUp, this );
GetVListBoxComboPopup()->Bind( wxEVT_LEFT_DCLICK, &FOOTPRINT_CHOICE::TryVetoMouse, this );
GetVListBoxComboPopup()->Bind(
wxEVT_LISTBOX, std::bind( &FOOTPRINT_CHOICE::TryVetoSelect, this, _1, true ) );
Bind( wxEVT_COMBOBOX, std::bind( &FOOTPRINT_CHOICE::TryVetoSelect, this, _1, false ) );
GetVListBoxComboPopup()->Bind(
wxEVT_CHAR_HOOK, std::bind( &FOOTPRINT_CHOICE::TrySkipSeparator, this, _1, true ) );
GetVListBoxComboPopup()->Bind( wxEVT_CHAR_HOOK, &FOOTPRINT_CHOICE::OnKeyUp, this );
Bind( wxEVT_KEY_DOWN, std::bind( &FOOTPRINT_CHOICE::TrySkipSeparator, this, _1, false ) );
}
void FOOTPRINT_CHOICE::OnDrawItem( wxDC& aDC, wxRect const& aRect, int aItem, int aFlags ) const
{
wxString text = SafeGetString( aItem );
if( text == wxEmptyString )
{
wxPen pen( m_grey, 1, wxPENSTYLE_SOLID );
aDC.SetPen( pen );
aDC.DrawLine( aRect.x, aRect.y + aRect.height / 2, aRect.x + aRect.width,
aRect.y + aRect.height / 2 );
}
else
{
wxCoord x, y;
if( aFlags & wxODCB_PAINTING_CONTROL )
{
x = aRect.x + GetMargins().x;
y = ( aRect.height - aDC.GetCharHeight() ) / 2 + aRect.y;
}
else
{
x = aRect.x + 2;
y = aRect.y;
}
// If this item has a footprint and that footprint has a ":" delimiter, find the
// library component, then find that in the display string and grey it out.
size_t start_grey = 0;
size_t end_grey = 0;
wxString lib = static_cast<wxStringClientData*>( GetClientObject( aItem ) )->GetData();
size_t colon_index = lib.rfind( ':' );
if( colon_index != wxString::npos )
{
wxString library_part = lib.SubString( 0, colon_index );
size_t library_index = text.rfind( library_part );
if( library_index != wxString::npos )
{
start_grey = library_index;
end_grey = start_grey + library_part.Length();
}
}
if( start_grey != end_grey && !( aFlags & wxODCB_PAINTING_SELECTED ) )
{
x = DrawTextFragment( aDC, x, y, text.SubString( 0, start_grey - 1 ) );
wxColour standard_color = aDC.GetTextForeground();
aDC.SetTextForeground( m_grey );
x = DrawTextFragment( aDC, x, y, text.SubString( start_grey, end_grey - 1 ) );
aDC.SetTextForeground( standard_color );
x = DrawTextFragment( aDC, x, y, text.SubString( end_grey, text.Length() - 1 ) );
}
else
{
aDC.DrawText( text, x, y );
}
}
}
wxCoord FOOTPRINT_CHOICE::OnMeasureItem( size_t aItem ) const
{
if( SafeGetString( aItem ) == "" )
return 11;
else
return wxOwnerDrawnComboBox::OnMeasureItem( aItem );
}
wxCoord FOOTPRINT_CHOICE::OnMeasureItemWidth( size_t aItem ) const
{
if( SafeGetString( aItem ) == "" )
return GetTextRect().GetWidth() - 2;
else
return wxOwnerDrawnComboBox::OnMeasureItemWidth( aItem );
}
wxCoord FOOTPRINT_CHOICE::DrawTextFragment( wxDC& aDC, wxCoord x, wxCoord y, wxString const& aText )
{
aDC.DrawText( aText, x, y );
return x + aDC.GetTextExtent( aText ).GetWidth();
}
void FOOTPRINT_CHOICE::TryVetoMouse( wxMouseEvent& aEvent )
{
int item = GetVListBoxComboPopup()->VirtualHitTest( aEvent.GetPosition().y );
if( SafeGetString( item ) != "" )
aEvent.Skip();
}
void FOOTPRINT_CHOICE::OnMouseUp( wxMouseEvent& aEvent )
{
int item = GetVListBoxComboPopup()->VirtualHitTest( aEvent.GetPosition().y );
wxCommandEvent evt( EVT_INTERACTIVE_CHOICE );
evt.SetInt( item );
wxPostEvent( this, evt );
aEvent.Skip();
}
void FOOTPRINT_CHOICE::OnKeyUp( wxKeyEvent& aEvent )
{
int item = GetSelectionEither( true );
if( aEvent.GetKeyCode() == WXK_RETURN )
{
wxCommandEvent evt( EVT_INTERACTIVE_CHOICE );
evt.SetInt( item );
wxPostEvent( this, evt );
}
aEvent.Skip();
}
void FOOTPRINT_CHOICE::TryVetoSelect( wxCommandEvent& aEvent, bool aInner )
{
int sel = GetSelectionEither( aInner );
if( sel >= 0 && sel < (int) GetCount() )
{
wxString text = SafeGetString( sel );
if( text == "" )
SetSelectionEither( aInner, m_last_selection );
else
{
m_last_selection = sel;
aEvent.Skip();
}
}
}
void FOOTPRINT_CHOICE::TrySkipSeparator( wxKeyEvent& aEvent, bool aInner )
{
int key = aEvent.GetKeyCode();
int sel = GetSelectionEither( aInner );
int new_sel = sel;
if( key == WXK_UP && SafeGetString( sel - 1 ) == wxEmptyString )
{
new_sel = sel - 2;
}
else if( key == WXK_DOWN && SafeGetString( sel + 1 ) == wxEmptyString )
{
new_sel = sel + 2;
}
if( new_sel != sel )
SetSelectionEither( aInner, new_sel );
else
aEvent.Skip();
}
wxString FOOTPRINT_CHOICE::SafeGetString( int aItem ) const
{
if( aItem >= 0 && aItem < (int) GetCount() )
return GetVListBoxComboPopup()->GetString( aItem );
else
return wxEmptyString;
}
int FOOTPRINT_CHOICE::GetSelectionEither( bool aInner ) const
{
if( aInner )
return GetVListBoxComboPopup()->wxVListBox::GetSelection();
else
return GetSelection();
}
void FOOTPRINT_CHOICE::SetSelectionEither( bool aInner, int aSel )
{
if( aSel >= 0 && aSel < (int) GetCount() )
{
if( aInner )
return GetVListBoxComboPopup()->wxVListBox::SetSelection( aSel );
else
return SetSelection( aSel );
}
}

View File

@ -0,0 +1,304 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 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, see <http://www.gnu.org/licenses/>.
*/
#include <dialog_shim.h>
#include <kiway.h>
#include <kiway_player.h>
#include <make_unique.h>
#include <project.h>
#include <widgets/footprint_choice.h>
#include <widgets/footprint_select_widget.h>
#include <functional>
#include <wx/combo.h>
#include <wx/gauge.h>
#include <wx/odcombo.h>
#include <wx/simplebook.h>
#include <wx/sizer.h>
#include <wx/timer.h>
#include <wx/utils.h>
#include <wx/wupdlock.h>
/**
* Fixed positions for standard items in the list
*/
enum
{
POS_DEFAULT,
POS_OTHER,
POS_SEPARATOR
};
/**
* Page numbers in the wxSimplebook
*/
enum
{
PAGE_PROGRESS,
PAGE_SELECT
};
wxDEFINE_EVENT( EVT_FOOTPRINT_SELECTED, wxCommandEvent );
FOOTPRINT_SELECT_WIDGET::FOOTPRINT_SELECT_WIDGET( wxWindow* aParent,
FOOTPRINT_ASYNC_LOADER& aLoader, std::unique_ptr<FOOTPRINT_LIST>& aFpList, bool aUpdate,
int aMaxItems )
: wxPanel( aParent ),
m_kiway( nullptr ),
m_update( aUpdate ),
m_finished_loading( false ),
m_max_items( aMaxItems ),
m_last_item( 0 ),
m_fp_loader( aLoader ),
m_fp_list( aFpList )
{
m_sizer = new wxBoxSizer( wxVERTICAL );
m_progress_timer = std::make_unique<wxTimer>( this );
m_book = new wxSimplebook( this, wxID_ANY );
m_progress_ctrl = new wxGauge( m_book, wxID_ANY, 100 );
m_fp_sel_ctrl = new FOOTPRINT_CHOICE( m_book, wxID_ANY );
m_book->SetEffect( wxSHOW_EFFECT_BLEND );
m_book->AddPage( m_progress_ctrl, "", true );
m_book->AddPage( m_fp_sel_ctrl, "", false );
m_sizer->Add( m_book, 1, wxEXPAND | wxALL, 5 );
SetSizer( m_sizer );
Layout();
m_sizer->Fit( this );
Bind( wxEVT_TIMER, &FOOTPRINT_SELECT_WIDGET::OnProgressTimer, this, m_progress_timer->GetId() );
m_fp_sel_ctrl->Bind( wxEVT_COMBOBOX, &FOOTPRINT_SELECT_WIDGET::OnComboBox, this );
m_fp_sel_ctrl->Bind(
EVT_INTERACTIVE_CHOICE, &FOOTPRINT_SELECT_WIDGET::OnComboInteractive, this );
}
void FOOTPRINT_SELECT_WIDGET::Load( KIWAY& aKiway, PROJECT& aProject )
{
m_kiway = &aKiway;
auto fp_lib_table = aProject.PcbFootprintLibs( aKiway );
if( m_fp_loader.GetProgress() == 0 || !m_fp_loader.IsSameTable( fp_lib_table ) )
{
m_fp_list = FOOTPRINT_LIST::GetInstance( aKiway );
m_fp_loader.SetList( &*m_fp_list );
m_fp_loader.Start( fp_lib_table );
}
m_progress_timer->Start( 200 );
}
void FOOTPRINT_SELECT_WIDGET::OnProgressTimer( wxTimerEvent& aEvent )
{
int prog = m_fp_loader.GetProgress();
m_progress_ctrl->SetValue( prog );
if( prog == 100 )
{
wxBusyCursor busy;
m_fp_loader.Join();
m_fp_filter.SetList( *m_fp_list );
m_progress_timer->Stop();
m_book->SetSelection( PAGE_SELECT );
m_finished_loading = true;
if( m_update )
UpdateList();
}
}
void FOOTPRINT_SELECT_WIDGET::OnComboBox( wxCommandEvent& aEvent )
{
wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
int sel = m_fp_sel_ctrl->GetSelection();
switch( sel )
{
case wxNOT_FOUND: return;
case POS_SEPARATOR:
// User somehow managed to select the separator. This should not be
// possible, but just in case... deselect it
m_fp_sel_ctrl->SetSelection( m_last_item );
break;
case POS_OTHER:
// When POS_OTHER is selected, a dialog should be shown. However, we don't want to
// do this ALL the time, as some times (e.g. when moving around with the arrow keys)
// it could be very annoying. Therefore showing the picker is done from the custom
// "interactive select" event on FOOTPRINT_CHOICE, which only fires for more direct
// choice actions.
break;
default:
{
wxStringClientData* clientdata =
static_cast<wxStringClientData*>( m_fp_sel_ctrl->GetClientObject( sel ) );
wxASSERT( clientdata );
evt.SetString( clientdata->GetData() );
wxPostEvent( this, evt );
}
}
}
void FOOTPRINT_SELECT_WIDGET::OnComboInteractive( wxCommandEvent& aEvent )
{
if( aEvent.GetInt() == POS_OTHER && !m_fp_sel_ctrl->IsPopupShown() )
{
DoOther();
}
}
void FOOTPRINT_SELECT_WIDGET::DoOther()
{
wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
wxString fpname = ShowPicker();
m_other_footprint = fpname;
UpdateList();
m_fp_sel_ctrl->SetSelection( POS_OTHER );
m_last_item = POS_OTHER;
evt.SetString( m_other_footprint );
wxPostEvent( this, evt );
}
wxString FOOTPRINT_SELECT_WIDGET::ShowPicker()
{
wxString fpname;
wxWindow* parent = ::wxGetTopLevelParent( this );
DIALOG_SHIM* dsparent = dynamic_cast<DIALOG_SHIM*>( parent );
// Only quasimodal dialogs can launch modal kiface dialogs. Otherwise the
// event loop goes all silly.
wxASSERT( !dsparent || dsparent->IsQuasiModal() );
auto frame = m_kiway->Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );
if( !frame->ShowModal( &fpname, parent ) )
{
fpname = wxEmptyString;
}
frame->Destroy();
return fpname;
}
void FOOTPRINT_SELECT_WIDGET::ClearFilters()
{
m_fp_filter.ClearFilters();
m_default_footprint.Clear();
m_other_footprint.Clear();
m_zero_filter = false;
}
void FOOTPRINT_SELECT_WIDGET::FilterByPinCount( int aPinCount )
{
m_fp_filter.FilterByPinCount( aPinCount );
}
void FOOTPRINT_SELECT_WIDGET::FilterByFootprintFilters(
wxArrayString const& aFilters, bool aZeroFilters )
{
if( aZeroFilters && aFilters.size() == 0 )
m_zero_filter = true;
else
m_zero_filter = false;
m_fp_filter.FilterByFootprintFilters( aFilters );
}
void FOOTPRINT_SELECT_WIDGET::SetDefaultFootprint( wxString const& aFp )
{
m_default_footprint = aFp;
}
bool FOOTPRINT_SELECT_WIDGET::UpdateList()
{
int n_items = 0;
if( !m_fp_list || !m_finished_loading )
return false;
wxWindowUpdateLocker lock( m_fp_sel_ctrl );
m_fp_sel_ctrl->Clear();
// Be careful adding items! "Default" must occupy POS_DEFAULT,
// "Other" must occupy POS_OTHER, and the separator must occupy POS_SEPARATOR.
m_fp_sel_ctrl->Append( m_default_footprint.IsEmpty() ?
_( "No default footprint" ) :
"[" + _( "Default" ) + "] " + m_default_footprint,
new wxStringClientData( m_default_footprint ) );
m_fp_sel_ctrl->Append( m_other_footprint.IsEmpty() ?
_( "Other..." ) :
"[" + _( "Other..." ) + "] " + m_other_footprint,
new wxStringClientData( m_other_footprint ) );
m_fp_sel_ctrl->Append( "", new wxStringClientData( "" ) );
if( !m_zero_filter )
{
for( auto& fpinfo : m_fp_filter )
{
wxString display_name( fpinfo.GetNickname() + ":" + fpinfo.GetFootprintName() );
m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) );
++n_items;
if( n_items >= m_max_items )
break;
}
}
SelectDefault();
return true;
}
void FOOTPRINT_SELECT_WIDGET::SelectDefault()
{
m_fp_sel_ctrl->SetSelection( POS_DEFAULT );
}
bool FOOTPRINT_SELECT_WIDGET::Enable( bool aEnable )
{
return m_fp_sel_ctrl->Enable( aEnable );
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -215,7 +215,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching( wxCommandEvent& event )
if( equivItem.m_ComponentValue.CmpNoCase( component->GetValue() ) != 0 )
continue;
const FOOTPRINT_INFO *module = m_FootprintsList.GetModuleInfo( equivItem.m_FootprintFPID );
const FOOTPRINT_INFO *module = m_FootprintsList->GetModuleInfo( equivItem.m_FootprintFPID );
bool equ_is_unique = true;
unsigned next = idx+1;
@ -277,7 +277,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching( wxCommandEvent& event )
{
// we do not need to analyze wildcards: single footprint do not
// contain them and if there are wildcards it just will not match any
const FOOTPRINT_INFO* module = m_FootprintsList.GetModuleInfo( component->GetFootprintFilters()[0] );
const FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( component->GetFootprintFilters()[0] );
if( module )
SetNewPkg( component->GetFootprintFilters()[0] );

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015-2016 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2007-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2007-2017 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
@ -459,7 +459,7 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
wxLogDebug( wxT( "Load footprint <%s> from library <%s>." ),
fpname.c_str(), nickname.c_str() );
footprint = Prj().PcbFootprintLibs()->FootprintLoad(
footprint = Prj().PcbFootprintLibs( Kiway() )->FootprintLoad(
FROM_UTF8( nickname.c_str() ), FROM_UTF8( fpname.c_str() ) );
}
catch( const IO_ERROR& ioe )
@ -495,7 +495,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay()
SetTitle( msg );
const FOOTPRINT_INFO* module_info =
parentframe->m_FootprintsList.GetModuleInfo( footprintName );
parentframe->m_FootprintsList->GetModuleInfo( footprintName );
const wxChar* libname;

View File

@ -29,12 +29,14 @@
#include <fctsys.h>
#include <wxstruct.h>
#include <wx/wupdlock.h>
#include <cvpcb.h>
#include <cvpcb_mainframe.h>
#include <listview_classes.h>
#include <cvpcb_id.h>
#include <eda_pattern_match.h>
#include <footprint_filter.h>
FOOTPRINTS_LISTBOX::FOOTPRINTS_LISTBOX( CVPCB_MAINFRAME* parent,
@ -133,62 +135,28 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
wxString msg;
wxString oldSelection;
EDA_PATTERN_MATCH_WILDCARD patternFilter;
patternFilter.SetPattern( aFootPrintFilterPattern.Lower() ); // Use case insensitive search
FOOTPRINT_FILTER filter( aList );
if( aFilterType & FILTERING_BY_COMPONENT_KEYWORD )
filter.FilterByFootprintFilters( aComponent->GetFootprintFilters() );
if( aFilterType & FILTERING_BY_PIN_COUNT )
filter.FilterByPinCount( aComponent->GetNetCount() );
if( aFilterType & FILTERING_BY_LIBRARY )
filter.FilterByLibrary( aLibName );
if( aFilterType & FILTERING_BY_NAME )
filter.FilterByPattern( aFootPrintFilterPattern );
if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() )
oldSelection = m_footprintList[ GetSelection() ];
for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
for( auto& i: filter )
{
if( aFilterType == UNFILTERED_FP_LIST )
{
msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
GetChars( aList.GetItem( ii ).GetNickname() ),
GetChars( aList.GetItem( ii ).GetFootprintName() ) );
newList.Add( msg );
continue;
}
// Filter footprints by selected library
if( (aFilterType & FILTERING_BY_LIBRARY) && !aLibName.IsEmpty()
&& !aList.GetItem( ii ).InLibrary( aLibName ) )
continue;
// Filter footprints by symbol fp-filters
if( (aFilterType & FILTERING_BY_COMPONENT_KEYWORD) && aComponent
&& !aComponent->MatchesFootprintFilters( aList.GetItem( ii ).GetNickname(), aList.GetItem( ii ).GetFootprintName() ) )
continue;
// Filter footprints by symbol pin-count
if( (aFilterType & FILTERING_BY_PIN_COUNT) && aComponent
&& aComponent->GetNetCount() != aList.GetItem( ii ).GetUniquePadCount() )
continue;
// Filter footprints by text-input
if( (aFilterType & FILTERING_BY_NAME ) && !aFootPrintFilterPattern.IsEmpty() )
{
wxString currname = "";
// If the search string contains a ':' character,
// include the library name in the search string
// e.g. LibName:FootprintName
if( aFootPrintFilterPattern.Contains( ":" ) )
{
currname = aList.GetItem( ii ).GetNickname().Lower() + ":";
}
currname += aList.GetItem( ii ).GetFootprintName().Lower();
if( patternFilter.Find( currname ) == EDA_PATTERN_NOT_FOUND )
{
continue;
}
}
msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
GetChars( aList.GetItem( ii ).GetNickname() ),
GetChars( aList.GetItem( ii ).GetFootprintName() ) );
msg.Printf( "%3d %s:%s", int( newList.GetCount() + 1 ),
GetChars( i.GetNickname() ),
GetChars( i.GetFootprintName() ) );
newList.Add( msg );
}
@ -202,6 +170,7 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
if( selection == wxNOT_FOUND )
selection = 0;
wxWindowUpdateLocker freeze( this );
DeleteAllItems();
if( m_footprintList.GetCount() )

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2011-2016 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -127,6 +127,7 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_skipComponentSelect = false;
m_filteringOptions = 0;
m_tcFilterString = NULL;
m_FootprintsList = FOOTPRINT_LIST::GetInstance( Kiway() );
/* Name of the document footprint list
* usually located in share/modules/footprints_doc
@ -409,7 +410,7 @@ bool CVPCB_MAINFRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, i
void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent )
{
bool tableChanged = false;
int r = InvokePcbLibTableEditor( this, &GFootprintTable, Prj().PcbFootprintLibs() );
int r = InvokePcbLibTableEditor( this, &GFootprintTable, Prj().PcbFootprintLibs( Kiway() ) );
if( r & 1 )
{
@ -437,7 +438,7 @@ void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent )
try
{
Prj().PcbFootprintLibs()->Save( fileName );
Prj().PcbFootprintLibs( Kiway() )->Save( fileName );
tableChanged = true;
}
catch( const IO_ERROR& ioe )
@ -455,7 +456,7 @@ void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent )
{
wxBusyCursor dummy;
BuildLIBRARY_LISTBOX();
m_FootprintsList.ReadFootprintFiles( Prj().PcbFootprintLibs() );
m_FootprintsList->ReadFootprintFiles( Prj().PcbFootprintLibs( Kiway() ) );
}
}
@ -482,7 +483,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event )
COMPONENT* component = GetSelectedComponent();
libraryName = m_libListBox->GetSelectedLibrary();
m_footprintListBox->SetFootprints( m_FootprintsList, libraryName, component,
m_footprintListBox->SetFootprints( *m_FootprintsList, libraryName, component,
m_currentSearchPattern, m_filteringOptions);
refreshAfterComponentSearch (component);
@ -657,7 +658,7 @@ void CVPCB_MAINFRAME::DisplayStatus()
{
wxString footprintName = GetSelectedFootprint();
FOOTPRINT_INFO* module = m_FootprintsList.GetModuleInfo( footprintName );
FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( footprintName );
if( module ) // can be NULL if no netlist loaded
{
@ -715,7 +716,7 @@ void CVPCB_MAINFRAME::DisplayStatus()
bool CVPCB_MAINFRAME::LoadFootprintFiles()
{
FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs();
FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs( Kiway() );
// Check if there are footprint libraries in the footprint library table.
if( !fptbl || !fptbl->GetLogicalLibs().size() )
@ -728,12 +729,12 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles()
{
wxBusyCursor dummy; // Let the user know something is happening.
m_FootprintsList.ReadFootprintFiles( fptbl );
m_FootprintsList->ReadFootprintFiles( fptbl );
}
if( m_FootprintsList.GetErrorCount() )
if( m_FootprintsList->GetErrorCount() )
{
m_FootprintsList.DisplayErrors( this );
m_FootprintsList->DisplayErrors( this );
}
return true;
@ -862,7 +863,7 @@ void CVPCB_MAINFRAME::BuildFOOTPRINTS_LISTBOX()
wxFONTWEIGHT_NORMAL ) );
}
m_footprintListBox->SetFootprints( m_FootprintsList, wxEmptyString, NULL,
m_footprintListBox->SetFootprints( *m_FootprintsList, wxEmptyString, NULL,
wxEmptyString, FOOTPRINTS_LISTBOX::UNFILTERED_FP_LIST );
DisplayStatus();
}
@ -921,7 +922,7 @@ void CVPCB_MAINFRAME::BuildLIBRARY_LISTBOX()
wxFONTWEIGHT_NORMAL ) );
}
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs( Kiway() );
if( tbl )
{

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -37,6 +37,7 @@
#include <wxBasePcbFrame.h>
#include <config_params.h>
#include <autosel.h>
#include <memory>
/* Forward declarations of all top-level window classes. */
@ -72,7 +73,7 @@ public:
wxArrayString m_ModuleLibNames;
wxArrayString m_EquFilesNames;
wxString m_DocModulesFileName;
FOOTPRINT_LIST m_FootprintsList;
std::unique_ptr<FOOTPRINT_LIST> m_FootprintsList;
protected:
int m_undefinedComponentCnt;

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -29,7 +29,7 @@
#define CVSTRUCT_H
#include <wx/listctrl.h>
#include <footprint_filter.h>
/* Forward declarations of all top-level window classes. */
class CVPCB_MAINFRAME;
@ -90,8 +90,12 @@ private:
wxArrayString m_footprintList;
public:
// OR'ed mask to manage footprint filtering options
enum FP_FILTER_T
/**
* Filter setting constants. The filter type is a bitwise OR of these flags,
* and only footprints matching all selected filter types are shown.
*/
enum FP_FILTER_T: int
{
UNFILTERED_FP_LIST = 0,
FILTERING_BY_COMPONENT_KEYWORD = 0x0001,

View File

@ -7,7 +7,7 @@
*
* Copyright (C) 2015 Jean-Pierre Charras, jean-pierre.charras
* Copyright (C) 2011-2016 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -26,7 +26,6 @@
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <fctsys.h>
#include <kiway.h>
#include <common.h>
@ -212,7 +211,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles( const std::string& aNetlist )
if( component->GetFPID().IsLegacy() )
{
// get this first here, it's possibly obsoleted if we get it too soon.
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs( Kiway() );
int guess = guessNickname( tbl, (LIB_ID*) &component->GetFPID() );

View File

@ -25,30 +25,31 @@
#include <dialog_choose_component.h>
#include <algorithm>
#include <set>
#include <wx/tokenzr.h>
#include <wx/utils.h>
#include <wx/artprov.h>
#include <wx/bitmap.h>
#include <wx/statbmp.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/dataview.h>
#include <wx/html/htmlwin.h>
#include <wx/panel.h>
#include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/button.h>
#include <wx/statbmp.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include <wx/utils.h>
#include <class_library.h>
#include <sch_base_frame.h>
#include <widgets/footprint_preview_widget.h>
#include <widgets/two_column_tree_list.h>
#include <template_fieldnames.h>
#include <generate_alias_info.h>
#include <sch_base_frame.h>
#include <template_fieldnames.h>
#include <widgets/footprint_preview_widget.h>
#include <widgets/footprint_select_widget.h>
// Tree navigation helpers.
static wxDataViewItem GetPrevItem( const wxDataViewCtrl& ctrl, const wxDataViewItem& item );
@ -56,21 +57,25 @@ static wxDataViewItem GetNextItem( const wxDataViewCtrl& ctrl, const wxDataViewI
static wxDataViewItem GetPrevSibling( const wxDataViewCtrl& ctrl, const wxDataViewItem& item );
static wxDataViewItem GetNextSibling( const wxDataViewCtrl& ctrl, const wxDataViewItem& item );
DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT(
SCH_BASE_FRAME* aParent, const wxString& aTitle,
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, int aDeMorganConvert ):
DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition,
wxSize( 800, 650 ), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_parent( aParent ),
m_adapter( aAdapter ),
m_deMorganConvert( aDeMorganConvert >= 0 ? aDeMorganConvert : 0 ),
m_external_browser_requested( false )
FOOTPRINT_ASYNC_LOADER DIALOG_CHOOSE_COMPONENT::m_fp_loader;
std::unique_ptr<FOOTPRINT_LIST> DIALOG_CHOOSE_COMPONENT::m_fp_list;
DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT( SCH_BASE_FRAME* aParent, const wxString& aTitle,
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, int aDeMorganConvert, bool aAllowFieldEdits )
: DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, wxSize( 800, 650 ),
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_parent( aParent ),
m_adapter( aAdapter ),
m_deMorganConvert( aDeMorganConvert >= 0 ? aDeMorganConvert : 0 ),
m_allow_field_edits( aAllowFieldEdits ),
m_external_browser_requested( false )
{
wxBusyCursor busy_while_loading;
auto sizer = new wxBoxSizer( wxVERTICAL );
auto splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_LIVE_UPDATE );
auto splitter = new wxSplitterWindow(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_LIVE_UPDATE );
auto left_panel = ConstructLeftPanel( splitter );
auto right_panel = ConstructRightPanel( splitter );
auto buttons = new wxStdDialogButtonSizer();
@ -84,22 +89,28 @@ DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT(
buttons->AddButton( new wxButton( this, wxID_CANCEL ) );
buttons->Realize();
sizer->Add( splitter, 1, wxEXPAND | wxALL, 5 );
sizer->Add( buttons, 0, wxEXPAND | wxBOTTOM, 10 );
sizer->Add( splitter, 1, wxEXPAND | wxALL, 5 );
sizer->Add( buttons, 0, wxEXPAND | wxBOTTOM, 10 );
SetSizer( sizer );
Bind( wxEVT_INIT_DIALOG, &DIALOG_CHOOSE_COMPONENT::OnInitDialog, this );
Bind( wxEVT_TIMER, &DIALOG_CHOOSE_COMPONENT::OnCloseTimer, this );
Bind( wxEVT_TIMER, &DIALOG_CHOOSE_COMPONENT::OnCloseTimer, this, m_dbl_click_timer->GetId() );
m_query_ctrl->Bind( wxEVT_TEXT, &DIALOG_CHOOSE_COMPONENT::OnQueryText, this );
m_query_ctrl->Bind( wxEVT_TEXT_ENTER, &DIALOG_CHOOSE_COMPONENT::OnQueryEnter, this );
m_query_ctrl->Bind( wxEVT_CHAR_HOOK, &DIALOG_CHOOSE_COMPONENT::OnQueryCharHook, this );
m_tree_ctrl->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &DIALOG_CHOOSE_COMPONENT::OnTreeActivate, this );
m_tree_ctrl->Bind( wxEVT_DATAVIEW_SELECTION_CHANGED, &DIALOG_CHOOSE_COMPONENT::OnTreeSelect, this );
m_query_ctrl->Bind( wxEVT_TEXT, &DIALOG_CHOOSE_COMPONENT::OnQueryText, this );
m_query_ctrl->Bind( wxEVT_TEXT_ENTER, &DIALOG_CHOOSE_COMPONENT::OnQueryEnter, this );
m_query_ctrl->Bind( wxEVT_CHAR_HOOK, &DIALOG_CHOOSE_COMPONENT::OnQueryCharHook, this );
m_tree_ctrl->Bind(
wxEVT_DATAVIEW_ITEM_ACTIVATED, &DIALOG_CHOOSE_COMPONENT::OnTreeActivate, this );
m_tree_ctrl->Bind(
wxEVT_DATAVIEW_SELECTION_CHANGED, &DIALOG_CHOOSE_COMPONENT::OnTreeSelect, this );
m_details_ctrl->Bind( wxEVT_HTML_LINK_CLICKED, &DIALOG_CHOOSE_COMPONENT::OnDetailsLink, this );
m_sch_view_ctrl->Bind( wxEVT_LEFT_DCLICK, &DIALOG_CHOOSE_COMPONENT::OnSchViewDClick, this );
m_sch_view_ctrl->Bind( wxEVT_PAINT, &DIALOG_CHOOSE_COMPONENT::OnSchViewPaint, this );
if( m_fp_sel_ctrl )
m_fp_sel_ctrl->Bind(
EVT_FOOTPRINT_SELECTED, &DIALOG_CHOOSE_COMPONENT::OnFootprintSelected, this );
Layout();
}
@ -121,31 +132,27 @@ wxPanel* DIALOG_CHOOSE_COMPONENT::ConstructLeftPanel( wxWindow* aParent )
auto sizer = new wxBoxSizer( wxVERTICAL );
auto search_sizer = new wxBoxSizer( wxHORIZONTAL );
m_query_ctrl = new wxTextCtrl( panel, wxID_ANY,
wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
m_query_ctrl = new wxTextCtrl(
panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_tree_ctrl = new wxDataViewCtrl( panel, wxID_ANY,
wxDefaultPosition, wxDefaultSize,
wxDV_SINGLE );
m_tree_ctrl =
new wxDataViewCtrl( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_SINGLE );
m_adapter->AttachTo( m_tree_ctrl );
m_details_ctrl = new wxHtmlWindow( panel, wxID_ANY,
wxDefaultPosition, wxSize( 320,240 ),
m_details_ctrl = new wxHtmlWindow( panel, wxID_ANY, wxDefaultPosition, wxSize( 320, 240 ),
wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER );
// Additional visual cue for GTK, which hides the placeholder text on focus
// Additional visual cue for GTK, which hides the placeholder text on focus
#ifdef __WXGTK__
search_sizer->Add(
new wxStaticBitmap(
panel, wxID_ANY, wxArtProvider::GetBitmap( wxART_FIND, wxART_FRAME_ICON ) ),
0, wxALIGN_CENTER | wxALL, 5 );
search_sizer->Add( new wxStaticBitmap( panel, wxID_ANY,
wxArtProvider::GetBitmap( wxART_FIND, wxART_FRAME_ICON ) ),
0, wxALIGN_CENTER | wxALL, 5 );
#endif
search_sizer->Add( m_query_ctrl, 1, wxALIGN_CENTER | wxALL | wxEXPAND, 5 );
sizer->Add( search_sizer, 0, wxEXPAND, 5 );
sizer->Add( m_tree_ctrl, 1, wxALL | wxEXPAND, 5 );
sizer->Add( search_sizer, 0, wxEXPAND, 5 );
sizer->Add( m_tree_ctrl, 1, wxALL | wxEXPAND, 5 );
sizer->Add( m_details_ctrl, 1, wxALL | wxEXPAND, 5 );
panel->SetSizer( sizer );
@ -160,23 +167,25 @@ wxPanel* DIALOG_CHOOSE_COMPONENT::ConstructRightPanel( wxWindow* aParent )
auto panel = new wxPanel( aParent );
auto sizer = new wxBoxSizer( wxVERTICAL );
m_sch_view_ctrl = new wxPanel( panel, wxID_ANY,
wxDefaultPosition, wxSize( -1, -1 ),
m_sch_view_ctrl = new wxPanel( panel, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ),
wxFULL_REPAINT_ON_RESIZE | wxSUNKEN_BORDER | wxTAB_TRAVERSAL );
m_sch_view_ctrl->SetLayoutDirection( wxLayout_LeftToRight );
m_fp_sel_ctrl = new wxChoice( panel, wxID_ANY );
m_fp_sel_ctrl->SetSelection( 0 );
if( m_allow_field_edits )
m_fp_sel_ctrl = new FOOTPRINT_SELECT_WIDGET( panel, m_fp_loader, m_fp_list, true );
else
m_fp_sel_ctrl = nullptr;
m_fp_view_ctrl = new FOOTPRINT_PREVIEW_WIDGET( panel, Kiway() );
sizer->Add( m_sch_view_ctrl, 1, wxEXPAND | wxALL, 5 );
sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxALL, 5 );
sizer->Add( m_fp_view_ctrl, 1, wxEXPAND | wxALL, 5 );
#ifndef KICAD_FOOTPRINT_SELECTOR
m_fp_sel_ctrl->Hide();
#endif
sizer->Add( m_sch_view_ctrl, 1, wxEXPAND | wxALL, 5 );
if( m_fp_sel_ctrl )
sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxALL, 5 );
sizer->Add( m_fp_view_ctrl, 1, wxEXPAND | wxALL, 5 );
panel->SetSizer( sizer );
panel->Layout();
@ -199,6 +208,12 @@ void DIALOG_CHOOSE_COMPONENT::OnInitDialog( wxInitDialogEvent& aEvent )
// This hides the GAL panel and shows the status label
m_fp_view_ctrl->SetStatusText( wxEmptyString );
}
if( m_fp_sel_ctrl )
m_fp_sel_ctrl->Load( Kiway(), Prj() );
// There may be a part preselected in the model. Make sure it is displayed.
PostSelectEvent();
}
@ -206,13 +221,19 @@ LIB_ALIAS* DIALOG_CHOOSE_COMPONENT::GetSelectedAlias( int* aUnit ) const
{
auto sel = m_tree_ctrl->GetSelection();
if( aUnit && m_adapter->GetUnitFor( sel ) )
if( aUnit )
*aUnit = m_adapter->GetUnitFor( sel );
return m_adapter->GetAliasFor( sel );
}
std::vector<std::pair<int, wxString>> DIALOG_CHOOSE_COMPONENT::GetFields() const
{
return m_field_edits;
}
void DIALOG_CHOOSE_COMPONENT::OnQueryText( wxCommandEvent& aEvent )
{
m_adapter->UpdateSearchString( m_query_ctrl->GetLineText( 0 ) );
@ -254,16 +275,12 @@ void DIALOG_CHOOSE_COMPONENT::OnQueryCharHook( wxKeyEvent& aKeyStroke )
switch( aKeyStroke.GetKeyCode() )
{
case WXK_UP:
SelectIfValid( GetPrevItem( *m_tree_ctrl, sel ) );
break;
case WXK_UP: SelectIfValid( GetPrevItem( *m_tree_ctrl, sel ) ); break;
case WXK_DOWN:
SelectIfValid( GetNextItem( *m_tree_ctrl, sel ) );
break;
case WXK_DOWN: SelectIfValid( GetNextItem( *m_tree_ctrl, sel ) ); break;
default:
aKeyStroke.Skip(); // Any other key: pass on to search box directly.
aKeyStroke.Skip(); // Any other key: pass on to search box directly.
break;
}
}
@ -271,8 +288,8 @@ void DIALOG_CHOOSE_COMPONENT::OnQueryCharHook( wxKeyEvent& aKeyStroke )
void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxDataViewEvent& aEvent )
{
auto sel = m_tree_ctrl->GetSelection();
int unit = m_adapter->GetUnitFor( sel );
auto sel = m_tree_ctrl->GetSelection();
int unit = m_adapter->GetUnitFor( sel );
LIB_ALIAS* alias = m_adapter->GetAliasFor( sel );
m_sch_view_ctrl->Refresh();
@ -281,6 +298,7 @@ void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxDataViewEvent& aEvent )
{
m_details_ctrl->SetPage( GenerateAliasInfo( alias, unit ) );
ShowFootprintFor( alias );
PopulateFootprintSelector( alias );
}
else
{
@ -288,6 +306,8 @@ void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxDataViewEvent& aEvent )
if( m_fp_view_ctrl->IsInitialized() )
m_fp_view_ctrl->SetStatusText( wxEmptyString );
PopulateFootprintSelector( nullptr );
}
}
@ -314,7 +334,7 @@ void DIALOG_CHOOSE_COMPONENT::OnCloseTimer( wxTimerEvent& aEvent )
}
else
{
EndModal( wxID_OK );
EndQuasiModal( wxID_OK );
}
}
@ -322,7 +342,7 @@ void DIALOG_CHOOSE_COMPONENT::OnCloseTimer( wxTimerEvent& aEvent )
void DIALOG_CHOOSE_COMPONENT::OnSchViewDClick( wxMouseEvent& aEvent )
{
m_external_browser_requested = true;
EndModal( wxID_OK );
EndQuasiModal( wxID_OK );
}
@ -331,32 +351,62 @@ void DIALOG_CHOOSE_COMPONENT::ShowFootprintFor( LIB_ALIAS* aAlias )
if( !m_fp_view_ctrl->IsInitialized() )
return;
LIB_FIELDS fields;
aAlias->GetPart()->GetFields( fields );
LIB_FIELD* fp_field = aAlias->GetPart()->GetField( FOOTPRINT );
wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
for( auto const & field: fields )
ShowFootprint( fp_name );
}
void DIALOG_CHOOSE_COMPONENT::ShowFootprint( wxString const& aName )
{
if( aName == wxEmptyString )
{
if( field.GetId() != FOOTPRINT )
continue;
wxString fpname = field.GetFullText();
if( fpname == wxEmptyString )
{
m_fp_view_ctrl->SetStatusText( _( "No footprint specified" ) );
}
else
{
m_fp_view_ctrl->ClearStatus();
m_fp_view_ctrl->CacheFootprint( LIB_ID( fpname ) );
m_fp_view_ctrl->DisplayFootprint( LIB_ID( fpname ) );
}
break;
m_fp_view_ctrl->SetStatusText( _( "No footprint specified" ) );
}
else
{
LIB_ID lib_id( aName );
m_fp_view_ctrl->ClearStatus();
m_fp_view_ctrl->CacheFootprint( lib_id );
m_fp_view_ctrl->DisplayFootprint( lib_id );
}
}
void DIALOG_CHOOSE_COMPONENT::PopulateFootprintSelector( LIB_ALIAS* aAlias )
{
if( !m_fp_sel_ctrl )
return;
m_fp_sel_ctrl->ClearFilters();
if( aAlias )
{
LIB_PINS temp_pins;
LIB_FIELD* fp_field = aAlias->GetPart()->GetField( FOOTPRINT );
wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
aAlias->GetPart()->GetPins( temp_pins );
m_fp_sel_ctrl->FilterByPinCount( temp_pins.size() );
m_fp_sel_ctrl->FilterByFootprintFilters( aAlias->GetPart()->GetFootPrints(), true );
m_fp_sel_ctrl->SetDefaultFootprint( fp_name );
m_fp_sel_ctrl->UpdateList();
m_fp_sel_ctrl->Enable();
}
else
{
m_fp_sel_ctrl->UpdateList();
m_fp_sel_ctrl->Disable();
}
}
void DIALOG_CHOOSE_COMPONENT::OnDetailsLink( wxHtmlLinkEvent& aEvent )
{
const wxHtmlLinkInfo & info = aEvent.GetLinkInfo();
const wxHtmlLinkInfo& info = aEvent.GetLinkInfo();
::wxLaunchDefaultBrowser( info.GetHref() );
}
@ -365,9 +415,9 @@ void DIALOG_CHOOSE_COMPONENT::OnSchViewPaint( wxPaintEvent& aEvent )
{
auto sel = m_tree_ctrl->GetSelection();
int unit = m_adapter->GetUnitFor( sel );
int unit = m_adapter->GetUnitFor( sel );
LIB_ALIAS* alias = m_adapter->GetAliasFor( sel );
LIB_PART* part = alias ? alias->GetPart() : nullptr;
LIB_PART* part = alias ? alias->GetPart() : nullptr;
// Don't draw anything (not even the background) if we don't have
// a part to show
@ -392,6 +442,21 @@ void DIALOG_CHOOSE_COMPONENT::OnSchViewPaint( wxPaintEvent& aEvent )
}
void DIALOG_CHOOSE_COMPONENT::OnFootprintSelected( wxCommandEvent& aEvent )
{
m_fp_override = aEvent.GetString();
m_field_edits.erase(
std::remove_if( m_field_edits.begin(), m_field_edits.end(),
[]( std::pair<int, wxString> const& i ) { return i.first == FOOTPRINT; } ),
m_field_edits.end() );
m_field_edits.push_back( std::make_pair( FOOTPRINT, m_fp_override ) );
ShowFootprint( m_fp_override );
}
void DIALOG_CHOOSE_COMPONENT::RenderPreview( LIB_PART* aComponent, int aUnit )
{
wxPaintDC dc( m_sch_view_ctrl );
@ -418,10 +483,10 @@ void DIALOG_CHOOSE_COMPONENT::RenderPreview( LIB_PART* aComponent, int aUnit )
dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 );
// Find joint bounding box for everything we are about to draw.
EDA_RECT bBox = aComponent->GetUnitBoundingBox( aUnit, m_deMorganConvert );
EDA_RECT bBox = aComponent->GetUnitBoundingBox( aUnit, m_deMorganConvert );
const double xscale = (double) dc_size.x / bBox.GetWidth();
const double yscale = (double) dc_size.y / bBox.GetHeight();
const double scale = std::min( xscale, yscale ) * 0.85;
const double scale = std::min( xscale, yscale ) * 0.85;
dc.SetUserScale( scale, scale );
@ -503,7 +568,7 @@ static wxDataViewItem GetNextItem( const wxDataViewCtrl& tree, const wxDataViewI
else
{
// Walk up levels until we find one that has a next sibling.
for ( wxDataViewItem walk = item; walk.IsOk(); walk = tree.GetModel()->GetParent( walk ) )
for( wxDataViewItem walk = item; walk.IsOk(); walk = tree.GetModel()->GetParent( walk ) )
{
nextItem = GetNextSibling( tree, walk );
@ -519,8 +584,8 @@ static wxDataViewItem GetNextItem( const wxDataViewCtrl& tree, const wxDataViewI
static wxDataViewItem GetPrevSibling( const wxDataViewCtrl& tree, const wxDataViewItem& item )
{
wxDataViewItemArray siblings;
wxDataViewItem invalid;
wxDataViewItem parent = tree.GetModel()->GetParent( item );
wxDataViewItem invalid;
wxDataViewItem parent = tree.GetModel()->GetParent( item );
tree.GetModel()->GetChildren( parent, siblings );
@ -542,8 +607,8 @@ static wxDataViewItem GetPrevSibling( const wxDataViewCtrl& tree, const wxDataVi
static wxDataViewItem GetNextSibling( const wxDataViewCtrl& tree, const wxDataViewItem& item )
{
wxDataViewItemArray siblings;
wxDataViewItem invalid;
wxDataViewItem parent = tree.GetModel()->GetParent( item );
wxDataViewItem invalid;
wxDataViewItem parent = tree.GetModel()->GetParent( item );
tree.GetModel()->GetChildren( parent, siblings );

View File

@ -27,6 +27,7 @@
#include "dialog_shim.h"
#include <cmp_tree_model_adapter.h>
#include <footprint_info.h>
class wxStaticBitmap;
class wxTextCtrl;
@ -40,6 +41,7 @@ class wxButton;
class wxTimer;
class FOOTPRINT_PREVIEW_WIDGET;
class FOOTPRINT_SELECT_WIDGET;
class LIB_ALIAS;
class LIB_PART;
class SCH_BASE_FRAME;
@ -82,7 +84,6 @@ class SCH_BASE_FRAME;
class DIALOG_CHOOSE_COMPONENT : public DIALOG_SHIM
{
public:
/**
* Create dialog to choose component.
*
@ -92,30 +93,44 @@ public:
* for documentation.
* @param aDeMorganConvert preferred deMorgan conversion
* (TODO: should happen in dialog)
* @param aAllowFieldEdits if false, all functions that allow the user to edit
* fields (currently just footprint selection) will not be available.
*/
DIALOG_CHOOSE_COMPONENT( SCH_BASE_FRAME* aParent, const wxString& aTitle,
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter,
int aDeMorganConvert );
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, int aDeMorganConvert, bool aAllowFieldEdits );
~DIALOG_CHOOSE_COMPONENT();
/** Function GetSelectedAlias
* To be called after this dialog returns from ShowModal().
*
* For multi-unit components, if the user selects the component itself
* rather than picking an individual unit, 0 will be returned in aUnit.
* Beware that this is an invalid unit number - this should be replaced
* with whatever default is desired (usually 1).
*
* @param aUnit if not NULL, the selected unit is filled in here.
* @return the alias that has been selected, or NULL if there is none.
*/
LIB_ALIAS* GetSelectedAlias( int* aUnit ) const;
/**
* Get a list of fields edited by the user.
* @return vector of pairs; each.first = field ID, each.second = new value
*/
std::vector<std::pair<int, wxString>> GetFields() const;
/** Function IsExternalBrowserSelected
*
* @return true, iff the user pressed the thumbnail view of the component to
* launch the component browser.
*/
bool IsExternalBrowserSelected() const { return m_external_browser_requested; }
bool IsExternalBrowserSelected() const
{
return m_external_browser_requested;
}
protected:
static constexpr int DblClickDelay = 100; // milliseconds
wxPanel* ConstructLeftPanel( wxWindow* aParent );
@ -123,6 +138,7 @@ protected:
void OnInitDialog( wxInitDialogEvent& aEvent );
void OnCloseTimer( wxTimerEvent& aEvent );
void OnProgressTimer( wxTimerEvent& aEvent );
void OnQueryText( wxCommandEvent& aEvent );
void OnQueryEnter( wxCommandEvent& aEvent );
@ -136,11 +152,25 @@ protected:
void OnSchViewDClick( wxMouseEvent& aEvent );
void OnSchViewPaint( wxPaintEvent& aEvent );
void OnFootprintSelected( wxCommandEvent& aEvent );
/**
* Look up the footprint for a given alias and display it.
*/
void ShowFootprintFor( LIB_ALIAS* aAlias );
/**
* Display the given footprint by name.
*/
void ShowFootprint( wxString const& aName );
/**
* Populate the footprint selector for a given alias.
*
* @param aAlias alias, or null to clear
*/
void PopulateFootprintSelector( LIB_ALIAS* aAlias );
/**
* If a wxDataViewitem is valid, select it and post a selection event.
*/
@ -170,15 +200,20 @@ protected:
wxDataViewCtrl* m_tree_ctrl;
wxHtmlWindow* m_details_ctrl;
wxPanel* m_sch_view_ctrl;
wxChoice* m_fp_sel_ctrl;
FOOTPRINT_SELECT_WIDGET* m_fp_sel_ctrl;
FOOTPRINT_PREVIEW_WIDGET* m_fp_view_ctrl;
SCH_BASE_FRAME* m_parent;
CMP_TREE_MODEL_ADAPTER::PTR m_adapter;
int m_deMorganConvert;
bool m_external_browser_requested;
int m_deMorganConvert;
bool m_allow_field_edits;
bool m_external_browser_requested;
wxString m_fp_override;
static FOOTPRINT_ASYNC_LOADER m_fp_loader;
static std::unique_ptr<FOOTPRINT_LIST> m_fp_list;
std::vector<std::pair<int, wxString>> m_field_edits;
};
#endif /* DIALOG_CHOOSE_COMPONENT_H */

View File

@ -281,14 +281,14 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnTestChipName( wxCommandEvent& event )
void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnSelectChipName( wxCommandEvent& event )
{
wxArrayString dummy;
int dummyunit = 1;
wxString chipname = m_parent->SelectComponentFromLibrary( NULL, dummy, dummyunit,
true, NULL, NULL );
if( chipname.IsEmpty() )
SCH_BASE_FRAME::HISTORY_LIST dummy;
auto sel = m_parent->SelectComponentFromLibrary( NULL, dummy, true, 0, 0 );
if( sel.Name.IsEmpty() )
return;
chipnameTextCtrl->SetValue( chipname );
chipnameTextCtrl->SetValue( sel.Name );
}

View File

@ -28,6 +28,7 @@
* @brief functions to get and place library components.
*/
#include <algorithm>
#include <fctsys.h>
#include <pgm_base.h>
#include <kiway.h>
@ -50,9 +51,10 @@
#include <dialog_get_component.h>
wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
int* aUnit, int* aConvert )
SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibBrowser(
const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
int aUnit, int aConvert )
{
// Close any open non-modal Lib browser, and open a new one, in "modal" mode:
LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
@ -71,38 +73,36 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFi
viewlibFrame->SetSelectedComponent( aPreselectedAlias->GetName() );
}
if( aUnit && *aUnit > 0 )
viewlibFrame->SetUnit( *aUnit );
if( aUnit > 0 )
viewlibFrame->SetUnit( aUnit );
if( aConvert && *aConvert > 0 )
viewlibFrame->SetConvert( *aConvert );
if( aConvert > 0 )
viewlibFrame->SetConvert( aConvert );
viewlibFrame->Refresh();
wxString cmpname;
COMPONENT_SELECTION sel;
if( viewlibFrame->ShowModal( &cmpname, this ) )
if( viewlibFrame->ShowModal( &sel.Name, this ) )
{
if( aUnit )
*aUnit = viewlibFrame->GetUnit();
if( aConvert )
*aConvert = viewlibFrame->GetConvert();
sel.Unit = viewlibFrame->GetUnit();
sel.Convert = viewlibFrame->GetConvert();
}
viewlibFrame->Destroy();
return cmpname;
return sel;
}
wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const SCHLIB_FILTER* aFilter,
wxArrayString& aHistoryList,
int& aHistoryLastUnit,
bool aUseLibBrowser,
int* aUnit,
int* aConvert,
const wxString& aHighlight )
SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary(
const SCHLIB_FILTER* aFilter,
std::vector<COMPONENT_SELECTION>& aHistoryList,
bool aUseLibBrowser,
int aUnit,
int aConvert,
const wxString& aHighlight,
bool aAllowFields )
{
wxString dialogTitle;
PART_LIBS* libs = Prj().SchLibs();
@ -141,56 +141,68 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const SCHLIB_FILTER* aFilte
if( !aHistoryList.empty() )
{
adapter->AddAliasList( "-- " + _( "History" ) + " --", aHistoryList, NULL );
adapter->SetPreselectNode( aHistoryList[0], aHistoryLastUnit );
wxArrayString history_list;
for( auto const& i : aHistoryList )
history_list.push_back( i.Name );
adapter->AddAliasList( "-- " + _( "History" ) + " --", history_list, NULL );
adapter->SetPreselectNode( aHistoryList[0].Name, aHistoryList[0].Unit );
}
if( !aHighlight.IsEmpty() )
adapter->SetPreselectNode( aHighlight, /* aUnit */ 0 );
const int deMorgan = aConvert ? *aConvert : 1;
dialogTitle.Printf( _( "Choose Component (%d items loaded)" ),
adapter->GetComponentsCount() );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, deMorgan );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, aConvert, aAllowFields );
if( dlg.ShowModal() == wxID_CANCEL )
return wxEmptyString;
if( dlg.ShowQuasiModal() == wxID_CANCEL )
return COMPONENT_SELECTION();
COMPONENT_SELECTION sel;
LIB_ALIAS* const alias = dlg.GetSelectedAlias( &sel.Unit );
if( alias->GetPart()->IsMulti() && sel.Unit == 0 )
sel.Unit = 1;
sel.Fields = dlg.GetFields();
wxString cmpName;
LIB_ALIAS* const alias = dlg.GetSelectedAlias( aUnit );
if ( alias )
cmpName = alias->GetName();
sel.Name = alias->GetName();
if( dlg.IsExternalBrowserSelected() ) // User requested component browser.
cmpName = SelectComponentFromLibBrowser( aFilter, alias, aUnit, aConvert);
sel = SelectComponentFromLibBrowser( aFilter, alias, sel.Unit, sel.Convert );
if( !cmpName.empty() )
if( !sel.Name.empty() )
{
AddHistoryComponentName( aHistoryList, cmpName );
aHistoryList.erase(
std::remove_if(
aHistoryList.begin(),
aHistoryList.end(),
[ &sel ]( COMPONENT_SELECTION const& i ) { return i.Name == sel.Name; } ),
aHistoryList.end() );
if ( aUnit )
aHistoryLastUnit = *aUnit;
aHistoryList.insert( aHistoryList.begin(), sel );
}
return cmpName;
return sel;
}
SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC,
const SCHLIB_FILTER* aFilter,
wxArrayString& aHistoryList,
int& aHistoryLastUnit,
bool aUseLibBrowser )
SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component(
wxDC* aDC,
const SCHLIB_FILTER* aFilter,
SCH_BASE_FRAME::HISTORY_LIST& aHistoryList,
bool aUseLibBrowser )
{
int unit = 1;
int convert = 1;
SetRepeatItem( NULL );
m_canvas->SetIgnoreMouseEvents( true );
wxString name = SelectComponentFromLibrary( aFilter, aHistoryList, aHistoryLastUnit,
aUseLibBrowser, &unit, &convert );
auto sel = SelectComponentFromLibrary( aFilter, aHistoryList,
aUseLibBrowser, 1, 1 );
if( name.IsEmpty() )
if( sel.Name.IsEmpty() )
{
m_canvas->SetIgnoreMouseEvents( false );
m_canvas->MoveCursorToCrossHair();
@ -205,19 +217,19 @@ SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC,
if( aFilter )
libsource = aFilter->GetLibSource();
LIB_PART* part = Prj().SchLibs()->FindLibPart( LIB_ID( wxEmptyString, name ), libsource );
LIB_PART* part = Prj().SchLibs()->FindLibPart( LIB_ID( wxEmptyString, sel.Name ), libsource );
if( !part )
{
wxString msg = wxString::Format( _(
"Failed to find part '%s' in library" ),
GetChars( name )
GetChars( sel.Name )
);
wxMessageBox( msg );
return NULL;
}
SCH_COMPONENT* component = new SCH_COMPONENT( *part, m_CurrentSheet, unit, convert,
SCH_COMPONENT* component = new SCH_COMPONENT( *part, m_CurrentSheet, sel.Unit, sel.Convert,
GetCrossHairPosition(), true );
// Set the m_ChipName value, from component name in lib, for aliases
@ -225,14 +237,23 @@ SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC,
// alias exists because its root component was found
LIB_ID libId;
libId.SetLibItemName( name, false );
libId.SetLibItemName( sel.Name, false );
component->SetLibId( libId );
// Be sure the link to the corresponding LIB_PART is OK:
component->Resolve( Prj().SchLibs() );
// Set any fields that have been modified
for( auto const& i : sel.Fields )
{
auto field = component->GetField( i.first );
if( field )
field->SetText( i.second );
}
// Set the component value that can differ from component name in lib, for aliases
component->GetField( VALUE )->SetText( name );
component->GetField( VALUE )->SetText( sel.Name );
MSG_PANEL_ITEMS items;

View File

@ -105,7 +105,6 @@ bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry )
void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
{
wxString cmp_name;
LIB_ALIAS* libEntry = NULL;
m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
@ -130,14 +129,13 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
LIB_PART* current_part = GetCurPart();
wxString part_name = current_part ? current_part->GetName() : wxString( wxEmptyString );
wxArrayString dummyHistoryList;
int dummyLastUnit;
SCH_BASE_FRAME::HISTORY_LIST dummyHistoryList;
SCHLIB_FILTER filter;
filter.LoadFrom( lib->GetName() );
cmp_name = SelectComponentFromLibrary( &filter, dummyHistoryList, dummyLastUnit,
true, NULL, NULL, part_name );
auto sel = SelectComponentFromLibrary( &filter, dummyHistoryList,
true, 0, 0, part_name, false );
if( cmp_name.IsEmpty() )
if( sel.Name.IsEmpty() )
return;
GetScreen()->ClrModify();
@ -148,14 +146,14 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
m_aliasName.Empty();
// Load the new library component
libEntry = lib->FindAlias( cmp_name );
libEntry = lib->FindAlias( sel.Name );
PART_LIB* searchLib = lib;
if( !libEntry )
{
// Not found in the active library: search inside the full list
// (can happen when using Viewlib to load a component)
libEntry = Prj().SchLibs()->FindLibraryAlias( LIB_ID( wxEmptyString, cmp_name ) );
libEntry = Prj().SchLibs()->FindLibraryAlias( LIB_ID( wxEmptyString, sel.Name ) );
if( libEntry )
{
@ -175,7 +173,7 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
if( !libEntry )
{
wxString msg = wxString::Format( _( "Part name '%s' not found in library '%s'" ),
GetChars( cmp_name ),
GetChars( sel.Name ),
GetChars( searchLib->GetName() ) );
DisplayError( this, msg );
return;
@ -540,9 +538,9 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
wxString dialogTitle;
dialogTitle.Printf( _( "Delete Component (%u items loaded)" ), adapter->GetComponentsCount() );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, m_convert );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, m_convert, false );
if( dlg.ShowModal() == wxID_CANCEL )
if( dlg.ShowQuasiModal() == wxID_CANCEL )
{
return;
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2017 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
@ -53,11 +53,8 @@
// TODO(hzeller): These pairs of elmenets should be represented by an object, but don't want
// to refactor too much right now to not get in the way with other code changes.
static wxArrayString s_CmpNameList;
static int s_CmpLastUnit;
static wxArrayString s_PowerNameList;
static int s_LastPowerUnit;
static SCH_BASE_FRAME::HISTORY_LIST s_CmpNameList;
static SCH_BASE_FRAME::HISTORY_LIST s_PowerNameList;
void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
@ -306,7 +303,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
if( (item == NULL) || (item->GetFlags() == 0) )
{
GetScreen()->SetCurItem( Load_Component( aDC, NULL,
s_CmpNameList, s_CmpLastUnit, true ) );
s_CmpNameList, true ) );
m_canvas->SetAutoPanRequest( true );
}
else
@ -321,7 +318,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
SCHLIB_FILTER filter;
filter.FilterPowerParts( true );
GetScreen()->SetCurItem( Load_Component( aDC, &filter,
s_PowerNameList, s_LastPowerUnit, false ) );
s_PowerNameList, false ) );
m_canvas->SetAutoPanRequest( true );
}
else

View File

@ -122,31 +122,55 @@ public:
void UpdateStatusBar() override;
struct COMPONENT_SELECTION
{
wxString Name;
int Unit;
int Convert;
std::vector<std::pair<int, wxString>> Fields;
COMPONENT_SELECTION():
Name(""),
Unit(1),
Convert(1)
{}
};
typedef std::vector<COMPONENT_SELECTION> HISTORY_LIST;
/**
* Function SelectComponentFromLib
* Calls the library viewer to select component to import into schematic.
* if the library viewer is currently running, it is closed and reopened
* in modal mode.
*
* aAllowFields chooses whether or not features that permit the user to edit
* fields (e.g. footprint selection) should be enabled. This should be false
* when they would have no effect, for example loading a part into libedit.
*
* @param aFilter is a SCHLIB_FILTER filter to pass the allowed library names
* and/or the library name to load the component from and/or some other filter
* if NULL, no filtering.
* @param aHistoryList list of previously loaded components
* @param aHistoryLastUnit remembering last unit in last component.
* @param aHistoryList list of previously loaded components - will be edited
* @param aUseLibBrowser bool to call the library viewer to select the component
* @param aUnit a pointer to int to return the selected unit (if any)
* @param aConvert a pointer to int to return the selected De Morgan shape (if any)
* @param aUnit preselected unit
* @param aConvert preselected De Morgan shape
* @param aHighlight name of component to highlight in the list.
* highlights none if there isn't one by that name
* @param aAllowFields whether to allow field editing in the dialog
*
* @return the component name
* @return the selected component
*/
wxString SelectComponentFromLibrary( const SCHLIB_FILTER* aFilter,
wxArrayString& aHistoryList,
int& aHistoryLastUnit,
bool aUseLibBrowser,
int* aUnit,
int* aConvert,
const wxString& aHighlight = wxEmptyString );
COMPONENT_SELECTION SelectComponentFromLibrary(
const SCHLIB_FILTER* aFilter,
std::vector<COMPONENT_SELECTION>& aHistoryList,
bool aUseLibBrowser,
int aUnit,
int aConvert,
const wxString& aHighlight = wxEmptyString,
bool aAllowFields = true );
protected:
@ -158,15 +182,14 @@ protected:
* @param aFilter is a filter to pass the allowed library names
* and/or some other filter
* @param aPreselectedAlias Preselected component alias. NULL if none.
* @param aUnit Pointer to Unit-number. Input is the pre-selected unit, output
* is the finally selected unit by the user. Can be NULL.
* @param aConvert Pointer to deMorgan conversion. Input is what is pre-selected,
* output is the finally selected deMorgan type by the user.
* @return the component name
* @param aUnit preselected unit
* @param aConvert preselected deMorgan conversion
* @return the selected component
*/
wxString SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
int* aUnit, int* aConvert );
COMPONENT_SELECTION SelectComponentFromLibBrowser(
const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
int aUnit, int aConvert );
/**
* Function OnOpenLibraryViewer

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras wanadoo.fr
* Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2015 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2004-2017 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
@ -1093,17 +1093,15 @@ private:
* to load the component from and/or some other filters
* if NULL, no filtering.
* @param aHistoryList list remembering recently used component names.
* @param aHistoryLastUnit remembering last unit in last component.
* @param aUseLibBrowser is the flag to determine if the library browser should be launched.
* @return a pointer the SCH_COMPONENT object selected or NULL if no component was selected.
* (TODO(hzeller): This really should be a class doing history, but didn't
* want to change too much while other refactoring is going on)
*/
SCH_COMPONENT* Load_Component( wxDC* aDC,
const SCHLIB_FILTER* aFilter,
wxArrayString& aHistoryList,
int& aHistoryLastUnit,
bool aUseLibBrowser );
SCH_COMPONENT* Load_Component( wxDC* aDC,
const SCHLIB_FILTER* aFilter,
SCH_BASE_FRAME::HISTORY_LIST& aHistoryList,
bool aUseLibBrowser );
/**
* Function EditComponent

View File

@ -59,9 +59,9 @@ void LIB_VIEW_FRAME::OnSelectSymbol( wxCommandEvent& aEvent )
dialogTitle.Printf( _( "Choose Component (%d items loaded)" ),
adapter->GetComponentsCount() );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, m_convert );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, m_convert, false );
if( dlg.ShowModal() == wxID_CANCEL )
if( dlg.ShowQuasiModal() == wxID_CANCEL )
return;
/// @todo: The unit selection gets reset to 1 by SetSelectedComponent() so the unit

Some files were not shown because too many files have changed in this diff Show More