فهرست منبع

Refactor the app prefs group

David Robertson 5 سال پیش
والد
کامیت
a2d48d1c66

+ 20 - 20
FlatCAMApp.py

@@ -625,8 +625,9 @@ class App(QtCore.QObject):
         # ###########################################################################################################
 
         self.languages = fcTranslate.load_languages()
+        language_field = self.preferencesUiManager.get_form_field("global_language")
         for name in sorted(self.languages.values()):
-            self.ui.general_defaults_form.general_app_group.language_cb.addItem(name)
+            language_field.addItem(name)
 
         # ###########################################################################################################
         # ####################################### APPLY APP LANGUAGE ################################################
@@ -639,7 +640,7 @@ class App(QtCore.QObject):
             log.debug("Could not find the Language files. The App strings are missing.")
         else:
             # make the current language the current selection on the language combobox
-            self.ui.general_defaults_form.general_app_group.language_cb.setCurrentText(ret_val)
+            self.preferencesUiManager.get_form_field("global_language").setCurrentText(ret_val)
             log.debug("App.__init__() --> Applied %s language." % str(ret_val).capitalize())
 
         # ###########################################################################################################
@@ -959,25 +960,24 @@ class App(QtCore.QObject):
         # #################################### GUI PREFERENCES SIGNALS ##############################################
         # ###########################################################################################################
 
