ADDED: Dynamic field columns in symbol chooser

CHANGED: Symbol chooser search now considers custom symbol fields

Visible columns can be controlled in database libraries.
In standard KiCad libraries, we show columns for all custom fields for now.

Customizable column visibility will be added in the future.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11946
This commit is contained in:
Jon Evans 2022-08-28 19:02:12 -04:00
parent 29c2151da5
commit e294fe2074
22 changed files with 410 additions and 61 deletions

View File

@ -175,6 +175,8 @@ LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITE
m_Desc = aItem->GetDescription();
m_Footprint = aItem->GetFootprint();
aItem->GetChooserFields( m_Fields );
m_MatchName = aItem->GetName();
m_SearchText = aItem->GetSearchText();
m_Normalized = false;
@ -206,6 +208,8 @@ void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
m_Desc = aItem->GetDescription();
m_MatchName = aItem->GetName();
aItem->GetChooserFields( m_Fields );
m_SearchText = aItem->GetSearchText();
m_Normalized = false;

View File

@ -74,16 +74,16 @@ LIB_TREE_MODEL_ADAPTER::LIB_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent,
m_show_units( true ),
m_preselect_unit( 0 ),
m_freeze( 0 ),
m_col_part( nullptr ),
m_col_desc( nullptr ),
m_widget( nullptr )
{
// Default column widths
m_colWidths[NAME_COL] = 300;
m_colWidths[DESC_COL] = 2000;
// Default column widths. Do not translate these names.
m_colWidths[ wxT( "Item" ) ] = 300;
m_colWidths[ wxT( "Description" ) ] = 600;
APP_SETTINGS_BASE* cfg = Kiface().KifaceSettings();
m_colWidths[NAME_COL] = cfg->m_LibTree.column_width;
for( const std::pair<const wxString, int>& pair : cfg->m_LibTree.column_widths )
m_colWidths[pair.first] = pair.second;
}
@ -96,7 +96,16 @@ void LIB_TREE_MODEL_ADAPTER::SaveColWidths()
if( m_widget )
{
APP_SETTINGS_BASE* cfg = Kiface().KifaceSettings();
cfg->m_LibTree.column_width = m_widget->GetColumn( NAME_COL )->GetWidth();
cfg->m_LibTree.columns.clear();
cfg->m_LibTree.column_widths.clear();
// TODO(JE) ordering?
for( const std::pair<const wxString, wxDataViewColumn*>& pair : m_colNameMap )
{
cfg->m_LibTree.columns.emplace_back( pair.first );
cfg->m_LibTree.column_widths[pair.first] = pair.second->GetWidth();
}
}
}
@ -236,30 +245,59 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
void LIB_TREE_MODEL_ADAPTER::AttachTo( wxDataViewCtrl* aDataViewCtrl )
{
wxString itemHead = _( "Item" );
wxString descHead = _( "Description" );
// The extent of the text doesn't take into account the space on either side
// in the header, so artificially pad it
wxSize itemHeadMinWidth = KIUI::GetTextSize( itemHead + wxT( "MMM" ), aDataViewCtrl );
wxSize descHeadMinWidth = KIUI::GetTextSize( descHead + wxT( "MMM" ), aDataViewCtrl );
// Ensure the part column is wider than the smallest allowable width
if( m_colWidths[NAME_COL] < itemHeadMinWidth.x )
m_colWidths[NAME_COL] = itemHeadMinWidth.x;
m_widget = aDataViewCtrl;
aDataViewCtrl->SetIndent( kDataViewIndent );
aDataViewCtrl->AssociateModel( this );
aDataViewCtrl->ClearColumns();
m_col_part = aDataViewCtrl->AppendTextColumn( itemHead, NAME_COL, wxDATAVIEW_CELL_INERT,
m_colWidths[NAME_COL] );
m_col_desc = aDataViewCtrl->AppendTextColumn( descHead, DESC_COL, wxDATAVIEW_CELL_INERT,
m_colWidths[DESC_COL] );
// These two columns are always added; other columns may be added by specific libraries.
// Do not use translated names here.
doAddColumn( wxT( "Item" ) );
m_col_part->SetMinWidth( itemHeadMinWidth.x );
m_col_desc->SetMinWidth( descHeadMinWidth.x );
// TODO(JE) make Description optional
doAddColumn( wxT( "Description" ) );
for( auto& it : m_colNameMap )
{
if( !it.second )
doAddColumn( it.first, false );
}
}
wxDataViewColumn* LIB_TREE_MODEL_ADAPTER::doAddColumn( const wxString& aHeader, bool aTranslate )
{
wxString translatedHeader = aTranslate ? wxGetTranslation( aHeader ) : aHeader;
// The extent of the text doesn't take into account the space on either side
// in the header, so artificially pad it
wxSize headerMinWidth = KIUI::GetTextSize( translatedHeader + wxT( "MMM" ), m_widget );
if( !m_colWidths.count( aHeader ) || m_colWidths[aHeader] < headerMinWidth.x )
m_colWidths[aHeader] = headerMinWidth.x;
int index = m_columns.size();
wxDataViewColumn* ret = m_widget->AppendTextColumn( translatedHeader, index,
wxDATAVIEW_CELL_INERT,
m_colWidths[aHeader] );
ret->SetMinWidth( headerMinWidth.x );
m_columns.emplace_back( ret );
m_colNameMap[aHeader] = ret;
m_colIdxMap[m_columns.size() - 1] = aHeader;
return ret;
}
void LIB_TREE_MODEL_ADAPTER::addColumnIfNecessary( const wxString& aHeader )
{
if( m_colNameMap.count( aHeader ) )
return;
// Columns will be created later
m_colNameMap[aHeader] = nullptr;
}
@ -352,19 +390,46 @@ unsigned int LIB_TREE_MODEL_ADAPTER::GetChildren( const wxDataViewItem& aItem,
void LIB_TREE_MODEL_ADAPTER::FinishTreeInitialization()
{
m_col_part->SetWidth( m_colWidths[NAME_COL] );
m_col_desc->SetWidth( m_colWidths[DESC_COL] );
wxDataViewColumn* col = nullptr;
size_t idx = 0;
int totalWidth = 0;
wxString header;
for( ; idx < m_columns.size() - 1; idx++ )
{
col = m_columns[idx];
header = col->GetTitle();
wxASSERT( m_colWidths.count( header ) );
col->SetWidth( m_colWidths[header] );
totalWidth += col->GetWidth();
}
int remainingWidth = m_widget->GetSize().x - totalWidth;
header = m_columns[idx]->GetTitle();
m_columns[idx]->SetWidth( std::max( m_colWidths[header], remainingWidth ) );
}
void LIB_TREE_MODEL_ADAPTER::OnSize( wxSizeEvent& aEvent )
{
// On GTK, this value in not immediately available, so don't
// set it to zero just because we haven't fully initialized
if( m_col_part->GetWidth() > 0 )
m_colWidths[NAME_COL] = m_col_part->GetWidth();
for( auto& it : m_colNameMap )
{
if( it.second == m_columns[0] )
{
// On GTK, this value in not immediately available, so don't
// set it to zero just because we haven't fully initialized
if( it.second->GetWidth() > 0 )
m_colWidths[it.first] = it.second->GetWidth();
m_col_desc->SetWidth( m_colWidths[DESC_COL] );
continue;
}
wxASSERT( m_colWidths.count( it.first ) );
it.second->SetWidth( m_colWidths[it.first] );
}
// Mandatory in any wxSizeEvent handler:
aEvent.Skip();
@ -378,22 +443,40 @@ void LIB_TREE_MODEL_ADAPTER::RefreshTree()
// user's scroll position (which re-attaching or deleting/re-inserting columns does).
static int walk = 1;
int partWidth = m_col_part->GetWidth();
int descWidth = m_col_desc->GetWidth();
std::vector<int> widths;
for( const wxDataViewColumn* col : m_columns )
widths.emplace_back( col->GetWidth() );
wxASSERT( widths.size() );
// Only use the widths read back if they are non-zero.
// GTK returns the displayed width of the column, which is not calculated immediately
if( descWidth > 0 )
if( widths[0] > 0 )
{
m_colWidths[NAME_COL] = partWidth;
m_colWidths[DESC_COL] = descWidth;
size_t i = 0;
for( auto& it : m_colNameMap )
m_colWidths[it.first] = widths[i++];
}
m_colWidths[NAME_COL] += walk;
m_colWidths[DESC_COL] -= walk;
auto colIt = m_colWidths.begin();
colIt->second += walk;
colIt++;
if( colIt != m_colWidths.end() )
colIt->second -= walk;
for( auto& it : m_colNameMap )
{
if( it.second == m_columns[0] )
continue;
wxASSERT( m_colWidths.count( it.first ) );
it.second->SetWidth( m_colWidths[it.first] );
}
m_col_part->SetWidth( m_colWidths[NAME_COL] );
m_col_desc->SetWidth( m_colWidths[DESC_COL] );
walk = -walk;
}
@ -443,13 +526,25 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
switch( aCol )
{
default: // column == -1 is used for default Compare function
case 0:
case NAME_COL:
aVariant = UnescapeString( node->m_Name );
break;
case 1:
case DESC_COL:
aVariant = node->m_Desc;
break;
default:
{
wxCHECK_RET( m_colIdxMap.count( aCol ), wxT( "Invalid column in LIB_TREE_MODEL_ADAPTER" ) );
if( node->m_Fields.count( m_colIdxMap.at( aCol ) ) )
aVariant = node->m_Fields[m_colIdxMap.at( aCol )];
else
aVariant = wxEmptyString;
break;
}
}
}

