/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 Jon Evans * Copyright (C) 2021-2023 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 "builtin_color_themes.h" ///! Update the schema version whenever a migration is required const int colorsSchemaVersion = 5; const wxString COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT = "_builtin_default"; const wxString COLOR_SETTINGS::COLOR_BUILTIN_CLASSIC = "_builtin_classic"; COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath ) : JSON_SETTINGS( aFilename, SETTINGS_LOC::COLORS, colorsSchemaVersion ), m_overrideSchItemColors( false ) { if( aAbsolutePath ) SetLocation( SETTINGS_LOC::NONE ); m_params.emplace_back( new PARAM( "meta.name", &m_displayName, wxS( "KiCad Default" ) ) ); m_params.emplace_back( new PARAM( "schematic.override_item_colors", &m_overrideSchItemColors, false ) ); #define CLR( x, y ) \ wxASSERT( s_defaultTheme.count( y ) ); \ m_params.emplace_back( new COLOR_MAP_PARAM( x, y, s_defaultTheme.at( y ), &m_colors ) ); CLR( "schematic.anchor", LAYER_SCHEMATIC_ANCHOR ); CLR( "schematic.aux_items", LAYER_SCHEMATIC_AUX_ITEMS ); CLR( "schematic.background", LAYER_SCHEMATIC_BACKGROUND ); CLR( "schematic.hovered", LAYER_HOVERED ); CLR( "schematic.brightened", LAYER_BRIGHTENED ); CLR( "schematic.bus", LAYER_BUS ); CLR( "schematic.bus_junction", LAYER_BUS_JUNCTION ); CLR( "schematic.component_body", LAYER_DEVICE_BACKGROUND ); CLR( "schematic.component_outline", LAYER_DEVICE ); CLR( "schematic.cursor", LAYER_SCHEMATIC_CURSOR ); CLR( "schematic.dnp_marker", LAYER_DNP_MARKER ); CLR( "schematic.excluded_from_sim", LAYER_EXCLUDED_FROM_SIM ); CLR( "schematic.erc_error", LAYER_ERC_ERR ); CLR( "schematic.erc_warning", LAYER_ERC_WARN ); CLR( "schematic.erc_exclusion", LAYER_ERC_EXCLUSION ); CLR( "schematic.fields", LAYER_FIELDS ); CLR( "schematic.grid", LAYER_SCHEMATIC_GRID ); CLR( "schematic.grid_axes", LAYER_SCHEMATIC_GRID_AXES ); CLR( "schematic.hidden", LAYER_HIDDEN ); CLR( "schematic.junction", LAYER_JUNCTION ); CLR( "schematic.label_global", LAYER_GLOBLABEL ); CLR( "schematic.label_hier", LAYER_HIERLABEL ); CLR( "schematic.label_local", LAYER_LOCLABEL ); CLR( "schematic.netclass_flag", LAYER_NETCLASS_REFS ); CLR( "schematic.rule_area", LAYER_RULE_AREAS ); CLR( "schematic.no_connect", LAYER_NOCONNECT ); CLR( "schematic.note", LAYER_NOTES ); CLR( "schematic.private_note", LAYER_PRIVATE_NOTES ); CLR( "schematic.note_background", LAYER_NOTES_BACKGROUND ); CLR( "schematic.pin", LAYER_PIN ); CLR( "schematic.pin_name", LAYER_PINNAM ); CLR( "schematic.pin_number", LAYER_PINNUM ); CLR( "schematic.reference", LAYER_REFERENCEPART ); CLR( "schematic.shadow", LAYER_SELECTION_SHADOWS ); CLR( "schematic.sheet", LAYER_SHEET ); CLR( "schematic.sheet_background", LAYER_SHEET_BACKGROUND ); CLR( "schematic.sheet_filename", LAYER_SHEETFILENAME ); CLR( "schematic.sheet_fields", LAYER_SHEETFIELDS ); CLR( "schematic.sheet_label", LAYER_SHEETLABEL ); CLR( "schematic.sheet_name", LAYER_SHEETNAME ); CLR( "schematic.value", LAYER_VALUEPART ); CLR( "schematic.wire", LAYER_WIRE ); CLR( "schematic.worksheet", LAYER_SCHEMATIC_DRAWINGSHEET ); CLR( "schematic.page_limits", LAYER_SCHEMATIC_PAGE_LIMITS ); CLR( "schematic.op_voltages", LAYER_OP_VOLTAGES ); CLR( "schematic.op_currents", LAYER_OP_CURRENTS ); CLR( "gerbview.axes", LAYER_GERBVIEW_AXES ); CLR( "gerbview.background", LAYER_GERBVIEW_BACKGROUND ); CLR( "gerbview.dcodes", LAYER_DCODES ); CLR( "gerbview.grid", LAYER_GERBVIEW_GRID ); CLR( "gerbview.negative_objects", LAYER_NEGATIVE_OBJECTS ); CLR( "gerbview.worksheet", LAYER_GERBVIEW_DRAWINGSHEET ); CLR( "gerbview.page_limits", LAYER_GERBVIEW_PAGE_LIMITS ); for( int i = 0, id = GERBVIEW_LAYER_ID_START; id < GERBER_DRAWLAYERS_COUNT + GERBVIEW_LAYER_ID_START; ++i, ++id ) { m_params.emplace_back( new COLOR_MAP_PARAM( "gerbview.layers." + std::to_string( i ), id, s_defaultTheme.at( id ), &m_colors ) ); } CLR( "board.anchor", LAYER_ANCHOR ); CLR( "board.locked_shadow", LAYER_LOCKED_ITEM_SHADOW ); CLR( "board.conflicts_shadow", LAYER_CONFLICTS_SHADOW ); CLR( "board.aux_items", LAYER_AUX_ITEMS ); CLR( "board.background", LAYER_PCB_BACKGROUND ); CLR( "board.cursor", LAYER_CURSOR ); CLR( "board.drc_error", LAYER_DRC_ERROR ); CLR( "board.drc_warning", LAYER_DRC_WARNING ); CLR( "board.drc_exclusion", LAYER_DRC_EXCLUSION ); CLR( "board.footprint_text_invisible", LAYER_HIDDEN_TEXT ); CLR( "board.grid", LAYER_GRID ); CLR( "board.grid_axes", LAYER_GRID_AXES ); CLR( "board.pad_plated_hole", LAYER_PAD_PLATEDHOLES ); CLR( "board.pad_through_hole", LAYER_PADS_TH ); CLR( "board.plated_hole", LAYER_NON_PLATEDHOLES ); CLR( "board.ratsnest", LAYER_RATSNEST ); CLR( "board.via_blind_buried", LAYER_VIA_BBLIND ); CLR( "board.via_hole", LAYER_VIA_HOLES ); CLR( "board.via_micro", LAYER_VIA_MICROVIA ); CLR( "board.via_through", LAYER_VIA_THROUGH ); CLR( "board.worksheet", LAYER_DRAWINGSHEET ); CLR( "board.page_limits", LAYER_PAGE_LIMITS ); CLR( "board.copper.f", F_Cu ); CLR( "board.copper.in1", In1_Cu ); CLR( "board.copper.in2", In2_Cu ); CLR( "board.copper.in3", In3_Cu ); CLR( "board.copper.in4", In4_Cu ); CLR( "board.copper.in5", In5_Cu ); CLR( "board.copper.in6", In6_Cu ); CLR( "board.copper.in7", In7_Cu ); CLR( "board.copper.in8", In8_Cu ); CLR( "board.copper.in9", In9_Cu ); CLR( "board.copper.in10", In10_Cu ); CLR( "board.copper.in11", In11_Cu ); CLR( "board.copper.in12", In12_Cu ); CLR( "board.copper.in13", In13_Cu ); CLR( "board.copper.in14", In14_Cu ); CLR( "board.copper.in15", In15_Cu ); CLR( "board.copper.in16", In16_Cu ); CLR( "board.copper.in17", In17_Cu ); CLR( "board.copper.in18", In18_Cu ); CLR( "board.copper.in19", In19_Cu ); CLR( "board.copper.in20", In20_Cu ); CLR( "board.copper.in21", In21_Cu ); CLR( "board.copper.in22", In22_Cu ); CLR( "board.copper.in23", In23_Cu ); CLR( "board.copper.in24", In24_Cu ); CLR( "board.copper.in25", In25_Cu ); CLR( "board.copper.in26", In26_Cu ); CLR( "board.copper.in27", In27_Cu ); CLR( "board.copper.in28", In28_Cu ); CLR( "board.copper.in29", In29_Cu ); CLR( "board.copper.in30", In30_Cu ); CLR( "board.copper.b", B_Cu ); CLR( "board.b_adhes", B_Adhes ); CLR( "board.f_adhes", F_Adhes ); CLR( "board.b_paste", B_Paste ); CLR( "board.f_paste", F_Paste ); CLR( "board.b_silks", B_SilkS ); CLR( "board.f_silks", F_SilkS ); CLR( "board.b_mask", B_Mask ); CLR( "board.f_mask", F_Mask ); CLR( "board.dwgs_user", Dwgs_User ); CLR( "board.cmts_user", Cmts_User ); CLR( "board.eco1_user", Eco1_User ); CLR( "board.eco2_user", Eco2_User ); CLR( "board.edge_cuts", Edge_Cuts ); CLR( "board.margin", Margin ); CLR( "board.b_crtyd", B_CrtYd ); CLR( "board.f_crtyd", F_CrtYd ); CLR( "board.b_fab", B_Fab ); CLR( "board.f_fab", F_Fab ); CLR( "board.user_1", User_1 ); CLR( "board.user_2", User_2 ); CLR( "board.user_3", User_3 ); CLR( "board.user_4", User_4 ); CLR( "board.user_5", User_5 ); CLR( "board.user_6", User_6 ); CLR( "board.user_7", User_7 ); CLR( "board.user_8", User_8 ); CLR( "board.user_9", User_9 ); // Colors for 3D viewer, which are used as defaults unless overridden by the board CLR( "3d_viewer.background_bottom", LAYER_3D_BACKGROUND_BOTTOM ); CLR( "3d_viewer.background_top", LAYER_3D_BACKGROUND_TOP ); CLR( "3d_viewer.board", LAYER_3D_BOARD ); CLR( "3d_viewer.copper", LAYER_3D_COPPER_TOP ); CLR( "3d_viewer.silkscreen_bottom", LAYER_3D_SILKSCREEN_BOTTOM ); CLR( "3d_viewer.silkscreen_top", LAYER_3D_SILKSCREEN_TOP ); CLR( "3d_viewer.soldermask_bottom", LAYER_3D_SOLDERMASK_BOTTOM ); CLR( "3d_viewer.soldermask_top", LAYER_3D_SOLDERMASK_TOP ); CLR( "3d_viewer.solderpaste", LAYER_3D_SOLDERPASTE ); registerMigration( 0, 1, std::bind( &COLOR_SETTINGS::migrateSchema0to1, this ) ); registerMigration( 1, 2, [&]() { // Fix LAYER_VIA_HOLES color - before version 2, this setting had no effect nlohmann::json::json_pointer ptr( "/board/via_hole" ); ( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToCSSString(); return true; } ); registerMigration( 2, 3, [&]() { // We don't support opacity in some 3D colors but some versions of 5.99 let // you set it. for( std::string path : { "3d_viewer.background_top", "3d_viewer.background_bottom", "3d_viewer.copper", "3d_viewer.silkscreen_top", "3d_viewer.silkscreen_bottom", "3d_viewer.solderpaste" } ) { if( std::optional optval = Get( path ) ) Set( path, optval->WithAlpha( 1.0 ) ); } return true; } ); registerMigration( 3, 4, [&]() { if( std::optional optval = Get( "board.grid" ) ) Set( "board.page_limits", *optval ); if( std::optional optval = Get( "schematic.grid" ) ) Set( "schematic.page_limits", *optval ); return true; } ); // this bump shouldn't have happened; add a no-op migration to avoid future issues registerMigration( 4, 5, []() { return true; } ); } COLOR_SETTINGS::COLOR_SETTINGS( const COLOR_SETTINGS& aOther ) : JSON_SETTINGS( aOther.m_filename, SETTINGS_LOC::COLORS, colorsSchemaVersion ) { initFromOther( aOther ); } COLOR_SETTINGS& COLOR_SETTINGS::operator=( const COLOR_SETTINGS &aOther ) { m_filename = aOther.m_filename; initFromOther( aOther ); return *this; } void COLOR_SETTINGS::initFromOther( const COLOR_SETTINGS& aOther ) { m_displayName = aOther.m_displayName; m_overrideSchItemColors = aOther.m_overrideSchItemColors; m_colors = aOther.m_colors; m_defaultColors = aOther.m_defaultColors; m_writeFile = aOther.m_writeFile; // Ensure default colors are present for( PARAM_BASE* param : aOther.m_params ) { if( COLOR_MAP_PARAM* cmp = dynamic_cast( param ) ) m_defaultColors[cmp->GetKey()] = cmp->GetDefault(); } } bool COLOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg ) { return false; } bool COLOR_SETTINGS::migrateSchema0to1() { /** * Schema version 0 to 1: * * - Footprint editor settings are split out into a new file called "ThemeName (Footprints)" * - fpedit namespace is removed from the schema */ if( !m_manager ) { wxLogTrace( traceSettings, wxT( "Error: COLOR_SETTINGS migration cannot run unmanaged!" ) ); return false; } if( !Contains( "fpedit" ) ) { wxLogTrace( traceSettings, wxT( "migrateSchema0to1: %s doesn't have fpedit settings; skipping." ), m_filename ); return true; } wxString filename = GetFilename().BeforeLast( '.' ) + wxT( "_footprints" ); COLOR_SETTINGS* fpsettings = m_manager->AddNewColorSettings( filename ); fpsettings->SetLocation( GetLocation() ); // Start out with a clone fpsettings->m_internals->CloneFrom( *m_internals ); // Footprint editor now just looks at the "board" namespace fpsettings->Set( "board", fpsettings->At( "fpedit" ) ); fpsettings->Internals()->erase( "fpedit" ); fpsettings->Load(); fpsettings->SetName( fpsettings->GetName() + wxS( " " ) + _( "(Footprints)" ) ); m_manager->Save( fpsettings ); // Now we can get rid of our own copy m_internals->erase( "fpedit" ); return true; } COLOR4D COLOR_SETTINGS::GetColor( int aLayer ) const { if( m_colors.count( aLayer ) ) return m_colors.at( aLayer ); return COLOR4D::UNSPECIFIED; } COLOR4D COLOR_SETTINGS::GetDefaultColor( int aLayer ) { if( !m_defaultColors.count( aLayer ) ) { COLOR_MAP_PARAM* p = nullptr; for( PARAM_BASE* param : m_params ) { COLOR_MAP_PARAM* cmp = dynamic_cast( param ); if( cmp && cmp->GetKey() == aLayer ) p = cmp; } if( p ) m_defaultColors[aLayer] = p->GetDefault(); else m_defaultColors[aLayer] = COLOR4D::UNSPECIFIED; } return m_defaultColors.at( aLayer ); } void COLOR_SETTINGS::SetColor( int aLayer, const COLOR4D& aColor ) { m_colors[ aLayer ] = aColor; } std::vector COLOR_SETTINGS::CreateBuiltinColorSettings() { COLOR_SETTINGS* defaultTheme = new COLOR_SETTINGS( COLOR_BUILTIN_DEFAULT ); defaultTheme->SetName( _( "KiCad Default" ) ); defaultTheme->m_writeFile = false; defaultTheme->Load(); // We can just get the colors out of the param defaults for this one COLOR_SETTINGS* classicTheme = new COLOR_SETTINGS( COLOR_BUILTIN_CLASSIC ); classicTheme->SetName( _( "KiCad Classic" ) ); classicTheme->m_writeFile = false; for( PARAM_BASE* param : classicTheme->m_params ) delete param; classicTheme->m_params.clear(); // Disable load/store for( const std::pair entry : s_classicTheme ) classicTheme->m_colors[entry.first] = entry.second; std::vector ret; ret.push_back( defaultTheme ); ret.push_back( classicTheme ); return ret; }