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 // 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_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) #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() void LIB_TREE_NODE::ResetScore()
{ {
for( auto& child: Children ) for( auto& child: m_Children )
child->ResetScore(); child->ResetScore();
Score = kLowestDefaultScore; m_Score = kLowestDefaultScore;
} }
@ -64,62 +64,65 @@ void LIB_TREE_NODE::AssignIntrinsicRanks( bool presorted )
if( presorted ) if( presorted )
{ {
int max = Children.size() - 1; int max = m_Children.size() - 1;
for( int i = 0; i <= max; ++i ) for( int i = 0; i <= max; ++i )
Children[i]->IntrinsicRank = max - i; m_Children[i]->m_IntrinsicRank = max - i;
} }
else else
{ {
for( auto const& node: Children ) for( auto const& node: m_Children )
sort_buf.push_back( &*node ); sort_buf.push_back( &*node );
std::sort( sort_buf.begin(), sort_buf.end(), std::sort( sort_buf.begin(), sort_buf.end(),
[]( LIB_TREE_NODE* a, LIB_TREE_NODE* b ) -> bool []( 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 ) 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() 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 ) []( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
{ {
return Compare( *a, *b ) > 0; 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(); node->SortNodes();
} }
int LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2 ) 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; return 0;
if( aNode1.Score != aNode2.Score ) if( aNode1.m_Score != aNode2.m_Score )
return aNode1.Score - aNode2.Score; return aNode1.m_Score - aNode2.m_Score;
if( aNode1.Parent != aNode2.Parent ) if( aNode1.m_Parent != aNode2.m_Parent )
return 0; return 0;
return aNode1.IntrinsicRank - aNode2.IntrinsicRank; return aNode1.m_IntrinsicRank - aNode2.m_IntrinsicRank;
} }
LIB_TREE_NODE::LIB_TREE_NODE() LIB_TREE_NODE::LIB_TREE_NODE()
: Parent( nullptr ), : m_Parent( nullptr ),
Type( INVALID ), m_Type( INVALID ),
IntrinsicRank( 0 ), m_IntrinsicRank( 0 ),
Score( kLowestDefaultScore ), m_Score( kLowestDefaultScore ),
Normalized( false ), m_Pinned( false ),
Unit( 0 ), m_Normalized( false ),
IsRoot( 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(); locale = Pgm().GetLocale();
} }
Parent = aParent; m_Parent = aParent;
Type = UNIT; m_Type = UNIT;
Unit = aUnit; m_Unit = aUnit;
LibId = aParent->LibId; m_LibId = aParent->m_LibId;
Name = namePrefix + " " + aItem->GetUnitReference( aUnit ); m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
Desc = wxEmptyString; m_Desc = wxEmptyString;
MatchName = 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 ) LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem )
{ {
Type = LIBID; m_Type = LIBID;
Parent = aParent; m_Parent = aParent;
LibId.SetLibNickname( aItem->GetLibNickname() ); m_LibId.SetLibNickname( aItem->GetLibNickname() );
LibId.SetLibItemName( aItem->GetName () ); m_LibId.SetLibItemName( aItem->GetName () );
Name = aItem->GetName(); m_Name = aItem->GetName();
Desc = aItem->GetDescription(); m_Desc = aItem->GetDescription();
MatchName = aItem->GetName(); m_MatchName = aItem->GetName();
SearchText = aItem->GetSearchText(); m_SearchText = aItem->GetSearchText();
Normalized = false; m_Normalized = false;
IsRoot = aItem->IsRoot(); m_IsRoot = aItem->IsRoot();
if( aItem->GetUnitCount() > 1 ) 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& 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 ); 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; 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. // 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(); m_SearchText = aItem->GetSearchText();
Normalized = false; m_Normalized = false;
IsRoot = aItem->IsRoot(); m_IsRoot = aItem->IsRoot();
Children.clear(); m_Children.clear();
for( int u = 1; u <= aItem->GetUnitCount(); ++u ) for( int u = 1; u <= aItem->GetUnitCount(); ++u )
AddUnit( aItem, 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 ) 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. return; // Leaf nodes without scores are out of the game.
if( !Normalized ) if( !m_Normalized )
{ {
MatchName = MatchName.Lower(); m_MatchName = m_MatchName.Lower();
SearchText = SearchText.Lower(); m_SearchText = m_SearchText.Lower();
Normalized = true; m_Normalized = true;
} }
// Keywords and description we only count if the match string is at // 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 found_pos = EDA_PATTERN_NOT_FOUND;
int matchers_fired = 0; 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. // 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), // 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 // 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 // For longer terms, we add scores 1..18 for positional match
// (higher in the front, where the keywords are). // (higher in the front, where the keywords are).
Score += matchPosScore( found_pos, 17 ) + 1; m_Score += matchPosScore( found_pos, 17 ) + 1;
} }
} }
else else
{ {
// No match. That's it for this item. // No match. That's it for this item.
Score = 0; m_Score = 0;
} }
// More matchers = better match // 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, LIB_TREE_NODE_LIB::LIB_TREE_NODE_LIB( LIB_TREE_NODE* aParent, wxString const& aName,
wxString const& aDesc ) wxString const& aDesc )
{ {
Type = LIB; m_Type = LIB;
Name = aName; m_Name = aName;
MatchName = aName.Lower(); m_MatchName = aName.Lower();
Desc = aDesc; m_Desc = aDesc;
Parent = aParent; m_Parent = aParent;
LibId.SetLibNickname( aName ); m_LibId.SetLibNickname( aName );
} }
LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddItem( LIB_TREE_ITEM* aItem ) 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 ); 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; return *item;
} }
void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) 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. // 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 ); child->UpdateScore( aMatcher );
Score = std::max( Score, child->Score ); m_Score = std::max( m_Score, child->m_Score );
} }
} }
else else
@ -297,39 +300,39 @@ void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
int found_pos = EDA_PATTERN_NOT_FOUND; int found_pos = EDA_PATTERN_NOT_FOUND;
int matchers_fired = 0; 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. // 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 // More matchers = better match
Score += 2 * matchers_fired; m_Score += 2 * matchers_fired;
} }
} }
LIB_TREE_NODE_ROOT::LIB_TREE_NODE_ROOT() 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_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString const& aDesc )
{ {
LIB_TREE_NODE_LIB* lib = new LIB_TREE_NODE_LIB( this, aName, 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; return *lib;
} }
void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{ {
for( auto& child: Children ) for( auto& child: m_Children )
child->UpdateScore( aMatcher ); child->UpdateScore( aMatcher );
} }

View File

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

View File

@ -27,6 +27,7 @@
#define LIST_COLUMN_WIDTH_KEY wxT( "SelectorColumnWidth" ) #define LIST_COLUMN_WIDTH_KEY wxT( "SelectorColumnWidth" )
#define PINNED_ITEMS_KEY wxT( "PinnedItems" )
static const int kDataViewIndent = 20; 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 * 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; 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 ) ); aChildren.Add( ToItem( &*child ) );
++n; ++n;
@ -91,6 +92,10 @@ LIB_TREE_MODEL_ADAPTER::LIB_TREE_MODEL_ADAPTER()
if( m_config->Read( m_configPrefix + LIST_COLUMN_WIDTH_KEY, &colWidth ) ) if( m_config->Read( m_configPrefix + LIST_COLUMN_WIDTH_KEY, &colWidth ) )
m_colWidths[PART_COL] = 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 ) 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_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 ) for( LIB_TREE_ITEM* item: aItemList )
lib_node.AddItem( item ); lib_node.AddItem( item );
@ -148,6 +169,12 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( wxString const& aSearch )
{ {
m_tree.ResetScore(); m_tree.ResetScore();
for( auto& child: m_tree.m_Children )
{
if( child->m_Pinned )
child->m_Score *= 2;
}
wxStringTokenizer tokenizer( aSearch ); wxStringTokenizer tokenizer( aSearch );
while( tokenizer.HasMoreTokens() ) while( tokenizer.HasMoreTokens() )
@ -267,21 +294,27 @@ LIB_ID LIB_TREE_MODEL_ADAPTER::GetAliasFor( const wxDataViewItem& aSelection ) c
if( !node ) if( !node )
return emptyId; return emptyId;
return node->LibId; return node->m_LibId;
} }
int LIB_TREE_MODEL_ADAPTER::GetUnitFor( const wxDataViewItem& aSelection ) const int LIB_TREE_MODEL_ADAPTER::GetUnitFor( const wxDataViewItem& aSelection ) const
{ {
const LIB_TREE_NODE* node = ToNode( aSelection ); 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 LIB_TREE_NODE::TYPE LIB_TREE_MODEL_ADAPTER::GetTypeFor( const wxDataViewItem& aSelection ) const
{ {
const LIB_TREE_NODE* node = ToNode( aSelection ); 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; int n = 0;
for( const std::unique_ptr<LIB_TREE_NODE>& lib: m_tree.Children ) for( const std::unique_ptr<LIB_TREE_NODE>& lib: m_tree.m_Children )
n += lib->Children.size(); n += lib->m_Children.size();
return n; return n;
} }
@ -298,18 +331,18 @@ int LIB_TREE_MODEL_ADAPTER::GetItemCount() const
wxDataViewItem LIB_TREE_MODEL_ADAPTER::FindItem( const LIB_ID& aLibId ) 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; continue;
// if part name is not specified, return the library node // if part name is not specified, return the library node
if( aLibId.GetLibItemName() == "" ) if( aLibId.GetLibItemName() == "" )
return ToItem( lib.get() ); 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() ); 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 ); auto node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
if( node->Type != LIB_TREE_NODE::TYPE::LIBID if( node->m_Type != LIB_TREE_NODE::TYPE::LIBID
|| ( m_show_units && node->Type == LIB_TREE_NODE::TYPE::LIBID ) ) || ( m_show_units && node->m_Type == LIB_TREE_NODE::TYPE::LIBID ) )
return IntoArray( *node, aChildren ); return IntoArray( *node, aChildren );
else else
return 0; 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 bool LIB_TREE_MODEL_ADAPTER::IsContainer( wxDataViewItem const& aItem ) const
{ {
auto node = ToNode( aItem ); 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 wxDataViewItem LIB_TREE_MODEL_ADAPTER::GetParent( wxDataViewItem const& aItem ) const
{ {
auto node = ToNode( aItem ); 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 // wxDataViewModel has no root node, but rather top-level elements have
// an invalid (null) parent. // 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 ); return ToItem( nullptr );
else else
return ToItem( parent ); return ToItem( parent );
@ -377,10 +410,10 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
{ {
default: // column == -1 is used for default Compare function default: // column == -1 is used for default Compare function
case 0: case 0:
aVariant = node->Name; aVariant = node->m_Name;
break; break;
case 1: case 1:
aVariant = node->Desc; aVariant = node->m_Desc;
break; break;
} }
} }
@ -396,13 +429,13 @@ bool LIB_TREE_MODEL_ADAPTER::GetAttr( wxDataViewItem const& aItem,
auto node = ToNode( aItem ); auto node = ToNode( aItem );
wxASSERT( node ); wxASSERT( node );
if( node->Type != LIB_TREE_NODE::LIBID ) if( node->m_Type != LIB_TREE_NODE::LIBID )
{ {
// Currently only aliases are formatted at all // Currently only aliases are formatted at all
return false; return false;
} }
if( !node->IsRoot && aCol == 0 ) if( !node->m_IsRoot && aCol == 0 )
{ {
// Names of non-root aliases are italicized // Names of non-root aliases are italicized
aAttr.SetItalic( true ); 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, std::function<bool( LIB_TREE_NODE const* )> aFunc,
LIB_TREE_NODE** aHighScore ) LIB_TREE_NODE** aHighScore )
{ {
for( auto& node: aNode.Children ) for( auto& node: aNode.m_Children )
{ {
if( aFunc( &*node ) ) if( aFunc( &*node ) )
{ {
auto item = wxDataViewItem( &*node ); auto item = wxDataViewItem( &*node );
m_widget->ExpandAncestors( item ); m_widget->ExpandAncestors( item );
if( !(*aHighScore) || node->Score > (*aHighScore)->Score ) if( !(*aHighScore) || node->m_Score > (*aHighScore)->m_Score )
(*aHighScore) = &*node; (*aHighScore) = &*node;
} }
@ -443,7 +476,7 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowResults()
[]( LIB_TREE_NODE const* n ) []( LIB_TREE_NODE const* n )
{ {
// return leaf nodes with some level of matching // 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 ); &highScore );
@ -461,10 +494,10 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowPreselect()
FindAndExpand( m_tree, FindAndExpand( m_tree,
[&]( LIB_TREE_NODE const* n ) [&]( LIB_TREE_NODE const* n )
{ {
if( n->Type == LIB_TREE_NODE::LIBID && ( n->Children.empty() || !m_preselect_unit ) ) if( n->m_Type == LIB_TREE_NODE::LIBID && ( n->m_Children.empty() || !m_preselect_unit ) )
return m_preselect_lib_id == n->LibId; return m_preselect_lib_id == n->m_LibId;
else if( n->Type == LIB_TREE_NODE::UNIT && m_preselect_unit ) else if( n->m_Type == LIB_TREE_NODE::UNIT && m_preselect_unit )
return m_preselect_lib_id == n->Parent->LibId && m_preselect_unit == n->Unit; return m_preselect_lib_id == n->m_Parent->m_LibId && m_preselect_unit == n->m_Unit;
else else
return false; return false;
}, },
@ -481,8 +514,8 @@ LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowSingleLibrary()
FindAndExpand( m_tree, FindAndExpand( m_tree,
[]( LIB_TREE_NODE const* n ) []( LIB_TREE_NODE const* n )
{ {
return n->Type == LIB_TREE_NODE::TYPE::LIBID && return n->m_Type == LIB_TREE_NODE::TYPE::LIBID &&
n->Parent->Parent->Children.size() == 1; n->m_Parent->m_Parent->m_Children.size() == 1;
}, },
&highScore ); &highScore );

View File

@ -29,6 +29,7 @@
#include <wx/headerctrl.h> #include <wx/headerctrl.h>
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <set>
/** /**
* Adapter class in the component selector Model-View-Adapter (mediated MVC) * Adapter class in the component selector Model-View-Adapter (mediated MVC)
@ -129,6 +130,7 @@ public:
* valid. * valid.
*/ */
void SaveColWidths(); void SaveColWidths();
void SavePinnedItems();
/** /**
* Set the component filter type. Must be set before adding libraries * 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::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; }; virtual wxString GenerateInfo( LIB_ID const& aLibId, int aUnit ) { return wxEmptyString; };
/** /**
@ -234,7 +238,7 @@ public:
*/ */
virtual int GetLibrariesCount() const virtual int GetLibrariesCount() const
{ {
return m_tree.Children.size(); return m_tree.m_Children.size();
} }
/** /**
@ -265,7 +269,7 @@ public:
protected: protected:
static wxDataViewItem ToItem( LIB_TREE_NODE const* aNode ); 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 ); static unsigned int IntoArray( LIB_TREE_NODE const& aNode, wxDataViewItemArray& aChildren );
LIB_TREE_NODE_ROOT m_tree; LIB_TREE_NODE_ROOT m_tree;
@ -343,6 +347,8 @@ private:
wxConfigBase* m_config; wxConfigBase* m_config;
wxString m_configPrefix; wxString m_configPrefix;
std::set<UTF8> m_pinnedLibIDs;
/** /**
* Find any results worth highlighting and expand them, according to given * Find any results worth highlighting and expand them, according to given
* criteria (f(CMP_TREE_NODE const*) -> bool) * 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", TOOL_ACTION ACTIONS::cursorClick( "common.Control.cursorClick",
AS_GLOBAL, AS_GLOBAL,
WXK_RETURN, LEGACY_HK_NAME( "Mouse Left Click" ), 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 ); nullptr, AF_NONE, (void*) CURSOR_CLICK );
TOOL_ACTION ACTIONS::cursorDblClick( "common.Control.cursorDblClick", TOOL_ACTION ACTIONS::cursorDblClick( "common.Control.cursorDblClick",
AS_GLOBAL, AS_GLOBAL,
WXK_END, LEGACY_HK_NAME( "Mouse Left Double Click" ), 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 ); nullptr, AF_NONE, (void*) CURSOR_DBL_CLICK );
TOOL_ACTION ACTIONS::refreshPreview( "common.Control.refreshPreview", TOOL_ACTION ACTIONS::refreshPreview( "common.Control.refreshPreview",
AS_GLOBAL ); 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", TOOL_ACTION ACTIONS::panUp( "common.Control.panUp",
AS_GLOBAL, AS_GLOBAL,
MD_SHIFT + WXK_UP, "", MD_SHIFT + WXK_UP, "",

View File

@ -139,6 +139,8 @@ LIB_TREE::~LIB_TREE()
{ {
// Save the column widths to the config file // Save the column widths to the config file
m_adapter->SaveColWidths(); 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 ) void LIB_TREE::SelectLibId( const LIB_ID& aLibId )
{ {
selectIfValid( m_adapter->FindItem( aLibId ) ); selectIfValid( m_adapter->FindItem( aLibId ) );

View File

@ -71,6 +71,8 @@ public:
*/ */
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const; LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
LIB_TREE_NODE* GetCurrentTreeNode() const;
/** /**
* Select an item in the tree widget. * Select an item in the tree widget.
*/ */
@ -136,6 +138,7 @@ protected:
{ {
///> List of expanded nodes ///> List of expanded nodes
std::vector<wxDataViewItem> expanded; std::vector<wxDataViewItem> expanded;
std::vector<wxString> pinned;
///> Current selection, might be not valid if nothing was selected ///> Current selection, might be not valid if nothing was selected
LIB_ID selection; 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 wxString LIB_EDIT_FRAME::getTargetLib() const
{ {
return getTargetLibId().GetLibNickname(); return getTargetLibId().GetLibNickname();
@ -583,7 +589,7 @@ void LIB_EDIT_FRAME::SyncLibraries( bool aShowProgress )
m_treePane->GetLibTree()->Unselect(); 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 // Try to select the parent library, in case the part is not found
if( !found && selected.IsValid() ) 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 ) SYMBOL_LIB_TABLE* LIB_EDIT_FRAME::selectSymLibTable( bool aOptional )
{ {
wxArrayString libTableNames; wxArrayString libTableNames;

View File

@ -40,6 +40,7 @@ class LIB_PART;
class LIB_FIELD; class LIB_FIELD;
class DIALOG_LIB_EDIT_TEXT; class DIALOG_LIB_EDIT_TEXT;
class SYMBOL_TREE_PANE; class SYMBOL_TREE_PANE;
class LIB_TREE_NODE;
class LIB_ID; class LIB_ID;
class LIB_MANAGER; class LIB_MANAGER;
@ -146,6 +147,8 @@ public:
/** Sets the current library nickname and returns the old library nickname. */ /** Sets the current library nickname and returns the old library nickname. */
wxString SetCurLib( const wxString& aLibNickname ); wxString SetCurLib( const wxString& aLibNickname );
LIB_TREE_NODE* GetCurrentTreeNode() const;
/** /**
* Return the LIB_ID of the library or symbol selected in the symbol tree. * Return the LIB_ID of the library or symbol selected in the symbol tree.
*/ */
@ -417,6 +420,12 @@ public:
*/ */
void SyncLibraries( bool aShowProgress ); 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. * 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() ) if( m_path.IsEmpty() )
m_path = aKiway->Prj().GetProjectPath(); m_path = aKiway->Prj().GetProjectPath();
wxLogTrace( traceSchLegacyPlugin, "Normalized append path \"%s\".", m_path ); wxLogTrace( traceSchLegacyPlugin, "m_Normalized append path \"%s\".", m_path );
} }
else else
{ {

View File

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

View File

@ -30,6 +30,7 @@
#include <tools/lib_control.h> #include <tools/lib_control.h>
#include <lib_edit_frame.h> #include <lib_edit_frame.h>
#include <lib_view_frame.h> #include <lib_view_frame.h>
#include <symbol_tree_model_adapter.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <gestfich.h> #include <gestfich.h>
#include <project.h> #include <project.h>
@ -51,11 +52,23 @@ bool LIB_CONTROL::Init()
LIB_ID sel = editFrame->GetTreeLIBID(); LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty(); 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 ) { auto symbolSelectedCondition = [ editFrame ] ( const SELECTION& aSel ) {
LIB_ID sel = editFrame->GetTreeLIBID(); LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty(); 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::newLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::save, libSelectedCondition ); 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 ) int LIB_CONTROL::ShowComponentTree( const TOOL_EVENT& aEvent )
{ {
if( m_frame->IsType( FRAME_SCH_LIB_EDITOR ) ) 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::OnDeMorgan, EE_ACTIONS::showDeMorganAlternate.MakeEvent() );
Go( &LIB_CONTROL::ShowElectricalTypes, EE_ACTIONS::showElectricalTypes.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::ShowComponentTree, EE_ACTIONS::showComponentTree.MakeEvent() );
Go( &LIB_CONTROL::ToggleSyncedPinsMode, EE_ACTIONS::toggleSyncedPinsMode.MakeEvent() ); Go( &LIB_CONTROL::ToggleSyncedPinsMode, EE_ACTIONS::toggleSyncedPinsMode.MakeEvent() );
} }

View File

@ -65,6 +65,8 @@ public:
int OnDeMorgan( const TOOL_EVENT& aEvent ); int OnDeMorgan( const TOOL_EVENT& aEvent );
int ShowElectricalTypes( 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 ShowComponentTree( const TOOL_EVENT& aEvent );
int ToggleSyncedPinsMode( 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 ) void SYMBOL_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent )
{ {
m_libEditFrame->GetToolManager()->RunAction( EE_ACTIONS::editSymbol, true ); m_libEditFrame->GetToolManager()->RunAction( EE_ACTIONS::editSymbol, true );

View File

@ -48,9 +48,6 @@ public:
return m_tree; return m_tree;
} }
///> Updates the component tree
void Regenerate();
protected: protected:
void onComponentSelected( wxCommandEvent& aEvent ); 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 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 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. * @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. * path could not be normalized.
*/ */
wxString NormalizePath( const wxFileName& aFilePath, const ENV_VAR_MAP* aEnvVars, 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 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 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. * @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. * path could not be normalized.
*/ */
wxString NormalizePath( wxString NormalizePath(

View File

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

View File

@ -649,7 +649,7 @@ int AR_AUTOPLACER::getOptimalModulePlacement(MODULE* aModule)
fpBBox.SetOrigin( fpBBoxOrg + m_curPosition ); fpBBox.SetOrigin( fpBBoxOrg + m_curPosition );
min_cost = -1.0; 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 ) 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; LastPosOK = m_curPosition;
min_cost = Score; min_cost = Score;
wxString msg; wxString msg;
/* msg.Printf( wxT( "Score %g, pos %s, %s" ), /* msg.Printf( wxT( "m_Score %g, pos %s, %s" ),
min_cost, min_cost,
GetChars( ::CoordinateToString( LastPosOK.x ) ), GetChars( ::CoordinateToString( LastPosOK.x ) ),
GetChars( ::CoordinateToString( LastPosOK.y ) ) ); 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 FOOTPRINT_EDIT_FRAME::GetTargetFPID() const
{ {
LIB_ID id = GetTreeFPID(); LIB_ID id = GetTreeFPID();
@ -715,7 +721,7 @@ void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( bool aProgress )
adapter->Sync(); adapter->Sync();
m_treePane->GetLibTree()->Unselect(); m_treePane->GetLibTree()->Unselect();
m_treePane->Regenerate(); m_treePane->GetLibTree()->Regenerate( true );
if( target.IsValid() ) 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 ) void FOOTPRINT_EDIT_FRAME::FocusOnLibID( const LIB_ID& aLibID )
{ {
m_treePane->GetLibTree()->SelectLibId( 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. /// Return the LIB_ID of the part or library selected in the footprint tree.
LIB_ID GetTreeFPID() const; LIB_ID GetTreeFPID() const;
LIB_TREE_NODE* GetCurrentTreeNode() const;
/// Return the LIB_ID of the part being edited. /// Return the LIB_ID of the part being edited.
LIB_ID GetLoadedFPID() const; LIB_ID GetLoadedFPID() const;
@ -215,11 +217,6 @@ public:
/// there is no selection in the tree. /// there is no selection in the tree.
LIB_ID GetTargetFPID() const; LIB_ID GetTargetFPID() const;
/**
* Perform a geometric transform on the current footprint.
*/
void Transform( MODULE* module, int transform );
// importing / exporting Footprint // importing / exporting Footprint
/** /**
* Create a file containing only one footprint. * Create a file containing only one footprint.
@ -339,6 +336,13 @@ public:
* @param aProgress * @param aProgress
*/ */
void SyncLibraryTree( bool 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 FocusOnLibID( const LIB_ID& aLibID );
void KiwayMailIn( KIWAY_EXPRESS& mail ) override; 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 ) void FOOTPRINT_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent )
{ {
m_frame->LoadModuleFromLibrary( GetLibTree()->GetSelectedLibId() ); m_frame->LoadModuleFromLibrary( GetLibTree()->GetSelectedLibId() );

View File

@ -47,9 +47,6 @@ public:
return m_tree; return m_tree;
} }
///> Updates the footprint tree
void Regenerate();
protected: protected:
void onComponentSelected( wxCommandEvent& aEvent ); void onComponentSelected( wxCommandEvent& aEvent );
void onUpdateUI( wxUpdateUIEvent& 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 bool FP_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
{ {
const LIB_TREE_NODE* node = ToNode( aItem ); 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() void FP_TREE_SYNCHRONIZING_ADAPTER::Sync()
{ {
// Process already stored libraries // 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 ) ) 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 ) 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 // 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 // Since the list is sorted we can use a binary search to speed up searches within
// libraries with lots of footprints. // 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, auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
[]( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b ) []( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
{ {
@ -132,7 +132,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
else else
{ {
// node does not exist in the library manager, remove the corresponding node // 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.AddItem( footprint );
aLibNode.AssignIntrinsicRanks(); 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::PTR_VECTOR::iterator& aLibNodeIt )
{ {
LIB_TREE_NODE* node = aLibNodeIt->get(); LIB_TREE_NODE* node = aLibNodeIt->get();
m_libMap.erase( node->Name ); m_libMap.erase( node->m_Name );
auto it = m_tree.Children.erase( aLibNodeIt ); auto it = m_tree.m_Children.erase( aLibNodeIt );
return it; return it;
} }
@ -169,7 +169,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
switch( aCol ) switch( aCol )
{ {
case 0: 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(); auto mod = m_frame->GetBoard()->GetFirstModule();
@ -183,16 +183,18 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
else else
aVariant = currentFPName; aVariant = currentFPName;
} }
else if( node->m_Pinned )
aVariant = "" + node->m_Name;
else else
aVariant = node->Name; aVariant = node->m_Name;
break; break;
case 1: case 1:
aVariant = node->Desc; aVariant = node->m_Desc;
break; break;
default: // column == -1 is used for default Compare function default: // column == -1 is used for default Compare function
aVariant = node->Name; aVariant = node->m_Name;
break; break;
} }
} }
@ -215,10 +217,10 @@ bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsign
auto node = ToNode( aItem ); auto node = ToNode( aItem );
wxCHECK( node, false ); wxCHECK( node, false );
switch( node->Type ) switch( node->m_Type )
{ {
case LIB_TREE_NODE::LIB: case LIB_TREE_NODE::LIB:
if( node->Name == m_frame->GetLoadedFPID().GetLibNickname() ) if( node->m_Name == m_frame->GetLoadedFPID().GetLibNickname() )
{ {
#ifdef __WXGTK__ #ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour // 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; break;
case LIB_TREE_NODE::LIBID: case LIB_TREE_NODE::LIBID:
if( node->LibId == m_frame->GetLoadedFPID() ) if( node->m_LibId == m_frame->GetLoadedFPID() )
{ {
#ifdef __WXGTK__ #ifdef __WXGTK__
// The native wxGTK+ impl ignores background colour, so set the text colour // 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(); LIB_ID sel = m_frame->GetTreeFPID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty(); 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 ) { auto fpSelectedCondition = [ this ] ( const SELECTION& aSel ) {
LIB_ID sel = m_frame->GetTreeFPID(); LIB_ID sel = m_frame->GetTreeFPID();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty(); 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::newLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways ); ctxMenu.AddItem( ACTIONS::addLibrary, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( ACTIONS::save, libSelectedCondition ); 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 ) int MODULE_EDITOR_TOOLS::ToggleFootprintTree( const TOOL_EVENT& aEvent )
{ {
m_frame->ToggleSearchTree(); 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::ImportFootprint, PCB_ACTIONS::importFootprint.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::ExportFootprint, PCB_ACTIONS::exportFootprint.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::ToggleFootprintTree, PCB_ACTIONS::toggleFootprintTree.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::Properties, PCB_ACTIONS::footprintProperties.MakeEvent() ); Go( &MODULE_EDITOR_TOOLS::Properties, PCB_ACTIONS::footprintProperties.MakeEvent() );
Go( &MODULE_EDITOR_TOOLS::DefaultPadProperties, PCB_ACTIONS::defaultPadProperties.MakeEvent() ); Go( &MODULE_EDITOR_TOOLS::DefaultPadProperties, PCB_ACTIONS::defaultPadProperties.MakeEvent() );

View File

@ -61,7 +61,9 @@ public:
int DeleteFootprint( const TOOL_EVENT& aEvent ); int DeleteFootprint( const TOOL_EVENT& aEvent );
int ImportFootprint( const TOOL_EVENT& aEvent ); int ImportFootprint( const TOOL_EVENT& aEvent );
int ExportFootprint( 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 ToggleFootprintTree( const TOOL_EVENT& aEvent );
int Properties( const TOOL_EVENT& aEvent ); int Properties( const TOOL_EVENT& aEvent );