View File

@ -42,7 +42,6 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
m_appSettingsSchemaVersion( aSchemaVersion )
{
// Make Coverity happy:
m_LibTree.column_width = 300;
m_Graphics.canvas_type = EDA_DRAW_PANEL_GAL::GAL_FALLBACK;
// Build parameters list:
@ -79,8 +78,32 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
m_params.emplace_back( new PARAM<int>( "color_picker.default_tab",
&m_ColorPicker.default_tab, 0 ) );
m_params.emplace_back( new PARAM<int>( "lib_tree.column_width",
&m_LibTree.column_width, 300 ) );
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "lib_tree.column_widths",
[&]() -> nlohmann::json
{
nlohmann::json ret = {};
for( const std::pair<const wxString, int>& pair : m_LibTree.column_widths )
ret[std::string( pair.first.ToUTF8() )] = pair.second;
return ret;
},
[&]( const nlohmann::json& aJson )
{
if( !aJson.is_object() )
return;
m_LibTree.column_widths.clear();
for( const auto& entry : aJson.items() )
{
if( !entry.value().is_number_integer() )
continue;
m_LibTree.column_widths[ entry.key() ] = entry.value().get<int>();
}
},
{} ) );
m_params.emplace_back( new PARAM<bool>( "printing.background",
&m_Printing.background, false ) );
@ -363,3 +386,17 @@ const std::vector<wxString> APP_SETTINGS_BASE::DefaultGridSizeList() const
"0.025 mm",
"0.01 mm" };
}
bool APP_SETTINGS_BASE::migrateLibTreeWidth()
{
// We used to store only the width of the first column, because there were only
// two possible columns.
if( std::optional<int> optWidth = Get<int>( "lib_tree.column_width" ) )
{
Set<nlohmann::json>( "lib_tree.column_widths", { { "Item", *optWidth } } );
At( "lib_tree" ).erase( "column_width" );
}
return true;
}

