Pinning for library trees in FPEditor and SymbolEditor.

Fixes https://gitlab.com/kicad/code/kicad/issues/2288
This commit is contained in:
Jeff Young 2020-02-07 17:06:24 +00:00
parent f502208211
commit 2017389f2d
26 changed files with 412 additions and 214 deletions

View File

@ -519,7 +519,7 @@ std::string FormatStringToGerber( const wxString& aString )
}
// Netname and Pan num fields cannot be empty in Gerber files
// Normalized names must be used, if any
// m_Normalized names must be used, if any
#define NO_NET_NAME wxT( "N/C" ) // net name of not connected pads (one pad net) (normalized)
#define NO_PAD_NAME wxT( "" ) // pad name of pads without pad name/number (not normalized)

View File

@ -51,10 +51,10 @@ static int matchPosScore(int aPosition, int aMaximum)
void LIB_TREE_NODE::ResetScore()
{
for( auto& child: Children )
for( auto& child: m_Children )
child->ResetScore();
Score = kLowestDefaultScore;
m_Score = kLowestDefaultScore;
}
@ -64,62 +64,65 @@ void LIB_TREE_NODE::AssignIntrinsicRanks( bool presorted )
if( presorted )
{
int max = Children.size() - 1;
int max = m_Children.size() - 1;
for( int i = 0; i <= max; ++i )
Children[i]->IntrinsicRank = max - i;
m_Children[i]->m_IntrinsicRank = max - i;
}
else
{
for( auto const& node: Children )
for( auto const& node: m_Children )
sort_buf.push_back( &*node );
std::sort( sort_buf.begin(), sort_buf.end(),
[]( LIB_TREE_NODE* a, LIB_TREE_NODE* b ) -> bool
{ return StrNumCmp( a->Name, b->Name, true ) > 0; } );
{
return StrNumCmp( a->m_Name, b->m_Name, true ) > 0;
} );
for( int i = 0; i < (int) sort_buf.size(); ++i )
sort_buf[i]->IntrinsicRank = i;
sort_buf[i]->m_IntrinsicRank = i;
}
}
void LIB_TREE_NODE::SortNodes()
{
std::sort( Children.begin(), Children.end(),
std::sort( m_Children.begin(), m_Children.end(),
[]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
{
return Compare( *a, *b ) > 0;
} );
for( std::unique_ptr<LIB_TREE_NODE>& node: Children )
for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
node->SortNodes();
}
int LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2 )
{
if( aNode1.Type != aNode2.Type )
if( aNode1.m_Type != aNode2.m_Type )
return 0;
if( aNode1.Score != aNode2.Score )
return aNode1.Score - aNode2.Score;
if( aNode1.m_Score != aNode2.m_Score )
return aNode1.m_Score - aNode2.m_Score;
if( aNode1.Parent != aNode2.Parent )
if( aNode1.m_Parent != aNode2.m_Parent )
return 0;
return aNode1.IntrinsicRank - aNode2.IntrinsicRank;
return aNode1.m_IntrinsicRank - aNode2.m_IntrinsicRank;
}
LIB_TREE_NODE::LIB_TREE_NODE()
: Parent( nullptr ),
Type( INVALID ),
IntrinsicRank( 0 ),
Score( kLowestDefaultScore ),
Normalized( false ),
Unit( 0 ),
IsRoot( false )
: m_Parent( nullptr ),
m_Type( INVALID ),
m_IntrinsicRank( 0 ),
m_Score( kLowestDefaultScore ),
m_Pinned( false ),
m_Normalized( false ),
m_Unit( 0 ),
m_IsRoot( false )
{}
@ -136,36 +139,36 @@ LIB_TREE_NODE_UNIT::LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* a
locale = Pgm().GetLocale();
}
Parent = aParent;
Type = UNIT;
m_Parent = aParent;
m_Type = UNIT;
Unit = aUnit;
LibId = aParent->LibId;
m_Unit = aUnit;
m_LibId = aParent->m_LibId;
Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
Desc = wxEmptyString;
MatchName = wxEmptyString;
m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
m_Desc = wxEmptyString;
m_MatchName = wxEmptyString;
IntrinsicRank = -aUnit;
m_IntrinsicRank = -aUnit;
}
LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem )
{
Type = LIBID;
Parent = aParent;
m_Type = LIBID;
m_Parent = aParent;
LibId.SetLibNickname( aItem->GetLibNickname() );
LibId.SetLibItemName( aItem->GetName () );
m_LibId.SetLibNickname( aItem->GetLibNickname() );
m_LibId.SetLibItemName( aItem->GetName () );
Name = aItem->GetName();
Desc = aItem->GetDescription();
m_Name = aItem->GetName();
m_Desc = aItem->GetDescription();
MatchName = aItem->GetName();
SearchText = aItem->GetSearchText();
Normalized = false;
m_MatchName = aItem->GetName();
m_SearchText = aItem->GetSearchText();
m_Normalized = false;
IsRoot = aItem->IsRoot();
m_IsRoot = aItem->IsRoot();
if( aItem->GetUnitCount() > 1 )
{
@ -178,7 +181,7 @@ LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITE
LIB_TREE_NODE_UNIT& LIB_TREE_NODE_LIB_ID::AddUnit( LIB_TREE_ITEM* aItem, int aUnit )
{
LIB_TREE_NODE_UNIT* unit = new LIB_TREE_NODE_UNIT( this, aItem, aUnit );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( unit ) );
m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( unit ) );
return *unit;
}
@ -187,15 +190,15 @@ void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
{
// Update is called when the names match, so just update the other fields.
LibId.SetLibNickname( aItem->GetLibId().GetLibNickname() );
m_LibId.SetLibNickname( aItem->GetLibId().GetLibNickname() );
Desc = aItem->GetDescription();
m_Desc = aItem->GetDescription();
SearchText = aItem->GetSearchText();
Normalized = false;
m_SearchText = aItem->GetSearchText();
m_Normalized = false;
IsRoot = aItem->IsRoot();
Children.clear();
m_IsRoot = aItem->IsRoot();
m_Children.clear();
for( int u = 1; u <= aItem->GetUnitCount(); ++u )
AddUnit( aItem, u );
@ -204,14 +207,14 @@ void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{
if( Score <= 0 )
if( m_Score <= 0 )
return; // Leaf nodes without scores are out of the game.
if( !Normalized )
if( !m_Normalized )
{
MatchName = MatchName.Lower();
SearchText = SearchText.Lower();
Normalized = true;
m_MatchName = m_MatchName.Lower();
m_SearchText = m_SearchText.Lower();
m_Normalized = true;
}
// Keywords and description we only count if the match string is at
@ -220,20 +223,20 @@ void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
int found_pos = EDA_PATTERN_NOT_FOUND;
int matchers_fired = 0;
if( aMatcher.GetPattern() == MatchName )
if( aMatcher.GetPattern() == m_MatchName )
{
Score += 1000; // exact match. High score :)
m_Score += 1000; // exact match. High score :)
}
else if( aMatcher.Find( MatchName, matchers_fired, found_pos ) )
else if( aMatcher.Find( m_MatchName, matchers_fired, found_pos ) )
{
// Substring match. The earlier in the string the better.
Score += matchPosScore( found_pos, 20 ) + 20;
m_Score += matchPosScore( found_pos, 20 ) + 20;
}
else if( aMatcher.Find( Parent->MatchName, matchers_fired, found_pos ) )
else if( aMatcher.Find( m_Parent->m_MatchName, matchers_fired, found_pos ) )
{
Score += 19; // parent name matches. score += 19
m_Score += 19; // parent name matches. score += 19
}
else if( aMatcher.Find( SearchText, matchers_fired, found_pos ) )
else if( aMatcher.Find( m_SearchText, matchers_fired, found_pos ) )
{
// If we have a very short search term (like one or two letters),
// we don't want to accumulate scores if they just happen to be in
@ -243,52 +246,52 @@ void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{
// For longer terms, we add scores 1..18 for positional match
// (higher in the front, where the keywords are).
Score += matchPosScore( found_pos, 17 ) + 1;
m_Score += matchPosScore( found_pos, 17 ) + 1;
}
}
else
{
// No match. That's it for this item.
Score = 0;
m_Score = 0;
}
// More matchers = better match
Score += 2 * matchers_fired;
m_Score += 2 * matchers_fired;
}
LIB_TREE_NODE_LIB::LIB_TREE_NODE_LIB( LIB_TREE_NODE* aParent, wxString const& aName,
wxString const& aDesc )
{
Type = LIB;
Name = aName;
MatchName = aName.Lower();
Desc = aDesc;
Parent = aParent;
LibId.SetLibNickname( aName );
m_Type = LIB;
m_Name = aName;
m_MatchName = aName.Lower();
m_Desc = aDesc;
m_Parent = aParent;
m_LibId.SetLibNickname( aName );
}
LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddItem( LIB_TREE_ITEM* aItem )
{
LIB_TREE_NODE_LIB_ID* item = new LIB_TREE_NODE_LIB_ID( this, aItem );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
return *item;
}
void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{
Score = 0;
m_Score = 0;
// We need to score leaf nodes, which are usually (but not always) children.
if( Children.size() )
if( m_Children.size() )
{
for( auto& child: Children )
for( auto& child: m_Children )
{
child->UpdateScore( aMatcher );
Score = std::max( Score, child->Score );
m_Score = std::max( m_Score, child->m_Score );
}
}
else
@ -297,39 +300,39 @@ void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
int found_pos = EDA_PATTERN_NOT_FOUND;
int matchers_fired = 0;
if( aMatcher.GetPattern() == MatchName )
if( aMatcher.GetPattern() == m_MatchName )
{
Score += 1000; // exact match. High score :)
m_Score += 1000; // exact match. High score :)
}
else if( aMatcher.Find( MatchName, matchers_fired, found_pos ) )
else if( aMatcher.Find( m_MatchName, matchers_fired, found_pos ) )
{
// Substring match. The earlier in the string the better.
Score += matchPosScore( found_pos, 20 ) + 20;
m_Score += matchPosScore( found_pos, 20 ) + 20;
}
// More matchers = better match
Score += 2 * matchers_fired;
m_Score += 2 * matchers_fired;
}
}
LIB_TREE_NODE_ROOT::LIB_TREE_NODE_ROOT()
{
Type = ROOT;
m_Type = ROOT;
}
LIB_TREE_NODE_LIB& LIB_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString const& aDesc )
{
LIB_TREE_NODE_LIB* lib = new LIB_TREE_NODE_LIB( this, aName, aDesc );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( lib ) );
m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( lib ) );
return *lib;
}
void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{
for( auto& child: Children )
for( auto& child: m_Children )
child->UpdateScore( aMatcher );
}

