From 21f2b235cea10e4d41dce72eeb3ab778088ce962 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 23 Aug 2021 19:58:18 +0100 Subject: [PATCH] Rework stackup colors a bit to support opacity for 3D viewer. Fixes https://gitlab.com/kicad/code/kicad/issues/9012 --- .../panel_board_stackup.cpp | 137 +++++++++--------- .../panel_board_stackup.h | 2 +- .../stackup_predefined_prms.h | 50 +++++-- pcbnew/plugins/kicad/pcb_parser.cpp | 13 +- 4 files changed, 123 insertions(+), 79 deletions(-) diff --git a/pcbnew/board_stackup_manager/panel_board_stackup.cpp b/pcbnew/board_stackup_manager/panel_board_stackup.cpp index 220c45bbe6..5e75d892dc 100644 --- a/pcbnew/board_stackup_manager/panel_board_stackup.cpp +++ b/pcbnew/board_stackup_manager/panel_board_stackup.cpp @@ -97,13 +97,13 @@ PANEL_SETUP_BOARD_STACKUP::PANEL_SETUP_BOARD_STACKUP( PAGED_DIALOG* aParent, PCB m_colorIconsSize = dc.GetTextExtent( "XXXX" ); // Calculates a good size for wxTextCtrl to enter Epsilon R and Loss tan - // ("0.000000" + margins) - m_numericFieldsSize = dc.GetTextExtent( "X.XXXXXX" ); + // ("0.0000000" + margins) + m_numericFieldsSize = dc.GetTextExtent( "X.XXXXXXX" ); m_numericFieldsSize.y = -1; // Use default for the vertical size // Calculates a minimal size for wxTextCtrl to enter a dim with units // ("000.0000000 mils" + margins) - m_numericTextCtrlSize = dc.GetTextExtent( "XXX.XXXXXX mils" ); + m_numericTextCtrlSize = dc.GetTextExtent( "XXX.XXXXXXX mils" ); m_numericTextCtrlSize.y = -1; // Use default for the vertical size // The grid column containing the lock checkbox is kept to a minimal @@ -412,15 +412,17 @@ void PANEL_SETUP_BOARD_STACKUP::onExportToClipboard( wxCommandEvent& event ) wxColor PANEL_SETUP_BOARD_STACKUP::GetSelectedColor( int aRow ) const { - wxBitmapComboBox* choice = dynamic_cast( m_rowUiItemsList[aRow].m_ColorCtrl ); + const BOARD_STACKUP_ROW_UI_ITEM& row = m_rowUiItemsList[aRow]; + const BOARD_STACKUP_ITEM* item = row.m_Item; + const wxBitmapComboBox* choice = dynamic_cast( row.m_ColorCtrl ); wxASSERT( choice ); int idx = choice ? choice->GetSelection() : 0; if( idx != GetColorUserDefinedListIdx() ) // a standard color is selected - return GetColorStandardList()[idx].m_Color; - - return m_rowUiItemsList[aRow].m_UserColor; + return GetColorStandardList()[idx].GetColor( item->GetType() ); + else + return m_rowUiItemsList[aRow].m_UserColor; } @@ -472,7 +474,8 @@ void PANEL_SETUP_BOARD_STACKUP::updateCopperLayerCount() void PANEL_SETUP_BOARD_STACKUP::synchronizeWithBoard( bool aFullSync ) { - const BOARD_STACKUP& brd_stackup = m_brdSettings->GetStackupDescriptor(); + const BOARD_STACKUP& brd_stackup = m_brdSettings->GetStackupDescriptor(); + const FAB_LAYER_COLOR* color_list = GetColorStandardList(); if( aFullSync ) { @@ -526,41 +529,38 @@ void PANEL_SETUP_BOARD_STACKUP::synchronizeWithBoard( bool aFullSync ) if( item->IsColorEditable() ) { auto bm_combo = dynamic_cast( ui_row_item.m_ColorCtrl ); - int color_idx = 0; if( item->GetColor().StartsWith( "#" ) ) // User defined color { - wxColour color( item->GetColor() ); - ui_row_item.m_UserColor = color; - color_idx = GetColorUserDefinedListIdx(); + ui_row_item.m_UserColor = wxColour( item->GetColor() ); if( bm_combo ) // Update user color shown in the wxBitmapComboBox { - wxString label = wxString::Format( _( "Custom (%s)" ), - color.GetAsString( wxC2S_HTML_SYNTAX ) ); - - bm_combo->SetString( color_idx, label ); + bm_combo->SetString( GetColorUserDefinedListIdx(), item->GetColor() ); wxBitmap layerbmp( m_colorSwatchesSize.x, m_colorSwatchesSize.y ); - LAYER_SELECTOR::DrawColorSwatch( layerbmp, COLOR4D(), COLOR4D( color ) ); - bm_combo->SetItemBitmap( color_idx, layerbmp ); + LAYER_SELECTOR::DrawColorSwatch( layerbmp, COLOR4D(), + wxColour( item->GetColor() ) ); + bm_combo->SetItemBitmap( GetColorUserDefinedListIdx(), layerbmp ); + bm_combo->SetSelection( GetColorUserDefinedListIdx() ); } } else { - const FAB_LAYER_COLOR* color_list = GetColorStandardList(); - - for( int ii = 0; ii < GetColorStandardListCount(); ii++ ) + if( bm_combo ) { - if( color_list[ii].m_ColorName == item->GetColor() ) + // Note: don't use bm_combo->FindString() because the combo strings are + // translated. + for( int ii = 0; ii < GetColorStandardListCount(); ii++ ) { - color_idx = ii; - break; + if( color_list[ii].GetName() == item->GetColor() ) + { + bm_combo->SetSelection( ii ); + break; + } } } } - if( bm_combo ) - bm_combo->SetSelection( color_idx ); } if( item->HasEpsilonRValue() ) @@ -785,33 +785,32 @@ BOARD_STACKUP_ROW_UI_ITEM PANEL_SETUP_BOARD_STACKUP::createRowData( int aRow, if( item->IsColorEditable() ) { - int color_idx = 0; - int user_color_idx = GetColorUserDefinedListIdx(); - - // Always init the user-defined color for a row - ui_row_item.m_UserColor = GetColorStandardList()[user_color_idx].m_Color; - if( item->GetColor().StartsWith( "#" ) ) // User defined color + ui_row_item.m_UserColor = wxColour( item->GetColor() ); + else + ui_row_item.m_UserColor = GetDefaultUserColor( item->GetType() ); + + wxBitmapComboBox* bm_combo = createColorBox( item, row ); + m_fgGridSizer->Add( bm_combo, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL|wxEXPAND, 2 ); + + if( item->GetColor().StartsWith( "#" ) ) { - wxColour color( item->GetColor() ); - ui_row_item.m_UserColor = color; - color_idx = user_color_idx; + bm_combo->SetString( GetColorUserDefinedListIdx(), item->GetColor() ); + bm_combo->SetSelection( GetColorUserDefinedListIdx() ); } else { + // Note: don't use bm_combo->FindString() because the combo strings are translated. for( int ii = 0; ii < GetColorStandardListCount(); ii++ ) { - if( color_list[ii].m_ColorName == item->GetColor() ) + if( color_list[ii].GetName() == item->GetColor() ) { - color_idx = ii; + bm_combo->SetSelection( ii ); break; } } } - wxBitmapComboBox* bm_combo = createBmComboBox( item, row ); - m_fgGridSizer->Add( bm_combo, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 2 ); - bm_combo->SetSelection( color_idx ); ui_row_item.m_ColorCtrl = bm_combo; } else @@ -1116,7 +1115,7 @@ bool PANEL_SETUP_BOARD_STACKUP::transferDataFromUIToStackup() } else { - item->SetColor( color_list[idx].m_ColorName ); + item->SetColor( color_list[idx].GetName() ); } } } @@ -1240,34 +1239,31 @@ void PANEL_SETUP_BOARD_STACKUP::onColorSelected( wxCommandEvent& event ) int row = item_id - ID_ITEM_COLOR; - if( GetColorStandardListCount()-1 == idx ) // Set user color is the last option in list + if( idx == GetColorStandardListCount() - 1 ) // Set user color is the last option in list { - wxColour userColour = m_rowUiItemsList[row].m_UserColor; - COLOR4D currentColor( userColour.IsOk() ? userColour : COLOR4D( 0.5, 0.5, 0.5, 1.0 ) ); - COLOR4D defaultColor( GetColorStandardList()[GetColorUserDefinedListIdx()].m_Color ); - - DIALOG_COLOR_PICKER dlg( this, currentColor, false, nullptr, defaultColor ); + DIALOG_COLOR_PICKER dlg( this, m_rowUiItemsList[row].m_UserColor, true, nullptr, + GetDefaultUserColor( m_rowUiItemsList[row].m_Item->GetType() ) ); +#ifdef __WXGTK__ // Give a time-slice to close the menu before opening the dialog. // (Only matters on some versions of GTK.) wxSafeYield(); +#endif if( dlg.ShowModal() == wxID_OK ) { wxBitmapComboBox* combo = static_cast( FindWindowById( item_id ) ); - - wxColour color = dlg.GetColor().ToColour(); + wxColour color = dlg.GetColor().ToColour(); m_rowUiItemsList[row].m_UserColor = color; - wxString label = wxString::Format( _( "Custom (%s)" ), - color.GetAsString( wxC2S_HTML_SYNTAX ) ); - - combo->SetString( idx, label ); + combo->SetString( idx, color.GetAsString( wxC2S_HTML_SYNTAX ) ); wxBitmap layerbmp( m_colorSwatchesSize.x, m_colorSwatchesSize.y ); LAYER_SELECTOR::DrawColorSwatch( layerbmp, COLOR4D( 0, 0, 0, 0 ), COLOR4D( color ) ); combo->SetItemBitmap( combo->GetCount()-1, layerbmp ); + + combo->SetSelection( idx ); } } @@ -1447,35 +1443,38 @@ void PANEL_SETUP_BOARD_STACKUP::updateIconColor( int aRow ) } -wxBitmapComboBox* PANEL_SETUP_BOARD_STACKUP::createBmComboBox( BOARD_STACKUP_ITEM* aStackupItem, - int aRow ) +wxBitmapComboBox* PANEL_SETUP_BOARD_STACKUP::createColorBox( BOARD_STACKUP_ITEM* aStackupItem, + int aRow ) { wxBitmapComboBox* combo = new wxBitmapComboBox( m_scGridWin, ID_ITEM_COLOR + aRow, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY ); // Fills the combo box with choice list + bitmaps - const FAB_LAYER_COLOR* color_list = GetColorStandardList(); + const FAB_LAYER_COLOR* color_list = GetColorStandardList(); + BOARD_STACKUP_ITEM_TYPE itemType = aStackupItem ? aStackupItem->GetType() + : BS_ITEM_TYPE_SILKSCREEN; for( int ii = 0; ii < GetColorStandardListCount(); ii++ ) { - const FAB_LAYER_COLOR& item = color_list[ii]; - - wxColor curr_color = item.m_Color; + wxColor curr_color; wxString label; // Defined colors have a name, the user color uses the HTML notation ( i.e. #FF0000) - if( GetColorStandardListCount()-1 > (int)combo->GetCount() ) - { - label = wxGetTranslation( item.m_ColorName ); - } - else // Append the user color, if specified, else add a default user color + if( ii == GetColorUserDefinedListIdx() ) { if( aStackupItem && aStackupItem->GetColor().StartsWith( "#" ) ) curr_color = wxColour( aStackupItem->GetColor() ); + else + curr_color = color_list[ii].GetColor( itemType ); - label = wxString::Format( _( "Custom (%s)" ), - curr_color.GetAsString( wxC2S_HTML_SYNTAX ) ); + label = _( curr_color.GetAsString( wxC2S_HTML_SYNTAX ) ); + } + else // Append the user color, if specified, else add a default user color + { + curr_color = color_list[ii].GetColor( itemType ); + + label = wxGetTranslation( color_list[ii].GetName() ); } wxBitmap layerbmp( m_colorSwatchesSize.x, m_colorSwatchesSize.y ); @@ -1507,6 +1506,12 @@ wxBitmapComboBox* PANEL_SETUP_BOARD_STACKUP::createBmComboBox( BOARD_STACKUP_ITE wxCommandEventHandler( PANEL_SETUP_BOARD_STACKUP::onColorSelected ), nullptr, this ); + combo->Bind( wxEVT_COMBOBOX_DROPDOWN, + [combo]( wxCommandEvent& aEvent ) + { + combo->SetString( combo->GetCount() - 1, _( "Custom..." ) ); + } ); + return combo; } diff --git a/pcbnew/board_stackup_manager/panel_board_stackup.h b/pcbnew/board_stackup_manager/panel_board_stackup.h index b1882792ff..5abefbf0de 100644 --- a/pcbnew/board_stackup_manager/panel_board_stackup.h +++ b/pcbnew/board_stackup_manager/panel_board_stackup.h @@ -221,7 +221,7 @@ private: * can be nullptr * @param aRow = the row index in the wxFlexGridSizer (used to build a wxWidget unique id) */ - wxBitmapComboBox* createBmComboBox( BOARD_STACKUP_ITEM* aStackupItem, int aRow ); + wxBitmapComboBox* createColorBox( BOARD_STACKUP_ITEM* aStackupItem, int aRow ); /** * disconnect event handlers connected to wxControl items diff --git a/pcbnew/board_stackup_manager/stackup_predefined_prms.h b/pcbnew/board_stackup_manager/stackup_predefined_prms.h index 1a335ce94d..a75e5514d4 100644 --- a/pcbnew/board_stackup_manager/stackup_predefined_prms.h +++ b/pcbnew/board_stackup_manager/stackup_predefined_prms.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2009-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2009-2021 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 @@ -36,6 +36,9 @@ #include #include // For _HKI definition +#include + +#include // Keyword used in file to identify the dielectric layer type #define KEY_CORE "core" @@ -44,8 +47,7 @@ #define KEY_COPPER "copper" // key string used for not specified parameters -// Can be translated in dialogs, and is also a keyword -// outside dialogs +// Can be translated in dialogs, and is also a keyword outside dialogs wxString inline NotSpecifiedPrm() { return _HKI( "Not specified" ); @@ -58,6 +60,8 @@ wxString inline NotSpecifiedPrm() */ bool IsPrmSpecified( const wxString& aPrmValue ); +#define DEFAULT_SOLDERMASK_OPACITY 0.83 + // A reasonable Epsilon R value for solder mask dielectric #define DEFAULT_EPSILON_R_SOLDERMASK 3.3 @@ -65,16 +69,34 @@ bool IsPrmSpecified( const wxString& aPrmValue ); #define DEFAULT_EPSILON_R_SILKSCREEN 1.0 // A minor struct to handle color in gerber job file and dialog -struct FAB_LAYER_COLOR +class FAB_LAYER_COLOR { - wxString m_ColorName; // the name (in job file) of the color - // User values are the HTML coding #rrggbb hexa value. - wxColor m_Color; // the color in r,g,b values (0..255) - - FAB_LAYER_COLOR() {} - FAB_LAYER_COLOR( const wxString& aColorName, const wxColor& aColor ) - : m_ColorName( aColorName ), m_Color( aColor ) +public: + FAB_LAYER_COLOR() {} + + FAB_LAYER_COLOR( const wxString& aColorName, const wxColor& aColor ) : + m_colorName( aColorName ), + m_color( aColor ) + {} + + const wxString& GetName() const + { + return m_colorName; + } + + wxColor GetColor( BOARD_STACKUP_ITEM_TYPE aItemType ) const + { + if( aItemType == BS_ITEM_TYPE_SOLDERMASK ) + return m_color.WithAlpha( DEFAULT_SOLDERMASK_OPACITY ).ToColour(); + else + return m_color.WithAlpha( 1.0 ).ToColour(); + } + +private: + wxString m_colorName; // the name (in job file) of the color + // User values are the HTML coding #rrggbbaa hexadecimal value. + KIGFX::COLOR4D m_color; }; @@ -99,4 +121,10 @@ int GetColorStandardListCount(); */ int GetColorUserDefinedListIdx(); +inline wxColour GetDefaultUserColor( BOARD_STACKUP_ITEM_TYPE aType ) +{ + return GetColorStandardList()[GetColorUserDefinedListIdx()].GetColor( aType ); +} + + #endif // #ifndef STACKUP_PREDEFINED_PRMS_H diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index a112f708ca..8357e2b2a7 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -1474,7 +1474,18 @@ void PCB_PARSER::parseBoardStackup() case T_color: NeedSYMBOL(); - item->SetColor( FromUTF8() ); + name = FromUTF8(); + + // Older versions didn't always store opacity with colors + if( name.StartsWith( "#" ) && name.Length() < 9 ) + { + if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK ) + name += "FF"; + else + name += "D3"; + } + + item->SetColor( name ); NeedRIGHT(); break;