View File

@ -40,7 +40,7 @@
using namespace T_BOMCFG_T; // for the BOM_CFG_PARSER parser and its keywords
///! Update the schema version whenever a migration is required
const int eeschemaSchemaVersion = 2;
const int eeschemaSchemaVersion = 3;
/// Default value for bom.plugins
const nlohmann::json defaultBomPlugins =
@ -475,6 +475,13 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
return true;
} );
registerMigration( 2, 3,
[&]() -> bool
{
// This is actually a migration for APP_SETTINGS_BASE::m_LibTree
return migrateLibTreeWidth();
} );
}

View File

@ -77,6 +77,7 @@ LIB_FIELD& LIB_FIELD::operator=( const LIB_FIELD& field )
m_autoAdded = field.m_autoAdded;
m_showName = field.m_showName;
m_allowAutoPlace = field.m_allowAutoPlace;
m_showInChooser = field.m_showInChooser;
SetText( field.GetText() );
SetAttributes( field );
@ -105,6 +106,7 @@ void LIB_FIELD::Init( int aId )
m_autoAdded = false;
m_showName = false;
m_allowAutoPlace = true;
m_showInChooser = true;
}
@ -199,6 +201,7 @@ void LIB_FIELD::Copy( LIB_FIELD* aTarget ) const
aTarget->m_name = m_name;
aTarget->m_showName = m_showName;
aTarget->m_allowAutoPlace = m_allowAutoPlace;
aTarget->m_showInChooser = m_showInChooser;
aTarget->CopyText( *this );
aTarget->SetAttributes( *this );