-        self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect(
+        self.preferencesUiManager.get_form_field("units").activated_custom.connect(
             lambda: self.on_toggle_units(no_pref=False))
 
         # ##################################### Workspace Setting Signals ###########################################
 
 
-        self.preferencesUiManager.option_dict()["global_workspaceT"].get_field().currentIndexChanged.connect(
+        self.preferencesUiManager.get_form_field("global_workspaceT").currentIndexChanged.connect(
             self.on_workspace_modified)
-        self.preferencesUiManager.option_dict()["global_workspace_orientation"].get_field().activated_custom.connect(
+        self.preferencesUiManager.get_form_field("global_workspace_orientation").activated_custom.connect(
             self.on_workspace_modified
         )
-        self.preferencesUiManager.option_dict()["global_workspace"].get_field().stateChanged.connect(self.on_workspace)
+        self.preferencesUiManager.get_form_field("global_workspace").stateChanged.connect(self.on_workspace)
 
 
         # ###########################################################################################################
         # ######################################## GUI SETTINGS SIGNALS #############################################
         # ###########################################################################################################
-        self.ui.general_defaults_form.general_app_group.ge_radio.activated_custom.connect(self.on_app_restart)
-
+        self.preferencesUiManager.get_form_field("global_graphic_engine").activated_custom.connect(self.on_app_restart)
         self.preferencesUiManager.get_form_field("global_cursor_type").activated_custom.connect(self.on_cursor_type)
 
         # ######################################## Tools related signals ############################################
@@ -998,7 +998,7 @@ class App(QtCore.QObject):
             self.on_qrcode_back_color_button)
 
         # portability changed signal
-        self.ui.general_defaults_form.general_app_group.portability_cb.stateChanged.connect(self.on_portable_checked)
+        self.preferencesUiManager.get_form_field("global_portable").stateChanged.connect(self.on_portable_checked)
 
         # Object list
         self.collection.view.activated.connect(self.on_row_activated)
@@ -1421,8 +1421,8 @@ class App(QtCore.QObject):
         # Separate thread (Not worker)
         # Check for updates on startup but only if the user consent and the app is not in Beta version
         if (self.beta is False or self.beta is None) and \
-                self.ui.general_defaults_form.general_app_group.version_check_cb.get_value() is True:
-            App.log.info("Checking for updates in backgroud (this is version %s)." % str(self.version))
+                self.preferencesUiManager.get_form_field("global_version_check").get_value() is True:
+            App.log.info("Checking for updates in background (this is version %s)." % str(self.version))
 
             # self.thr2 = QtCore.QThread()
             self.worker_task.emit({'fcn': self.version_check,
@@ -1549,7 +1549,7 @@ class App(QtCore.QObject):
         self.abort_flag = False
 
         # set the value used in the Windows Title
-        self.engine = self.ui.general_defaults_form.general_app_group.ge_radio.get_value()
+        self.engine = self.preferencesUiManager.get_form_field("global_graphic_engine").get_value()
 
         # this holds a widget that is installed in the Plot Area when View Source option is used
         self.source_editor_tab = None
@@ -3562,7 +3562,7 @@ class App(QtCore.QObject):
             stgs.setValue('maximized_gui', self.ui.isMaximized())
             stgs.setValue(
                 'language',
-                self.ui.general_defaults_form.general_app_group.language_cb.get_value()
+                self.preferencesUiManager.get_form_field("global_language").get_value()
             )
             stgs.setValue(
                 'notebook_font_size',
@@ -4204,18 +4204,18 @@ class App(QtCore.QObject):
 
     def on_toggle_units_click(self):
         try:
-            self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.disconnect()
+            self.preferencesUiManager.get_form_field("units").activated_custom.disconnect()
         except (TypeError, AttributeError):
             pass
 
         if self.defaults["units"] == 'MM':
-            self.ui.general_defaults_form.general_app_group.units_radio.set_value("IN")
+            self.preferencesUiManager.get_form_field("units").set_value("IN")
         else:
-            self.ui.general_defaults_form.general_app_group.units_radio.set_value("MM")
+            self.preferencesUiManager.get_form_field("units").set_value("MM")
 
         self.on_toggle_units(no_pref=True)
 
-        self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect(
+        self.preferencesUiManager.get_form_field("units").activated_custom.connect(
             lambda: self.on_toggle_units(no_pref=False))
 
     def on_toggle_units(self, no_pref=False):
@@ -4233,7 +4233,7 @@ class App(QtCore.QObject):
         if self.toggle_units_ignore:
             return
 
-        new_units = self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
+        new_units = self.preferencesUiManager.get_form_field("units").get_value().upper()
 
         # If option is the same, then ignore
         if new_units == self.defaults["units"].upper():
@@ -4530,9 +4530,9 @@ class App(QtCore.QObject):
             # Undo toggling
             self.toggle_units_ignore = True
             if self.defaults['units'].upper() == 'MM':
-                self.ui.general_defaults_form.general_app_group.units_radio.set_value('IN')
+                self.preferencesUiManager.get_form_field("units").set_value('IN')
             else:
-                self.ui.general_defaults_form.general_app_group.units_radio.set_value('MM')
+                self.preferencesUiManager.get_form_field("units").set_value('MM')
             self.toggle_units_ignore = False
 
             # store the grid values so they are not changed in the next step

+ 1 - 1
FlatCAMTranslation.py

@@ -79,7 +79,7 @@ def on_language_apply_click(app, restart=False):
 
     :return:
     """
-    name = app.ui.general_defaults_form.general_app_group.language_cb.currentText()
+    name = app.preferencesUiManager.get_form_field("global_language").currentText()
 
     theme_settings = QSettings("Open Source", "FlatCAM")
     if theme_settings.contains("theme"):

+ 1 - 1
flatcamGUI/FlatCAMGUI.py

@@ -4057,7 +4057,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                     if key == QtCore.Qt.Key_T or key == 'T':
                         self.app.exc_editor.launched_from_shortcuts = True
                         # ## Current application units in Upper Case
-                        self.units = self.general_defaults_form.general_app_group.units_radio.get_value().upper()
+                        self.units = self.general_defaults_form.option_dict()["units"].get_field().get_value().upper()
                         tool_add_popup = FCInputDialog(title=_("New Tool ..."),
                                                        text='%s:' % _('Enter a Tool Diameter'),
                                                        min=0.0000, max=99.9999, decimals=4)

+ 20 - 13
flatcamGUI/preferences/OptionUI.py

@@ -30,15 +30,22 @@ class OptionUI:
 
 class BasicOptionUI(OptionUI):
     """Abstract OptionUI that has a label on the left then some other widget on the right"""
-    def __init__(self, option: str, label_text: str, label_tooltip: str):
+    def __init__(self, option: str, label_text: str, label_tooltip: Union[str, None] = None, label_bold: bool = False, label_red: bool = False):
         super().__init__(option=option)
         self.label_text = label_text
         self.label_tooltip = label_tooltip
+        self.label_bold = label_bold
+        self.label_red = label_red
         self.label_widget = self.build_label_widget()
         self.entry_widget = self.build_entry_widget()
 
     def build_label_widget(self) -> QtWidgets.QLabel:
-        label_widget = QtWidgets.QLabel('%s:' % _(self.label_text))
+        fmt = "%s:"
+        if self.label_bold:
+            fmt = "<b>%s</b>" % fmt
+        if self.label_red:
+            fmt = "<span style=\"color:red;\">%s</span>" % fmt
+        label_widget = QtWidgets.QLabel(fmt % _(self.label_text))
         if self.label_tooltip is not None:
             label_widget.setToolTip(_(self.label_tooltip))
         return label_widget
@@ -57,10 +64,10 @@ class BasicOptionUI(OptionUI):
 
 class RadioSetOptionUI(BasicOptionUI):
 
-    def __init__(self, option: str, label_text: str, label_tooltip: str, choices: list, orientation='horizontal'):
+    def __init__(self, option: str, label_text: str, choices: list, orientation='horizontal', **kwargs):
         self.choices = choices
         self.orientation = orientation
-        super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip)
+        super().__init__(option=option, label_text=label_text, **kwargs)
 
     def build_entry_widget(self) -> QtWidgets.QWidget:
         return RadioSet(choices=self.choices, orientation=self.orientation)
@@ -89,9 +96,9 @@ class CheckboxOptionUI(OptionUI):
 
 class ComboboxOptionUI(BasicOptionUI):
 
-    def __init__(self, option: str, label_text: str, label_tooltip: str, choices: Sequence):
+    def __init__(self, option: str, label_text: str, choices: Sequence, **kwargs):
         self.choices = choices
-        super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip)
+        super().__init__(option=option, label_text=label_text, **kwargs)
 
     def build_entry_widget(self):
         combo = FCComboBox()
@@ -108,11 +115,11 @@ class ColorOptionUI(BasicOptionUI):
 
 
 class SliderWithSpinnerOptionUI(BasicOptionUI):
-    def __init__(self, option: str, label_text: str, label_tooltip: str, min_value=0, max_value=100, step=1):
+    def __init__(self, option: str, label_text: str, min_value=0, max_value=100, step=1, **kwargs):
         self.min_value = min_value
         self.max_value = max_value
         self.step = step
-        super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip)
+        super().__init__(option=option, label_text=label_text, **kwargs)
 
     def build_entry_widget(self) -> QtWidgets.QWidget:
         entry = FCSliderWithSpinner(min=self.min_value, max=self.max_value, step=self.step)
@@ -120,11 +127,11 @@ class SliderWithSpinnerOptionUI(BasicOptionUI):
 
 
 class SpinnerOptionUI(BasicOptionUI):
-    def __init__(self, option: str, label_text: str, label_tooltip: str, min_value: int, max_value: int, step: int = 1):
+    def __init__(self, option: str, label_text: str, min_value: int, max_value: int, step: int = 1, **kwargs):
         self.min_value = min_value
         self.max_value = max_value
         self.step = step
-        super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip)
+        super().__init__(option=option, label_text=label_text, **kwargs)
 
     def build_entry_widget(self) -> QtWidgets.QWidget:
         entry = FCSpinner()
@@ -135,12 +142,12 @@ class SpinnerOptionUI(BasicOptionUI):
 
 
 class DoubleSpinnerOptionUI(BasicOptionUI):
-    def __init__(self, option: str, label_text: str, label_tooltip: str, step: float, decimals: int, min_value=None, max_value=None):
+    def __init__(self, option: str, label_text: str, step: float, decimals: int, min_value=None, max_value=None, **kwargs):
         self.min_value = min_value
         self.max_value = max_value
         self.step = step
         self.decimals = decimals
-        super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip)
+        super().__init__(option=option, label_text=label_text, **kwargs)
 
     def build_entry_widget(self) -> QtWidgets.QWidget:
         entry = FCDoubleSpinner()
@@ -158,7 +165,7 @@ class DoubleSpinnerOptionUI(BasicOptionUI):
 
 
 class HeadingOptionUI(OptionUI):
-    def __init__(self, label_text: str, label_tooltip: Union[str, None]):
+    def __init__(self, label_text: str, label_tooltip: Union[str, None] = None):
         super().__init__(option="__heading")
         self.label_text = label_text
         self.label_tooltip = label_tooltip

+ 2 - 30
flatcamGUI/preferences/PreferencesUIManager.py

@@ -48,34 +48,6 @@ class PreferencesUIManager:
         # when adding entries here read the comments in the  method found below named:
         # def new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
         self.defaults_form_fields = {
-            # General App
-            "decimals_inch": self.ui.general_defaults_form.general_app_group.precision_inch_entry,
-            "decimals_metric": self.ui.general_defaults_form.general_app_group.precision_metric_entry,
-            "units": self.ui.general_defaults_form.general_app_group.units_radio,
-            "global_graphic_engine": self.ui.general_defaults_form.general_app_group.ge_radio,
-            "global_app_level": self.ui.general_defaults_form.general_app_group.app_level_radio,
-            "global_portable": self.ui.general_defaults_form.general_app_group.portability_cb,
-            "global_language": self.ui.general_defaults_form.general_app_group.language_cb,
-
-            "global_systray_icon": self.ui.general_defaults_form.general_app_group.systray_cb,
-            "global_shell_at_startup": self.ui.general_defaults_form.general_app_group.shell_startup_cb,
-            "global_project_at_startup": self.ui.general_defaults_form.general_app_group.project_startup_cb,
-            "global_version_check": self.ui.general_defaults_form.general_app_group.version_check_cb,
-            "global_send_stats": self.ui.general_defaults_form.general_app_group.send_stats_cb,
-
-            "global_worker_number": self.ui.general_defaults_form.general_app_group.worker_number_sb,
-            "global_tolerance": self.ui.general_defaults_form.general_app_group.tol_entry,
-
-            "global_compression_level": self.ui.general_defaults_form.general_app_group.compress_spinner,
-            "global_save_compressed": self.ui.general_defaults_form.general_app_group.save_type_cb,
-            "global_autosave": self.ui.general_defaults_form.general_app_group.autosave_cb,
-            "global_autosave_timeout": self.ui.general_defaults_form.general_app_group.autosave_entry,
-
-            "global_tpdf_tmargin": self.ui.general_defaults_form.general_app_group.tmargin_entry,
-            "global_tpdf_bmargin": self.ui.general_defaults_form.general_app_group.bmargin_entry,
-            "global_tpdf_lmargin": self.ui.general_defaults_form.general_app_group.lmargin_entry,
-            "global_tpdf_rmargin": self.ui.general_defaults_form.general_app_group.rmargin_entry,
-
             # Gerber General
             "gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
             "gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb,
@@ -844,11 +816,11 @@ class PreferencesUIManager:
         self.ignore_tab_close_event = True
 
         try:
-            self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.disconnect()
+            self.get_form_field("units").activated_custom.disconnect()
         except (TypeError, AttributeError):
             pass
         self.defaults_write_form(source_dict=self.defaults.current_defaults)
-        self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect(
+        self.get_form_field("units").activated_custom.connect(
             lambda: self.ui.app.on_toggle_units(no_pref=False))
         self.defaults.update(self.defaults.current_defaults)
 

+ 227 - 356
flatcamGUI/preferences/general/GeneralAppPrefGroupUI.py

@@ -1,382 +1,253 @@
 import sys
 
-from PyQt5 import QtWidgets
 from PyQt5.QtCore import QSettings
 
-from flatcamGUI.GUIElements import RadioSet, FCSpinner, FCCheckBox, FCComboBox, FCButton, OptionalInputSection, \
-    FCDoubleSpinner
-from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
+from flatcamGUI.GUIElements import OptionalInputSection
+from flatcamGUI.preferences.OptionUI import *
+from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2
 
 import gettext
 import FlatCAMTranslation as fcTranslate
 import builtins
-
 fcTranslate.apply_language('strings')
 if '_' not in builtins.__dict__:
     _ = gettext.gettext
 
-settings = QSettings("Open Source", "FlatCAM")
-if settings.contains("machinist"):
-    machinist_setting = settings.value('machinist', type=int)
-else:
-    machinist_setting = 0
-
 
-class GeneralAppPrefGroupUI(OptionsGroupUI):
+class GeneralAppPrefGroupUI(OptionsGroupUI2):
     def __init__(self, decimals=4, **kwargs):
-        super().__init__(**kwargs)
-
-        self.setTitle(_("App Preferences"))
         self.decimals = decimals
+        super().__init__(**kwargs)
+        self.setTitle(str(_("App Preferences")))
 
-        # Create a form layout for the Application general settings
-        grid0 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid0)
-        grid0.setColumnStretch(0, 0)
-        grid0.setColumnStretch(1, 1)
-
-        # Units for FlatCAM
-        self.unitslabel = QtWidgets.QLabel('<span style="color:red;"><b>%s:</b></span>' % _('Units'))
-        self.unitslabel.setToolTip(_("The default value for FlatCAM units.\n"
-                                     "Whatever is selected here is set every time\n"
-                                     "FlatCAM is started."))
-        self.units_radio = RadioSet([{'label': _('MM'), 'value': 'MM'},
-                                     {'label': _('IN'), 'value': 'IN'}])
-
-        grid0.addWidget(self.unitslabel, 0, 0)
-        grid0.addWidget(self.units_radio, 0, 1)
-
-        # Precision Metric
-        self.precision_metric_label = QtWidgets.QLabel('%s:' % _('Precision MM'))
-        self.precision_metric_label.setToolTip(
-            _("The number of decimals used throughout the application\n"
-              "when the set units are in METRIC system.\n"
-              "Any change here require an application restart.")
-        )
-        self.precision_metric_entry = FCSpinner()
-        self.precision_metric_entry.set_range(2, 16)
-        self.precision_metric_entry.setWrapping(True)
-
-        grid0.addWidget(self.precision_metric_label, 1, 0)
-        grid0.addWidget(self.precision_metric_entry, 1, 1)
-
-        # Precision Inch
-        self.precision_inch_label = QtWidgets.QLabel('%s:' % _('Precision INCH'))
-        self.precision_inch_label.setToolTip(
-            _("The number of decimals used throughout the application\n"
-              "when the set units are in INCH system.\n"
-              "Any change here require an application restart.")
-        )
-        self.precision_inch_entry = FCSpinner()
-        self.precision_inch_entry.set_range(2, 16)
-        self.precision_inch_entry.setWrapping(True)
-
-        grid0.addWidget(self.precision_inch_label, 2, 0)
-        grid0.addWidget(self.precision_inch_entry, 2, 1)
-
-        # Graphic Engine for FlatCAM
-        self.ge_label = QtWidgets.QLabel('<b>%s:</b>' % _('Graphic Engine'))
-        self.ge_label.setToolTip(_("Choose what graphic engine to use in FlatCAM.\n"
-                                   "Legacy(2D) -> reduced functionality, slow performance but enhanced compatibility.\n"
-                                   "OpenGL(3D) -> full functionality, high performance\n"
-                                   "Some graphic cards are too old and do not work in OpenGL(3D) mode, like:\n"
-                                   "Intel HD3000 or older. In this case the plot area will be black therefore\n"
-                                   "use the Legacy(2D) mode."))
-        self.ge_radio = RadioSet([{'label': _('Legacy(2D)'), 'value': '2D'},
-                                  {'label': _('OpenGL(3D)'), 'value': '3D'}],
-                                 orientation='vertical')
-
-        grid0.addWidget(self.ge_label, 3, 0)
-        grid0.addWidget(self.ge_radio, 3, 1)
-
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 4, 0, 1, 2)
-
-        # Application Level for FlatCAM
-        self.app_level_label = QtWidgets.QLabel('<span style="color:red;"><b>%s:</b></span>' % _('APP. LEVEL'))
-        self.app_level_label.setToolTip(_("Choose the default level of usage for FlatCAM.\n"
-                                          "BASIC level -> reduced functionality, best for beginner's.\n"
-                                          "ADVANCED level -> full functionality.\n\n"
-                                          "The choice here will influence the parameters in\n"
-                                          "the Selected Tab for all kinds of FlatCAM objects."))
-        self.app_level_radio = RadioSet([{'label': _('Basic'), 'value': 'b'},
-                                         {'label': _('Advanced'), 'value': 'a'}])
-
-        grid0.addWidget(self.app_level_label, 5, 0)
-        grid0.addWidget(self.app_level_radio, 5, 1)
-
-        # Portability for FlatCAM
-        self.portability_cb = FCCheckBox('%s' % _('Portable app'))
-        self.portability_cb.setToolTip(_("Choose if the application should run as portable.\n\n"
-                                         "If Checked the application will run portable,\n"
-                                         "which means that the preferences files will be saved\n"
-                                         "in the application folder, in the lib\\config subfolder."))
-
-        grid0.addWidget(self.portability_cb, 6, 0, 1, 2)
-
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 7, 0, 1, 2)
-
-        # Languages for FlatCAM
-        self.languagelabel = QtWidgets.QLabel('<b>%s</b>' % _('Languages'))
-        self.languagelabel.setToolTip(_("Set the language used throughout FlatCAM."))
-        self.language_cb = FCComboBox()
-
-        grid0.addWidget(self.languagelabel, 8, 0, 1, 2)
-        grid0.addWidget(self.language_cb, 9, 0, 1, 2)
-
-        self.language_apply_btn = FCButton(_("Apply Language"))
-        self.language_apply_btn.setToolTip(_("Set the language used throughout FlatCAM.\n"
-                                             "The app will restart after click."))
-
-        grid0.addWidget(self.language_apply_btn, 15, 0, 1, 2)
-
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 16, 0, 1, 2)
-
-        # -----------------------------------------------------------
-        # ----------- APPLICATION STARTUP SETTINGS ------------------
-        # -----------------------------------------------------------
-
-        self.startup_label = QtWidgets.QLabel('<b>%s</b>' % _('Startup Settings'))
-        grid0.addWidget(self.startup_label, 17, 0, 1, 2)
-
-        # Splash Screen
-        self.splash_cb = FCCheckBox('%s' % _('Splash Screen'))
-        self.splash_cb.setToolTip(
-            _("Enable display of the splash screen at application startup.")
-        )
+        if sys.platform != 'win32':
+            self.option_dict()["global_portable"].get_field().hide()
+        self.option_dict()["splash_screen"].get_field().stateChanged.connect(self.on_splash_changed)
+        self.option_dict()["global_shell_at_startup"].get_field().clicked.connect(self.on_toggle_shell_from_settings)
+        self.option_dict()["__apply_language_button"].get_field().clicked.connect(lambda: fcTranslate.on_language_apply_click(app=self.app, restart=True))
 
         qsettings = QSettings("Open Source", "FlatCAM")
         if qsettings.value("splash_screen"):
-            self.splash_cb.set_value(True)
+            self.option_dict()["splash_screen"].get_field().set_value(True)
         else:
-            self.splash_cb.set_value(False)
-
-        grid0.addWidget(self.splash_cb, 18, 0, 1, 2)
-
-        # Sys Tray Icon
-        self.systray_cb = FCCheckBox('%s' % _('Sys Tray Icon'))
-        self.systray_cb.setToolTip(
-            _("Enable display of FlatCAM icon in Sys Tray.")
-        )
-        grid0.addWidget(self.systray_cb, 19, 0, 1, 2)
-
-        # Shell StartUp CB
-        self.shell_startup_cb = FCCheckBox(label='%s' % _('Show Shell'))
-        self.shell_startup_cb.setToolTip(
-            _("Check this box if you want the shell to\n"
-              "start automatically at startup.")
-        )
-
-        grid0.addWidget(self.shell_startup_cb, 20, 0, 1, 2)
-
-        # Project at StartUp CB
-        self.project_startup_cb = FCCheckBox(label='%s' % _('Show Project'))
-        self.project_startup_cb.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "to be shown automatically at startup.")
-        )
-        grid0.addWidget(self.project_startup_cb, 21, 0, 1, 2)
-
-        # Version Check CB
-        self.version_check_cb = FCCheckBox(label='%s' % _('Version Check'))
-        self.version_check_cb.setToolTip(
-            _("Check this box if you want to check\n"
-              "for a new version automatically at startup.")
-        )
-
-        grid0.addWidget(self.version_check_cb, 22, 0, 1, 2)
-
-        # Send Stats CB
-        self.send_stats_cb = FCCheckBox(label='%s' % _('Send Statistics'))
-        self.send_stats_cb.setToolTip(
-            _("Check this box if you agree to send anonymous\n"
-              "stats automatically at startup, to help improve FlatCAM.")
-        )
+            self.option_dict()["splash_screen"].get_field().set_value(False)
 
-        grid0.addWidget(self.send_stats_cb, 23, 0, 1, 2)
-
-        self.ois_version_check = OptionalInputSection(self.version_check_cb, [self.send_stats_cb])
-
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 24, 0, 1, 2)
-
-        # Worker Numbers
-        self.worker_number_label = QtWidgets.QLabel('%s:' % _('Workers number'))
-        self.worker_number_label.setToolTip(
-            _("The number of Qthreads made available to the App.\n"
-              "A bigger number may finish the jobs more quickly but\n"
-              "depending on your computer speed, may make the App\n"
-              "unresponsive. Can have a value between 2 and 16.\n"
-              "Default value is 2.\n"
-              "After change, it will be applied at next App start.")
-        )
-        self.worker_number_sb = FCSpinner()
-        self.worker_number_sb.set_range(2, 16)
-
-        grid0.addWidget(self.worker_number_label, 25, 0)
-        grid0.addWidget(self.worker_number_sb, 25, 1)
-
-        # Geometric tolerance
-        tol_label = QtWidgets.QLabel('%s:' % _("Geo Tolerance"))
-        tol_label.setToolTip(_(
-            "This value can counter the effect of the Circle Steps\n"
-            "parameter. Default value is 0.005.\n"
-            "A lower value will increase the detail both in image\n"
-            "and in Gcode for the circles, with a higher cost in\n"
-            "performance. Higher value will provide more\n"
-            "performance at the expense of level of detail."
-        ))
-        self.tol_entry = FCDoubleSpinner()
-        self.tol_entry.setSingleStep(0.001)
-        self.tol_entry.set_precision(6)
-
-        grid0.addWidget(tol_label, 26, 0)
-        grid0.addWidget(self.tol_entry, 26, 1)
-
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 27, 0, 1, 2)
-
-        # Save Settings
-        self.save_label = QtWidgets.QLabel('<b>%s</b>' % _("Save Settings"))
-        grid0.addWidget(self.save_label, 28, 0, 1, 2)
-
-        # Save compressed project CB
-        self.save_type_cb = FCCheckBox(_('Save Compressed Project'))
-        self.save_type_cb.setToolTip(
-            _("Whether to save a compressed or uncompressed project.\n"
-              "When checked it will save a compressed FlatCAM project.")
-        )
-
-        grid0.addWidget(self.save_type_cb, 29, 0, 1, 2)
-
-        # Project LZMA Comppression Level
-        self.compress_spinner = FCSpinner()
-        self.compress_spinner.set_range(0, 9)
-        self.compress_label = QtWidgets.QLabel('%s:' % _('Compression'))
-        self.compress_label.setToolTip(
-            _("The level of compression used when saving\n"
-              "a FlatCAM project. Higher value means better compression\n"
-              "but require more RAM usage and more processing time.")
-        )
-
-        grid0.addWidget(self.compress_label, 30, 0)
-        grid0.addWidget(self.compress_spinner, 30, 1)
-
-        self.proj_ois = OptionalInputSection(self.save_type_cb, [self.compress_label, self.compress_spinner], True)
-
-        # Auto save CB
-        self.autosave_cb = FCCheckBox(_('Enable Auto Save'))
-        self.autosave_cb.setToolTip(
-            _("Check to enable the autosave feature.\n"
-              "When enabled, the application will try to save a project\n"
-              "at the set interval.")
-        )
-
-        grid0.addWidget(self.autosave_cb, 31, 0, 1, 2)
-
-        # Auto Save Timeout Interval
-        self.autosave_entry = FCSpinner()
-        self.autosave_entry.set_range(0, 9999999)
-        self.autosave_label = QtWidgets.QLabel('%s:' % _('Interval'))
-        self.autosave_label.setToolTip(
-            _("Time interval for autosaving. In milliseconds.\n"
-              "The application will try to save periodically but only\n"
-              "if the project was saved manually at least once.\n"
-              "While active, some operations may block this feature.")
-        )
-
-        grid0.addWidget(self.autosave_label, 32, 0)
-        grid0.addWidget(self.autosave_entry, 32, 1)
+        self.version_check_field = self.option_dict()["global_version_check"].get_field()
+        self.send_stats_field = self.option_dict()["global_send_stats"].get_field()
+        self.ois_version_check = OptionalInputSection(self.version_check_field, [self.send_stats_field])
 
+        self.save_compressed_field = self.option_dict()["global_save_compressed"].get_field()
+        self.compression_label = self.option_dict()["global_compression_level"].label_widget
+        self.compression_field = self.option_dict()["global_compression_level"].get_field()
+        self.proj_ois = OptionalInputSection(self.save_compressed_field, [self.compression_label, self.compression_field], True)
         # self.as_ois = OptionalInputSection(self.autosave_cb, [self.autosave_label, self.autosave_entry], True)
 
-        separator_line = QtWidgets.QFrame()
-        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
-        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        grid0.addWidget(separator_line, 33, 0, 1, 2)
-
-        self.pdf_param_label = QtWidgets.QLabel('<B>%s:</b>' % _("Text to PDF parameters"))
-        self.pdf_param_label.setToolTip(
-            _("Used when saving text in Code Editor or in FlatCAM Document objects.")
-        )
-        grid0.addWidget(self.pdf_param_label, 34, 0, 1, 2)
-
-        # Top Margin value
-        self.tmargin_entry = FCDoubleSpinner()
-        self.tmargin_entry.set_precision(self.decimals)
-        self.tmargin_entry.set_range(0.0000, 9999.9999)
-
-        self.tmargin_label = QtWidgets.QLabel('%s:' % _("Top Margin"))
-        self.tmargin_label.setToolTip(
-            _("Distance between text body and the top of the PDF file.")
-        )
-
-        grid0.addWidget(self.tmargin_label, 35, 0)
-        grid0.addWidget(self.tmargin_entry, 35, 1)
-
-        # Bottom Margin value
-        self.bmargin_entry = FCDoubleSpinner()
-        self.bmargin_entry.set_precision(self.decimals)
-        self.bmargin_entry.set_range(0.0000, 9999.9999)
-
-        self.bmargin_label = QtWidgets.QLabel('%s:' % _("Bottom Margin"))
-        self.bmargin_label.setToolTip(
-            _("Distance between text body and the bottom of the PDF file.")
-        )
-
-        grid0.addWidget(self.bmargin_label, 36, 0)
-        grid0.addWidget(self.bmargin_entry, 36, 1)
-
-        # Left Margin value
-        self.lmargin_entry = FCDoubleSpinner()
-        self.lmargin_entry.set_precision(self.decimals)
-        self.lmargin_entry.set_range(0.0000, 9999.9999)
-
-        self.lmargin_label = QtWidgets.QLabel('%s:' % _("Left Margin"))
-        self.lmargin_label.setToolTip(
-            _("Distance between text body and the left of the PDF file.")
-        )
-
-        grid0.addWidget(self.lmargin_label, 37, 0)
-        grid0.addWidget(self.lmargin_entry, 37, 1)
-
-        # Right Margin value
-        self.rmargin_entry = FCDoubleSpinner()
-        self.rmargin_entry.set_precision(self.decimals)
-        self.rmargin_entry.set_range(0.0000, 9999.9999)
-
-        self.rmargin_label = QtWidgets.QLabel('%s:' % _("Right Margin"))
-        self.rmargin_label.setToolTip(
-            _("Distance between text body and the right of the PDF file.")
-        )
-
-        grid0.addWidget(self.rmargin_label, 38, 0)
-        grid0.addWidget(self.rmargin_entry, 38, 1)
-
-        self.layout.addStretch()
-
-        if sys.platform != 'win32':
-            self.portability_cb.hide()
-
-        # splash screen button signal
-        self.splash_cb.stateChanged.connect(self.on_splash_changed)
-
-        # Monitor the checkbox from the Application Defaults Tab and show the TCL shell or not depending on it's value
-        self.shell_startup_cb.clicked.connect(self.on_toggle_shell_from_settings)
-
-        self.language_apply_btn.clicked.connect(lambda: fcTranslate.on_language_apply_click(app=self.app, restart=True))
+    def build_options(self) -> [OptionUI]:
+        return [
+            RadioSetOptionUI(
+                option="units",
+                label_text="Units",
+                label_tooltip="The default value for FlatCAM units.\n"
+                              "Whatever is selected here is set every time\n"
+                              "FlatCAM is started.",
+                label_bold=True,
+                label_red=True,
+                choices=[{'label': _('MM'), 'value': 'MM'},
+                         {'label': _('IN'), 'value': 'IN'}]
+            ),
+            SpinnerOptionUI(
+                option="decimals_metric",
+                label_text="Precision MM",
+                label_tooltip="The number of decimals used throughout the application\n"
+                              "when the set units are in METRIC system.\n"
+                              "Any change here require an application restart.",
+                min_value=2, max_value=16, step=1
+            ),
+            SpinnerOptionUI(
+                option="decimals_metric",
+                label_text="Precision INCH",
+                label_tooltip="The number of decimals used throughout the application\n"
+                              "when the set units are in INCH system.\n"
+                              "Any change here require an application restart.",
+                min_value=2, max_value=16, step=1
+            ),
+            RadioSetOptionUI(
+                option="global_graphic_engine",
+                label_text='Graphic Engine',
+                label_tooltip="Choose what graphic engine to use in FlatCAM.\n"
+                              "Legacy(2D) -> reduced functionality, slow performance but enhanced compatibility.\n"
+                              "OpenGL(3D) -> full functionality, high performance\n"
+                              "Some graphic cards are too old and do not work in OpenGL(3D) mode, like:\n"
+                              "Intel HD3000 or older. In this case the plot area will be black therefore\n"
+                              "use the Legacy(2D) mode.",
+                label_bold=True,
+                choices=[{'label': _('Legacy(2D)'), 'value': '2D'},
+                         {'label': _('OpenGL(3D)'), 'value': '3D'}],
+                orientation="vertical"
+            ),
+            SeparatorOptionUI(),
+
+            RadioSetOptionUI(
+                option="global_app_level",
+                label_text="APP. LEVEL",
+                label_tooltip="Choose the default level of usage for FlatCAM.\n"
+                              "BASIC level -> reduced functionality, best for beginner's.\n"
+                              "ADVANCED level -> full functionality.\n\n"
+                              "The choice here will influence the parameters in\n"
+                              "the Selected Tab for all kinds of FlatCAM objects.",
+                label_bold=True,
+                label_red=True,
+                choices=[{'label': _('Basic'),    'value': 'b'},
+                         {'label': _('Advanced'), 'value': 'a'}]
+            ),
+            CheckboxOptionUI(
+                option="global_portable",
+                label_text="Portable app",
+                label_tooltip="Choose if the application should run as portable.\n\n"
+                              "If Checked the application will run portable,\n"
+                              "which means that the preferences files will be saved\n"
+                              "in the application folder, in the lib\\config subfolder."
+            ),
+            SeparatorOptionUI(),
+
+            HeadingOptionUI(label_text="Languages", label_tooltip="Set the language used throughout FlatCAM."),
+            ComboboxOptionUI(
+                option="global_language",
+                label_text="Language",
+                label_tooltip="Set the language used throughout FlatCAM.",
+                choices=[] # FIXME: choices should be added here instead of in App
+            ),
+            FullWidthButtonOptionUI(
+                option="__apply_language_button",
+                label_text="Apply Language",
+                label_tooltip="Set the language used throughout FlatCAM.\n"
+                              "The app will restart after click."
+            ),
+            SeparatorOptionUI(),
+
+            HeadingOptionUI("Startup Settings", label_tooltip=None),
+            CheckboxOptionUI(
+                option="splash_screen",
+                label_text="Splash Screen",
+                label_tooltip="Enable display of the splash screen at application startup."
+            ),
+            CheckboxOptionUI(
+                option="global_systray_icon",
+                label_text="Sys Tray Icon",
+                label_tooltip="Enable display of FlatCAM icon in Sys Tray."
+            ),
+            CheckboxOptionUI(
+                option="global_shell_at_startup",
+                label_text="Show Shell",
+                label_tooltip="Check this box if you want the shell to\n"
+                              "start automatically at startup."
+            ),
+            CheckboxOptionUI(
+                option="global_project_at_startup",
+                label_text="Show Project",
+                label_tooltip="Check this box if you want the project/selected/tool tab area to\n"
+                              "to be shown automatically at startup."
+            ),
+            CheckboxOptionUI(
+                option="global_version_check",
+                label_text="Version Check",
+                label_tooltip="Check this box if you want to check\n"
+                              "for a new version automatically at startup."
+            ),
+            CheckboxOptionUI(
+                option="global_send_stats",
+                label_text="Send Statistics",
+                label_tooltip="Check this box if you agree to send anonymous\n"
+                              "stats automatically at startup, to help improve FlatCAM."
+            ),
+            SeparatorOptionUI(),
+
+            SpinnerOptionUI(
+                option="global_worker_number",
+                label_text="Workers number",
+                label_tooltip="The number of Qthreads made available to the App.\n"
+                              "A bigger number may finish the jobs more quickly but\n"
+                              "depending on your computer speed, may make the App\n"
+                              "unresponsive. Can have a value between 2 and 16.\n"
+                              "Default value is 2.\n"
+                              "After change, it will be applied at next App start.",
+                min_value=2, max_value=16, step=1
+            ),
+            DoubleSpinnerOptionUI(
+                option="global_tolerance",
+                label_text="Geo Tolerance",
+                label_tooltip="This value can counter the effect of the Circle Steps\n"
+                              "parameter. Default value is 0.005.\n"
+                              "A lower value will increase the detail both in image\n"
+                              "and in Gcode for the circles, with a higher cost in\n"
+                              "performance. Higher value will provide more\n"
+                              "performance at the expense of level of detail.",
+                min_value=0.0, max_value=100.0, step=0.001, decimals=6
+            ),
+            SeparatorOptionUI(),
+
+            HeadingOptionUI(label_text="Save Settings"),
+            CheckboxOptionUI(
+                option="global_save_compressed",
+                label_text="Save Compressed Project",
+                label_tooltip="Whether to save a compressed or uncompressed project.\n"
+                              "When checked it will save a compressed FlatCAM project."
+            ),
+            SpinnerOptionUI(
+                option="global_compression_level",
+                label_text="Compression",
+                label_tooltip="The level of compression used when saving\n"
+                              "a FlatCAM project. Higher value means better compression\n"
+                              "but require more RAM usage and more processing time.",
+                min_value=0, max_value=9, step=1
+            ),
+            CheckboxOptionUI(
+                option="global_autosave",
+                label_text="Enable Auto Save",
+                label_tooltip="Check to enable the autosave feature.\n"
+                              "When enabled, the application will try to save a project\n"
+                              "at the set interval."
+            ),
+            SpinnerOptionUI(
+                option="global_autosave_timeout",
+                label_text="Interval",
+                label_tooltip="Time interval for autosaving. In milliseconds.\n"
+                              "The application will try to save periodically but only\n"
+                              "if the project was saved manually at least once.\n"
+                              "While active, some operations may block this feature.",
+                min_value=500, max_value=9999999, step=60000
+            ),
+            SeparatorOptionUI(),
+
+            HeadingOptionUI(
+                label_text="Text to PDF parameters",
+                label_tooltip="Used when saving text in Code Editor or in FlatCAM Document objects."
+            ),
+            DoubleSpinnerOptionUI(
+                option="global_tpdf_tmargin",
+                label_text="Top Margin",
+                label_tooltip="Distance between text body and the top of the PDF file.",
+                min_value=0.0, max_value=9999.9999, step=1, decimals=2
+            ),
+            DoubleSpinnerOptionUI(
+                option="global_tpdf_bmargin",
+                label_text="Bottom Margin",
+                label_tooltip="Distance between text body and the bottom of the PDF file.",
+                min_value=0.0, max_value=9999.9999, step=1, decimals=2
+            ),
+            DoubleSpinnerOptionUI(
+                option="global_tpdf_lmargin",
+                label_text="Left Margin",
+                label_tooltip="Distance between text body and the left of the PDF file.",
+                min_value=0.0, max_value=9999.9999, step=1, decimals=2
+            ),
+            DoubleSpinnerOptionUI(
+                option="global_tpdf_rmargin",
+                label_text="Right Margin",
+                label_tooltip="Distance between text body and the right of the PDF file.",
+                min_value=0.0, max_value=9999.9999, step=1, decimals=2
+            )
+        ]
 
     def on_toggle_shell_from_settings(self, state):
         """
@@ -399,4 +270,4 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         qsettings.setValue('splash_screen', 1) if state else qsettings.setValue('splash_screen', 0)
 
         # This will write the setting to the platform specific storage.
-        del qsettings
+        del qsettings

+ 1 - 1
flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py

@@ -17,8 +17,8 @@ from flatcamGUI.preferences.OptionUI import OptionUI, CheckboxOptionUI, RadioSet
 class GeneralGUIPrefGroupUI(OptionsGroupUI2):
 
     def __init__(self, decimals=4, **kwargs):
-        super().__init__(**kwargs)
         self.decimals = decimals
+        super().__init__(**kwargs)
         self.setTitle(str(_("GUI Preferences")))
 
         self.layout_field = self.option_dict()["layout"].get_field()