KiCad PCB EDA Suite
panel_color_settings.cpp
Go to the documentation of this file.
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 (C) 2020 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 
21 #include <bitmaps.h>
23 #include <launch_ext.h>
25 #include <menus_helpers.h>
26 #include <panel_color_settings.h>
27 #include <pgm_base.h>
31 #include <validators.h>
32 #include <widgets/color_swatch.h>
33 
34 
35 // Button ID starting point
36 constexpr int FIRST_BUTTON_ID = 1800;
37 
38 
40  PANEL_COLOR_SETTINGS_BASE( aParent ),
41  m_currentSettings( nullptr ),
42  m_swatches(),
43  m_copied( COLOR4D::UNSPECIFIED ),
44  m_validLayers(),
45  m_backgroundLayer( LAYER_PCB_BACKGROUND ),
46  m_colorNamespace()
47 {
48 #ifdef __APPLE__
49  m_btnOpenFolder->SetLabel( _( "Reveal Themes in Finder" ) );
50 
51  // Simple border is too dark on OSX
52  m_colorsListWindow->SetWindowStyle( wxBORDER_SUNKEN|wxVSCROLL );
53 #endif
54 }
55 
56 
58 {
60  LaunchExternal( dir );
61 }
62 
63 
64 void PANEL_COLOR_SETTINGS::OnBtnResetClicked( wxCommandEvent& event )
65 {
66  if( !m_currentSettings )
67  return;
68 
69  for( const std::pair<const int, COLOR_SWATCH*>& pair : m_swatches )
70  {
71  int layer = pair.first;
72  COLOR_SWATCH* button = pair.second;
73 
74  COLOR4D defaultColor = m_currentSettings->GetDefaultColor( layer );
75 
76  m_currentSettings->SetColor( layer, defaultColor );
77  button->SetSwatchColor( defaultColor, false );
78  }
79 }
80 
81 
82 void PANEL_COLOR_SETTINGS::OnThemeChanged( wxCommandEvent& event )
83 {
84  int idx = m_cbTheme->GetSelection();
85 
86  if( idx == static_cast<int>( m_cbTheme->GetCount() ) - 2 )
87  {
88  // separator; re-select active theme
89  m_cbTheme->SetStringSelection( m_currentSettings->GetName() );
90  return;
91  }
92 
93  if( idx == (int)m_cbTheme->GetCount() - 1 )
94  {
95  // New Theme...
96 
97  if( !saveCurrentTheme( false ) )
98  return;
99 
100  MODULE_NAME_CHAR_VALIDATOR themeNameValidator;
101  wxTextEntryDialog dlg( this, _( "New theme name:" ), _( "Add Color Theme" ) );
102  dlg.SetTextValidator( themeNameValidator );
103 
104  if( dlg.ShowModal() != wxID_OK )
105  return;
106 
107  wxString themeName = dlg.GetValue();
108  wxFileName fn( themeName + wxT( ".json" ) );
110 
111  if( fn.Exists() )
112  {
113  wxMessageBox( _( "Theme already exists!" ) );
114  return;
115  }
116 
117  SETTINGS_MANAGER& settingsMgr = Pgm().GetSettingsManager();
118  COLOR_SETTINGS* newSettings = settingsMgr.AddNewColorSettings( themeName );
119  newSettings->SetName( themeName );
120 
121  for( auto layer : m_validLayers )
122  newSettings->SetColor( layer, m_currentSettings->GetColor( layer ) );
123 
124  newSettings->SaveToFile( settingsMgr.GetPathForSettingsFile( newSettings ) );
125 
126  idx = m_cbTheme->Insert( themeName, idx - 1, static_cast<void*>( newSettings ) );
127  m_cbTheme->SetSelection( idx );
128 
129  m_optOverrideColors->SetValue( newSettings->GetOverrideSchItemColors() );
130 
131  *m_currentSettings = *newSettings;
133  }
134  else
135  {
136  COLOR_SETTINGS* selected = static_cast<COLOR_SETTINGS*>( m_cbTheme->GetClientData( idx ) );
137 
138  if( selected->GetFilename() != m_currentSettings->GetFilename() )
139  {
140  if( !saveCurrentTheme( false ) )
141  return;
142 
143  m_optOverrideColors->SetValue( selected->GetOverrideSchItemColors() );
144 
145  *m_currentSettings = *selected;
147 
149 
150  for( std::pair<int, COLOR_SWATCH*> pair : m_swatches )
151  {
152  pair.second->SetSwatchBackground( background );
153  pair.second->SetSwatchColor( m_currentSettings->GetColor( pair.first ), false );
154 
155  if( pair.first == LAYER_SHEET || pair.first == LAYER_SHEET_BACKGROUND )
156  pair.second->Show( selected->GetOverrideSchItemColors() );
157  }
158  }
159  }
160 }
161 
162 
163 void PANEL_COLOR_SETTINGS::createThemeList( const wxString& aCurrent )
164 {
165  int width = 0;
166  int height = 0;
167 
168  m_cbTheme->GetTextExtent( _( "New Theme..." ), &width, &height );
169  int minwidth = width;
170 
171  m_cbTheme->Clear();
172 
173  for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
174  {
175  int pos = m_cbTheme->Append( settings->GetName(), static_cast<void*>( settings ) );
176 
177  if( settings->GetFilename() == aCurrent )
178  m_cbTheme->SetSelection( pos );
179 
180  m_cbTheme->GetTextExtent( settings->GetName(), &width, &height );
181  minwidth = std::max( minwidth, width );
182  }
183 
184  m_cbTheme->Append( wxT( "---" ) );
185  m_cbTheme->Append( _( "New Theme..." ) );
186 
187  m_cbTheme->SetMinSize( wxSize( minwidth + 50, -1 ) );
188 }
189 
190 
191 void PANEL_COLOR_SETTINGS::createSwatch( int aLayer, const wxString& aName )
192 {
193  wxStaticText* label = new wxStaticText( m_colorsListWindow, wxID_ANY, aName );
194 
195  void* clientData = m_cbTheme->GetClientData( m_cbTheme->GetSelection() );
196  COLOR_SETTINGS* selected = static_cast<COLOR_SETTINGS*>( clientData );
197  int id = FIRST_BUTTON_ID + aLayer;
198  COLOR4D defaultColor = selected->GetDefaultColor( aLayer );
200  COLOR4D backgroundColor = m_currentSettings->GetColor( m_backgroundLayer );
201 
202  COLOR_SWATCH* swatch = new COLOR_SWATCH( m_colorsListWindow, color, id, backgroundColor,
203  defaultColor, true );
204  swatch->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
205 
206  m_colorsGridSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxLEFT, 5 );
207  m_colorsGridSizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3 );
208 
209  m_labels[aLayer] = label;
210  m_swatches[aLayer] = swatch;
211 
212  swatch->Bind( wxEVT_RIGHT_DOWN,
213  [&, aLayer]( wxMouseEvent& aEvent )
214  {
215  ShowColorContextMenu( aEvent, aLayer );
216  } );
217  swatch->Bind( COLOR_SWATCH_CHANGED, &PANEL_COLOR_SETTINGS::OnColorChanged, this );
218 }
219 
220 
221 void PANEL_COLOR_SETTINGS::ShowColorContextMenu( wxMouseEvent& aEvent, int aLayer )
222 {
223  auto selected =
224  static_cast<COLOR_SETTINGS*>( m_cbTheme->GetClientData( m_cbTheme->GetSelection() ) );
225 
226  COLOR4D current = m_currentSettings->GetColor( aLayer );
227  COLOR4D saved = selected->GetColor( aLayer );
228 
229  wxMenu menu;
230 
231  AddMenuItem( &menu, ID_COPY, _( "Copy color" ), KiBitmap( copy_xpm ) );
232 
233  if( m_copied != COLOR4D::UNSPECIFIED )
234  AddMenuItem( &menu, ID_PASTE, _( "Paste color" ), KiBitmap( paste_xpm ) );
235 
236  if( current != saved )
237  AddMenuItem( &menu, ID_REVERT, _( "Revert to saved color" ), KiBitmap( undo_xpm ) );
238 
239  menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
240  [&]( wxCommandEvent& aCmd )
241  {
242  switch( aCmd.GetId() )
243  {
244  case ID_COPY:
245  m_copied = current;
246  break;
247 
248  case ID_PASTE:
249  updateColor( aLayer, m_copied );
250  break;
251 
252  case ID_REVERT:
253  updateColor( aLayer, saved );
254  break;
255 
256  default:
257  aCmd.Skip();
258  }
259  } );
260 
261  PopupMenu( &menu );
262 }
263 
264 
265 void PANEL_COLOR_SETTINGS::OnColorChanged( wxCommandEvent& aEvent )
266 {
267  COLOR_SWATCH* swatch = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
268  COLOR4D newColor = swatch->GetSwatchColor();
269  LAYER_NUM layer = static_cast<SCH_LAYER_ID>( swatch->GetId() - FIRST_BUTTON_ID );
270 
271  updateColor( layer, newColor );
272 }
273 
274 
275 void PANEL_COLOR_SETTINGS::updateColor( int aLayer, const KIGFX::COLOR4D& aColor )
276 {
277  if( m_currentSettings )
278  m_currentSettings->SetColor( aLayer, aColor );
279 
280  m_swatches[aLayer]->SetSwatchColor( aColor, false );
281 
282  if( aLayer == m_backgroundLayer )
283  {
285 
286  for( std::pair<int, COLOR_SWATCH*> pair : m_swatches )
287  pair.second->SetSwatchBackground( background );
288  }
289 
290  onColorChanged();
291 }
292 
293 
295 {
296  if( aValidate && !validateSave() )
297  return false;
298 
299  SETTINGS_MANAGER& settingsMgr = Pgm().GetSettingsManager();
300  COLOR_SETTINGS* selected = settingsMgr.GetColorSettings( m_currentSettings->GetFilename() );
301 
302  selected->SetOverrideSchItemColors( m_optOverrideColors->GetValue() );
303 
304  for( auto layer : m_validLayers )
305  selected->SetColor( layer, m_currentSettings->GetColor( layer ) );
306 
307  settingsMgr.SaveColorSettings( selected, m_colorNamespace );
308 
309  return true;
310 }
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
KIGFX::COLOR4D GetSwatchColor() const
virtual bool saveCurrentTheme(bool aValidate)
void SetSwatchColor(KIGFX::COLOR4D aColor, bool sendEvent)
Set the current swatch color directly.
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:250
int color
Definition: DXF_plotter.cpp:61
std::map< int, wxStaticText * > m_labels
virtual void onNewThemeSelected()
Event fired when a new theme is selected that can be overridden in children.
std::map< int, COLOR_SWATCH * > m_swatches
void updateColor(int aLayer, const KIGFX::COLOR4D &aColor)
const wxString & GetName() const
COLOR_SETTINGS * AddNewColorSettings(const wxString &aFilename)
Registers a new color settings object with the given filename.
std::string GetPathForSettingsFile(JSON_SETTINGS *aSettings)
Returns the path a given settings file should be loaded from / stored to.
void ShowColorContextMenu(wxMouseEvent &aEvent, int aLayer)
std::string m_colorNamespace
A namespace that will be passed to SETTINGS_MANAGER::SaveColorSettings.
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
Class PANEL_COLOR_SETTINGS_BASE.
void createThemeList(const wxString &aCurrent)
COLOR_SETTINGS * m_currentSettings
void SetOverrideSchItemColors(bool aFlag)
COLOR4D GetDefaultColor(int aLayer)
This class provides a custom wxValidator object for limiting the allowable characters when defining f...
Definition: validators.h:63
const BITMAP_OPAQUE copy_xpm[1]
Definition: copy.cpp:67
void SetName(const wxString &aName)
constexpr int FIRST_BUTTON_ID
static std::string GetColorSettingsPath()
Returns the path where color scheme files are stored (normally .
virtual void onColorChanged()
Event fired when the user changes any color.
PANEL_COLOR_SETTINGS(wxWindow *aParent)
std::vector< int > m_validLayers
A list of layer IDs that are valid for the current color settings dialog.
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
void OnBtnOpenThemeFolderClicked(wxCommandEvent &event) override
const BITMAP_OPAQUE paste_xpm[1]
Definition: paste.cpp:69
COLOR_SETTINGS * GetColorSettings(const wxString &aName="user")
Retrieves a color settings object that applications can read colors from.
COLOR4D GetColor(int aLayer) const
see class PGM_BASE
Board layer functions and definitions.
void OnBtnResetClicked(wxCommandEvent &aEvent) override
#define _(s)
Definition: 3d_actions.cpp:33
Class representing a simple color swatch, of the kind used to set layer colors.
Definition: color_swatch.h:38
void SaveColorSettings(COLOR_SETTINGS *aSettings, const std::string &aNamespace="")
Safely saves a COLOR_SETTINGS to disk, preserving any changes outside the given namespace.
const BITMAP_OPAQUE undo_xpm[1]
Definition: undo.cpp:74
Color settings are a bit different than most of the settings objects in that there can be more than o...
std::string GetFilename() const
Definition: json_settings.h:55
bool GetOverrideSchItemColors() const
virtual bool SaveToFile(const std::string &aDirectory, bool aForce=false)
Calls Store() and then writes the contents of the JSON document to a file.
void LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
Definition: launch_ext.cpp:26
void createSwatch(int aLayer, const wxString &aName)
void OnThemeChanged(wxCommandEvent &aEvent) override
Custom text control validator definitions.
virtual bool validateSave(bool aQuiet=false)
Performs a pre-save validation of the current color theme.
void SetColor(int aLayer, COLOR4D aColor)
void OnColorChanged(wxCommandEvent &aEvent)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40