View File

@ -62,17 +62,18 @@ class EDA_COMBINED_MATCHER;
* - `Parent` - parent node, or nullptr if root
* - `Children` - vector of unique_ptrs to children
* - `Type` - ROOT, LIB, ALIAS, or UNIT
* - `IntrinsicRank` - cached initial sort order
* - `Score` - score taking into account search terms. Zero means irrelevant and
* - `m_IntrinsicRank` - cached initial sort order
* - `m_Score` - score taking into account search terms. Zero means irrelevant and
* should be hidden.
* - `Name` - name of the library/alias/unit, to be displayed
* - `Desc` - description of the alias, to be displayed
* - `MatchName` - Name, normalized to lowercase for matching
* - `SearchText` - normalized composite of keywords and description
* - `m_MatchName` - Name, normalized to lowercase for matching
* - `m_SearchText` - normalized composite of keywords and description
* - `LibId` - the #LIB_ID this alias or unit is from, or not valid
* - `Unit` - the unit number, or zero for non-units
*/
class LIB_TREE_NODE {
class LIB_TREE_NODE
{
public:
enum TYPE {
ROOT, LIB, LIBID, UNIT, INVALID
@ -80,31 +81,30 @@ public:
typedef std::vector<std::unique_ptr<LIB_TREE_NODE>> PTR_VECTOR;
LIB_TREE_NODE* Parent; ///< Parent node or null
PTR_VECTOR Children; ///< List of child nodes
enum TYPE Type; ///< Node type
LIB_TREE_NODE* m_Parent; // Parent node or null
PTR_VECTOR m_Children; // List of child nodes
enum TYPE m_Type; // Node type
/**
* The rank of the item before any search terms are applied. This is
* a fairly expensive sort (involving string compares) so it helps to
* store the result of that sort.
*/
int IntrinsicRank;
int m_IntrinsicRank;
/// The score of an item resulting from the search algorithm.
int Score;
int m_Score; // The score of an item resulting from the search algorithm.
bool m_Pinned; // Item should appear at top when there is no search string
wxString Name; ///< Actual name of the part
wxString Desc; ///< Description to be displayed
wxString MatchName; ///< Normalized name for matching
wxString SearchText; ///< Descriptive text to search
bool Normalized; ///< Support for lazy normalization.
wxString m_Name; // Actual name of the part
wxString m_Desc; // Description to be displayed
wxString m_MatchName; // Normalized name for matching
wxString m_SearchText; // Descriptive text to search
bool m_Normalized; // Support for lazy normalization.
LIB_ID LibId; ///< LIB_ID determined by the parent library nickname and alias name.
int Unit; ///< Actual unit, or zero
bool IsRoot; ///< Indicates if the symbol is a root symbol instead of an alias.
int VisLen; ///< Length of the string as shown on screen
LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name.
int m_Unit; // Actual unit, or zero
bool m_IsRoot; // Indicates if the symbol is a root symbol instead of an alias.
/**
* Update the score for this part. This is accumulative - it will be
@ -120,7 +120,7 @@ public:
void ResetScore();
/**
* Store intrinsic ranks on all children of this node. See IntrinsicRank
* Store intrinsic ranks on all children of this node. See m_IntrinsicRank
* member doc for more information.
*/
void AssignIntrinsicRanks( bool presorted = false );

View File

@ -27,6 +27,7 @@
#define LIST_COLUMN_WIDTH_KEY wxT( "SelectorColumnWidth" )
#define PINNED_ITEMS_KEY wxT( "PinnedItems" )
static const int kDataViewIndent = 20;
@ -43,9 +44,9 @@ wxDataViewItem LIB_TREE_MODEL_ADAPTER::ToItem( LIB_TREE_NODE const* aNode )
/**
* Convert wxDataViewItem -> CMP_TREE_NODE
*/
LIB_TREE_NODE const* LIB_TREE_MODEL_ADAPTER::ToNode( wxDataViewItem aItem )
LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ToNode( wxDataViewItem aItem )
{
return static_cast<LIB_TREE_NODE const*>( aItem.GetID() );
return static_cast<LIB_TREE_NODE*>( aItem.GetID() );
}
@ -57,9 +58,9 @@ unsigned int LIB_TREE_MODEL_ADAPTER::IntoArray( LIB_TREE_NODE const& aNode,
{
unsigned int n = 0;
for( auto const& child: aNode.Children )
for( auto const& child: aNode.m_Children )
{
if( child->Score > 0 )
if( child->m_Score > 0 )
{
aChildren.Add( ToItem( &*child ) );
++n;
@ -91,6 +92,10 @@ LIB_TREE_MODEL_ADAPTER::LIB_TREE_MODEL_ADAPTER()
if( m_config->Read( m_configPrefix + LIST_COLUMN_WIDTH_KEY, &colWidth ) )
m_colWidths[PART_COL] = colWidth;
// JEY TODO NEW SETTINGS ARCH: read pinned items array....
//for( UFT8 pinnedItem : pinnedItems )
// m_pinnedLibIDs.insert( pinnedItem );
}
@ -111,6 +116,20 @@ void LIB_TREE_MODEL_ADAPTER::SaveColWidths()
}
}
void LIB_TREE_MODEL_ADAPTER::SavePinnedItems()
{
// JEY TODO NEW SETTINGS ARCH: clear pinned items array in settings....
for( auto& child: m_tree.m_Children )
{
if( child->m_Pinned )
{
UTF8 pinnedItem = child->m_LibId.Format();
// JEY TODO NEW SETTINGS ARCH: add pinned entry to settings array....
}
}
}
void LIB_TREE_MODEL_ADAPTER::SetFilter( CMP_FILTER_TYPE aFilter )
{
@ -137,6 +156,8 @@ void LIB_TREE_MODEL_ADAPTER::DoAddLibrary( wxString const& aNodeName, wxString c
{
LIB_TREE_NODE_LIB& lib_node = m_tree.AddLib( aNodeName, aDesc );
lib_node.m_Pinned = m_pinnedLibIDs.count( lib_node.m_LibId.Format() ) > 0;
for( LIB_TREE_ITEM* item: aItemList )
lib_node.AddItem( item );
@ -148,6 +169,12 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( wxString const& aSearch )
{
m_tree.ResetScore();
for( auto& child: m_tree.m_Children )
{
if( child->m_Pinned )
child->m_Score *= 2;
}
wxStringTokenizer tokenizer( aSearch );
while( tokenizer.HasMoreTokens() )
@ -267,21 +294,27 @@ LIB_ID LIB_TREE_MODEL_ADAPTER::GetAliasFor( const wxDataViewItem& aSelection ) c
if( !node )
return emptyId;
return node->LibId;
return node->m_LibId;
}
int LIB_TREE_MODEL_ADAPTER::GetUnitFor( const wxDataViewItem& aSelection ) const
{
const LIB_TREE_NODE* node = ToNode( aSelection );
return node ? node->Unit : 0;
return node ? node->m_Unit : 0;
}
LIB_TREE_NODE::TYPE LIB_TREE_MODEL_ADAPTER::GetTypeFor( const wxDataViewItem& aSelection ) const
{
const LIB_TREE_NODE* node = ToNode( aSelection );
return node ? node->Type : LIB_TREE_NODE::INVALID;
return node ? node->m_Type : LIB_TREE_NODE::INVALID;
}
LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::GetTreeNodeFor( const wxDataViewItem& aSelection ) const
{
return ToNode( aSelection );
}
@ -289,8 +322,8 @@ int LIB_TREE_MODEL_ADAPTER::GetItemCount() const
{
int n = 0;
for( const std::unique_ptr<LIB_TREE_NODE>& lib: m_tree.Children )
n += lib->Children.size();
for( const std::unique_ptr<LIB_TREE_NODE>& lib: m_tree.m_Children )
n += lib->m_Children.size();
return n;
}
@ -298,18 +331,18 @@ int LIB_TREE_MODEL_ADAPTER::GetItemCount() const
wxDataViewItem LIB_TREE_MODEL_ADAPTER::FindItem( const LIB_ID& aLibId )
{
for( auto& lib: m_tree.Children )
for( auto& lib: m_tree.m_Children )
{
if( lib->Name != aLibId.GetLibNickname() )
if( lib->m_Name != aLibId.GetLibNickname() )
continue;
// if part name is not specified, return the library node
if( aLibId.GetLibItemName() == "" )
return ToItem( lib.get() );
for( auto& alias: lib->Children )
for( auto& alias: lib->m_Children )
{
if( alias->Name == aLibId.GetLibItemName() )
if( alias->m_Name == aLibId.GetLibItemName() )
return ToItem( alias.get() );
}
@ -325,8 +358,8 @@ unsigned int LIB_TREE_MODEL_ADAPTER::GetChildren( wxDataViewItem const& aItem,
{
auto node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
if( node->Type != LIB_TREE_NODE::TYPE::LIBID
|| ( m_show_units && node->Type == LIB_TREE_NODE::TYPE::LIBID ) )
if( node->m_Type != LIB_TREE_NODE::TYPE::LIBID
|| ( m_show_units && node->m_Type == LIB_TREE_NODE::TYPE::LIBID ) )
return IntoArray( *node, aChildren );
else
return 0;
@ -342,18 +375,18 @@ bool LIB_TREE_MODEL_ADAPTER::HasContainerColumns( wxDataViewItem const& aItem )
bool LIB_TREE_MODEL_ADAPTER::IsContainer( wxDataViewItem const& aItem ) const
{
auto node = ToNode( aItem );
return node ? node->Children.size() : true;
return node ? node->m_Children.size() : true;
}
wxDataViewItem LIB_TREE_MODEL_ADAPTER::GetParent( wxDataViewItem const& aItem ) const
{
auto node = ToNode( aItem );
auto parent = node ? node->Parent : nullptr;
auto parent = node ? node->m_Parent : nullptr;
// wxDataViewModel has no root node, but rather top-level elements have
// an invalid (null) parent.
if( !node || !parent || parent->Type == LIB_TREE_NODE::TYPE::ROOT )
if( !node || !parent || parent->m_Type == LIB_TREE_NODE::TYPE::ROOT )
return ToItem( nullptr );
else
return ToItem( parent );
@ -377,10 +410,10 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
{
default: // column == -1 is used for default Compare function
case 0:
aVariant = node->Name;
aVariant = node->m_Name;
break;
case 1:
aVariant = node->Desc;
aVariant = node->m_Desc;
break;
}
}
@ -396,13 +429,13 @@ bool LIB_TREE_MODEL_ADAPTER::GetAttr( wxDataViewItem const& aItem,
auto node = ToNode( aItem );
wxASSERT( node );
if( node->Type != LIB_TREE_NODE::LIBID )
if( node->m_Type != LIB_TREE_NODE::LIBID )
{
// Currently only aliases are formatted at all
return false;
}
if( !node->IsRoot && aCol == 0 )
if( !node->m_IsRoot && aCol == 0 )
{
// Names of non-root aliases are italicized
aAttr.SetItalic( true );
@ -419,14 +452,14 @@ void LIB_TREE_MODEL_ADAPTER::FindAndExpand( LIB_TREE_NODE& aNode,
std::function<bool( LIB_TREE_NODE const* )> aFunc,
LIB_TREE_NODE** aHighScore )
{
for( auto& node: aNode.Children )
for( auto& node: aNode.m_Children )
{
if( aFunc( &*node ) )
{
auto item = wxDataViewItem( &*node );
m_widget->ExpandAncestors( item );
if( !(*aHighScore) || node->Score > (*aHighScore)->Score )
if( !(*aHighScore) || node->m_Score > (*aHighScore)->m_Score )
(*aHighScore) = &*node;
}
@ -443,7 +476,7 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowResults()
[]( LIB_TREE_NODE const* n )
{
// return leaf nodes with some level of matching
return n->Type == LIB_TREE_NODE::TYPE::LIBID && n->Score > 1;
return n->m_Type == LIB_TREE_NODE::TYPE::LIBID && n->m_Score > 1;
},
&highScore );
@ -461,10 +494,10 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowPreselect()
FindAndExpand( m_tree,
[&]( LIB_TREE_NODE const* n )
{
if( n->Type == LIB_TREE_NODE::LIBID && ( n->Children.empty() || !m_preselect_unit ) )
return m_preselect_lib_id == n->LibId;
else if( n->Type == LIB_TREE_NODE::UNIT && m_preselect_unit )
return m_preselect_lib_id == n->Parent->LibId && m_preselect_unit == n->Unit;
if( n->m_Type == LIB_TREE_NODE::LIBID && ( n->m_Children.empty() || !m_preselect_unit ) )
return m_preselect_lib_id == n->m_LibId;
else if( n->m_Type == LIB_TREE_NODE::UNIT && m_preselect_unit )
return m_preselect_lib_id == n->m_Parent->m_LibId && m_preselect_unit == n->m_Unit;
else
return false;
},
@ -481,8 +514,8 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowSingleLibrary()
FindAndExpand( m_tree,
[]( LIB_TREE_NODE const* n )
{
return n->Type == LIB_TREE_NODE::TYPE::LIBID &&
n->Parent->Parent->Children.size() == 1;
return n->m_Type == LIB_TREE_NODE::TYPE::LIBID &&
n->m_Parent->m_Parent->m_Children.size() == 1;
},
&highScore );

View File

@ -29,6 +29,7 @@
#include <wx/headerctrl.h>
#include <vector>
#include <functional>
#include <set>
/**
* Adapter class in the component selector Model-View-Adapter (mediated MVC)
@ -129,6 +130,7 @@ public:
* valid.
*/
void SaveColWidths();
void SavePinnedItems();
/**
* Set the component filter type. Must be set before adding libraries
@ -222,6 +224,8 @@ public:
*/
LIB_TREE_NODE::TYPE GetTypeFor( const wxDataViewItem& aSelection ) const;
LIB_TREE_NODE* GetTreeNodeFor( const wxDataViewItem& aSelection ) const;
virtual wxString GenerateInfo( LIB_ID const& aLibId, int aUnit ) { return wxEmptyString; };
/**
@ -234,7 +238,7 @@ public:
*/
virtual int GetLibrariesCount() const
{
return m_tree.Children.size();
return m_tree.m_Children.size();
}
/**
@ -265,7 +269,7 @@ public:
protected:
static wxDataViewItem ToItem( LIB_TREE_NODE const* aNode );
static LIB_TREE_NODE const* ToNode( wxDataViewItem aItem );
static LIB_TREE_NODE* ToNode( wxDataViewItem aItem );
static unsigned int IntoArray( LIB_TREE_NODE const& aNode, wxDataViewItemArray& aChildren );
LIB_TREE_NODE_ROOT m_tree;
@ -343,6 +347,8 @@ private:
wxConfigBase* m_config;
wxString m_configPrefix;
std::set<UTF8> m_pinnedLibIDs;
/**
* Find any results worth highlighting and expand them, according to given
* criteria (f(CMP_TREE_NODE const*) -> bool)

View File

@ -356,18 +356,26 @@ TOOL_ACTION ACTIONS::cursorRightFast( "common.Control.cursorRightFast",
TOOL_ACTION ACTIONS::cursorClick( "common.Control.cursorClick",
AS_GLOBAL,
WXK_RETURN, LEGACY_HK_NAME( "Mouse Left Click" ),
_( "Click" ), "Performs left mouse button click",
_( "Click" ), _( "Performs left mouse button click" ),
nullptr, AF_NONE, (void*) CURSOR_CLICK );
TOOL_ACTION ACTIONS::cursorDblClick( "common.Control.cursorDblClick",
AS_GLOBAL,
WXK_END, LEGACY_HK_NAME( "Mouse Left Double Click" ),
_( "Double-click" ), "Performs left mouse button double-click",
_( "Double-click" ), _( "Performs left mouse button double-click" ),
nullptr, AF_NONE, (void*) CURSOR_DBL_CLICK );
TOOL_ACTION ACTIONS::refreshPreview( "common.Control.refreshPreview",
AS_GLOBAL );
TOOL_ACTION ACTIONS::pinLibrary( "common.Control.pinLibrary",
AS_GLOBAL, 0, "",
_( "Pin Library" ), "Keep the library at the top of the list" );
TOOL_ACTION ACTIONS::unpinLibrary( "common.Control.unpinLibrary",
AS_GLOBAL, 0, "",
_( "Unpin Library" ), "No longer keep the library at the top of the list" );
TOOL_ACTION ACTIONS::panUp( "common.Control.panUp",
AS_GLOBAL,
MD_SHIFT + WXK_UP, "",

View File

@ -139,6 +139,8 @@ LIB_TREE::~LIB_TREE()
{
// Save the column widths to the config file
m_adapter->SaveColWidths();
m_adapter->SavePinnedItems();
}
@ -160,6 +162,17 @@ LIB_ID LIB_TREE::GetSelectedLibId( int* aUnit ) const
}
LIB_TREE_NODE* LIB_TREE::GetCurrentTreeNode() const
{
auto sel = m_tree_ctrl->GetSelection();
if( !sel )
return nullptr;
return m_adapter->GetTreeNodeFor( sel );
}
void LIB_TREE::SelectLibId( const LIB_ID& aLibId )
{
selectIfValid( m_adapter->FindItem( aLibId ) );

View File

@ -71,6 +71,8 @@ public:
*/
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
LIB_TREE_NODE* GetCurrentTreeNode() const;
/**
* Select an item in the tree widget.
*/
@ -136,6 +138,7 @@ protected:
{
///> List of expanded nodes
std::vector<wxDataViewItem> expanded;
std::vector<wxString> pinned;
///> Current selection, might be not valid if nothing was selected
LIB_ID selection;

View File

@ -540,6 +540,12 @@ LIB_ID LIB_EDIT_FRAME::getTargetLibId() const
}
LIB_TREE_NODE* LIB_EDIT_FRAME::GetCurrentTreeNode() const
{
return m_treePane->GetLibTree()->GetCurrentTreeNode();
}
wxString LIB_EDIT_FRAME::getTargetLib() const
{
return getTargetLibId().GetLibNickname();
@ -583,7 +589,7 @@ void LIB_EDIT_FRAME::SyncLibraries( bool aShowProgress )
m_treePane->GetLibTree()->Unselect();
}
m_treePane->Regenerate();
m_treePane->GetLibTree()->Regenerate( true );
// Try to select the parent library, in case the part is not found
if( !found && selected.IsValid() )
@ -605,6 +611,17 @@ void LIB_EDIT_FRAME::SyncLibraries( bool aShowProgress )
}
void LIB_EDIT_FRAME::RegenerateLibraryTree()
{
LIB_ID target = getTargetLibId();
m_treePane->GetLibTree()->Regenerate( true );
if( target.IsValid() )
m_treePane->GetLibTree()->CenterLibId( target );
}
SYMBOL_LIB_TABLE* LIB_EDIT_FRAME::selectSymLibTable( bool aOptional )
{
wxArrayString libTableNames;

View File

@ -40,6 +40,7 @@ class LIB_PART;
class LIB_FIELD;
class DIALOG_LIB_EDIT_TEXT;
class SYMBOL_TREE_PANE;
class LIB_TREE_NODE;
class LIB_ID;
class LIB_MANAGER;
@ -146,6 +147,8 @@ public:
/** Sets the current library nickname and returns the old library nickname. */
wxString SetCurLib( const wxString& aLibNickname );
LIB_TREE_NODE* GetCurrentTreeNode() const;
/**
* Return the LIB_ID of the library or symbol selected in the symbol tree.
*/
@ -417,6 +420,12 @@ public:
*/
void SyncLibraries( bool aShowProgress );
/**
* Filter, sort, and redisplay the library tree. Does NOT synchronize it with libraries
* in disk.
*/
void RegenerateLibraryTree();
/**
* Allows Libedit to install its preferences panel into the preferences dialog.
*/

View File

@ -617,7 +617,7 @@ SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway,
if( m_path.IsEmpty() )
m_path = aKiway->Prj().GetProjectPath();
wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path );
wxLogTrace( traceSchLegacyPlugin, "m_Normalized append path \"%s\".", m_path );
}
else
{

View File

@ -56,7 +56,7 @@ TOOL_INTERACTIVE* SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetContextMenuTool()
bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
{
const LIB_TREE_NODE* node = ToNode( aItem );
return node ? node->Type == LIB_TREE_NODE::LIB : true;
return node ? node->m_Type == LIB_TREE_NODE::LIB : true;
}
@ -76,9 +76,9 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( bool aForce,
int i = 0, max = GetLibrariesCount();
// Process already stored libraries
for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); /* iteration inside */ )
for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); /* iteration inside */ )
{
const wxString& name = it->get()->Name;
const wxString& name = it->get()->m_Name;
if( wxGetUTCTimeMillis() > nextUpdate )
{
@ -142,25 +142,25 @@ int SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetLibrariesCount() const
void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
{
auto hashIt = m_libHashes.find( aLibNode.Name );
auto hashIt = m_libHashes.find( aLibNode.m_Name );
if( hashIt == m_libHashes.end() )
{
// add a new library
for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) )
for( auto alias : m_libMgr->GetAliases( aLibNode.m_Name ) )
aLibNode.AddItem( alias );
}
else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.Name ) )
else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.m_Name ) )
{
// update an existing library
std::list<LIB_PART*> aliases = m_libMgr->GetAliases( aLibNode.Name );
std::list<LIB_PART*> aliases = m_libMgr->GetAliases( aLibNode.m_Name );
// remove the common part from the aliases list
for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); /**/ )
for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); /**/ )
{
auto aliasIt = std::find_if( aliases.begin(), aliases.end(),
[&] ( const LIB_PART* a ) {
return a->GetName() == (*nodeIt)->Name;
return a->GetName() == (*nodeIt)->m_Name;
} );
if( aliasIt != aliases.end() )
@ -174,7 +174,7 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNo
else
{
// node does not exist in the library manager, remove the corresponding node
nodeIt = aLibNode.Children.erase( nodeIt );
nodeIt = aLibNode.m_Children.erase( nodeIt );
}
}
@ -184,7 +184,7 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNo
}
aLibNode.AssignIntrinsicRanks();
m_libHashes[aLibNode.Name] = m_libMgr->GetLibraryHash( aLibNode.Name );
m_libHashes[aLibNode.m_Name] = m_libMgr->GetLibraryHash( aLibNode.m_Name );
}
@ -192,8 +192,8 @@ LIB_TREE_NODE::PTR_VECTOR::iterator SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLib
LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
{
LIB_TREE_NODE* node = aLibNodeIt->get();
m_libHashes.erase( node->Name );
auto it = m_tree.Children.erase( aLibNodeIt );
m_libHashes.erase( node->m_Name );
auto it = m_tree.m_Children.erase( aLibNodeIt );
return it;
}
@ -213,25 +213,28 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataVie
switch( aCol )
{
case 0:
aVariant = node->Name;
aVariant = node->m_Name;
if( node->m_Pinned )
aVariant = "" + node->m_Name;
// mark modified libs with an asterisk
if( node->Type == LIB_TREE_NODE::LIB && m_libMgr->IsLibraryModified( node->Name ) )
aVariant = node->Name + " *";
if( node->m_Type == LIB_TREE_NODE::LIB && m_libMgr->IsLibraryModified( node->m_Name ) )
aVariant = aVariant.GetString() + " *";
// mark modified parts with an aster-ix
if( node->Type == LIB_TREE_NODE::LIBID
&& m_libMgr->IsPartModified( node->Name, node->Parent->Name ) )
aVariant = node->Name + " *";
if( node->m_Type == LIB_TREE_NODE::LIBID
&& m_libMgr->IsPartModified( node->m_Name, node->m_Parent->m_Name ) )
aVariant = aVariant.GetString() + " *";
break;
case 1:
aVariant = node->Desc;
aVariant = node->m_Desc;
break;
default: // column == -1 is used for default Compare function
aVariant = node->Name;
aVariant = node->m_Name;
break;
}
}
@ -250,11 +253,11 @@ bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, un
auto node = ToNode( aItem );
wxCHECK( node, false );
switch( node->Type )
switch( node->m_Type )
{
case LIB_TREE_NODE::LIB:
// mark modified libs with bold font
aAttr.SetBold( m_libMgr->IsLibraryModified( node->Name ) );
aAttr.SetBold( m_libMgr->IsLibraryModified( node->m_Name ) );
#ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour instead.
@ -263,7 +266,7 @@ bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, un
aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
#else
// mark the current library with background color
if( node->Name == m_libMgr->GetCurrentLib() )
if( node->m_Name == m_libMgr->GetCurrentLib() )
{
aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
@ -273,10 +276,10 @@ bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, un
case LIB_TREE_NODE::LIBID:
// mark modified part with bold font
aAttr.SetBold( m_libMgr->IsPartModified( node->Name, node->Parent->Name ) );
aAttr.SetBold( m_libMgr->IsPartModified( node->m_Name, node->m_Parent->m_Name ) );
// mark aliases with italic font
aAttr.SetItalic( !node->IsRoot );
aAttr.SetItalic( !node->m_IsRoot );
#ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour instead.
@ -285,7 +288,7 @@ bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, un
aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
#else
// mark the current part with background color
if( node->LibId == m_libMgr->GetCurrentLibId() )
if( node->m_LibId == m_libMgr->GetCurrentLibId() )
{
aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );

View File

@ -30,6 +30,7 @@
#include <tools/lib_control.h>
#include <lib_edit_frame.h>
#include <lib_view_frame.h>
#include <symbol_tree_model_adapter.h>
#include <wildcards_and_files_ext.h>
#include <gestfich.h>
#include <project.h>
@ -51,11 +52,23 @@ bool LIB_CONTROL::Init()
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
};
auto pinnedLibSelectedCondition = [ editFrame ] ( const SELECTION& aSel ) {
LIB_TREE_NODE* current = editFrame->GetCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::LIB && current->m_Pinned;
};
auto unpinnedLibSelectedCondition = [ editFrame ] (const SELECTION& aSel ) {
LIB_TREE_NODE* current = editFrame->GetCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::LIB && !current->m_Pinned;
};
auto symbolSelectedCondition = [ editFrame ] ( const SELECTION& aSel ) {
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
};
ctxMenu.AddItem( ACTIONS::pinLibrary, unpinnedLibSelectedCondition );
ctxMenu.AddItem( ACTIONS::unpinLibrary, pinnedLibSelectedCondition );
ctxMenu.AddSeparator();
ctxMenu.AddItem( ACTIONS::newLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::save, libSelectedCondition );
@ -220,6 +233,42 @@ int LIB_CONTROL::OnDeMorgan( const TOOL_EVENT& aEvent )
}
int LIB_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
{
if( m_frame->IsType( FRAME_SCH_LIB_EDITOR ) )
{
LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
LIB_TREE_NODE* currentNode = editFrame->GetCurrentTreeNode();
if( currentNode && !currentNode->m_Pinned )
{
currentNode->m_Pinned = true;
editFrame->RegenerateLibraryTree();
}
}
return 0;
}
int LIB_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
{
if( m_frame->IsType( FRAME_SCH_LIB_EDITOR ) )
{
LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame );
LIB_TREE_NODE* currentNode = editFrame->GetCurrentTreeNode();
if( currentNode && currentNode->m_Pinned )
{
currentNode->m_Pinned = false;
editFrame->RegenerateLibraryTree();
}
}
return 0;
}
int LIB_CONTROL::ShowComponentTree( const TOOL_EVENT& aEvent )
{
if( m_frame->IsType( FRAME_SCH_LIB_EDITOR ) )
@ -435,6 +484,8 @@ void LIB_CONTROL::setTransitions()
Go( &LIB_CONTROL::OnDeMorgan, EE_ACTIONS::showDeMorganAlternate.MakeEvent() );
Go( &LIB_CONTROL::ShowElectricalTypes, EE_ACTIONS::showElectricalTypes.MakeEvent() );
Go( &LIB_CONTROL::PinLibrary, ACTIONS::pinLibrary.MakeEvent() );
Go( &LIB_CONTROL::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
Go( &LIB_CONTROL::ShowComponentTree, EE_ACTIONS::showComponentTree.MakeEvent() );
Go( &LIB_CONTROL::ToggleSyncedPinsMode, EE_ACTIONS::toggleSyncedPinsMode.MakeEvent() );
}

View File

@ -65,6 +65,8 @@ public:
int OnDeMorgan( const TOOL_EVENT& aEvent );
int ShowElectricalTypes( const TOOL_EVENT& aEvent );
int PinLibrary( const TOOL_EVENT& aEvent );
int UnpinLibrary( const TOOL_EVENT& aEvent );
int ShowComponentTree( const TOOL_EVENT& aEvent );
int ToggleSyncedPinsMode( const TOOL_EVENT& aEvent );

View File

@ -57,13 +57,6 @@ SYMBOL_TREE_PANE::~SYMBOL_TREE_PANE()
}
void SYMBOL_TREE_PANE::Regenerate()
{
if( m_tree )
m_tree->Regenerate( true );
}
void SYMBOL_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent )
{
m_libEditFrame->GetToolManager()->RunAction( EE_ACTIONS::editSymbol, true );

View File

@ -48,9 +48,6 @@ public:
return m_tree;
}
///> Updates the component tree
void Regenerate();
protected:
void onComponentSelected( wxCommandEvent& aEvent );