View File

@ -184,6 +184,9 @@ public:
bool CanAutoplace() const { return m_allowAutoPlace; }
void SetCanAutoplace( bool aCanPlace ) { m_allowAutoPlace = aCanPlace; }
bool ShowInChooser() const { return m_showInChooser; }
void SetShowInChooser( bool aShow = true ) { m_showInChooser = aShow; }
private:
/**
@ -223,6 +226,7 @@ private:
bool m_autoAdded; ///< Was this field automatically added to a LIB_SYMBOL?
bool m_showName; ///< Render the field's name in addition to its value
bool m_allowAutoPlace; ///< This field can be autoplaced when converted to a SCH_FIELD
bool m_showInChooser; ///< This field is available as a data column for the chooser
};
#endif // CLASS_LIBENTRY_FIELDS_H

View File

@ -59,10 +59,29 @@ wxString LIB_SYMBOL::GetSearchText()
text += discount + footprint;
}
// TODO(JE) rework this later so we can highlight matches in their column
std::map<wxString, wxString> fields;
GetChooserFields( fields );
for( const auto& it : fields )
text += discount + it.second;
return text;
}
void LIB_SYMBOL::GetChooserFields( std::map<wxString , wxString>& aColumnMap )
{
for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
{
LIB_FIELD* field = static_cast<LIB_FIELD*>( &item );
if( field->ShowInChooser() )
aColumnMap[field->GetName()] = field->EDA_TEXT::GetShownText();
}
}
bool operator<( const LIB_SYMBOL& aItem1, const LIB_SYMBOL& aItem2 )
{
return aItem1.GetName() < aItem2.GetName();

View File

@ -174,7 +174,9 @@ public:
return GetFootprintField().GetText();
}
/**
void GetChooserFields( std::map<wxString , wxString>& aColumnMap ) override;
/**
* For symbols derived from other symbols, IsRoot() indicates no derivation.
*/
bool IsRoot() const override { return m_parent.use_count() == 0; }

View File

