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, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <advanced_config.h>
23#include <bitmaps.h>
25#include <dpi_scaling_common.h>
26#include <eda_draw_frame.h>
28#include <kiface_base.h>
29#include <kiplatform/ui.h>
30#include <pgm_base.h>
31#include <id.h>
35#include <wx/filedlg.h>
36
37#include <algorithm>
38
39/*
40 * What follows is a whole lot of ugly to handle various platform GUI deficiences with respect
41 * to light/dark mode, DPI scaling, and other foibles.
42 *
43 * Ugly as it all is, it does improve our usability on various platforms.
44 */
45
47{
48 int type;
49 wxString label;
50};
51
52
53static std::vector<CANVAS_CHOICE> canvasChoices()
54{
55 return {
56 { EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL, _( "Accelerated Graphics" ) },
57#ifdef __WXMAC__
58 { EDA_DRAW_PANEL_GAL::GAL_TYPE_MODERN, _( "RHI Metal (Experimental)" ) },
59#else
60 { EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO, _( "Fallback Graphics" ) },
61 { EDA_DRAW_PANEL_GAL::GAL_TYPE_MODERN, _( "RHI Vulkan (Experimental)" ) },
62#endif
63 };
64}
65
66
69{
70 m_canvasType->Clear();
71
72 for( const CANVAS_CHOICE& choice : canvasChoices() )
73 m_canvasType->Append( choice.label );
74
75 m_canvasType->SetSelection( 0 );
76
78
81
82 /*
83 * Automatic dark mode detection works fine on Mac, so no need for the explicit options.
84 */
85#ifdef __WXMAC__
86 m_stIconTheme->Show( false );
87 m_rbIconThemeLight->Show( false );
88 m_rbIconThemeDark->Show( false );
89 m_rbIconThemeAuto->Show( false );
90#endif
91
92 // It's common on Windows to have separate app and system settings for light/dark
93#ifndef __WXMSW__
94 m_stAppTheme->Show( false );
95 m_rbAppThemeLight->Show( false );
96 m_rbAppThemeDark->Show( false );
97 m_rbAppThemeAuto->Show( false );
98#endif
99
100 /*
101 * Automatic canvas scaling works fine on all supported platforms, so manual scaling is disabled
102 */
103 if( ADVANCED_CFG::GetCfg().m_AllowManualCanvasScale )
104 {
105 static constexpr int dpi_scaling_precision = 1;
106 static constexpr double dpi_scaling_increment = 0.5;
107
110 m_canvasScaleCtrl->SetDigits( dpi_scaling_precision );
111 m_canvasScaleCtrl->SetIncrement( dpi_scaling_increment );
113
114 m_canvasScaleCtrl->SetToolTip( _( "Set the scale for the canvas."
115 "\n\n"
116 "On high-DPI displays on some platforms, KiCad cannot determine the "
117 "scaling factor. In this case you may need to set this to a value to "
118 "match your system's DPI scaling. 2.0 is a common value. "
119 "\n\n"
120 "If this does not match the system DPI scaling, the canvas will "
121 "not match the window size and cursor position." ) );
122
123 m_canvasScaleAuto->SetToolTip( _( "Use an automatic value for the canvas scale."
124 "\n\n"
125 "On some platforms, the automatic value is incorrect and should be "
126 "set manually." ) );
127 }
128 else
129 {
130 m_staticTextCanvasScale->Show( false );
131 m_canvasScaleCtrl->Show( false );
132 m_canvasScaleCtrl = nullptr;
133 m_canvasScaleAuto->Show( false );
134 }
135
137 Pgm().GetCommonSettings()->m_Appearance.zoom_correction_factor,
138 ADVANCED_CFG::GetCfg().m_ScreenDPI );
139
140 m_scalingSizer->Add( m_zoomCorrectionCtrl, 1, wxEXPAND );
141
142 // Hide the option of icons in menus for platforms that do not support them
144
145 m_scaleFonts->Show( false );
146 m_fontScalingHelp->Show( false );
147
149 {
150 m_canvasScaleCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED,
151 wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
152 nullptr, this );
153 }
154
155 wxSize minSize = m_highContrastCtrl->GetMinSize();
156 int minWidth = m_highContrastCtrl->GetTextExtent( wxT( "XXX.XXX" ) ).GetWidth();
157
158 m_highContrastCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
159}
160
161
163{
165 {
166 m_canvasScaleCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
167 wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
168 nullptr, this );
169 }
170}
171
172
174{
175 COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
176
177 applySettingsToPanel( *commonSettings );
178
179 m_textCtrlFileManager->SetValue( commonSettings->m_System.file_explorer );
180
181 // TODO(JE) Move these into COMMON_SETTINGS probably
182 m_textEditorPath->SetValue( Pgm().GetTextEditor( false ) );
183 m_defaultPDFViewer->SetValue( Pgm().UseSystemPdfBrowser() );
184 m_otherPDFViewer->SetValue( !Pgm().UseSystemPdfBrowser() );
185 m_PDFViewerPath->SetValue( Pgm().GetPdfBrowserName() );
187
188 return true;
189}
190
191
193{
194 COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
195
196 commonSettings->m_System.file_explorer = m_textCtrlFileManager->GetValue();
197 commonSettings->m_System.file_history_size = m_fileHistorySize->GetValue();
198
199 commonSettings->m_Graphics.aa_mode = m_antialiasing->GetSelection();
200
201 const std::vector<CANVAS_CHOICE> choices = canvasChoices();
202 int sel = m_canvasType->GetSelection();
203
204 if( sel >= 0 && sel < static_cast<int>( choices.size() ) )
205 commonSettings->m_Graphics.canvas_type = choices[sel].type;
206 else
208
210 {
211 DPI_SCALING_COMMON dpi( commonSettings, this );
212 dpi.SetDpiConfig( m_canvasScaleAuto->GetValue(), m_canvasScaleCtrl->GetValue() );
213 }
214
215 if( m_rbIconThemeLight->GetValue() )
216 commonSettings->m_Appearance.icon_theme = ICON_THEME::LIGHT;
217 else if( m_rbIconThemeDark->GetValue() )
218 commonSettings->m_Appearance.icon_theme = ICON_THEME::DARK;
219 else if( m_rbIconThemeAuto->GetValue() )
220 commonSettings->m_Appearance.icon_theme = ICON_THEME::AUTO;
221
222 if( m_rbAppThemeLight->GetValue() )
223 commonSettings->m_Appearance.app_theme = APP_THEME::LIGHT;
224 else if( m_rbAppThemeDark->GetValue() )
225 commonSettings->m_Appearance.app_theme = APP_THEME::DARK;
226 else if( m_rbAppThemeAuto->GetValue() )
227 commonSettings->m_Appearance.app_theme = APP_THEME::AUTO;
228
229 if( m_rbIconSizeSmall->GetValue() )
230 commonSettings->m_Appearance.toolbar_icon_size = 16;
231 else if( m_rbIconSizeNormal->GetValue() )
232 commonSettings->m_Appearance.toolbar_icon_size = 24;
233 else if( m_rbIconSizeLarge->GetValue() )
234 commonSettings->m_Appearance.toolbar_icon_size = 32;
235
236 commonSettings->m_Appearance.use_icons_in_menus = m_checkBoxIconsInMenus->GetValue();
237 commonSettings->m_Appearance.apply_icon_scale_to_fonts = m_scaleFonts->GetValue();
238
239 commonSettings->m_Appearance.show_scrollbars = m_showScrollbars->GetValue();
240
241 commonSettings->m_Appearance.grid_striping = m_gridStriping->GetValue();
242
243 commonSettings->m_Appearance.use_custom_cursors = !m_disableCustomCursors->GetValue();
244
245 commonSettings->m_Appearance.zoom_correction_factor = m_zoomCorrectionCtrl->GetValue();
246
247 double dimmingPercent = 80;
248 m_highContrastCtrl->GetValue().ToDouble( &dimmingPercent );
249 commonSettings->m_Appearance.hicontrast_dimming_factor = dimmingPercent / 100.0f;
250
251 commonSettings->m_Input.focus_follow_sch_pcb = m_focusFollowSchPcb->GetValue();
252 commonSettings->m_Input.hotkey_feedback = m_hotkeyFeedback->GetValue();
253 commonSettings->m_Input.immediate_actions = !m_NonImmediateActions->GetValue();
254 commonSettings->m_Input.warp_mouse_on_move = m_warpMouseOnMove->GetValue();
255
256 commonSettings->m_Backup.enabled = m_cbBackupEnabled->GetValue();
257 commonSettings->m_Backup.limit_total_size = m_backupLimitTotalSize->GetValue() * 1024ULL * 1024ULL;
258
259 // The radio-box choice order is constructed to match these enum values; if the enum
260 // is reordered in common_settings.h the ternaries below silently flip without these.
261 static_assert( static_cast<int>( BACKUP_FORMAT::INCREMENTAL ) == 0 );
262 static_assert( static_cast<int>( BACKUP_FORMAT::ZIP ) == 1 );
263 static_assert( static_cast<int>( BACKUP_LOCATION::PROJECT_DIR ) == 0 );
264 static_assert( static_cast<int>( BACKUP_LOCATION::USER_DIR ) == 1 );
265
266 commonSettings->m_Backup.format = ( m_choiceBackupFormat->GetSelection() == 0 )
269
270 commonSettings->m_Backup.location = ( m_choiceBackupLocation->GetSelection() == 0 )
273
274 commonSettings->m_Session.remember_open_files = m_cbRememberOpenFiles->GetValue();
275
276 Pgm().SetTextEditor( m_textEditorPath->GetValue());
277
278 Pgm().SetPdfBrowserName( m_PDFViewerPath->GetValue() );
281
282 Pgm().GetSettingsManager().Save( commonSettings );
283
284 return true;
285}
286
287
289{
290 COMMON_SETTINGS defaultSettings;
291
292 defaultSettings.ResetToDefaults();
293
294 applySettingsToPanel( defaultSettings );
295
296 // TODO(JE) Move these into COMMON_SETTINGS probably
297 m_textEditorPath->SetValue( defaultSettings.m_System.text_editor );
298 m_defaultPDFViewer->SetValue( defaultSettings.m_System.use_system_pdf_viewer );
299 m_otherPDFViewer->SetValue( !defaultSettings.m_System.use_system_pdf_viewer );
300 m_PDFViewerPath->SetValue( defaultSettings.m_System.pdf_viewer_name );
302}
303
304
306{
307 m_fileHistorySize->SetValue( aSettings.m_System.file_history_size );
308
309 m_antialiasing->SetSelection( aSettings.m_Graphics.aa_mode );
310
311 // A canvas this platform does not offer shows as the first entry
312 const std::vector<CANVAS_CHOICE> choices = canvasChoices();
313 const int storedType = static_cast<int>(
315 auto it = std::ranges::find( choices, storedType, &CANVAS_CHOICE::type );
316
317 m_canvasType->SetSelection( it == choices.end() ? 0 : static_cast<int>( it - choices.begin() ) );
318
320 {
321 const DPI_SCALING_COMMON dpi( &aSettings, this );
322 m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
323 m_canvasScaleAuto->SetValue( dpi.GetCanvasIsAutoScaled() );
324 }
325
326 switch( aSettings.m_Appearance.icon_theme )
327 {
328 case ICON_THEME::LIGHT: m_rbIconThemeLight->SetValue( true ); break;
329 case ICON_THEME::DARK: m_rbIconThemeDark->SetValue( true ); break;
330 case ICON_THEME::AUTO: m_rbIconThemeAuto->SetValue( true ); break;
331 }
332
333 switch( aSettings.m_Appearance.app_theme )
334 {
335 case APP_THEME::LIGHT: m_rbAppThemeLight->SetValue( true ); break;
336 case APP_THEME::DARK: m_rbAppThemeDark->SetValue( true ); break;
337 case APP_THEME::AUTO: m_rbAppThemeAuto->SetValue( true ); break;
338 }
339
340 switch( aSettings.m_Appearance.toolbar_icon_size )
341 {
342 case 16: m_rbIconSizeSmall->SetValue( true ); break;
343 case 24: m_rbIconSizeNormal->SetValue( true ); break;
344 case 32: m_rbIconSizeLarge->SetValue( true ); break;
345 }
346
349
350 m_gridStriping->SetValue( aSettings.m_Appearance.grid_striping );
351
353
354 m_zoomCorrectionCtrl->SetDisplayedValue( aSettings.m_Appearance.zoom_correction_factor );
355
356 double dimmingPercent = aSettings.m_Appearance.hicontrast_dimming_factor * 100.0f;
357 m_highContrastCtrl->SetValue( wxString::Format( "%.0f", dimmingPercent ) );
358
359 m_focusFollowSchPcb->SetValue( aSettings.m_Input.focus_follow_sch_pcb );
360 m_hotkeyFeedback->SetValue( aSettings.m_Input.hotkey_feedback );
361 m_warpMouseOnMove->SetValue( aSettings.m_Input.warp_mouse_on_move );
362 m_NonImmediateActions->SetValue( !aSettings.m_Input.immediate_actions );
363
365
366 m_cbBackupEnabled->SetValue( aSettings.m_Backup.enabled );
367 m_backupLimitTotalSize->SetValue( aSettings.m_Backup.limit_total_size / ( 1024 * 1024 ) );
368
369 m_choiceBackupFormat->SetSelection(
370 aSettings.m_Backup.format == BACKUP_FORMAT::INCREMENTAL ? 0 : 1 );
371
372 m_choiceBackupLocation->SetSelection(
373 aSettings.m_Backup.location == BACKUP_LOCATION::PROJECT_DIR ? 0 : 1 );
374
375 m_showScrollbars->SetValue( aSettings.m_Appearance.show_scrollbars );
376}
377
378
379void PANEL_COMMON_SETTINGS::OnCanvasScaleChange( wxCommandEvent& aEvent )
380{
381 m_canvasScaleAuto->SetValue( false );
382}
383
384
385void PANEL_COMMON_SETTINGS::OnCanvasScaleAuto( wxCommandEvent& aEvent )
386{
387 const bool automatic = m_canvasScaleAuto->GetValue();
388
389 if( automatic && m_canvasScaleCtrl )
390 {
391 // set the scale to the auto value, without consulting the config
392 DPI_SCALING_COMMON dpi( nullptr, this );
393
394 // update the field (no events sent)
395 m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
396 }
397}
398
399
400void PANEL_COMMON_SETTINGS::OnTextEditorClick( wxCommandEvent& event )
401{
402 // Ask the user to select a new editor, but suggest the current one as the default.
403 wxString editorname = Pgm().AskUserForPreferredEditor( m_textEditorPath->GetValue() );
404
405 // If we have a new editor name request it to be copied to m_text_editor and saved
406 // to the preferences file. If the user cancelled the dialog then the previous
407 // value will be retained.
408 if( !editorname.IsEmpty() )
409 m_textEditorPath->SetValue( editorname );
410}
411
412
414{
415 m_staticTextFileManager->Show( aBool );
416 m_textCtrlFileManager->Show( aBool );
417
418 if( aBool )
419 {
420#if defined( __WINDOWS__ )
421 wxString msg = _( "Default 'explorer.exe /n,/select,%F' for this OS." );
422 m_textCtrlFileManager->SetToolTip( msg );
423 wxString str = "%F";
424#else
425 wxString msg = _( "File explorer command.\nexample:" ) + wxS( " 'nemo -n %F'" );
426 m_textCtrlFileManager->SetToolTip( msg );
427 wxString str= " %F";
428#endif
429 msg = _( "Explorer command with mandatory '%s' suffix after last entered character." );
430 m_staticTextFileManager->SetToolTip( wxString::Format( msg, str ) );
431 }
432}
433
434
435void PANEL_COMMON_SETTINGS::OnPDFViewerClick( wxCommandEvent& event )
436{
437 wxString mask( wxT( "*" ) );
438
439#ifdef __WINDOWS__
440 mask += wxT( ".exe" );
441#endif
442
443 wxString wildcard = _( "Executable files (" ) + mask + wxT( ")|" ) + mask;
444
446 wxFileName fn = Pgm().GetPdfBrowserName();
447
448 wxWindow* topLevelParent = wxGetTopLevelParent( this );
449
450 wxFileDialog dlg( topLevelParent, _( "Select Preferred PDF Viewer" ), fn.GetPath(),
451 fn.GetFullPath(), wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
452
454
455 if( dlg.ShowModal() == wxID_CANCEL )
456 return;
457
458 m_otherPDFViewer->SetValue( true );
459 m_PDFViewerPath->SetValue( dlg.GetPath() );
460}
461
462
464{
466}
467
468
470{
471 m_PDFViewerPath->Enable( m_otherPDFViewer->GetValue() );
472 m_pdfViewerBtn->Enable( m_otherPDFViewer->GetValue() );
473}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
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_MODERN
RHI implementation, Vulkan or Metal on macOS.
@ GAL_TYPE_CAIRO
Cairo implementation.
static GAL_TYPE ResolveStoredCanvasType(int aStoredCanvasType)
Convert a stored canvas type setting into a backend that can actually be used.
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:562
virtual void SetPdfBrowserName(const wxString &aFileName)
Definition pgm_base.h:178
virtual void ReadPdfBrowserInfos()
Read the PDF browser choice from the common configuration.
Definition pgm_base.cpp:894
virtual const wxString & GetPdfBrowserName() const
Definition pgm_base.h:176
virtual void SetTextEditor(const wxString &aFileName)
Definition pgm_base.cpp:226
virtual void ForceSystemPdfBrowser(bool aFlg)
Force the use of system PDF browser, even if a preferred PDF browser is set.
Definition pgm_base.h:193
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
virtual void WritePdfBrowserInfos()
Save the PDF browser choice to the common configuration.
Definition pgm_base.cpp:901
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:269
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:481
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
static std::vector< CANVAS_CHOICE > canvasChoices()
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.