View File

@ -33,7 +33,7 @@
* @param aFilePath is the full file path (path and file name) to be normalized.
* @param aEnvVars is an optional map of environmental variables to try substition with.
* @param aProject is an optional project, to normalize the file path to the project path.
* @return Normalized full file path (path and file name) if succeeded or empty string if the
* @return m_Normalized full file path (path and file name) if succeeded or empty string if the
* path could not be normalized.
*/
wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars,
@ -45,7 +45,7 @@ wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars
* @param aFilePath is the full file path (path and file name) to be normalized.
* @param aEnvVars is an optional map of environmental variables to try substition with.
* @param aProjectPath is an optional string to normalize the file path to the project path.
* @return Normalized full file path (path and file name) if succeeded or empty string if the
* @return m_Normalized full file path (path and file name) if succeeded or empty string if the
* path could not be normalized.
*/
wxString NormalizePath(

View File

@ -101,6 +101,9 @@ public:
static TOOL_ACTION refreshPreview; // Similar to a synthetic mouseMoved event, but also
// used after a rotate, mirror, etc.
static TOOL_ACTION pinLibrary;
static TOOL_ACTION unpinLibrary;
/// Cursor control with keyboard
static TOOL_ACTION cursorUp;
static TOOL_ACTION cursorDown;

View File

@ -649,7 +649,7 @@ int AR_AUTOPLACER::getOptimalModulePlacement(MODULE* aModule)
fpBBox.SetOrigin( fpBBoxOrg + m_curPosition );
min_cost = -1.0;
// m_frame->SetStatusText( wxT( "Score ??, pos ??" ) );
// m_frame->SetStatusText( wxT( "m_Score ??, pos ??" ) );
for( ; m_curPosition.x < xylimit.x; m_curPosition.x += m_matrix.m_GridRouting )
@ -675,7 +675,7 @@ int AR_AUTOPLACER::getOptimalModulePlacement(MODULE* aModule)
LastPosOK = m_curPosition;
min_cost = Score;
wxString msg;
/* msg.Printf( wxT( "Score %g, pos %s, %s" ),
/* msg.Printf( wxT( "m_Score %g, pos %s, %s" ),
min_cost,
GetChars( ::CoordinateToString( LastPosOK.x ) ),
GetChars( ::CoordinateToString( LastPosOK.y ) ) );

View File

@ -298,6 +298,12 @@ LIB_ID FOOTPRINT_EDIT_FRAME::GetTreeFPID() const
}
LIB_TREE_NODE* FOOTPRINT_EDIT_FRAME::GetCurrentTreeNode() const
{
return m_treePane->GetLibTree()->GetCurrentTreeNode();
}
LIB_ID FOOTPRINT_EDIT_FRAME::GetTargetFPID() const
{
LIB_ID id = GetTreeFPID();
@ -715,7 +721,7 @@ void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( bool aProgress )
adapter->Sync();
m_treePane->GetLibTree()->Unselect();
m_treePane->Regenerate();
m_treePane->GetLibTree()->Regenerate( true );
if( target.IsValid() )
{
@ -736,6 +742,17 @@ void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( bool aProgress )
}
void FOOTPRINT_EDIT_FRAME::RegenerateLibraryTree()
{
LIB_ID target = GetTargetFPID();
m_treePane->GetLibTree()->Regenerate( true );
if( target.IsValid() )
m_treePane->GetLibTree()->CenterLibId( target );
}
void FOOTPRINT_EDIT_FRAME::FocusOnLibID( const LIB_ID& aLibID )
{
m_treePane->GetLibTree()->SelectLibId( aLibID );

View File

@ -208,6 +208,8 @@ public:
/// Return the LIB_ID of the part or library selected in the footprint tree.
LIB_ID GetTreeFPID() const;
LIB_TREE_NODE* GetCurrentTreeNode() const;
/// Return the LIB_ID of the part being edited.
LIB_ID GetLoadedFPID() const;
@ -215,11 +217,6 @@ public:
/// there is no selection in the tree.
LIB_ID GetTargetFPID() const;
/**
* Perform a geometric transform on the current footprint.
*/
void Transform( MODULE* module, int transform );
// importing / exporting Footprint
/**
* Create a file containing only one footprint.
@ -339,6 +336,13 @@ public:
* @param aProgress
*/
void SyncLibraryTree( bool aProgress );
/**
* Filter, sort, and redisplay the library tree. Does NOT synchronize it with libraries
* in disk.
*/
void RegenerateLibraryTree();
void FocusOnLibID( const LIB_ID& aLibID );
void KiwayMailIn( KIWAY_EXPRESS& mail ) override;

View File

@ -53,13 +53,6 @@ FOOTPRINT_TREE_PANE::~FOOTPRINT_TREE_PANE()
}
void FOOTPRINT_TREE_PANE::Regenerate()
{
if( m_tree )
m_tree->Regenerate( true );
}
void FOOTPRINT_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent )
{
m_frame->LoadModuleFromLibrary( GetLibTree()->GetSelectedLibId() );

View File

@ -47,9 +47,6 @@ public:
return m_tree;
}
///> Updates the footprint tree
void Regenerate();
protected:
void onComponentSelected( wxCommandEvent& aEvent );
void onUpdateUI( wxUpdateUIEvent& aEvent );

