diff --git a/common/lib_tree_model.cpp b/common/lib_tree_model.cpp index 6c8f64e4b0..f7691a855b 100644 --- a/common/lib_tree_model.cpp +++ b/common/lib_tree_model.cpp @@ -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; diff --git a/common/lib_tree_model_adapter.cpp b/common/lib_tree_model_adapter.cpp index aa5a0ab19f..265b0b9d38 100644 --- a/common/lib_tree_model_adapter.cpp +++ b/common/lib_tree_model_adapter.cpp @@ -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& 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& 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 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; + } } } diff --git a/common/settings/app_settings.cpp b/common/settings/app_settings.cpp index 5dadb5738f..914564eb32 100644 --- a/common/settings/app_settings.cpp +++ b/common/settings/app_settings.cpp @@ -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( "color_picker.default_tab", &m_ColorPicker.default_tab, 0 ) ); - m_params.emplace_back( new PARAM( "lib_tree.column_width", - &m_LibTree.column_width, 300 ) ); + m_params.emplace_back( new PARAM_LAMBDA( "lib_tree.column_widths", + [&]() -> nlohmann::json + { + nlohmann::json ret = {}; + + for( const std::pair& 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(); + } + }, + {} ) ); m_params.emplace_back( new PARAM( "printing.background", &m_Printing.background, false ) ); @@ -363,3 +386,17 @@ const std::vector 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 optWidth = Get( "lib_tree.column_width" ) ) + { + Set( "lib_tree.column_widths", { { "Item", *optWidth } } ); + At( "lib_tree" ).erase( "column_width" ); + } + + return true; +} diff --git a/eeschema/eeschema_settings.cpp b/eeschema/eeschema_settings.cpp index cdecd00d60..a23e7b4bab 100644 --- a/eeschema/eeschema_settings.cpp +++ b/eeschema/eeschema_settings.cpp @@ -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(); + } ); } diff --git a/eeschema/lib_field.cpp b/eeschema/lib_field.cpp index 05a2d0abf3..76eae1c16b 100644 --- a/eeschema/lib_field.cpp +++ b/eeschema/lib_field.cpp @@ -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 ); diff --git a/eeschema/lib_field.h b/eeschema/lib_field.h index ad8e7f1b8f..964d7d4c62 100644 --- a/eeschema/lib_field.h +++ b/eeschema/lib_field.h @@ -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 diff --git a/eeschema/lib_symbol.cpp b/eeschema/lib_symbol.cpp index 270cc464dc..cdfea0c3ff 100644 --- a/eeschema/lib_symbol.cpp +++ b/eeschema/lib_symbol.cpp @@ -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 fields; + GetChooserFields( fields ); + + for( const auto& it : fields ) + text += discount + it.second; + return text; } +void LIB_SYMBOL::GetChooserFields( std::map& aColumnMap ) +{ + for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] ) + { + LIB_FIELD* field = static_cast( &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(); diff --git a/eeschema/lib_symbol.h b/eeschema/lib_symbol.h index eeb23db2c4..a01c2909bf 100644 --- a/eeschema/lib_symbol.h +++ b/eeschema/lib_symbol.h @@ -174,7 +174,9 @@ public: return GetFootprintField().GetText(); } - /** + void GetChooserFields( std::map& aColumnMap ) override; + + /** * For symbols derived from other symbols, IsRoot() indicates no derivation. */ bool IsRoot() const override { return m_parent.use_count() == 0; } diff --git a/eeschema/sch_io_mgr.h b/eeschema/sch_io_mgr.h index a945681ad9..ff5da3b35d 100644 --- a/eeschema/sch_io_mgr.h +++ b/eeschema/sch_io_mgr.h @@ -462,6 +462,34 @@ public: */ virtual void GetSubLibraryNames( std::vector& 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& 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& aNames ) + { + return GetAvailableSymbolFields( aNames ); + } + /** * Return true if the first line in @a aFileName begins with the expected header. * diff --git a/eeschema/sch_plugins/database/sch_database_plugin.cpp b/eeschema/sch_plugins/database/sch_database_plugin.cpp index 339658e05f..1189811951 100644 --- a/eeschema/sch_plugins/database/sch_database_plugin.cpp +++ b/eeschema/sch_plugins/database/sch_database_plugin.cpp @@ -153,6 +153,19 @@ void SCH_DATABASE_PLUGIN::GetSubLibraryNames( std::vector& aNames ) } +void SCH_DATABASE_PLUGIN::GetAvailableSymbolFields( std::vector& aNames ) +{ + std::copy( m_customFields.begin(), m_customFields.end(), std::back_inserter( aNames ) ); +} + + +void SCH_DATABASE_PLUGIN::GetDefaultSymbolFields( std::vector& 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; diff --git a/eeschema/sch_plugins/database/sch_database_plugin.h b/eeschema/sch_plugins/database/sch_database_plugin.h index da16cc0a8d..b542e8dad3 100644 --- a/eeschema/sch_plugins/database/sch_database_plugin.h +++ b/eeschema/sch_plugins/database/sch_database_plugin.h @@ -77,6 +77,10 @@ public: void GetSubLibraryNames( std::vector& aNames ) override; + void GetAvailableSymbolFields( std::vector& aNames ) override; + + void GetDefaultSymbolFields( std::vector& 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 m_conn; + std::set m_customFields; + + std::set m_defaultShownFields; + }; #endif //KICAD_SCH_DATABASE_PLUGIN_H diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp index 2cca1d7570..8535dae5cf 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp +++ b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp @@ -1433,6 +1433,41 @@ bool SCH_SEXPR_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath ) } +void SCH_SEXPR_PLUGIN::GetAvailableSymbolFields( std::vector& aNames ) +{ + if( !m_cache ) + return; + + const LIB_SYMBOL_MAP& symbols = m_cache->m_symbols; + + std::set fieldNames; + + for( LIB_SYMBOL_MAP::const_iterator it = symbols.begin(); it != symbols.end(); ++it ) + { + std::vector 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& aNames ) +{ + GetAvailableSymbolFields( aNames ); +} + + LIB_SYMBOL* SCH_SEXPR_PLUGIN::ParseLibSymbol( LINE_READER& aReader, int aFileVersion ) { LOCALE_IO toggle; // toggles on, then off, the C locale. diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h index bd9ec54071..5b31d92b69 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h +++ b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h @@ -133,6 +133,9 @@ public: bool CheckHeader( const wxString& aFileName ) override; bool IsSymbolLibWritable( const wxString& aLibraryPath ) override; + void GetAvailableSymbolFields( std::vector& aNames ) override; + void GetDefaultSymbolFields( std::vector& aNames ) override; + const wxString& GetError() const override { return m_error; } static LIB_SYMBOL* ParseLibSymbol( LINE_READER& aReader, diff --git a/eeschema/symbol_editor/symbol_editor_settings.cpp b/eeschema/symbol_editor/symbol_editor_settings.cpp index fadfe0305f..a976fc3828 100644 --- a/eeschema/symbol_editor/symbol_editor_settings.cpp +++ b/eeschema/symbol_editor/symbol_editor_settings.cpp @@ -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( "use_eeschema_color_settings", &m_UseEeschemaColorSettings, true ) ); + + registerMigration( 0, 1, + [&]() -> bool + { + // This is actually a migration for APP_SETTINGS_BASE::m_LibTree + return migrateLibTreeWidth(); + } ); } diff --git a/eeschema/symbol_lib_table.h b/eeschema/symbol_lib_table.h index a7a46f2d9b..64df33d81c 100644 --- a/eeschema/symbol_lib_table.h +++ b/eeschema/symbol_lib_table.h @@ -84,6 +84,24 @@ public: void GetSubLibraryNames( std::vector& aNames ) const; + /** + * @see SCH_PLUGIN::GetAvailableSymbolFields + */ + void GetAvailableSymbolFields( std::vector& aNames ) const + { + if( plugin ) + plugin->GetAvailableSymbolFields( aNames ); + } + + /** + * @see SCH_PLUGIN::GetDefaultSymbolFields + */ + void GetDefaultSymbolFields( std::vector& aNames ) const + { + if( plugin ) + plugin->GetDefaultSymbolFields( aNames ); + } + protected: SYMBOL_LIB_TABLE_ROW( const SYMBOL_LIB_TABLE_ROW& aRow ) : LIB_TABLE_ROW( aRow ), diff --git a/eeschema/symbol_tree_model_adapter.cpp b/eeschema/symbol_tree_model_adapter.cpp index 26a68665f2..b558bd83ad 100644 --- a/eeschema/symbol_tree_model_adapter.cpp +++ b/eeschema/symbol_tree_model_adapter.cpp @@ -136,6 +136,12 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector& aNick if( !row->GetIsVisible() ) continue; + std::vector additionalColumns; + row->GetAvailableSymbolFields( additionalColumns ); + + for( const wxString& column : additionalColumns ) + addColumnIfNecessary( column ); + if( row->SupportsSubLibraries() ) { std::vector 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; + } } } diff --git a/include/lib_tree_item.h b/include/lib_tree_item.h index e476a1e85c..58e26f2f5e 100644 --- a/include/lib_tree_item.h +++ b/include/lib_tree_item.h @@ -25,6 +25,7 @@ #ifndef LIB_TREE_ITEM_H #define LIB_TREE_ITEM_H +#include #include #include @@ -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& aColumnMap ) {} + virtual wxString GetSearchText() { return wxEmptyString; } /** diff --git a/include/lib_tree_model.h b/include/lib_tree_model.h index bcb31d328b..fa9be1eff4 100644 --- a/include/lib_tree_model.h +++ b/include/lib_tree_model.h @@ -23,6 +23,7 @@ #define LIB_TREE_MODEL_H #include +#include #include #include #include @@ -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 m_Fields; LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name. int m_Unit; // Actual unit, or zero diff --git a/include/lib_tree_model_adapter.h b/include/lib_tree_model_adapter.h index f436b00010..3efdbb2157 100644 --- a/include/lib_tree_model_adapter.h +++ b/include/lib_tree_model_adapter.h @@ -30,6 +30,7 @@ #include #include #include +#include /** * 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& 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 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 m_columns; + std::map m_colNameMap; + std::map m_colWidths; }; #endif // LIB_TREE_MODEL_ADAPTER_H diff --git a/include/settings/app_settings.h b/include/settings/app_settings.h index 5209d04125..9e087e641b 100644 --- a/include/settings/app_settings.h +++ b/include/settings/app_settings.h @@ -127,7 +127,8 @@ public: struct LIB_TREE { - int column_width; + std::vector columns; ///< Ordered list of visible columns in the tree + std::map 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 diff --git a/pcbnew/footprint_editor_settings.cpp b/pcbnew/footprint_editor_settings.cpp index a306351ff3..fb7f664f15 100644 --- a/pcbnew/footprint_editor_settings.cpp +++ b/pcbnew/footprint_editor_settings.cpp @@ -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(); + } ); } diff --git a/pcbnew/pcbnew_settings.cpp b/pcbnew/pcbnew_settings.cpp index d726c526ba..566c6e9183 100644 --- a/pcbnew/pcbnew_settings.cpp +++ b/pcbnew/pcbnew_settings.cpp @@ -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(); + } ); }