KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_common_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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <advanced_config.h>
27#include <bitmaps.h>
29#include <dpi_scaling_common.h>
30#include <eda_draw_frame.h>
32#include <kiface_base.h>
33#include <kiplatform/ui.h>
34#include <pgm_base.h>
35#include <id.h>
39#include <wx/filedlg.h>
40
41/*
42 * What follows is a whole lot of ugly to handle various platform GUI deficiences with respect
43 * to light/dark mode, DPI scaling, and other foibles.
44 *
45 * Ugly as it all is, it does improve our usability on various platforms.
46 */
47
50{
51 // Rendering engine
52#ifdef __WXMAC__
53 // On MAC, Cairo render does not work.
54 m_renderingSizer->Show( false );
55#endif
56
58
61
62 /*
63 * Automatic dark mode detection works fine on Mac, so no need for the explicit options.
64 */
65#ifdef __WXMAC__
66 m_stIconTheme->Show( false );
67 m_rbIconThemeLight->Show( false );
68 m_rbIconThemeDark->Show( false );
69 m_rbIconThemeAuto->Show( false );
70#endif
71
72 // It's common on Windows to have separate app and system settings for light/dark
73#ifndef __WXMSW__
74 m_stAppTheme->Show( false );
75 m_rbAppThemeLight->Show( false );
76 m_rbAppThemeDark->Show( false );
77 m_rbAppThemeAuto->Show( false );
78#endif
79
80 /*
81 * Automatic canvas scaling works fine on all supported platforms, so manual scaling is disabled
82 */
83 if( ADVANCED_CFG::GetCfg().m_AllowManualCanvasScale )
84 {
85 static constexpr int dpi_scaling_precision = 1;
86 static constexpr double dpi_scaling_increment = 0.5;
87
90 m_canvasScaleCtrl->SetDigits( dpi_scaling_precision );
91 m_canvasScaleCtrl->SetIncrement( dpi_scaling_increment );
93
94 m_canvasScaleCtrl->SetToolTip( _( "Set the scale for the canvas."
95 "\n\n"
96 "On high-DPI displays on some platforms, KiCad cannot determine the "
97 "scaling factor. In this case you may need to set this to a value to "
98 "match your system's DPI scaling. 2.0 is a common value. "
99 "\n\n"
100 "If this does not match the system DPI scaling, the canvas will "
101 "not match the window size and cursor position." ) );
102
103 m_canvasScaleAuto->SetToolTip( _( "Use an automatic value for the canvas scale."
104 "\n\n"
105 "On some platforms, the automatic value is incorrect and should be "
106 "set manually." ) );
107 }
108 else
109 {
110 m_staticTextCanvasScale->Show( false );
111 m_canvasScaleCtrl->Show( false );
112 m_canvasScaleCtrl = nullptr;
113 m_canvasScaleAuto->Show( false );
114 }
115
117 Pgm().GetCommonSettings()->m_Appearance.zoom_correction_factor,
118 ADVANCED_CFG::GetCfg().m_ScreenDPI );
119
120 m_scalingSizer->Add( m_zoomCorrectionCtrl, 1, wxEXPAND );
121
122 // Hide the option of icons in menus for platforms that do not support them
124
125 m_scaleFonts->Show( false );
126 m_fontScalingHelp->Show( false );
127
129 {
130 m_canvasScaleCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED,
131 wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
132 nullptr, this );
133 }
134
135 wxSize minSize = m_highContrastCtrl->GetMinSize();
136 int minWidth = m_highContrastCtrl->GetTextExtent( wxT( "XXX.XXX" ) ).GetWidth();
137
138 m_highContrastCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
139}
140
141
143{
145 {
146 m_canvasScaleCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
147 wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
148 nullptr, this );
149 }
150}
151
152
154{
155 COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
156
157 applySettingsToPanel( *commonSettings );
158
159 m_textCtrlFileManager->SetValue( commonSettings->m_System.file_explorer );
160
161 // TODO(JE) Move these into COMMON_SETTINGS probably
162 m_textEditorPath->SetValue( Pgm().GetTextEditor( false ) );
163 m_defaultPDFViewer->SetValue( Pgm().UseSystemPdfBrowser() );
164 m_otherPDFViewer->SetValue( !Pgm().UseSystemPdfBrowser() );
165 m_PDFViewerPath->SetValue( Pgm().GetPdfBrowserName() );
167
168 return true;
169}
170
171
173{
174 COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
175
176 commonSettings->m_System.file_explorer = m_textCtrlFileManager->GetValue();
177 commonSettings->m_System.file_history_size = m_fileHistorySize->GetValue();
178
179 commonSettings->m_Graphics.aa_mode = m_antialiasing->GetSelection();
180
181 if( m_rbAccelerated->GetValue() )
183 else
185
187 {
188 DPI_SCALING_COMMON dpi( commonSettings, this );
189 dpi.SetDpiConfig( m_canvasScaleAuto->GetValue(), m_canvasScaleCtrl->GetValue() );
190 }
191
192 if( m_rbIconThemeLight->GetValue() )
193 commonSettings->m_Appearance.icon_theme = ICON_THEME::LIGHT;
194 else if( m_rbIconThemeDark->GetValue() )
195 commonSettings->m_Appearance.icon_theme = ICON_THEME::DARK;
196 else if( m_rbIconThemeAuto->GetValue() )
197 commonSettings->m_Appearance.icon_theme = ICON_THEME::AUTO;
198
199 if( m_rbAppThemeLight->GetValue() )
200 commonSettings->m_Appearance.app_theme = APP_THEME::LIGHT;
201 else if( m_rbAppThemeDark->GetValue() )
202 commonSettings->m_Appearance.app_theme = APP_THEME::DARK;
203 else if( m_rbAppThemeAuto->GetValue() )
204 commonSettings->m_Appearance.app_theme = APP_THEME::AUTO;
205
206 if( m_rbIconSizeSmall->GetValue() )
207 commonSettings->m_Appearance.toolbar_icon_size = 16;
208 else if( m_rbIconSizeNormal->GetValue() )
209 commonSettings->m_Appearance.toolbar_icon_size = 24;
210 else if( m_rbIconSizeLarge->GetValue() )
211 commonSettings->m_Appearance.toolbar_icon_size = 32;
212
213 commonSettings->m_Appearance.use_icons_in_menus = m_checkBoxIconsInMenus->GetValue();
214 commonSettings->m_Appearance.apply_icon_scale_to_fonts = m_scaleFonts->GetValue();
215
216 commonSettings->m_Appearance.show_scrollbars = m_showScrollbars->GetValue();
217
218 commonSettings->m_Appearance.grid_striping = m_gridStriping->GetValue();
219
220 commonSettings->m_Appearance.use_custom_cursors = !m_disableCustomCursors->GetValue();
221
222 commonSettings->m_Appearance.zoom_correction_factor = m_zoomCorrectionCtrl->GetValue();
223
224 double dimmingPercent = 80;
225 m_highContrastCtrl->GetValue().ToDouble( &dimmingPercent );
226 commonSettings->m_Appearance.hicontrast_dimming_factor = dimmingPercent / 100.0f;
227
228 commonSettings->m_Input.focus_follow_sch_pcb = m_focusFollowSchPcb->GetValue();
229 commonSettings->m_Input.hotkey_feedback = m_hotkeyFeedback->GetValue();
230 commonSettings->m_Input.immediate_actions = !m_NonImmediateActions->GetValue();
231 commonSettings->m_Input.warp_mouse_on_move = m_warpMouseOnMove->GetValue();
232
233 commonSettings->m_Backup.enabled = m_cbBackupEnabled->GetValue();
234 commonSettings->m_Backup.limit_total_size = m_backupLimitTotalSize->GetValue() * 1024ULL * 1024ULL;
235
236 // The radio-box choice order is constructed to match these enum values; if the enum
237 // is reordered in common_settings.h the ternaries below silently flip without these.
238 static_assert( static_cast<int>( BACKUP_FORMAT::INCREMENTAL ) == 0 );
239 static_assert( static_cast<int>( BACKUP_FORMAT::ZIP ) == 1 );
240 static_assert( static_cast<int>( BACKUP_LOCATION::PROJECT_DIR ) == 0 );
241 static_assert( static_cast<int>( BACKUP_LOCATION::USER_DIR ) == 1 );
242
243 commonSettings->m_Backup.format = ( m_choiceBackupFormat->GetSelection() == 0 )
246
247 commonSettings->m_Backup.location = ( m_choiceBackupLocation->GetSelection() == 0 )
250
251 commonSettings->m_Session.remember_open_files = m_cbRememberOpenFiles->GetValue();
252
253 Pgm().SetTextEditor( m_textEditorPath->GetValue());
254
255 Pgm().SetPdfBrowserName( m_PDFViewerPath->GetValue() );
258
259 Pgm().GetSettingsManager().Save( commonSettings );
260
261 return true;
262}
263
264
266{
267 COMMON_SETTINGS defaultSettings;
268
269 defaultSettings.ResetToDefaults();
270
271 applySettingsToPanel( defaultSettings );
272
273 // TODO(JE) Move these into COMMON_SETTINGS probably
274 m_textEditorPath->SetValue( defaultSettings.m_System.text_editor );
275 m_defaultPDFViewer->SetValue( defaultSettings.m_System.use_system_pdf_viewer );
276 m_otherPDFViewer->SetValue( !defaultSettings.m_System.use_system_pdf_viewer );
277 m_PDFViewerPath->SetValue( defaultSettings.m_System.pdf_viewer_name );
279}
280
281
283{
284 m_fileHistorySize->SetValue( aSettings.m_System.file_history_size );
285
286 m_antialiasing->SetSelection( aSettings.m_Graphics.aa_mode );
287
289 m_rbAccelerated->SetValue( true );
290 else
291 m_rbFallback->SetValue( true );
292
294 {
295 const DPI_SCALING_COMMON dpi( &aSettings, this );
296 m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
297 m_canvasScaleAuto->SetValue( dpi.GetCanvasIsAutoScaled() );
298 }
299
300 switch( aSettings.m_Appearance.icon_theme )
301 {
302 case ICON_THEME::LIGHT: m_rbIconThemeLight->SetValue( true ); break;
303 case ICON_THEME::DARK: m_rbIconThemeDark->SetValue( true ); break;
304 case ICON_THEME::AUTO: m_rbIconThemeAuto->SetValue( true ); break;
305 }
306
307 switch( aSettings.m_Appearance.app_theme )
308 {
309 case APP_THEME::LIGHT: m_rbAppThemeLight->SetValue( true ); break;
310 case APP_THEME::DARK: m_rbAppThemeDark->SetValue( true ); break;
311 case APP_THEME::AUTO: m_rbAppThemeAuto->SetValue( true ); break;
312 }
313
314 switch( aSettings.m_Appearance.toolbar_icon_size )
315 {
316 case 16: m_rbIconSizeSmall->SetValue( true ); break;
317 case 24: m_rbIconSizeNormal->SetValue( true ); break;
318 case 32: m_rbIconSizeLarge->SetValue( true ); break;
319 }
320
323
324 m_gridStriping->SetValue( aSettings.m_Appearance.grid_striping );
325
327
328 m_zoomCorrectionCtrl->SetDisplayedValue( aSettings.m_Appearance.zoom_correction_factor );
329
330 double dimmingPercent = aSettings.m_Appearance.hicontrast_dimming_factor * 100.0f;
331 m_highContrastCtrl->SetValue( wxString::Format( "%.0f", dimmingPercent ) );
332
333 m_focusFollowSchPcb->SetValue( aSettings.m_Input.focus_follow_sch_pcb );
334 m_hotkeyFeedback->SetValue( aSettings.m_Input.hotkey_feedback );
335 m_warpMouseOnMove->SetValue( aSettings.m_Input.warp_mouse_on_move );
336 m_NonImmediateActions->SetValue( !aSettings.m_Input.immediate_actions );
337
339
340 m_cbBackupEnabled->SetValue( aSettings.m_Backup.enabled );
341 m_backupLimitTotalSize->SetValue( aSettings.m_Backup.limit_total_size / ( 1024 * 1024 ) );
342
343 m_choiceBackupFormat->SetSelection(
344 aSettings.m_Backup.format == BACKUP_FORMAT::INCREMENTAL ? 0 : 1 );
345
346 m_choiceBackupLocation->SetSelection(
347 aSettings.m_Backup.location == BACKUP_LOCATION::PROJECT_DIR ? 0 : 1 );
348
349 m_showScrollbars->SetValue( aSettings.m_Appearance.show_scrollbars );
350}
351
352
353void PANEL_COMMON_SETTINGS::OnCanvasScaleChange( wxCommandEvent& aEvent )
354{
355 m_canvasScaleAuto->SetValue( false );
356}
357
358
359void PANEL_COMMON_SETTINGS::OnCanvasScaleAuto( wxCommandEvent& aEvent )
360{
361 const bool automatic = m_canvasScaleAuto->GetValue();
362
363 if( automatic && m_canvasScaleCtrl )
364 {
365 // set the scale to the auto value, without consulting the config
366 DPI_SCALING_COMMON dpi( nullptr, this );
367
368 // update the field (no events sent)
369 m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
370 }
371}
372
373
374void PANEL_COMMON_SETTINGS::OnTextEditorClick( wxCommandEvent& event )
375{
376 // Ask the user to select a new editor, but suggest the current one as the default.
377 wxString editorname = Pgm().AskUserForPreferredEditor( m_textEditorPath->GetValue() );
378
379 // If we have a new editor name request it to be copied to m_text_editor and saved
380 // to the preferences file. If the user cancelled the dialog then the previous
381 // value will be retained.
382 if( !editorname.IsEmpty() )
383 m_textEditorPath->SetValue( editorname );
384}
385
386
388{
389 m_staticTextFileManager->Show( aBool );
390 m_textCtrlFileManager->Show( aBool );
391
392 if( aBool )
393 {
394#if defined( __WINDOWS__ )
395 wxString msg = _( "Default 'explorer.exe /n,/select,%F' for this OS." );
396 m_textCtrlFileManager->SetToolTip( msg );
397 wxString str = "%F";
398#else
399 wxString msg = _( "File explorer command.\nexample:" ) + wxS( " 'nemo -n %F'" );
400 m_textCtrlFileManager->SetToolTip( msg );
401 wxString str= " %F";
402#endif
403 msg = _( "Explorer command with mandatory '%s' suffix after last entered character." );
404 m_staticTextFileManager->SetToolTip( wxString::Format( msg, str ) );
405 }
406}
407
408
409void PANEL_COMMON_SETTINGS::OnPDFViewerClick( wxCommandEvent& event )
410{
411 wxString mask( wxT( "*" ) );
412
413#ifdef __WINDOWS__
414 mask += wxT( ".exe" );
415#endif
416
417 wxString wildcard = _( "Executable files (" ) + mask + wxT( ")|" ) + mask;
418
420 wxFileName fn = Pgm().GetPdfBrowserName();
421
422 wxWindow* topLevelParent = wxGetTopLevelParent( this );
423
424 wxFileDialog dlg( topLevelParent, _( "Select Preferred PDF Viewer" ), fn.GetPath(),
425 fn.GetFullPath(), wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
426
428
429 if( dlg.ShowModal() == wxID_CANCEL )
430 return;
431
432 m_otherPDFViewer->SetValue( true );
433 m_PDFViewerPath->SetValue( dlg.GetPath() );
434}
435
436
438{
440}
441
442
444{
445 m_PDFViewerPath->Enable( m_otherPDFViewer->GetValue() );
446 m_pdfViewerBtn->Enable( m_otherPDFViewer->GetValue() );
447}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APPEARANCE m_Appearance
AUTO_BACKUP m_Backup
Class to handle configuration and automatic determination of the DPI scale to use for canvases.
bool GetCanvasIsAutoScaled() const override
Is the current value auto scaled, or is it user-set in the config.
double GetScaleFactor() const override
Get the DPI scale from all known sources in order:
void SetDpiConfig(bool aAuto, double aValue) override
Set the common DPI config in a given config object.
static double GetDefaultScaleFactor()
Get the "default" scaling factor to use if not other config is available.
static double GetMaxScaleFactor()
Get the maximum scaling factor that should be presented to the user.
static double GetMinScaleFactor()
Get the minimum scaling factor that should be presented to the user.
@ GAL_TYPE_OPENGL
OpenGL implementation.
@ GAL_TYPE_CAIRO
Cairo implementation.
void ResetToDefaults()
Resets all parameters to default values.
PANEL_COMMON_SETTINGS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void OnTextEditorClick(wxCommandEvent &event) override
ZOOM_CORRECTION_CTRL * m_zoomCorrectionCtrl
void OnCanvasScaleChange(wxCommandEvent &aEvent)
Event fired when the canvas scale field is modified.
void ShowFileManagerWidgets(bool aBool)
PANEL_COMMON_SETTINGS(wxWindow *aParent)
void applySettingsToPanel(COMMON_SETTINGS &aSettings)
void OnPDFViewerClick(wxCommandEvent &event) override
void OnCanvasScaleAuto(wxCommandEvent &aEvent) override
Event fired when the canvas auto-scale option is changed.
void ResetPanel() override
Reset the contents of this panel.
void OnRadioButtonPdfViewer(wxCommandEvent &event) override
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:541
virtual void SetPdfBrowserName(const wxString &aFileName)
Definition pgm_base.h:187
virtual void ReadPdfBrowserInfos()
Read the PDF browser choice from the common configuration.
Definition pgm_base.cpp:873
virtual const wxString & GetPdfBrowserName() const
Definition pgm_base.h:185
virtual void SetTextEditor(const wxString &aFileName)
Definition pgm_base.cpp:218
virtual void ForceSystemPdfBrowser(bool aFlg)
Force the use of system PDF browser, even if a preferred PDF browser is set.
Definition pgm_base.h:202
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:130
virtual void WritePdfBrowserInfos()
Save the PDF browser choice to the common configuration.
Definition pgm_base.cpp:880
virtual const wxString AskUserForPreferredEditor(const wxString &aDefaultEditor=wxEmptyString)
Show a dialog that instructs the user to select a new preferred editor.
Definition pgm_base.cpp:261
Control to calibrate screen zoom to match real-world size.
@ ZIP
Zip archive snapshots; autosave uses recovery files.
@ INCREMENTAL
Git-based local history (default)
@ USER_DIR
Under the KiCad user data directory.
@ PROJECT_DIR
Inside the project directory (default)
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
bool AllowIconsInMenus()
If the user has disabled icons system-wide, we check that here.
Definition wxgtk/ui.cpp:295
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
unsigned long long limit_total_size
Maximum total size of backups (bytes), 0 for unlimited.
BACKUP_LOCATION location
Where backups, history, and autosave files live.
BACKUP_FORMAT format
Backup format (incremental git history vs zip archives)
bool enabled
Automatically back up the project when files are saved.
int canvas_type
EDA_DRAW_PANEL_GAL::GAL_TYPE_* value, see gal_options_panel.cpp.