You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
15 KiB

3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018-2023 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. #include <dialogs/panel_common_settings.h>
  24. #include <advanced_config.h>
  25. #include <bitmaps.h>
  26. #include <dialog_shim.h>
  27. #include <dpi_scaling_common.h>
  28. #include <kiface_base.h>
  29. #include <kiplatform/ui.h>
  30. #include <pgm_base.h>
  31. #include <id.h>
  32. #include <settings/common_settings.h>
  33. #include <settings/settings_manager.h>
  34. #include <widgets/stepped_slider.h>
  35. #include <widgets/std_bitmap_button.h>
  36. #include <wx/filedlg.h>
  37. /*
  38. * What follows is a whole lot of ugly to handle various platform GUI deficiences with respect
  39. * to light/dark mode, DPI scaling, and other foibles.
  40. *
  41. * Ugly as it all is, it does improve our usability on various platforms.
  42. */
  43. PANEL_COMMON_SETTINGS::PANEL_COMMON_SETTINGS( wxWindow* aParent )
  44. : PANEL_COMMON_SETTINGS_BASE( aParent )
  45. {
  46. /*
  47. * Cairo canvas doesn't work on Mac, so no need for fallback anti-aliasing options
  48. */
  49. #ifdef __WXMAC__
  50. m_antialiasingFallback->Show( false );
  51. m_antialiasingFallbackLabel->Show( false );
  52. #endif
  53. ShowFileManagerWidgets( ADVANCED_CFG::GetCfg().m_EnableLibDir );
  54. m_textEditorBtn->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
  55. m_pdfViewerBtn->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
  56. /*
  57. * Automatic dark mode detection works fine on Mac, so no need for the explicit options.
  58. */
  59. #ifdef __WXMAC__
  60. m_stIconTheme->Show( false );
  61. m_rbIconThemeLight->Show( false );
  62. m_rbIconThemeDark->Show( false );
  63. m_rbIconThemeAuto->Show( false );
  64. #endif
  65. /*
  66. * Automatic canvas scaling works fine on all supported platforms, so manual scaling is disabled
  67. */
  68. if( ADVANCED_CFG::GetCfg().m_AllowManualCanvasScale )
  69. {
  70. static constexpr int dpi_scaling_precision = 1;
  71. static constexpr double dpi_scaling_increment = 0.5;
  72. m_canvasScaleCtrl->SetRange( DPI_SCALING::GetMinScaleFactor(),
  73. DPI_SCALING::GetMaxScaleFactor() );
  74. m_canvasScaleCtrl->SetDigits( dpi_scaling_precision );
  75. m_canvasScaleCtrl->SetIncrement( dpi_scaling_increment );
  76. m_canvasScaleCtrl->SetValue( DPI_SCALING::GetDefaultScaleFactor() );
  77. m_canvasScaleCtrl->SetToolTip(
  78. _( "Set the scale for the canvas."
  79. "\n\n"
  80. "On high-DPI displays on some platforms, KiCad cannot determine the "
  81. "scaling factor. In this case you may need to set this to a value to "
  82. "match your system's DPI scaling. 2.0 is a common value. "
  83. "\n\n"
  84. "If this does not match the system DPI scaling, the canvas will "
  85. "not match the window size and cursor position." ) );
  86. m_canvasScaleAuto->SetToolTip(
  87. _( "Use an automatic value for the canvas scale."
  88. "\n\n"
  89. "On some platforms, the automatic value is incorrect and should be "
  90. "set manually." ) );
  91. }
  92. else
  93. {
  94. m_staticTextCanvasScale->Show( false );
  95. m_canvasScaleCtrl->Show( false );
  96. m_canvasScaleCtrl = nullptr;
  97. m_canvasScaleAuto->Show( false );
  98. }
  99. // Hide the option of icons in menus for platforms that do not support them
  100. m_checkBoxIconsInMenus->Show( KIPLATFORM::UI::AllowIconsInMenus() );
  101. m_scaleFonts->Show( false );
  102. m_fontScalingHelp->Show( false );
  103. if( m_canvasScaleCtrl )
  104. {
  105. m_canvasScaleCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED,
  106. wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
  107. nullptr, this );
  108. }
  109. wxSize minSize = m_highContrastCtrl->GetMinSize();
  110. int minWidth = m_highContrastCtrl->GetTextExtent( wxT( "XXX.XXX" ) ).GetWidth();
  111. m_highContrastCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
  112. }
  113. PANEL_COMMON_SETTINGS::~PANEL_COMMON_SETTINGS()
  114. {
  115. if( m_canvasScaleCtrl )
  116. {
  117. m_canvasScaleCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
  118. wxCommandEventHandler( PANEL_COMMON_SETTINGS::OnCanvasScaleChange ),
  119. nullptr, this );
  120. }
  121. }
  122. bool PANEL_COMMON_SETTINGS::TransferDataToWindow()
  123. {
  124. COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
  125. applySettingsToPanel( *commonSettings );
  126. m_textCtrlFileManager->SetValue( commonSettings->m_System.file_explorer );
  127. // TODO(JE) Move these into COMMON_SETTINGS probably
  128. m_textEditorPath->SetValue( Pgm().GetTextEditor( false ) );
  129. m_defaultPDFViewer->SetValue( Pgm().UseSystemPdfBrowser() );
  130. m_otherPDFViewer->SetValue( !Pgm().UseSystemPdfBrowser() );
  131. m_PDFViewerPath->SetValue( Pgm().GetPdfBrowserName() );
  132. setPdfViewerPathState();
  133. return true;
  134. }
  135. bool PANEL_COMMON_SETTINGS::TransferDataFromWindow()
  136. {
  137. COMMON_SETTINGS* commonSettings = Pgm().GetCommonSettings();
  138. commonSettings->m_System.file_explorer = m_textCtrlFileManager->GetValue();
  139. commonSettings->m_System.autosave_interval = m_SaveTime->GetValue() * 60;
  140. commonSettings->m_System.file_history_size = m_fileHistorySize->GetValue();
  141. commonSettings->m_System.clear_3d_cache_interval = m_Clear3DCacheFilesOlder->GetValue();
  142. commonSettings->m_Graphics.opengl_aa_mode = m_antialiasing->GetSelection();
  143. commonSettings->m_Graphics.cairo_aa_mode = m_antialiasingFallback->GetSelection();
  144. if( m_canvasScaleCtrl )
  145. {
  146. DPI_SCALING_COMMON dpi( commonSettings, this );
  147. dpi.SetDpiConfig( m_canvasScaleAuto->GetValue(), m_canvasScaleCtrl->GetValue() );
  148. }
  149. if( m_rbIconThemeLight->GetValue() )
  150. commonSettings->m_Appearance.icon_theme = ICON_THEME::LIGHT;
  151. else if( m_rbIconThemeDark->GetValue() )
  152. commonSettings->m_Appearance.icon_theme = ICON_THEME::DARK;
  153. else if( m_rbIconThemeAuto->GetValue() )
  154. commonSettings->m_Appearance.icon_theme = ICON_THEME::AUTO;
  155. if( m_rbIconSizeSmall->GetValue() )
  156. commonSettings->m_Appearance.toolbar_icon_size = 16;
  157. else if( m_rbIconSizeNormal->GetValue() )
  158. commonSettings->m_Appearance.toolbar_icon_size = 24;
  159. else if( m_rbIconSizeLarge->GetValue() )
  160. commonSettings->m_Appearance.toolbar_icon_size = 32;
  161. commonSettings->m_Appearance.use_icons_in_menus = m_checkBoxIconsInMenus->GetValue();
  162. commonSettings->m_Appearance.apply_icon_scale_to_fonts = m_scaleFonts->GetValue();
  163. commonSettings->m_Appearance.show_scrollbars = m_showScrollbars->GetValue();
  164. commonSettings->m_Appearance.grid_striping = m_gridStriping->GetValue();
  165. double dimmingPercent = 80;
  166. m_highContrastCtrl->GetValue().ToDouble( &dimmingPercent );
  167. commonSettings->m_Appearance.hicontrast_dimming_factor = dimmingPercent / 100.0f;
  168. commonSettings->m_Input.focus_follow_sch_pcb = m_focusFollowSchPcb->GetValue();
  169. commonSettings->m_Input.hotkey_feedback = m_hotkeyFeedback->GetValue();
  170. commonSettings->m_Input.immediate_actions = !m_NonImmediateActions->GetValue();
  171. commonSettings->m_Input.warp_mouse_on_move = m_warpMouseOnMove->GetValue();
  172. commonSettings->m_Backup.enabled = m_cbBackupEnabled->GetValue();
  173. commonSettings->m_Backup.backup_on_autosave = m_cbBackupAutosave->GetValue();
  174. commonSettings->m_Backup.limit_total_files = m_backupLimitTotalFiles->GetValue();
  175. commonSettings->m_Backup.limit_daily_files = m_backupLimitDailyFiles->GetValue();
  176. commonSettings->m_Backup.min_interval = m_backupMinInterval->GetValue() * 60;
  177. commonSettings->m_Backup.limit_total_size = m_backupLimitTotalSize->GetValue() * 1024 * 1024;
  178. commonSettings->m_Session.remember_open_files = m_cbRememberOpenFiles->GetValue();
  179. Pgm().SetTextEditor( m_textEditorPath->GetValue());
  180. Pgm().SetPdfBrowserName( m_PDFViewerPath->GetValue() );
  181. Pgm().ForceSystemPdfBrowser( m_defaultPDFViewer->GetValue() );
  182. Pgm().WritePdfBrowserInfos();
  183. Pgm().GetSettingsManager().Save( commonSettings );
  184. return true;
  185. }
  186. void PANEL_COMMON_SETTINGS::ResetPanel()
  187. {
  188. COMMON_SETTINGS defaultSettings;
  189. defaultSettings.ResetToDefaults();
  190. applySettingsToPanel( defaultSettings );
  191. // TODO(JE) Move these into COMMON_SETTINGS probably
  192. m_textEditorPath->SetValue( defaultSettings.m_System.text_editor );
  193. m_defaultPDFViewer->SetValue( defaultSettings.m_System.use_system_pdf_viewer );
  194. m_otherPDFViewer->SetValue( !defaultSettings.m_System.use_system_pdf_viewer );
  195. m_PDFViewerPath->SetValue( defaultSettings.m_System.pdf_viewer_name );
  196. setPdfViewerPathState();
  197. }
  198. void PANEL_COMMON_SETTINGS::applySettingsToPanel( COMMON_SETTINGS& aSettings )
  199. {
  200. int timevalue = aSettings.m_System.autosave_interval;
  201. wxString msg;
  202. msg << timevalue / 60;
  203. m_SaveTime->SetValue( msg );
  204. m_fileHistorySize->SetValue( aSettings.m_System.file_history_size );
  205. m_antialiasing->SetSelection( aSettings.m_Graphics.opengl_aa_mode );
  206. m_antialiasingFallback->SetSelection( aSettings.m_Graphics.cairo_aa_mode );
  207. m_Clear3DCacheFilesOlder->SetValue( aSettings.m_System.clear_3d_cache_interval );
  208. if( m_canvasScaleCtrl )
  209. {
  210. const DPI_SCALING_COMMON dpi( &aSettings, this );
  211. m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
  212. m_canvasScaleAuto->SetValue( dpi.GetCanvasIsAutoScaled() );
  213. }
  214. switch( aSettings.m_Appearance.icon_theme )
  215. {
  216. case ICON_THEME::LIGHT: m_rbIconThemeLight->SetValue( true ); break;
  217. case ICON_THEME::DARK: m_rbIconThemeDark->SetValue( true ); break;
  218. case ICON_THEME::AUTO: m_rbIconThemeAuto->SetValue( true ); break;
  219. }
  220. switch( aSettings.m_Appearance.toolbar_icon_size )
  221. {
  222. case 16: m_rbIconSizeSmall->SetValue( true ); break;
  223. case 24: m_rbIconSizeNormal->SetValue( true ); break;
  224. case 32: m_rbIconSizeLarge->SetValue( true ); break;
  225. }
  226. m_checkBoxIconsInMenus->SetValue( aSettings.m_Appearance.use_icons_in_menus );
  227. m_scaleFonts->SetValue( aSettings.m_Appearance.apply_icon_scale_to_fonts );
  228. m_gridStriping->SetValue( aSettings.m_Appearance.grid_striping );
  229. double dimmingPercent = aSettings.m_Appearance.hicontrast_dimming_factor * 100.0f;
  230. m_highContrastCtrl->SetValue( wxString::Format( "%.0f", dimmingPercent ) );
  231. m_focusFollowSchPcb->SetValue( aSettings.m_Input.focus_follow_sch_pcb );
  232. m_hotkeyFeedback->SetValue( aSettings.m_Input.hotkey_feedback );
  233. m_warpMouseOnMove->SetValue( aSettings.m_Input.warp_mouse_on_move );
  234. m_NonImmediateActions->SetValue( !aSettings.m_Input.immediate_actions );
  235. m_cbRememberOpenFiles->SetValue( aSettings.m_Session.remember_open_files );
  236. m_cbBackupEnabled->SetValue( aSettings.m_Backup.enabled );
  237. m_cbBackupAutosave->SetValue( aSettings.m_Backup.backup_on_autosave );
  238. m_backupLimitTotalFiles->SetValue( aSettings.m_Backup.limit_total_files );
  239. m_backupLimitDailyFiles->SetValue( aSettings.m_Backup.limit_daily_files );
  240. m_backupMinInterval->SetValue( aSettings.m_Backup.min_interval / 60 );
  241. m_backupLimitTotalSize->SetValue( aSettings.m_Backup.limit_total_size / ( 1024 * 1024 ) );
  242. m_showScrollbars->SetValue( aSettings.m_Appearance.show_scrollbars );
  243. }
  244. void PANEL_COMMON_SETTINGS::OnCanvasScaleChange( wxCommandEvent& aEvent )
  245. {
  246. m_canvasScaleAuto->SetValue( false );
  247. }
  248. void PANEL_COMMON_SETTINGS::OnCanvasScaleAuto( wxCommandEvent& aEvent )
  249. {
  250. const bool automatic = m_canvasScaleAuto->GetValue();
  251. if( automatic && m_canvasScaleCtrl )
  252. {
  253. // set the scale to the auto value, without consulting the config
  254. DPI_SCALING_COMMON dpi( nullptr, this );
  255. // update the field (no events sent)
  256. m_canvasScaleCtrl->SetValue( dpi.GetScaleFactor() );
  257. }
  258. }
  259. void PANEL_COMMON_SETTINGS::OnTextEditorClick( wxCommandEvent& event )
  260. {
  261. // Ask the user to select a new editor, but suggest the current one as the default.
  262. wxString editorname = Pgm().AskUserForPreferredEditor( m_textEditorPath->GetValue() );
  263. // If we have a new editor name request it to be copied to m_text_editor and saved
  264. // to the preferences file. If the user cancelled the dialog then the previous
  265. // value will be retained.
  266. if( !editorname.IsEmpty() )
  267. m_textEditorPath->SetValue( editorname );
  268. }
  269. void PANEL_COMMON_SETTINGS::ShowFileManagerWidgets( bool aBool )
  270. {
  271. m_staticTextFileManager->Show( aBool );
  272. m_textCtrlFileManager->Show( aBool );
  273. if( aBool )
  274. {
  275. #if defined( __WINDOWS__ )
  276. wxString msg = _( "Default 'explorer.exe /n,/select,%F' for this OS." );
  277. m_textCtrlFileManager->SetToolTip( msg );
  278. wxString str = "%F";
  279. #else
  280. wxString msg = _( "File explorer command.\nexample:" ) + wxS( " 'nemo -n %F'" );
  281. m_textCtrlFileManager->SetToolTip( msg );
  282. wxString str= " %F";
  283. #endif
  284. msg = _( "Explorer command with mandatory '%s' suffix after last entered character." );
  285. m_staticTextFileManager->SetToolTip( wxString::Format( msg, str ) );
  286. }
  287. }
  288. void PANEL_COMMON_SETTINGS::OnPDFViewerClick( wxCommandEvent& event )
  289. {
  290. wxString mask( wxT( "*" ) );
  291. #ifdef __WINDOWS__
  292. mask += wxT( ".exe" );
  293. #endif
  294. wxString wildcard = _( "Executable files (" ) + mask + wxT( ")|" ) + mask;
  295. Pgm().ReadPdfBrowserInfos();
  296. wxFileName fn = Pgm().GetPdfBrowserName();
  297. wxWindow* topLevelParent = wxGetTopLevelParent( this );
  298. wxFileDialog dlg( topLevelParent, _( "Select Preferred PDF Viewer" ), fn.GetPath(),
  299. fn.GetFullPath(), wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
  300. if( dlg.ShowModal() == wxID_CANCEL )
  301. return;
  302. m_otherPDFViewer->SetValue( true );
  303. m_PDFViewerPath->SetValue( dlg.GetPath() );
  304. }
  305. void PANEL_COMMON_SETTINGS::OnRadioButtonPdfViewer( wxCommandEvent& event )
  306. {
  307. setPdfViewerPathState();
  308. }
  309. void PANEL_COMMON_SETTINGS::setPdfViewerPathState()
  310. {
  311. m_PDFViewerPath->Enable( m_otherPDFViewer->GetValue() );
  312. m_pdfViewerBtn->Enable( m_otherPDFViewer->GetValue() );
  313. }