You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

624 lines
28 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation, either version 3 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "footprint_editor_settings.h"
  21. #include <common.h>
  22. #include <layer_ids.h>
  23. #include <lset.h>
  24. #include <pgm_base.h>
  25. #include <eda_text.h>
  26. #include <pcb_dimension.h>
  27. #include <settings/common_settings.h>
  28. #include <settings/json_settings_internals.h>
  29. #include <settings/parameters.h>
  30. #include <settings/settings_manager.h>
  31. #include <base_units.h>
  32. #include <wx/config.h>
  33. #include <wx/log.h>
  34. ///! Update the schema version whenever a migration is required
  35. const int fpEditSchemaVersion = 5;
  36. FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() :
  37. PCB_VIEWERS_SETTINGS_BASE( "fpedit", fpEditSchemaVersion ),
  38. m_DesignSettings( nullptr, "fpedit.settings" ),
  39. m_MagneticItems(),
  40. m_Display(),
  41. m_UserGrid(),
  42. m_PolarCoords( false ),
  43. m_DisplayInvertXAxis( false ),
  44. m_DisplayInvertYAxis( false ),
  45. m_RotationAngle( ANGLE_90 ),
  46. m_Use45Limit( true ),
  47. m_ArcEditMode( ARC_EDIT_MODE::KEEP_CENTER_ADJUST_ANGLE_RADIUS ),
  48. m_LibWidth( 250 ),
  49. m_LastExportPath(),
  50. m_FootprintTextShownColumns()
  51. {
  52. m_MagneticItems.pads = MAGNETIC_OPTIONS::CAPTURE_ALWAYS;
  53. m_MagneticItems.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
  54. m_MagneticItems.graphics = true;
  55. m_MagneticItems.allLayers = false;
  56. m_AuiPanels.appearance_panel_tab = 0;
  57. m_AuiPanels.right_panel_width = -1;
  58. m_AuiPanels.show_layer_manager = true;
  59. m_params.emplace_back( new PARAM<int>( "window.lib_width",
  60. &m_LibWidth, 250 ) );
  61. m_params.emplace_back( new PARAM<bool>( "aui.show_layer_manager",
  62. &m_AuiPanels.show_layer_manager, true ) );
  63. m_params.emplace_back( new PARAM<int>( "aui.right_panel_width",
  64. &m_AuiPanels.right_panel_width, -1 ) );
  65. m_params.emplace_back( new PARAM<int>( "aui.appearance_panel_tab",
  66. &m_AuiPanels.appearance_panel_tab, 0, 0, 2 ) );
  67. m_params.emplace_back( new PARAM<int>( "aui.properties_panel_width",
  68. &m_AuiPanels.properties_panel_width, -1 ) );
  69. m_params.emplace_back( new PARAM<float>( "aui.properties_splitter_proportion",
  70. &m_AuiPanels.properties_splitter, 0.5f ) );
  71. m_params.emplace_back( new PARAM<bool>( "aui.show_properties",
  72. &m_AuiPanels.show_properties, false ) );
  73. m_params.emplace_back( new PARAM<int>( "library.sort_mode",
  74. &m_LibrarySortMode, 0 ) );
  75. m_params.emplace_back( new PARAM<wxString>( "system.last_import_export_path",
  76. &m_LastExportPath, "" ) );
  77. m_params.emplace_back( new PARAM<bool>( "pcb_display.graphics_fill",
  78. &m_ViewersDisplay.m_DisplayGraphicsFill, true ) );
  79. m_params.emplace_back( new PARAM<bool>( "pcb_display.text_fill",
  80. &m_ViewersDisplay.m_DisplayTextFill, true ) );
  81. m_params.emplace_back( new PARAM<bool>( "pcb_display.pad_fill",
  82. &m_ViewersDisplay.m_DisplayPadFill, true ) );
  83. m_params.emplace_back( new PARAM<bool>( "pcb_display.pad_numbers",
  84. &m_ViewersDisplay.m_DisplayPadNumbers, true ) );
  85. m_params.emplace_back( new PARAM<wxString>( "window.footprint_text_shown_columns",
  86. &m_FootprintTextShownColumns, "0 1 2 3 4 5 7" ) );
  87. m_params.emplace_back( new PARAM<int>( "editing.magnetic_pads",
  88. reinterpret_cast<int*>( &m_MagneticItems.pads ),
  89. static_cast<int>( MAGNETIC_OPTIONS::CAPTURE_ALWAYS ) ) );
  90. m_params.emplace_back( new PARAM<bool>( "editing.magnetic_graphics",
  91. &m_MagneticItems.graphics, true ) );
  92. m_params.emplace_back( new PARAM<bool>( "editing.magnetic_all_layers",
  93. &m_MagneticItems.allLayers, false ) );
  94. m_params.emplace_back( new PARAM<bool>( "editing.polar_coords",
  95. &m_PolarCoords, false ) );
  96. m_params.emplace_back( new PARAM<bool>( "origin_invert_x_axis",
  97. &m_DisplayInvertXAxis, false ) );
  98. m_params.emplace_back( new PARAM<bool>( "origin_invert_y_axis",
  99. &m_DisplayInvertYAxis, false ) );
  100. m_params.emplace_back( new PARAM_LAMBDA<int>( "editing.rotation_angle",
  101. [this] () -> int
  102. {
  103. return m_RotationAngle.AsTenthsOfADegree();
  104. },
  105. [this] ( int aVal )
  106. {
  107. if( aVal )
  108. m_RotationAngle = EDA_ANGLE( aVal, TENTHS_OF_A_DEGREE_T );
  109. },
  110. 900 ) );
  111. m_params.emplace_back( new PARAM<bool>( "editing.fp_use_45_degree_limit",
  112. &m_Use45Limit, false ) );
  113. m_params.emplace_back( new PARAM_LAYER_PRESET( "pcb_display.layer_presets", &m_LayerPresets ) );
  114. m_params.emplace_back( new PARAM<wxString>( "pcb_display.active_layer_preset",
  115. &m_ActiveLayerPreset, "" ) );
  116. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
  117. "design_settings.default_footprint_text_items",
  118. [&] () -> nlohmann::json
  119. {
  120. nlohmann::json js = nlohmann::json::array();
  121. for( const TEXT_ITEM_INFO& item : m_DesignSettings.m_DefaultFPTextItems )
  122. {
  123. js.push_back( nlohmann::json( { item.m_Text.ToUTF8(),
  124. item.m_Visible,
  125. LSET::Name( item.m_Layer ) } ) );
  126. }
  127. return js;
  128. },
  129. [&] ( const nlohmann::json& aObj )
  130. {
  131. m_DesignSettings.m_DefaultFPTextItems.clear();
  132. if( !aObj.is_array() )
  133. return;
  134. for( const nlohmann::json& entry : aObj )
  135. {
  136. if( entry.empty() || !entry.is_array() )
  137. continue;
  138. TEXT_ITEM_INFO textInfo( wxT( "" ), true, F_SilkS );
  139. textInfo.m_Text = entry.at(0).get<wxString>();
  140. textInfo.m_Visible = entry.at(1).get<bool>();
  141. wxString layerName = entry.at(2).get<wxString>();
  142. int candidateLayer = LSET::NameToLayer( layerName );
  143. textInfo.m_Layer = candidateLayer >= 0
  144. ? static_cast<PCB_LAYER_ID>(candidateLayer)
  145. : F_SilkS;
  146. m_DesignSettings.m_DefaultFPTextItems.push_back( std::move( textInfo ) );
  147. }
  148. },
  149. nlohmann::json::array( {
  150. { "REF**", true, LSET::Name( F_SilkS ) },
  151. { "", true, LSET::Name( F_Fab ) },
  152. { "${REFERENCE}", true, LSET::Name( F_Fab ) }
  153. } ) ) );
  154. m_params.emplace_back( new PARAM_MAP<wxString>( "design_settings.default_footprint_layer_names",
  155. &m_DesignSettings.m_UserLayerNames, {} ) );
  156. int minTextSize = pcbIUScale.mmToIU( TEXT_MIN_SIZE_MM );
  157. int maxTextSize = pcbIUScale.mmToIU( TEXT_MAX_SIZE_MM );
  158. int minStroke = 1;
  159. int maxStroke = pcbIUScale.mmToIU( 100 );
  160. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_line_width",
  161. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_SILK ],
  162. pcbIUScale.mmToIU( DEFAULT_SILK_LINE_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  163. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_size_h",
  164. &m_DesignSettings.m_TextSize[ LAYER_CLASS_SILK ].x,
  165. pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  166. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_size_v",
  167. &m_DesignSettings.m_TextSize[ LAYER_CLASS_SILK ].y,
  168. pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  169. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_thickness",
  170. &m_DesignSettings.m_TextThickness[ LAYER_CLASS_SILK ],
  171. pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH ), 1, maxTextSize, pcbIUScale.MM_PER_IU ) );
  172. m_params.emplace_back( new PARAM<bool>( "design_settings.silk_text_italic",
  173. &m_DesignSettings.m_TextItalic[ LAYER_CLASS_SILK ], false ) );
  174. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_line_width",
  175. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_COPPER ],
  176. pcbIUScale.mmToIU( DEFAULT_COPPER_LINE_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  177. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_size_h",
  178. &m_DesignSettings.m_TextSize[ LAYER_CLASS_COPPER ].x,
  179. pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  180. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_size_v",
  181. &m_DesignSettings.m_TextSize[ LAYER_CLASS_COPPER ].y,
  182. pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  183. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_thickness",
  184. &m_DesignSettings.m_TextThickness[ LAYER_CLASS_COPPER ],
  185. pcbIUScale.mmToIU( DEFAULT_COPPER_TEXT_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  186. m_params.emplace_back( new PARAM<bool>( "design_settings.copper_text_italic",
  187. &m_DesignSettings.m_TextItalic[ LAYER_CLASS_COPPER ], false ) );
  188. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.edge_line_width",
  189. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_EDGES ],
  190. pcbIUScale.mmToIU( DEFAULT_EDGE_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  191. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.courtyard_line_width",
  192. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ],
  193. pcbIUScale.mmToIU( DEFAULT_COURTYARD_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  194. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_line_width",
  195. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_FAB ],
  196. pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  197. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_size_h",
  198. &m_DesignSettings.m_TextSize[ LAYER_CLASS_FAB ].x,
  199. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  200. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_size_v",
  201. &m_DesignSettings.m_TextSize[ LAYER_CLASS_FAB ].y,
  202. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  203. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_thickness",
  204. &m_DesignSettings.m_TextThickness[ LAYER_CLASS_FAB ],
  205. pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH ), 1, maxTextSize, pcbIUScale.MM_PER_IU ) );
  206. m_params.emplace_back( new PARAM<bool>( "design_settings.fab_text_italic",
  207. &m_DesignSettings.m_TextItalic[ LAYER_CLASS_FAB ], false ) );
  208. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_line_width",
  209. &m_DesignSettings.m_LineThickness[ LAYER_CLASS_OTHERS ],
  210. pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ), minStroke, maxStroke, pcbIUScale.MM_PER_IU ) );
  211. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_size_h",
  212. &m_DesignSettings.m_TextSize[ LAYER_CLASS_OTHERS ].x,
  213. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  214. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_size_v",
  215. &m_DesignSettings.m_TextSize[ LAYER_CLASS_OTHERS ].y,
  216. pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE ), minTextSize, maxTextSize, pcbIUScale.MM_PER_IU ) );
  217. m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_thickness",
  218. &m_DesignSettings.m_TextThickness[ LAYER_CLASS_OTHERS ],
  219. pcbIUScale.mmToIU( DEFAULT_TEXT_WIDTH ), 1, maxTextSize, pcbIUScale.MM_PER_IU ) );
  220. m_params.emplace_back( new PARAM<bool>( "design_settings.others_text_italic",
  221. &m_DesignSettings.m_TextItalic[ LAYER_CLASS_OTHERS ], false ) );
  222. // ---------------------------------------------------------------------------------------------
  223. // Dimension settings
  224. m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_MODE>( "design_settings.dimensions.units",
  225. &m_DesignSettings.m_DimensionUnitsMode, DIM_UNITS_MODE::AUTOMATIC, DIM_UNITS_MODE::INCH,
  226. DIM_UNITS_MODE::AUTOMATIC ) );
  227. m_params.emplace_back( new PARAM_ENUM<DIM_PRECISION>( "design_settings.dimensions.precision",
  228. &m_DesignSettings.m_DimensionPrecision, DIM_PRECISION::X_XXXX, DIM_PRECISION::X, DIM_PRECISION::V_VVVVV ) );
  229. m_params.emplace_back( new PARAM_ENUM<DIM_UNITS_FORMAT>( "design_settings.dimensions.units_format",
  230. &m_DesignSettings.m_DimensionUnitsFormat, DIM_UNITS_FORMAT::NO_SUFFIX, DIM_UNITS_FORMAT::NO_SUFFIX,
  231. DIM_UNITS_FORMAT::PAREN_SUFFIX ) );
  232. m_params.emplace_back( new PARAM<bool>( "design_settings.dimensions.suppress_zeroes",
  233. &m_DesignSettings.m_DimensionSuppressZeroes, true ) );
  234. // NOTE: excluding DIM_TEXT_POSITION::MANUAL from the valid range here
  235. m_params.emplace_back( new PARAM_ENUM<DIM_TEXT_POSITION>( "design_settings.dimensions.text_position",
  236. &m_DesignSettings.m_DimensionTextPosition, DIM_TEXT_POSITION::OUTSIDE, DIM_TEXT_POSITION::OUTSIDE,
  237. DIM_TEXT_POSITION::INLINE ) );
  238. m_params.emplace_back( new PARAM<bool>( "design_settings.dimensions.keep_text_aligned",
  239. &m_DesignSettings.m_DimensionKeepTextAligned, true ) );
  240. m_params.emplace_back( new PARAM<int>( "design_settings.dimensions.arrow_length",
  241. &m_DesignSettings.m_DimensionArrowLength,
  242. pcbIUScale.MilsToIU( DEFAULT_DIMENSION_ARROW_LENGTH ) ) );
  243. m_params.emplace_back( new PARAM<int>( "design_settings.dimensions.extension_offset",
  244. &m_DesignSettings.m_DimensionExtensionOffset,
  245. pcbIUScale.mmToIU( DEFAULT_DIMENSION_EXTENSION_OFFSET ) ) );
  246. // ---------------------------------------------------------------------------------------------
  247. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "editing.selection_filter",
  248. [&]() -> nlohmann::json
  249. {
  250. nlohmann::json ret;
  251. ret["lockedItems"] = m_SelectionFilter.lockedItems;
  252. ret["footprints"] = m_SelectionFilter.footprints;
  253. ret["text"] = m_SelectionFilter.text;
  254. ret["tracks"] = m_SelectionFilter.tracks;
  255. ret["vias"] = m_SelectionFilter.vias;
  256. ret["pads"] = m_SelectionFilter.pads;
  257. ret["graphics"] = m_SelectionFilter.graphics;
  258. ret["zones"] = m_SelectionFilter.zones;
  259. ret["keepouts"] = m_SelectionFilter.keepouts;
  260. ret["dimensions"] = m_SelectionFilter.dimensions;
  261. ret["otherItems"] = m_SelectionFilter.otherItems;
  262. return ret;
  263. },
  264. [&]( const nlohmann::json& aVal )
  265. {
  266. if( aVal.empty() || !aVal.is_object() )
  267. return;
  268. SetIfPresent( aVal, "lockedItems", m_SelectionFilter.lockedItems );
  269. SetIfPresent( aVal, "footprints", m_SelectionFilter.footprints );
  270. SetIfPresent( aVal, "text", m_SelectionFilter.text );
  271. SetIfPresent( aVal, "tracks", m_SelectionFilter.tracks );
  272. SetIfPresent( aVal, "vias", m_SelectionFilter.vias );
  273. SetIfPresent( aVal, "pads", m_SelectionFilter.pads );
  274. SetIfPresent( aVal, "graphics", m_SelectionFilter.graphics );
  275. SetIfPresent( aVal, "zones", m_SelectionFilter.zones );
  276. SetIfPresent( aVal, "keepouts", m_SelectionFilter.keepouts );
  277. SetIfPresent( aVal, "dimensions", m_SelectionFilter.dimensions );
  278. SetIfPresent( aVal, "otherItems", m_SelectionFilter.otherItems );
  279. },
  280. {
  281. { "lockedItems", false },
  282. { "footprints", true },
  283. { "text", true },
  284. { "tracks", true },
  285. { "vias", true },
  286. { "pads", true },
  287. { "graphics", true },
  288. { "zones", true },
  289. { "keepouts", true },
  290. { "dimensions", true },
  291. { "otherItems", true }
  292. } ) );
  293. registerMigration( 0, 1, std::bind( &FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1, this ) );
  294. registerMigration( 1, 2,
  295. [&]() -> bool
  296. {
  297. // This is actually a migration for APP_SETTINGS_BASE::m_LibTree
  298. return migrateLibTreeWidth();
  299. } );
  300. registerMigration( 2, 3, std::bind( &FOOTPRINT_EDITOR_SETTINGS::migrateSchema2To3, this ) );
  301. registerMigration( 3, 4, std::bind( &FOOTPRINT_EDITOR_SETTINGS::migrateSchema3To4, this ) );
  302. registerMigration( 4, 5, std::bind( &FOOTPRINT_EDITOR_SETTINGS::migrateSchema4To5, this ) );
  303. }
  304. bool FOOTPRINT_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
  305. {
  306. bool ret = APP_SETTINGS_BASE::MigrateFromLegacy( aCfg );
  307. //
  308. // NOTE: there's no value in line-wrapping these; it just makes the table unreadable.
  309. //
  310. ret &= fromLegacy<int>( aCfg, "ModeditLibWidth", "window.lib_width" );
  311. ret &= fromLegacyString( aCfg, "import_last_path", "system.last_import_export_path" );
  312. ret &= fromLegacyString( aCfg, "LibFootprintTextShownColumns", "window.footprint_text_shown_columns" );
  313. ret &= fromLegacy<int>( aCfg, "FpEditorMagneticPads", "editing.magnetic_pads" );
  314. ret &= fromLegacy<bool>( aCfg, "FpEditorDisplayPolarCoords", "editing.polar_coords" );
  315. ret &= fromLegacy<int>( aCfg, "FpEditorUse45DegreeGraphicSegments", "editing.use_45_degree_graphic_segments" );
  316. ret &= fromLegacy<bool>( aCfg, "FpEditorGraphicLinesDisplayMode", "pcb_display.graphic_items_fill" );
  317. ret &= fromLegacy<bool>( aCfg, "FpEditorPadDisplayMode", "pcb_display.pad_fill" );
  318. ret &= fromLegacy<bool>( aCfg, "FpEditorTextsDisplayMode", "pcb_display.footprint_text" );
  319. ret &= fromLegacy<double>( aCfg, "FpEditorSilkLineWidth", "design_settings.silk_line_width" );
  320. ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextSizeH", "design_settings.silk_text_size_h" );
  321. ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextSizeV", "design_settings.silk_text_size_v" );
  322. ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextThickness", "design_settings.silk_text_thickness" );
  323. ret &= fromLegacy<bool>( aCfg, "FpEditorSilkTextItalic", "design_settings.silk_text_italic" );
  324. ret &= fromLegacy<double>( aCfg, "FpEditorCopperLineWidth", "design_settings.copper_line_width" );
  325. ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextSizeH", "design_settings.copper_text_size_h" );
  326. ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextSizeV", "design_settings.copper_text_size_v" );
  327. ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextThickness", "design_settings.copper_text_thickness" );
  328. ret &= fromLegacy<bool>( aCfg, "FpEditorCopperTextItalic", "design_settings.copper_text_italic" );
  329. ret &= fromLegacy<double>( aCfg, "FpEditorEdgeCutLineWidth", "design_settings.edge_line_width" );
  330. ret &= fromLegacy<double>( aCfg, "FpEditorCourtyardLineWidth", "design_settings.courtyard_line_width" );
  331. ret &= fromLegacy<double>( aCfg, "FpEditorOthersLineWidth", "design_settings.others_line_width" );
  332. ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextSizeH", "design_settings.others_text_size_h" );
  333. ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextSizeV", "design_settings.others_text_size_v" );
  334. ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextThickness", "design_settings.others_text_thickness" );
  335. ret &= fromLegacy<bool>( aCfg, "FpEditorOthersTextItalic", "design_settings.others_text_italic" );
  336. nlohmann::json textItems = nlohmann::json::array( {
  337. { "REF**", true, F_SilkS },
  338. { "", true, F_Fab }
  339. } );
  340. Set( "design_settings.default_footprint_text_items", std::move( textItems ) );
  341. ret &= fromLegacyString( aCfg, "FpEditorRefDefaultText", "design_settings.default_footprint_text_items.0.0" );
  342. ret &= fromLegacy<bool>( aCfg, "FpEditorRefDefaultVisibility", "design_settings.default_footprint_text_items.0.1" );
  343. ret &= fromLegacy<int>( aCfg, "FpEditorRefDefaultLayer", "design_settings.default_footprint_text_items.0.2" );
  344. ret &= fromLegacyString( aCfg, "FpEditorValueDefaultText", "design_settings.default_footprint_text_items.1.0" );
  345. ret &= fromLegacy<bool>( aCfg, "FpEditorValueDefaultVisibility", "design_settings.default_footprint_text_items.1.1" );
  346. ret &= fromLegacy<int>( aCfg, "FpEditorValueDefaultLayer", "design_settings.default_footprint_text_items.1.2" );
  347. std::string f = "ModEdit";
  348. // Migrate color settings that were stored in the pcbnew config file
  349. // We create a copy of the user scheme for the footprint editor context
  350. SETTINGS_MANAGER& manager = Pgm().GetSettingsManager();
  351. COLOR_SETTINGS* cs = manager.AddNewColorSettings( "user_footprints" );
  352. cs->SetName( wxT( "User (Footprints)" ) );
  353. manager.Save( cs );
  354. auto migrateLegacyColor = [&] ( const std::string& aKey, int aLayerId )
  355. {
  356. wxString str;
  357. if( aCfg->Read( aKey, &str ) )
  358. cs->SetColor( aLayerId, COLOR4D( str ) );
  359. };
  360. for( int i = 0; i < PCB_LAYER_ID_COUNT; ++i )
  361. {
  362. wxString layer = LSET::Name( PCB_LAYER_ID( i ) );
  363. migrateLegacyColor( f + "Color4DPCBLayer_" + layer.ToStdString(), PCB_LAYER_ID( i ) );
  364. }
  365. migrateLegacyColor( f + "Color4DAnchorEx", LAYER_ANCHOR );
  366. migrateLegacyColor( f + "Color4DAuxItems", LAYER_AUX_ITEMS );
  367. migrateLegacyColor( f + "Color4DGrid", LAYER_GRID );
  368. migrateLegacyColor( f + "Color4DNonPlatedEx", LAYER_NON_PLATEDHOLES );
  369. migrateLegacyColor( f + "Color4DPCBBackground", LAYER_PCB_BACKGROUND );
  370. migrateLegacyColor( f + "Color4DPCBCursor", LAYER_CURSOR );
  371. migrateLegacyColor( f + "Color4DRatsEx", LAYER_RATSNEST );
  372. migrateLegacyColor( f + "Color4DViaBBlindEx", LAYER_VIA_BBLIND );
  373. migrateLegacyColor( f + "Color4DViaMicroEx", LAYER_VIA_MICROVIA );
  374. migrateLegacyColor( f + "Color4DViaThruEx", LAYER_VIA_THROUGH );
  375. migrateLegacyColor( f + "Color4DWorksheet", LAYER_DRAWINGSHEET );
  376. manager.SaveColorSettings( cs, "board" );
  377. ( *m_internals )[m_internals->PointerFromString( "appearance.color_theme" )] = "user_footprints";
  378. double x = 0, y = 0;
  379. f = "ModEditFrame";
  380. if( aCfg->Read( f + "PcbUserGrid_X", &x ) && aCfg->Read( f + "PcbUserGrid_Y", &y ) )
  381. {
  382. EDA_UNITS u = static_cast<EDA_UNITS>( aCfg->ReadLong( f + "PcbUserGrid_Unit",
  383. static_cast<long>( EDA_UNITS::INCH ) ) );
  384. // Convert to internal units
  385. x = EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, u, x );
  386. y = EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, u, y );
  387. Set( "window.grid.user_grid_x", EDA_UNIT_UTILS::UI::StringFromValue( pcbIUScale, u, x ) );
  388. Set( "window.grid.user_grid_y", EDA_UNIT_UTILS::UI::StringFromValue( pcbIUScale, u, y ) );
  389. }
  390. return ret;
  391. }
  392. bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1()
  393. {
  394. /**
  395. * Schema version 0 to 1:
  396. *
  397. * - Check to see if a footprints version of the currently selected theme exists.
  398. * - If so, select it
  399. */
  400. if( !m_manager )
  401. {
  402. wxLogTrace( traceSettings,
  403. wxT( "Error: FOOTPRINT_EDITOR_SETTINGS migration cannot run unmanaged!" ) );
  404. return false;
  405. }
  406. std::string theme_ptr( "appearance.color_theme" );
  407. if( !Contains( theme_ptr ) )
  408. return true;
  409. wxString selected = At( theme_ptr ).get<wxString>();
  410. wxString search = selected + wxT( "_footprints" );
  411. for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
  412. {
  413. if( settings->GetFilename() == search )
  414. {
  415. wxLogTrace( traceSettings, wxT( "Updating footprint editor theme from %s to %s" ),
  416. selected, search );
  417. Set( theme_ptr, search );
  418. return true;
  419. }
  420. }
  421. return true;
  422. }
  423. /**
  424. * Schema version 2: Bump for KiCad 9 layer numbering changes
  425. * Migrate layer presets to use new enum values for copper layers
  426. */
  427. bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema2To3()
  428. {
  429. auto p( "/pcb_display/layer_presets"_json_pointer );
  430. if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
  431. return true;
  432. nlohmann::json& presets = m_internals->at( p );
  433. for( nlohmann::json& entry : presets )
  434. PARAM_LAYER_PRESET::MigrateToV9Layers( entry );
  435. return true;
  436. }
  437. /**
  438. * Schema version 4: move layer presets to use named render layers
  439. */
  440. bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema3To4()
  441. {
  442. auto p( "/pcb_display/layer_presets"_json_pointer );
  443. if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
  444. return true;
  445. nlohmann::json& presets = m_internals->at( p );
  446. for( nlohmann::json& entry : presets )
  447. PARAM_LAYER_PRESET::MigrateToNamedRenderLayers( entry );
  448. return true;
  449. }
  450. /**
  451. * Schema version 5: move text defaults to used named layers
  452. */
  453. bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema4To5 ()
  454. {
  455. auto p( "/design_settings/default_footprint_text_items"_json_pointer );
  456. if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
  457. return true;
  458. nlohmann::json& defaults = m_internals->at( p );
  459. bool reset = false;
  460. for( nlohmann::json& entry : defaults )
  461. {
  462. TEXT_ITEM_INFO textInfo( wxT( "" ), true, F_SilkS );
  463. textInfo.m_Text = entry.at(0).get<wxString>();
  464. textInfo.m_Visible = entry.at(1).get<bool>();
  465. textInfo.m_Layer = static_cast<PCB_LAYER_ID>( entry.at(2).get<int>() );
  466. if( textInfo.m_Layer == Rescue || textInfo.m_Layer >= User_5 )
  467. {
  468. // KiCad pre-9.0 nightlies would write buggy preferences out with invalid layers.
  469. // If we detect that, reset to defaults
  470. reset = true;
  471. }
  472. else
  473. {
  474. // Coming from 8.0 or earlier, just migrate to named layers
  475. entry.at(2) = LSET::Name( textInfo.m_Layer );
  476. }
  477. }
  478. if( reset )
  479. {
  480. defaults = nlohmann::json::array( {
  481. { "REF**", true, LSET::Name( F_SilkS ) },
  482. { "", true, LSET::Name( F_Fab ) },
  483. { "${REFERENCE}", true, LSET::Name( F_Fab ) }
  484. } );
  485. }
  486. return true;
  487. }