diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 3d4abf7b18..4f6b8454bf 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -118,6 +118,9 @@ set( KICOMMON_SRCS project/project_file.cpp project/project_local_settings.cpp + # This is basically a settings object, but for the toolbar + tool/ui/toolbar_configuration.cpp + dialogs/dialog_migrate_settings.cpp dialogs/dialog_migrate_settings_base.cpp dialogs/dialog_rc_job.cpp diff --git a/common/settings/settings_manager.cpp b/common/settings/settings_manager.cpp index ece784683d..022f194850 100644 --- a/common/settings/settings_manager.cpp +++ b/common/settings/settings_manager.cpp @@ -822,6 +822,27 @@ wxString SETTINGS_MANAGER::GetColorSettingsPath() } +wxString SETTINGS_MANAGER::GetToolbarSettingsPath() +{ + wxFileName path; + + path.AssignDir( PATHS::GetUserSettingsPath() ); + path.AppendDir( wxS( "toolbars" ) ); + + if( !path.DirExists() ) + { + if( !wxMkdir( path.GetPath() ) ) + { + wxLogTrace( traceSettings, + wxT( "GetToolbarSettingsPath(): Path %s missing and could not be created!" ), + path.GetPath() ); + } + } + + return path.GetPath(); +} + + std::string SETTINGS_MANAGER::GetSettingsVersion() { // CMake computes the major.minor string for us. diff --git a/common/tool/ui/toolbar_configuration.cpp b/common/tool/ui/toolbar_configuration.cpp index 8c57fd4aec..7883d98c7e 100644 --- a/common/tool/ui/toolbar_configuration.cpp +++ b/common/tool/ui/toolbar_configuration.cpp @@ -24,8 +24,126 @@ #include <nlohmann/json.hpp> -#include <action_toolbar.h> -#include <tools/ui/toolbar_configuration.h> +#include <tool/action_toolbar.h> +#include <tool/ui/toolbar_configuration.h> ///! Update the schema version whenever a migration is required const int toolbarSchemaVersion = 1; + + +void to_json( nlohmann::json& aJson, const TOOLBAR_CONFIGURATION& aConfig ) +{ + nlohmann::json groups = nlohmann::json::array(); + + // Serialize the group object + for( const TOOLBAR_GROUP_CONFIG& grp : aConfig.m_toolbarGroups ) + { + nlohmann::json jsGrp = { + { "name", grp.m_groupName } + }; + + nlohmann::json grpItems = nlohmann::json::array(); + + for( const auto& it : grp.m_groupItems ) + grpItems.push_back( it ); + + jsGrp["items"] = grpItems; + + groups.push_back( jsGrp ); + } + + // Serialize the items + nlohmann::json tbItems = nlohmann::json::array(); + + for( const auto& it : aConfig.m_toolbarItems ) + tbItems.push_back( it ); + + aJson = { + { "groups", groups }, + { "items", tbItems } + }; +} + + +void from_json( const nlohmann::json& aJson, TOOLBAR_CONFIGURATION& aConfig ) +{ + if( aJson.empty() ) + return; + + aConfig.m_toolbarItems.clear(); + aConfig.m_toolbarGroups.clear(); + + // Deserialize the groups + if( aJson.contains( "groups" ) && aJson.at( "groups" ).is_array()) + { + for( const nlohmann::json& grp : aJson.at( "groups" ) ) + { + std::string name = ""; + + if( grp.contains( "name" ) ) + name = grp.at( "name" ).get<std::string>(); + + TOOLBAR_GROUP_CONFIG cfg( name ); + + // Deserialize the items + if( grp.contains( "items" ) ) + { + for( const nlohmann::json& it : grp.at( "items" ) ) + { + if( it.is_string() ) + cfg.m_groupItems.push_back( it.get<std::string>() ); + } + } + aConfig.m_toolbarGroups.push_back( cfg ); + } + } + + // Deserialize the items + if( aJson.contains( "items" ) ) + { + for( const nlohmann::json& it : aJson.at( "items" ) ) + { + if( it.is_string() ) + aConfig.m_toolbarItems.push_back( it.get<std::string>() ); + } + } +} + + +TOOLBAR_SETTINGS::TOOLBAR_SETTINGS( const wxString& aFullPath ) : + JSON_SETTINGS( aFullPath, SETTINGS_LOC::NONE, toolbarSchemaVersion ) +{ + m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "toolbars", + [&]() -> nlohmann::json + { + // Serialize the toolbars + nlohmann::json js = nlohmann::json::array(); + + for( const auto& [name, tb] : m_Toolbars ) + { + js.push_back( nlohmann::json( { { "name", name }, + { "contents", tb } } ) ); + } + + return js; + }, + [&]( const nlohmann::json& aObj ) + { + // Deserialize the toolbars + m_Toolbars.clear(); + + if( !aObj.is_array() ) + return; + + for( const auto& entry : aObj ) + { + if( entry.empty() || !entry.is_object() ) + continue; + + m_Toolbars.emplace( + std::make_pair( entry["name"].get<std::string>(), + entry["contents"].get<TOOLBAR_CONFIGURATION>() ) ); + } + }, + nlohmann::json::array() ) ); +} diff --git a/cvpcb/toolbars_cvpcb.cpp b/cvpcb/toolbars_cvpcb.cpp index dd9f373952..45d6924eab 100644 --- a/cvpcb/toolbars_cvpcb.cpp +++ b/cvpcb/toolbars_cvpcb.cpp @@ -27,6 +27,8 @@ #include <tools/cvpcb_actions.h> #include <wx/stattext.h> +#include <settings/settings_manager.h> + std::optional<TOOLBAR_CONFIGURATION> CVPCB_MAINFRAME::DefaultTopMainToolbarConfig() { @@ -104,4 +106,20 @@ void CVPCB_MAINFRAME::configureToolbars() RegisterCustomToolbarControlFactory( "control.CVPCBFilters", _( "Footprint filters" ), _( "Footprint filtering controls" ), footprintFilterFactory ); + + TOOLBAR_SETTINGS tb( "cvpcb-toolbars" ); + + if( m_tbConfigLeft.has_value() ) + tb.m_Toolbars.emplace( "left", m_tbConfigLeft.value() ); + + if( m_tbConfigRight.has_value() ) + tb.m_Toolbars.emplace( "right", m_tbConfigRight.value() ); + + if( m_tbConfigTopAux.has_value() ) + tb.m_Toolbars.emplace( "top_aux", m_tbConfigTopAux.value() ); + + if( m_tbConfigTopMain.has_value() ) + tb.m_Toolbars.emplace( "top_main", m_tbConfigTopMain.value() ); + + tb.SaveToFile( SETTINGS_MANAGER::GetToolbarSettingsPath(), true ); } diff --git a/include/settings/settings_manager.h b/include/settings/settings_manager.h index 7eb03daec3..ea15dd30da 100644 --- a/include/settings/settings_manager.h +++ b/include/settings/settings_manager.h @@ -378,6 +378,12 @@ public: */ static wxString GetColorSettingsPath(); + /** + * Return the path where toolbar configuration files are stored; creating it if missing + * (normally ./toolbars/ under the user settings path). + */ + static wxString GetToolbarSettingsPath(); + /** * Parse the current KiCad build version and extracts the major and minor revision to use * as the name of the settings directory for this KiCad version. diff --git a/include/tool/ui/toolbar_configuration.h b/include/tool/ui/toolbar_configuration.h index d2eb5d3f10..91e2739577 100644 --- a/include/tool/ui/toolbar_configuration.h +++ b/include/tool/ui/toolbar_configuration.h @@ -29,6 +29,7 @@ #include <vector> #include <settings/json_settings.h> +#include <settings/parameters.h> #include <tool/tool_action.h> @@ -64,7 +65,9 @@ public: return m_groupItems; } -private: +public: + // These are public to write the JSON, but are lower-cased to encourage people not to directly + // access them and treat them as private. std::string m_groupName; std::vector<std::string> m_groupItems; }; @@ -135,9 +138,24 @@ public: m_toolbarGroups.clear(); } -private: +public: + // These are public to write the JSON, but are lower-cased to encourage people not to directly + // access them and treat them as private. std::vector<std::string> m_toolbarItems; std::vector<TOOLBAR_GROUP_CONFIG> m_toolbarGroups; }; + +class KICOMMON_API TOOLBAR_SETTINGS : public JSON_SETTINGS +{ +public: + TOOLBAR_SETTINGS( const wxString& aFilename ); + + virtual ~TOOLBAR_SETTINGS() {} + +public: + // The toolbars + std::map<std::string,TOOLBAR_CONFIGURATION> m_Toolbars; +}; + #endif /* TOOLBAR_CONFIGURATION_H_ */ diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index 78fc78ca3f..72e87e6ca3 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -59,6 +59,8 @@ #include <wx/wupdlock.h> #include <wx/combobox.h> +#include <settings/settings_manager.h> + #include "../scripting/python_scripting.h" @@ -451,6 +453,22 @@ void PCB_EDIT_FRAME::configureToolbars() RegisterCustomToolbarControlFactory( "control.PCBPlugin", _( "IPC/Scripting plugins" ), _( "Region to hold the IPC/Scripting action buttons" ), pluginControlFactory ); + + TOOLBAR_SETTINGS tb( "pcbnew-toolbars" ); + + if( m_tbConfigLeft.has_value() ) + tb.m_Toolbars.emplace( "left", m_tbConfigLeft.value() ); + + if( m_tbConfigRight.has_value() ) + tb.m_Toolbars.emplace( "right", m_tbConfigRight.value() ); + + if( m_tbConfigTopAux.has_value() ) + tb.m_Toolbars.emplace( "top_aux", m_tbConfigTopAux.value() ); + + if( m_tbConfigTopMain.has_value() ) + tb.m_Toolbars.emplace( "top_main", m_tbConfigTopMain.value() ); + + tb.SaveToFile( SETTINGS_MANAGER::GetToolbarSettingsPath(), true ); }