@ -462,6 +462,34 @@ public:
*/
virtual void GetSubLibraryNames( std::vector<wxString>& aNames ) {}
/**
* Retrieves a list of (custom) field names that are present on symbols in this library.
* The plugin is responsible for guaranteeing that this list contains the set of unique
* custom field names present on any symbols contained in the library.
*
* The required KiCad fields are not included in this list.
*
* @param aNames will be filled with any custom fields present in this library.
*/
virtual void GetAvailableSymbolFields( std::vector<wxString>& aNames ) {}
/**
* Retrieves a list of (custom) field names that should be shown by default for this library
* in the symbol chooser. This list should be a subset of the result returned by
* GetAvailableSymbolFields().
*
* The preference for which fields to hide and show for a given library is stored on a
* per-library basis in a user's preferences (or in the project local settings for a project-
* local library). The set of fields returned by GetDefaultSymbolFields() will be used if this
* preference is missing.
*
* @param aNames will be filled with the custom field names that should be shown by default
*/
virtual void GetDefaultSymbolFields( std::vector<wxString>& aNames )
{
return GetAvailableSymbolFields( aNames );
}
/**
* Return true if the first line in @a aFileName begins with the expected header.
*

View File

@ -153,6 +153,19 @@ void SCH_DATABASE_PLUGIN::GetSubLibraryNames( std::vector<wxString>& aNames )
}
void SCH_DATABASE_PLUGIN::GetAvailableSymbolFields( std::vector<wxString>& aNames )
{
std::copy( m_customFields.begin(), m_customFields.end(), std::back_inserter( aNames ) );
}
void SCH_DATABASE_PLUGIN::GetDefaultSymbolFields( std::vector<wxString>& aNames )
{
std::copy( m_defaultShownFields.begin(), m_defaultShownFields.end(),
std::back_inserter( aNames ) );
}
bool SCH_DATABASE_PLUGIN::CheckHeader( const wxString& aFileName )
{
// TODO: Implement this sometime; but CheckHeader isn't even called...
@ -352,6 +365,11 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::loadSymbolFromRow( const wxString& aSymbolName,
field->SetNameShown( mapping.show_name );
symbol->AddField( field );
m_customFields.insert( mapping.name );
if( mapping.visible_in_chooser )
m_defaultShownFields.insert( mapping.name );
}
return symbol;

View File

@ -77,6 +77,10 @@ public:
void GetSubLibraryNames( std::vector<wxString>& aNames ) override;
void GetAvailableSymbolFields( std::vector<wxString>& aNames ) override;
void GetDefaultSymbolFields( std::vector<wxString>& aNames ) override;
bool CheckHeader( const wxString& aFileName ) override;
// Database libraries can never be written using the symbol editing API
@ -105,6 +109,10 @@ private:
std::unique_ptr<DATABASE_CONNECTION> m_conn;
std::set<wxString> m_customFields;
std::set<wxString> m_defaultShownFields;
};
#endif //KICAD_SCH_DATABASE_PLUGIN_H

View File

@ -1433,6 +1433,41 @@ bool SCH_SEXPR_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
}
void SCH_SEXPR_PLUGIN::GetAvailableSymbolFields( std::vector<wxString>& aNames )
{
if( !m_cache )
return;
const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols;
std::set<wxString> fieldNames;
for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it )
{
std::vector<LIB_FIELD*> fields;
it->second->GetFields( fields );
for( LIB_FIELD* field : fields )
{
if( field->IsMandatory() )
continue;
// TODO(JE): enable configurability of this outside database libraries?
// if( field->ShowInChooser() )
fieldNames.insert( field->GetName() );
}
}
std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
}
void SCH_SEXPR_PLUGIN::GetDefaultSymbolFields( std::vector<wxString>& aNames )
{
GetAvailableSymbolFields( aNames );
}
LIB_SYMBOL* SCH_SEXPR_PLUGIN::ParseLibSymbol( LINE_READER& aReader, int aFileVersion )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.

View File

@ -133,6 +133,9 @@ public:
bool CheckHeader( const wxString& aFileName ) override;
bool IsSymbolLibWritable( const wxString& aLibraryPath ) override;
void GetAvailableSymbolFields( std::vector<wxString>& aNames ) override;
void GetDefaultSymbolFields( std::vector<wxString>& aNames ) override;
const wxString& GetError() const override { return m_error; }
static LIB_SYMBOL* ParseLibSymbol( LINE_READER& aReader,

View File

@ -29,7 +29,7 @@
///! Update the schema version whenever a migration is required
const int libeditSchemaVersion = 0;
const int libeditSchemaVersion = 1;
SYMBOL_EDITOR_SETTINGS::SYMBOL_EDITOR_SETTINGS() :
@ -81,6 +81,13 @@ SYMBOL_EDITOR_SETTINGS::SYMBOL_EDITOR_SETTINGS() :
m_params.emplace_back( new PARAM<bool>( "use_eeschema_color_settings",
&m_UseEeschemaColorSettings, true ) );
registerMigration( 0, 1,
[&]() -> bool
{
// This is actually a migration for APP_SETTINGS_BASE::m_LibTree
return migrateLibTreeWidth();
} );
}

View File

@ -84,6 +84,24 @@ public:
void GetSubLibraryNames( std::vector<wxString>& aNames ) const;
/**
* @see SCH_PLUGIN::GetAvailableSymbolFields
*/
void GetAvailableSymbolFields( std::vector<wxString>& aNames ) const
{
if( plugin )
plugin->GetAvailableSymbolFields( aNames );
}
/**
* @see SCH_PLUGIN::GetDefaultSymbolFields
*/
void GetDefaultSymbolFields( std::vector<wxString>& aNames ) const
{
if( plugin )
plugin->GetDefaultSymbolFields( aNames );
}
protected:
SYMBOL_LIB_TABLE_ROW( const SYMBOL_LIB_TABLE_ROW& aRow ) :
LIB_TABLE_ROW( aRow ),