View File

@ -57,7 +57,7 @@ TOOL_INTERACTIVE* FP_TREE_SYNCHRONIZING_ADAPTER::GetContextMenuTool()
bool FP_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
{
const LIB_TREE_NODE* node = ToNode( aItem );
return node ? node->Type == LIB_TREE_NODE::LIB : true;
return node ? node->m_Type == LIB_TREE_NODE::LIB : true;
}
@ -66,9 +66,9 @@ bool FP_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) c
void FP_TREE_SYNCHRONIZING_ADAPTER::Sync()
{
// Process already stored libraries
for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); )
for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); )
{
const wxString& name = it->get()->Name;
const wxString& name = it->get()->m_Name;
if( !m_libs->HasLibrary( name, true ) )
{
@ -107,14 +107,14 @@ int FP_TREE_SYNCHRONIZING_ADAPTER::GetLibrariesCount() const
void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
{
std::vector<LIB_TREE_ITEM*> footprints = getFootprints( aLibNode.Name );
std::vector<LIB_TREE_ITEM*> footprints = getFootprints( aLibNode.m_Name );
// remove the common part from the footprints list
for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); )
for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); )
{
// Since the list is sorted we can use a binary search to speed up searches within
// libraries with lots of footprints.
FOOTPRINT_INFO_IMPL dummy( wxEmptyString, (*nodeIt)->Name );
FOOTPRINT_INFO_IMPL dummy( wxEmptyString, (*nodeIt)->m_Name );
auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
[]( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
{
@ -132,7 +132,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
else
{
// node does not exist in the library manager, remove the corresponding node
nodeIt = aLibNode.Children.erase( nodeIt );
nodeIt = aLibNode.m_Children.erase( nodeIt );
}
}
@ -141,7 +141,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
aLibNode.AddItem( footprint );
aLibNode.AssignIntrinsicRanks();
m_libMap.insert( aLibNode.Name );
m_libMap.insert( aLibNode.m_Name );
}
@ -149,8 +149,8 @@ LIB_TREE_NODE::PTR_VECTOR::iterator FP_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary
LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
{
LIB_TREE_NODE* node = aLibNodeIt->get();
m_libMap.erase( node->Name );
auto it = m_tree.Children.erase( aLibNodeIt );
m_libMap.erase( node->m_Name );
auto it = m_tree.m_Children.erase( aLibNodeIt );
return it;
}
@ -169,7 +169,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
switch( aCol )
{
case 0:
if( node->LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
{
auto mod = m_frame->GetBoard()->GetFirstModule();
@ -183,16 +183,18 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
else
aVariant = currentFPName;
}
else if( node->m_Pinned )
aVariant = "" + node->m_Name;
else
aVariant = node->Name;
aVariant = node->m_Name;
break;
case 1:
aVariant = node->Desc;
aVariant = node->m_Desc;
break;
default: // column == -1 is used for default Compare function
aVariant = node->Name;
aVariant = node->m_Name;
break;
}
}
@ -215,10 +217,10 @@ bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsign
auto node = ToNode( aItem );
wxCHECK( node, false );
switch( node->Type )
switch( node->m_Type )
{
case LIB_TREE_NODE::LIB:
if( node->Name == m_frame->GetLoadedFPID().GetLibNickname() )
if( node->m_Name == m_frame->GetLoadedFPID().GetLibNickname() )
{
#ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour
@ -236,7 +238,7 @@ bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsign
break;
case LIB_TREE_NODE::LIBID:
if( node->LibId == m_frame->GetLoadedFPID() )
if( node->m_LibId == m_frame->GetLoadedFPID() )
{
#ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour

View File

@ -82,11 +82,23 @@ bool MODULE_EDITOR_TOOLS::Init()
LIB_ID sel = m_frame->GetTreeFPID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
};
auto pinnedLibSelectedCondition = [ this ] ( const SELECTION& aSel ) {
LIB_TREE_NODE* current = m_frame->GetCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::LIB && current->m_Pinned;
};
auto unpinnedLibSelectedCondition = [ this ] (const SELECTION& aSel ) {
LIB_TREE_NODE* current = m_frame->GetCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::LIB && !current->m_Pinned;
};
auto fpSelectedCondition = [ this ] ( const SELECTION& aSel ) {
LIB_ID sel = m_frame->GetTreeFPID();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
};
ctxMenu.AddItem( ACTIONS::pinLibrary, unpinnedLibSelectedCondition );
ctxMenu.AddItem( ACTIONS::unpinLibrary, pinnedLibSelectedCondition );
ctxMenu.AddSeparator();
ctxMenu.AddItem( ACTIONS::newLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::save, libSelectedCondition );
@ -256,6 +268,34 @@ int MODULE_EDITOR_TOOLS::EditFootprint( const TOOL_EVENT& aEvent )
}
int MODULE_EDITOR_TOOLS::PinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* currentNode = m_frame->GetCurrentTreeNode();
if( currentNode && !currentNode->m_Pinned )
{
currentNode->m_Pinned = true;
m_frame->RegenerateLibraryTree();
}
return 0;
}
int MODULE_EDITOR_TOOLS::UnpinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* currentNode = m_frame->GetCurrentTreeNode();
if( currentNode && currentNode->m_Pinned )
{
currentNode->m_Pinned = false;
m_frame->RegenerateLibraryTree();
}
return 0;
}
int MODULE_EDITOR_TOOLS::ToggleFootprintTree( const TOOL_EVENT& aEvent )
{
m_frame->ToggleSearchTree();
@ -558,6 +598,8 @@ void MODULE_EDITOR_TOOLS::setTransitions()
Go( &MODULE_EDITOR_TOOLS::ImportFootprint, PCB_ACTIONS::importFootprint.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::ExportFootprint, PCB_ACTIONS::exportFootprint.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::PinLibrary, ACTIONS::pinLibrary.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::ToggleFootprintTree, PCB_ACTIONS::toggleFootprintTree.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::Properties, PCB_ACTIONS::footprintProperties.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::DefaultPadProperties, PCB_ACTIONS::defaultPadProperties.MakeEvent() );

View File

@ -61,7 +61,9 @@ public:
int DeleteFootprint( const TOOL_EVENT& aEvent );
int ImportFootprint( const TOOL_EVENT& aEvent );
int ExportFootprint( const TOOL_EVENT& aEvent );
int PinLibrary( const TOOL_EVENT& aEvent );
int UnpinLibrary( const TOOL_EVENT& aEvent );
int ToggleFootprintTree( const TOOL_EVENT& aEvent );
int Properties( const TOOL_EVENT& aEvent );