KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_edit_cfg.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "dialog_edit_cfg.h"
21
22#include <advanced_config.h>
23#include <config_params.h>
24#include <paths.h>
25#include <wx/button.h>
26#include <wx/display.h>
27#include <wx/fileconf.h>
28#include <wx/log.h>
29#include <wx/menu.h>
30#include <wx/sizer.h>
31#include <wx/settings.h>
32#include <functional>
33#include <memory>
34#include <set>
35
36
37static wxString paramValueString( const PARAM_CFG& aParam )
38{
39 wxString s;
40
41 try
42 {
43 switch( aParam.m_Type )
44 {
45 case paramcfg_id::PARAM_INT: s << *static_cast<const PARAM_CFG_INT&>( aParam ).m_Pt_param; break;
47 s = wxString::FromCDouble( *static_cast<const PARAM_CFG_DOUBLE&>( aParam ).m_Pt_param );
48 break;
49 case paramcfg_id::PARAM_WXSTRING: s = *static_cast<const PARAM_CFG_WXSTRING&>( aParam ).m_Pt_param; break;
51 s << ( *static_cast<const PARAM_CFG_BOOL&>( aParam ).m_Pt_param ? wxS( "true" ) : wxS( "false" ) );
52 break;
53 default:
54 wxLogError( wxS( "Unsupported PARAM_CFG variant: " ) + wxString::Format( wxS( "%d" ), aParam.m_Type ) );
55 }
56 }
57 catch( ... )
58 {
59 wxLogError( wxS( "Error converting parameter value to string." ) );
60 }
61 return s;
62}
63
64static wxString paramDefaultString( const PARAM_CFG& aParam )
65{
66 wxString s;
67
68 try
69 {
70 switch( aParam.m_Type )
71 {
72 case paramcfg_id::PARAM_INT: s << static_cast<const PARAM_CFG_INT&>( aParam ).m_Default; break;
74 s = wxString::FromCDouble( static_cast<const PARAM_CFG_DOUBLE&>( aParam ).m_Default );
75 break;
76 case paramcfg_id::PARAM_WXSTRING: s << static_cast<const PARAM_CFG_WXSTRING&>( aParam ).m_default; break;
78 s << ( static_cast<const PARAM_CFG_BOOL&>( aParam ).m_Default ? wxS( "true" ) : wxS( "false" ) );
79 break;
80 default: break;
81 }
82 }
83 catch( ... )
84 {
85 wxLogError( wxS( "Error converting parameter default value to string." ) );
86 }
87
88 return s;
89}
90
91static void writeParam( PARAM_CFG& aParam, const wxString& aValue )
92{
93 switch( aParam.m_Type )
94 {
96 {
97 PARAM_CFG_INT& param = static_cast<PARAM_CFG_INT&>( aParam );
98 *param.m_Pt_param = wxAtoi( aValue );
99 break;
100 }
102 {
103 PARAM_CFG_BOOL& param = static_cast<PARAM_CFG_BOOL&>( aParam );
104
105 if( aValue.CmpNoCase( wxS( "true" ) ) == 0 || aValue.CmpNoCase( wxS( "yes" ) ) == 0
106 || aValue.CmpNoCase( wxS( "1" ) ) == 0 )
107 {
108 *param.m_Pt_param = true;
109 }
110 else
111 {
112 *param.m_Pt_param = false;
113 }
114 break;
115 }
117 {
118 PARAM_CFG_DOUBLE& param = static_cast<PARAM_CFG_DOUBLE&>( aParam );
119 aValue.ToCDouble( param.m_Pt_param );
120 break;
121 }
123 {
124 PARAM_CFG_WXSTRING& param = static_cast<PARAM_CFG_WXSTRING&>( aParam );
125 *param.m_Pt_param = aValue;
126 break;
127 }
128 default:
129 wxASSERT_MSG( false,
130 wxS( "Unsupported PARAM_CFG variant: " ) + wxString::Format( wxS( "%d" ), aParam.m_Type ) );
131 }
132}
133
135 wxDialog( aParent, wxID_ANY, _( "Edit Advanced Configuration" ), wxDefaultPosition, wxDefaultSize,
136 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
137{
138 m_cfgFile = wxFileName( PATHS::GetUserSettingsPath(), wxS( "kicad_advanced" ) );
139
140 m_grid = new wxGrid( this, wxID_ANY );
141 m_grid->CreateGrid( 0, 3 );
142 m_grid->SetColLabelValue( 0, _( "Key" ) );
143 m_grid->SetColLabelValue( 1, _( "Value" ) );
144 m_grid->SetColLabelValue( 2, _( "Extant" ) );
145 m_grid->HideCol( 2 );
146 m_grid->SetRowLabelSize( 0 );
147
148 loadSettings();
149
150 wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
151 wxButton* okButton = new wxButton( this, wxID_OK, _( "OK" ) );
152 okButton->SetDefault();
153 buttonSizer->AddButton( okButton );
154 buttonSizer->Realize();
155
156 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
157 sizer->Add( m_grid, 1, wxEXPAND | wxALL, 5 );
158 sizer->Add( buttonSizer, 0, wxEXPAND | wxALL, 5 );
159 SetSizer( sizer );
160
161 wxDisplay display( wxDisplay::GetFromWindow( this ) );
162 wxRect displayRect = display.GetClientArea();
163
164 SetMinSize( wxSize( 500, 300 ) );
165 SetMaxSize( wxSize( displayRect.GetWidth() - 100, displayRect.GetHeight() - 100 ) );
166 SetSizeHints( wxSize( 700, 500 ) );
167
168 m_grid->Bind( wxEVT_GRID_CELL_CHANGED, &DIALOG_EDIT_CFG::OnCellChange, this );
169 m_grid->Bind( wxEVT_GRID_CELL_RIGHT_CLICK, &DIALOG_EDIT_CFG::OnCellRightClick, this );
170 Bind( wxEVT_SIZE, &DIALOG_EDIT_CFG::OnSize, this );
171
172 m_contextRow = -1;
173
174 Layout();
175 Centre();
176
177 // CallAfter ensures layout is complete before column adjustment
178 CallAfter(
179 [this]()
180 {
182 } );
183}
184
186{
187 if( !m_grid || m_grid->GetNumberRows() == 0 )
188 return;
189
190 m_grid->Layout();
191
192 wxSize clientSize = m_grid->GetClientSize();
193 int availableWidth = clientSize.GetWidth();
194
195 // Reserve space for vertical scrollbar when we have many rows
196 availableWidth -= wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
197
198 if( availableWidth < 200 )
199 availableWidth = 200;
200
201 int keyWidth = ( availableWidth * 6 ) / 10;
202 int valueWidth = availableWidth - keyWidth;
203
204 keyWidth = std::max( keyWidth, 100 );
205 valueWidth = std::max( valueWidth, 80 );
206
207 m_grid->SetColSize( 0, keyWidth );
208 m_grid->SetColSize( 1, valueWidth );
209
210 // Prevent wxWidgets auto-sizing from interfering
211 m_grid->SetColMinimalAcceptableWidth( 50 );
212}
213
214void DIALOG_EDIT_CFG::OnSize( wxSizeEvent& aEvent )
215{
216 aEvent.Skip();
217
218 if( m_grid && m_grid->GetNumberRows() > 0 )
219 {
220 // Defer column adjustment until resize is complete
221 CallAfter(
222 [this]()
223 {
225 } );
226 }
227}
228
230{
231 const ADVANCED_CFG& adv = ADVANCED_CFG::GetCfg();
232 const std::vector<std::unique_ptr<PARAM_CFG>>& entries = adv.GetEntries();
233
234 for( const auto& entry : entries )
235 {
236 wxString value = paramValueString( *entry );
237 wxString def = paramDefaultString( *entry );
238 int row = m_grid->GetNumberRows();
239 m_grid->AppendRows( 1 );
240 m_grid->SetCellValue( row, 0, entry->m_Ident );
241 m_grid->SetCellValue( row, 1, value );
242 m_grid->SetCellValue( row, 2, def == value ? wxS( "0" ) : wxS( "1" ) );
243 m_grid->SetReadOnly( row, 2 );
244 updateRowAppearance( row );
245 }
246}
247
249{
250 int rows = m_grid->GetNumberRows();
251
252 for( int row = 0; row < rows; ++row )
253 {
254 wxString key = m_grid->GetCellValue( row, 0 );
255 wxString val = m_grid->GetCellValue( row, 1 );
256 wxString ext = m_grid->GetCellValue( row, 2 );
257
258 if( key.IsEmpty() || ext != wxS( "1" ) )
259 continue;
260
261 const std::vector<std::unique_ptr<PARAM_CFG>>& entries = ADVANCED_CFG::GetCfg().GetEntries();
262 for( auto& entry : entries )
263 {
264 if( entry->m_Ident == key )
265 {
266 writeParam( *entry, val );
267 break;
268 }
269 }
270 }
271
272 ADVANCED_CFG& adv = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() );
273 adv.Save();
274}
275
276void DIALOG_EDIT_CFG::OnCellChange( wxGridEvent& aEvent )
277{
278 int row = aEvent.GetRow();
279 int col = aEvent.GetCol();
280
281 if( col == 0 || col == 1 )
282 {
283 m_grid->SetCellValue( row, 2, wxS( "1" ) );
284 updateRowAppearance( row );
285 }
286
287 saveSettings();
288
289 int lastRow = m_grid->GetNumberRows() - 1;
290 if( !m_grid->GetCellValue( lastRow, 0 ).IsEmpty() || !m_grid->GetCellValue( lastRow, 1 ).IsEmpty() )
291 {
292 m_grid->AppendRows( 1 );
293 m_grid->SetCellValue( m_grid->GetNumberRows() - 1, 2, wxS( "0" ) );
294 m_grid->SetReadOnly( m_grid->GetNumberRows() - 1, 2 );
295 updateRowAppearance( m_grid->GetNumberRows() - 1 );
296 }
297
298 aEvent.Skip();
299}
300
301void DIALOG_EDIT_CFG::OnCellRightClick( wxGridEvent& aEvent )
302{
303 m_contextRow = aEvent.GetRow();
304 wxMenu menu;
305 menu.Append( wxID_ANY, _( "Reset to default" ) );
306 menu.Bind( wxEVT_MENU, &DIALOG_EDIT_CFG::OnResetDefault, this );
307 PopupMenu( &menu );
308 menu.Unbind( wxEVT_MENU, &DIALOG_EDIT_CFG::OnResetDefault, this );
309}
310
311void DIALOG_EDIT_CFG::OnResetDefault( wxCommandEvent& aEvent )
312{
313 if( m_contextRow < 0 )
314 return;
315
316 wxString key = m_grid->GetCellValue( m_contextRow, 0 );
317 wxString def;
318
319 const ADVANCED_CFG& adv = ADVANCED_CFG::GetCfg();
320 const std::vector<std::unique_ptr<PARAM_CFG>>& entries = adv.GetEntries();
321
322 for( const auto& entry : entries )
323 {
324 if( entry->m_Ident == key )
325 {
326 def = paramDefaultString( *entry );
327 break;
328 }
329 }
330
331 m_grid->SetCellValue( m_contextRow, 1, def );
332 m_grid->SetCellValue( m_contextRow, 2, wxS( "0" ) );
334 saveSettings();
335}
336
338{
339 bool ext = m_grid->GetCellValue( aRow, 2 ) == wxS( "1" );
340 wxFont font = m_grid->GetCellFont( aRow, 0 );
341 font.SetWeight( ext ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL );
342 m_grid->SetCellFont( aRow, 0, font );
343 m_grid->SetCellFont( aRow, 1, font );
344}
const std::vector< std::unique_ptr< PARAM_CFG > > & GetEntries() const
void Save()
Save the configuration to the configuration file.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void OnSize(wxSizeEvent &aEvent)
DIALOG_EDIT_CFG(wxWindow *aParent)
void OnCellChange(wxGridEvent &aEvent)
void OnCellRightClick(wxGridEvent &aEvent)
void OnResetDefault(wxCommandEvent &aEvent)
wxFileName m_cfgFile
void updateRowAppearance(int aRow)
Configuration object for booleans.
bool * m_Pt_param
Pointer to the parameter value.
Configuration object for double precision floating point numbers.
double * m_Pt_param
Pointer to the parameter value.
Configuration object for integers.
int * m_Pt_param
Pointer to the parameter value.
Configuration object for wxString objects.
wxString * m_Pt_param
Pointer to the parameter value.
A base class which establishes the interface functions ReadParam and SaveParam, which are implemented...
paramcfg_id m_Type
Type of parameter.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
Definition paths.cpp:592
@ PARAM_WXSTRING
@ PARAM_INT
@ PARAM_DOUBLE
@ PARAM_BOOL
static wxString paramValueString(const PARAM_CFG &aParam)
static void writeParam(PARAM_CFG &aParam, const wxString &aValue)
static wxString paramDefaultString(const PARAM_CFG &aParam)
#define _(s)