View File

@ -136,6 +136,12 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
if( !row->GetIsVisible() )
continue;
std::vector<wxString> additionalColumns;
row->GetAvailableSymbolFields( additionalColumns );
for( const wxString& column : additionalColumns )
addColumnIfNecessary( column );
if( row->SupportsSubLibraries() )
{
std::vector<wxString> subLibraries;
@ -248,6 +254,21 @@ void SYMBOL_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem co
case DESC_COL:
aVariant = node->m_Desc;
break;
default:
{
if( m_colIdxMap.count( aCol ) )
{
const wxString& key = m_colIdxMap.at( aCol );
if( node->m_Fields.count( key ) )
aVariant = node->m_Fields.at( key );
else
aVariant = wxEmptyString;
}
break;
}
}
}

View File

@ -25,6 +25,7 @@
#ifndef LIB_TREE_ITEM_H
#define LIB_TREE_ITEM_H
#include <map>
#include <lib_id.h>
#include <import_export.h>
@ -46,9 +47,14 @@ public:
virtual wxString GetName() const = 0;
virtual wxString GetLibNickname() const = 0;
virtual wxString GetDescription() = 0;
/**
* Retrieves a key/value map of the fields on this item that should be exposed to the library
* browser/chooser for displaying in columns, searching, etc
*/
virtual void GetChooserFields( std::map<wxString , wxString>& aColumnMap ) {}
virtual wxString GetSearchText() { return wxEmptyString; }
/**

View File

@ -23,6 +23,7 @@
#define LIB_TREE_MODEL_H
#include <vector>
#include <map>
#include <memory>
#include <wx/string.h>
#include <lib_tree_item.h>
@ -135,6 +136,8 @@ public:
wxString m_SearchText; // Descriptive text to search
bool m_Normalized; // Support for lazy normalization.
/// @see LIB_TREE_ITEMS::GetChooserFields
std::map<wxString, wxString> m_Fields;
LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name.
int m_Unit; // Actual unit, or zero

View File

@ -30,6 +30,7 @@
#include <vector>
#include <functional>
#include <set>
#include <map>
/**
* Adapter class in the symbol selector Model-View-Adapter (mediated MVC)
@ -123,15 +124,16 @@ public:
};
/**
* This enum defines the order of the columns in the tree view
* This enum defines the order of the default columns in the tree view
*/
enum TREE_COLS
{
NAME_COL = 0, ///< Library or library item name column
DESC_COL, ///< Library or library description column
NUM_COLS ///< The number of tree columns
NUM_COLS ///< The number of default tree columns
};
/**
* Save the column widths to the config file. This requires the tree view to still be
* valid.
@ -179,6 +181,10 @@ public:
const std::vector<LIB_TREE_ITEM*>& aItemList,
bool pinned, bool presorted );
void AddColumn( const wxString& aHeader )
{
doAddColumn( aHeader, false );
}
/**
* Sort the tree and assign ranks after adding libraries.
@ -328,7 +334,7 @@ protected:
*/
wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override;
unsigned int GetColumnCount() const override { return NUM_COLS; }
unsigned int GetColumnCount() const override { return m_columns.size(); }
/**
* Return the type of data stored in the column as indicated by wxVariant::GetType()
@ -389,8 +395,13 @@ private:
*/
LIB_TREE_NODE* ShowSingleLibrary();
wxDataViewColumn* doAddColumn( const wxString& aHeader, bool aTranslate = true );
protected:
LIB_TREE_NODE_ROOT m_tree;
void addColumnIfNecessary( const wxString& aHeader );
LIB_TREE_NODE_ROOT m_tree;
std::map<unsigned, wxString> m_colIdxMap;
private:
[[maybe_unused]] EDA_BASE_FRAME* m_parent;
@ -401,11 +412,11 @@ private:
int m_preselect_unit;
int m_freeze;
wxDataViewColumn* m_col_part;
wxDataViewColumn* m_col_desc;
wxDataViewCtrl* m_widget;
int m_colWidths[NUM_COLS];
std::vector<wxDataViewColumn*> m_columns;
std::map<wxString, wxDataViewColumn*> m_colNameMap;
std::map<wxString, int> m_colWidths;
};
#endif // LIB_TREE_MODEL_ADAPTER_H

