mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Unlike the old "icon scale" (that actually scaled all bitmaps) this one actually changes the toolbar size while making use of the new bitmap bundle functionality Add more resolutions for all tool icon bitmaps Wouldn't want Mark's eyes to bleed
836 lines
30 KiB
C++
836 lines
30 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
|
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <set>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include <paths.h>
|
|
#include <search_stack.h>
|
|
#include <settings/settings_manager.h>
|
|
#include <settings/common_settings.h>
|
|
#include <settings/json_settings_internals.h>
|
|
#include <settings/parameters.h>
|
|
#include <systemdirsappend.h>
|
|
#include <trace_helpers.h>
|
|
#include <wx/config.h>
|
|
#include <wx/log.h>
|
|
#include <wx/regex.h>
|
|
|
|
|
|
///! The following environment variables will never be migrated from a previous version
|
|
const std::set<wxString> envVarBlacklist =
|
|
{
|
|
wxT( "KICAD7_SYMBOL_DIR" ),
|
|
wxT( "KICAD7_FOOTPRINT_DIR" ),
|
|
wxT( "KICAD7_TEMPLATES_DIR" ),
|
|
wxT( "KICAD7_3DMODEL_DIR" )
|
|
};
|
|
|
|
|
|
///! Update the schema version whenever a migration is required
|
|
const int commonSchemaVersion = 3;
|
|
|
|
COMMON_SETTINGS::COMMON_SETTINGS() :
|
|
JSON_SETTINGS( "kicad_common", SETTINGS_LOC::USER, commonSchemaVersion ),
|
|
m_Appearance(),
|
|
m_Backup(),
|
|
m_Env(),
|
|
m_Input(),
|
|
m_Graphics(),
|
|
m_Session(),
|
|
m_System(),
|
|
m_DoNotShowAgain(),
|
|
m_NetclassPanel(),
|
|
m_PackageManager()
|
|
{
|
|
/*
|
|
* Automatic dark mode detection works fine on Mac.
|
|
*/
|
|
#if defined( __WXGTK__ ) || defined( __WXMSW__ )
|
|
m_params.emplace_back( new PARAM_ENUM<ICON_THEME>( "appearance.icon_theme",
|
|
&m_Appearance.icon_theme, ICON_THEME::AUTO, ICON_THEME::LIGHT, ICON_THEME::AUTO ) );
|
|
#else
|
|
m_Appearance.icon_theme = ICON_THEME::AUTO;
|
|
#endif
|
|
|
|
/*
|
|
* Automatic canvas scaling works fine on all supported platforms, so it's no longer exposed as
|
|
* a configuration option.
|
|
*/
|
|
m_Appearance.canvas_scale = 0.0;
|
|
|
|
/*
|
|
* Menu icons are off by default on OSX and on for all other platforms.
|
|
*/
|
|
#ifdef __WXMAC__
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
|
|
&m_Appearance.use_icons_in_menus, false ) );
|
|
#else
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
|
|
&m_Appearance.use_icons_in_menus, true ) );
|
|
#endif
|
|
|
|
/*
|
|
* Font scaling hacks are only needed on GTK under wxWidgets 3.0.
|
|
*/
|
|
m_Appearance.apply_icon_scale_to_fonts = false;
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.show_scrollbars",
|
|
&m_Appearance.show_scrollbars, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<double>( "appearance.hicontrast_dimming_factor",
|
|
&m_Appearance.hicontrast_dimming_factor, 0.8f ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "appearance.text_editor_zoom",
|
|
&m_Appearance.text_editor_zoom, 0 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "appearance.toolbar_icon_size",
|
|
&m_Appearance.toolbar_icon_size, 24, 16, 64 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "auto_backup.enabled", &m_Backup.enabled, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "auto_backup.backup_on_autosave",
|
|
&m_Backup.backup_on_autosave, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.limit_total_files",
|
|
&m_Backup.limit_total_files, 25 ) );
|
|
|
|
m_params.emplace_back( new PARAM<unsigned long long>( "auto_backup.limit_total_size",
|
|
&m_Backup.limit_total_size, 104857600 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.limit_daily_files",
|
|
&m_Backup.limit_daily_files, 5 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.min_interval",
|
|
&m_Backup.min_interval, 300 ) );
|
|
|
|
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "environment.vars",
|
|
[&]() -> nlohmann::json
|
|
{
|
|
nlohmann::json ret = {};
|
|
|
|
for( const std::pair<wxString, ENV_VAR_ITEM> entry : m_Env.vars )
|
|
{
|
|
const ENV_VAR_ITEM& var = entry.second;
|
|
|
|
wxASSERT( entry.first == var.GetKey() );
|
|
|
|
// Default values are never persisted
|
|
if( var.IsDefault() )
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s skipping save (default)" ),
|
|
var.GetKey() );
|
|
continue;
|
|
}
|
|
|
|
wxString value = var.GetValue();
|
|
|
|
// Vars that existed in JSON are persisted, but if they were overridden
|
|
// externally, we persist the old value (i.e. the one that was loaded from JSON)
|
|
if( var.GetDefinedExternally() )
|
|
{
|
|
if( var.GetDefinedInSettings() )
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s was overridden externally, " )
|
|
"saving previously-loaded value %s",
|
|
var.GetKey(), var.GetSettingsValue() );
|
|
value = var.GetSettingsValue();
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s skipping save (external)" ),
|
|
var.GetKey() );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Saving env var %s = %s" ),
|
|
var.GetKey(), value);
|
|
|
|
std::string key( var.GetKey().ToUTF8() );
|
|
ret[key] = value;
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
[&]( const nlohmann::json& aJson )
|
|
{
|
|
if( !aJson.is_object() )
|
|
return;
|
|
|
|
for( const auto& entry : aJson.items() )
|
|
{
|
|
wxString key = wxString( entry.key().c_str(), wxConvUTF8 );
|
|
wxString val = entry.value().get<wxString>();
|
|
|
|
if( m_Env.vars.count( key ) )
|
|
{
|
|
if( m_Env.vars[key].GetDefinedExternally() )
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: %s is defined externally" ),
|
|
key );
|
|
m_Env.vars[key].SetDefinedInSettings();
|
|
m_Env.vars[key].SetSettingsValue( val );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Updating %s: %s -> %s"),
|
|
key, m_Env.vars[key].GetValue(), val );
|
|
m_Env.vars[key].SetValue( val );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ),
|
|
key, val );
|
|
m_Env.vars[key] = ENV_VAR_ITEM( key, val );
|
|
}
|
|
|
|
m_Env.vars[key].SetDefinedInSettings();
|
|
m_Env.vars[key].SetSettingsValue( val );
|
|
}
|
|
},
|
|
{} ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.focus_follow_sch_pcb",
|
|
&m_Input.focus_follow_sch_pcb, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.auto_pan", &m_Input.auto_pan, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.auto_pan_acceleration",
|
|
&m_Input.auto_pan_acceleration, 5 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.center_on_zoom",
|
|
&m_Input.center_on_zoom, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.immediate_actions",
|
|
&m_Input.immediate_actions, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.warp_mouse_on_move",
|
|
&m_Input.warp_mouse_on_move, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.horizontal_pan",
|
|
&m_Input.horizontal_pan, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.hotkey_feedback",
|
|
&m_Input.hotkey_feedback, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.zoom_acceleration",
|
|
&m_Input.zoom_acceleration, false ) );
|
|
|
|
#ifdef __WXMAC__
|
|
int default_zoom_speed = 5;
|
|
#else
|
|
int default_zoom_speed = 1;
|
|
#endif
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.zoom_speed",
|
|
&m_Input.zoom_speed, default_zoom_speed ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.zoom_speed_auto",
|
|
&m_Input.zoom_speed_auto, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_zoom",
|
|
&m_Input.scroll_modifier_zoom, 0 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_h",
|
|
&m_Input.scroll_modifier_pan_h, WXK_CONTROL ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_v",
|
|
&m_Input.scroll_modifier_pan_v, WXK_SHIFT ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_pan_h",
|
|
&m_Input.reverse_scroll_pan_h, false ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_left",
|
|
&m_Input.drag_left, MOUSE_DRAG_ACTION::DRAG_SELECTED, MOUSE_DRAG_ACTION::DRAG_ANY,
|
|
MOUSE_DRAG_ACTION::SELECT ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_middle",
|
|
&m_Input.drag_middle, MOUSE_DRAG_ACTION::PAN, MOUSE_DRAG_ACTION::SELECT,
|
|
MOUSE_DRAG_ACTION::NONE ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_right",
|
|
&m_Input.drag_right, MOUSE_DRAG_ACTION::PAN, MOUSE_DRAG_ACTION::SELECT,
|
|
MOUSE_DRAG_ACTION::NONE ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "graphics.opengl_antialiasing_mode",
|
|
&m_Graphics.opengl_aa_mode, 1, 0, 2 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "graphics.cairo_antialiasing_mode",
|
|
&m_Graphics.cairo_aa_mode, 0, 0, 2 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.autosave_interval",
|
|
&m_System.autosave_interval, 600 ) );
|
|
|
|
#ifdef __WXMAC__
|
|
m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
|
|
&m_System.text_editor, wxS( "/usr/bin/open -e" ) ) );
|
|
#else
|
|
m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
|
|
&m_System.text_editor, wxS( "" ) ) );
|
|
#endif
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.file_history_size",
|
|
&m_System.file_history_size, 9 ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.language",
|
|
&m_System.language, wxS( "Default" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.pdf_viewer_name",
|
|
&m_System.pdf_viewer_name, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "system.use_system_pdf_viewer",
|
|
&m_System.use_system_pdf_viewer, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.working_dir",
|
|
&m_System.working_dir, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.clear_3d_cache_interval",
|
|
&m_System.clear_3d_cache_interval, 30 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.zone_fill_warning",
|
|
&m_DoNotShowAgain.zone_fill_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.env_var_overwrite_warning",
|
|
&m_DoNotShowAgain.env_var_overwrite_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.scaled_3d_models_warning",
|
|
&m_DoNotShowAgain.scaled_3d_models_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.data_collection_prompt",
|
|
&m_DoNotShowAgain.data_collection_prompt, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "session.remember_open_files",
|
|
&m_Session.remember_open_files, false ) );
|
|
|
|
m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_symbol_libs",
|
|
&m_Session.pinned_symbol_libs, {} ) );
|
|
|
|
m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_fp_libs",
|
|
&m_Session.pinned_fp_libs, {} ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "netclass_panel.sash_pos",
|
|
&m_NetclassPanel.sash_pos, 160 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "package_manager.sash_pos",
|
|
&m_PackageManager.sash_pos, 380 ) );
|
|
|
|
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "git.repositories",
|
|
[&]() -> nlohmann::json
|
|
{
|
|
nlohmann::json ret = {};
|
|
|
|
for( const GIT_REPOSITORY& repo : m_Git.repositories )
|
|
{
|
|
nlohmann::json repoJson = {};
|
|
|
|
repoJson["name"] = repo.name;
|
|
repoJson["path"] = repo.path;
|
|
repoJson["authType"] = repo.authType;
|
|
repoJson["username"] = repo.username;
|
|
repoJson["ssh_path"] = repo.ssh_path;
|
|
repoJson["active"] = repo.active;
|
|
|
|
ret.push_back( repoJson );
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
[&]( const nlohmann::json& aJson )
|
|
{
|
|
if( !aJson.is_array() )
|
|
return;
|
|
|
|
m_Git.repositories.clear();
|
|
|
|
for( const auto& repoJson : aJson )
|
|
{
|
|
GIT_REPOSITORY repo;
|
|
|
|
repo.name = repoJson["name"].get<wxString>();
|
|
repo.path = repoJson["path"].get<wxString>();
|
|
repo.authType = repoJson["authType"].get<wxString>();
|
|
repo.username = repoJson["username"].get<wxString>();
|
|
repo.ssh_path = repoJson["ssh_path"].get<wxString>();
|
|
repo.active = repoJson["active"].get<bool>();
|
|
repo.checkValid = true;
|
|
|
|
m_Git.repositories.push_back( repo );
|
|
}
|
|
},
|
|
{} ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "git.authorName",
|
|
&m_Git.authorName, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "git.authorEmail",
|
|
&m_Git.authorEmail, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "git.useDefaultAuthor",
|
|
&m_Git.useDefaultAuthor, true ) );
|
|
|
|
|
|
|
|
registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) );
|
|
registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) );
|
|
registerMigration( 2, 3, std::bind( &COMMON_SETTINGS::migrateSchema2to3, this ) );
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema0to1()
|
|
{
|
|
/**
|
|
* Schema version 0 to 1:
|
|
*
|
|
* mousewheel_pan is replaced by explicit settings for scroll wheel behavior
|
|
*/
|
|
|
|
nlohmann::json::json_pointer mwp_pointer( "/input/mousewheel_pan"_json_pointer );
|
|
|
|
bool mwp = false;
|
|
|
|
try
|
|
{
|
|
mwp = m_internals->at( mwp_pointer );
|
|
m_internals->At( "input" ).erase( "mousewheel_pan" );
|
|
}
|
|
catch( ... )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 0->1: mousewheel_pan not found" ) );
|
|
}
|
|
|
|
if( mwp )
|
|
{
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = true;
|
|
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_SHIFT;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = 0;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = WXK_CONTROL;
|
|
}
|
|
else
|
|
{
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = false;
|
|
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_CONTROL;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = WXK_SHIFT;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema1to2()
|
|
{
|
|
nlohmann::json::json_pointer v1_pointer( "/input/prefer_select_to_drag"_json_pointer );
|
|
|
|
bool prefer_selection = false;
|
|
|
|
try
|
|
{
|
|
prefer_selection = m_internals->at( v1_pointer );
|
|
m_internals->at( nlohmann::json::json_pointer( "/input"_json_pointer ) ).erase( "prefer_select_to_drag" );
|
|
}
|
|
catch( ... )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 1->2: prefer_select_to_drag not found" ) );
|
|
}
|
|
|
|
if( prefer_selection )
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::SELECT;
|
|
else
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::DRAG_ANY;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema2to3()
|
|
{
|
|
wxFileName cfgpath;
|
|
cfgpath.AssignDir( PATHS::GetUserSettingsPath() );
|
|
cfgpath.AppendDir( wxT( "3d" ) );
|
|
cfgpath.SetFullName( wxS( "3Dresolver.cfg" ) );
|
|
cfgpath.MakeAbsolute();
|
|
|
|
std::vector<LEGACY_3D_SEARCH_PATH> legacyPaths;
|
|
readLegacy3DResolverCfg( cfgpath.GetFullPath(), legacyPaths );
|
|
|
|
// env variables have a limited allowed character set for names
|
|
wxRegEx nonValidCharsRegex( wxS( "[^A-Z0-9_]+" ), wxRE_ADVANCED );
|
|
|
|
for( const LEGACY_3D_SEARCH_PATH& path : legacyPaths )
|
|
{
|
|
wxString key = path.m_Alias;
|
|
const wxString& val = path.m_Pathvar;
|
|
|
|
// The 3d alias config didnt use the same naming restrictions as real env variables
|
|
// We need to sanitize them
|
|
|
|
// upper case only
|
|
key.MakeUpper();
|
|
// logically swap - with _
|
|
key.Replace( wxS( "-" ), wxS( "_" ) );
|
|
|
|
// remove any other chars
|
|
nonValidCharsRegex.Replace( &key, wxEmptyString );
|
|
|
|
if( !m_Env.vars.count( key ) )
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ), key, val );
|
|
m_Env.vars[key] = ENV_VAR_ITEM( key, val );
|
|
}
|
|
}
|
|
|
|
if( cfgpath.FileExists() )
|
|
{
|
|
wxRemoveFile( cfgpath.GetFullPath() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
|
|
{
|
|
bool ret = true;
|
|
|
|
ret &= fromLegacy<double>( aCfg, "CanvasScale", "appearance.canvas_scale" );
|
|
ret &= fromLegacy<int>( aCfg, "IconScale", "appearance.icon_scale" );
|
|
ret &= fromLegacy<bool>( aCfg, "UseIconsInMenus", "appearance.use_icons_in_menus" );
|
|
ret &= fromLegacy<bool>( aCfg, "ShowEnvVarWarningDialog", "environment.show_warning_dialog" );
|
|
|
|
auto load_env_vars =
|
|
[&]()
|
|
{
|
|
wxString key, value;
|
|
long index = 0;
|
|
nlohmann::json::json_pointer ptr = m_internals->PointerFromString( "environment.vars" );
|
|
|
|
aCfg->SetPath( "EnvironmentVariables" );
|
|
( *m_internals )[ptr] = nlohmann::json( {} );
|
|
|
|
while( aCfg->GetNextEntry( key, index ) )
|
|
{
|
|
if( envVarBlacklist.count( key ) )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "Migrate Env: %s is blacklisted; skipping." ), key );
|
|
continue;
|
|
}
|
|
|
|
value = aCfg->Read( key, wxEmptyString );
|
|
|
|
if( !value.IsEmpty() )
|
|
{
|
|
ptr.push_back( key.ToStdString() );
|
|
|
|
wxLogTrace( traceSettings, wxT( "Migrate Env: %s=%s" ), ptr.to_string(), value );
|
|
( *m_internals )[ptr] = value.ToUTF8();
|
|
|
|
ptr.pop_back();
|
|
}
|
|
}
|
|
|
|
aCfg->SetPath( ".." );
|
|
};
|
|
|
|
load_env_vars();
|
|
|
|
bool mousewheel_pan = false;
|
|
|
|
if( aCfg->Read( "MousewheelPAN", &mousewheel_pan ) && mousewheel_pan )
|
|
{
|
|
Set( "input.horizontal_pan", true );
|
|
Set( "input.scroll_modifier_pan_h", static_cast<int>( WXK_SHIFT ) );
|
|
Set( "input.scroll_modifier_pan_v", 0 );
|
|
Set( "input.scroll_modifier_zoom", static_cast<int>( WXK_CONTROL ) );
|
|
}
|
|
|
|
ret &= fromLegacy<bool>( aCfg, "AutoPAN", "input.auto_pan" );
|
|
ret &= fromLegacy<bool>( aCfg, "ImmediateActions", "input.immediate_actions" );
|
|
ret &= fromLegacy<bool>( aCfg, "PreferSelectionToDragging", "input.prefer_select_to_drag" );
|
|
ret &= fromLegacy<bool>( aCfg, "MoveWarpsCursor", "input.warp_mouse_on_move" );
|
|
ret &= fromLegacy<bool>( aCfg, "ZoomNoCenter", "input.center_on_zoom" );
|
|
|
|
// This was stored inverted in legacy config
|
|
if( std::optional<bool> value = Get<bool>( "input.center_on_zoom" ) )
|
|
Set( "input.center_on_zoom", !( *value ) );
|
|
|
|
ret &= fromLegacy<int>( aCfg, "OpenGLAntialiasingMode", "graphics.opengl_antialiasing_mode" );
|
|
ret &= fromLegacy<int>( aCfg, "CairoAntialiasingMode", "graphics.cairo_antialiasing_mode" );
|
|
|
|
ret &= fromLegacy<int>( aCfg, "AutoSaveInterval", "system.autosave_interval" );
|
|
ret &= fromLegacyString( aCfg, "Editor", "system.editor_name" );
|
|
ret &= fromLegacy<int>( aCfg, "FileHistorySize", "system.file_history_size" );
|
|
ret &= fromLegacyString( aCfg, "LanguageID", "system.language" );
|
|
ret &= fromLegacyString( aCfg, "PdfBrowserName", "system.pdf_viewer_name" );
|
|
ret &= fromLegacy<bool>( aCfg, "UseSystemBrowser", "system.use_system_pdf_viewer" );
|
|
ret &= fromLegacyString( aCfg, "WorkingDir", "system.working_dir" );
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void COMMON_SETTINGS::InitializeEnvironment()
|
|
{
|
|
auto addVar =
|
|
[&]( const wxString& aKey, const wxString& aDefault )
|
|
{
|
|
m_Env.vars[aKey] = ENV_VAR_ITEM( aKey, aDefault, aDefault );
|
|
|
|
wxString envValue;
|
|
|
|
if( wxGetEnv( aKey, &envValue ) == true && !envValue.IsEmpty() )
|
|
{
|
|
m_Env.vars[aKey].SetValue( envValue );
|
|
m_Env.vars[aKey].SetDefinedExternally();
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "InitializeEnvironment: Entry %s defined externally as %s" ), aKey,
|
|
envValue );
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "InitializeEnvironment: Setting entry %s to default %s" ),
|
|
aKey, aDefault );
|
|
}
|
|
};
|
|
|
|
wxFileName basePath( PATHS::GetStockEDALibraryPath(), wxEmptyString );
|
|
|
|
wxFileName path( basePath );
|
|
path.AppendDir( wxT( "footprints" ) );
|
|
addVar( wxT( "KICAD7_FOOTPRINT_DIR" ), path.GetFullPath() );
|
|
|
|
path = basePath;
|
|
path.AppendDir( wxT( "3dmodels" ) );
|
|
addVar( wxT( "KICAD7_3DMODEL_DIR" ), path.GetFullPath() );
|
|
|
|
addVar( wxT( "KICAD7_TEMPLATE_DIR" ), PATHS::GetStockTemplatesPath() );
|
|
|
|
addVar( wxT( "KICAD_USER_TEMPLATE_DIR" ), PATHS::GetUserTemplatesPath() );
|
|
|
|
addVar( wxT( "KICAD7_3RD_PARTY" ), PATHS::GetDefault3rdPartyPath() );
|
|
|
|
path = basePath;
|
|
path.AppendDir( wxT( "symbols" ) );
|
|
addVar( wxT( "KICAD7_SYMBOL_DIR" ), path.GetFullPath() );
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::readLegacy3DResolverCfg( const wxString& path,
|
|
std::vector<LEGACY_3D_SEARCH_PATH>& aSearchPaths )
|
|
{
|
|
wxFileName cfgpath( path );
|
|
|
|
// This should be the same as wxWidgets 3.0 wxPATH_NORM_ALL which is deprecated in 3.1.
|
|
// There are known issues with environment variable expansion so maybe we should be using
|
|
// our own ExpandEnvVarSubstitutions() here instead.
|
|
cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
|
|
wxString cfgname = cfgpath.GetFullPath();
|
|
|
|
std::ifstream cfgFile;
|
|
std::string cfgLine;
|
|
|
|
if( !wxFileName::Exists( cfgname ) )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = "no 3D configuration file";
|
|
ostr << " * " << errmsg.ToUTF8() << " '";
|
|
ostr << cfgname.ToUTF8() << "'";
|
|
wxLogTrace( traceSettings, "%s\n", ostr.str().c_str() );
|
|
return false;
|
|
}
|
|
|
|
cfgFile.open( cfgname.ToUTF8() );
|
|
|
|
if( !cfgFile.is_open() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "Could not open configuration file" );
|
|
ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
return false;
|
|
}
|
|
|
|
int lineno = 0;
|
|
LEGACY_3D_SEARCH_PATH al;
|
|
size_t idx;
|
|
int vnum = 0; // version number
|
|
|
|
while( cfgFile.good() )
|
|
{
|
|
cfgLine.clear();
|
|
std::getline( cfgFile, cfgLine );
|
|
++lineno;
|
|
|
|
if( cfgLine.empty() )
|
|
{
|
|
if( cfgFile.eof() )
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
|
|
if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 )
|
|
{
|
|
// extract the version number and parse accordingly
|
|
if( cfgLine.size() > 2 )
|
|
{
|
|
std::istringstream istr;
|
|
istr.str( cfgLine.substr( 2 ) );
|
|
istr >> vnum;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Alias ) )
|
|
continue;
|
|
|
|
// Don't add KICAD7_3DMODEL_DIR, one of its legacy equivalents, or KIPRJMOD from a
|
|
// config file. They're system variables are are defined at runtime.
|
|
if( al.m_Alias == wxS( "${KICAD7_3DMODEL_DIR}" ) || al.m_Alias == wxS( "${KIPRJMOD}" )
|
|
|| al.m_Alias == wxS( "$(KIPRJMOD)" ) || al.m_Alias == wxS( "${KISYS3DMOD}" )
|
|
|| al.m_Alias == wxS( "$(KISYS3DMOD)" ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Pathvar ) )
|
|
continue;
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Description ) )
|
|
continue;
|
|
|
|
aSearchPaths.push_back( al );
|
|
}
|
|
|
|
cfgFile.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::getLegacy3DHollerith( const std::string& aString, size_t& aIndex,
|
|
wxString& aResult )
|
|
{
|
|
aResult.clear();
|
|
|
|
if( aIndex >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "bad Hollerith string on line" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t i2 = aString.find( '"', aIndex );
|
|
|
|
if( std::string::npos == i2 )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "missing opening quote mark in config file" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
++i2;
|
|
|
|
if( i2 >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string tnum;
|
|
|
|
while( aString[i2] >= '0' && aString[i2] <= '9' )
|
|
tnum.append( 1, aString[i2++] );
|
|
|
|
if( tnum.empty() || aString[i2++] != ':' )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "bad Hollerith string on line" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
std::istringstream istr;
|
|
istr.str( tnum );
|
|
size_t nchars;
|
|
istr >> nchars;
|
|
|
|
if( ( i2 + nchars ) >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
if( nchars > 0 )
|
|
{
|
|
aResult = wxString::FromUTF8( aString.substr( i2, nchars ).c_str() );
|
|
i2 += nchars;
|
|
}
|
|
|
|
if( i2 >= aString.size() || aString[i2] != '"' )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "missing closing quote mark in config file" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
aIndex = i2 + 1;
|
|
return true;
|
|
}
|