/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 Jon Evans * Copyright (C) 2020 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 . */ #include #include #include #include #include #include #include #include #include #include #include extern const char* traceSettings; ///! Update the schema version whenever a migration is required const int fpEditSchemaVersion = 1; FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() : APP_SETTINGS_BASE( "fpedit", fpEditSchemaVersion ), m_DesignSettings( nullptr, "fpedit.settings" ), m_MagneticItems(), m_Display(), m_UserGrid(), m_PolarCoords( false ), m_Use45DegreeGraphicSegments( true ), m_LibWidth( 250 ), m_LastImportExportPath(), m_FootprintTextShownColumns() { m_MagneticItems.pads = MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL; m_MagneticItems.tracks = MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL; m_MagneticItems.graphics = false; m_params.emplace_back( new PARAM( "window.lib_width", &m_LibWidth, 250 ) ); m_params.emplace_back( new PARAM( "system.last_import_export_path", &m_LastImportExportPath, "" ) ); m_params.emplace_back( new PARAM( "window.footprint_text_shown_columns", &m_FootprintTextShownColumns, "0 1 2 3 4 5 6" ) ); m_params.emplace_back( new PARAM( "editing.magnetic_pads", reinterpret_cast( &m_MagneticItems.pads ), static_cast( MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL ) ) ); m_params.emplace_back( new PARAM( "editing.polar_coords", &m_PolarCoords, false ) ); m_params.emplace_back( new PARAM( "editing.use_45_degree_graphic_segments", &m_Use45DegreeGraphicSegments, false ) ); m_params.emplace_back( new PARAM( "pcb_display.text_fill", &m_Display.m_DisplayTextFill, true ) ); m_params.emplace_back( new PARAM( "pcb_display.graphic_items_fill", &m_Display.m_DisplayGraphicsFill, true ) ); m_params.emplace_back( new PARAM( "pcb_display.pad_fill", &m_Display.m_DisplayPadFill, true ) ); m_params.emplace_back( new PARAM_LAMBDA( "design_settings.default_footprint_text_items", [&] () -> nlohmann::json { nlohmann::json js = nlohmann::json::array(); for( const TEXT_ITEM_INFO& item : m_DesignSettings.m_DefaultFPTextItems ) { js.push_back( nlohmann::json( { item.m_Text.ToUTF8(), item.m_Visible, item.m_Layer } ) ); } return js; }, [&] ( const nlohmann::json& aObj ) { m_DesignSettings.m_DefaultFPTextItems.clear(); if( !aObj.is_array() ) return; for( const nlohmann::json& entry : aObj ) { if( entry.empty() || !entry.is_array() ) continue; TEXT_ITEM_INFO textInfo( wxT( "" ), true, F_SilkS ); textInfo.m_Text = entry.at(0).get(); textInfo.m_Visible = entry.at(1).get(); textInfo.m_Layer = entry.at(2).get(); m_DesignSettings.m_DefaultFPTextItems.push_back( std::move( textInfo ) ); } }, nlohmann::json::array( { { "REF**", true, F_SilkS }, { "", true, F_Fab }, { "${REFERENCE}", true, F_Fab } } ) ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.silk_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_SILK ], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 100.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.silk_text_size_h", &m_DesignSettings.m_TextSize[ LAYER_CLASS_SILK ].x, Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.silk_text_size_v", &m_DesignSettings.m_TextSize[ LAYER_CLASS_SILK ].y, Millimeter2iu( DEFAULT_SILK_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.silk_text_thickness", &m_DesignSettings.m_TextThickness[ LAYER_CLASS_SILK ], Millimeter2iu( DEFAULT_SILK_TEXT_WIDTH ), 1, TEXTS_MAX_WIDTH, MM_PER_IU ) ); m_params.emplace_back( new PARAM( "design_settings.silk_text_italic", &m_DesignSettings.m_TextItalic[ LAYER_CLASS_SILK ], false ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.copper_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_COPPER ], Millimeter2iu( DEFAULT_COPPER_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.copper_text_size_h", &m_DesignSettings.m_TextSize[ LAYER_CLASS_COPPER ].x, Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.copper_text_size_v", &m_DesignSettings.m_TextSize[ LAYER_CLASS_COPPER ].y, Millimeter2iu( DEFAULT_COPPER_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.copper_text_thickness", &m_DesignSettings.m_TextThickness[ LAYER_CLASS_COPPER ], Millimeter2iu( DEFAULT_COPPER_TEXT_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM( "design_settings.copper_text_italic", &m_DesignSettings.m_TextItalic[ LAYER_CLASS_COPPER ], false ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.edge_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_EDGES ], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.courtyard_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.fab_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_FAB ], Millimeter2iu( DEFAULT_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.fab_text_size_h", &m_DesignSettings.m_TextSize[ LAYER_CLASS_FAB ].x, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.fab_text_size_v", &m_DesignSettings.m_TextSize[ LAYER_CLASS_FAB ].y, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.fab_text_thickness", &m_DesignSettings.m_TextThickness[ LAYER_CLASS_FAB ], Millimeter2iu( DEFAULT_TEXT_WIDTH ), 1, TEXTS_MAX_WIDTH, MM_PER_IU ) ); m_params.emplace_back( new PARAM( "design_settings.fab_text_italic", &m_DesignSettings.m_TextItalic[ LAYER_CLASS_FAB ], false ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.others_line_width", &m_DesignSettings.m_LineThickness[ LAYER_CLASS_OTHERS ], Millimeter2iu( DEFAULT_SILK_LINE_WIDTH ), Millimeter2iu( 0.01 ), Millimeter2iu( 5.0 ), MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.others_text_size_h", &m_DesignSettings.m_TextSize[ LAYER_CLASS_OTHERS ].x, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.others_text_size_v", &m_DesignSettings.m_TextSize[ LAYER_CLASS_OTHERS ].y, Millimeter2iu( DEFAULT_TEXT_SIZE ), TEXTS_MIN_SIZE, TEXTS_MAX_SIZE, MM_PER_IU ) ); m_params.emplace_back( new PARAM_SCALED( "design_settings.others_text_thickness", &m_DesignSettings.m_TextThickness[ LAYER_CLASS_OTHERS ], Millimeter2iu( DEFAULT_TEXT_WIDTH ), 1, TEXTS_MAX_WIDTH, MM_PER_IU ) ); m_params.emplace_back( new PARAM( "design_settings.others_text_italic", &m_DesignSettings.m_TextItalic[ LAYER_CLASS_OTHERS ], false ) ); m_params.emplace_back( new PARAM_LAMBDA( "editing.selection_filter", [&]() -> nlohmann::json { nlohmann::json ret; ret["lockedItems"] = m_SelectionFilter.lockedItems; ret["footprints"] = m_SelectionFilter.footprints; ret["text"] = m_SelectionFilter.text; ret["tracks"] = m_SelectionFilter.tracks; ret["vias"] = m_SelectionFilter.vias; ret["pads"] = m_SelectionFilter.pads; ret["graphics"] = m_SelectionFilter.graphics; ret["zones"] = m_SelectionFilter.zones; ret["keepouts"] = m_SelectionFilter.keepouts; ret["dimensions"] = m_SelectionFilter.dimensions; ret["otherItems"] = m_SelectionFilter.otherItems; return ret; }, [&]( const nlohmann::json& aVal ) { if( aVal.empty() || !aVal.is_object() ) return; auto setIfPresent = [&aVal]( const std::string& aKey, bool& aTarget ) { if( aVal.contains( aKey ) && aVal.at( aKey ).is_boolean() ) aTarget = aVal.at( aKey ).get(); }; setIfPresent( "lockedItems", m_SelectionFilter.lockedItems ); setIfPresent( "footprints", m_SelectionFilter.footprints ); setIfPresent( "text", m_SelectionFilter.text ); setIfPresent( "tracks", m_SelectionFilter.tracks ); setIfPresent( "vias", m_SelectionFilter.vias ); setIfPresent( "pads", m_SelectionFilter.pads ); setIfPresent( "graphics", m_SelectionFilter.graphics ); setIfPresent( "zones", m_SelectionFilter.zones ); setIfPresent( "keepouts", m_SelectionFilter.keepouts ); setIfPresent( "dimensions", m_SelectionFilter.dimensions ); setIfPresent( "otherItems", m_SelectionFilter.otherItems ); }, { { "lockedItems", true }, { "footprints", true }, { "text", true }, { "tracks", true }, { "vias", true }, { "pads", true }, { "graphics", true }, { "zones", true }, { "keepouts", true }, { "dimensions", true }, { "otherItems", true } } ) ); } bool FOOTPRINT_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg ) { bool ret = APP_SETTINGS_BASE::MigrateFromLegacy( aCfg ); // // NOTE: there's no value in line-wrapping these; it just makes the table unreadable. // ret &= fromLegacy( aCfg, "ModeditLibWidth", "window.lib_width" ); ret &= fromLegacyString( aCfg, "import_last_path", "system.last_import_export_path" ); ret &= fromLegacyString( aCfg, "LibFootprintTextShownColumns", "window.footprint_text_shown_columns" ); ret &= fromLegacy( aCfg, "FpEditorMagneticPads", "editing.magnetic_pads" ); ret &= fromLegacy( aCfg, "FpEditorDisplayPolarCoords", "editing.polar_coords" ); ret &= fromLegacy( aCfg, "FpEditorUse45DegreeGraphicSegments", "editing.use_45_degree_graphic_segments" ); ret &= fromLegacy( aCfg, "FpEditorGraphicLinesDisplayMode", "pcb_display.graphic_items_fill" ); ret &= fromLegacy( aCfg, "FpEditorPadDisplayMode", "pcb_display.pad_fill" ); ret &= fromLegacy( aCfg, "FpEditorTextsDisplayMode", "pcb_display.footprint_text" ); ret &= fromLegacy( aCfg, "FpEditorSilkLineWidth", "design_settings.silk_line_width" ); ret &= fromLegacy( aCfg, "FpEditorSilkTextSizeH", "design_settings.silk_text_size_h" ); ret &= fromLegacy( aCfg, "FpEditorSilkTextSizeV", "design_settings.silk_text_size_v" ); ret &= fromLegacy( aCfg, "FpEditorSilkTextThickness", "design_settings.silk_text_thickness" ); ret &= fromLegacy( aCfg, "FpEditorSilkTextItalic", "design_settings.silk_text_italic" ); ret &= fromLegacy( aCfg, "FpEditorCopperLineWidth", "design_settings.copper_line_width" ); ret &= fromLegacy( aCfg, "FpEditorCopperTextSizeH", "design_settings.copper_text_size_h" ); ret &= fromLegacy( aCfg, "FpEditorCopperTextSizeV", "design_settings.copper_text_size_v" ); ret &= fromLegacy( aCfg, "FpEditorCopperTextThickness", "design_settings.copper_text_thickness" ); ret &= fromLegacy( aCfg, "FpEditorCopperTextItalic", "design_settings.copper_text_italic" ); ret &= fromLegacy( aCfg, "FpEditorEdgeCutLineWidth", "design_settings.edge_line_width" ); ret &= fromLegacy( aCfg, "FpEditorCourtyardLineWidth", "design_settings.courtyard_line_width" ); ret &= fromLegacy( aCfg, "FpEditorOthersLineWidth", "design_settings.others_line_width" ); ret &= fromLegacy( aCfg, "FpEditorOthersTextSizeH", "design_settings.others_text_size_h" ); ret &= fromLegacy( aCfg, "FpEditorOthersTextSizeV", "design_settings.others_text_size_v" ); ret &= fromLegacy( aCfg, "FpEditorOthersTextThickness", "design_settings.others_text_thickness" ); ret &= fromLegacy( aCfg, "FpEditorOthersTextItalic", "design_settings.others_text_italic" ); nlohmann::json textItems = nlohmann::json::array( { { "REF**", true, F_SilkS }, { "", true, F_Fab } } ); ( *this )[PointerFromString( "design_settings.default_footprint_text_items" )] = textItems; ret &= fromLegacyString( aCfg, "FpEditorRefDefaultText", "design_settings.default_footprint_text_items.0.0" ); ret &= fromLegacy( aCfg, "FpEditorRefDefaultVisibility", "design_settings.default_footprint_text_items.0.1" ); ret &= fromLegacy( aCfg, "FpEditorRefDefaultLayer", "design_settings.default_footprint_text_items.0.2" ); ret &= fromLegacyString( aCfg, "FpEditorValueDefaultText", "design_settings.default_footprint_text_items.1.0" ); ret &= fromLegacy( aCfg, "FpEditorValueDefaultVisibility", "design_settings.default_footprint_text_items.1.1" ); ret &= fromLegacy( aCfg, "FpEditorValueDefaultLayer", "design_settings.default_footprint_text_items.1.2" ); std::string f = "ModEdit"; // Migrate color settings that were stored in the pcbnew config file // We create a copy of the user scheme for the footprint editor context SETTINGS_MANAGER& manager = Pgm().GetSettingsManager(); COLOR_SETTINGS* cs = manager.AddNewColorSettings( "user_footprints" ); cs->SetName( wxT( "KiCad Default (Footprints)" ) ); manager.Save( cs ); auto migrateLegacyColor = [&] ( const std::string& aKey, int aLayerId ) { wxString str; if( aCfg->Read( aKey, &str ) ) cs->SetColor( aLayerId, COLOR4D( str ) ); }; for( int i = 0; i < PCB_LAYER_ID_COUNT; ++i ) { wxString layer = LSET::Name( PCB_LAYER_ID( i ) ); migrateLegacyColor( f + "Color4DPCBLayer_" + layer.ToStdString(), PCB_LAYER_ID( i ) ); } migrateLegacyColor( f + "Color4DAnchorEx", LAYER_ANCHOR ); migrateLegacyColor( f + "Color4DAuxItems", LAYER_AUX_ITEMS ); migrateLegacyColor( f + "Color4DGrid", LAYER_GRID ); migrateLegacyColor( f + "Color4DNoNetPadMarker", LAYER_NO_CONNECTS ); migrateLegacyColor( f + "Color4DNonPlatedEx", LAYER_NON_PLATEDHOLES ); migrateLegacyColor( f + "Color4DPadBackEx", LAYER_PAD_BK ); migrateLegacyColor( f + "Color4DPadFrontEx", LAYER_PAD_FR ); migrateLegacyColor( f + "Color4DPadThruHoleEx", LAYER_PADS_TH ); migrateLegacyColor( f + "Color4DPCBBackground", LAYER_PCB_BACKGROUND ); migrateLegacyColor( f + "Color4DPCBCursor", LAYER_CURSOR ); migrateLegacyColor( f + "Color4DRatsEx", LAYER_RATSNEST ); migrateLegacyColor( f + "Color4DTxtInvisEx", LAYER_MOD_TEXT_INVISIBLE ); migrateLegacyColor( f + "Color4DViaBBlindEx", LAYER_VIA_BBLIND ); migrateLegacyColor( f + "Color4DViaMicroEx", LAYER_VIA_MICROVIA ); migrateLegacyColor( f + "Color4DViaThruEx", LAYER_VIA_THROUGH ); migrateLegacyColor( f + "Color4DWorksheet", LAYER_WORKSHEET ); manager.SaveColorSettings( cs, "board" ); ( *this )[PointerFromString( "appearance.color_theme" )] = "user_footprints"; double x, y; f = "ModEditFrame"; if( aCfg->Read( f + "PcbUserGrid_X", &x ) && aCfg->Read( f + "PcbUserGrid_Y", &y ) ) { EDA_UNITS u = static_cast( aCfg->ReadLong( f + "PcbUserGrid_Unit", static_cast( EDA_UNITS::INCHES ) ) ); // Convert to internal units x = From_User_Unit( u, x ); y = From_User_Unit( u, y ); ( *this )[PointerFromString( "window.grid.user_grid_x" )] = StringFromValue( u, x, true, true ); ( *this )[PointerFromString( "window.grid.user_grid_y" )] = StringFromValue( u, y, true, true ); } return ret; } bool FOOTPRINT_EDITOR_SETTINGS::Migrate() { bool ret = true; int filever = at( PointerFromString( "meta.version" ) ).get(); if( filever == 0 ) { ret &= migrateSchema0to1(); if( ret ) { ( *this )[PointerFromString( "meta.version" )] = 1; } } return ret; } bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1() { /** * Schema version 0 to 1: * * - Check to see if a footprints version of the currently selected theme exists. * - If so, select it */ if( !m_manager ) { wxLogTrace( traceSettings, "Error: FOOTPRINT_EDITOR_SETTINGS migration cannot run unmanaged!" ); return false; } nlohmann::json::json_pointer theme_ptr( "/appearance/color_theme" ); wxString selected = at( theme_ptr ).get(); wxString search = selected + wxT( "_footprints" ); for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() ) { if( settings->GetFilename() == search ) { wxLogTrace( traceSettings, "Updating footprint editor theme from %s to %s", selected, search ); ( *this )[theme_ptr] = search; return true; } } return true; }