View File

@ -127,7 +127,8 @@ public:
struct LIB_TREE
{
int column_width;
std::vector<wxString> columns; ///< Ordered list of visible columns in the tree
std::map<wxString, int> column_widths; ///< Column widths, keyed by header name
};
struct PRINTING
@ -211,6 +212,11 @@ protected:
* @param aJsonPath is the path to read parameters from
*/
void addParamsForWindow( WINDOW_SETTINGS* aWindow, const std::string& aJsonPath );
/**
* Migrates the library tree width setting from a single column (Item) to multi-column
*/
bool migrateLibTreeWidth();
};
#endif

View File

@ -34,7 +34,7 @@
///! Update the schema version whenever a migration is required
const int fpEditSchemaVersion = 1;
const int fpEditSchemaVersion = 2;
FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() :
@ -292,6 +292,13 @@ FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() :
} ) );
registerMigration( 0, 1, std::bind( &FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1, this ) );
registerMigration( 1, 2,
[&]() -> bool
{
// This is actually a migration for APP_SETTINGS_BASE::m_LibTree
return migrateLibTreeWidth();
} );
}

View File

@ -43,7 +43,7 @@
///! Update the schema version whenever a migration is required
const int pcbnewSchemaVersion = 3;
const int pcbnewSchemaVersion = 4;
PCBNEW_SETTINGS::PCBNEW_SETTINGS()
@ -595,6 +595,13 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
return true;
} );
registerMigration( 3, 4,
[&]() -> bool
{
// This is actually a migration for APP_SETTINGS_BASE::m_LibTree
return migrateLibTreeWidth();
} );
}