From 612aa6a48fc1b1766e23c2fa32ec8a2ad07d07b8 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Mon, 1 Jun 2020 12:57:10 +0000 Subject: [PATCH] Revert "Preferences refactoring (pull request #309)" --- CHANGELOG.md | 10 - FlatCAMApp.py | 295 ++++-- FlatCAMCommon.py | 13 +- FlatCAMTranslation.py | 2 +- Utils/vispy_example.py | 195 ---- defaults.py | 1 - flatcamEditors/FlatCAMExcEditor.py | 20 +- flatcamEditors/FlatCAMGeoEditor.py | 41 +- flatcamEditors/FlatCAMGrbEditor.py | 19 +- flatcamGUI/ColumnarFlowLayout.py | 174 ---- flatcamGUI/FlatCAMGUI.py | 259 ++--- flatcamGUI/GUIElements.py | 98 -- flatcamGUI/PlotCanvas.py | 33 +- flatcamGUI/PlotCanvasLegacy.py | 73 -- flatcamGUI/VisPyCanvas.py | 1 - flatcamGUI/preferences/OptionUI.py | 322 ------- flatcamGUI/preferences/OptionsGroupUI.py | 62 +- .../preferences/PreferencesSectionUI.py | 42 - .../preferences/PreferencesUIManager.py | 568 +++++++++-- .../cncjob/CNCJobAdvOptPrefGroupUI.py | 211 +++-- .../cncjob/CNCJobGenPrefGroupUI.py | 497 +++++++--- .../cncjob/CNCJobOptPrefGroupUI.py | 95 +- .../preferences/cncjob/CNCJobPreferencesUI.py | 40 +- .../excellon/ExcellonAdvOptPrefGroupUI.py | 228 +++-- .../excellon/ExcellonEditorPrefGroupUI.py | 441 ++++++--- .../excellon/ExcellonExpPrefGroupUI.py | 224 +++-- .../excellon/ExcellonGenPrefGroupUI.py | 576 ++++++++---- .../excellon/ExcellonOptPrefGroupUI.py | 461 +++++---- .../excellon/ExcellonPreferencesUI.py | 83 +- .../general/GeneralAPPSetGroupUI.py | 483 ++++++++++ .../general/GeneralAppPrefGroupUI.py | 575 ++++++----- .../general/GeneralAppSettingsGroupUI.py | 301 ------ .../general/GeneralGUIPrefGroupUI.py | 889 ++++++++++++++---- .../general/GeneralPreferencesUI.py | 50 +- .../geometry/GeometryAdvOptPrefGroupUI.py | 368 +++++--- .../geometry/GeometryEditorPrefGroupUI.py | 84 +- .../geometry/GeometryGenPrefGroupUI.py | 147 ++- .../geometry/GeometryOptPrefGroupUI.py | 366 ++++--- .../geometry/GeometryPreferencesUI.py | 47 +- .../gerber/GerberAdvOptPrefGroupUI.py | 274 +++--- .../gerber/GerberEditorPrefGroupUI.py | 351 ++++--- .../gerber/GerberExpPrefGroupUI.py | 149 ++- .../gerber/GerberGenPrefGroupUI.py | 349 +++++-- .../gerber/GerberOptPrefGroupUI.py | 266 ++++-- .../preferences/gerber/GerberPreferencesUI.py | 51 +- .../preferences/tools/Tools2PreferencesUI.py | 86 +- .../preferences/tools/ToolsPreferencesUI.py | 90 +- .../utilities/UtilPreferencesUI.py | 40 +- flatcamTools/ToolCopperThieving.py | 16 +- flatcamTools/ToolDistance.py | 15 +- flatcamTools/ToolNCC.py | 16 +- flatcamTools/ToolPaint.py | 16 +- 52 files changed, 6162 insertions(+), 3951 deletions(-) delete mode 100644 Utils/vispy_example.py delete mode 100644 flatcamGUI/ColumnarFlowLayout.py delete mode 100644 flatcamGUI/preferences/OptionUI.py delete mode 100644 flatcamGUI/preferences/PreferencesSectionUI.py create mode 100644 flatcamGUI/preferences/general/GeneralAPPSetGroupUI.py delete mode 100644 flatcamGUI/preferences/general/GeneralAppSettingsGroupUI.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f6c6b3d..7770a326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,6 @@ CHANGELOG for FlatCAM beta ================================================= -11.05.2020 - -- removed the labels in status bar that display X,Y positions and replaced it with a HUD display on canvas (combo key SHIFT+H) will toggle the display of the HUD -- made the HUD work in Legacy2D mode -- fixed situation when the mouse cursor is outside of the canvas and no therefore returning None values - -10.05.2020 - -- fixed the problem with using comma as decimal separator in Grid Snap fields - 9.05.2020 - modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now). diff --git a/FlatCAMApp.py b/FlatCAMApp.py index a07f28c4..4641420d 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -285,8 +285,6 @@ class App(QtCore.QObject): :rtype: App """ - super().__init__() - App.log.info("FlatCAM Starting...") self.main_thread = QtWidgets.QApplication.instance().thread() @@ -454,8 +452,6 @@ class App(QtCore.QObject): self.current_units = self.defaults['units'] - - # ########################################################################################################### # #################################### SETUP OBJECT CLASSES ################################################# # ########################################################################################################### @@ -508,6 +504,8 @@ class App(QtCore.QObject): self.FC_light_blue = '#a5a5ffbf' self.FC_dark_blue = '#0000ffbf' + QtCore.QObject.__init__(self) + self.ui = FlatCAMGUI(self) theme_settings = QtCore.QSettings("Open Source", "FlatCAM") @@ -605,11 +603,13 @@ class App(QtCore.QObject): # ################################ It's done only once after install ##################################### # ########################################################################################################### if self.defaults["first_run"] is True: - # ONLY AT FIRST STARTUP INIT THE GUI LAYOUT TO 'minimal' + # ONLY AT FIRST STARTUP INIT THE GUI LAYOUT TO 'COMPACT' initial_lay = 'minimal' - layout_field = self.preferencesUiManager.get_form_field("layout") - layout_field.setCurrentIndex(layout_field.findText(initial_lay)) - self.ui.set_layout(initial_lay) + self.ui.general_defaults_form.general_gui_group.on_layout(lay=initial_lay) + + # Set the combobox in Preferences to the current layout + idx = self.ui.general_defaults_form.general_gui_group.layout_combo.findText(initial_lay) + self.ui.general_defaults_form.general_gui_group.layout_combo.setCurrentIndex(idx) # after the first run, this object should be False self.defaults["first_run"] = False @@ -632,9 +632,8 @@ 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()): - language_field.addItem(name) + self.ui.general_defaults_form.general_app_group.language_cb.addItem(name) # ########################################################################################################### # ####################################### APPLY APP LANGUAGE ################################################ @@ -647,7 +646,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.preferencesUiManager.get_form_field("global_language").setCurrentText(ret_val) + self.ui.general_defaults_form.general_app_group.language_cb.setCurrentText(ret_val) log.debug("App.__init__() --> Applied %s language." % str(ret_val).capitalize()) # ########################################################################################################### @@ -967,25 +966,23 @@ class App(QtCore.QObject): # #################################### GUI PREFERENCES SIGNALS ############################################## # ########################################################################################################### - self.preferencesUiManager.get_form_field("units").activated_custom.connect( + self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect( lambda: self.on_toggle_units(no_pref=False)) # ##################################### Workspace Setting Signals ########################################### - - - self.preferencesUiManager.get_form_field("global_workspaceT").currentIndexChanged.connect( + self.ui.general_defaults_form.general_app_set_group.wk_cb.currentIndexChanged.connect( self.on_workspace_modified) - self.preferencesUiManager.get_form_field("global_workspace_orientation").activated_custom.connect( + self.ui.general_defaults_form.general_app_set_group.wk_orientation_radio.activated_custom.connect( self.on_workspace_modified ) - self.preferencesUiManager.get_form_field("global_workspace").stateChanged.connect(self.on_workspace) + self.ui.general_defaults_form.general_app_set_group.workspace_cb.stateChanged.connect(self.on_workspace) # ########################################################################################################### # ######################################## GUI SETTINGS SIGNALS ############################################# # ########################################################################################################### - 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) + self.ui.general_defaults_form.general_app_group.ge_radio.activated_custom.connect(self.on_app_restart) + self.ui.general_defaults_form.general_app_set_group.cursor_radio.activated_custom.connect(self.on_cursor_type) # ######################################## Tools related signals ############################################ # Film Tool @@ -1005,7 +1002,7 @@ class App(QtCore.QObject): self.on_qrcode_back_color_button) # portability changed signal - self.preferencesUiManager.get_form_field("global_portable").stateChanged.connect(self.on_portable_checked) + self.ui.general_defaults_form.general_app_group.portability_cb.stateChanged.connect(self.on_portable_checked) # Object list self.collection.view.activated.connect(self.on_row_activated) @@ -1013,6 +1010,15 @@ class App(QtCore.QObject): self.object_status_changed.connect(self.on_collection_updated) + # Make sure that when the Excellon loading parameters are changed, the change is reflected in the + # Export Excellon parameters. + self.ui.excellon_defaults_form.excellon_gen_group.update_excellon_cb.stateChanged.connect( + self.on_update_exc_export + ) + + # call it once to make sure it is updated at startup + self.on_update_exc_export(state=self.defaults["excellon_update"]) + # when there are arguments at application startup this get launched self.args_at_startup[list].connect(self.on_startup_args) @@ -1419,8 +1425,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.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.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.thr2 = QtCore.QThread() self.worker_task.emit({'fcn': self.version_check, @@ -1547,7 +1553,7 @@ class App(QtCore.QObject): self.abort_flag = False # set the value used in the Windows Title - self.engine = self.preferencesUiManager.get_form_field("global_graphic_engine").get_value() + self.engine = self.ui.general_defaults_form.general_app_group.ge_radio.get_value() # this holds a widget that is installed in the Plot Area when View Source option is used self.source_editor_tab = None @@ -1592,7 +1598,11 @@ class App(QtCore.QObject): self.set_ui_title(name=_("New Project - Not saved")) - + # disable the Excellon path optimizations made with Google OR-Tools if the app is run on a 32bit platform + current_platform = platform.architecture()[0] + if current_platform != '64bit': + self.ui.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio.set_value('T') + self.ui.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio.setDisabled(True) # ########################################################################################################### # ########################################### EXCLUSION AREAS ############################################### @@ -3561,24 +3571,24 @@ class App(QtCore.QObject): stgs.setValue('maximized_gui', self.ui.isMaximized()) stgs.setValue( 'language', - self.preferencesUiManager.get_form_field("global_language").get_value() + self.ui.general_defaults_form.general_app_group.language_cb.get_value() ) stgs.setValue( 'notebook_font_size', - self.preferencesUiManager.get_form_field("notebook_font_size").get_value() + self.ui.general_defaults_form.general_app_set_group.notebook_font_size_spinner.get_value() ) stgs.setValue( 'axis_font_size', - self.preferencesUiManager.get_form_field("axis_font_size").get_value() + self.ui.general_defaults_form.general_app_set_group.axis_font_size_spinner.get_value() ) stgs.setValue( 'textbox_font_size', - self.preferencesUiManager.get_form_field("textbox_font_size").get_value() + self.ui.general_defaults_form.general_app_set_group.textbox_font_size_spinner.get_value() ) stgs.setValue('toolbar_lock', self.ui.lock_action.isChecked()) stgs.setValue( 'machinist', - 1 if self.preferencesUiManager.get_form_field("global_machinist_setting").get_value() else 0 + 1 if self.ui.general_defaults_form.general_app_set_group.machinist_cb.get_value() else 0 ) # This will write the setting to the platform specific storage. @@ -4201,18 +4211,18 @@ class App(QtCore.QObject): def on_toggle_units_click(self): try: - self.preferencesUiManager.get_form_field("units").activated_custom.disconnect() + self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.disconnect() except (TypeError, AttributeError): pass if self.defaults["units"] == 'MM': - self.preferencesUiManager.get_form_field("units").set_value("IN") + self.ui.general_defaults_form.general_app_group.units_radio.set_value("IN") else: - self.preferencesUiManager.get_form_field("units").set_value("MM") + self.ui.general_defaults_form.general_app_group.units_radio.set_value("MM") self.on_toggle_units(no_pref=True) - self.preferencesUiManager.get_form_field("units").activated_custom.connect( + self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect( lambda: self.on_toggle_units(no_pref=False)) def on_toggle_units(self, no_pref=False): @@ -4230,7 +4240,7 @@ class App(QtCore.QObject): if self.toggle_units_ignore: return - new_units = self.preferencesUiManager.get_form_field("units").get_value().upper() + new_units = self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() # If option is the same, then ignore if new_units == self.defaults["units"].upper(): @@ -4441,9 +4451,9 @@ class App(QtCore.QObject): # Undo toggling self.toggle_units_ignore = True if self.defaults['units'].upper() == 'MM': - self.preferencesUiManager.get_form_field("units").set_value('IN') + self.ui.general_defaults_form.general_app_group.units_radio.set_value('IN') else: - self.preferencesUiManager.get_form_field("units").set_value('MM') + self.ui.general_defaults_form.general_app_group.units_radio.set_value('MM') self.toggle_units_ignore = False # store the grid values so they are not changed in the next step @@ -4612,7 +4622,133 @@ class App(QtCore.QObject): self.app_cursor.enabled = True self.app_cursor.enabled = False + def on_update_exc_export(self, state): + """ + This is handling the update of Excellon Export parameters based on the ones in the Excellon General but only + if the update_excellon_cb checkbox is checked + :param state: state of the checkbox whose signals is tied to his slot + :return: + """ + if state: + # first try to disconnect + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_in_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_mm_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_mm_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio.activated_custom. \ + disconnect(self.on_excellon_zeros_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio.activated_custom. \ + disconnect(self.on_excellon_zeros_changed) + except TypeError: + pass + + # the connect them + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry.returnPressed.connect( + self.on_excellon_format_changed) + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_in_entry.returnPressed.connect( + self.on_excellon_format_changed) + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_mm_entry.returnPressed.connect( + self.on_excellon_format_changed) + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_mm_entry.returnPressed.connect( + self.on_excellon_format_changed) + self.ui.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio.activated_custom.connect( + self.on_excellon_zeros_changed) + self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio.activated_custom.connect( + self.on_excellon_units_changed) + else: + # disconnect the signals + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_in_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_mm_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_mm_entry.returnPressed. \ + disconnect(self.on_excellon_format_changed) + except TypeError: + pass + + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio.activated_custom. \ + disconnect(self.on_excellon_zeros_changed) + except TypeError: + pass + try: + self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio.activated_custom. \ + disconnect(self.on_excellon_zeros_changed) + except TypeError: + pass + + def on_excellon_format_changed(self): + """ + Slot activated when the user changes the Excellon format values in Preferences -> Excellon -> Excellon General + :return: None + """ + if self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio.get_value().upper() == 'METRIC': + self.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_mm_entry.get_value() + ) + self.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_mm_entry.get_value() + ) + else: + self.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry.get_value() + ) + self.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_in_entry.get_value() + ) + + def on_excellon_zeros_changed(self): + """ + Slot activated when the user changes the Excellon zeros values in Preferences -> Excellon -> Excellon General + :return: None + """ + self.ui.excellon_defaults_form.excellon_exp_group.zeros_radio.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio.get_value() + 'Z' + ) + + def on_excellon_units_changed(self): + """ + Slot activated when the user changes the Excellon unit values in Preferences -> Excellon -> Excellon General + :return: None + """ + self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio.set_value( + self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio.get_value() + ) + self.on_excellon_format_changed() def on_film_color_entry(self): self.defaults['tools_film_color'] = \ @@ -4739,7 +4875,7 @@ class App(QtCore.QObject): self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT']) def on_workspace(self): - if self.preferencesUiManager.get_form_field("global_workspace").get_value(): + if self.ui.general_defaults_form.general_app_set_group.workspace_cb.get_value(): self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT']) else: self.plotcanvas.delete_workspace() @@ -4747,13 +4883,13 @@ class App(QtCore.QObject): # self.save_defaults(silent=True) def on_workspace_toggle(self): - state = False if self.preferencesUiManager.get_form_field("global_workspace").get_value() else True + state = False if self.ui.general_defaults_form.general_app_set_group.workspace_cb.get_value() else True try: - self.preferencesUiManager.get_form_field("global_workspace").stateChanged.disconnect(self.on_workspace) + self.ui.general_defaults_form.general_app_set_group.workspace_cb.stateChanged.disconnect(self.on_workspace) except TypeError: pass - self.preferencesUiManager.get_form_field("global_workspace").set_value(state) - self.preferencesUiManager.get_form_field("global_workspace").stateChanged.connect(self.on_workspace) + self.ui.general_defaults_form.general_app_set_group.workspace_cb.set_value(state) + self.ui.general_defaults_form.general_app_set_group.workspace_cb.stateChanged.connect(self.on_workspace) self.on_workspace() def on_cursor_type(self, val): @@ -4765,12 +4901,12 @@ class App(QtCore.QObject): self.app_cursor.enabled = False if val == 'small': - self.preferencesUiManager.get_form_field("global_cursor_size").setDisabled(False) - #self.ui.general_defaults_form.general_app_set_group.cursor_size_lbl.setDisabled(False) + self.ui.general_defaults_form.general_app_set_group.cursor_size_entry.setDisabled(False) + self.ui.general_defaults_form.general_app_set_group.cursor_size_lbl.setDisabled(False) self.app_cursor = self.plotcanvas.new_cursor() else: - self.preferencesUiManager.get_form_field("global_cursor_size").setDisabled(False) - #self.ui.general_defaults_form.general_app_set_group.cursor_size_lbl.setDisabled(True) + self.ui.general_defaults_form.general_app_set_group.cursor_size_entry.setDisabled(True) + self.ui.general_defaults_form.general_app_set_group.cursor_size_lbl.setDisabled(True) self.app_cursor = self.plotcanvas.new_cursor(big=True) if self.ui.grid_snap_btn.isChecked(): @@ -5242,20 +5378,14 @@ class App(QtCore.QObject): edge_width=self.defaults["global_cursor_width"], size=self.defaults["global_cursor_size"]) + # Set the position label + self.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (location[0], location[1])) # Set the relative position label dx = location[0] - float(self.rel_point1[0]) dy = location[1] - float(self.rel_point1[1]) - # self.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (location[0], location[1])) - # # Set the position label - # - # self.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (dx, dy)) - - units = self.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - dx, units, dy, units, location[0], units, location[1], units) + self.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (dx, dy)) self.inform.emit('[success] %s' % _("Done.")) return location @@ -5397,19 +5527,14 @@ class App(QtCore.QObject): edge_width=self.defaults["global_cursor_width"], size=self.defaults["global_cursor_size"]) + # Set the position label + self.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (location[0], location[1])) # Set the relative position label self.dx = location[0] - float(self.rel_point1[0]) self.dy = location[1] - float(self.rel_point1[1]) - # Set the position label - # self.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (location[0], location[1])) - # self.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.dx, self.dy)) - - units = self.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.dx, units, self.dy, units, location[0], units, location[1], units) + self.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.dx, self.dy)) self.inform.emit('[success] %s' % _("Done.")) return location @@ -5718,8 +5843,8 @@ class App(QtCore.QObject): self.ui.plot_tab_area.addTab(self.ui.preferences_tab, _("Preferences")) # delete the absolute and relative position and messages in the infobar - # self.ui.position_label.setText("") - # self.ui.rel_position_label.setText("") + self.ui.position_label.setText("") + self.ui.rel_position_label.setText("") # Switch plot_area to preferences page self.ui.plot_tab_area.setCurrentWidget(self.ui.preferences_tab) @@ -6613,9 +6738,6 @@ class App(QtCore.QObject): try: # May fail in case mouse not within axes pos_canvas = self.plotcanvas.translate_coords(event_pos) - if pos_canvas[0] is None or pos_canvas[1] is None: - return - if self.grid_status(): pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1]) @@ -6627,19 +6749,13 @@ class App(QtCore.QObject): else: pos = (pos_canvas[0], pos_canvas[1]) + self.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (pos[0], pos[1])) + self.dx = pos[0] - float(self.rel_point1[0]) self.dy = pos[1] - float(self.rel_point1[1]) - - # self.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (pos[0], pos[1])) - # self.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.dx, self.dy)) - - units = self.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.dx, units, self.dy, units, pos[0], units, pos[1], units) - + self.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.dx, self.dy)) self.mouse = [pos[0], pos[1]] # if the mouse is moved and the LMB is clicked then the action is a selection @@ -6688,10 +6804,9 @@ class App(QtCore.QObject): # In this case poly_obj creation (see above) will fail pass - except Exception as e: - log.debug("App.on_mouse_move_over_plot() - rel_point1 is not None -> %s" % str(e)) - # self.ui.position_label.setText("") - # self.ui.rel_position_label.setText("") + except Exception: + self.ui.position_label.setText("") + self.ui.rel_position_label.setText("") self.mouse = None def on_mouse_click_release_over_plot(self, event): @@ -10019,8 +10134,7 @@ class App(QtCore.QObject): self.log.debug("version_check()") - - if self.defaults["global_send_stats"] is True: + if self.ui.general_defaults_form.general_app_group.send_stats_cb.get_value() is True: full_url = "%s?s=%s&v=%s&os=%s&%s" % ( App.version_url, str(self.defaults['global_serial']), @@ -10359,9 +10473,10 @@ class App(QtCore.QObject): alpha_level = 'BF' for sel_obj in sel_obj_list: if sel_obj.kind == 'excellon': - alpha_level = self.defaults["excellon_plot_fill"][7:] + alpha_level = str(hex( + self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_slider.value())[2:]) elif sel_obj.kind == 'gerber': - alpha_level = self.defaults["gerber_plot_fill"][7:] + alpha_level = str(hex(self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.value())[2:]) elif sel_obj.kind == 'geometry': alpha_level = 'FF' else: diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py index bcd61a98..b95091aa 100644 --- a/FlatCAMCommon.py +++ b/FlatCAMCommon.py @@ -466,20 +466,15 @@ class ExclusionAreas(QtCore.QObject): size=self.app.defaults["global_cursor_size"]) # update the positions on status bar + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (curr_pos[0], curr_pos[1])) if self.cursor_pos is None: self.cursor_pos = (0, 0) self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (curr_pos[0], curr_pos[1])) - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.app.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units) + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) if self.obj_type == 'excellon': color = "#FF7400" diff --git a/FlatCAMTranslation.py b/FlatCAMTranslation.py index ddd376c7..82a8ac33 100644 --- a/FlatCAMTranslation.py +++ b/FlatCAMTranslation.py @@ -79,7 +79,7 @@ def on_language_apply_click(app, restart=False): :return: """ - name = app.preferencesUiManager.get_form_field("global_language").currentText() + name = app.ui.general_defaults_form.general_app_group.language_cb.currentText() theme_settings = QSettings("Open Source", "FlatCAM") if theme_settings.contains("theme"): diff --git a/Utils/vispy_example.py b/Utils/vispy_example.py deleted file mode 100644 index a9eaee12..00000000 --- a/Utils/vispy_example.py +++ /dev/null @@ -1,195 +0,0 @@ -from PyQt5.QtGui import QPalette -from PyQt5 import QtCore, QtWidgets - -import vispy.scene as scene -from vispy.scene.visuals import Rectangle, Text -from vispy.color import Color - -import sys - - -class VisPyCanvas(scene.SceneCanvas): - - def __init__(self, config=None): - super().__init__(config=config, keys=None) - - self.unfreeze() - - # Colors used by the Scene - theme_color = Color('#FFFFFF') - tick_color = Color('#000000') - back_color = str(QPalette().color(QPalette.Window).name()) - - # Central Widget Colors - self.central_widget.bgcolor = back_color - self.central_widget.border_color = back_color - - self.grid_widget = self.central_widget.add_grid(margin=10) - self.grid_widget.spacing = 0 - - # TOP Padding - top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2) - top_padding.height_max = 0 - - # RIGHT Padding - right_padding = self.grid_widget.add_widget(row=0, col=2, row_span=2) - right_padding.width_max = 0 - - # X Axis - self.xaxis = scene.AxisWidget( - orientation='bottom', axis_color=tick_color, text_color=tick_color, - font_size=8, axis_width=1, - anchors=['center', 'bottom'] - ) - self.xaxis.height_max = 30 - self.grid_widget.add_widget(self.xaxis, row=2, col=1) - - # Y Axis - self.yaxis = scene.AxisWidget( - orientation='left', axis_color=tick_color, text_color=tick_color, - font_size=8, axis_width=1 - ) - self.yaxis.width_max = 55 - self.grid_widget.add_widget(self.yaxis, row=1, col=0) - - # View & Camera - self.view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color, - bgcolor=theme_color) - self.view.camera = scene.PanZoomCamera(aspect=1, rect=(-25, -25, 150, 150)) - - self.xaxis.link_view(self.view) - self.yaxis.link_view(self.view) - - self.grid = scene.GridLines(parent=self.view.scene, color='dimgray') - self.grid.set_gl_state(depth_test=False) - - self.rect = Rectangle(center=(65,30), color=Color('#0000FF10'), border_color=Color('#0000FF10'), - width=120, height=50, radius=[5, 5, 5, 5], parent=self.view) - self.rect.set_gl_state(depth_test=False) - - self.text = Text('', parent=self.view, color='black', pos=(5, 30), method='gpu', anchor_x='left') - self.text.font_size = 8 - self.text.text = 'Coordinates:\nX: %s\nY: %s' % ('0.0000', '0.0000') - - self.freeze() - - # self.measure_fps() - - -class PlotCanvas(QtCore.QObject): - - def __init__(self, container, my_app): - """ - The constructor configures the VisPy figure that - will contain all plots, creates the base axes and connects - events to the plotting area. - - :param container: The parent container in which to draw plots. - :rtype: PlotCanvas - """ - - super().__init__() - - # VisPyCanvas instance - self.vispy_canvas = VisPyCanvas() - - self.vispy_canvas.unfreeze() - - self.my_app = my_app - - # Parent container - self.container = container - - # - self.vispy_canvas.create_native() - self.vispy_canvas.native.setParent(self.my_app.ui) - - # - self.container.addWidget(self.vispy_canvas.native) - - # add two Infinite Lines to act as markers for the X,Y axis - self.v_line = scene.visuals.InfiniteLine( - pos=0, color=(0.0, 0.0, 1.0, 0.3), vertical=True, - parent=self.vispy_canvas.view.scene) - - self.h_line = scene.visuals.InfiniteLine( - pos=0, color=(0.00, 0.0, 1.0, 0.3), vertical=False, - parent=self.vispy_canvas.view.scene) - - self.vispy_canvas.freeze() - - def event_connect(self, event, callback): - getattr(self.vispy_canvas.events, event).connect(callback) - - def event_disconnect(self, event, callback): - getattr(self.vispy_canvas.events, event).disconnect(callback) - - def translate_coords(self, pos): - """ - Translate pixels to canvas units. - """ - tr = self.vispy_canvas.grid.get_transform('canvas', 'visual') - return tr.map(pos) - - -class MyGui(QtWidgets.QMainWindow): - - def __init__(self): - super().__init__() - - self.setWindowTitle("VisPy Test") - - # add Menubar - self.menu = self.menuBar() - self.menufile = self.menu.addMenu("File") - self.menuedit = self.menu.addMenu("Edit") - self.menufhelp = self.menu.addMenu("Help") - - # add a Toolbar - self.file_toolbar = QtWidgets.QToolBar("File Toolbar") - self.addToolBar(self.file_toolbar) - self.button = self.file_toolbar.addAction("Open") - - # add Central Widget - self.c_widget = QtWidgets.QWidget() - self.central_layout = QtWidgets.QVBoxLayout() - self.c_widget.setLayout(self.central_layout) - self.setCentralWidget(self.c_widget) - - # add InfoBar - # self.infobar = self.statusBar() - # self.position_label = QtWidgets.QLabel("Position: X: 0.0000\tY: 0.0000") - # self.infobar.addWidget(self.position_label) - - -class MyApp(QtCore.QObject): - - def __init__(self): - super().__init__() - - self.ui = MyGui() - self.plot = PlotCanvas(container=self.ui.central_layout, my_app=self) - - self.ui.show() - - self.plot.event_connect(event="mouse_move", callback=self.on_mouse_move) - - def on_mouse_move(self, event): - cursor_pos = event.pos - - pos_canvas = self.plot.translate_coords(cursor_pos) - - # we don't need all the info in the tuple returned by the translate_coords() - # only first 2 elements - pos_canvas = [pos_canvas[0], pos_canvas[1]] - # self.ui.position_label.setText("Position: X: %.4f\tY: %.4f" % (pos_canvas[0], pos_canvas[1])) - # pos_text = 'Coordinates: \nX: {:<7.4f}\nY: {:<7.4f}'.format(pos_canvas[0], pos_canvas[1]) - pos_text = 'Coordinates: \nX: {:<.4f}\nY: {:<.4f}'.format(pos_canvas[0], pos_canvas[1]) - self.plot.vispy_canvas.text.text = pos_text - - -if __name__ == '__main__': - app = QtWidgets.QApplication(sys.argv) - - m_app = MyApp() - sys.exit(app.exec_()) diff --git a/defaults.py b/defaults.py index 64f0fa70..b446a39a 100644 --- a/defaults.py +++ b/defaults.py @@ -43,7 +43,6 @@ class FlatCAMDefaults: # General "global_graphic_engine": '3D', - "global_hud": True, "global_app_level": 'b', "global_portable": False, "global_language": 'English', diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py index 26666e0a..49dc5eb5 100644 --- a/flatcamEditors/FlatCAMExcEditor.py +++ b/flatcamEditors/FlatCAMExcEditor.py @@ -2119,7 +2119,7 @@ class FlatCAMExcEditor(QtCore.QObject): if self.app.is_legacy is False: self.shapes = self.app.plotcanvas.new_shape_collection(layers=1) if self.app.plotcanvas.big_cursor is True: - self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1) + self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1, line_width=2) else: self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1) else: @@ -3801,22 +3801,18 @@ class FlatCAMExcEditor(QtCore.QObject): self.snap_x = x self.snap_y = y + # update the position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (x, y)) + if self.pos is None: self.pos = (0, 0) self.app.dx = x - self.pos[0] self.app.dy = y - self.pos[1] - # # update the position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (x, y)) - # # update the reference position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, x, units, y, units) + # update the reference position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) # ## Utility geometry (animated) self.update_utility_geometry(data=(x, y)) diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py index e8d969cb..ccf67ce4 100644 --- a/flatcamEditors/FlatCAMGeoEditor.py +++ b/flatcamEditors/FlatCAMGeoEditor.py @@ -3467,32 +3467,22 @@ class FlatCAMGeoEditor(QtCore.QObject): :return: """ try: - text_value = entry.text() - if ',' in text_value: - text_value = text_value.replace(',', '.') - self.options[opt] = float(text_value) + self.options[opt] = float(entry.text()) except Exception as e: - entry.set_value(self.app.defaults[opt]) log.debug("FlatCAMGeoEditor.__init__().entry2option() --> %s" % str(e)) return - def grid_changed(goption, gentry): + def gridx_changed(goption, gentry): """ - :param goption: String. Can be either 'global_gridx' or 'global_gridy' - :param gentry: A GUI element which text value is read and used + :param goption: String. Can be either 'global_gridx' or 'global_gridy' + :param gentry: A GUI element which text value is read and used :return: """ - if goption not in ['global_gridx', 'global_gridy']: - return - entry2option(opt=goption, entry=gentry) # if the grid link is checked copy the value in the GridX field to GridY try: - text_value = gentry.text() - if ',' in text_value: - text_value = text_value.replace(',', '.') - val = float(text_value) + val = float(gentry.get_value()) except ValueError: return @@ -3501,7 +3491,7 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator()) self.app.ui.grid_gap_x_entry.textChanged.connect( - lambda: grid_changed("global_gridx", self.app.ui.grid_gap_x_entry)) + lambda: gridx_changed("global_gridx", self.app.ui.grid_gap_x_entry)) self.app.ui.grid_gap_y_entry.setValidator(QtGui.QDoubleValidator()) self.app.ui.grid_gap_y_entry.textChanged.connect( @@ -4271,23 +4261,18 @@ class FlatCAMGeoEditor(QtCore.QObject): self.snap_y = y self.app.mouse = [x, y] + # update the position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (x, y)) + if self.pos is None: self.pos = (0, 0) self.app.dx = x - self.pos[0] self.app.dy = y - self.pos[1] - # # update the position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (x, y)) - # - # # update the reference position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, x, units, y, units) + # update the reference position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser): pass diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index d5659fbf..3362c5ba 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -4774,23 +4774,18 @@ class FlatCAMGrbEditor(QtCore.QObject): self.app.mouse = [x, y] + # update the position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (x, y)) + if self.pos is None: self.pos = (0, 0) self.app.dx = x - self.pos[0] self.app.dy = y - self.pos[1] - # # update the position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (x, y)) - # - # # update the reference position label in the infobar since the APP mouse event handlers are disconnected - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, x, units, y, units) + # update the reference position label in the infobar since the APP mouse event handlers are disconnected + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) self.update_utility_geometry(data=(x, y)) diff --git a/flatcamGUI/ColumnarFlowLayout.py b/flatcamGUI/ColumnarFlowLayout.py deleted file mode 100644 index 753c070b..00000000 --- a/flatcamGUI/ColumnarFlowLayout.py +++ /dev/null @@ -1,174 +0,0 @@ -import sys - -from PyQt5.QtCore import QPoint, QRect, QSize, Qt -from PyQt5.QtWidgets import QLayout, QSizePolicy -import math - -class ColumnarFlowLayout(QLayout): - def __init__(self, parent=None, margin=0, spacing=-1): - super().__init__(parent) - - if parent is not None: - self.setContentsMargins(margin, margin, margin, margin) - - self.setSpacing(spacing) - self.itemList = [] - - def __del__(self): - item = self.takeAt(0) - while item: - item = self.takeAt(0) - - def addItem(self, item): - self.itemList.append(item) - - def count(self): - return len(self.itemList) - - def itemAt(self, index): - if 0 <= index < len(self.itemList): - return self.itemList[index] - return None - - def takeAt(self, index): - if 0 <= index < len(self.itemList): - return self.itemList.pop(index) - return None - - def expandingDirections(self): - return Qt.Orientations(Qt.Orientation(0)) - - def hasHeightForWidth(self): - return True - - def heightForWidth(self, width): - height = self.doLayout(QRect(0, 0, width, 0), True) - return height - - def setGeometry(self, rect): - super().setGeometry(rect) - self.doLayout(rect, False) - - def sizeHint(self): - return self.minimumSize() - - def minimumSize(self): - size = QSize() - - for item in self.itemList: - size = size.expandedTo(item.minimumSize()) - - margin, _, _, _ = self.getContentsMargins() - - size += QSize(2 * margin, 2 * margin) - return size - - def doLayout(self, rect: QRect, testOnly: bool) -> int: - spacing = self.spacing() - x = rect.x() - y = rect.y() - - # Determine width of widest item - widest = 0 - for item in self.itemList: - widest = max(widest, item.sizeHint().width()) - - # Determine how many equal-width columns we can get, and how wide each one should be - column_count = math.floor(rect.width() / (widest + spacing)) - column_count = min(column_count, len(self.itemList)) - column_count = max(1, column_count) - column_width = math.floor((rect.width() - (column_count-1)*spacing - 1) / column_count) - - # Get the heights for all of our items - item_heights = {} - for item in self.itemList: - height = item.heightForWidth(column_width) if item.hasHeightForWidth() else item.sizeHint().height() - item_heights[item] = height - - # Prepare our column representation - column_contents = [] - column_heights = [] - for column_index in range(column_count): - column_contents.append([]) - column_heights.append(0) - - def add_to_column(column: int, item): - column_contents[column].append(item) - column_heights[column] += (item_heights[item] + spacing) - - def shove_one(from_column: int) -> bool: - if len(column_contents[from_column]) >= 1: - item = column_contents[from_column].pop(0) - column_heights[from_column] -= (item_heights[item] + spacing) - add_to_column(from_column-1, item) - return True - return False - - def shove_cascade_consider(from_column: int) -> bool: - changed = False - - if len(column_contents[from_column]) > 1: - item = column_contents[from_column][0] - item_height = item_heights[item] - if column_heights[from_column-1] + item_height < max(column_heights): - changed = shove_one(from_column) or changed - - if from_column+1 < column_count: - changed = shove_cascade_consider(from_column+1) or changed - - return changed - - def shove_cascade() -> bool: - if column_count < 2: - return False - changed = True - while changed: - changed = shove_cascade_consider(1) - return changed - - def pick_best_shoving_position() -> int: - best_pos = 1 - best_height = sys.maxsize - for column_index in range(1, column_count): - if len(column_contents[column_index]) == 0: - continue - item = column_contents[column_index][0] - height_after_shove = column_heights[column_index-1] + item_heights[item] - if height_after_shove < best_height: - best_height = height_after_shove - best_pos = column_index - return best_pos - - # Calculate the best layout - column_index = 0 - for item in self.itemList: - item_height = item_heights[item] - if column_heights[column_index] != 0 and (column_heights[column_index] + item_height) > max(column_heights): - column_index += 1 - if column_index >= column_count: - # Run out of room, need to shove more stuff in each column - if column_count >= 2: - changed = shove_cascade() - if not changed: - shoving_pos = pick_best_shoving_position() - shove_one(shoving_pos) - shove_cascade() - column_index = column_count-1 - - add_to_column(column_index, item) - - shove_cascade() - - # Set geometry according to the layout we have calculated - if not testOnly: - for column_index, items in enumerate(column_contents): - x = column_index * (column_width + spacing) - y = 0 - for item in items: - height = item_heights[item] - item.setGeometry(QRect(x, y, column_width, height)) - y += (height + spacing) - - # Return the overall height - return max(column_heights) - diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index deda0428..09d7383b 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -1207,6 +1207,89 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.pref_tab_area_tabBar.setExpanding(True) self.pref_tab_layout.addWidget(self.pref_tab_area) + self.general_tab = QtWidgets.QWidget() + self.general_tab.setObjectName("general_tab") + self.pref_tab_area.addTab(self.general_tab, _("General")) + self.general_tab_lay = QtWidgets.QVBoxLayout() + self.general_tab_lay.setContentsMargins(2, 2, 2, 2) + self.general_tab.setLayout(self.general_tab_lay) + + self.hlay1 = QtWidgets.QHBoxLayout() + self.general_tab_lay.addLayout(self.hlay1) + + self.hlay1.addStretch() + + self.general_scroll_area = QtWidgets.QScrollArea() + self.general_tab_lay.addWidget(self.general_scroll_area) + + self.gerber_tab = QtWidgets.QWidget() + self.gerber_tab.setObjectName("gerber_tab") + self.pref_tab_area.addTab(self.gerber_tab, _("GERBER")) + self.gerber_tab_lay = QtWidgets.QVBoxLayout() + self.gerber_tab_lay.setContentsMargins(2, 2, 2, 2) + self.gerber_tab.setLayout(self.gerber_tab_lay) + + self.gerber_scroll_area = QtWidgets.QScrollArea() + self.gerber_tab_lay.addWidget(self.gerber_scroll_area) + + self.excellon_tab = QtWidgets.QWidget() + self.excellon_tab.setObjectName("excellon_tab") + self.pref_tab_area.addTab(self.excellon_tab, _("EXCELLON")) + self.excellon_tab_lay = QtWidgets.QVBoxLayout() + self.excellon_tab_lay.setContentsMargins(2, 2, 2, 2) + self.excellon_tab.setLayout(self.excellon_tab_lay) + + self.excellon_scroll_area = QtWidgets.QScrollArea() + self.excellon_tab_lay.addWidget(self.excellon_scroll_area) + + self.geometry_tab = QtWidgets.QWidget() + self.geometry_tab.setObjectName("geometry_tab") + self.pref_tab_area.addTab(self.geometry_tab, _("GEOMETRY")) + self.geometry_tab_lay = QtWidgets.QVBoxLayout() + self.geometry_tab_lay.setContentsMargins(2, 2, 2, 2) + self.geometry_tab.setLayout(self.geometry_tab_lay) + + self.geometry_scroll_area = QtWidgets.QScrollArea() + self.geometry_tab_lay.addWidget(self.geometry_scroll_area) + + self.text_editor_tab = QtWidgets.QWidget() + self.text_editor_tab.setObjectName("text_editor_tab") + self.pref_tab_area.addTab(self.text_editor_tab, _("CNC-JOB")) + self.cncjob_tab_lay = QtWidgets.QVBoxLayout() + self.cncjob_tab_lay.setContentsMargins(2, 2, 2, 2) + self.text_editor_tab.setLayout(self.cncjob_tab_lay) + + self.cncjob_scroll_area = QtWidgets.QScrollArea() + self.cncjob_tab_lay.addWidget(self.cncjob_scroll_area) + + self.tools_tab = QtWidgets.QWidget() + self.pref_tab_area.addTab(self.tools_tab, _("TOOLS")) + self.tools_tab_lay = QtWidgets.QVBoxLayout() + self.tools_tab_lay.setContentsMargins(2, 2, 2, 2) + self.tools_tab.setLayout(self.tools_tab_lay) + + self.tools_scroll_area = QtWidgets.QScrollArea() + self.tools_tab_lay.addWidget(self.tools_scroll_area) + + self.tools2_tab = QtWidgets.QWidget() + self.pref_tab_area.addTab(self.tools2_tab, _("TOOLS 2")) + self.tools2_tab_lay = QtWidgets.QVBoxLayout() + self.tools2_tab_lay.setContentsMargins(2, 2, 2, 2) + self.tools2_tab.setLayout(self.tools2_tab_lay) + + self.tools2_scroll_area = QtWidgets.QScrollArea() + self.tools2_tab_lay.addWidget(self.tools2_scroll_area) + + self.fa_tab = QtWidgets.QWidget() + self.fa_tab.setObjectName("fa_tab") + self.pref_tab_area.addTab(self.fa_tab, _("UTILITIES")) + self.fa_tab_lay = QtWidgets.QVBoxLayout() + self.fa_tab_lay.setContentsMargins(2, 2, 2, 2) + self.fa_tab.setLayout(self.fa_tab_lay) + + self.fa_scroll_area = QtWidgets.QScrollArea() + self.fa_tab_lay.addWidget(self.fa_scroll_area) + self.pref_tab_bottom_layout = QtWidgets.QHBoxLayout() self.pref_tab_bottom_layout.setAlignment(QtCore.Qt.AlignVCenter) self.pref_tab_layout.addLayout(self.pref_tab_bottom_layout) @@ -2223,17 +2306,17 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.snap_infobar_label.setPixmap(QtGui.QPixmap(self.app.resource_location + '/snap_16.png')) self.infobar.addWidget(self.snap_infobar_label) - # self.rel_position_label = QtWidgets.QLabel( - # "Dx: 0.0000   Dy: 0.0000    ") - # self.rel_position_label.setMinimumWidth(110) - # self.rel_position_label.setToolTip(_("Relative measurement.\nReference is last click position")) - # self.infobar.addWidget(self.rel_position_label) - # - # self.position_label = QtWidgets.QLabel( - # "    X: 0.0000   Y: 0.0000") - # self.position_label.setMinimumWidth(110) - # self.position_label.setToolTip(_("Absolute measurement.\nReference is (X=0, Y= 0) position")) - # self.infobar.addWidget(self.position_label) + self.rel_position_label = QtWidgets.QLabel( + "Dx: 0.0000   Dy: 0.0000    ") + self.rel_position_label.setMinimumWidth(110) + self.rel_position_label.setToolTip(_("Relative measurement.\nReference is last click position")) + self.infobar.addWidget(self.rel_position_label) + + self.position_label = QtWidgets.QLabel( + "    X: 0.0000   Y: 0.0000") + self.position_label.setMinimumWidth(110) + self.position_label.setToolTip(_("Absolute measurement.\nReference is (X=0, Y= 0) position")) + self.infobar.addWidget(self.position_label) self.units_label = QtWidgets.QLabel("[in]") self.units_label.setMargin(2) @@ -2910,11 +2993,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow): if key == QtCore.Qt.Key_G: self.app.on_toggle_axis() - # Toggle HUD (Heads-Up Display) - if key == QtCore.Qt.Key_H: - state = False if self.app.plotcanvas.hud_enabled else True - self.app.plotcanvas.on_toggle_hud(state=state) - # Locate in Object if key == QtCore.Qt.Key_J: self.app.on_locate(obj=self.app.collection.get_active()) @@ -3984,7 +4062,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.option_dict()["units"].get_field().get_value().upper() + self.units = self.general_defaults_form.general_app_group.units_radio.get_value().upper() tool_add_popup = FCInputDialog(title=_("New Tool ..."), text='%s:' % _('Enter a Tool Diameter'), min=0.0000, max=99.9999, decimals=4) @@ -4202,153 +4280,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.final_save.emit() event.ignore() - def set_layout(self, layout: str): - """ - Set the toolbars layout (location) - - :param index: - :param lay: Type of layout to be set on the toolbard - :return: None - """ - - self.app.defaults.report_usage("on_layout()") - - lay_settings = QSettings("Open Source", "FlatCAM") - lay_settings.setValue('layout', layout) - # This will write the setting to the platform specific storage. - del lay_settings - - # first remove the toolbars: - try: - self.removeToolBar(self.app.ui.toolbarfile) - self.removeToolBar(self.app.ui.toolbargeo) - self.removeToolBar(self.app.ui.toolbarview) - self.removeToolBar(self.app.ui.toolbarshell) - self.removeToolBar(self.app.ui.toolbartools) - self.removeToolBar(self.app.ui.exc_edit_toolbar) - self.removeToolBar(self.app.ui.geo_edit_toolbar) - self.removeToolBar(self.app.ui.grb_edit_toolbar) - self.removeToolBar(self.app.ui.snap_toolbar) - self.removeToolBar(self.app.ui.toolbarshell) - except Exception: - pass - - if layout == 'compact': - # ## TOOLBAR INSTALLATION # ## - self.toolbarfile = QtWidgets.QToolBar('File Toolbar') - self.toolbarfile.setObjectName('File_TB') - self.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbarfile) - - self.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') - self.toolbargeo.setObjectName('Edit_TB') - self.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbargeo) - - self.toolbarshell = QtWidgets.QToolBar('Shell Toolbar') - self.toolbarshell.setObjectName('Shell_TB') - self.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbarshell) - - self.toolbartools = QtWidgets.QToolBar('Tools Toolbar') - self.toolbartools.setObjectName('Tools_TB') - self.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbartools) - - self.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') - # self.geo_edit_toolbar.setVisible(False) - self.geo_edit_toolbar.setObjectName('GeoEditor_TB') - self.addToolBar(Qt.RightToolBarArea, self.app.ui.geo_edit_toolbar) - - self.toolbarview = QtWidgets.QToolBar('View Toolbar') - self.toolbarview.setObjectName('View_TB') - self.addToolBar(Qt.RightToolBarArea, self.app.ui.toolbarview) - - self.addToolBarBreak(area=Qt.RightToolBarArea) - - self.grb_edit_toolbar = QtWidgets.QToolBar('Gerber Editor Toolbar') - # self.grb_edit_toolbar.setVisible(False) - self.grb_edit_toolbar.setObjectName('GrbEditor_TB') - self.addToolBar(Qt.RightToolBarArea, self.app.ui.grb_edit_toolbar) - - self.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') - self.exc_edit_toolbar.setObjectName('ExcEditor_TB') - self.addToolBar(Qt.RightToolBarArea, self.app.ui.exc_edit_toolbar) - - self.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') - self.snap_toolbar.setObjectName('Snap_TB') - self.snap_toolbar.setMaximumHeight(30) - self.splitter_left.addWidget(self.app.ui.snap_toolbar) - - self.corner_snap_btn.setVisible(True) - self.snap_magnet.setVisible(True) - else: - # ## TOOLBAR INSTALLATION # ## - self.toolbarfile = QtWidgets.QToolBar('File Toolbar') - self.toolbarfile.setObjectName('File_TB') - self.addToolBar(self.app.ui.toolbarfile) - - self.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') - self.toolbargeo.setObjectName('Edit_TB') - self.addToolBar(self.app.ui.toolbargeo) - - self.toolbarview = QtWidgets.QToolBar('View Toolbar') - self.toolbarview.setObjectName('View_TB') - self.addToolBar(self.app.ui.toolbarview) - - self.toolbarshell = QtWidgets.QToolBar('Shell Toolbar') - self.toolbarshell.setObjectName('Shell_TB') - self.addToolBar(self.app.ui.toolbarshell) - - self.toolbartools = QtWidgets.QToolBar('Tools Toolbar') - self.toolbartools.setObjectName('Tools_TB') - self.addToolBar(self.app.ui.toolbartools) - - self.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') - # self.exc_edit_toolbar.setVisible(False) - self.exc_edit_toolbar.setObjectName('ExcEditor_TB') - self.addToolBar(self.app.ui.exc_edit_toolbar) - - self.addToolBarBreak() - - self.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') - # self.geo_edit_toolbar.setVisible(False) - self.geo_edit_toolbar.setObjectName('GeoEditor_TB') - self.addToolBar(self.app.ui.geo_edit_toolbar) - - self.grb_edit_toolbar = QtWidgets.QToolBar('Gerber Editor Toolbar') - # self.grb_edit_toolbar.setVisible(False) - self.grb_edit_toolbar.setObjectName('GrbEditor_TB') - self.addToolBar(self.app.ui.grb_edit_toolbar) - - self.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') - self.snap_toolbar.setObjectName('Snap_TB') - # self.snap_toolbar.setMaximumHeight(30) - self.addToolBar(self.app.ui.snap_toolbar) - - self.corner_snap_btn.setVisible(False) - self.snap_magnet.setVisible(False) - - if layout == 'minimal': - self.toolbarview.setVisible(False) - self.toolbarshell.setVisible(False) - self.snap_toolbar.setVisible(False) - self.geo_edit_toolbar.setVisible(False) - self.grb_edit_toolbar.setVisible(False) - self.exc_edit_toolbar.setVisible(False) - self.lock_toolbar(lock=True) - - # add all the actions to the toolbars - self.populate_toolbars() - - # reconnect all the signals to the toolbar actions - self.app.connect_toolbar_signals() - - self.grid_snap_btn.setChecked(True) - self.on_grid_snap_triggered(state=True) - - self.grid_gap_x_entry.setText(str(self.app.defaults["global_gridx"])) - self.grid_gap_y_entry.setText(str(self.app.defaults["global_gridy"])) - self.snap_max_dist_entry.setText(str(self.app.defaults["global_snap_max"])) - self.grid_gap_link_cb.setChecked(True) - - class FlatCAMActivityView(QtWidgets.QWidget): """ diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py index d048a022..7b9b38f4 100644 --- a/flatcamGUI/GUIElements.py +++ b/flatcamGUI/GUIElements.py @@ -656,104 +656,6 @@ class EvalEntry2(QtWidgets.QLineEdit): return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height()) -class FCColorEntry(QtWidgets.QFrame): - - def __init__(self, **kwargs): - super().__init__(**kwargs) - - self.entry = FCEntry() - - self.button = QtWidgets.QPushButton() - self.button.setFixedSize(15, 15) - self.button.setStyleSheet("border-color: dimgray;") - - self.layout = QtWidgets.QHBoxLayout() - self.layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) - self.layout.setContentsMargins(0, 0, 0, 0) - self.layout.addWidget(self.entry) - self.layout.addWidget(self.button) - self.setLayout(self.layout) - - self.entry.editingFinished.connect(self._sync_button_color) - self.button.clicked.connect(self._on_button_clicked) - - - def get_value(self) -> str: - return self.entry.get_value() - - def set_value(self, value: str): - self.entry.set_value(value) - self._sync_button_color() - - def _sync_button_color(self): - value = self.get_value() - self.button.setStyleSheet("background-color:%s;" % self._extract_color(value)) - - def _on_button_clicked(self): - value = self.entry.get_value() - current_color = QtGui.QColor(self._extract_color(value)) - - color_dialog = QtWidgets.QColorDialog() - selected_color = color_dialog.getColor(initial=current_color, options=QtWidgets.QColorDialog.ShowAlphaChannel) - - if selected_color.isValid() is False: - return - - new_value = str(selected_color.name()) + self._extract_alpha(value) - self.set_value(new_value) - - def _extract_color(self, value: str) -> str: - return value[:7] - - def _extract_alpha(self, value: str) -> str: - return value[7:9] - - -class FCSliderWithSpinner(QtWidgets.QFrame): - - def __init__(self, min=0, max=100, step=1, **kwargs): - super().__init__(**kwargs) - - self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) - self.slider.setMinimum(min) - self.slider.setMaximum(max) - self.slider.setSingleStep(step) - - self.spinner = FCSpinner() - self.spinner.set_range(min, max) - self.spinner.set_step(step) - self.spinner.setMinimumWidth(70) - - self.layout = QtWidgets.QHBoxLayout() - self.layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) - self.layout.setContentsMargins(0, 0, 0, 0) - self.layout.addWidget(self.slider) - self.layout.addWidget(self.spinner) - self.setLayout(self.layout) - - self.slider.valueChanged.connect(self._on_slider) - self.spinner.valueChanged.connect(self._on_spinner) - - self.valueChanged = self.spinner.valueChanged - - def get_value(self) -> int: - return self.spinner.get_value() - - def set_value(self, value: int): - self.spinner.set_value(value) - - def _on_spinner(self): - spinner_value = self.spinner.value() - self.slider.setValue(spinner_value) - - def _on_slider(self): - slider_value = self.slider.value() - self.spinner.set_value(slider_value) - - - - - class FCSpinner(QtWidgets.QSpinBox): returnPressed = QtCore.pyqtSignal() diff --git a/flatcamGUI/PlotCanvas.py b/flatcamGUI/PlotCanvas.py index a1be6099..44af74d0 100644 --- a/flatcamGUI/PlotCanvas.py +++ b/flatcamGUI/PlotCanvas.py @@ -10,7 +10,7 @@ from PyQt5 import QtCore import logging from flatcamGUI.VisPyCanvas import VisPyCanvas, Color from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor -from vispy.scene.visuals import InfiniteLine, Line, Rectangle, Text +from vispy.scene.visuals import InfiniteLine, Line import numpy as np from vispy.geometry import Rect @@ -54,12 +54,8 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas): if theme == 'white': self.line_color = (0.3, 0.0, 0.0, 1.0) - self.rect_hud_color = Color('#0000FF10') - self.text_hud_color = 'black' else: self.line_color = (0.4, 0.4, 0.4, 1.0) - self.rect_hud_color = Color('#0000FF10') - self.text_hud_color = 'white' # workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node, # which might decrease performance @@ -150,28 +146,13 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas): self.cursor_h_line = InfiniteLine(pos=None, color=c_color, vertical=False, parent=self.line_parent) - self.rect_hud = Rectangle(center=(90,45), color=self.rect_hud_color, border_color=self.rect_hud_color, - width=170, height=80, radius=[5, 5, 5, 5], parent=None) - self.rect_hud.set_gl_state(depth_test=False) - - # HUD Display - self.hud_enabled = False - - self.text_hud = Text('', color=self.text_hud_color, pos=(8, 45), method='gpu', anchor_x='left', parent=None) - self.text_hud.font_size = 8 - units = self.fcapp.defaults["units"].lower() - self.text_hud.text = 'Dx:\t%s [%s]\nDy:\t%s [%s]\nX: \t%s [%s]\nY: \t%s [%s]' % \ - ('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units) - - if self.fcapp.defaults['global_hud'] is True: - self.on_toggle_hud(state=True) - self.shape_collections = [] self.shape_collection = self.new_shape_collection() self.fcapp.pool_recreated.connect(self.on_pool_recreated) self.text_collection = self.new_text_collection() + # TODO: Should be setting to show/hide CNC job annotations (global or per object) self.text_collection.enabled = True self.c = None @@ -182,16 +163,6 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas): self.graph_event_connect('mouse_wheel', self.on_mouse_scroll) - def on_toggle_hud(self, state): - if state: - self.hud_enabled = True - self.rect_hud.parent = self.view - self.text_hud.parent = self.view - else: - self.hud_enabled = False - self.rect_hud.parent = None - self.text_hud.parent = None - def draw_workspace(self, workspace_size): """ Draw a rectangular shape on canvas to specify our valid workspace. diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py index 7856bb8f..a9a6216f 100644 --- a/flatcamGUI/PlotCanvasLegacy.py +++ b/flatcamGUI/PlotCanvasLegacy.py @@ -29,7 +29,6 @@ mpl_use("Qt5Agg") from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.lines import Line2D -from matplotlib.offsetbox import AnchoredText # from matplotlib.widgets import Cursor fcTranslate.apply_language('strings') @@ -148,13 +147,9 @@ class PlotCanvasLegacy(QtCore.QObject): if self.app.defaults['global_theme'] == 'white': theme_color = '#FFFFFF' tick_color = '#000000' - self.rect_hud_color = '#0000FF10' - self.text_hud_color = '#000000' else: theme_color = '#000000' tick_color = '#FFFFFF' - self.rect_hud_color = '#0000FF10' - self.text_hud_color = '#000000' # workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node, # which might decrease performance @@ -303,79 +298,11 @@ class PlotCanvasLegacy(QtCore.QObject): # signal if there is a doubleclick self.is_dblclk = False - self.hud_enabled = False - self.text_hud = self.Thud(plotcanvas=self) - - # bbox_props = dict(boxstyle="round,pad=0.3", fc="blue", ec="b", lw=0) - # self.text_hud = self.figure.text(0, 0, "Direction", ha="left", va="center", rotation=0, - # size=15, - # bbox=bbox_props) - # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area # all CNC have a limited workspace if self.app.defaults['global_workspace'] is True: self.draw_workspace(workspace_size=self.app.defaults["global_workspaceT"]) - if self.app.defaults['global_hud'] is True: - self.on_toggle_hud(state=True) - - def on_toggle_hud(self, state): - if state: - self.hud_enabled = True - self.text_hud.add_artist() - else: - self.hud_enabled = False - self.text_hud.remove_artist() - self.canvas.draw() - - class Thud(QtCore.QObject): - text_changed = QtCore.pyqtSignal(str) - - def __init__(self, plotcanvas): - super().__init__() - - self.p = plotcanvas - units = self.p.app.defaults['units'] - self._text = 'Dx: %s [%s]\nDy: %s [%s]\nX: %s [%s]\nY: %s [%s]' % \ - ('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units) - - self.hud_holder = AnchoredText(self._text, - prop=dict(size=20), frameon=True, - loc='upper left', - ) - self.hud_holder.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") - - self.hud_holder.patch.set_facecolor('blue') - self.hud_holder.patch.set_alpha(0.3) - self.hud_holder.patch.set_edgecolor((0, 0, 0, 0)) - - self.text_changed.connect(self.on_text_changed) - - @property - def text(self): - return self._text - - @text.setter - def text(self, val): - self.text_changed.emit(val) - self._text = val - - def on_text_changed(self, txt): - try: - txt = txt.replace('\t', ' ') - self.hud_holder.txt.set_text(txt) - self.p.canvas.draw() - except Exception: - pass - - def add_artist(self): - if self.hud_holder not in self.p.axes.artists: - self.p.axes.add_artist(self.hud_holder) - - def remove_artist(self): - if self.hud_holder in self.p.axes.artists: - self.p.axes.artists.remove(self.hud_holder) - def draw_workspace(self, workspace_size): """ Draw a rectangular shape on canvas to specify our valid workspace. diff --git a/flatcamGUI/VisPyCanvas.py b/flatcamGUI/VisPyCanvas.py index aa55675f..7d7efe13 100644 --- a/flatcamGUI/VisPyCanvas.py +++ b/flatcamGUI/VisPyCanvas.py @@ -13,7 +13,6 @@ import numpy as np import vispy.scene as scene from vispy.scene.cameras.base_camera import BaseCamera -# from vispy.scene.widgets import Widget as VisPyWidget from vispy.color import Color import time diff --git a/flatcamGUI/preferences/OptionUI.py b/flatcamGUI/preferences/OptionUI.py deleted file mode 100644 index 824c417a..00000000 --- a/flatcamGUI/preferences/OptionUI.py +++ /dev/null @@ -1,322 +0,0 @@ -from typing import Union, Sequence, List - -from PyQt5 import QtWidgets, QtGui -from PyQt5.QtCore import QSettings - -from flatcamGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner, FCColorEntry, \ - FCSliderWithSpinner, FCDoubleSpinner, FloatEntry, FCTextArea - -import gettext -import FlatCAMTranslation as fcTranslate -import builtins - -fcTranslate.apply_language('strings') -if '_' not in builtins.__dict__: - _ = gettext.gettext - - -class OptionUI: - - def __init__(self, option: str): - self.option = option - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - """ - Adds the necessary widget to the grid, starting at the supplied row. - Returns the number of rows used (normally 1) - """ - raise NotImplementedError() - - def get_field(self): - raise NotImplementedError() - - -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: Union[str, None] = None, label_bold: bool = False, label_color: Union[str, None] = None): - super().__init__(option=option) - self.label_text = label_text - self.label_tooltip = label_tooltip - self.label_bold = label_bold - self.label_color = label_color - self.label_widget = self.build_label_widget() - self.entry_widget = self.build_entry_widget() - - def build_label_widget(self) -> QtWidgets.QLabel: - fmt = "%s:" - if self.label_bold: - fmt = "%s" % fmt - if self.label_color: - fmt = "%s" % (self.label_color, 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 - - def build_entry_widget(self) -> QtWidgets.QWidget: - raise NotImplementedError() - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.label_widget, row, 0) - grid.addWidget(self.entry_widget, row, 1) - return 1 - - def get_field(self): - return self.entry_widget - - -class LineEntryOptionUI(BasicOptionUI): - def build_entry_widget(self) -> QtWidgets.QWidget: - return FCEntry() - - -# Not sure why this is needed over DoubleSpinnerOptionUI -class FloatEntryOptionUI(BasicOptionUI): - def build_entry_widget(self) -> QtWidgets.QWidget: - return FloatEntry() - - -class RadioSetOptionUI(BasicOptionUI): - - 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, **kwargs) - - def build_entry_widget(self) -> QtWidgets.QWidget: - return RadioSet(choices=self.choices, orientation=self.orientation) - - -class TextAreaOptionUI(OptionUI): - - def __init__(self, option: str, label_text: str, label_tooltip: str): - super().__init__(option=option) - self.label_text = label_text - self.label_tooltip = label_tooltip - self.label_widget = self.build_label_widget() - self.textarea_widget = self.build_textarea_widget() - - def build_label_widget(self): - label = QtWidgets.QLabel("%s:" % _(self.label_text)) - label.setToolTip(_(self.label_tooltip)) - return label - - def build_textarea_widget(self): - textarea = FCTextArea() - textarea.setPlaceholderText(_(self.label_tooltip)) - - qsettings = QSettings("Open Source", "FlatCAM") - if qsettings.contains("textbox_font_size"): - tb_fsize = qsettings.value('textbox_font_size', type=int) - else: - tb_fsize = 10 - font = QtGui.QFont() - font.setPointSize(tb_fsize) - textarea.setFont(font) - - return textarea - - def get_field(self): - return self.textarea_widget - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.label_widget, row, 0, 1, 3) - grid.addWidget(self.textarea_widget, row+1, 0, 1, 3) - return 2 - - -class CheckboxOptionUI(OptionUI): - - def __init__(self, option: str, label_text: str, label_tooltip: str): - super().__init__(option=option) - self.label_text = label_text - self.label_tooltip = label_tooltip - self.checkbox_widget = self.build_checkbox_widget() - - def build_checkbox_widget(self): - checkbox = FCCheckBox('%s' % _(self.label_text)) - checkbox.setToolTip(_(self.label_tooltip)) - return checkbox - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.checkbox_widget, row, 0, 1, 3) - return 1 - - def get_field(self): - return self.checkbox_widget - - -class ComboboxOptionUI(BasicOptionUI): - - def __init__(self, option: str, label_text: str, choices: Sequence, **kwargs): - self.choices = choices - super().__init__(option=option, label_text=label_text, **kwargs) - - def build_entry_widget(self): - combo = FCComboBox() - for choice in self.choices: - # don't translate the QCombo items as they are used in QSettings and identified by name - combo.addItem(choice) - return combo - - -class ColorOptionUI(BasicOptionUI): - def build_entry_widget(self) -> QtWidgets.QWidget: - entry = FCColorEntry() - return entry - - -class SliderWithSpinnerOptionUI(BasicOptionUI): - 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, **kwargs) - - def build_entry_widget(self) -> QtWidgets.QWidget: - entry = FCSliderWithSpinner(min=self.min_value, max=self.max_value, step=self.step) - return entry - - -class ColorAlphaSliderOptionUI(SliderWithSpinnerOptionUI): - def __init__(self, applies_to: List[str], group, label_text: str, **kwargs): - self.applies_to = applies_to - self.group = group - super().__init__(option="__color_alpha_slider", label_text=label_text, min_value=0, max_value=255, step=1, **kwargs) - self.get_field().valueChanged.connect(self._on_alpha_change) - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - for index, field in enumerate(self._get_target_fields()): - field.entry.textChanged.connect(lambda value, i=index: self._on_target_change(target_index=i)) - return super().add_to_grid(grid, row) - - def _get_target_fields(self): - return list(map(lambda n: self.group.option_dict()[n].get_field(), self.applies_to)) - - def _on_target_change(self, target_index: int): - field = self._get_target_fields()[target_index] - color = field.get_value() - alpha_part = color[7:] - if len(alpha_part) != 2: - return - alpha = int(alpha_part, 16) - if alpha < 0 or alpha > 255 or self.get_field().get_value() == alpha: - return - self.get_field().set_value(alpha) - - def _on_alpha_change(self): - alpha = self.get_field().get_value() - for field in self._get_target_fields(): - old_value = field.get_value() - new_value = self._modify_color_alpha(old_value, alpha=alpha) - field.set_value(new_value) - - def _modify_color_alpha(self, color: str, alpha: int): - color_without_alpha = color[:7] - if alpha > 255: - return color_without_alpha + "FF" - elif alpha < 0: - return color_without_alpha + "00" - else: - hexalpha = hex(alpha)[2:] - if len(hexalpha) == 1: - hexalpha = "0" + hexalpha - return color_without_alpha + hexalpha - - -class SpinnerOptionUI(BasicOptionUI): - 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, **kwargs) - - def build_entry_widget(self) -> QtWidgets.QWidget: - entry = FCSpinner() - entry.set_range(self.min_value, self.max_value) - entry.set_step(self.step) - entry.setWrapping(True) - return entry - - -class DoubleSpinnerOptionUI(BasicOptionUI): - def __init__(self, option: str, label_text: str, step: float, decimals: int, min_value=None, max_value=None, suffix=None, **kwargs): - self.min_value = min_value - self.max_value = max_value - self.step = step - self.suffix = suffix - self.decimals = decimals - super().__init__(option=option, label_text=label_text, **kwargs) - - def build_entry_widget(self) -> QtWidgets.QWidget: - entry = FCDoubleSpinner(suffix=self.suffix) - entry.set_precision(self.decimals) - entry.setSingleStep(self.step) - if self.min_value is None: - self.min_value = entry.minimum() - else: - entry.setMinimum(self.min_value) - if self.max_value is None: - self.max_value = entry.maximum() - else: - entry.setMaximum(self.max_value) - return entry - - -class HeadingOptionUI(OptionUI): - 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 - - def build_heading_widget(self): - heading = QtWidgets.QLabel('%s' % _(self.label_text)) - heading.setToolTip(_(self.label_tooltip)) - return heading - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.build_heading_widget(), row, 0, 1, 2) - return 1 - - def get_field(self): - return None - - -class SeparatorOptionUI(OptionUI): - - def __init__(self): - super().__init__(option="__separator") - - def build_separator_widget(self): - separator = QtWidgets.QFrame() - separator.setFrameShape(QtWidgets.QFrame.HLine) - separator.setFrameShadow(QtWidgets.QFrame.Sunken) - return separator - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.build_separator_widget(), row, 0, 1, 2) - return 1 - - def get_field(self): - return None - - -class FullWidthButtonOptionUI(OptionUI): - def __init__(self, option: str, label_text: str, label_tooltip: Union[str, None]): - super().__init__(option=option) - self.label_text = label_text - self.label_tooltip = label_tooltip - self.button_widget = self.build_button_widget() - - def build_button_widget(self): - button = FCButton(_(self.label_text)) - if self.label_tooltip is not None: - button.setToolTip(_(self.label_tooltip)) - return button - - def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int: - grid.addWidget(self.button_widget, row, 0, 1, 3) - return 1 - - def get_field(self): - return self.button_widget \ No newline at end of file diff --git a/flatcamGUI/preferences/OptionsGroupUI.py b/flatcamGUI/preferences/OptionsGroupUI.py index 2f519ea9..98780004 100644 --- a/flatcamGUI/preferences/OptionsGroupUI.py +++ b/flatcamGUI/preferences/OptionsGroupUI.py @@ -1,32 +1,12 @@ -from typing import Dict - from PyQt5 import QtWidgets -from PyQt5.QtCore import QSettings - -import gettext -import FlatCAMTranslation as fcTranslate -import builtins - -from flatcamGUI.preferences.OptionUI import OptionUI - -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 OptionsGroupUI(QtWidgets.QGroupBox): app = None - def __init__(self, fixme_get_rid_of_this=None, **kwargs): - super().__init__(**kwargs) - + def __init__(self, title, parent=None): + # QtGui.QGroupBox.__init__(self, title, parent=parent) + super(OptionsGroupUI, self).__init__() self.setStyleSheet(""" QGroupBox { @@ -36,38 +16,4 @@ class OptionsGroupUI(QtWidgets.QGroupBox): """) self.layout = QtWidgets.QVBoxLayout() - self.setLayout(self.layout) - - def option_dict(self) -> Dict[str, OptionUI]: - # FIXME! - return {} - - -class OptionsGroupUI2(OptionsGroupUI): - - def __init__(self, **kwargs): - super().__init__(**kwargs) - - self.grid = QtWidgets.QGridLayout() - self.layout.addLayout(self.grid) - self.grid.setColumnStretch(0, 0) - self.grid.setColumnStretch(1, 1) - - self.options = self.build_options() - - row = 0 - for option in self.options: - row += option.add_to_grid(grid=self.grid, row=row) - - self.layout.addStretch() - - def build_options(self) -> [OptionUI]: - return [] - - def option_dict(self) -> Dict[str, OptionUI]: - result = {} - for optionui in self.options: - result[optionui.option] = optionui - return result - - + self.setLayout(self.layout) \ No newline at end of file diff --git a/flatcamGUI/preferences/PreferencesSectionUI.py b/flatcamGUI/preferences/PreferencesSectionUI.py deleted file mode 100644 index 92168377..00000000 --- a/flatcamGUI/preferences/PreferencesSectionUI.py +++ /dev/null @@ -1,42 +0,0 @@ -from typing import Dict -from PyQt5 import QtWidgets, QtCore - -from flatcamGUI.ColumnarFlowLayout import ColumnarFlowLayout -from flatcamGUI.preferences.OptionUI import OptionUI -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI - - -class PreferencesSectionUI(QtWidgets.QWidget): - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.layout = ColumnarFlowLayout() #QtWidgets.QHBoxLayout() - self.setLayout(self.layout) - - self.groups = self.build_groups() - for group in self.groups: - group.setMinimumWidth(250) - self.layout.addWidget(group) - - - def build_groups(self) -> [OptionsGroupUI]: - return [] - - def option_dict(self) -> Dict[str, OptionUI]: - result = {} - for group in self.groups: - groupoptions = group.option_dict() - result.update(groupoptions) - return result - - def build_tab(self): - scroll_area = QtWidgets.QScrollArea() - scroll_area.setWidget(self) - scroll_area.setWidgetResizable(True) - return scroll_area - - def get_tab_id(self) -> str: - raise NotImplementedError - - def get_tab_label(self) -> str: - raise NotImplementedError diff --git a/flatcamGUI/preferences/PreferencesUIManager.py b/flatcamGUI/preferences/PreferencesUIManager.py index de4468b1..c49841ba 100644 --- a/flatcamGUI/preferences/PreferencesUIManager.py +++ b/flatcamGUI/preferences/PreferencesUIManager.py @@ -1,6 +1,4 @@ import os -from typing import Any, Dict - from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5.QtCore import QSettings from defaults import FlatCAMDefaults @@ -10,8 +8,6 @@ import gettext import FlatCAMTranslation as fcTranslate import builtins -from flatcamGUI.preferences.OptionUI import OptionUI - fcTranslate.apply_language('strings') if '_' not in builtins.__dict__: _ = gettext.gettext @@ -24,6 +20,7 @@ else: log = logging.getLogger('PreferencesUIManager') + class PreferencesUIManager: def __init__(self, defaults: FlatCAMDefaults, data_path: str, ui, inform): @@ -33,7 +30,7 @@ class PreferencesUIManager: :param defaults: a dictionary storage where all the application settings are stored :param data_path: a path to the file where all the preferences are stored for persistence :param ui: reference to the FlatCAMGUI class which constructs the UI - :param inform: a pyqtSignal used to display information in the StatusBar of the GUI + :param inform: a pyqtSignal used to display information's in the StatusBar of the GUI """ self.defaults = defaults @@ -48,6 +45,298 @@ 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, + + # General GUI Preferences + "global_theme": self.ui.general_defaults_form.general_gui_group.theme_radio, + "global_gray_icons": self.ui.general_defaults_form.general_gui_group.gray_icons_cb, + "global_layout": self.ui.general_defaults_form.general_gui_group.layout_combo, + "global_hover": self.ui.general_defaults_form.general_gui_group.hover_cb, + "global_selection_shape": self.ui.general_defaults_form.general_gui_group.selection_cb, + + "global_sel_fill": self.ui.general_defaults_form.general_gui_group.sf_color_entry, + "global_sel_line": self.ui.general_defaults_form.general_gui_group.sl_color_entry, + "global_alt_sel_fill": self.ui.general_defaults_form.general_gui_group.alt_sf_color_entry, + "global_alt_sel_line": self.ui.general_defaults_form.general_gui_group.alt_sl_color_entry, + "global_draw_color": self.ui.general_defaults_form.general_gui_group.draw_color_entry, + "global_sel_draw_color": self.ui.general_defaults_form.general_gui_group.sel_draw_color_entry, + + "global_proj_item_color": self.ui.general_defaults_form.general_gui_group.proj_color_entry, + "global_proj_item_dis_color": self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry, + "global_project_autohide": self.ui.general_defaults_form.general_gui_group.project_autohide_cb, + + # General GUI Settings + "global_gridx": self.ui.general_defaults_form.general_app_set_group.gridx_entry, + "global_gridy": self.ui.general_defaults_form.general_app_set_group.gridy_entry, + "global_snap_max": self.ui.general_defaults_form.general_app_set_group.snap_max_dist_entry, + "global_workspace": self.ui.general_defaults_form.general_app_set_group.workspace_cb, + "global_workspaceT": self.ui.general_defaults_form.general_app_set_group.wk_cb, + "global_workspace_orientation": self.ui.general_defaults_form.general_app_set_group.wk_orientation_radio, + + "global_cursor_type": self.ui.general_defaults_form.general_app_set_group.cursor_radio, + "global_cursor_size": self.ui.general_defaults_form.general_app_set_group.cursor_size_entry, + "global_cursor_width": self.ui.general_defaults_form.general_app_set_group.cursor_width_entry, + "global_cursor_color_enabled": self.ui.general_defaults_form.general_app_set_group.mouse_cursor_color_cb, + "global_cursor_color": self.ui.general_defaults_form.general_app_set_group.mouse_cursor_entry, + "global_pan_button": self.ui.general_defaults_form.general_app_set_group.pan_button_radio, + "global_mselect_key": self.ui.general_defaults_form.general_app_set_group.mselect_radio, + "global_delete_confirmation": self.ui.general_defaults_form.general_app_set_group.delete_conf_cb, + "global_open_style": self.ui.general_defaults_form.general_app_set_group.open_style_cb, + "global_toggle_tooltips": self.ui.general_defaults_form.general_app_set_group.toggle_tooltips_cb, + "global_machinist_setting": self.ui.general_defaults_form.general_app_set_group.machinist_cb, + + "global_bookmarks_limit": self.ui.general_defaults_form.general_app_set_group.bm_limit_spinner, + "global_activity_icon": self.ui.general_defaults_form.general_app_set_group.activity_combo, + + # 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, + "gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb, + "gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry, + "gerber_def_units": self.ui.gerber_defaults_form.gerber_gen_group.gerber_units_radio, + "gerber_def_zeros": self.ui.gerber_defaults_form.gerber_gen_group.gerber_zeros_radio, + "gerber_clean_apertures": self.ui.gerber_defaults_form.gerber_gen_group.gerber_clean_cb, + "gerber_extra_buffering": self.ui.gerber_defaults_form.gerber_gen_group.gerber_extra_buffering, + "gerber_plot_fill": self.ui.gerber_defaults_form.gerber_gen_group.pf_color_entry, + "gerber_plot_line": self.ui.gerber_defaults_form.gerber_gen_group.pl_color_entry, + + # Gerber Options + "gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry, + "gerber_isopasses": self.ui.gerber_defaults_form.gerber_opt_group.iso_width_entry, + "gerber_isooverlap": self.ui.gerber_defaults_form.gerber_opt_group.iso_overlap_entry, + "gerber_combine_passes": self.ui.gerber_defaults_form.gerber_opt_group.combine_passes_cb, + "gerber_iso_scope": self.ui.gerber_defaults_form.gerber_opt_group.iso_scope_radio, + "gerber_milling_type": self.ui.gerber_defaults_form.gerber_opt_group.milling_type_radio, + "gerber_noncoppermargin": self.ui.gerber_defaults_form.gerber_opt_group.noncopper_margin_entry, + "gerber_noncopperrounded": self.ui.gerber_defaults_form.gerber_opt_group.noncopper_rounded_cb, + "gerber_bboxmargin": self.ui.gerber_defaults_form.gerber_opt_group.bbmargin_entry, + "gerber_bboxrounded": self.ui.gerber_defaults_form.gerber_opt_group.bbrounded_cb, + + # Gerber Advanced Options + "gerber_aperture_display": self.ui.gerber_defaults_form.gerber_adv_opt_group.aperture_table_visibility_cb, + # "gerber_aperture_scale_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.scale_aperture_entry, + # "gerber_aperture_buffer_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffer_aperture_entry, + "gerber_follow": self.ui.gerber_defaults_form.gerber_adv_opt_group.follow_cb, + "gerber_tool_type": self.ui.gerber_defaults_form.gerber_adv_opt_group.tool_type_radio, + "gerber_vtipdia": self.ui.gerber_defaults_form.gerber_adv_opt_group.tipdia_spinner, + "gerber_vtipangle": self.ui.gerber_defaults_form.gerber_adv_opt_group.tipangle_spinner, + "gerber_vcutz": self.ui.gerber_defaults_form.gerber_adv_opt_group.cutz_spinner, + "gerber_iso_type": self.ui.gerber_defaults_form.gerber_adv_opt_group.iso_type_radio, + + "gerber_buffering": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffering_radio, + "gerber_simplification": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplify_cb, + "gerber_simp_tolerance": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplification_tol_spinner, + + # Gerber Export + "gerber_exp_units": self.ui.gerber_defaults_form.gerber_exp_group.gerber_units_radio, + "gerber_exp_integer": self.ui.gerber_defaults_form.gerber_exp_group.format_whole_entry, + "gerber_exp_decimals": self.ui.gerber_defaults_form.gerber_exp_group.format_dec_entry, + "gerber_exp_zeros": self.ui.gerber_defaults_form.gerber_exp_group.zeros_radio, + + # Gerber Editor + "gerber_editor_sel_limit": self.ui.gerber_defaults_form.gerber_editor_group.sel_limit_entry, + "gerber_editor_newcode": self.ui.gerber_defaults_form.gerber_editor_group.addcode_entry, + "gerber_editor_newsize": self.ui.gerber_defaults_form.gerber_editor_group.addsize_entry, + "gerber_editor_newtype": self.ui.gerber_defaults_form.gerber_editor_group.addtype_combo, + "gerber_editor_newdim": self.ui.gerber_defaults_form.gerber_editor_group.adddim_entry, + "gerber_editor_array_size": self.ui.gerber_defaults_form.gerber_editor_group.grb_array_size_entry, + "gerber_editor_lin_axis": self.ui.gerber_defaults_form.gerber_editor_group.grb_axis_radio, + "gerber_editor_lin_pitch": self.ui.gerber_defaults_form.gerber_editor_group.grb_pitch_entry, + "gerber_editor_lin_angle": self.ui.gerber_defaults_form.gerber_editor_group.grb_angle_entry, + "gerber_editor_circ_dir": self.ui.gerber_defaults_form.gerber_editor_group.grb_circular_dir_radio, + "gerber_editor_circ_angle": + self.ui.gerber_defaults_form.gerber_editor_group.grb_circular_angle_entry, + "gerber_editor_scale_f": self.ui.gerber_defaults_form.gerber_editor_group.grb_scale_entry, + "gerber_editor_buff_f": self.ui.gerber_defaults_form.gerber_editor_group.grb_buff_entry, + "gerber_editor_ma_low": self.ui.gerber_defaults_form.gerber_editor_group.grb_ma_low_entry, + "gerber_editor_ma_high": self.ui.gerber_defaults_form.gerber_editor_group.grb_ma_high_entry, + + # Excellon General + "excellon_plot": self.ui.excellon_defaults_form.excellon_gen_group.plot_cb, + "excellon_solid": self.ui.excellon_defaults_form.excellon_gen_group.solid_cb, + "excellon_format_upper_in": + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry, + "excellon_format_lower_in": + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_in_entry, + "excellon_format_upper_mm": + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_mm_entry, + "excellon_format_lower_mm": + self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_lower_mm_entry, + "excellon_zeros": self.ui.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio, + "excellon_units": self.ui.excellon_defaults_form.excellon_gen_group.excellon_units_radio, + "excellon_update": self.ui.excellon_defaults_form.excellon_gen_group.update_excellon_cb, + "excellon_optimization_type": self.ui.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio, + "excellon_search_time": self.ui.excellon_defaults_form.excellon_gen_group.optimization_time_entry, + "excellon_plot_fill": self.ui.excellon_defaults_form.excellon_gen_group.fill_color_entry, + "excellon_plot_line": self.ui.excellon_defaults_form.excellon_gen_group.line_color_entry, + + # Excellon Options + "excellon_operation": self.ui.excellon_defaults_form.excellon_opt_group.operation_radio, + "excellon_milling_type": self.ui.excellon_defaults_form.excellon_opt_group.milling_type_radio, + + "excellon_milling_dia": self.ui.excellon_defaults_form.excellon_opt_group.mill_dia_entry, + + "excellon_cutz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry, + "excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb, + "excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry, + "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry, + "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry, + "excellon_endxy": self.ui.excellon_defaults_form.excellon_opt_group.endxy_entry, + + "excellon_feedrate_z": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry, + "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry, + "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb, + "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry, + "excellon_toolchange": self.ui.excellon_defaults_form.excellon_opt_group.toolchange_cb, + "excellon_toolchangez": self.ui.excellon_defaults_form.excellon_opt_group.toolchangez_entry, + "excellon_ppname_e": self.ui.excellon_defaults_form.excellon_opt_group.pp_excellon_name_cb, + "excellon_tooldia": self.ui.excellon_defaults_form.excellon_opt_group.tooldia_entry, + "excellon_slot_tooldia": self.ui.excellon_defaults_form.excellon_opt_group.slot_tooldia_entry, + "excellon_gcode_type": self.ui.excellon_defaults_form.excellon_opt_group.excellon_gcode_type_radio, + + # Excellon Advanced Options + "excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry, + "excellon_toolchangexy": self.ui.excellon_defaults_form.excellon_adv_opt_group.toolchangexy_entry, + "excellon_startz": self.ui.excellon_defaults_form.excellon_adv_opt_group.estartz_entry, + "excellon_feedrate_rapid": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_rapid_entry, + "excellon_z_pdepth": self.ui.excellon_defaults_form.excellon_adv_opt_group.pdepth_entry, + "excellon_feedrate_probe": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_probe_entry, + "excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio, + "excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb, + "excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb, + + # Excellon Export + "excellon_exp_units": self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio, + "excellon_exp_format": self.ui.excellon_defaults_form.excellon_exp_group.format_radio, + "excellon_exp_integer": self.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry, + "excellon_exp_decimals": self.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry, + "excellon_exp_zeros": self.ui.excellon_defaults_form.excellon_exp_group.zeros_radio, + "excellon_exp_slot_type": self.ui.excellon_defaults_form.excellon_exp_group.slot_type_radio, + + # Excellon Editor + "excellon_editor_sel_limit": self.ui.excellon_defaults_form.excellon_editor_group.sel_limit_entry, + "excellon_editor_newdia": self.ui.excellon_defaults_form.excellon_editor_group.addtool_entry, + "excellon_editor_array_size": self.ui.excellon_defaults_form.excellon_editor_group.drill_array_size_entry, + "excellon_editor_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_axis_radio, + "excellon_editor_lin_pitch": self.ui.excellon_defaults_form.excellon_editor_group.drill_pitch_entry, + "excellon_editor_lin_angle": self.ui.excellon_defaults_form.excellon_editor_group.drill_angle_entry, + "excellon_editor_circ_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_dir_radio, + "excellon_editor_circ_angle": + self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_angle_entry, + # Excellon Slots + "excellon_editor_slot_direction": + self.ui.excellon_defaults_form.excellon_editor_group.slot_axis_radio, + "excellon_editor_slot_angle": + self.ui.excellon_defaults_form.excellon_editor_group.slot_angle_spinner, + "excellon_editor_slot_length": + self.ui.excellon_defaults_form.excellon_editor_group.slot_length_entry, + # Excellon Slots + "excellon_editor_slot_array_size": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_size_entry, + "excellon_editor_slot_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.slot_array_axis_radio, + "excellon_editor_slot_lin_pitch": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_pitch_entry, + "excellon_editor_slot_lin_angle": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_angle_entry, + "excellon_editor_slot_circ_dir": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_dir_radio, + "excellon_editor_slot_circ_angle": + self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_angle_entry, + + # Geometry General + "geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb, + "geometry_circle_steps": self.ui.geometry_defaults_form.geometry_gen_group.circle_steps_entry, + "geometry_cnctooldia": self.ui.geometry_defaults_form.geometry_gen_group.cnctooldia_entry, + "geometry_plot_line": self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry, + + # Geometry Options + "geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry, + "geometry_travelz": self.ui.geometry_defaults_form.geometry_opt_group.travelz_entry, + "geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry, + "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.feedrate_z_entry, + "geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry, + "geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb, + "geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry, + "geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb, + "geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb, + "geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry, + "geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.endz_entry, + "geometry_endxy": self.ui.geometry_defaults_form.geometry_opt_group.endxy_entry, + "geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry, + "geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb, + + # Geometry Advanced Options + "geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry, + "geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry, + "geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_rapid_entry, + "geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb, + "geometry_extracut_length": self.ui.geometry_defaults_form.geometry_adv_opt_group.e_cut_entry, + "geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry, + "geometry_feedrate_probe": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_probe_entry, + "geometry_spindledir": self.ui.geometry_defaults_form.geometry_adv_opt_group.spindledir_radio, + "geometry_f_plunge": self.ui.geometry_defaults_form.geometry_adv_opt_group.fplunge_cb, + "geometry_segx": self.ui.geometry_defaults_form.geometry_adv_opt_group.segx_entry, + "geometry_segy": self.ui.geometry_defaults_form.geometry_adv_opt_group.segy_entry, + "geometry_area_exclusion": self.ui.geometry_defaults_form.geometry_adv_opt_group.exclusion_cb, + "geometry_area_shape": self.ui.geometry_defaults_form.geometry_adv_opt_group.area_shape_radio, + "geometry_area_strategy": self.ui.geometry_defaults_form.geometry_adv_opt_group.strategy_radio, + "geometry_area_overz": self.ui.geometry_defaults_form.geometry_adv_opt_group.over_z_entry, + + # Geometry Editor + "geometry_editor_sel_limit": self.ui.geometry_defaults_form.geometry_editor_group.sel_limit_entry, + "geometry_editor_milling_type": self.ui.geometry_defaults_form.geometry_editor_group.milling_type_radio, + + # CNCJob General + "cncjob_plot": self.ui.cncjob_defaults_form.cncjob_gen_group.plot_cb, + "cncjob_plot_kind": self.ui.cncjob_defaults_form.cncjob_gen_group.cncplot_method_radio, + "cncjob_annotation": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_cb, + + "cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry, + "cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio, + "cncjob_coords_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_dec_entry, + "cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry, + "cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry, + "cncjob_line_ending": self.ui.cncjob_defaults_form.cncjob_gen_group.line_ending_cb, + "cncjob_plot_line": self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_entry, + "cncjob_plot_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_entry, + "cncjob_travel_line": self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_entry, + "cncjob_travel_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_entry, + + # CNC Job Options + "cncjob_prepend": self.ui.cncjob_defaults_form.cncjob_opt_group.prepend_text, + "cncjob_append": self.ui.cncjob_defaults_form.cncjob_opt_group.append_text, + + # CNC Job Advanced Options + "cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text, + "cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb, + "cncjob_annotation_fontsize": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontsize_sp, + "cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry, # NCC Tool "tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry, @@ -298,49 +587,17 @@ class PreferencesUIManager: } - self.sections = [ - ui.general_defaults_form, - ui.gerber_defaults_form, - ui.excellon_defaults_form, - ui.geometry_defaults_form, - ui.cncjob_defaults_form, - ui.tools_defaults_form, - ui.tools2_defaults_form, - ui.util_defaults_form - ] - - def get_form_fields(self) -> Dict[str, Any]: - result = {} - result.update(self.defaults_form_fields) - result.update(self._option_field_dict()) - return result - - def get_form_field(self, option: str) -> Any: - return self.get_form_fields()[option] - - def option_dict(self) -> Dict[str, OptionUI]: - result = {} - for section in self.sections: - sectionoptions = section.option_dict() - result.update(sectionoptions) - return result - - def _option_field_dict(self): - result = {k: v.get_field() for k, v in self.option_dict().items()} - return result - def defaults_read_form(self): """ Will read all the values in the Preferences GUI and update the defaults dictionary. :return: None """ - for option in self.get_form_fields(): - if option in self.defaults: - try: - self.defaults[option] = self.get_form_field(option=option).get_value() - except Exception as e: - log.debug("App.defaults_read_form() --> %s" % str(e)) + for option in self.defaults_form_fields: + try: + self.defaults[option] = self.defaults_form_fields[option].get_value() + except Exception as e: + log.debug("App.defaults_read_form() --> %s" % str(e)) def defaults_write_form(self, factor=None, fl_units=None, source_dict=None): """ @@ -380,7 +637,7 @@ class PreferencesUIManager: if factor is not None: value *= factor - form_field = self.get_form_field(option=field) + form_field = self.defaults_form_fields[field] if units is None: form_field.set_value(value) elif (units == 'IN' or units == 'MM') and (field == 'global_gridx' or field == 'global_gridy'): @@ -397,12 +654,70 @@ class PreferencesUIManager: :return: None """ - # FIXME this should be done in __init__ - for section in self.sections: - tab = section.build_tab() - tab.setObjectName(section.get_tab_id()) - self.ui.pref_tab_area.addTab(tab, section.get_tab_label()) + gen_form = self.ui.general_defaults_form + try: + self.ui.general_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.general_scroll_area.setWidget(gen_form) + gen_form.show() + + ger_form = self.ui.gerber_defaults_form + try: + self.ui.gerber_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.gerber_scroll_area.setWidget(ger_form) + ger_form.show() + + exc_form = self.ui.excellon_defaults_form + try: + self.ui.excellon_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.excellon_scroll_area.setWidget(exc_form) + exc_form.show() + + geo_form = self.ui.geometry_defaults_form + try: + self.ui.geometry_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.geometry_scroll_area.setWidget(geo_form) + geo_form.show() + + cnc_form = self.ui.cncjob_defaults_form + try: + self.ui.cncjob_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.cncjob_scroll_area.setWidget(cnc_form) + cnc_form.show() + + tools_form = self.ui.tools_defaults_form + try: + self.ui.tools_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.tools_scroll_area.setWidget(tools_form) + tools_form.show() + + tools2_form = self.ui.tools2_defaults_form + try: + self.ui.tools2_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.tools2_scroll_area.setWidget(tools2_form) + tools2_form.show() + + fa_form = self.ui.util_defaults_form + try: + self.ui.fa_scroll_area.takeWidget() + except Exception: + log.debug("Nothing to remove") + self.ui.fa_scroll_area.setWidget(fa_form) + fa_form.show() # Initialize the color box's color in Preferences -> Global -> Colo self.__init_color_pickers() @@ -416,6 +731,148 @@ class PreferencesUIManager: log.debug("Finished Preferences GUI form initialization.") def __init_color_pickers(self): + # Init Gerber Plot Colors + self.ui.gerber_defaults_form.gerber_gen_group.pf_color_entry.set_value(self.defaults['gerber_plot_fill']) + self.ui.gerber_defaults_form.gerber_gen_group.pf_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['gerber_plot_fill'])[:7]) + self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_spinner.set_value( + int(self.defaults['gerber_plot_fill'][7:9], 16)) + self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.setValue( + int(self.defaults['gerber_plot_fill'][7:9], 16)) + + self.ui.gerber_defaults_form.gerber_gen_group.pl_color_entry.set_value(self.defaults['gerber_plot_line']) + self.ui.gerber_defaults_form.gerber_gen_group.pl_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['gerber_plot_line'])[:7]) + + # Init Excellon Plot Colors + self.ui.excellon_defaults_form.excellon_gen_group.fill_color_entry.set_value( + self.defaults['excellon_plot_fill']) + self.ui.excellon_defaults_form.excellon_gen_group.fill_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['excellon_plot_fill'])[:7]) + self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_spinner.set_value( + int(self.defaults['excellon_plot_fill'][7:9], 16)) + self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_slider.setValue( + int(self.defaults['excellon_plot_fill'][7:9], 16)) + + self.ui.excellon_defaults_form.excellon_gen_group.line_color_entry.set_value( + self.defaults['excellon_plot_line']) + self.ui.excellon_defaults_form.excellon_gen_group.line_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['excellon_plot_line'])[:7]) + + # Init Geometry Plot Colors + self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry.set_value( + self.defaults['geometry_plot_line']) + self.ui.geometry_defaults_form.geometry_gen_group.line_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['geometry_plot_line'])[:7]) + + # Init CNCJob Travel Line Colors + self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_entry.set_value( + self.defaults['cncjob_travel_fill']) + self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['cncjob_travel_fill'])[:7]) + self.ui.cncjob_defaults_form.cncjob_gen_group.tcolor_alpha_spinner.set_value( + int(self.defaults['cncjob_travel_fill'][7:9], 16)) + self.ui.cncjob_defaults_form.cncjob_gen_group.tcolor_alpha_slider.setValue( + int(self.defaults['cncjob_travel_fill'][7:9], 16)) + + self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_entry.set_value( + self.defaults['cncjob_travel_line']) + self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['cncjob_travel_line'])[:7]) + + # Init CNCJob Plot Colors + self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_entry.set_value( + self.defaults['cncjob_plot_fill']) + self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['cncjob_plot_fill'])[:7]) + + self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_entry.set_value( + self.defaults['cncjob_plot_line']) + self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['cncjob_plot_line'])[:7]) + + # Init Left-Right Selection colors + self.ui.general_defaults_form.general_gui_group.sf_color_entry.set_value(self.defaults['global_sel_fill']) + self.ui.general_defaults_form.general_gui_group.sf_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_sel_fill'])[:7]) + self.ui.general_defaults_form.general_gui_group.sf_color_alpha_spinner.set_value( + int(self.defaults['global_sel_fill'][7:9], 16)) + self.ui.general_defaults_form.general_gui_group.sf_color_alpha_slider.setValue( + int(self.defaults['global_sel_fill'][7:9], 16)) + + self.ui.general_defaults_form.general_gui_group.sl_color_entry.set_value(self.defaults['global_sel_line']) + self.ui.general_defaults_form.general_gui_group.sl_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_sel_line'])[:7]) + + # Init Right-Left Selection colors + self.ui.general_defaults_form.general_gui_group.alt_sf_color_entry.set_value( + self.defaults['global_alt_sel_fill']) + self.ui.general_defaults_form.general_gui_group.alt_sf_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_alt_sel_fill'])[:7]) + self.ui.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.set_value( + int(self.defaults['global_sel_fill'][7:9], 16)) + self.ui.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.setValue( + int(self.defaults['global_sel_fill'][7:9], 16)) + + self.ui.general_defaults_form.general_gui_group.alt_sl_color_entry.set_value( + self.defaults['global_alt_sel_line']) + self.ui.general_defaults_form.general_gui_group.alt_sl_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_alt_sel_line'])[:7]) + + # Init Draw color and Selection Draw Color + self.ui.general_defaults_form.general_gui_group.draw_color_entry.set_value( + self.defaults['global_draw_color']) + self.ui.general_defaults_form.general_gui_group.draw_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_draw_color'])[:7]) + + self.ui.general_defaults_form.general_gui_group.sel_draw_color_entry.set_value( + self.defaults['global_sel_draw_color']) + self.ui.general_defaults_form.general_gui_group.sel_draw_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_sel_draw_color'])[:7]) + + # Init Project Items color + self.ui.general_defaults_form.general_gui_group.proj_color_entry.set_value( + self.defaults['global_proj_item_color']) + self.ui.general_defaults_form.general_gui_group.proj_color_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_proj_item_color'])[:7]) + + # Init Project Disabled Items color + self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry.set_value( + self.defaults['global_proj_item_dis_color']) + self.ui.general_defaults_form.general_gui_group.proj_color_dis_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_proj_item_dis_color'])[:7]) + + # Init Project Disabled Items color + self.ui.general_defaults_form.general_app_set_group.mouse_cursor_entry.set_value( + self.defaults['global_cursor_color']) + self.ui.general_defaults_form.general_app_set_group.mouse_cursor_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['global_cursor_color'])[:7]) + + # Init the Annotation CNC Job color + self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.set_value( + self.defaults['cncjob_annotation_fontcolor']) + self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.setStyleSheet( + "background-color:%s;" + "border-color: dimgray" % str(self.defaults['cncjob_annotation_fontcolor'])[:7]) + # Init the Tool Film color self.ui.tools_defaults_form.tools_film_group.film_color_entry.set_value( self.defaults['tools_film_color']) @@ -464,8 +921,7 @@ class PreferencesUIManager: theme = 'white' should_restart = False - - val = self.get_form_field("global_theme").get_value() + val = self.ui.general_defaults_form.general_gui_group.theme_radio.get_value() if val != theme: msgbox = QtWidgets.QMessageBox() msgbox.setText(_("Are you sure you want to continue?")) @@ -500,20 +956,20 @@ class PreferencesUIManager: settgs = QSettings("Open Source", "FlatCAM") # save the notebook font size - fsize = self.get_form_field("notebook_font_size").get_value() + fsize = self.ui.general_defaults_form.general_app_set_group.notebook_font_size_spinner.get_value() settgs.setValue('notebook_font_size', fsize) # save the axis font size - g_fsize = self.get_form_field("axis_font_size").get_value() + g_fsize = self.ui.general_defaults_form.general_app_set_group.axis_font_size_spinner.get_value() settgs.setValue('axis_font_size', g_fsize) # save the textbox font size - tb_fsize = self.get_form_field("textbox_font_size").get_value() + tb_fsize = self.ui.general_defaults_form.general_app_set_group.textbox_font_size_spinner.get_value() settgs.setValue('textbox_font_size', tb_fsize) settgs.setValue( 'machinist', - 1 if self.get_form_field("global_machinist_setting").get_value() else 0 + 1 if self.ui.general_defaults_form.general_app_set_group.machinist_cb.get_value() else 0 ) # This will write the setting to the platform specific storage. @@ -536,11 +992,11 @@ class PreferencesUIManager: self.ignore_tab_close_event = True try: - self.get_form_field("units").activated_custom.disconnect() + self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.disconnect() except (TypeError, AttributeError): pass self.defaults_write_form(source_dict=self.defaults.current_defaults) - self.get_form_field("units").activated_custom.connect( + self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect( lambda: self.ui.app.on_toggle_units(no_pref=False)) self.defaults.update(self.defaults.current_defaults) diff --git a/flatcamGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py b/flatcamGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py index 5422e297..8d7a1cf0 100644 --- a/flatcamGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py +++ b/flatcamGUI/preferences/cncjob/CNCJobAdvOptPrefGroupUI.py @@ -1,7 +1,8 @@ -from PyQt5.QtCore import Qt +from PyQt5 import QtWidgets, QtGui, QtCore +from PyQt5.QtCore import QSettings, Qt -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from flatcamGUI.GUIElements import FCTextArea, FCCheckBox, FCComboBox, FCSpinner, FCEntry +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate import builtins @@ -10,18 +11,93 @@ 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 CNCJobAdvOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): +class CNCJobAdvOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "CNC Job Advanced Options Preferences", parent=None) + super(CNCJobAdvOptPrefGroupUI, self).__init__(self, parent=parent) self.decimals = decimals - super().__init__(**kwargs) + self.setTitle(str(_("CNC Job Adv. Options"))) - self.toolchange_text = self.option_dict()["cncjob_toolchange_macro"].get_field() + # ## Export G-Code + self.export_gcode_label = QtWidgets.QLabel("%s:" % _("Export CNC Code")) + self.export_gcode_label.setToolTip( + _("Export and save G-Code to\n" + "make this object to a file.") + ) + self.layout.addWidget(self.export_gcode_label) + + # Prepend to G-Code + toolchangelabel = QtWidgets.QLabel('%s' % _('Toolchange G-Code')) + toolchangelabel.setToolTip( + _( + "Type here any G-Code commands you would\n" + "like to be executed when Toolchange event is encountered.\n" + "This will constitute a Custom Toolchange GCode,\n" + "or a Toolchange Macro.\n" + "The FlatCAM variables are surrounded by '%' symbol.\n\n" + "WARNING: it can be used only with a preprocessor file\n" + "that has 'toolchange_custom' in it's name and this is built\n" + "having as template the 'Toolchange Custom' posprocessor file." + ) + ) + self.layout.addWidget(toolchangelabel) + + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("textbox_font_size"): + tb_fsize = qsettings.value('textbox_font_size', type=int) + else: + tb_fsize = 10 + font = QtGui.QFont() + font.setPointSize(tb_fsize) + + self.toolchange_text = FCTextArea() + self.toolchange_text.setPlaceholderText( + _( + "Type here any G-Code commands you would " + "like to be executed when Toolchange event is encountered.\n" + "This will constitute a Custom Toolchange GCode, " + "or a Toolchange Macro.\n" + "The FlatCAM variables are surrounded by '%' symbol.\n" + "WARNING: it can be used only with a preprocessor file " + "that has 'toolchange_custom' in it's name." + ) + ) + self.layout.addWidget(self.toolchange_text) + self.toolchange_text.setFont(font) + + hlay = QtWidgets.QHBoxLayout() + self.layout.addLayout(hlay) + + # Toolchange Replacement GCode + self.toolchange_cb = FCCheckBox(label='%s' % _('Use Toolchange Macro')) + self.toolchange_cb.setToolTip( + _("Check this box if you want to use\n" + "a Custom Toolchange GCode (macro).") + ) + hlay.addWidget(self.toolchange_cb) + hlay.addStretch() + + hlay1 = QtWidgets.QHBoxLayout() + self.layout.addLayout(hlay1) + + # Variable list + self.tc_variable_combo = FCComboBox() + self.tc_variable_combo.setToolTip( + _("A list of the FlatCAM variables that can be used\n" + "in the Toolchange event.\n" + "They have to be surrounded by the '%' symbol") + ) + hlay1.addWidget(self.tc_variable_combo) # Populate the Combo Box - self.tc_variable_combo = self.option_dict()["__toolchange_variable"].get_field() variables = [_('Parameters'), 'tool', 'tooldia', 't_drills', 'x_toolchange', 'y_toolchange', 'z_toolchange', 'z_cut', 'z_move', 'z_depthpercut', 'spindlespeed', 'dwelltime'] self.tc_variable_combo.addItems(variables) @@ -50,58 +126,83 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI2): _("dwelltime = time to dwell to allow the spindle to reach it's set RPM"), Qt.ToolTipRole) + # hlay1.addStretch() + + # Insert Variable into the Toolchange G-Code Text Box + # self.tc_insert_buton = FCButton("Insert") + # self.tc_insert_buton.setToolTip( + # "Insert the variable in the GCode Box\n" + # "surrounded by the '%' symbol." + # ) + # hlay1.addWidget(self.tc_insert_buton) + + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + + grid0.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 2) + + # Annotation Font Size + self.annotation_fontsize_label = QtWidgets.QLabel('%s:' % _("Annotation Size")) + self.annotation_fontsize_label.setToolTip( + _("The font size of the annotation text. In pixels.") + ) + grid0.addWidget(self.annotation_fontsize_label, 2, 0) + self.annotation_fontsize_sp = FCSpinner() + self.annotation_fontsize_sp.set_range(0, 9999) + + grid0.addWidget(self.annotation_fontsize_sp, 2, 1) + grid0.addWidget(QtWidgets.QLabel(''), 2, 2) + + # Annotation Font Color + self.annotation_color_label = QtWidgets.QLabel('%s:' % _('Annotation Color')) + self.annotation_color_label.setToolTip( + _("Set the font color for the annotation texts.") + ) + self.annotation_fontcolor_entry = FCEntry() + self.annotation_fontcolor_button = QtWidgets.QPushButton() + self.annotation_fontcolor_button.setFixedSize(15, 15) + + self.form_box_child = QtWidgets.QHBoxLayout() + self.form_box_child.setContentsMargins(0, 0, 0, 0) + self.form_box_child.addWidget(self.annotation_fontcolor_entry) + self.form_box_child.addWidget(self.annotation_fontcolor_button, alignment=Qt.AlignRight) + self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + color_widget = QtWidgets.QWidget() + color_widget.setLayout(self.form_box_child) + grid0.addWidget(self.annotation_color_label, 3, 0) + grid0.addWidget(color_widget, 3, 1) + grid0.addWidget(QtWidgets.QLabel(''), 3, 2) + + self.layout.addStretch() + self.tc_variable_combo.currentIndexChanged[str].connect(self.on_cnc_custom_parameters) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Export CNC Code", - label_tooltip="Export and save G-Code to\n" - "make this object to a file." - ), - CheckboxOptionUI( - option="cncjob_toolchange_macro_enable", - label_text="Use Toolchange Macro", - label_tooltip="Check this box if you want to use\n" - "a Custom Toolchange GCode (macro)." - ), - TextAreaOptionUI( - option="cncjob_toolchange_macro", - label_text="Toolchange G-Code", - label_tooltip="Type here any G-Code commands you would " - "like to be executed when Toolchange event is encountered.\n" - "This will constitute a Custom Toolchange GCode, " - "or a Toolchange Macro.\n" - "The FlatCAM variables are surrounded by '%' symbol.\n" - "WARNING: it can be used only with a preprocessor file " - "that has 'toolchange_custom' in it's name." - ), - ComboboxOptionUI( - option="__toolchange_variable", - label_text="Insert variable", - label_tooltip="A list of the FlatCAM variables that can be used\n" - "in the Toolchange event.\n" - "They have to be surrounded by the '%' symbol", - choices=[] # see init. - ), - - SpinnerOptionUI( - option="cncjob_annotation_fontsize", - label_text="Annotation Size", - label_tooltip="The font size of the annotation text. In pixels.", - min_value=1, max_value=9999, step=1 - ), - ColorOptionUI( - option="cncjob_annotation_fontcolor", - label_text="Annotation Color", - label_tooltip="Set the font color for the annotation texts." - ) - ] + self.annotation_fontcolor_entry.editingFinished.connect(self.on_annotation_fontcolor_entry) + self.annotation_fontcolor_button.clicked.connect(self.on_annotation_fontcolor_button) def on_cnc_custom_parameters(self, signal_text): - if signal_text == _("Parameters"): + if signal_text == 'Parameters': return else: self.toolchange_text.insertPlainText('%%%s%%' % signal_text) - self.tc_variable_combo.set_value(_("Parameters")) + def on_annotation_fontcolor_entry(self): + self.app.defaults['cncjob_annotation_fontcolor'] = self.annotation_fontcolor_entry.get_value() + self.annotation_fontcolor_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['cncjob_annotation_fontcolor'])) + + def on_annotation_fontcolor_button(self): + current_color = QtGui.QColor(self.app.defaults['cncjob_annotation_fontcolor']) + + c_dialog = QtWidgets.QColorDialog() + annotation_color = c_dialog.getColor(initial=current_color) + + if annotation_color.isValid() is False: + return + + self.annotation_fontcolor_button.setStyleSheet("background-color:%s" % str(annotation_color.name())) + + new_val_sel = str(annotation_color.name()) + self.annotation_fontcolor_entry.set_value(new_val_sel) + self.app.defaults['cncjob_annotation_fontcolor'] = new_val_sel diff --git a/flatcamGUI/preferences/cncjob/CNCJobGenPrefGroupUI.py b/flatcamGUI/preferences/cncjob/CNCJobGenPrefGroupUI.py index e999fb6e..66276e23 100644 --- a/flatcamGUI/preferences/cncjob/CNCJobGenPrefGroupUI.py +++ b/flatcamGUI/preferences/cncjob/CNCJobGenPrefGroupUI.py @@ -1,142 +1,389 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt5.QtCore import QSettings +from flatcamGUI.GUIElements import FCCheckBox, RadioSet, FCSpinner, FCDoubleSpinner, FCEntry +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 CNCJobGenPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class CNCJobGenPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "CNC Job General Preferences", parent=None) + super(CNCJobGenPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("CNC Job General"))) + self.decimals = decimals + + # ## Plot options + self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options")) + self.layout.addWidget(self.plot_options_label) + + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + grid0.setColumnStretch(0, 0) + grid0.setColumnStretch(1, 1) + + # Plot CB + # self.plot_cb = QtWidgets.QCheckBox('Plot') + self.plot_cb = FCCheckBox(_('Plot Object')) + self.plot_cb.setToolTip(_("Plot (show) this object.")) + grid0.addWidget(self.plot_cb, 0, 0, 1, 2) + + # Plot Kind + self.cncplot_method_label = QtWidgets.QLabel('%s:' % _("Plot kind")) + self.cncplot_method_label.setToolTip( + _("This selects the kind of geometries on the canvas to plot.\n" + "Those can be either of type 'Travel' which means the moves\n" + "above the work piece or it can be of type 'Cut',\n" + "which means the moves that cut into the material.") + ) + + self.cncplot_method_radio = RadioSet([ + {"label": _("All"), "value": "all"}, + {"label": _("Travel"), "value": "travel"}, + {"label": _("Cut"), "value": "cut"} + ], orientation='vertical') + + grid0.addWidget(self.cncplot_method_label, 1, 0) + grid0.addWidget(self.cncplot_method_radio, 1, 1) + grid0.addWidget(QtWidgets.QLabel(''), 1, 2) + + # Display Annotation + self.annotation_cb = FCCheckBox(_("Display Annotation")) + self.annotation_cb.setToolTip( + _("This selects if to display text annotation on the plot.\n" + "When checked it will display numbers in order for each end\n" + "of a travel line." + ) + ) + + grid0.addWidget(self.annotation_cb, 2, 0, 1, 3) + + # ################################################################### + # Number of circle steps for circular aperture linear approximation # + # ################################################################### + self.steps_per_circle_label = QtWidgets.QLabel('%s:' % _("Circle Steps")) + self.steps_per_circle_label.setToolTip( + _("The number of circle steps for GCode \n" + "circle and arc shapes linear approximation.") + ) + grid0.addWidget(self.steps_per_circle_label, 3, 0) + self.steps_per_circle_entry = FCSpinner() + self.steps_per_circle_entry.set_range(0, 99999) + grid0.addWidget(self.steps_per_circle_entry, 3, 1) + + # Tool dia for plot + tdlabel = QtWidgets.QLabel('%s:' % _('Travel dia')) + tdlabel.setToolTip( + _("The width of the travel lines to be\n" + "rendered in the plot.") + ) + self.tooldia_entry = FCDoubleSpinner() + self.tooldia_entry.set_range(0, 99999) + self.tooldia_entry.set_precision(self.decimals) + self.tooldia_entry.setSingleStep(0.1) + self.tooldia_entry.setWrapping(True) + + grid0.addWidget(tdlabel, 4, 0) + grid0.addWidget(self.tooldia_entry, 4, 1) + + # add a space + grid0.addWidget(QtWidgets.QLabel('%s:' % _("G-code Decimals")), 5, 0, 1, 2) + + # Number of decimals to use in GCODE coordinates + cdeclabel = QtWidgets.QLabel('%s:' % _('Coordinates')) + cdeclabel.setToolTip( + _("The number of decimals to be used for \n" + "the X, Y, Z coordinates in CNC code (GCODE, etc.)") + ) + self.coords_dec_entry = FCSpinner() + self.coords_dec_entry.set_range(0, 9) + self.coords_dec_entry.setWrapping(True) + + grid0.addWidget(cdeclabel, 6, 0) + grid0.addWidget(self.coords_dec_entry, 6, 1) + + # Number of decimals to use in GCODE feedrate + frdeclabel = QtWidgets.QLabel('%s:' % _('Feedrate')) + frdeclabel.setToolTip( + _("The number of decimals to be used for \n" + "the Feedrate parameter in CNC code (GCODE, etc.)") + ) + self.fr_dec_entry = FCSpinner() + self.fr_dec_entry.set_range(0, 9) + self.fr_dec_entry.setWrapping(True) + + grid0.addWidget(frdeclabel, 7, 0) + grid0.addWidget(self.fr_dec_entry, 7, 1) + + # The type of coordinates used in the Gcode: Absolute or Incremental + coords_type_label = QtWidgets.QLabel('%s:' % _('Coordinates type')) + coords_type_label.setToolTip( + _("The type of coordinates to be used in Gcode.\n" + "Can be:\n" + "- Absolute G90 -> the reference is the origin x=0, y=0\n" + "- Incremental G91 -> the reference is the previous position") + ) + self.coords_type_radio = RadioSet([ + {"label": _("Absolute G90"), "value": "G90"}, + {"label": _("Incremental G91"), "value": "G91"} + ], orientation='vertical', stretch=False) + grid0.addWidget(coords_type_label, 8, 0) + grid0.addWidget(self.coords_type_radio, 8, 1) # hidden for the time being, until implemented - self.option_dict()["cncjob_coords_type"].label_widget.hide() - self.option_dict()["cncjob_coords_type"].get_field().hide() + coords_type_label.hide() + self.coords_type_radio.hide() - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Plot Options"), - CheckboxOptionUI( - option="cncjob_plot", - label_text="Plot Object", - label_tooltip="Plot (show) this object." - ), - RadioSetOptionUI( - option="cncjob_plot_kind", - label_text="Plot kind", - label_tooltip="This selects the kind of geometries on the canvas to plot.\n" - "Those can be either of type 'Travel' which means the moves\n" - "above the work piece or it can be of type 'Cut',\n" - "which means the moves that cut into the material.", - choices=[ - {"label": _("All"), "value": "all"}, - {"label": _("Travel"), "value": "travel"}, - {"label": _("Cut"), "value": "cut"} - ], - orientation="vertical" - ), - CheckboxOptionUI( - option="cncjob_annotation", - label_text="Display Annotation", - label_tooltip="This selects if to display text annotation on the plot.\n" - "When checked it will display numbers in order for each end\n" - "of a travel line." - ), - SpinnerOptionUI( - option="cncjob_steps_per_circle", - label_text="Circle Steps", - label_tooltip="The number of circle steps for GCode \n" - "circle and arc shapes linear approximation.", - min_value=3, max_value=99999, step=1 - ), - DoubleSpinnerOptionUI( - option="cncjob_tooldia", - label_text="Travel dia", - label_tooltip="The width of the travel lines to be\n" - "rendered in the plot.", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals - ), + # Line Endings + self.line_ending_cb = FCCheckBox(_("Force Windows style line-ending")) + self.line_ending_cb.setToolTip( + _("When checked will force a Windows style line-ending\n" + "(\\r\\n) on non-Windows OS's.") + ) - HeadingOptionUI(label_text="G-code Decimals"), - SpinnerOptionUI( - option="cncjob_coords_decimals", - label_text="Coordinates", - label_tooltip="The number of decimals to be used for \n" - "the X, Y, Z coordinates in CNC code (GCODE, etc.)", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="cncjob_fr_decimals", - label_text="Feedrate", - label_tooltip="The number of decimals to be used for \n" - "the Feedrate parameter in CNC code (GCODE, etc.)", - min_value=0, max_value=9, step=1 - ), - RadioSetOptionUI( - option="cncjob_coords_type", - label_text="Coordinates type", - label_tooltip="The type of coordinates to be used in Gcode.\n" - "Can be:\n" - "- Absolute G90 -> the reference is the origin x=0, y=0\n" - "- Incremental G91 -> the reference is the previous position", - choices=[ - {"label": _("Absolute G90"), "value": "G90"}, - {"label": _("Incremental G91"), "value": "G91"} - ], - orientation="vertical" - ), - CheckboxOptionUI( - option="cncjob_line_ending", - label_text="Force Windows style line-ending", - label_tooltip="When checked will force a Windows style line-ending\n" - "(\\r\\n) on non-Windows OS's." - ), - SeparatorOptionUI(), + grid0.addWidget(self.line_ending_cb, 9, 0, 1, 3) - HeadingOptionUI(label_text="Travel Line Color"), - ColorOptionUI( - option="cncjob_travel_line", - label_text="Outline", - label_tooltip="Set the line color for plotted objects.", - ), - ColorOptionUI( - option="cncjob_travel_fill", - label_text="Fill", - label_tooltip="Set the fill color for plotted objects.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["cncjob_travel_line", "cncjob_travel_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the transparency for plotted objects." - ), + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 12, 0, 1, 2) - HeadingOptionUI(label_text="CNCJob Object Color"), - ColorOptionUI( - option="cncjob_plot_line", - label_text="Outline", - label_tooltip="Set the line color for plotted objects.", - ), - ColorOptionUI( - option="cncjob_plot_fill", - label_text="Fill", - label_tooltip="Set the fill color for plotted objects.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["cncjob_plot_line", "cncjob_plot_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the transparency for plotted objects." - ) - ] \ No newline at end of file + # Travel Line Color + self.travel_color_label = QtWidgets.QLabel('%s' % _('Travel Line Color')) + grid0.addWidget(self.travel_color_label, 13, 0, 1, 2) + + # Plot Line Color + self.tline_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.tline_color_label.setToolTip( + _("Set the travel line color for plotted objects.") + ) + self.tline_color_entry = FCEntry() + self.tline_color_button = QtWidgets.QPushButton() + self.tline_color_button.setFixedSize(15, 15) + + self.form_box_child_2 = QtWidgets.QHBoxLayout() + self.form_box_child_2.addWidget(self.tline_color_entry) + self.form_box_child_2.addWidget(self.tline_color_button) + self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.tline_color_label, 14, 0) + grid0.addLayout(self.form_box_child_2, 14, 1) + + # Plot Fill Color + self.tfill_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.tfill_color_label.setToolTip( + _("Set the fill color for plotted objects.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.tfill_color_entry = FCEntry() + self.tfill_color_button = QtWidgets.QPushButton() + self.tfill_color_button.setFixedSize(15, 15) + + self.form_box_child_1 = QtWidgets.QHBoxLayout() + self.form_box_child_1.addWidget(self.tfill_color_entry) + self.form_box_child_1.addWidget(self.tfill_color_button) + self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.tfill_color_label, 15, 0) + grid0.addLayout(self.form_box_child_1, 15, 1) + + # Plot Fill Transparency Level + self.alpha_label = QtWidgets.QLabel('%s:' % _('Alpha')) + self.alpha_label.setToolTip( + _("Set the fill transparency for plotted objects.") + ) + self.tcolor_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.tcolor_alpha_slider.setMinimum(0) + self.tcolor_alpha_slider.setMaximum(255) + self.tcolor_alpha_slider.setSingleStep(1) + + self.tcolor_alpha_spinner = FCSpinner() + self.tcolor_alpha_spinner.setMinimumWidth(70) + self.tcolor_alpha_spinner.set_range(0, 255) + + self.form_box_child_3 = QtWidgets.QHBoxLayout() + self.form_box_child_3.addWidget(self.tcolor_alpha_slider) + self.form_box_child_3.addWidget(self.tcolor_alpha_spinner) + + grid0.addWidget(self.alpha_label, 16, 0) + grid0.addLayout(self.form_box_child_3, 16, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 17, 0, 1, 2) + + # CNCJob Object Color + self.cnc_color_label = QtWidgets.QLabel('%s' % _('CNCJob Object Color')) + grid0.addWidget(self.cnc_color_label, 18, 0, 1, 2) + + # Plot Line Color + self.line_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.line_color_label.setToolTip( + _("Set the color for plotted objects.") + ) + self.line_color_entry = FCEntry() + self.line_color_button = QtWidgets.QPushButton() + self.line_color_button.setFixedSize(15, 15) + + self.form_box_child_2 = QtWidgets.QHBoxLayout() + self.form_box_child_2.addWidget(self.line_color_entry) + self.form_box_child_2.addWidget(self.line_color_button) + self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.line_color_label, 19, 0) + grid0.addLayout(self.form_box_child_2, 19, 1) + + # Plot Fill Color + self.fill_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.fill_color_label.setToolTip( + _("Set the fill color for plotted objects.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.fill_color_entry = FCEntry() + self.fill_color_button = QtWidgets.QPushButton() + self.fill_color_button.setFixedSize(15, 15) + + self.form_box_child_1 = QtWidgets.QHBoxLayout() + self.form_box_child_1.addWidget(self.fill_color_entry) + self.form_box_child_1.addWidget(self.fill_color_button) + self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.fill_color_label, 20, 0) + grid0.addLayout(self.form_box_child_1, 20, 1) + + self.layout.addStretch() + + # Setting plot colors signals + self.tline_color_entry.editingFinished.connect(self.on_tline_color_entry) + self.tline_color_button.clicked.connect(self.on_tline_color_button) + self.tfill_color_entry.editingFinished.connect(self.on_tfill_color_entry) + self.tfill_color_button.clicked.connect(self.on_tfill_color_button) + self.tcolor_alpha_spinner.valueChanged.connect(self.on_tcolor_spinner) + self.tcolor_alpha_slider.valueChanged.connect(self.on_tcolor_slider) + + self.line_color_entry.editingFinished.connect(self.on_line_color_entry) + self.line_color_button.clicked.connect(self.on_line_color_button) + self.fill_color_entry.editingFinished.connect(self.on_fill_color_entry) + self.fill_color_button.clicked.connect(self.on_fill_color_button) + + # ------------------------------------------------------ + # Setting travel colors handlers + # ------------------------------------------------------ + def on_tfill_color_entry(self): + self.app.defaults['cncjob_travel_fill'] = self.tfill_color_entry.get_value()[:7] + \ + self.app.defaults['cncjob_travel_fill'][7:9] + self.tfill_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['cncjob_travel_fill'])[:7]) + + def on_tfill_color_button(self): + current_color = QtGui.QColor(self.app.defaults['cncjob_travel_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.tfill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['cncjob_travel_fill'][7:9]) + self.tfill_color_entry.set_value(new_val) + self.app.defaults['cncjob_travel_fill'] = new_val + + def on_tcolor_spinner(self): + spinner_value = self.tcolor_alpha_spinner.value() + self.tcolor_alpha_slider.setValue(spinner_value) + self.app.defaults['cncjob_travel_fill'] = \ + self.app.defaults['cncjob_travel_fill'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + self.app.defaults['cncjob_travel_line'] = \ + self.app.defaults['cncjob_travel_line'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + + def on_tcolor_slider(self): + slider_value = self.tcolor_alpha_slider.value() + self.tcolor_alpha_spinner.setValue(slider_value) + + def on_tline_color_entry(self): + self.app.defaults['cncjob_travel_line'] = self.tline_color_entry.get_value()[:7] + \ + self.app.defaults['cncjob_travel_line'][7:9] + self.tline_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['cncjob_travel_line'])[:7]) + + def on_tline_color_button(self): + current_color = QtGui.QColor(self.app.defaults['cncjob_travel_line'][:7]) + # print(current_color) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.tline_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['cncjob_travel_line'][7:9]) + self.tline_color_entry.set_value(new_val_line) + self.app.defaults['cncjob_travel_line'] = new_val_line + + # ------------------------------------------------------ + # Setting plot colors handlers + # ------------------------------------------------------ + def on_fill_color_entry(self): + self.app.defaults['cncjob_plot_fill'] = self.fill_color_entry.get_value()[:7] + \ + self.app.defaults['cncjob_plot_fill'][7:9] + self.fill_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['cncjob_plot_fill'])[:7]) + + def on_fill_color_button(self): + current_color = QtGui.QColor(self.app.defaults['cncjob_plot_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.fill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['cncjob_plot_fill'][7:9]) + self.fill_color_entry.set_value(new_val) + self.app.defaults['cncjob_plot_fill'] = new_val + + def on_line_color_entry(self): + self.app.defaults['cncjob_plot_line'] = self.line_color_entry.get_value()[:7] + \ + self.app.defaults['cncjob_plot_line'][7:9] + self.line_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['cncjob_plot_line'])[:7]) + + def on_line_color_button(self): + current_color = QtGui.QColor(self.app.defaults['cncjob_plot_line'][:7]) + # print(current_color) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['cncjob_plot_line'][7:9]) + self.line_color_entry.set_value(new_val_line) + self.app.defaults['cncjob_plot_line'] = new_val_line diff --git a/flatcamGUI/preferences/cncjob/CNCJobOptPrefGroupUI.py b/flatcamGUI/preferences/cncjob/CNCJobOptPrefGroupUI.py index eefaee28..c8eb7e66 100644 --- a/flatcamGUI/preferences/cncjob/CNCJobOptPrefGroupUI.py +++ b/flatcamGUI/preferences/cncjob/CNCJobOptPrefGroupUI.py @@ -1,39 +1,80 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtGui +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCTextArea +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 CNCJobOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class CNCJobOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "CNC Job Options Preferences", parent=None) + super(CNCJobOptPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("CNC Job Options"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Export G-Code", - label_tooltip="Export and save G-Code to\n" - "make this object to a file." - ), - TextAreaOptionUI( - option="cncjob_prepend", - label_text="Prepend to G-Code", - label_tooltip="Type here any G-Code commands you would\n" - "like to add at the beginning of the G-Code file." - ), - TextAreaOptionUI( - option="cncjob_append", - label_text="Append to G-Code", - label_tooltip="Type here any G-Code commands you would\n" - "like to append to the generated file.\n" - "I.e.: M2 (End of program)" - ) - ] + # ## Export G-Code + self.export_gcode_label = QtWidgets.QLabel("%s:" % _("Export G-Code")) + self.export_gcode_label.setToolTip( + _("Export and save G-Code to\n" + "make this object to a file.") + ) + self.layout.addWidget(self.export_gcode_label) + + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("textbox_font_size"): + tb_fsize = qsettings.value('textbox_font_size', type=int) + else: + tb_fsize = 10 + font = QtGui.QFont() + font.setPointSize(tb_fsize) + + # Prepend to G-Code + prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to G-Code')) + prependlabel.setToolTip( + _("Type here any G-Code commands you would\n" + "like to add at the beginning of the G-Code file.") + ) + self.layout.addWidget(prependlabel) + + self.prepend_text = FCTextArea() + self.prepend_text.setPlaceholderText( + _("Type here any G-Code commands you would " + "like to add at the beginning of the G-Code file.") + ) + self.layout.addWidget(self.prepend_text) + self.prepend_text.setFont(font) + + # Append text to G-Code + appendlabel = QtWidgets.QLabel('%s:' % _('Append to G-Code')) + appendlabel.setToolTip( + _("Type here any G-Code commands you would\n" + "like to append to the generated file.\n" + "I.e.: M2 (End of program)") + ) + self.layout.addWidget(appendlabel) + + self.append_text = FCTextArea() + self.append_text.setPlaceholderText( + _("Type here any G-Code commands you would " + "like to append to the generated file.\n" + "I.e.: M2 (End of program)") + ) + self.layout.addWidget(self.append_text) + self.append_text.setFont(font) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/cncjob/CNCJobPreferencesUI.py b/flatcamGUI/preferences/cncjob/CNCJobPreferencesUI.py index d81134d8..cc9a7e32 100644 --- a/flatcamGUI/preferences/cncjob/CNCJobPreferencesUI.py +++ b/flatcamGUI/preferences/cncjob/CNCJobPreferencesUI.py @@ -1,33 +1,27 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets + from flatcamGUI.preferences.cncjob.CNCJobAdvOptPrefGroupUI import CNCJobAdvOptPrefGroupUI from flatcamGUI.preferences.cncjob.CNCJobOptPrefGroupUI import CNCJobOptPrefGroupUI from flatcamGUI.preferences.cncjob.CNCJobGenPrefGroupUI import CNCJobGenPrefGroupUI -import gettext -import FlatCAMTranslation as fcTranslate -import builtins -fcTranslate.apply_language('strings') -if '_' not in builtins.__dict__: - _ = gettext.gettext +class CNCJobPreferencesUI(QtWidgets.QWidget): -class CNCJobPreferencesUI(PreferencesSectionUI): - - def __init__(self, decimals, **kwargs): + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals - super().__init__(**kwargs) - def build_groups(self) -> [OptionsGroupUI]: - return [ - CNCJobGenPrefGroupUI(decimals=self.decimals), - CNCJobOptPrefGroupUI(decimals=self.decimals), - CNCJobAdvOptPrefGroupUI(decimals=self.decimals) - ] + self.cncjob_gen_group = CNCJobGenPrefGroupUI(decimals=self.decimals) + self.cncjob_gen_group.setMinimumWidth(260) + self.cncjob_opt_group = CNCJobOptPrefGroupUI(decimals=self.decimals) + self.cncjob_opt_group.setMinimumWidth(260) + self.cncjob_adv_opt_group = CNCJobAdvOptPrefGroupUI(decimals=self.decimals) + self.cncjob_adv_opt_group.setMinimumWidth(260) - def get_tab_id(self): - # FIXME this doesn't seem right - return "text_editor_tab" + self.layout.addWidget(self.cncjob_gen_group) + self.layout.addWidget(self.cncjob_opt_group) + self.layout.addWidget(self.cncjob_adv_opt_group) - def get_tab_label(self): - return _("CNC-JOB") \ No newline at end of file + self.layout.addStretch() diff --git a/flatcamGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py b/flatcamGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py index 321fc21b..a63998f9 100644 --- a/flatcamGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py @@ -1,97 +1,155 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings +from flatcamGUI.GUIElements import FCDoubleSpinner, FCEntry, FloatEntry, RadioSet, FCCheckBox +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 ExcellonAdvOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class ExcellonAdvOptPrefGroupUI(OptionsGroupUI): + + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Excellon Advanced Options", parent=parent) + super(ExcellonAdvOptPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Excellon Adv. Options"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Advanced Options", - label_tooltip="A list of Excellon advanced parameters.\n" - "Those parameters are available only for\n" - "Advanced App. Level." - ), - DoubleSpinnerOptionUI( - option="excellon_offset", - label_text="Offset Z", - label_tooltip="Some drill bits (the larger ones) need to drill deeper\n" - "to create the desired exit hole diameter due of the tip shape.\n" - "The value here can compensate the Cut Z parameter.", - min_value=-999.9999, max_value=999.9999, step=0.1, decimals=self.decimals - ), - LineEntryOptionUI( - option="excellon_toolchangexy", - label_text="Toolchange X,Y", - label_tooltip="Toolchange X,Y position." - ), - FloatEntryOptionUI( - option="excellon_startz", - label_text="Start Z", - label_tooltip="Height of the tool just after start.\n" - "Delete the value if you don't need this feature." - ), - DoubleSpinnerOptionUI( - option="excellon_feedrate_rapid", - label_text="Feedrate Rapids", - label_tooltip="Tool speed while drilling\n" - "(in units per minute).\n" - "This is for the rapid move G00.\n" - "It is useful only for Marlin,\n" - "ignore for any other cases.", - min_value=0.0001, max_value=99999.9999, step=50, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_z_pdepth", - label_text="Probe Z depth", - label_tooltip="The maximum depth that the probe is allowed\n" - "to probe. Negative value, in current units.", - min_value=-99999.9999, max_value=0.0, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_feedrate_probe", - label_text="Feedrate Probe", - label_tooltip="The feedrate used while the probe is probing.", - min_value=0.0001, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - RadioSetOptionUI( - option="excellon_spindledir", - label_text="Spindle direction", - label_tooltip="This sets the direction that the spindle is rotating.\n" - "It can be either:\n" - "- CW = clockwise or\n" - "- CCW = counter clockwise", - choices=[{'label': _('CW'), 'value': 'CW'}, - {'label': _('CCW'), 'value': 'CCW'}] - ), - CheckboxOptionUI( - option="excellon_f_plunge", - label_text="Fast Plunge", - label_tooltip="By checking this, the vertical move from\n" - "Z_Toolchange to Z_move is done with G0,\n" - "meaning the fastest speed available.\n" - "WARNING: the move is done at Toolchange X,Y coords." - ), - CheckboxOptionUI( - option="excellon_f_retract", - label_text="Fast Retract", - label_tooltip="Exit hole strategy.\n" - " - When uncheked, while exiting the drilled hole the drill bit\n" - "will travel slow, with set feedrate (G1), up to zero depth and then\n" - "travel as fast as possible (G0) to the Z Move (travel height).\n" - " - When checked the travel from Z cut (cut depth) to Z_move\n" - "(travel height) is done as fast as possible (G0) in one move." - ) - ] \ No newline at end of file + # ####################### + # ## ADVANCED OPTIONS ### + # ####################### + + self.exc_label = QtWidgets.QLabel('%s:' % _('Advanced Options')) + self.exc_label.setToolTip( + _("A list of Excellon advanced parameters.\n" + "Those parameters are available only for\n" + "Advanced App. Level.") + ) + self.layout.addWidget(self.exc_label) + + grid1 = QtWidgets.QGridLayout() + self.layout.addLayout(grid1) + + # Offset Z + offsetlabel = QtWidgets.QLabel('%s:' % _('Offset Z')) + offsetlabel.setToolTip( + _("Some drill bits (the larger ones) need to drill deeper\n" + "to create the desired exit hole diameter due of the tip shape.\n" + "The value here can compensate the Cut Z parameter.")) + self.offset_entry = FCDoubleSpinner() + self.offset_entry.set_precision(self.decimals) + self.offset_entry.set_range(-999.9999, 999.9999) + + grid1.addWidget(offsetlabel, 0, 0) + grid1.addWidget(self.offset_entry, 0, 1) + + # ToolChange X,Y + toolchange_xy_label = QtWidgets.QLabel('%s:' % _('Toolchange X,Y')) + toolchange_xy_label.setToolTip( + _("Toolchange X,Y position.") + ) + self.toolchangexy_entry = FCEntry() + + grid1.addWidget(toolchange_xy_label, 1, 0) + grid1.addWidget(self.toolchangexy_entry, 1, 1) + + # Start Z + startzlabel = QtWidgets.QLabel('%s:' % _('Start Z')) + startzlabel.setToolTip( + _("Height of the tool just after start.\n" + "Delete the value if you don't need this feature.") + ) + self.estartz_entry = FloatEntry() + + grid1.addWidget(startzlabel, 2, 0) + grid1.addWidget(self.estartz_entry, 2, 1) + + # Feedrate Rapids + fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids')) + fr_rapid_label.setToolTip( + _("Tool speed while drilling\n" + "(in units per minute).\n" + "This is for the rapid move G00.\n" + "It is useful only for Marlin,\n" + "ignore for any other cases.") + ) + self.feedrate_rapid_entry = FCDoubleSpinner() + self.feedrate_rapid_entry.set_precision(self.decimals) + self.feedrate_rapid_entry.set_range(0, 99999.9999) + + grid1.addWidget(fr_rapid_label, 3, 0) + grid1.addWidget(self.feedrate_rapid_entry, 3, 1) + + # Probe depth + self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth")) + self.pdepth_label.setToolTip( + _("The maximum depth that the probe is allowed\n" + "to probe. Negative value, in current units.") + ) + self.pdepth_entry = FCDoubleSpinner() + self.pdepth_entry.set_precision(self.decimals) + self.pdepth_entry.set_range(-99999.9999, 0.0000) + + grid1.addWidget(self.pdepth_label, 4, 0) + grid1.addWidget(self.pdepth_entry, 4, 1) + + # Probe feedrate + self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe")) + self.feedrate_probe_label.setToolTip( + _("The feedrate used while the probe is probing.") + ) + self.feedrate_probe_entry = FCDoubleSpinner() + self.feedrate_probe_entry.set_precision(self.decimals) + self.feedrate_probe_entry.set_range(0, 99999.9999) + + grid1.addWidget(self.feedrate_probe_label, 5, 0) + grid1.addWidget(self.feedrate_probe_entry, 5, 1) + + # Spindle direction + spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle direction')) + spindle_dir_label.setToolTip( + _("This sets the direction that the spindle is rotating.\n" + "It can be either:\n" + "- CW = clockwise or\n" + "- CCW = counter clockwise") + ) + + self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + grid1.addWidget(spindle_dir_label, 6, 0) + grid1.addWidget(self.spindledir_radio, 6, 1) + + self.fplunge_cb = FCCheckBox('%s' % _('Fast Plunge')) + self.fplunge_cb.setToolTip( + _("By checking this, the vertical move from\n" + "Z_Toolchange to Z_move is done with G0,\n" + "meaning the fastest speed available.\n" + "WARNING: the move is done at Toolchange X,Y coords.") + ) + grid1.addWidget(self.fplunge_cb, 7, 0, 1, 2) + + self.fretract_cb = FCCheckBox('%s' % _('Fast Retract')) + self.fretract_cb.setToolTip( + _("Exit hole strategy.\n" + " - When uncheked, while exiting the drilled hole the drill bit\n" + "will travel slow, with set feedrate (G1), up to zero depth and then\n" + "travel as fast as possible (G0) to the Z Move (travel height).\n" + " - When checked the travel from Z cut (cut depth) to Z_move\n" + "(travel height) is done as fast as possible (G0) in one move.") + ) + + grid1.addWidget(self.fretract_cb, 8, 0, 1, 2) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/excellon/ExcellonEditorPrefGroupUI.py b/flatcamGUI/preferences/excellon/ExcellonEditorPrefGroupUI.py index 162cdf8a..5b04cf2f 100644 --- a/flatcamGUI/preferences/excellon/ExcellonEditorPrefGroupUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonEditorPrefGroupUI.py @@ -1,173 +1,306 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 ExcellonEditorPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class ExcellonEditorPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + super(ExcellonEditorPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Excellon Editor"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Parameters", - label_tooltip="A list of Excellon Editor parameters." - ), - SpinnerOptionUI( - option="excellon_editor_sel_limit", - label_text="Selection limit", - label_tooltip="Set the number of selected Excellon geometry\n" - "items above which the utility geometry\n" - "becomes just a selection rectangle.\n" - "Increases the performance when moving a\n" - "large number of geometric elements.", - min_value=0, max_value=99999, step=1 - ), - DoubleSpinnerOptionUI( - option="excellon_editor_newdia", - label_text="New Dia", - label_tooltip="Diameter for the new tool", - min_value=0.000001, max_value=99.9999, step=0.1, decimals=self.decimals - ), - SpinnerOptionUI( - option="excellon_editor_array_size", - label_text="Nr of drills", - label_tooltip="Specify how many drills to be in the array.", - min_value=0, max_value=9999, step=1 - ), + # Excellon Editor Parameters + self.param_label = QtWidgets.QLabel("%s:" % _("Parameters")) + self.param_label.setToolTip( + _("A list of Excellon Editor parameters.") + ) + self.layout.addWidget(self.param_label) - HeadingOptionUI(label_text="Linear Drill Array"), - RadioSetOptionUI( - option="excellon_editor_lin_dir", - label_text="Linear Direction", - label_tooltip="Direction on which the linear array is oriented:\n" - "- 'X' - horizontal axis \n" - "- 'Y' - vertical axis or \n" - "- 'Angle' - a custom angle for the array inclination", - choices=[ - {'label': _('X'), 'value': 'X'}, - {'label': _('Y'), 'value': 'Y'}, - {'label': _('Angle'), 'value': 'A'} - ] - ), - DoubleSpinnerOptionUI( - option="excellon_editor_lin_pitch", - label_text="Pitch", - label_tooltip="Pitch = Distance between elements of the array.", - min_value=0, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_editor_lin_angle", - label_text="Angle", - label_tooltip="Angle at which each element in circular array is placed.", # FIXME tooltip seems wrong ? - min_value=-360, max_value=360, step=5, decimals=self.decimals - ), + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) - HeadingOptionUI(label_text="Circular Drill Array"), - RadioSetOptionUI( - option="excellon_editor_circ_dir", - label_text="Circular Direction", - label_tooltip="Direction for circular array.\n" - "Can be CW = clockwise or CCW = counter clockwise.", - choices=[ - {'label': _('CW'), 'value': 'CW'}, - {'label': _('CCW'), 'value': 'CCW'} - ] - ), - DoubleSpinnerOptionUI( - option="excellon_editor_circ_angle", - label_text="Angle", - label_tooltip="Angle at which each element in circular array is placed.", - min_value=-360, max_value=360, step=5, decimals=self.decimals - ), + # Selection Limit + self.sel_limit_label = QtWidgets.QLabel('%s:' % _("Selection limit")) + self.sel_limit_label.setToolTip( + _("Set the number of selected Excellon geometry\n" + "items above which the utility geometry\n" + "becomes just a selection rectangle.\n" + "Increases the performance when moving a\n" + "large number of geometric elements.") + ) + self.sel_limit_entry = FCSpinner() + self.sel_limit_entry.set_range(0, 99999) - HeadingOptionUI(label_text="Slots"), - DoubleSpinnerOptionUI( - option="excellon_editor_slot_length", - label_text="Length", - label_tooltip="Length = The length of the slot.", - min_value=0, max_value=99999, step=1, decimals=self.decimals - ), - RadioSetOptionUI( - option="excellon_editor_slot_direction", - label_text="Direction", - label_tooltip="Direction on which the slot is oriented:\n" - "- 'X' - horizontal axis \n" - "- 'Y' - vertical axis or \n" - "- 'Angle' - a custom angle for the slot inclination", - choices=[ - {'label': _('X'), 'value': 'X'}, - {'label': _('Y'), 'value': 'Y'}, - {'label': _('Angle'), 'value': 'A'} - ] - ), - DoubleSpinnerOptionUI( - option="excellon_editor_slot_angle", - label_text="Angle", - label_tooltip="Angle at which the slot is placed.\n" - "The precision is of max 2 decimals.\n" - "Min value is: -359.99 degrees.\n" - "Max value is: 360.00 degrees.", - min_value=-359.99, max_value=360.00, step=5, decimals=self.decimals - ), + grid0.addWidget(self.sel_limit_label, 0, 0) + grid0.addWidget(self.sel_limit_entry, 0, 1) - HeadingOptionUI(label_text="Linear Slot Array"), - SpinnerOptionUI( - option="excellon_editor_slot_array_size", - label_text="Nr of slots", - label_tooltip="Specify how many slots to be in the array.", - min_value=0, max_value=999999, step=1 - ), - RadioSetOptionUI( - option="excellon_editor_slot_lin_dir", - label_text="Linear Direction", - label_tooltip="Direction on which the linear array is oriented:\n" - "- 'X' - horizontal axis \n" - "- 'Y' - vertical axis or \n" - "- 'Angle' - a custom angle for the array inclination", - choices=[ - {'label': _('X'), 'value': 'X'}, - {'label': _('Y'), 'value': 'Y'}, - {'label': _('Angle'), 'value': 'A'} - ] - ), - DoubleSpinnerOptionUI( - option="excellon_editor_slot_lin_pitch", - label_text="Pitch", - label_tooltip="Pitch = Distance between elements of the array.", - min_value=0, max_value=999999, step=1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_editor_slot_lin_angle", - label_text="Angle", - label_tooltip="Angle at which each element in circular array is placed.", # FIXME - min_value=-360, max_value=360, step=5, decimals=self.decimals - ), + # New Diameter + self.addtool_entry_lbl = QtWidgets.QLabel('%s:' % _('New Dia')) + self.addtool_entry_lbl.setToolTip( + _("Diameter for the new tool") + ) - HeadingOptionUI(label_text="Circular Slot Array"), - RadioSetOptionUI( - option="excellon_editor_slot_circ_dir", - label_text="Circular Direction", - label_tooltip="Direction for circular array.\n" - "Can be CW = clockwise or CCW = counter clockwise.", - choices=[{'label': _('CW'), 'value': 'CW'}, - {'label': _('CCW'), 'value': 'CCW'}] - ), - DoubleSpinnerOptionUI( - option="excellon_editor_slot_circ_angle", - label_text="Circular Angle", - label_tooltip="Angle at which each element in circular array is placed.", - min_value=-360, max_value=360, step=5, decimals=self.decimals - ) + self.addtool_entry = FCDoubleSpinner() + self.addtool_entry.set_range(0.000001, 99.9999) + self.addtool_entry.set_precision(self.decimals) - ] + grid0.addWidget(self.addtool_entry_lbl, 1, 0) + grid0.addWidget(self.addtool_entry, 1, 1) + # Number of drill holes in a drill array + self.drill_array_size_label = QtWidgets.QLabel('%s:' % _('Nr of drills')) + self.drill_array_size_label.setToolTip( + _("Specify how many drills to be in the array.") + ) + # self.drill_array_size_label.setMinimumWidth(100) + + self.drill_array_size_entry = FCSpinner() + self.drill_array_size_entry.set_range(0, 9999) + + grid0.addWidget(self.drill_array_size_label, 2, 0) + grid0.addWidget(self.drill_array_size_entry, 2, 1) + + self.drill_array_linear_label = QtWidgets.QLabel('%s:' % _('Linear Drill Array')) + grid0.addWidget(self.drill_array_linear_label, 3, 0, 1, 2) + + # Linear Drill Array direction + self.drill_axis_label = QtWidgets.QLabel('%s:' % _('Linear Direction')) + self.drill_axis_label.setToolTip( + _("Direction on which the linear array is oriented:\n" + "- 'X' - horizontal axis \n" + "- 'Y' - vertical axis or \n" + "- 'Angle' - a custom angle for the array inclination") + ) + # self.drill_axis_label.setMinimumWidth(100) + self.drill_axis_radio = RadioSet([{'label': _('X'), 'value': 'X'}, + {'label': _('Y'), 'value': 'Y'}, + {'label': _('Angle'), 'value': 'A'}]) + + grid0.addWidget(self.drill_axis_label, 4, 0) + grid0.addWidget(self.drill_axis_radio, 4, 1) + + # Linear Drill Array pitch distance + self.drill_pitch_label = QtWidgets.QLabel('%s:' % _('Pitch')) + self.drill_pitch_label.setToolTip( + _("Pitch = Distance between elements of the array.") + ) + # self.drill_pitch_label.setMinimumWidth(100) + self.drill_pitch_entry = FCDoubleSpinner() + self.drill_pitch_entry.set_range(0, 99999.9999) + self.drill_pitch_entry.set_precision(self.decimals) + + grid0.addWidget(self.drill_pitch_label, 5, 0) + grid0.addWidget(self.drill_pitch_entry, 5, 1) + + # Linear Drill Array custom angle + self.drill_angle_label = QtWidgets.QLabel('%s:' % _('Angle')) + self.drill_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.drill_angle_entry = FCDoubleSpinner() + self.drill_pitch_entry.set_range(-360, 360) + self.drill_pitch_entry.set_precision(self.decimals) + self.drill_angle_entry.setWrapping(True) + self.drill_angle_entry.setSingleStep(5) + + grid0.addWidget(self.drill_angle_label, 6, 0) + grid0.addWidget(self.drill_angle_entry, 6, 1) + + self.drill_array_circ_label = QtWidgets.QLabel('%s:' % _('Circular Drill Array')) + grid0.addWidget(self.drill_array_circ_label, 7, 0, 1, 2) + + # Circular Drill Array direction + self.drill_circular_direction_label = QtWidgets.QLabel('%s:' % _('Circular Direction')) + self.drill_circular_direction_label.setToolTip( + _("Direction for circular array.\n" + "Can be CW = clockwise or CCW = counter clockwise.") + ) + + self.drill_circular_dir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + + grid0.addWidget(self.drill_circular_direction_label, 8, 0) + grid0.addWidget(self.drill_circular_dir_radio, 8, 1) + + # Circular Drill Array Angle + self.drill_circular_angle_label = QtWidgets.QLabel('%s:' % _('Circular Angle')) + self.drill_circular_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.drill_circular_angle_entry = FCDoubleSpinner() + self.drill_circular_angle_entry.set_range(-360, 360) + self.drill_circular_angle_entry.set_precision(self.decimals) + self.drill_circular_angle_entry.setWrapping(True) + self.drill_circular_angle_entry.setSingleStep(5) + + grid0.addWidget(self.drill_circular_angle_label, 9, 0) + grid0.addWidget(self.drill_circular_angle_entry, 9, 1) + + # ##### SLOTS ##### + # ################# + self.drill_array_circ_label = QtWidgets.QLabel('%s:' % _('Slots')) + grid0.addWidget(self.drill_array_circ_label, 10, 0, 1, 2) + + # Slot length + self.slot_length_label = QtWidgets.QLabel('%s:' % _('Length')) + self.slot_length_label.setToolTip( + _("Length = The length of the slot.") + ) + self.slot_length_label.setMinimumWidth(100) + + self.slot_length_entry = FCDoubleSpinner() + self.slot_length_entry.set_range(0, 99999) + self.slot_length_entry.set_precision(self.decimals) + self.slot_length_entry.setWrapping(True) + self.slot_length_entry.setSingleStep(1) + + grid0.addWidget(self.slot_length_label, 11, 0) + grid0.addWidget(self.slot_length_entry, 11, 1) + + # Slot direction + self.slot_axis_label = QtWidgets.QLabel('%s:' % _('Direction')) + self.slot_axis_label.setToolTip( + _("Direction on which the slot is oriented:\n" + "- 'X' - horizontal axis \n" + "- 'Y' - vertical axis or \n" + "- 'Angle' - a custom angle for the slot inclination") + ) + self.slot_axis_label.setMinimumWidth(100) + + self.slot_axis_radio = RadioSet([{'label': _('X'), 'value': 'X'}, + {'label': _('Y'), 'value': 'Y'}, + {'label': _('Angle'), 'value': 'A'}]) + grid0.addWidget(self.slot_axis_label, 12, 0) + grid0.addWidget(self.slot_axis_radio, 12, 1) + + # Slot custom angle + self.slot_angle_label = QtWidgets.QLabel('%s:' % _('Angle')) + self.slot_angle_label.setToolTip( + _("Angle at which the slot is placed.\n" + "The precision is of max 2 decimals.\n" + "Min value is: -359.99 degrees.\n" + "Max value is: 360.00 degrees.") + ) + self.slot_angle_label.setMinimumWidth(100) + + self.slot_angle_spinner = FCDoubleSpinner() + self.slot_angle_spinner.set_precision(self.decimals) + self.slot_angle_spinner.setWrapping(True) + self.slot_angle_spinner.setRange(-359.99, 360.00) + self.slot_angle_spinner.setSingleStep(5) + + grid0.addWidget(self.slot_angle_label, 13, 0) + grid0.addWidget(self.slot_angle_spinner, 13, 1) + + # #### SLOTS ARRAY ####### + # ######################## + + self.slot_array_linear_label = QtWidgets.QLabel('%s:' % _('Linear Slot Array')) + grid0.addWidget(self.slot_array_linear_label, 14, 0, 1, 2) + + # Number of slot holes in a drill array + self.slot_array_size_label = QtWidgets.QLabel('%s:' % _('Nr of slots')) + self.drill_array_size_label.setToolTip( + _("Specify how many slots to be in the array.") + ) + # self.slot_array_size_label.setMinimumWidth(100) + + self.slot_array_size_entry = FCSpinner() + self.slot_array_size_entry.set_range(0, 999999) + + grid0.addWidget(self.slot_array_size_label, 15, 0) + grid0.addWidget(self.slot_array_size_entry, 15, 1) + + # Linear Slot Array direction + self.slot_array_axis_label = QtWidgets.QLabel('%s:' % _('Linear Direction')) + self.slot_array_axis_label.setToolTip( + _("Direction on which the linear array is oriented:\n" + "- 'X' - horizontal axis \n" + "- 'Y' - vertical axis or \n" + "- 'Angle' - a custom angle for the array inclination") + ) + # self.slot_axis_label.setMinimumWidth(100) + self.slot_array_axis_radio = RadioSet([{'label': _('X'), 'value': 'X'}, + {'label': _('Y'), 'value': 'Y'}, + {'label': _('Angle'), 'value': 'A'}]) + + grid0.addWidget(self.slot_array_axis_label, 16, 0) + grid0.addWidget(self.slot_array_axis_radio, 16, 1) + + # Linear Slot Array pitch distance + self.slot_array_pitch_label = QtWidgets.QLabel('%s:' % _('Pitch')) + self.slot_array_pitch_label.setToolTip( + _("Pitch = Distance between elements of the array.") + ) + # self.drill_pitch_label.setMinimumWidth(100) + self.slot_array_pitch_entry = FCDoubleSpinner() + self.slot_array_pitch_entry.set_precision(self.decimals) + self.slot_array_pitch_entry.setWrapping(True) + self.slot_array_pitch_entry.setRange(0, 999999) + self.slot_array_pitch_entry.setSingleStep(1) + + grid0.addWidget(self.slot_array_pitch_label, 17, 0) + grid0.addWidget(self.slot_array_pitch_entry, 17, 1) + + # Linear Slot Array custom angle + self.slot_array_angle_label = QtWidgets.QLabel('%s:' % _('Angle')) + self.slot_array_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.slot_array_angle_entry = FCDoubleSpinner() + self.slot_array_angle_entry.set_precision(self.decimals) + self.slot_array_angle_entry.setWrapping(True) + self.slot_array_angle_entry.setRange(-360, 360) + self.slot_array_angle_entry.setSingleStep(5) + + grid0.addWidget(self.slot_array_angle_label, 18, 0) + grid0.addWidget(self.slot_array_angle_entry, 18, 1) + + self.slot_array_circ_label = QtWidgets.QLabel('%s:' % _('Circular Slot Array')) + grid0.addWidget(self.slot_array_circ_label, 19, 0, 1, 2) + + # Circular Slot Array direction + self.slot_array_circular_direction_label = QtWidgets.QLabel('%s:' % _('Circular Direction')) + self.slot_array_circular_direction_label.setToolTip( + _("Direction for circular array.\n" + "Can be CW = clockwise or CCW = counter clockwise.") + ) + + self.slot_array_circular_dir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + + grid0.addWidget(self.slot_array_circular_direction_label, 20, 0) + grid0.addWidget(self.slot_array_circular_dir_radio, 20, 1) + + # Circular Slot Array Angle + self.slot_array_circular_angle_label = QtWidgets.QLabel('%s:' % _('Circular Angle')) + self.slot_array_circular_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.slot_array_circular_angle_entry = FCDoubleSpinner() + self.slot_array_circular_angle_entry.set_precision(self.decimals) + self.slot_array_circular_angle_entry.setWrapping(True) + self.slot_array_circular_angle_entry.setRange(-360, 360) + self.slot_array_circular_angle_entry.setSingleStep(5) + + grid0.addWidget(self.slot_array_circular_angle_label, 21, 0) + grid0.addWidget(self.slot_array_circular_angle_entry, 21, 1) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/excellon/ExcellonExpPrefGroupUI.py b/flatcamGUI/preferences/excellon/ExcellonExpPrefGroupUI.py index 52905e30..db2e922a 100644 --- a/flatcamGUI/preferences/excellon/ExcellonExpPrefGroupUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonExpPrefGroupUI.py @@ -1,86 +1,168 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore +from PyQt5.QtCore import QSettings +from flatcamGUI.GUIElements import RadioSet, FCSpinner +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 ExcellonExpPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class ExcellonExpPrefGroupUI(OptionsGroupUI): + + def __init__(self, decimals=4, parent=None): + super(ExcellonExpPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Excellon Export"))) + self.decimals = decimals - self.option_dict()["excellon_exp_format"].get_field().activated_custom.connect(self.optimization_selection) + # Plot options + self.export_options_label = QtWidgets.QLabel("%s:" % _("Export Options")) + self.export_options_label.setToolTip( + _("The parameters set here are used in the file exported\n" + "when using the File -> Export -> Export Excellon menu entry.") + ) + self.layout.addWidget(self.export_options_label) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Export Options", - label_tooltip="The parameters set here are used in the file exported\n" - "when using the File -> Export -> Export Excellon menu entry." - ), - RadioSetOptionUI( - option="excellon_exp_units", - label_text="Units", - label_tooltip="The units used in the Excellon file.", - choices=[{'label': _('INCH'), 'value': 'INCH'}, - {'label': _('MM'), 'value': 'METRIC'}] - ), - SpinnerOptionUI( - option="excellon_exp_integer", - label_text="Int", - label_tooltip="This number signifies the number of digits in\nthe whole part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="excellon_exp_decimals", - label_text="Decimals", - label_tooltip="This number signifies the number of digits in\nthe decimal part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - RadioSetOptionUI( - option="excellon_exp_format", - label_text="Format", - label_tooltip="Select the kind of coordinates format used.\n" - "Coordinates can be saved with decimal point or without.\n" - "When there is no decimal point, it is required to specify\n" - "the number of digits for integer part and the number of decimals.\n" - "Also it will have to be specified if LZ = leading zeros are kept\n" - "or TZ = trailing zeros are kept.", - choices=[{'label': _('Decimal'), 'value': 'dec'}, - {'label': _('No-Decimal'), 'value': 'ndec'}] - ), - RadioSetOptionUI( - option="excellon_exp_zeros", - label_text="Zeros", - label_tooltip="This sets the type of Excellon zeros.\n" - "If LZ then Leading Zeros are kept and\n" - "Trailing Zeros are removed.\n" - "If TZ is checked then Trailing Zeros are kept\n" - "and Leading Zeros are removed.", - choices=[{'label': _('LZ'), 'value': 'LZ'}, - {'label': _('TZ'), 'value': 'TZ'}] - ), - RadioSetOptionUI( - option="excellon_exp_slot_type", - label_text="Slot type", - label_tooltip="This sets how the slots will be exported.\n" - "If ROUTED then the slots will be routed\n" - "using M15/M16 commands.\n" - "If DRILLED(G85) the slots will be exported\n" - "using the Drilled slot command (G85).", - choices=[{'label': _('Routed'), 'value': 'routing'}, - {'label': _('Drilled(G85)'), 'value': 'drilling'}] - ) - ] + form = QtWidgets.QFormLayout() + self.layout.addLayout(form) + + # Excellon Units + self.excellon_units_label = QtWidgets.QLabel('%s:' % _('Units')) + self.excellon_units_label.setToolTip( + _("The units used in the Excellon file.") + ) + + self.excellon_units_radio = RadioSet([{'label': _('INCH'), 'value': 'INCH'}, + {'label': _('MM'), 'value': 'METRIC'}]) + self.excellon_units_radio.setToolTip( + _("The units used in the Excellon file.") + ) + + form.addRow(self.excellon_units_label, self.excellon_units_radio) + + # Excellon non-decimal format + self.digits_label = QtWidgets.QLabel("%s:" % _("Int/Decimals")) + self.digits_label.setToolTip( + _("The NC drill files, usually named Excellon files\n" + "are files that can be found in different formats.\n" + "Here we set the format used when the provided\n" + "coordinates are not using period.") + ) + + hlay1 = QtWidgets.QHBoxLayout() + + self.format_whole_entry = FCSpinner() + self.format_whole_entry.set_range(0, 9) + self.format_whole_entry.setMinimumWidth(30) + self.format_whole_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the whole part of Excellon coordinates.") + ) + hlay1.addWidget(self.format_whole_entry, QtCore.Qt.AlignLeft) + + excellon_separator_label = QtWidgets.QLabel(':') + excellon_separator_label.setFixedWidth(5) + hlay1.addWidget(excellon_separator_label, QtCore.Qt.AlignLeft) + + self.format_dec_entry = FCSpinner() + self.format_dec_entry.set_range(0, 9) + self.format_dec_entry.setMinimumWidth(30) + self.format_dec_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the decimal part of Excellon coordinates.") + ) + hlay1.addWidget(self.format_dec_entry, QtCore.Qt.AlignLeft) + hlay1.addStretch() + + form.addRow(self.digits_label, hlay1) + + # Select the Excellon Format + self.format_label = QtWidgets.QLabel("%s:" % _("Format")) + self.format_label.setToolTip( + _("Select the kind of coordinates format used.\n" + "Coordinates can be saved with decimal point or without.\n" + "When there is no decimal point, it is required to specify\n" + "the number of digits for integer part and the number of decimals.\n" + "Also it will have to be specified if LZ = leading zeros are kept\n" + "or TZ = trailing zeros are kept.") + ) + self.format_radio = RadioSet([{'label': _('Decimal'), 'value': 'dec'}, + {'label': _('No-Decimal'), 'value': 'ndec'}]) + self.format_radio.setToolTip( + _("Select the kind of coordinates format used.\n" + "Coordinates can be saved with decimal point or without.\n" + "When there is no decimal point, it is required to specify\n" + "the number of digits for integer part and the number of decimals.\n" + "Also it will have to be specified if LZ = leading zeros are kept\n" + "or TZ = trailing zeros are kept.") + ) + + form.addRow(self.format_label, self.format_radio) + + # Excellon Zeros + self.zeros_label = QtWidgets.QLabel('%s:' % _('Zeros')) + self.zeros_label.setAlignment(QtCore.Qt.AlignLeft) + self.zeros_label.setToolTip( + _("This sets the type of Excellon zeros.\n" + "If LZ then Leading Zeros are kept and\n" + "Trailing Zeros are removed.\n" + "If TZ is checked then Trailing Zeros are kept\n" + "and Leading Zeros are removed.") + ) + + self.zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'LZ'}, + {'label': _('TZ'), 'value': 'TZ'}]) + self.zeros_radio.setToolTip( + _("This sets the default type of Excellon zeros.\n" + "If LZ then Leading Zeros are kept and\n" + "Trailing Zeros are removed.\n" + "If TZ is checked then Trailing Zeros are kept\n" + "and Leading Zeros are removed.") + ) + + form.addRow(self.zeros_label, self.zeros_radio) + + # Slot type + self.slot_type_label = QtWidgets.QLabel('%s:' % _('Slot type')) + self.slot_type_label.setAlignment(QtCore.Qt.AlignLeft) + self.slot_type_label.setToolTip( + _("This sets how the slots will be exported.\n" + "If ROUTED then the slots will be routed\n" + "using M15/M16 commands.\n" + "If DRILLED(G85) the slots will be exported\n" + "using the Drilled slot command (G85).") + ) + + self.slot_type_radio = RadioSet([{'label': _('Routed'), 'value': 'routing'}, + {'label': _('Drilled(G85)'), 'value': 'drilling'}]) + self.slot_type_radio.setToolTip( + _("This sets how the slots will be exported.\n" + "If ROUTED then the slots will be routed\n" + "using M15/M16 commands.\n" + "If DRILLED(G85) the slots will be exported\n" + "using the Drilled slot command (G85).") + ) + + form.addRow(self.slot_type_label, self.slot_type_radio) + + self.layout.addStretch() + self.format_radio.activated_custom.connect(self.optimization_selection) def optimization_selection(self): - disable_zeros = self.option_dict()["excellon_exp_format"].get_field().get_value() == "dec" - self.option_dict()["excellon_exp_zeros"].label_widget.setDisabled(disable_zeros) - self.option_dict()["excellon_exp_zeros"].get_field().setDisabled(disable_zeros) + if self.format_radio.get_value() == 'dec': + self.zeros_label.setDisabled(True) + self.zeros_radio.setDisabled(True) + else: + self.zeros_label.setDisabled(False) + self.zeros_radio.setDisabled(False) diff --git a/flatcamGUI/preferences/excellon/ExcellonGenPrefGroupUI.py b/flatcamGUI/preferences/excellon/ExcellonGenPrefGroupUI.py index 91b3dcde..06d4dfc7 100644 --- a/flatcamGUI/preferences/excellon/ExcellonGenPrefGroupUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonGenPrefGroupUI.py @@ -1,199 +1,415 @@ import platform -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCCheckBox, FCSpinner, RadioSet, FCEntry +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 ExcellonGenPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class ExcellonGenPrefGroupUI(OptionsGroupUI): + + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Excellon Options", parent=parent) + super(ExcellonGenPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Excellon General"))) + self.decimals = decimals - # disable the Excellon path optimizations made with Google OR-Tools if the app is run on a 32bit platform - if platform.architecture()[0] != '64bit': - self.option_dict()["excellon_optimization_type"].get_field().set_value('T') - self.option_dict()["excellon_optimization_type"].get_field().setDisabled(True) - self.option_dict()["excellon_optimization_type"].label_widget.setDisabled(True) + # Plot options + self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options")) + self.layout.addWidget(self.plot_options_label) - # Enable/disable the duration box according to type selected - self.option_dict()["excellon_optimization_type"].get_field().activated_custom.connect(self.optimization_selection) - self.optimization_selection() + grid1 = QtWidgets.QGridLayout() + self.layout.addLayout(grid1) + + self.plot_cb = FCCheckBox(label=_('Plot')) + self.plot_cb.setToolTip( + "Plot (show) this object." + ) + grid1.addWidget(self.plot_cb, 0, 0) + + self.solid_cb = FCCheckBox(label=_('Solid')) + self.solid_cb.setToolTip( + "Plot as solid circles." + ) + grid1.addWidget(self.solid_cb, 0, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid1.addWidget(separator_line, 1, 0, 1, 2) + + grid2 = QtWidgets.QGridLayout() + self.layout.addLayout(grid2) + grid2.setColumnStretch(0, 0) + grid2.setColumnStretch(1, 1) + + # Excellon format + self.excellon_format_label = QtWidgets.QLabel("%s:" % _("Excellon Format")) + self.excellon_format_label.setToolTip( + _("The NC drill files, usually named Excellon files\n" + "are files that can be found in different formats.\n" + "Here we set the format used when the provided\n" + "coordinates are not using period.\n" + "\n" + "Possible presets:\n" + "\n" + "PROTEUS 3:3 MM LZ\n" + "DipTrace 5:2 MM TZ\n" + "DipTrace 4:3 MM LZ\n" + "\n" + "EAGLE 3:3 MM TZ\n" + "EAGLE 4:3 MM TZ\n" + "EAGLE 2:5 INCH TZ\n" + "EAGLE 3:5 INCH TZ\n" + "\n" + "ALTIUM 2:4 INCH LZ\n" + "Sprint Layout 2:4 INCH LZ" + "\n" + "KiCAD 3:5 INCH TZ") + ) + grid2.addWidget(self.excellon_format_label, 0, 0, 1, 2) + + self.excellon_format_in_label = QtWidgets.QLabel('%s:' % _("INCH")) + self.excellon_format_in_label.setToolTip(_("Default values for INCH are 2:4")) + + hlay1 = QtWidgets.QHBoxLayout() + self.excellon_format_upper_in_entry = FCSpinner() + self.excellon_format_upper_in_entry.set_range(0, 9) + self.excellon_format_upper_in_entry.setMinimumWidth(30) + self.excellon_format_upper_in_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the whole part of Excellon coordinates.") + ) + hlay1.addWidget(self.excellon_format_upper_in_entry) + + excellon_separator_in_label = QtWidgets.QLabel(':') + excellon_separator_in_label.setFixedWidth(5) + hlay1.addWidget(excellon_separator_in_label) + + self.excellon_format_lower_in_entry = FCSpinner() + self.excellon_format_lower_in_entry.set_range(0, 9) + self.excellon_format_lower_in_entry.setMinimumWidth(30) + self.excellon_format_lower_in_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the decimal part of Excellon coordinates.") + ) + hlay1.addWidget(self.excellon_format_lower_in_entry) + + grid2.addWidget(self.excellon_format_in_label, 1, 0) + grid2.addLayout(hlay1, 1, 1) + + self.excellon_format_mm_label = QtWidgets.QLabel('%s:' % _("METRIC")) + self.excellon_format_mm_label.setToolTip(_("Default values for METRIC are 3:3")) + + hlay2 = QtWidgets.QHBoxLayout() + self.excellon_format_upper_mm_entry = FCSpinner() + self.excellon_format_upper_mm_entry.set_range(0, 9) + self.excellon_format_upper_mm_entry.setMinimumWidth(30) + self.excellon_format_upper_mm_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the whole part of Excellon coordinates.") + ) + hlay2.addWidget(self.excellon_format_upper_mm_entry) + + excellon_separator_mm_label = QtWidgets.QLabel(':') + excellon_separator_mm_label.setFixedWidth(5) + hlay2.addWidget(excellon_separator_mm_label, QtCore.Qt.AlignLeft) + + self.excellon_format_lower_mm_entry = FCSpinner() + self.excellon_format_lower_mm_entry.set_range(0, 9) + self.excellon_format_lower_mm_entry.setMinimumWidth(30) + self.excellon_format_lower_mm_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the decimal part of Excellon coordinates.") + ) + hlay2.addWidget(self.excellon_format_lower_mm_entry) + + grid2.addWidget(self.excellon_format_mm_label, 2, 0) + grid2.addLayout(hlay2, 2, 1) + + self.excellon_zeros_label = QtWidgets.QLabel('%s:' % _('Zeros')) + self.excellon_zeros_label.setAlignment(QtCore.Qt.AlignLeft) + self.excellon_zeros_label.setToolTip( + _("This sets the type of Excellon zeros.\n" + "If LZ then Leading Zeros are kept and\n" + "Trailing Zeros are removed.\n" + "If TZ is checked then Trailing Zeros are kept\n" + "and Leading Zeros are removed.\n\n" + "This is used when there is no information\n" + "stored in the Excellon file.") + ) + grid2.addWidget(self.excellon_zeros_label, 3, 0) + + self.excellon_zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'L'}, + {'label': _('TZ'), 'value': 'T'}]) + + grid2.addWidget(self.excellon_zeros_radio, 3, 1) + + self.excellon_units_label = QtWidgets.QLabel('%s:' % _('Units')) + self.excellon_units_label.setAlignment(QtCore.Qt.AlignLeft) + self.excellon_units_label.setToolTip( + _("This sets the default units of Excellon files.\n" + "If it is not detected in the parsed file the value here\n" + "will be used." + "Some Excellon files don't have an header\n" + "therefore this parameter will be used.") + ) + + self.excellon_units_radio = RadioSet([{'label': _('INCH'), 'value': 'INCH'}, + {'label': _('MM'), 'value': 'METRIC'}]) + self.excellon_units_radio.setToolTip( + _("This sets the units of Excellon files.\n" + "Some Excellon files don't have an header\n" + "therefore this parameter will be used.") + ) + + grid2.addWidget(self.excellon_units_label, 4, 0) + grid2.addWidget(self.excellon_units_radio, 4, 1) + + self.update_excellon_cb = FCCheckBox(label=_('Update Export settings')) + self.update_excellon_cb.setToolTip( + "If checked, the Excellon Export settings will be updated with the ones above." + ) + grid2.addWidget(self.update_excellon_cb, 5, 0, 1, 2) + + # Adding the Excellon Format Defaults Button + self.excellon_defaults_button = QtWidgets.QPushButton() + self.excellon_defaults_button.setText(str(_("Restore Defaults"))) + self.excellon_defaults_button.setMinimumWidth(80) + grid2.addWidget(self.excellon_defaults_button, 6, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid2.addWidget(separator_line, 7, 0, 1, 2) + + self.excellon_general_label = QtWidgets.QLabel("%s:" % _("Excellon Optimization")) + grid2.addWidget(self.excellon_general_label, 8, 0, 1, 2) + + self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm:')) + self.excellon_optimization_label.setToolTip( + _("This sets the optimization type for the Excellon drill path.\n" + "If <> is checked then Google OR-Tools algorithm with\n" + "MetaHeuristic Guided Local Path is used. Default search time is 3sec.\n" + "If <> is checked then Google OR-Tools Basic algorithm is used.\n" + "If <> is checked then Travelling Salesman algorithm is used for\n" + "drill path optimization.\n" + "\n" + "If this control is disabled, then FlatCAM works in 32bit mode and it uses\n" + "Travelling Salesman algorithm for path optimization.") + ) + + self.excellon_optimization_radio = RadioSet([{'label': _('MetaHeuristic'), 'value': 'M'}, + {'label': _('Basic'), 'value': 'B'}, + {'label': _('TSA'), 'value': 'T'}], + orientation='vertical', stretch=False) + self.excellon_optimization_radio.setToolTip( + _("This sets the optimization type for the Excellon drill path.\n" + "If <> is checked then Google OR-Tools algorithm with\n" + "MetaHeuristic Guided Local Path is used. Default search time is 3sec.\n" + "If <> is checked then Google OR-Tools Basic algorithm is used.\n" + "If <> is checked then Travelling Salesman algorithm is used for\n" + "drill path optimization.\n" + "\n" + "If this control is disabled, then FlatCAM works in 32bit mode and it uses\n" + "Travelling Salesman algorithm for path optimization.") + ) + + grid2.addWidget(self.excellon_optimization_label, 9, 0) + grid2.addWidget(self.excellon_optimization_radio, 9, 1) + + self.optimization_time_label = QtWidgets.QLabel('%s:' % _('Duration')) + self.optimization_time_label.setAlignment(QtCore.Qt.AlignLeft) + self.optimization_time_label.setToolTip( + _("When OR-Tools Metaheuristic (MH) is enabled there is a\n" + "maximum threshold for how much time is spent doing the\n" + "path optimization. This max duration is set here.\n" + "In seconds.") + + ) + + self.optimization_time_entry = FCSpinner() + self.optimization_time_entry.set_range(0, 999) + + grid2.addWidget(self.optimization_time_label, 10, 0) + grid2.addWidget(self.optimization_time_entry, 10, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid2.addWidget(separator_line, 11, 0, 1, 2) + + # Excellon Object Color + self.gerber_color_label = QtWidgets.QLabel('%s' % _('Excellon Object Color')) + grid2.addWidget(self.gerber_color_label, 12, 0, 1, 2) + + # Plot Line Color + self.line_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.line_color_label.setToolTip( + _("Set the line color for plotted objects.") + ) + self.line_color_entry = FCEntry() + self.line_color_button = QtWidgets.QPushButton() + self.line_color_button.setFixedSize(15, 15) + + self.form_box_child_2 = QtWidgets.QHBoxLayout() + self.form_box_child_2.addWidget(self.line_color_entry) + self.form_box_child_2.addWidget(self.line_color_button) + self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid2.addWidget(self.line_color_label, 13, 0) + grid2.addLayout(self.form_box_child_2, 13, 1) + + # Plot Fill Color + self.fill_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.fill_color_label.setToolTip( + _("Set the fill color for plotted objects.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.fill_color_entry = FCEntry() + self.fill_color_button = QtWidgets.QPushButton() + self.fill_color_button.setFixedSize(15, 15) + + self.form_box_child_1 = QtWidgets.QHBoxLayout() + self.form_box_child_1.addWidget(self.fill_color_entry) + self.form_box_child_1.addWidget(self.fill_color_button) + self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid2.addWidget(self.fill_color_label, 14, 0) + grid2.addLayout(self.form_box_child_1, 14, 1) + + # Plot Fill Transparency Level + self.alpha_label = QtWidgets.QLabel('%s:' % _('Alpha')) + self.alpha_label.setToolTip( + _("Set the fill transparency for plotted objects.") + ) + self.color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.color_alpha_slider.setMinimum(0) + self.color_alpha_slider.setMaximum(255) + self.color_alpha_slider.setSingleStep(1) + + self.color_alpha_spinner = FCSpinner() + self.color_alpha_spinner.setMinimumWidth(70) + self.color_alpha_spinner.set_range(0, 255) + + self.form_box_child_3 = QtWidgets.QHBoxLayout() + self.form_box_child_3.addWidget(self.color_alpha_slider) + self.form_box_child_3.addWidget(self.color_alpha_spinner) + + grid2.addWidget(self.alpha_label, 15, 0) + grid2.addLayout(self.form_box_child_3, 15, 1) + + self.layout.addStretch() + + current_platform = platform.architecture()[0] + if current_platform == '64bit': + self.excellon_optimization_label.setDisabled(False) + self.excellon_optimization_radio.setDisabled(False) + self.optimization_time_label.setDisabled(False) + self.optimization_time_entry.setDisabled(False) + self.excellon_optimization_radio.activated_custom.connect(self.optimization_selection) + + else: + self.excellon_optimization_label.setDisabled(True) + self.excellon_optimization_radio.setDisabled(True) + self.optimization_time_label.setDisabled(True) + self.optimization_time_entry.setDisabled(True) + + # Setting plot colors signals + self.line_color_entry.editingFinished.connect(self.on_line_color_entry) + self.line_color_button.clicked.connect(self.on_line_color_button) + self.fill_color_entry.editingFinished.connect(self.on_fill_color_entry) + self.fill_color_button.clicked.connect(self.on_fill_color_button) + self.color_alpha_spinner.valueChanged.connect(self.on_color_spinner) + self.color_alpha_slider.valueChanged.connect(self.on_color_slider) # Load the defaults values into the Excellon Format and Excellon Zeros fields - self.option_dict()["__excellon_restore_defaults"].get_field().clicked.connect(self.on_defaults_button) - - - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Plot Options"), - CheckboxOptionUI( - option="excellon_plot", - label_text="Plot", - label_tooltip="Plot (show) this object." - ), - CheckboxOptionUI( - option="excellon_solid", - label_text="Solid", - label_tooltip="Plot as solid circles." - ), - SeparatorOptionUI(), - - HeadingOptionUI( - label_text="Excellon Format", - label_tooltip="The NC drill files, usually named Excellon files\n" - "are files that can be found in different formats.\n" - "Here we set the format used when the provided\n" - "coordinates are not using period.\n" - "\n" - "Possible presets:\n" - "\n" - "PROTEUS 3:3 MM LZ\n" - "DipTrace 5:2 MM TZ\n" - "DipTrace 4:3 MM LZ\n" - "\n" - "EAGLE 3:3 MM TZ\n" - "EAGLE 4:3 MM TZ\n" - "EAGLE 2:5 INCH TZ\n" - "EAGLE 3:5 INCH TZ\n" - "\n" - "ALTIUM 2:4 INCH LZ\n" - "Sprint Layout 2:4 INCH LZ" - "\n" - "KiCAD 3:5 INCH TZ" - ), - SpinnerOptionUI( - option="excellon_format_upper_in", - label_text="INCH int", - label_tooltip="This number signifies the number of digits in\nthe whole part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="excellon_format_lower_in", - label_text="INCH decimals", - label_tooltip="This number signifies the number of digits in\nthe decimal part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="excellon_format_upper_mm", - label_text="METRIC int", - label_tooltip="This number signifies the number of digits in\nthe whole part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="excellon_format_lower_mm", - label_text="METRIC decimals", - label_tooltip="This number signifies the number of digits in\nthe decimal part of Excellon coordinates.", - min_value=0, max_value=9, step=1 - ), - RadioSetOptionUI( - option="excellon_zeros", - label_text="Zeros", - label_tooltip="This sets the type of Excellon zeros.\n" - "If LZ then Leading Zeros are kept and\n" - "Trailing Zeros are removed.\n" - "If TZ is checked then Trailing Zeros are kept\n" - "and Leading Zeros are removed.\n\n" - "This is used when there is no information\n" - "stored in the Excellon file.", - choices=[ - {'label': _('LZ'), 'value': 'L'}, - {'label': _('TZ'), 'value': 'T'} - ] - ), - RadioSetOptionUI( - option="excellon_units", - label_text="Units", - label_tooltip="This sets the default units of Excellon files.\n" - "If it is not detected in the parsed file the value here\n" - "will be used." - "Some Excellon files don't have an header\n" - "therefore this parameter will be used.", - choices=[ - {'label': _('INCH'), 'value': 'INCH'}, - {'label': _('MM'), 'value': 'METRIC'} - ] - ), - CheckboxOptionUI( - option="excellon_update", - label_text="Update Export settings", - label_tooltip="If checked, the Excellon Export settings will be updated with the ones above." - ), - FullWidthButtonOptionUI( - option="__excellon_restore_defaults", - label_text="Restore Defaults", - label_tooltip=None - ), - SeparatorOptionUI(), - - HeadingOptionUI(label_text="Excellon Optimization"), - RadioSetOptionUI( - option="excellon_optimization_type", - label_text="Algorithm", - label_tooltip="This sets the optimization type for the Excellon drill path.\n" - "If <> is checked then Google OR-Tools algorithm with\n" - "MetaHeuristic Guided Local Path is used. Default search time is 3sec.\n" - "If <> is checked then Google OR-Tools Basic algorithm is used.\n" - "If <> is checked then Travelling Salesman algorithm is used for\n" - "drill path optimization.\n" - "\n" - "If this control is disabled, then FlatCAM works in 32bit mode and it uses\n" - "Travelling Salesman algorithm for path optimization.", - choices=[ - {'label': _('MetaHeuristic'), 'value': 'M'}, - {'label': _('Basic'), 'value': 'B'}, - {'label': _('TSA'), 'value': 'T'} - ], - orientation="vertical" - ), - SpinnerOptionUI( - option="excellon_search_time", - label_text="Duration", - label_tooltip="When OR-Tools Metaheuristic (MH) is enabled there is a\n" - "maximum threshold for how much time is spent doing the\n" - "path optimization. This max duration is set here.\n" - "In seconds.", - min_value=1, max_value=999, step=1 - ), - SeparatorOptionUI(), - - HeadingOptionUI(label_text="Excellon Object Color"), - ColorOptionUI( - option="excellon_plot_line", - label_text="Outline", - label_tooltip="Set the line color for plotted objects.", - ), - ColorOptionUI( - option="excellon_plot_fill", - label_text="Fill", - label_tooltip="Set the fill color for plotted objects.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["excellon_plot_line", "excellon_plot_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the transparency for plotted objects." - ) - ] + self.excellon_defaults_button.clicked.connect(self.on_excellon_defaults_button) def optimization_selection(self): - disable_time = (self.option_dict()["excellon_optimization_type"].get_field().get_value() != 'M') - self.option_dict()["excellon_search_time"].label_widget.setDisabled(disable_time) - self.option_dict()["excellon_search_time"].get_field().setDisabled(disable_time) + if self.excellon_optimization_radio.get_value() == 'M': + self.optimization_time_label.setDisabled(False) + self.optimization_time_entry.setDisabled(False) + else: + self.optimization_time_label.setDisabled(True) + self.optimization_time_entry.setDisabled(True) - def on_defaults_button(self): - self.option_dict()["excellon_format_lower_in"].get_field().set_value('4') - self.option_dict()["excellon_format_upper_in"].get_field().set_value('2') - self.option_dict()["excellon_format_lower_mm"].get_field().set_value('3') - self.option_dict()["excellon_format_upper_mm"].get_field().set_value('3') - self.option_dict()["excellon_zeros"].get_field().set_value('L') - self.option_dict()["excellon_units"].get_field().set_value('INCH') + # Setting plot colors handlers + def on_fill_color_entry(self): + self.app.defaults['excellon_plot_fill'] = self.fill_color_entry.get_value()[:7] + \ + self.app.defaults['excellon_plot_fill'][7:9] + self.fill_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['excellon_plot_fill'])[:7]) + + def on_fill_color_button(self): + current_color = QtGui.QColor(self.app.defaults['excellon_plot_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.fill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['excellon_plot_fill'][7:9]) + self.fill_color_entry.set_value(new_val) + self.app.defaults['excellon_plot_fill'] = new_val + + def on_color_spinner(self): + spinner_value = self.color_alpha_spinner.value() + self.color_alpha_slider.setValue(spinner_value) + self.app.defaults['excellon_plot_fill'] = \ + self.app.defaults['excellon_plot_fill'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + self.app.defaults['excellon_plot_line'] = \ + self.app.defaults['excellon_plot_line'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + + def on_color_slider(self): + slider_value = self.color_alpha_slider.value() + self.color_alpha_spinner.setValue(slider_value) + + def on_line_color_entry(self): + self.app.defaults['excellon_plot_line'] = self.line_color_entry.get_value()[:7] + \ + self.app.defaults['excellon_plot_line'][7:9] + self.line_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['excellon_plot_line'])[:7]) + + def on_line_color_button(self): + current_color = QtGui.QColor(self.app.defaults['excellon_plot_line'][:7]) + # print(current_color) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['excellon_plot_line'][7:9]) + self.line_color_entry.set_value(new_val_line) + self.app.defaults['excellon_plot_line'] = new_val_line + + def on_excellon_defaults_button(self): + self.app.preferencesUiManager.defaults_form_fields["excellon_format_lower_in"].set_value('4') + self.app.preferencesUiManager.defaults_form_fields["excellon_format_upper_in"].set_value('2') + self.app.preferencesUiManager.defaults_form_fields["excellon_format_lower_mm"].set_value('3') + self.app.preferencesUiManager.defaults_form_fields["excellon_format_upper_mm"].set_value('3') + self.app.preferencesUiManager.defaults_form_fields["excellon_zeros"].set_value('L') + self.app.preferencesUiManager.defaults_form_fields["excellon_units"].set_value('INCH') diff --git a/flatcamGUI/preferences/excellon/ExcellonOptPrefGroupUI.py b/flatcamGUI/preferences/excellon/ExcellonOptPrefGroupUI.py index 4f68eaca..cdc6ce5e 100644 --- a/flatcamGUI/preferences/excellon/ExcellonOptPrefGroupUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonOptPrefGroupUI.py @@ -1,7 +1,10 @@ -from flatcamGUI.GUIElements import OptionalInputSection +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt, QSettings + +from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCEntry, FCSpinner, OptionalInputSection, \ + FCComboBox from flatcamGUI.preferences import machinist_setting -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate import builtins @@ -17,182 +20,298 @@ else: machinist_setting = 0 -class ExcellonOptPrefGroupUI(OptionsGroupUI2): +class ExcellonOptPrefGroupUI(OptionsGroupUI): + + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Excellon Options", parent=parent) + super(ExcellonOptPrefGroupUI, self).__init__(self, parent=parent) - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) self.setTitle(str(_("Excellon Options"))) + self.decimals = decimals - self.pp_excellon_name_cb = self.option_dict()["excellon_ppname_e"].get_field() + # ## Create CNC Job + self.cncjob_label = QtWidgets.QLabel('%s' % _('Create CNC Job')) + self.cncjob_label.setToolTip( + _("Parameters used to create a CNC Job object\n" + "for this drill object.") + ) + self.layout.addWidget(self.cncjob_label) - self.multidepth_cb = self.option_dict()["excellon_multidepth"].get_field() - self.depthperpass_entry = self.option_dict()["excellon_depthperpass"].get_field() - self.ois_multidepth = OptionalInputSection(self.multidepth_cb, [self.depthperpass_entry]) + grid2 = QtWidgets.QGridLayout() + self.layout.addLayout(grid2) + grid2.setColumnStretch(0, 0) + grid2.setColumnStretch(1, 1) - self.dwell_cb = self.option_dict()["excellon_dwell"].get_field() - self.dwelltime_entry = self.option_dict()["excellon_dwelltime"].get_field() - self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry]) + # Operation Type + self.operation_label = QtWidgets.QLabel('%s:' % _('Operation')) + self.operation_label.setToolTip( + _("Operation type:\n" + "- Drilling -> will drill the drills/slots associated with this tool\n" + "- Milling -> will mill the drills/slots") + ) + self.operation_radio = RadioSet( + [ + {'label': _('Drilling'), 'value': 'drill'}, + {'label': _("Milling"), 'value': 'mill'} + ] + ) - # FIXME until this feature is implemented these are disabled - self.option_dict()["excellon_gcode_type"].label_widget.hide() - self.option_dict()["excellon_gcode_type"].get_field().hide() + grid2.addWidget(self.operation_label, 0, 0) + grid2.addWidget(self.operation_radio, 0, 1) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Create CNC Job", - label_tooltip="Parameters used to create a CNC Job object\n" - "for this drill object." - ), - RadioSetOptionUI( - option="excellon_operation", - label_text="Operation", - label_bold=True, - label_tooltip="Operation type:\n" - "- Drilling -> will drill the drills/slots associated with this tool\n" - "- Milling -> will mill the drills/slots", - choices=[ - {'label': _('Drilling'), 'value': 'drill'}, - {'label': _("Milling"), 'value': 'mill'} - ] - ), - RadioSetOptionUI( - option="excellon_milling_type", - label_text="Milling Type", - label_tooltip="Milling type:\n" - "- Drills -> will mill the drills associated with this tool\n" - "- Slots -> will mill the slots associated with this tool\n" - "- Both -> will mill both drills and mills or whatever is available", - choices=[ - {'label': _('Drills'), 'value': 'drills'}, - {'label': _("Slots"), 'value': 'slots'}, - {'label': _("Both"), 'value': 'both'}, - ] - ), - DoubleSpinnerOptionUI( - option="excellon_milling_dia", - label_text="Milling Diameter", - label_tooltip="The diameter of the tool who will do the milling", - min_value=0.0, max_value=9999.9999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_cutz", - label_text="Cut Z", - label_tooltip="Drill depth (negative) \nbelow the copper surface.", - min_value=-9999.9999, max_value=(9999.9999 if machinist_setting else 0.0), - step=0.1, decimals=self.decimals - ), + self.mill_type_label = QtWidgets.QLabel('%s:' % _('Milling Type')) + self.mill_type_label.setToolTip( + _("Milling type:\n" + "- Drills -> will mill the drills associated with this tool\n" + "- Slots -> will mill the slots associated with this tool\n" + "- Both -> will mill both drills and mills or whatever is available") + ) + self.milling_type_radio = RadioSet( + [ + {'label': _('Drills'), 'value': 'drills'}, + {'label': _("Slots"), 'value': 'slots'}, + {'label': _("Both"), 'value': 'both'}, + ] + ) + grid2.addWidget(self.mill_type_label, 1, 0) + grid2.addWidget(self.milling_type_radio, 1, 1) - CheckboxOptionUI( - option="excellon_multidepth", - label_text="Multi-Depth", - label_tooltip="Use multiple passes to limit\n" - "the cut depth in each pass. Will\n" - "cut multiple times until Cut Z is\n" - "reached." - ), - DoubleSpinnerOptionUI( - option="excellon_depthperpass", - label_text="Depth/Pass", - label_tooltip="Depth of each pass (positive).", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_travelz", - label_text="Travel Z", - label_tooltip="Tool height when travelling\nacross the XY plane.", - min_value=(-9999.9999 if machinist_setting else 0.0001), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - CheckboxOptionUI( - option="excellon_toolchange", - label_text="Tool change", - label_tooltip="Include tool-change sequence\nin G-Code (Pause for tool change)." - ), - DoubleSpinnerOptionUI( - option="excellon_toolchangez", - label_text="Toolchange Z", - label_tooltip="Z-axis position (height) for\ntool change.", - min_value=(-9999.9999 if machinist_setting else 0.0), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_endz", - label_text="End move Z", - label_tooltip="Height of the tool after\nthe last move at the end of the job.", - min_value=(-9999.9999 if machinist_setting else 0.0), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - LineEntryOptionUI( - option="excellon_endxy", - label_text="End move X,Y", - label_tooltip="End move X,Y position. In format (x,y).\n" - "If no value is entered then there is no move\n" - "on X,Y plane at the end of the job." - ), - DoubleSpinnerOptionUI( - option="excellon_feedrate_z", - label_text="Feedrate Z", - label_tooltip="Tool speed while drilling\n" - "(in units per minute).\n" - "So called 'Plunge' feedrate.\n" - "This is for linear move G01.", - min_value=0, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - SpinnerOptionUI( - option="excellon_spindlespeed", - label_text="Spindle speed", - label_tooltip="Speed of the spindle in RPM (optional).", - min_value=0, max_value=1000000, step=100 - ), - CheckboxOptionUI( - option="excellon_dwell", - label_text="Enable Dwell", - label_tooltip="Pause to allow the spindle to reach its\nspeed before cutting." - ), - DoubleSpinnerOptionUI( - option="excellon_dwelltime", - label_text="Duration", - label_tooltip="Number of time units for spindle to dwell.", - min_value=0, max_value=999999, step=0.5, decimals=self.decimals - ), - ComboboxOptionUI( - option="excellon_ppname_e", - label_text="Preprocessor", - label_tooltip="The preprocessor JSON file that dictates\nGcode output.", # FIXME tooltip incorrect? - choices=[] # Populated in App (FIXME) - ), - RadioSetOptionUI( - option="excellon_gcode_type", - label_text="Gcode", - label_bold=True, - label_tooltip="Choose what to use for GCode generation:\n" - "'Drills', 'Slots' or 'Both'.\n" - "When choosing 'Slots' or 'Both', slots will be\n" - "converted to drills.", - choices=[ - {'label': 'Drills', 'value': 'drills'}, - {'label': 'Slots', 'value': 'slots'}, - {'label': 'Both', 'value': 'both'} - ] - ), + self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter')) + self.mill_dia_label.setToolTip( + _("The diameter of the tool who will do the milling") + ) - HeadingOptionUI( - label_text="Mill Holes", - label_tooltip="Create Geometry for milling holes." - ), - DoubleSpinnerOptionUI( - option="excellon_tooldia", - label_text="Drill Tool dia", - label_tooltip="Diameter of the cutting tool", - min_value=0.0, max_value=999.9999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="excellon_slot_tooldia", - label_text="Slot Tool dia", - label_tooltip="Diameter of the cutting tool\nwhen milling slots.", - min_value=0.0, max_value=999.9999, step=0.1, decimals=self.decimals + self.mill_dia_entry = FCDoubleSpinner() + self.mill_dia_entry.set_precision(self.decimals) + self.mill_dia_entry.set_range(0.0000, 9999.9999) + + grid2.addWidget(self.mill_dia_label, 2, 0) + grid2.addWidget(self.mill_dia_entry, 2, 1) + + # Cut Z + cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + cutzlabel.setToolTip( + _("Drill depth (negative)\n" + "below the copper surface.") + ) + + self.cutz_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.cutz_entry.set_range(-9999.9999, 0.0000) + else: + self.cutz_entry.set_range(-9999.9999, 9999.9999) + + self.cutz_entry.setSingleStep(0.1) + self.cutz_entry.set_precision(self.decimals) + + grid2.addWidget(cutzlabel, 3, 0) + grid2.addWidget(self.cutz_entry, 3, 1) + + # Multi-Depth + self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth")) + self.mpass_cb.setToolTip( + _( + "Use multiple passes to limit\n" + "the cut depth in each pass. Will\n" + "cut multiple times until Cut Z is\n" + "reached." ) - ] + ) + + self.maxdepth_entry = FCDoubleSpinner() + self.maxdepth_entry.set_precision(self.decimals) + self.maxdepth_entry.set_range(0, 9999.9999) + self.maxdepth_entry.setSingleStep(0.1) + + self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) + + grid2.addWidget(self.mpass_cb, 4, 0) + grid2.addWidget(self.maxdepth_entry, 4, 1) + + # Travel Z + travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) + travelzlabel.setToolTip( + _("Tool height when travelling\n" + "across the XY plane.") + ) + + self.travelz_entry = FCDoubleSpinner() + self.travelz_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.travelz_entry.set_range(0.0001, 9999.9999) + else: + self.travelz_entry.set_range(-9999.9999, 9999.9999) + + grid2.addWidget(travelzlabel, 5, 0) + grid2.addWidget(self.travelz_entry, 5, 1) + + # Tool change: + self.toolchange_cb = FCCheckBox('%s' % _("Tool change")) + self.toolchange_cb.setToolTip( + _("Include tool-change sequence\n" + "in G-Code (Pause for tool change).") + ) + grid2.addWidget(self.toolchange_cb, 6, 0, 1, 2) + + # Tool Change Z + toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z')) + toolchangezlabel.setToolTip( + _("Z-axis position (height) for\n" + "tool change.") + ) + + self.toolchangez_entry = FCDoubleSpinner() + self.toolchangez_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.toolchangez_entry.set_range(0.0001, 9999.9999) + else: + self.toolchangez_entry.set_range(-9999.9999, 9999.9999) + + grid2.addWidget(toolchangezlabel, 7, 0) + grid2.addWidget(self.toolchangez_entry, 7, 1) + + # End Move Z + endz_label = QtWidgets.QLabel('%s:' % _('End move Z')) + endz_label.setToolTip( + _("Height of the tool after\n" + "the last move at the end of the job.") + ) + self.endz_entry = FCDoubleSpinner() + self.endz_entry.set_precision(self.decimals) + + if machinist_setting == 0: + self.endz_entry.set_range(0.0000, 9999.9999) + else: + self.endz_entry.set_range(-9999.9999, 9999.9999) + + grid2.addWidget(endz_label, 8, 0) + grid2.addWidget(self.endz_entry, 8, 1) + + # End Move X,Y + endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y')) + endmove_xy_label.setToolTip( + _("End move X,Y position. In format (x,y).\n" + "If no value is entered then there is no move\n" + "on X,Y plane at the end of the job.") + ) + self.endxy_entry = FCEntry() + + grid2.addWidget(endmove_xy_label, 9, 0) + grid2.addWidget(self.endxy_entry, 9, 1) + + # Feedrate Z + frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) + frlabel.setToolTip( + _("Tool speed while drilling\n" + "(in units per minute).\n" + "So called 'Plunge' feedrate.\n" + "This is for linear move G01.") + ) + self.feedrate_z_entry = FCDoubleSpinner() + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.set_range(0, 99999.9999) + + grid2.addWidget(frlabel, 10, 0) + grid2.addWidget(self.feedrate_z_entry, 10, 1) + + # Spindle speed + spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed')) + spdlabel.setToolTip( + _("Speed of the spindle\n" + "in RPM (optional)") + ) + + self.spindlespeed_entry = FCSpinner() + self.spindlespeed_entry.set_range(0, 1000000) + self.spindlespeed_entry.set_step(100) + + grid2.addWidget(spdlabel, 11, 0) + grid2.addWidget(self.spindlespeed_entry, 11, 1) + + # Dwell + self.dwell_cb = FCCheckBox('%s' % _('Enable Dwell')) + self.dwell_cb .setToolTip( + _("Pause to allow the spindle to reach its\n" + "speed before cutting.") + ) + + grid2.addWidget(self.dwell_cb, 12, 0, 1, 2) + + # Dwell Time + dwelltime = QtWidgets.QLabel('%s:' % _('Duration')) + dwelltime.setToolTip(_("Number of time units for spindle to dwell.")) + self.dwelltime_entry = FCDoubleSpinner() + self.dwelltime_entry.set_precision(self.decimals) + self.dwelltime_entry.set_range(0, 99999.9999) + + grid2.addWidget(dwelltime, 13, 0) + grid2.addWidget(self.dwelltime_entry, 13, 1) + + self.ois_dwell_exc = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry]) + + # preprocessor selection + pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor")) + pp_excellon_label.setToolTip( + _("The preprocessor JSON file that dictates\n" + "Gcode output.") + ) + + self.pp_excellon_name_cb = FCComboBox() + self.pp_excellon_name_cb.setFocusPolicy(Qt.StrongFocus) + + grid2.addWidget(pp_excellon_label, 14, 0) + grid2.addWidget(self.pp_excellon_name_cb, 14, 1) + + # ### Choose what to use for Gcode creation: Drills, Slots or Both + excellon_gcode_type_label = QtWidgets.QLabel('%s' % _('Gcode')) + excellon_gcode_type_label.setToolTip( + _("Choose what to use for GCode generation:\n" + "'Drills', 'Slots' or 'Both'.\n" + "When choosing 'Slots' or 'Both', slots will be\n" + "converted to drills.") + ) + self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'}, + {'label': 'Slots', 'value': 'slots'}, + {'label': 'Both', 'value': 'both'}]) + grid2.addWidget(excellon_gcode_type_label, 15, 0) + grid2.addWidget(self.excellon_gcode_type_radio, 15, 1) + + # until I decide to implement this feature those remain disabled + excellon_gcode_type_label.hide() + self.excellon_gcode_type_radio.setVisible(False) + + # ### Milling Holes ## ## + self.mill_hole_label = QtWidgets.QLabel('%s' % _('Mill Holes')) + self.mill_hole_label.setToolTip( + _("Create Geometry for milling holes.") + ) + grid2.addWidget(self.mill_hole_label, 16, 0, 1, 2) + + tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia')) + tdlabel.setToolTip( + _("Diameter of the cutting tool.") + ) + self.tooldia_entry = FCDoubleSpinner() + self.tooldia_entry.set_precision(self.decimals) + self.tooldia_entry.set_range(0, 999.9999) + + grid2.addWidget(tdlabel, 18, 0) + grid2.addWidget(self.tooldia_entry, 18, 1) + + stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia')) + stdlabel.setToolTip( + _("Diameter of the cutting tool\n" + "when milling slots.") + ) + self.slot_tooldia_entry = FCDoubleSpinner() + self.slot_tooldia_entry.set_precision(self.decimals) + self.slot_tooldia_entry.set_range(0, 999.9999) + + grid2.addWidget(stdlabel, 21, 0) + grid2.addWidget(self.slot_tooldia_entry, 21, 1) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/excellon/ExcellonPreferencesUI.py b/flatcamGUI/preferences/excellon/ExcellonPreferencesUI.py index 91176f9d..b3d6d165 100644 --- a/flatcamGUI/preferences/excellon/ExcellonPreferencesUI.py +++ b/flatcamGUI/preferences/excellon/ExcellonPreferencesUI.py @@ -1,5 +1,6 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.excellon.ExcellonEditorPrefGroupUI import ExcellonEditorPrefGroupUI from flatcamGUI.preferences.excellon.ExcellonExpPrefGroupUI import ExcellonExpPrefGroupUI from flatcamGUI.preferences.excellon.ExcellonAdvOptPrefGroupUI import ExcellonAdvOptPrefGroupUI @@ -9,62 +10,44 @@ from flatcamGUI.preferences.excellon.ExcellonGenPrefGroupUI import ExcellonGenPr 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 ExcellonPreferencesUI(PreferencesSectionUI): - def __init__(self, decimals, **kwargs): +class ExcellonPreferencesUI(QtWidgets.QWidget): + + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals - # FIXME: remove the need for external access to excellon_opt_group + + self.excellon_gen_group = ExcellonGenPrefGroupUI(decimals=self.decimals) + self.excellon_gen_group.setMinimumWidth(220) self.excellon_opt_group = ExcellonOptPrefGroupUI(decimals=self.decimals) - super().__init__(**kwargs) - self.init_sync_export() + self.excellon_opt_group.setMinimumWidth(290) + self.excellon_exp_group = ExcellonExpPrefGroupUI(decimals=self.decimals) + self.excellon_exp_group.setMinimumWidth(250) + self.excellon_adv_opt_group = ExcellonAdvOptPrefGroupUI(decimals=self.decimals) + self.excellon_adv_opt_group.setMinimumWidth(250) + self.excellon_editor_group = ExcellonEditorPrefGroupUI(decimals=self.decimals) + self.excellon_editor_group.setMinimumWidth(260) - def build_groups(self) -> [OptionsGroupUI]: - return [ - ExcellonGenPrefGroupUI(decimals=self.decimals), - self.excellon_opt_group, - ExcellonExpPrefGroupUI(decimals=self.decimals), - ExcellonAdvOptPrefGroupUI(decimals=self.decimals), - ExcellonEditorPrefGroupUI(decimals=self.decimals) - ] - - def get_tab_id(self): - return "excellon_tab" - - def get_tab_label(self): - return _("EXCELLON") - - def init_sync_export(self): - self.option_dict()["excellon_update"].get_field().stateChanged.connect(self.sync_export) - self.option_dict()["excellon_format_upper_in"].get_field().returnPressed.connect(self.sync_export) - self.option_dict()["excellon_format_lower_in"].get_field().returnPressed.connect(self.sync_export) - self.option_dict()["excellon_format_upper_mm"].get_field().returnPressed.connect(self.sync_export) - self.option_dict()["excellon_format_lower_mm"].get_field().returnPressed.connect(self.sync_export) - self.option_dict()["excellon_zeros"].get_field().activated_custom.connect(self.sync_export) - self.option_dict()["excellon_units"].get_field().activated_custom.connect(self.sync_export) - - def sync_export(self): - if not self.option_dict()["excellon_update"].get_field().get_value(): - # User has disabled sync. - return - - zeros = self.option_dict()["excellon_zeros"].get_field().get_value() + 'Z' - self.option_dict()["excellon_exp_zeros"].get_field().set_value(zeros) - - units = self.option_dict()["excellon_units"].get_field().get_value() - self.option_dict()["excellon_exp_units"].get_field().set_value(units) - - if units.upper() == 'METRIC': - whole = self.option_dict()["excellon_format_upper_mm"].get_field().get_value() - dec = self.option_dict()["excellon_format_lower_mm"].get_field().get_value() - else: - whole = self.option_dict()["excellon_format_upper_in"].get_field().get_value() - dec = self.option_dict()["excellon_format_lower_in"].get_field().get_value() - self.option_dict()["excellon_exp_integer"].get_field().set_value(whole) - self.option_dict()["excellon_exp_decimals"].get_field().set_value(dec) + self.vlay = QtWidgets.QVBoxLayout() + self.vlay.addWidget(self.excellon_opt_group) + self.vlay.addWidget(self.excellon_exp_group) + self.layout.addWidget(self.excellon_gen_group) + self.layout.addLayout(self.vlay) + self.layout.addWidget(self.excellon_adv_opt_group) + self.layout.addWidget(self.excellon_editor_group) + self.layout.addStretch() diff --git a/flatcamGUI/preferences/general/GeneralAPPSetGroupUI.py b/flatcamGUI/preferences/general/GeneralAPPSetGroupUI.py new file mode 100644 index 00000000..3daff809 --- /dev/null +++ b/flatcamGUI/preferences/general/GeneralAPPSetGroupUI.py @@ -0,0 +1,483 @@ +from PyQt5 import QtCore, QtWidgets, QtGui +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, RadioSet, OptionalInputSection, FCSpinner, \ + FCEntry +from flatcamGUI.preferences import settings +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI + +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 GeneralAPPSetGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + super(GeneralAPPSetGroupUI, self).__init__(self, parent=parent) + + self.setTitle(str(_("App Settings"))) + self.decimals = decimals + + theme_settings = QtCore.QSettings("Open Source", "FlatCAM") + if theme_settings.contains("theme"): + theme = theme_settings.value('theme', type=str) + else: + theme = 'white' + + if theme == 'white': + self.resource_loc = 'assets/resources' + else: + self.resource_loc = 'assets/resources' + + # Create a grid layout for the Application general settings + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + grid0.setColumnStretch(0, 0) + grid0.setColumnStretch(1, 1) + + # GRID Settings + self.grid_label = QtWidgets.QLabel('%s' % _('Grid Settings')) + grid0.addWidget(self.grid_label, 0, 0, 1, 2) + + # Grid X Entry + self.gridx_label = QtWidgets.QLabel('%s:' % _('X value')) + self.gridx_label.setToolTip( + _("This is the Grid snap value on X axis.") + ) + self.gridx_entry = FCDoubleSpinner() + self.gridx_entry.set_precision(self.decimals) + self.gridx_entry.setSingleStep(0.1) + + grid0.addWidget(self.gridx_label, 1, 0) + grid0.addWidget(self.gridx_entry, 1, 1) + + # Grid Y Entry + self.gridy_label = QtWidgets.QLabel('%s:' % _('Y value')) + self.gridy_label.setToolTip( + _("This is the Grid snap value on Y axis.") + ) + self.gridy_entry = FCDoubleSpinner() + self.gridy_entry.set_precision(self.decimals) + self.gridy_entry.setSingleStep(0.1) + + grid0.addWidget(self.gridy_label, 2, 0) + grid0.addWidget(self.gridy_entry, 2, 1) + + # Snap Max Entry + self.snap_max_label = QtWidgets.QLabel('%s:' % _('Snap Max')) + self.snap_max_label.setToolTip(_("Max. magnet distance")) + self.snap_max_dist_entry = FCDoubleSpinner() + self.snap_max_dist_entry.set_precision(self.decimals) + self.snap_max_dist_entry.setSingleStep(0.1) + + grid0.addWidget(self.snap_max_label, 3, 0) + grid0.addWidget(self.snap_max_dist_entry, 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) + + # Workspace + self.workspace_label = QtWidgets.QLabel('%s' % _('Workspace Settings')) + grid0.addWidget(self.workspace_label, 5, 0, 1, 2) + + self.workspace_cb = FCCheckBox('%s' % _('Active')) + self.workspace_cb.setToolTip( + _("Draw a delimiting rectangle on canvas.\n" + "The purpose is to illustrate the limits for our work.") + ) + + grid0.addWidget(self.workspace_cb, 6, 0, 1, 2) + + self.workspace_type_lbl = QtWidgets.QLabel('%s:' % _('Size')) + self.workspace_type_lbl.setToolTip( + _("Select the type of rectangle to be used on canvas,\n" + "as valid workspace.") + ) + self.wk_cb = FCComboBox() + + grid0.addWidget(self.workspace_type_lbl, 7, 0) + grid0.addWidget(self.wk_cb, 7, 1) + + self.pagesize = {} + self.pagesize.update( + { + 'A0': (841, 1189), + 'A1': (594, 841), + 'A2': (420, 594), + 'A3': (297, 420), + 'A4': (210, 297), + 'A5': (148, 210), + 'A6': (105, 148), + 'A7': (74, 105), + 'A8': (52, 74), + 'A9': (37, 52), + 'A10': (26, 37), + + 'B0': (1000, 1414), + 'B1': (707, 1000), + 'B2': (500, 707), + 'B3': (353, 500), + 'B4': (250, 353), + 'B5': (176, 250), + 'B6': (125, 176), + 'B7': (88, 125), + 'B8': (62, 88), + 'B9': (44, 62), + 'B10': (31, 44), + + 'C0': (917, 1297), + 'C1': (648, 917), + 'C2': (458, 648), + 'C3': (324, 458), + 'C4': (229, 324), + 'C5': (162, 229), + 'C6': (114, 162), + 'C7': (81, 114), + 'C8': (57, 81), + 'C9': (40, 57), + 'C10': (28, 40), + + # American paper sizes + 'LETTER': (8.5, 11), + 'LEGAL': (8.5, 14), + 'ELEVENSEVENTEEN': (11, 17), + + # From https://en.wikipedia.org/wiki/Paper_size + 'JUNIOR_LEGAL': (5, 8), + 'HALF_LETTER': (5.5, 8), + 'GOV_LETTER': (8, 10.5), + 'GOV_LEGAL': (8.5, 13), + 'LEDGER': (17, 11), + } + ) + + page_size_list = list(self.pagesize.keys()) + + self.wk_cb.addItems(page_size_list) + + # Page orientation + self.wk_orientation_label = QtWidgets.QLabel('%s:' % _("Orientation")) + self.wk_orientation_label.setToolTip(_("Can be:\n" + "- Portrait\n" + "- Landscape")) + + self.wk_orientation_radio = RadioSet([{'label': _('Portrait'), 'value': 'p'}, + {'label': _('Landscape'), 'value': 'l'}, + ], stretch=False) + + self.wks = OptionalInputSection(self.workspace_cb, + [ + self.workspace_type_lbl, + self.wk_cb, + self.wk_orientation_label, + self.wk_orientation_radio + ]) + + grid0.addWidget(self.wk_orientation_label, 8, 0) + grid0.addWidget(self.wk_orientation_radio, 8, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 9, 0, 1, 2) + + # Font Size + self.font_size_label = QtWidgets.QLabel('%s' % _('Font Size')) + grid0.addWidget(self.font_size_label, 10, 0, 1, 2) + + # Notebook Font Size + self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('Notebook')) + self.notebook_font_size_label.setToolTip( + _("This sets the font size for the elements found in the Notebook.\n" + "The notebook is the collapsible area in the left side of the GUI,\n" + "and include the Project, Selected and Tool tabs.") + ) + + self.notebook_font_size_spinner = FCSpinner() + self.notebook_font_size_spinner.set_range(8, 40) + self.notebook_font_size_spinner.setWrapping(True) + + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("notebook_font_size"): + self.notebook_font_size_spinner.set_value(qsettings.value('notebook_font_size', type=int)) + else: + self.notebook_font_size_spinner.set_value(12) + + grid0.addWidget(self.notebook_font_size_label, 11, 0) + grid0.addWidget(self.notebook_font_size_spinner, 11, 1) + + # Axis Font Size + self.axis_font_size_label = QtWidgets.QLabel('%s:' % _('Axis')) + self.axis_font_size_label.setToolTip( + _("This sets the font size for canvas axis.") + ) + + self.axis_font_size_spinner = FCSpinner() + self.axis_font_size_spinner.set_range(0, 40) + self.axis_font_size_spinner.setWrapping(True) + + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("axis_font_size"): + self.axis_font_size_spinner.set_value(qsettings.value('axis_font_size', type=int)) + else: + self.axis_font_size_spinner.set_value(8) + + grid0.addWidget(self.axis_font_size_label, 12, 0) + grid0.addWidget(self.axis_font_size_spinner, 12, 1) + + # TextBox Font Size + self.textbox_font_size_label = QtWidgets.QLabel('%s:' % _('Textbox')) + self.textbox_font_size_label.setToolTip( + _("This sets the font size for the Textbox GUI\n" + "elements that are used in FlatCAM.") + ) + + self.textbox_font_size_spinner = FCSpinner() + self.textbox_font_size_spinner.set_range(8, 40) + self.textbox_font_size_spinner.setWrapping(True) + + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("textbox_font_size"): + self.textbox_font_size_spinner.set_value(settings.value('textbox_font_size', type=int)) + else: + self.textbox_font_size_spinner.set_value(10) + + grid0.addWidget(self.textbox_font_size_label, 13, 0) + grid0.addWidget(self.textbox_font_size_spinner, 13, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 14, 0, 1, 2) + + # ----------------------------------------------------------- + # -------------- MOUSE SETTINGS ----------------------------- + # ----------------------------------------------------------- + + self.mouse_lbl = QtWidgets.QLabel('%s' % _('Mouse Settings')) + grid0.addWidget(self.mouse_lbl, 21, 0, 1, 2) + + # Mouse Cursor Shape + self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Cursor Shape')) + self.cursor_lbl.setToolTip( + _("Choose a mouse cursor shape.\n" + "- Small -> with a customizable size.\n" + "- Big -> Infinite lines") + ) + + self.cursor_radio = RadioSet([ + {"label": _("Small"), "value": "small"}, + {"label": _("Big"), "value": "big"} + ], orientation='horizontal', stretch=False) + + grid0.addWidget(self.cursor_lbl, 22, 0) + grid0.addWidget(self.cursor_radio, 22, 1) + + # Mouse Cursor Size + self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Cursor Size')) + self.cursor_size_lbl.setToolTip( + _("Set the size of the mouse cursor, in pixels.") + ) + + self.cursor_size_entry = FCSpinner() + self.cursor_size_entry.set_range(10, 70) + self.cursor_size_entry.setWrapping(True) + + grid0.addWidget(self.cursor_size_lbl, 23, 0) + grid0.addWidget(self.cursor_size_entry, 23, 1) + + # Cursor Width + self.cursor_width_lbl = QtWidgets.QLabel('%s:' % _('Cursor Width')) + self.cursor_width_lbl.setToolTip( + _("Set the line width of the mouse cursor, in pixels.") + ) + + self.cursor_width_entry = FCSpinner() + self.cursor_width_entry.set_range(1, 10) + self.cursor_width_entry.setWrapping(True) + + grid0.addWidget(self.cursor_width_lbl, 24, 0) + grid0.addWidget(self.cursor_width_entry, 24, 1) + + # Cursor Color Enable + self.mouse_cursor_color_cb = FCCheckBox(label='%s' % _('Cursor Color')) + self.mouse_cursor_color_cb.setToolTip( + _("Check this box to color mouse cursor.") + ) + grid0.addWidget(self.mouse_cursor_color_cb, 25, 0, 1, 2) + + # Cursor Color + self.mouse_color_label = QtWidgets.QLabel('%s:' % _('Cursor Color')) + self.mouse_color_label.setToolTip( + _("Set the color of the mouse cursor.") + ) + self.mouse_cursor_entry = FCEntry() + self.mouse_cursor_button = QtWidgets.QPushButton() + self.mouse_cursor_button.setFixedSize(15, 15) + + self.form_box_child_1 = QtWidgets.QHBoxLayout() + self.form_box_child_1.addWidget(self.mouse_cursor_entry) + self.form_box_child_1.addWidget(self.mouse_cursor_button) + self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.mouse_color_label, 26, 0) + grid0.addLayout(self.form_box_child_1, 26, 1) + + self.mois = OptionalInputSection( + self.mouse_cursor_color_cb, + [ + self.mouse_color_label, + self.mouse_cursor_entry, + self.mouse_cursor_button + ] + ) + # Select mouse pan button + self.panbuttonlabel = QtWidgets.QLabel('%s:' % _('Pan Button')) + self.panbuttonlabel.setToolTip( + _("Select the mouse button to use for panning:\n" + "- MMB --> Middle Mouse Button\n" + "- RMB --> Right Mouse Button") + ) + self.pan_button_radio = RadioSet([{'label': _('MMB'), 'value': '3'}, + {'label': _('RMB'), 'value': '2'}]) + + grid0.addWidget(self.panbuttonlabel, 27, 0) + grid0.addWidget(self.pan_button_radio, 27, 1) + + # Multiple Selection Modifier Key + self.mselectlabel = QtWidgets.QLabel('%s:' % _('Multiple Selection')) + self.mselectlabel.setToolTip( + _("Select the key used for multiple selection.") + ) + self.mselect_radio = RadioSet([{'label': _('CTRL'), 'value': 'Control'}, + {'label': _('SHIFT'), 'value': 'Shift'}]) + + grid0.addWidget(self.mselectlabel, 28, 0) + grid0.addWidget(self.mselect_radio, 28, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 29, 0, 1, 2) + + # Delete confirmation + self.delete_conf_cb = FCCheckBox(_('Delete object confirmation')) + self.delete_conf_cb.setToolTip( + _("When checked the application will ask for user confirmation\n" + "whenever the Delete object(s) event is triggered, either by\n" + "menu shortcut or key shortcut.") + ) + grid0.addWidget(self.delete_conf_cb, 30, 0, 1, 2) + + # Open behavior + self.open_style_cb = FCCheckBox('%s' % _('"Open" behavior')) + self.open_style_cb.setToolTip( + _("When checked the path for the last saved file is used when saving files,\n" + "and the path for the last opened file is used when opening files.\n\n" + "When unchecked the path for opening files is the one used last: either the\n" + "path for saving files or the path for opening files.") + ) + + grid0.addWidget(self.open_style_cb, 31, 0, 1, 2) + + # Enable/Disable ToolTips globally + self.toggle_tooltips_cb = FCCheckBox(label=_('Enable ToolTips')) + self.toggle_tooltips_cb.setToolTip( + _("Check this box if you want to have toolTips displayed\n" + "when hovering with mouse over items throughout the App.") + ) + + grid0.addWidget(self.toggle_tooltips_cb, 32, 0, 1, 2) + + # Machinist settings that allow unsafe settings + self.machinist_cb = FCCheckBox(_("Allow Machinist Unsafe Settings")) + self.machinist_cb.setToolTip( + _("If checked, some of the application settings will be allowed\n" + "to have values that are usually unsafe to use.\n" + "Like Z travel negative values or Z Cut positive values.\n" + "It will applied at the next application start.\n" + "<>: Don't change this unless you know what you are doing !!!") + ) + + grid0.addWidget(self.machinist_cb, 33, 0, 1, 2) + + # Bookmarks Limit in the Help Menu + self.bm_limit_spinner = FCSpinner() + self.bm_limit_spinner.set_range(0, 9999) + self.bm_limit_label = QtWidgets.QLabel('%s:' % _('Bookmarks limit')) + self.bm_limit_label.setToolTip( + _("The maximum number of bookmarks that may be installed in the menu.\n" + "The number of bookmarks in the bookmark manager may be greater\n" + "but the menu will hold only so much.") + ) + + grid0.addWidget(self.bm_limit_label, 34, 0) + grid0.addWidget(self.bm_limit_spinner, 34, 1) + + # Activity monitor icon + self.activity_label = QtWidgets.QLabel('%s:' % _("Activity Icon")) + self.activity_label.setToolTip( + _("Select the GIF that show activity when FlatCAM is active.") + ) + self.activity_combo = FCComboBox() + self.activity_combo.addItems(['Ball black', 'Ball green', 'Arrow green', 'Eclipse green']) + + grid0.addWidget(self.activity_label, 35, 0) + grid0.addWidget(self.activity_combo, 35, 1) + + self.layout.addStretch() + + self.mouse_cursor_color_cb.stateChanged.connect(self.on_mouse_cursor_color_enable) + + self.mouse_cursor_entry.editingFinished.connect(self.on_mouse_cursor_entry) + self.mouse_cursor_button.clicked.connect(self.on_mouse_cursor_button) + + def on_mouse_cursor_color_enable(self, val): + if val: + self.app.cursor_color_3D = self.app.defaults["global_cursor_color"] + else: + theme_settings = QtCore.QSettings("Open Source", "FlatCAM") + if theme_settings.contains("theme"): + theme = theme_settings.value('theme', type=str) + else: + theme = 'white' + + if theme == 'white': + self.app.cursor_color_3D = 'black' + else: + self.app.cursor_color_3D = 'gray' + + def on_mouse_cursor_entry(self): + self.app.defaults['global_cursor_color'] = self.mouse_cursor_entry.get_value() + self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_cursor_color'])) + + self.app.cursor_color_3D = self.app.defaults["global_cursor_color"] + + def on_mouse_cursor_button(self): + current_color = QtGui.QColor(self.app.defaults['global_cursor_color']) + + c_dialog = QtWidgets.QColorDialog() + proj_color = c_dialog.getColor(initial=current_color) + + if proj_color.isValid() is False: + return + + self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(proj_color.name())) + + new_val_sel = str(proj_color.name()) + self.mouse_cursor_entry.set_value(new_val_sel) + self.app.defaults['global_cursor_color'] = new_val_sel + + self.app.cursor_color_3D = self.app.defaults["global_cursor_color"] diff --git a/flatcamGUI/preferences/general/GeneralAppPrefGroupUI.py b/flatcamGUI/preferences/general/GeneralAppPrefGroupUI.py index 4ab4f105..7f238b5f 100644 --- a/flatcamGUI/preferences/general/GeneralAppPrefGroupUI.py +++ b/flatcamGUI/preferences/general/GeneralAppPrefGroupUI.py @@ -1,251 +1,382 @@ import sys + +from PyQt5 import QtWidgets from PyQt5.QtCore import QSettings -from flatcamGUI.GUIElements import OptionalInputSection -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 + +from flatcamGUI.GUIElements import RadioSet, FCSpinner, FCCheckBox, FCComboBox, FCButton, OptionalInputSection, \ + FCDoubleSpinner +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): + +class GeneralAppPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + super(GeneralAppPrefGroupUI, self).__init__(self, parent=parent) + + self.setTitle(_("App Preferences")) self.decimals = decimals - super().__init__(**kwargs) - self.setTitle(str(_("App Preferences"))) - 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)) + # 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('%s:' % _('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('%s:' % _('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('%s:' % _('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('%s' % _('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('%s' % _('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.") + ) qsettings = QSettings("Open Source", "FlatCAM") if qsettings.value("splash_screen"): - self.option_dict()["splash_screen"].get_field().set_value(True) + self.splash_cb.set_value(True) else: - self.option_dict()["splash_screen"].get_field().set_value(False) + self.splash_cb.set_value(False) - 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]) + 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.") + ) + + 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('%s' % _("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.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) - 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_color="red", - 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(), + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 33, 0, 1, 2) - 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_color="red", - 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(), + self.pdf_param_label = QtWidgets.QLabel('%s:' % _("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) - 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(), + # Top Margin value + self.tmargin_entry = FCDoubleSpinner() + self.tmargin_entry.set_precision(self.decimals) + self.tmargin_entry.set_range(0.0000, 9999.9999) - 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(), + self.tmargin_label = QtWidgets.QLabel('%s:' % _("Top Margin")) + self.tmargin_label.setToolTip( + _("Distance between text body and the top of the PDF file.") + ) - 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(), + grid0.addWidget(self.tmargin_label, 35, 0) + grid0.addWidget(self.tmargin_entry, 35, 1) - 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(), + # Bottom Margin value + self.bmargin_entry = FCDoubleSpinner() + self.bmargin_entry.set_precision(self.decimals) + self.bmargin_entry.set_range(0.0000, 9999.9999) - 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 - ) - ] + 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 on_toggle_shell_from_settings(self, state): """ @@ -268,4 +399,4 @@ class GeneralAppPrefGroupUI(OptionsGroupUI2): 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 \ No newline at end of file + del qsettings diff --git a/flatcamGUI/preferences/general/GeneralAppSettingsGroupUI.py b/flatcamGUI/preferences/general/GeneralAppSettingsGroupUI.py deleted file mode 100644 index 1978bd6d..00000000 --- a/flatcamGUI/preferences/general/GeneralAppSettingsGroupUI.py +++ /dev/null @@ -1,301 +0,0 @@ -from PyQt5 import QtCore -from PyQt5.QtCore import QSettings -from flatcamGUI.GUIElements import OptionalInputSection -from flatcamGUI.preferences import settings -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 - - -class GeneralAppSettingsGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - self.pagesize = {} - self.pagesize.update( - { - 'A0': (841, 1189), - 'A1': (594, 841), - 'A2': (420, 594), - 'A3': (297, 420), - 'A4': (210, 297), - 'A5': (148, 210), - 'A6': (105, 148), - 'A7': (74, 105), - 'A8': (52, 74), - 'A9': (37, 52), - 'A10': (26, 37), - - 'B0': (1000, 1414), - 'B1': (707, 1000), - 'B2': (500, 707), - 'B3': (353, 500), - 'B4': (250, 353), - 'B5': (176, 250), - 'B6': (125, 176), - 'B7': (88, 125), - 'B8': (62, 88), - 'B9': (44, 62), - 'B10': (31, 44), - - 'C0': (917, 1297), - 'C1': (648, 917), - 'C2': (458, 648), - 'C3': (324, 458), - 'C4': (229, 324), - 'C5': (162, 229), - 'C6': (114, 162), - 'C7': (81, 114), - 'C8': (57, 81), - 'C9': (40, 57), - 'C10': (28, 40), - - # American paper sizes - 'LETTER': (8.5, 11), - 'LEGAL': (8.5, 14), - 'ELEVENSEVENTEEN': (11, 17), - - # From https://en.wikipedia.org/wiki/Paper_size - 'JUNIOR_LEGAL': (5, 8), - 'HALF_LETTER': (5.5, 8), - 'GOV_LETTER': (8, 10.5), - 'GOV_LEGAL': (8.5, 13), - 'LEDGER': (17, 11), - } - ) - super().__init__(**kwargs) - - self.setTitle(str(_("App Settings"))) - - qsettings = QSettings("Open Source", "FlatCAM") - - self.notebook_font_size_field = self.option_dict()["notebook_font_size"].get_field() - if qsettings.contains("notebook_font_size"): - self.notebook_font_size_field.set_value(qsettings.value('notebook_font_size', type=int)) - else: - self.notebook_font_size_field.set_value(12) - - self.axis_font_size_field = self.option_dict()["axis_font_size"].get_field() - if qsettings.contains("axis_font_size"): - self.axis_font_size_field.set_value(qsettings.value('axis_font_size', type=int)) - else: - self.axis_font_size_field.set_value(8) - - self.textbox_font_size_field = self.option_dict()["textbox_font_size"].get_field() - if qsettings.contains("textbox_font_size"): - self.textbox_font_size_field.set_value(settings.value('textbox_font_size', type=int)) - else: - self.textbox_font_size_field.set_value(10) - - self.workspace_enabled_field = self.option_dict()["global_workspace"].get_field() - self.workspace_type_field = self.option_dict()["global_workspaceT"].get_field() - self.workspace_type_label = self.option_dict()["global_workspaceT"].label_widget - self.workspace_orientation_field = self.option_dict()["global_workspace_orientation"].get_field() - self.workspace_orientation_label = self.option_dict()["global_workspace_orientation"].label_widget - self.wks = OptionalInputSection(self.workspace_enabled_field, [self.workspace_type_label, self.workspace_type_field, self.workspace_orientation_label, self.workspace_orientation_field]) - - self.mouse_cursor_color_enabled_field = self.option_dict()["global_cursor_color_enabled"].get_field() - self.mouse_cursor_color_field = self.option_dict()["global_cursor_color"].get_field() - self.mouse_cursor_color_label = self.option_dict()["global_cursor_color"].label_widget - self.mois = OptionalInputSection(self.mouse_cursor_color_enabled_field, [self.mouse_cursor_color_label, self.mouse_cursor_color_field]) - self.mouse_cursor_color_enabled_field.stateChanged.connect(self.on_mouse_cursor_color_enable) - self.mouse_cursor_color_field.entry.editingFinished.connect(self.on_mouse_cursor_entry) - - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Grid Settings", label_tooltip=None), - DoubleSpinnerOptionUI( - option="global_gridx", - label_text="X value", - label_tooltip="This is the Grid snap value on X axis.", - step=0.1, - decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="global_gridy", - label_text='Y value', - label_tooltip="This is the Grid snap value on Y axis.", - step=0.1, - decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="global_snap_max", - label_text="Snap Max", - label_tooltip="Max. magnet distance", - step=0.1, - decimals=self.decimals - ), - SeparatorOptionUI(), - - HeadingOptionUI(label_text="Workspace Settings", label_tooltip=None), - CheckboxOptionUI( - option="global_workspace", - label_text="Active", - label_tooltip="Draw a delimiting rectangle on canvas.\n" - "The purpose is to illustrate the limits for our work." - ), - ComboboxOptionUI( - option="global_workspaceT", - label_text="Size", - label_tooltip="Select the type of rectangle to be used on canvas,\nas valid workspace.", - choices=list(self.pagesize.keys()) - ), - RadioSetOptionUI( - option="global_workspace_orientation", - label_text="Orientation", - label_tooltip="Can be:\n- Portrait\n- Landscape", - choices=[ - {'label': _('Portrait'), 'value': 'p'}, - {'label': _('Landscape'), 'value': 'l'}, - ] - ), - # FIXME enabling OptionalInputSection ?? - SeparatorOptionUI(), - - HeadingOptionUI(label_text="Font Size", label_tooltip=None), - SpinnerOptionUI( - option="notebook_font_size", - label_text="Notebook", - label_tooltip="This sets the font size for the elements found in the Notebook.\n" - "The notebook is the collapsible area in the left side of the GUI,\n" - "and include the Project, Selected and Tool tabs.", - min_value=8, max_value=40, step=1 - ), - SpinnerOptionUI( - option="axis_font_size", - label_text="Axis", - label_tooltip="This sets the font size for canvas axis.", - min_value=8, max_value=40, step=1 - ), - SpinnerOptionUI( - option="textbox_font_size", - label_text="Textbox", - label_tooltip="This sets the font size for the Textbox GUI\n" - "elements that are used in FlatCAM.", - min_value=8, max_value=40, step=1 - ), - SeparatorOptionUI(), - - HeadingOptionUI(label_text="Mouse Settings", label_tooltip=None), - RadioSetOptionUI( - option="global_cursor_type", - label_text="Cursor Shape", - label_tooltip="Choose a mouse cursor shape.\n" - "- Small -> with a customizable size.\n" - "- Big -> Infinite lines", - choices=[ - {"label": _("Small"), "value": "small"}, - {"label": _("Big"), "value": "big"} - ] - ), - SpinnerOptionUI( - option="global_cursor_size", - label_text="Cursor Size", - label_tooltip="Set the size of the mouse cursor, in pixels.", - min_value=10, max_value=70, step=1 - ), - SpinnerOptionUI( - option="global_cursor_width", - label_text="Cursor Width", - label_tooltip="Set the line width of the mouse cursor, in pixels.", - min_value=1, max_value=10, step=1 - ), - CheckboxOptionUI( - option="global_cursor_color_enabled", - label_text="Cursor Color", - label_tooltip="Check this box to color mouse cursor." - ), - ColorOptionUI( - option="global_cursor_color", - label_text="Cursor Color", - label_tooltip="Set the color of the mouse cursor." - ), - # FIXME enabling of cursor color - RadioSetOptionUI( - option="global_pan_button", - label_text="Pan Button", - label_tooltip="Select the mouse button to use for panning:\n" - "- MMB --> Middle Mouse Button\n" - "- RMB --> Right Mouse Button", - choices=[{'label': _('MMB'), 'value': '3'}, - {'label': _('RMB'), 'value': '2'}] - ), - RadioSetOptionUI( - option="global_mselect_key", - label_text="Multiple Selection", - label_tooltip="Select the key used for multiple selection.", - choices=[{'label': _('CTRL'), 'value': 'Control'}, - {'label': _('SHIFT'), 'value': 'Shift'}] - ), - SeparatorOptionUI(), - - CheckboxOptionUI( - option="global_delete_confirmation", - label_text="Delete object confirmation", - label_tooltip="When checked the application will ask for user confirmation\n" - "whenever the Delete object(s) event is triggered, either by\n" - "menu shortcut or key shortcut." - ), - CheckboxOptionUI( - option="global_open_style", - label_text='"Open" behavior', - label_tooltip="When checked the path for the last saved file is used when saving files,\n" - "and the path for the last opened file is used when opening files.\n\n" - "When unchecked the path for opening files is the one used last: either the\n" - "path for saving files or the path for opening files." - ), - CheckboxOptionUI( - option="global_toggle_tooltips", - label_text="Enable ToolTips", - label_tooltip="Check this box if you want to have toolTips displayed\n" - "when hovering with mouse over items throughout the App." - ), - CheckboxOptionUI( - option="global_machinist_setting", - label_text="Allow Machinist Unsafe Settings", - label_tooltip="If checked, some of the application settings will be allowed\n" - "to have values that are usually unsafe to use.\n" - "Like Z travel negative values or Z Cut positive values.\n" - "It will applied at the next application start.\n" - "<>: Don't change this unless you know what you are doing !!!" - ), - SpinnerOptionUI( - option="global_bookmarks_limit", - label_text="Bookmarks limit", - label_tooltip="The maximum number of bookmarks that may be installed in the menu.\n" - "The number of bookmarks in the bookmark manager may be greater\n" - "but the menu will hold only so much.", - min_value=0, max_value=9999, step=1 - ), - ComboboxOptionUI( - option="global_activity_icon", - label_text="Activity Icon", - label_tooltip="Select the GIF that show activity when FlatCAM is active.", - choices=['Ball black', 'Ball green', 'Arrow green', 'Eclipse green'] - ) - - ] - - def on_mouse_cursor_color_enable(self, val): - if val: - self.app.cursor_color_3D = self.app.defaults["global_cursor_color"] - else: - theme_settings = QtCore.QSettings("Open Source", "FlatCAM") - if theme_settings.contains("theme"): - theme = theme_settings.value('theme', type=str) - else: - theme = 'white' - - if theme == 'white': - self.app.cursor_color_3D = 'black' - else: - self.app.cursor_color_3D = 'gray' - - def on_mouse_cursor_entry(self): - self.app.defaults['global_cursor_color'] = self.mouse_cursor_color_field.get_value() - self.app.cursor_color_3D = self.app.defaults["global_cursor_color"] diff --git a/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py b/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py index 44172641..baedacc7 100644 --- a/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py +++ b/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py @@ -1,187 +1,423 @@ -from PyQt5 import QtWidgets, QtCore -from PyQt5.QtCore import QSettings -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt5.QtCore import QSettings, Qt + +from flatcamGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate import builtins + fcTranslate.apply_language('strings') if '_' not in builtins.__dict__: _ = gettext.gettext -from flatcamGUI.preferences.OptionUI import OptionUI, CheckboxOptionUI, RadioSetOptionUI, \ - SeparatorOptionUI, HeadingOptionUI, ComboboxOptionUI, ColorOptionUI, FullWidthButtonOptionUI, \ - SliderWithSpinnerOptionUI, ColorAlphaSliderOptionUI +settings = QSettings("Open Source", "FlatCAM") +if settings.contains("machinist"): + machinist_setting = settings.value('machinist', type=int) +else: + machinist_setting = 0 -class GeneralGUIPrefGroupUI(OptionsGroupUI2): +class GeneralGUIPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + super(GeneralGUIPrefGroupUI, self).__init__(self, parent=parent) - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) self.setTitle(str(_("GUI Preferences"))) + self.decimals = decimals - self.layout_field = self.option_dict()["layout"].get_field() - self.layout_field.activated.connect(self.on_layout) + # Create a grid layout for the Application general settings + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + grid0.setColumnStretch(0, 0) + grid0.setColumnStretch(1, 1) - self.theme_field = self.option_dict()["global_theme"].get_field() + # Theme selection + self.theme_label = QtWidgets.QLabel('%s:' % _('Theme')) + self.theme_label.setToolTip( + _("Select a theme for FlatCAM.\n" + "It will theme the plot area.") + ) - self.style_field = self.option_dict()["style"].get_field() - current_style_index = self.style_field.findText(QtWidgets.qApp.style().objectName(), QtCore.Qt.MatchFixedString) - self.style_field.setCurrentIndex(current_style_index) - self.style_field.activated[str].connect(self.handle_style) + self.theme_radio = RadioSet([ + {"label": _("Light"), "value": "white"}, + {"label": _("Dark"), "value": "black"} + ], orientation='vertical') + + grid0.addWidget(self.theme_label, 0, 0) + grid0.addWidget(self.theme_radio, 0, 1) + + # Enable Gray Icons + self.gray_icons_cb = FCCheckBox('%s' % _('Use Gray Icons')) + self.gray_icons_cb.setToolTip( + _("Check this box to use a set of icons with\n" + "a lighter (gray) color. To be used when a\n" + "full dark theme is applied.") + ) + grid0.addWidget(self.gray_icons_cb, 1, 0, 1, 3) + + # self.theme_button = FCButton(_("Apply Theme")) + # self.theme_button.setToolTip( + # _("Select a theme for FlatCAM.\n" + # "It will theme the plot area.\n" + # "The application will restart after change.") + # ) + # grid0.addWidget(self.theme_button, 2, 0, 1, 3) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 3, 0, 1, 2) + + # Layout selection + self.layout_label = QtWidgets.QLabel('%s:' % _('Layout')) + self.layout_label.setToolTip( + _("Select an layout for FlatCAM.\n" + "It is applied immediately.") + ) + self.layout_combo = FCComboBox() + # don't translate the QCombo items as they are used in QSettings and identified by name + self.layout_combo.addItem("standard") + self.layout_combo.addItem("compact") + self.layout_combo.addItem("minimal") + + grid0.addWidget(self.layout_label, 4, 0) + grid0.addWidget(self.layout_combo, 4, 1) + + # Set the current index for layout_combo + qsettings = QSettings("Open Source", "FlatCAM") + if qsettings.contains("layout"): + layout = qsettings.value('layout', type=str) + idx = self.layout_combo.findText(layout.capitalize()) + self.layout_combo.setCurrentIndex(idx) + + # Style selection + self.style_label = QtWidgets.QLabel('%s:' % _('Style')) + self.style_label.setToolTip( + _("Select an style for FlatCAM.\n" + "It will be applied at the next app start.") + ) + self.style_combo = FCComboBox() + self.style_combo.addItems(QtWidgets.QStyleFactory.keys()) + # find current style + index = self.style_combo.findText(QtWidgets.qApp.style().objectName(), QtCore.Qt.MatchFixedString) + self.style_combo.setCurrentIndex(index) + self.style_combo.activated[str].connect(self.handle_style) + + grid0.addWidget(self.style_label, 5, 0) + grid0.addWidget(self.style_combo, 5, 1) + + # Enable High DPI Support + self.hdpi_cb = FCCheckBox('%s' % _('Activate HDPI Support')) + self.hdpi_cb.setToolTip( + _("Enable High DPI support for FlatCAM.\n" + "It will be applied at the next app start.") + ) - self.hdpi_field = self.option_dict()["hdpi"].get_field() qsettings = QSettings("Open Source", "FlatCAM") if qsettings.contains("hdpi"): - self.hdpi_field.set_value(qsettings.value('hdpi', type=int)) + self.hdpi_cb.set_value(qsettings.value('hdpi', type=int)) else: - self.hdpi_field.set_value(False) - self.hdpi_field.stateChanged.connect(self.handle_hdpi) + self.hdpi_cb.set_value(False) + self.hdpi_cb.stateChanged.connect(self.handle_hdpi) - def build_options(self) -> [OptionUI]: - return [ - RadioSetOptionUI( - option="global_theme", - label_text="Theme", - label_tooltip="Select a theme for FlatCAM.\nIt will theme the plot area.", - choices=[ - {"label": _("Light"), "value": "white"}, - {"label": _("Dark"), "value": "black"} - ], - orientation='vertical' - ), - CheckboxOptionUI( - option="global_gray_icons", - label_text="Use Gray Icons", - label_tooltip="Check this box to use a set of icons with\na lighter (gray) color. To be used when a\nfull dark theme is applied." - ), - SeparatorOptionUI(), + grid0.addWidget(self.hdpi_cb, 6, 0, 1, 3) - ComboboxOptionUI( - option="layout", - label_text="Layout", - label_tooltip="Select an layout for FlatCAM.\nIt is applied immediately.", - choices=[ - "standard", - "compact", - "minimal" - ] - ), - ComboboxOptionUI( - option="style", - label_text="Style", - label_tooltip="Select an style for FlatCAM.\nIt will be applied at the next app start.", - choices=QtWidgets.QStyleFactory.keys() - ), - CheckboxOptionUI( - option="hdpi", - label_text='Activate HDPI Support', - label_tooltip="Enable High DPI support for FlatCAM.\nIt will be applied at the next app start.", - ), - CheckboxOptionUI( - option="global_hover", - label_text='Display Hover Shape', - label_tooltip="Enable display of a hover shape for FlatCAM objects.\nIt is displayed whenever the mouse cursor is hovering\nover any kind of not-selected object.", - ), - CheckboxOptionUI( - option="global_selection_shape", - label_text='Display Selection Shape', - label_tooltip="Enable the display of a selection shape for FlatCAM objects.\n" - "It is displayed whenever the mouse selects an object\n" - "either by clicking or dragging mouse from left to right or\n" - "right to left." - ), - SeparatorOptionUI(), + # Enable Hover box + self.hover_cb = FCCheckBox('%s' % _('Display Hover Shape')) + self.hover_cb.setToolTip( + _("Enable display of a hover shape for FlatCAM objects.\n" + "It is displayed whenever the mouse cursor is hovering\n" + "over any kind of not-selected object.") + ) + grid0.addWidget(self.hover_cb, 8, 0, 1, 3) - HeadingOptionUI(label_text="Left-Right Selection Color", label_tooltip=None), - ColorOptionUI( - option="global_sel_line", - label_text="Outline", - label_tooltip="Set the line color for the 'left to right' selection box." - ), - ColorOptionUI( - option="global_sel_fill", - label_text="Fill", - label_tooltip="Set the fill color for the selection box\n" - "in case that the selection is done from left to right.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["global_sel_line", "global_sel_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the fill transparency for the 'left to right' selection box." - ), - SeparatorOptionUI(), + # Enable Selection box + self.selection_cb = FCCheckBox('%s' % _('Display Selection Shape')) + self.selection_cb.setToolTip( + _("Enable the display of a selection shape for FlatCAM objects.\n" + "It is displayed whenever the mouse selects an object\n" + "either by clicking or dragging mouse from left to right or\n" + "right to left.") + ) + grid0.addWidget(self.selection_cb, 9, 0, 1, 3) - HeadingOptionUI(label_text="Right-Left Selection Color", label_tooltip=None), - ColorOptionUI( - option="global_alt_sel_line", - label_text="Outline", - label_tooltip="Set the line color for the 'right to left' selection box." - ), - ColorOptionUI( - option="global_alt_sel_fill", - label_text="Fill", - label_tooltip="Set the fill color for the selection box\n" - "in case that the selection is done from right to left.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["global_alt_sel_line", "global_alt_sel_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the fill transparency for the 'right to left' selection box." - ), - SeparatorOptionUI(), + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 14, 0, 1, 2) - HeadingOptionUI(label_text='Editor Color', label_tooltip=None), - ColorOptionUI( - option="global_draw_color", - label_text="Drawing", - label_tooltip="Set the color for the shape." - ), - ColorOptionUI( - option="global_sel_draw_color", - label_text="Selection", - label_tooltip="Set the color of the shape when selected." - ), - SeparatorOptionUI(), + # Plot Selection (left - right) Color + self.sel_lr_label = QtWidgets.QLabel('%s' % _('Left-Right Selection Color')) + grid0.addWidget(self.sel_lr_label, 15, 0, 1, 2) - HeadingOptionUI(label_text='Project Items Color', label_tooltip=None), - ColorOptionUI( - option="global_proj_item_color", - label_text="Enabled", - label_tooltip="Set the color of the items in Project Tab Tree." - ), - ColorOptionUI( - option="global_proj_item_dis_color", - label_text="Disabled", - label_tooltip="Set the color of the items in Project Tab Tree,\n" - "for the case when the items are disabled." - ), - CheckboxOptionUI( - option="global_project_autohide", - label_text="Project AutoHide", - label_tooltip="Check this box if you want the project/selected/tool tab area to\n" - "hide automatically when there are no objects loaded and\n" - "to show whenever a new object is created." - ), - ] + self.sl_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.sl_color_label.setToolTip( + _("Set the line color for the 'left to right' selection box.") + ) + self.sl_color_entry = FCEntry() + self.sl_color_button = QtWidgets.QPushButton() + self.sl_color_button.setFixedSize(15, 15) - def on_layout(self, index=None, lay=None): - if lay: - current_layout = lay - else: - current_layout = self.layout_field.get_value() - self.app.ui.set_layout(current_layout) + self.form_box_child_4 = QtWidgets.QHBoxLayout() + self.form_box_child_4.addWidget(self.sl_color_entry) + self.form_box_child_4.addWidget(self.sl_color_button) + self.form_box_child_4.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.sl_color_label, 16, 0) + grid0.addLayout(self.form_box_child_4, 16, 1) + + self.sf_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.sf_color_label.setToolTip( + _("Set the fill color for the selection box\n" + "in case that the selection is done from left to right.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.sf_color_entry = FCEntry() + self.sf_color_button = QtWidgets.QPushButton() + self.sf_color_button.setFixedSize(15, 15) + + self.form_box_child_5 = QtWidgets.QHBoxLayout() + self.form_box_child_5.addWidget(self.sf_color_entry) + self.form_box_child_5.addWidget(self.sf_color_button) + self.form_box_child_5.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.sf_color_label, 17, 0) + grid0.addLayout(self.form_box_child_5, 17, 1) + + # Plot Selection (left - right) Fill Transparency Level + self.sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha')) + self.sf_alpha_label.setToolTip( + _("Set the fill transparency for the 'left to right' selection box.") + ) + self.sf_color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.sf_color_alpha_slider.setMinimum(0) + self.sf_color_alpha_slider.setMaximum(255) + self.sf_color_alpha_slider.setSingleStep(1) + + self.sf_color_alpha_spinner = FCSpinner() + self.sf_color_alpha_spinner.setMinimumWidth(70) + self.sf_color_alpha_spinner.set_range(0, 255) + + self.form_box_child_6 = QtWidgets.QHBoxLayout() + self.form_box_child_6.addWidget(self.sf_color_alpha_slider) + self.form_box_child_6.addWidget(self.sf_color_alpha_spinner) + + grid0.addWidget(self.sf_alpha_label, 18, 0) + grid0.addLayout(self.form_box_child_6, 18, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 19, 0, 1, 2) + + # Plot Selection (left - right) Color + self.sel_rl_label = QtWidgets.QLabel('%s' % _('Right-Left Selection Color')) + grid0.addWidget(self.sel_rl_label, 20, 0, 1, 2) + + # Plot Selection (right - left) Line Color + self.alt_sl_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.alt_sl_color_label.setToolTip( + _("Set the line color for the 'right to left' selection box.") + ) + self.alt_sl_color_entry = FCEntry() + self.alt_sl_color_button = QtWidgets.QPushButton() + self.alt_sl_color_button.setFixedSize(15, 15) + + self.form_box_child_7 = QtWidgets.QHBoxLayout() + self.form_box_child_7.addWidget(self.alt_sl_color_entry) + self.form_box_child_7.addWidget(self.alt_sl_color_button) + self.form_box_child_7.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.alt_sl_color_label, 21, 0) + grid0.addLayout(self.form_box_child_7, 21, 1) + + # Plot Selection (right - left) Fill Color + self.alt_sf_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.alt_sf_color_label.setToolTip( + _("Set the fill color for the selection box\n" + "in case that the selection is done from right to left.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.alt_sf_color_entry = FCEntry() + self.alt_sf_color_button = QtWidgets.QPushButton() + self.alt_sf_color_button.setFixedSize(15, 15) + + self.form_box_child_8 = QtWidgets.QHBoxLayout() + self.form_box_child_8.addWidget(self.alt_sf_color_entry) + self.form_box_child_8.addWidget(self.alt_sf_color_button) + self.form_box_child_8.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.alt_sf_color_label, 22, 0) + grid0.addLayout(self.form_box_child_8, 22, 1) + + # Plot Selection (right - left) Fill Transparency Level + self.alt_sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha')) + self.alt_sf_alpha_label.setToolTip( + _("Set the fill transparency for selection 'right to left' box.") + ) + self.alt_sf_color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.alt_sf_color_alpha_slider.setMinimum(0) + self.alt_sf_color_alpha_slider.setMaximum(255) + self.alt_sf_color_alpha_slider.setSingleStep(1) + + self.alt_sf_color_alpha_spinner = FCSpinner() + self.alt_sf_color_alpha_spinner.setMinimumWidth(70) + self.alt_sf_color_alpha_spinner.set_range(0, 255) + + self.form_box_child_9 = QtWidgets.QHBoxLayout() + self.form_box_child_9.addWidget(self.alt_sf_color_alpha_slider) + self.form_box_child_9.addWidget(self.alt_sf_color_alpha_spinner) + + grid0.addWidget(self.alt_sf_alpha_label, 23, 0) + grid0.addLayout(self.form_box_child_9, 23, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 24, 0, 1, 2) + + # ------------------------------------------------------------------ + # ----------------------- Editor Color ----------------------------- + # ------------------------------------------------------------------ + + self.editor_color_label = QtWidgets.QLabel('%s' % _('Editor Color')) + grid0.addWidget(self.editor_color_label, 25, 0, 1, 2) + + # Editor Draw Color + self.draw_color_label = QtWidgets.QLabel('%s:' % _('Drawing')) + self.alt_sf_color_label.setToolTip( + _("Set the color for the shape.") + ) + self.draw_color_entry = FCEntry() + self.draw_color_button = QtWidgets.QPushButton() + self.draw_color_button.setFixedSize(15, 15) + + self.form_box_child_10 = QtWidgets.QHBoxLayout() + self.form_box_child_10.addWidget(self.draw_color_entry) + self.form_box_child_10.addWidget(self.draw_color_button) + self.form_box_child_10.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.draw_color_label, 26, 0) + grid0.addLayout(self.form_box_child_10, 26, 1) + + # Editor Draw Selection Color + self.sel_draw_color_label = QtWidgets.QLabel('%s:' % _('Selection')) + self.sel_draw_color_label.setToolTip( + _("Set the color of the shape when selected.") + ) + self.sel_draw_color_entry = FCEntry() + self.sel_draw_color_button = QtWidgets.QPushButton() + self.sel_draw_color_button.setFixedSize(15, 15) + + self.form_box_child_11 = QtWidgets.QHBoxLayout() + self.form_box_child_11.addWidget(self.sel_draw_color_entry) + self.form_box_child_11.addWidget(self.sel_draw_color_button) + self.form_box_child_11.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.sel_draw_color_label, 27, 0) + grid0.addLayout(self.form_box_child_11, 27, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 28, 0, 1, 2) + + # ------------------------------------------------------------------ + # ----------------------- Project Settings ----------------------------- + # ------------------------------------------------------------------ + + self.proj_settings_label = QtWidgets.QLabel('%s' % _('Project Items Color')) + grid0.addWidget(self.proj_settings_label, 29, 0, 1, 2) + + # Project Tab items color + self.proj_color_label = QtWidgets.QLabel('%s:' % _('Enabled')) + self.proj_color_label.setToolTip( + _("Set the color of the items in Project Tab Tree.") + ) + self.proj_color_entry = FCEntry() + self.proj_color_button = QtWidgets.QPushButton() + self.proj_color_button.setFixedSize(15, 15) + + self.form_box_child_12 = QtWidgets.QHBoxLayout() + self.form_box_child_12.addWidget(self.proj_color_entry) + self.form_box_child_12.addWidget(self.proj_color_button) + self.form_box_child_12.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.proj_color_label, 30, 0) + grid0.addLayout(self.form_box_child_12, 30, 1) + + self.proj_color_dis_label = QtWidgets.QLabel('%s:' % _('Disabled')) + self.proj_color_dis_label.setToolTip( + _("Set the color of the items in Project Tab Tree,\n" + "for the case when the items are disabled.") + ) + self.proj_color_dis_entry = FCEntry() + self.proj_color_dis_button = QtWidgets.QPushButton() + self.proj_color_dis_button.setFixedSize(15, 15) + + self.form_box_child_13 = QtWidgets.QHBoxLayout() + self.form_box_child_13.addWidget(self.proj_color_dis_entry) + self.form_box_child_13.addWidget(self.proj_color_dis_button) + self.form_box_child_13.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.proj_color_dis_label, 31, 0) + grid0.addLayout(self.form_box_child_13, 31, 1) + + # Project autohide CB + self.project_autohide_cb = FCCheckBox(label=_('Project AutoHide')) + self.project_autohide_cb.setToolTip( + _("Check this box if you want the project/selected/tool tab area to\n" + "hide automatically when there are no objects loaded and\n" + "to show whenever a new object is created.") + ) + + grid0.addWidget(self.project_autohide_cb, 32, 0, 1, 2) + + # Just to add empty rows + grid0.addWidget(QtWidgets.QLabel(''), 33, 0, 1, 2) + + self.layout.addStretch() + + # ############################################################################# + # ############################# GUI COLORS SIGNALS ############################ + # ############################################################################# + + # Setting selection (left - right) colors signals + self.sf_color_entry.editingFinished.connect(self.on_sf_color_entry) + self.sf_color_button.clicked.connect(self.on_sf_color_button) + self.sf_color_alpha_spinner.valueChanged.connect(self.on_sf_color_spinner) + self.sf_color_alpha_slider.valueChanged.connect(self.on_sf_color_slider) + self.sl_color_entry.editingFinished.connect(self.on_sl_color_entry) + self.sl_color_button.clicked.connect(self.on_sl_color_button) + + # Setting selection (right - left) colors signals + self.alt_sf_color_entry.editingFinished.connect(self.on_alt_sf_color_entry) + self.alt_sf_color_button.clicked.connect(self.on_alt_sf_color_button) + self.alt_sf_color_alpha_spinner.valueChanged.connect(self.on_alt_sf_color_spinner) + self.alt_sf_color_alpha_slider.valueChanged.connect(self.on_alt_sf_color_slider) + self.alt_sl_color_entry.editingFinished.connect(self.on_alt_sl_color_entry) + self.alt_sl_color_button.clicked.connect(self.on_alt_sl_color_button) + + # Setting Editor Draw colors signals + self.draw_color_entry.editingFinished.connect(self.on_draw_color_entry) + self.draw_color_button.clicked.connect(self.on_draw_color_button) + + self.sel_draw_color_entry.editingFinished.connect(self.on_sel_draw_color_entry) + self.sel_draw_color_button.clicked.connect(self.on_sel_draw_color_button) + + self.proj_color_entry.editingFinished.connect(self.on_proj_color_entry) + self.proj_color_button.clicked.connect(self.on_proj_color_button) + + self.proj_color_dis_entry.editingFinished.connect(self.on_proj_color_dis_entry) + self.proj_color_dis_button.clicked.connect(self.on_proj_color_dis_button) + + self.layout_combo.activated.connect(self.on_layout) @staticmethod def handle_style(style): - # FIXME: this should be moved out to a view model # set current style qsettings = QSettings("Open Source", "FlatCAM") qsettings.setValue('style', style) @@ -191,10 +427,349 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI2): @staticmethod def handle_hdpi(state): - # FIXME: this should be moved out to a view model # set current HDPI qsettings = QSettings("Open Source", "FlatCAM") qsettings.setValue('hdpi', state) # This will write the setting to the platform specific storage. - del qsettings \ No newline at end of file + del qsettings + + # Setting selection colors (left - right) handlers + def on_sf_color_entry(self): + self.app.defaults['global_sel_fill'] = self.app.defaults['global_sel_fill'][7:9] + self.sf_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_sel_fill'])[:7]) + + def on_sf_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_sel_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.sf_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['global_sel_fill'][7:9]) + self.sf_color_entry.set_value(new_val) + self.app.defaults['global_sel_fill'] = new_val + + def on_sf_color_spinner(self): + spinner_value = self.sf_color_alpha_spinner.value() + self.sf_color_alpha_slider.setValue(spinner_value) + self.app.defaults['global_sel_fill'] = self.app.defaults['global_sel_fill'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + self.app.defaults['global_sel_line'] = self.app.defaults['global_sel_line'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + + def on_sf_color_slider(self): + slider_value = self.sf_color_alpha_slider.value() + self.sf_color_alpha_spinner.setValue(slider_value) + + def on_sl_color_entry(self): + self.app.defaults['global_sel_line'] = self.sl_color_entry.get_value()[:7] + \ + self.app.defaults['global_sel_line'][7:9] + self.sl_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_sel_line'])[:7]) + + def on_sl_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_sel_line'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.sl_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['global_sel_line'][7:9]) + self.sl_color_entry.set_value(new_val_line) + self.app.defaults['global_sel_line'] = new_val_line + + # Setting selection colors (right - left) handlers + def on_alt_sf_color_entry(self): + self.app.defaults['global_alt_sel_fill'] = self.alt_sf_color_entry.get_value()[:7] + \ + self.app.defaults['global_alt_sel_fill'][7:9] + self.alt_sf_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['global_alt_sel_fill'])[:7] + ) + + def on_alt_sf_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_alt_sel_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.alt_sf_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['global_alt_sel_fill'][7:9]) + self.alt_sf_color_entry.set_value(new_val) + self.app.defaults['global_alt_sel_fill'] = new_val + + def on_alt_sf_color_spinner(self): + spinner_value = self.alt_sf_color_alpha_spinner.value() + self.alt_sf_color_alpha_slider.setValue(spinner_value) + self.app.defaults['global_alt_sel_fill'] = self.app.defaults['global_alt_sel_fill'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + self.app.defaults['global_alt_sel_line'] = self.app.defaults['global_alt_sel_line'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + + def on_alt_sf_color_slider(self): + slider_value = self.alt_sf_color_alpha_slider.value() + self.alt_sf_color_alpha_spinner.setValue(slider_value) + + def on_alt_sl_color_entry(self): + self.app.defaults['global_alt_sel_line'] = self.alt_sl_color_entry.get_value()[:7] + \ + self.app.defaults['global_alt_sel_line'][7:9] + self.alt_sl_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['global_alt_sel_line'])[:7] + ) + + def on_alt_sl_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_alt_sel_line'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.alt_sl_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['global_alt_sel_line'][7:9]) + self.alt_sl_color_entry.set_value(new_val_line) + self.app.defaults['global_alt_sel_line'] = new_val_line + + # Setting Editor colors + def on_draw_color_entry(self): + self.app.defaults['global_draw_color'] = self.draw_color_entry.get_value() + self.draw_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_draw_color'])) + + def on_draw_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_draw_color']) + + c_dialog = QtWidgets.QColorDialog() + draw_color = c_dialog.getColor(initial=current_color) + + if draw_color.isValid() is False: + return + + self.draw_color_button.setStyleSheet("background-color:%s" % str(draw_color.name())) + + new_val = str(draw_color.name()) + self.draw_color_entry.set_value(new_val) + self.app.defaults['global_draw_color'] = new_val + + def on_sel_draw_color_entry(self): + self.app.defaults['global_sel_draw_color'] = self.sel_draw_color_entry.get_value() + self.sel_draw_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['global_sel_draw_color'])) + + def on_sel_draw_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_sel_draw_color']) + + c_dialog = QtWidgets.QColorDialog() + sel_draw_color = c_dialog.getColor(initial=current_color) + + if sel_draw_color.isValid() is False: + return + + self.sel_draw_color_button.setStyleSheet("background-color:%s" % str(sel_draw_color.name())) + + new_val_sel = str(sel_draw_color.name()) + self.sel_draw_color_entry.set_value(new_val_sel) + self.app.defaults['global_sel_draw_color'] = new_val_sel + + def on_proj_color_entry(self): + self.app.defaults['global_proj_item_color'] = self.proj_color_entry.get_value() + self.proj_color_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['global_proj_item_color'])) + + def on_proj_color_button(self): + current_color = QtGui.QColor(self.app.defaults['global_proj_item_color']) + + c_dialog = QtWidgets.QColorDialog() + proj_color = c_dialog.getColor(initial=current_color) + + if proj_color.isValid() is False: + return + + self.proj_color_button.setStyleSheet("background-color:%s" % str(proj_color.name())) + + new_val_sel = str(proj_color.name()) + self.proj_color_entry.set_value(new_val_sel) + self.app.defaults['global_proj_item_color'] = new_val_sel + + def on_proj_color_dis_entry(self): + self.app.defaults['global_proj_item_dis_color'] = self.proj_color_dis_entry.get_value() + self.proj_color_dis_button.setStyleSheet( + "background-color:%s" % str(self.app.defaults['global_proj_item_dis_color'])) + + def on_proj_color_dis_button(self): + current_color = QtGui.QColor(self.app.defaults['global_proj_item_dis_color']) + + c_dialog = QtWidgets.QColorDialog() + proj_color = c_dialog.getColor(initial=current_color) + + if proj_color.isValid() is False: + return + + self.proj_color_dis_button.setStyleSheet("background-color:%s" % str(proj_color.name())) + + new_val_sel = str(proj_color.name()) + self.proj_color_dis_entry.set_value(new_val_sel) + self.app.defaults['global_proj_item_dis_color'] = new_val_sel + + def on_layout(self, index=None, lay=None): + """ + Set the toolbars layout (location) + + :param index: + :param lay: Type of layout to be set on the toolbard + :return: None + """ + + self.app.defaults.report_usage("on_layout()") + if lay: + current_layout = lay + else: + current_layout = self.layout_combo.get_value() + + lay_settings = QSettings("Open Source", "FlatCAM") + lay_settings.setValue('layout', current_layout) + + # This will write the setting to the platform specific storage. + del lay_settings + + # first remove the toolbars: + try: + self.app.ui.removeToolBar(self.app.ui.toolbarfile) + self.app.ui.removeToolBar(self.app.ui.toolbargeo) + self.app.ui.removeToolBar(self.app.ui.toolbarview) + self.app.ui.removeToolBar(self.app.ui.toolbarshell) + self.app.ui.removeToolBar(self.app.ui.toolbartools) + self.app.ui.removeToolBar(self.app.ui.exc_edit_toolbar) + self.app.ui.removeToolBar(self.app.ui.geo_edit_toolbar) + self.app.ui.removeToolBar(self.app.ui.grb_edit_toolbar) + self.app.ui.removeToolBar(self.app.ui.snap_toolbar) + self.app.ui.removeToolBar(self.app.ui.toolbarshell) + except Exception: + pass + + if current_layout == 'compact': + # ## TOOLBAR INSTALLATION # ## + self.app.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') + self.app.ui.toolbarfile.setObjectName('File_TB') + self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbarfile) + + self.app.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') + self.app.ui.toolbargeo.setObjectName('Edit_TB') + self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbargeo) + + self.app.ui.toolbarshell = QtWidgets.QToolBar('Shell Toolbar') + self.app.ui.toolbarshell.setObjectName('Shell_TB') + self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbarshell) + + self.app.ui.toolbartools = QtWidgets.QToolBar('Tools Toolbar') + self.app.ui.toolbartools.setObjectName('Tools_TB') + self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbartools) + + self.app.ui.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') + # self.app.ui.geo_edit_toolbar.setVisible(False) + self.app.ui.geo_edit_toolbar.setObjectName('GeoEditor_TB') + self.app.ui.addToolBar(Qt.RightToolBarArea, self.app.ui.geo_edit_toolbar) + + self.app.ui.toolbarview = QtWidgets.QToolBar('View Toolbar') + self.app.ui.toolbarview.setObjectName('View_TB') + self.app.ui.addToolBar(Qt.RightToolBarArea, self.app.ui.toolbarview) + + self.app.ui.addToolBarBreak(area=Qt.RightToolBarArea) + + self.app.ui.grb_edit_toolbar = QtWidgets.QToolBar('Gerber Editor Toolbar') + # self.app.ui.grb_edit_toolbar.setVisible(False) + self.app.ui.grb_edit_toolbar.setObjectName('GrbEditor_TB') + self.app.ui.addToolBar(Qt.RightToolBarArea, self.app.ui.grb_edit_toolbar) + + self.app.ui.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') + self.app.ui.exc_edit_toolbar.setObjectName('ExcEditor_TB') + self.app.ui.addToolBar(Qt.RightToolBarArea, self.app.ui.exc_edit_toolbar) + + self.app.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') + self.app.ui.snap_toolbar.setObjectName('Snap_TB') + self.app.ui.snap_toolbar.setMaximumHeight(30) + self.app.ui.splitter_left.addWidget(self.app.ui.snap_toolbar) + + self.app.ui.corner_snap_btn.setVisible(True) + self.app.ui.snap_magnet.setVisible(True) + else: + # ## TOOLBAR INSTALLATION # ## + self.app.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') + self.app.ui.toolbarfile.setObjectName('File_TB') + self.app.ui.addToolBar(self.app.ui.toolbarfile) + + self.app.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') + self.app.ui.toolbargeo.setObjectName('Edit_TB') + self.app.ui.addToolBar(self.app.ui.toolbargeo) + + self.app.ui.toolbarview = QtWidgets.QToolBar('View Toolbar') + self.app.ui.toolbarview.setObjectName('View_TB') + self.app.ui.addToolBar(self.app.ui.toolbarview) + + self.app.ui.toolbarshell = QtWidgets.QToolBar('Shell Toolbar') + self.app.ui.toolbarshell.setObjectName('Shell_TB') + self.app.ui.addToolBar(self.app.ui.toolbarshell) + + self.app.ui.toolbartools = QtWidgets.QToolBar('Tools Toolbar') + self.app.ui.toolbartools.setObjectName('Tools_TB') + self.app.ui.addToolBar(self.app.ui.toolbartools) + + self.app.ui.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') + # self.app.ui.exc_edit_toolbar.setVisible(False) + self.app.ui.exc_edit_toolbar.setObjectName('ExcEditor_TB') + self.app.ui.addToolBar(self.app.ui.exc_edit_toolbar) + + self.app.ui.addToolBarBreak() + + self.app.ui.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') + # self.app.ui.geo_edit_toolbar.setVisible(False) + self.app.ui.geo_edit_toolbar.setObjectName('GeoEditor_TB') + self.app.ui.addToolBar(self.app.ui.geo_edit_toolbar) + + self.app.ui.grb_edit_toolbar = QtWidgets.QToolBar('Gerber Editor Toolbar') + # self.app.ui.grb_edit_toolbar.setVisible(False) + self.app.ui.grb_edit_toolbar.setObjectName('GrbEditor_TB') + self.app.ui.addToolBar(self.app.ui.grb_edit_toolbar) + + self.app.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') + self.app.ui.snap_toolbar.setObjectName('Snap_TB') + # self.app.ui.snap_toolbar.setMaximumHeight(30) + self.app.ui.addToolBar(self.app.ui.snap_toolbar) + + self.app.ui.corner_snap_btn.setVisible(False) + self.app.ui.snap_magnet.setVisible(False) + + if current_layout == 'minimal': + self.app.ui.toolbarview.setVisible(False) + self.app.ui.toolbarshell.setVisible(False) + self.app.ui.snap_toolbar.setVisible(False) + self.app.ui.geo_edit_toolbar.setVisible(False) + self.app.ui.grb_edit_toolbar.setVisible(False) + self.app.ui.exc_edit_toolbar.setVisible(False) + self.app.ui.lock_toolbar(lock=True) + + # add all the actions to the toolbars + self.app.ui.populate_toolbars() + + # reconnect all the signals to the toolbar actions + self.app.connect_toolbar_signals() + + self.app.ui.grid_snap_btn.setChecked(True) + self.app.ui.on_grid_snap_triggered(state=True) + + self.app.ui.grid_gap_x_entry.setText(str(self.app.defaults["global_gridx"])) + self.app.ui.grid_gap_y_entry.setText(str(self.app.defaults["global_gridy"])) + self.app.ui.snap_max_dist_entry.setText(str(self.app.defaults["global_snap_max"])) + self.app.ui.grid_gap_link_cb.setChecked(True) diff --git a/flatcamGUI/preferences/general/GeneralPreferencesUI.py b/flatcamGUI/preferences/general/GeneralPreferencesUI.py index c88d7362..46636438 100644 --- a/flatcamGUI/preferences/general/GeneralPreferencesUI.py +++ b/flatcamGUI/preferences/general/GeneralPreferencesUI.py @@ -1,25 +1,43 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.general.GeneralAppPrefGroupUI import GeneralAppPrefGroupUI -from flatcamGUI.preferences.general.GeneralAppSettingsGroupUI import GeneralAppSettingsGroupUI +from flatcamGUI.preferences.general.GeneralAPPSetGroupUI import GeneralAPPSetGroupUI from flatcamGUI.preferences.general.GeneralGUIPrefGroupUI import GeneralGUIPrefGroupUI +import gettext +import FlatCAMTranslation as fcTranslate +import builtins -class GeneralPreferencesUI(PreferencesSectionUI): +fcTranslate.apply_language('strings') +if '_' not in builtins.__dict__: + _ = gettext.gettext - def __init__(self, decimals, **kwargs): +settings = QSettings("Open Source", "FlatCAM") +if settings.contains("machinist"): + machinist_setting = settings.value('machinist', type=int) +else: + machinist_setting = 0 + + +class GeneralPreferencesUI(QtWidgets.QWidget): + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals - super().__init__(**kwargs) - def build_groups(self) -> [OptionsGroupUI]: - return [ - GeneralAppPrefGroupUI(decimals=self.decimals), - GeneralGUIPrefGroupUI(decimals=self.decimals), - GeneralAppSettingsGroupUI(decimals=self.decimals) - ] + self.general_app_group = GeneralAppPrefGroupUI(decimals=self.decimals) + self.general_app_group.setMinimumWidth(250) - def get_tab_id(self): - return "general_tab" + self.general_gui_group = GeneralGUIPrefGroupUI(decimals=self.decimals) + self.general_gui_group.setMinimumWidth(250) - def get_tab_label(self): - return _("General") + self.general_app_set_group = GeneralAPPSetGroupUI(decimals=self.decimals) + self.general_app_set_group.setMinimumWidth(250) + + self.layout.addWidget(self.general_app_group) + self.layout.addWidget(self.general_gui_group) + self.layout.addWidget(self.general_app_set_group) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/geometry/GeometryAdvOptPrefGroupUI.py b/flatcamGUI/preferences/geometry/GeometryAdvOptPrefGroupUI.py index 57993400..7ade9b90 100644 --- a/flatcamGUI/preferences/geometry/GeometryAdvOptPrefGroupUI.py +++ b/flatcamGUI/preferences/geometry/GeometryAdvOptPrefGroupUI.py @@ -1,150 +1,246 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCEntry, FloatEntry, FCDoubleSpinner, FCCheckBox, RadioSet, FCLabel +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 GeometryAdvOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GeometryAdvOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Geometry Advanced Options Preferences", parent=parent) + super(GeometryAdvOptPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Geometry Adv. Options"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Advanced Options", - label_tooltip="A list of Geometry advanced parameters.\n" - "Those parameters are available only for\n" - "Advanced App. Level." - ), - LineEntryOptionUI( - option="geometry_toolchangexy", - label_text="Toolchange X-Y", - label_tooltip="Toolchange X,Y position." - ), - FloatEntryOptionUI( - option="geometry_startz", - label_text="Start Z", - label_tooltip="Height of the tool just after starting the work.\n" - "Delete the value if you don't need this feature." - ), - DoubleSpinnerOptionUI( - option="geometry_feedrate_rapid", - label_text="Feedrate Rapids", - label_tooltip="Cutting speed in the XY plane\n" - "(in units per minute).\n" - "This is for the rapid move G00.\n" - "It is useful only for Marlin,\n" - "ignore for any other cases.", - min_value=0, max_value=99999.9999, step=10, decimals=self.decimals - ), - CheckboxOptionUI( - option="geometry_extracut", - label_text="Re-cut", - label_tooltip="In order to remove possible\n" - "copper leftovers where first cut\n" - "meet with last cut, we generate an\n" - "extended cut over the first cut section." - ), - DoubleSpinnerOptionUI( - option="geometry_extracut_length", - label_text="Re-cut length", - label_tooltip="In order to remove possible\n" - "copper leftovers where first cut\n" - "meet with last cut, we generate an\n" - "extended cut over the first cut section.", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="geometry_z_pdepth", - label_text="Probe Z depth", - label_tooltip="The maximum depth that the probe is allowed\n" - "to probe. Negative value, in current units.", - min_value=-99999, max_value=0.0, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="geometry_feedrate_probe", - label_text="Feedrate Probe", - label_tooltip="The feedrate used while the probe is probing.", - min_value=0, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - RadioSetOptionUI( - option="geometry_spindledir", - label_text="Spindle direction", - label_tooltip="This sets the direction that the spindle is rotating.\n" - "It can be either:\n" - "- CW = clockwise or\n" - "- CCW = counter clockwise", - choices=[{'label': _('CW'), 'value': 'CW'}, - {'label': _('CCW'), 'value': 'CCW'}] - ), - CheckboxOptionUI( - option="geometry_f_plunge", - label_text="Fast Plunge", - label_tooltip="By checking this, the vertical move from\n" - "Z_Toolchange to Z_move is done with G0,\n" - "meaning the fastest speed available.\n" - "WARNING: the move is done at Toolchange X,Y coords." - ), - DoubleSpinnerOptionUI( - option="geometry_segx", - label_text="Segment X size", - label_tooltip="The size of the trace segment on the X axis.\n" - "Useful for auto-leveling.\n" - "A value of 0 means no segmentation on the X axis.", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="geometry_segy", - label_text="Segment Y size", - label_tooltip="The size of the trace segment on the Y axis.\n" - "Useful for auto-leveling.\n" - "A value of 0 means no segmentation on the Y axis.", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals - ), + # ------------------------------ + # ## Advanced Options + # ------------------------------ + self.geo_label = QtWidgets.QLabel('%s:' % _('Advanced Options')) + self.geo_label.setToolTip( + _("A list of Geometry advanced parameters.\n" + "Those parameters are available only for\n" + "Advanced App. Level.") + ) + self.layout.addWidget(self.geo_label) - HeadingOptionUI( - label_text="Area Exclusion", - label_tooltip="Area exclusion parameters.\n" - "Those parameters are available only for\n" - "Advanced App. Level." - ), - CheckboxOptionUI( - option="geometry_area_exclusion", - label_text="Exclusion areas", - label_tooltip="Include exclusion areas.\n" - "In those areas the travel of the tools\n" - "is forbidden." - ), - RadioSetOptionUI( - option="geometry_area_shape", - label_text="Shape", - label_tooltip="The kind of selection shape used for area selection.", - choices=[{'label': _("Square"), 'value': 'square'}, - {'label': _("Polygon"), 'value': 'polygon'}] - ), - RadioSetOptionUI( - option="geometry_area_strategy", - label_text="Strategy", - label_tooltip="The strategy followed when encountering an exclusion area.\n" - "Can be:\n" - "- Over -> when encountering the area, the tool will go to a set height\n" - "- Around -> will avoid the exclusion area by going around the area", - choices=[{'label': _('Over'), 'value': 'over'}, - {'label': _('Around'), 'value': 'around'}] - ), - DoubleSpinnerOptionUI( - option="geometry_area_overz", - label_text="Over Z", - label_tooltip="The height Z to which the tool will rise in order to avoid\n" - "an interdiction area.", - min_value=0.0, max_value=9999.9999, step=0.5, decimals=self.decimals + grid1 = QtWidgets.QGridLayout() + self.layout.addLayout(grid1) + + # Toolchange X,Y + toolchange_xy_label = QtWidgets.QLabel('%s:' % _('Toolchange X-Y')) + toolchange_xy_label.setToolTip( + _("Toolchange X,Y position.") + ) + grid1.addWidget(toolchange_xy_label, 1, 0) + self.toolchangexy_entry = FCEntry() + grid1.addWidget(self.toolchangexy_entry, 1, 1) + + # Start move Z + startzlabel = QtWidgets.QLabel('%s:' % _('Start Z')) + startzlabel.setToolTip( + _("Height of the tool just after starting the work.\n" + "Delete the value if you don't need this feature.") + ) + grid1.addWidget(startzlabel, 2, 0) + self.gstartz_entry = FloatEntry() + grid1.addWidget(self.gstartz_entry, 2, 1) + + # Feedrate rapids + fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids')) + fr_rapid_label.setToolTip( + _("Cutting speed in the XY plane\n" + "(in units per minute).\n" + "This is for the rapid move G00.\n" + "It is useful only for Marlin,\n" + "ignore for any other cases.") + ) + self.feedrate_rapid_entry = FCDoubleSpinner() + self.feedrate_rapid_entry.set_range(0, 99999.9999) + self.feedrate_rapid_entry.set_precision(self.decimals) + self.feedrate_rapid_entry.setSingleStep(0.1) + self.feedrate_rapid_entry.setWrapping(True) + + grid1.addWidget(fr_rapid_label, 4, 0) + grid1.addWidget(self.feedrate_rapid_entry, 4, 1) + + # End move extra cut + self.extracut_cb = FCCheckBox('%s' % _('Re-cut')) + self.extracut_cb.setToolTip( + _("In order to remove possible\n" + "copper leftovers where first cut\n" + "meet with last cut, we generate an\n" + "extended cut over the first cut section.") + ) + + self.e_cut_entry = FCDoubleSpinner() + self.e_cut_entry.set_range(0, 99999) + self.e_cut_entry.set_precision(self.decimals) + self.e_cut_entry.setSingleStep(0.1) + self.e_cut_entry.setWrapping(True) + self.e_cut_entry.setToolTip( + _("In order to remove possible\n" + "copper leftovers where first cut\n" + "meet with last cut, we generate an\n" + "extended cut over the first cut section.") + ) + grid1.addWidget(self.extracut_cb, 5, 0) + grid1.addWidget(self.e_cut_entry, 5, 1) + + # Probe depth + self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth")) + self.pdepth_label.setToolTip( + _("The maximum depth that the probe is allowed\n" + "to probe. Negative value, in current units.") + ) + self.pdepth_entry = FCDoubleSpinner() + self.pdepth_entry.set_range(-99999, 0.0000) + self.pdepth_entry.set_precision(self.decimals) + self.pdepth_entry.setSingleStep(0.1) + self.pdepth_entry.setWrapping(True) + + grid1.addWidget(self.pdepth_label, 6, 0) + grid1.addWidget(self.pdepth_entry, 6, 1) + + # Probe feedrate + self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe")) + self.feedrate_probe_label.setToolTip( + _("The feedrate used while the probe is probing.") + ) + self.feedrate_probe_entry = FCDoubleSpinner() + self.feedrate_probe_entry.set_range(0, 99999.9999) + self.feedrate_probe_entry.set_precision(self.decimals) + self.feedrate_probe_entry.setSingleStep(0.1) + self.feedrate_probe_entry.setWrapping(True) + + grid1.addWidget(self.feedrate_probe_label, 7, 0) + grid1.addWidget(self.feedrate_probe_entry, 7, 1) + + # Spindle direction + spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle direction')) + spindle_dir_label.setToolTip( + _("This sets the direction that the spindle is rotating.\n" + "It can be either:\n" + "- CW = clockwise or\n" + "- CCW = counter clockwise") + ) + + self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + grid1.addWidget(spindle_dir_label, 8, 0) + grid1.addWidget(self.spindledir_radio, 8, 1) + + # Fast Move from Z Toolchange + self.fplunge_cb = FCCheckBox('%s' % _('Fast Plunge')) + self.fplunge_cb.setToolTip( + _("By checking this, the vertical move from\n" + "Z_Toolchange to Z_move is done with G0,\n" + "meaning the fastest speed available.\n" + "WARNING: the move is done at Toolchange X,Y coords.") + ) + grid1.addWidget(self.fplunge_cb, 9, 0, 1, 2) + + # Size of trace segment on X axis + segx_label = QtWidgets.QLabel('%s:' % _("Segment X size")) + segx_label.setToolTip( + _("The size of the trace segment on the X axis.\n" + "Useful for auto-leveling.\n" + "A value of 0 means no segmentation on the X axis.") + ) + self.segx_entry = FCDoubleSpinner() + self.segx_entry.set_range(0, 99999) + self.segx_entry.set_precision(self.decimals) + self.segx_entry.setSingleStep(0.1) + self.segx_entry.setWrapping(True) + + grid1.addWidget(segx_label, 10, 0) + grid1.addWidget(self.segx_entry, 10, 1) + + # Size of trace segment on Y axis + segy_label = QtWidgets.QLabel('%s:' % _("Segment Y size")) + segy_label.setToolTip( + _("The size of the trace segment on the Y axis.\n" + "Useful for auto-leveling.\n" + "A value of 0 means no segmentation on the Y axis.") + ) + self.segy_entry = FCDoubleSpinner() + self.segy_entry.set_range(0, 99999) + self.segy_entry.set_precision(self.decimals) + self.segy_entry.setSingleStep(0.1) + self.segy_entry.setWrapping(True) + + grid1.addWidget(segy_label, 11, 0) + grid1.addWidget(self.segy_entry, 11, 1) + + # ----------------------------- + # --- Area Exclusion ---------- + # ----------------------------- + self.adv_label = QtWidgets.QLabel('%s:' % _('Area Exclusion')) + self.adv_label.setToolTip( + _("Area exclusion parameters.\n" + "Those parameters are available only for\n" + "Advanced App. Level.") + ) + grid1.addWidget(self.adv_label, 12, 0, 1, 2) + + # Exclusion Area CB + self.exclusion_cb = FCCheckBox('%s:' % _("Exclusion areas")) + self.exclusion_cb.setToolTip( + _( + "Include exclusion areas.\n" + "In those areas the travel of the tools\n" + "is forbidden." ) - ] + ) + grid1.addWidget(self.exclusion_cb, 13, 0, 1, 2) + + # Area Selection shape + self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape")) + self.area_shape_label.setToolTip( + _("The kind of selection shape used for area selection.") + ) + + self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'}, + {'label': _("Polygon"), 'value': 'polygon'}]) + + grid1.addWidget(self.area_shape_label, 14, 0) + grid1.addWidget(self.area_shape_radio, 14, 1) + + # Chose Strategy + self.strategy_label = FCLabel('%s:' % _("Strategy")) + self.strategy_label.setToolTip(_("The strategy followed when encountering an exclusion area.\n" + "Can be:\n" + "- Over -> when encountering the area, the tool will go to a set height\n" + "- Around -> will avoid the exclusion area by going around the area")) + self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'}, + {'label': _('Around'), 'value': 'around'}]) + + grid1.addWidget(self.strategy_label, 15, 0) + grid1.addWidget(self.strategy_radio, 15, 1) + + # Over Z + self.over_z_label = FCLabel('%s:' % _("Over Z")) + self.over_z_label.setToolTip(_("The height Z to which the tool will rise in order to avoid\n" + "an interdiction area.")) + self.over_z_entry = FCDoubleSpinner() + self.over_z_entry.set_range(0.000, 9999.9999) + self.over_z_entry.set_precision(self.decimals) + + grid1.addWidget(self.over_z_label, 18, 0) + grid1.addWidget(self.over_z_entry, 18, 1) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/geometry/GeometryEditorPrefGroupUI.py b/flatcamGUI/preferences/geometry/GeometryEditorPrefGroupUI.py index fe861c34..9c5204ab 100644 --- a/flatcamGUI/preferences/geometry/GeometryEditorPrefGroupUI.py +++ b/flatcamGUI/preferences/geometry/GeometryEditorPrefGroupUI.py @@ -1,41 +1,67 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCSpinner, RadioSet +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 GeometryEditorPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GeometryEditorPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Gerber Adv. Options Preferences", parent=parent) + super(GeometryEditorPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Geometry Editor"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Parameters"), - SpinnerOptionUI( - option="geometry_editor_sel_limit", - label_text="Selection limit", - label_tooltip="Set the number of selected geometry\n" - "items above which the utility geometry\n" - "becomes just a selection rectangle.\n" - "Increases the performance when moving a\n" - "large number of geometric elements.", - min_value=0, max_value=9999, step=1 - ), - RadioSetOptionUI( - option="geometry_editor_milling_type", - label_text="Milling Type", - label_tooltip="Milling type:\n" - "- climb / best for precision milling and to reduce tool usage\n" - "- conventional / useful when there is no backlash compensation", - choices=[{'label': _('Climb'), 'value': 'cl'}, - {'label': _('Conventional'), 'value': 'cv'}] - ) - ] \ No newline at end of file + # Advanced Geometry Parameters + self.param_label = QtWidgets.QLabel("%s:" % _("Parameters")) + self.param_label.setToolTip( + _("A list of Geometry Editor parameters.") + ) + self.layout.addWidget(self.param_label) + + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + + # Selection Limit + self.sel_limit_label = QtWidgets.QLabel('%s:' % _("Selection limit")) + self.sel_limit_label.setToolTip( + _("Set the number of selected geometry\n" + "items above which the utility geometry\n" + "becomes just a selection rectangle.\n" + "Increases the performance when moving a\n" + "large number of geometric elements.") + ) + self.sel_limit_entry = FCSpinner() + self.sel_limit_entry.set_range(0, 9999) + + grid0.addWidget(self.sel_limit_label, 0, 0) + grid0.addWidget(self.sel_limit_entry, 0, 1) + + # Milling Type + milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type')) + milling_type_label.setToolTip( + _("Milling type:\n" + "- climb / best for precision milling and to reduce tool usage\n" + "- conventional / useful when there is no backlash compensation") + ) + self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'}, + {'label': _('Conventional'), 'value': 'cv'}]) + grid0.addWidget(milling_type_label, 1, 0) + grid0.addWidget(self.milling_type_radio, 1, 1) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/geometry/GeometryGenPrefGroupUI.py b/flatcamGUI/preferences/geometry/GeometryGenPrefGroupUI.py index 1e800702..60479236 100644 --- a/flatcamGUI/preferences/geometry/GeometryGenPrefGroupUI.py +++ b/flatcamGUI/preferences/geometry/GeometryGenPrefGroupUI.py @@ -1,5 +1,8 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCCheckBox, FCSpinner, FCEntry +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate @@ -9,46 +12,112 @@ 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 GeometryGenPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GeometryGenPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Geometry General Preferences", parent=parent) + super(GeometryGenPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Geometry General"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Plot Options"), - CheckboxOptionUI( - option="geometry_plot", - label_text="Plot", - label_tooltip="Plot (show) this object." - ), - SpinnerOptionUI( - option="geometry_circle_steps", - label_text="Circle Steps", - label_tooltip="The number of circle steps for Geometry \n" - "circle and arc shapes linear approximation.", - min_value=0, max_value=9999, step=1 - ), - HeadingOptionUI(label_text="Tools"), - LineEntryOptionUI( - option="geometry_cnctooldia", - label_text="Tools Dia", - label_color="green", - label_bold=True, - label_tooltip="Diameters of the tools, separated by comma.\n" - "The value of the diameter has to use the dot decimals separator.\n" - "Valid values: 0.3, 1.0" - ), - SeparatorOptionUI(), + # ## Plot options + self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options")) + self.layout.addWidget(self.plot_options_label) - HeadingOptionUI(label_text="Geometry Object Color"), - ColorOptionUI( - option="geometry_plot_line", - label_text="Outline", + # Plot CB + self.plot_cb = FCCheckBox(label=_('Plot')) + self.plot_cb.setToolTip( + _("Plot (show) this object.") + ) + self.layout.addWidget(self.plot_cb) - label_tooltip="Set the line color for plotted objects.", - ), - ] + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) + grid0.setColumnStretch(0, 0) + grid0.setColumnStretch(1, 1) + + # Number of circle steps for circular aperture linear approximation + self.circle_steps_label = QtWidgets.QLabel('%s:' % _("Circle Steps")) + self.circle_steps_label.setToolTip( + _("The number of circle steps for Geometry \n" + "circle and arc shapes linear approximation.") + ) + self.circle_steps_entry = FCSpinner() + self.circle_steps_entry.set_range(0, 999) + + grid0.addWidget(self.circle_steps_label, 1, 0) + grid0.addWidget(self.circle_steps_entry, 1, 1) + + # Tools + self.tools_label = QtWidgets.QLabel("%s:" % _("Tools")) + grid0.addWidget(self.tools_label, 2, 0, 1, 2) + + # Tooldia + tdlabel = QtWidgets.QLabel('%s:' % _('Tools Dia')) + tdlabel.setToolTip( + _("Diameters of the tools, separated by comma.\n" + "The value of the diameter has to use the dot decimals separator.\n" + "Valid values: 0.3, 1.0") + ) + self.cnctooldia_entry = FCEntry() + + grid0.addWidget(tdlabel, 3, 0) + grid0.addWidget(self.cnctooldia_entry, 3, 1) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 9, 0, 1, 2) + + # Geometry Object Color + self.gerber_color_label = QtWidgets.QLabel('%s' % _('Geometry Object Color')) + grid0.addWidget(self.gerber_color_label, 10, 0, 1, 2) + + # Plot Line Color + self.line_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.line_color_label.setToolTip( + _("Set the line color for plotted objects.") + ) + self.line_color_entry = FCEntry() + self.line_color_button = QtWidgets.QPushButton() + self.line_color_button.setFixedSize(15, 15) + + self.form_box_child_2 = QtWidgets.QHBoxLayout() + self.form_box_child_2.addWidget(self.line_color_entry) + self.form_box_child_2.addWidget(self.line_color_button) + self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.line_color_label, 11, 0) + grid0.addLayout(self.form_box_child_2, 11, 1) + + self.layout.addStretch() + + # Setting plot colors signals + self.line_color_entry.editingFinished.connect(self.on_line_color_entry) + self.line_color_button.clicked.connect(self.on_line_color_button) + + def on_line_color_entry(self): + self.app.defaults['geometry_plot_line'] = self.line_color_entry.get_value()[:7] + 'FF' + self.line_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['geometry_plot_line'])[:7]) + + def on_line_color_button(self): + current_color = QtGui.QColor(self.app.defaults['geometry_plot_line'][:7]) + # print(current_color) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['geometry_plot_line'][7:9]) + self.line_color_entry.set_value(new_val_line) diff --git a/flatcamGUI/preferences/geometry/GeometryOptPrefGroupUI.py b/flatcamGUI/preferences/geometry/GeometryOptPrefGroupUI.py index 102a9273..c2e0f6e2 100644 --- a/flatcamGUI/preferences/geometry/GeometryOptPrefGroupUI.py +++ b/flatcamGUI/preferences/geometry/GeometryOptPrefGroupUI.py @@ -1,13 +1,14 @@ -from PyQt5.QtCore import QSettings +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt, QSettings -from flatcamGUI.GUIElements import OptionalInputSection +from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCEntry, FCSpinner, FCComboBox from flatcamGUI.preferences import machinist_setting -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate import builtins + fcTranslate.apply_language('strings') if '_' not in builtins.__dict__: _ = gettext.gettext @@ -19,135 +20,246 @@ else: machinist_setting = 0 -class GeometryOptPrefGroupUI(OptionsGroupUI2): +class GeometryOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Geometry Options Preferences", parent=parent) + super(GeometryOptPrefGroupUI, self).__init__(self, parent=parent) - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) self.setTitle(str(_("Geometry Options"))) - self.pp_geometry_name_cb = self.option_dict()["geometry_ppname_g"].get_field() + self.decimals = decimals + + # ------------------------------ + # ## Create CNC Job + # ------------------------------ + self.cncjob_label = QtWidgets.QLabel('%s:' % _('Create CNC Job')) + self.cncjob_label.setToolTip( + _("Create a CNC Job object\n" + "tracing the contours of this\n" + "Geometry object.") + ) + self.layout.addWidget(self.cncjob_label) + + grid1 = QtWidgets.QGridLayout() + self.layout.addLayout(grid1) + grid1.setColumnStretch(0, 0) + grid1.setColumnStretch(1, 1) + + # Cut Z + cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + cutzlabel.setToolTip( + _("Cutting depth (negative)\n" + "below the copper surface.") + ) + self.cutz_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.cutz_entry.set_range(-9999.9999, 0.0000) + else: + self.cutz_entry.set_range(-9999.9999, 9999.9999) + + self.cutz_entry.set_precision(self.decimals) + self.cutz_entry.setSingleStep(0.1) + self.cutz_entry.setWrapping(True) + + grid1.addWidget(cutzlabel, 0, 0) + grid1.addWidget(self.cutz_entry, 0, 1) + + # Multidepth CheckBox + self.multidepth_cb = FCCheckBox(label=_('Multi-Depth')) + self.multidepth_cb.setToolTip( + _( + "Use multiple passes to limit\n" + "the cut depth in each pass. Will\n" + "cut multiple times until Cut Z is\n" + "reached." + ) + ) + grid1.addWidget(self.multidepth_cb, 1, 0) + + # Depth/pass + dplabel = QtWidgets.QLabel('%s:' % _('Depth/Pass')) + dplabel.setToolTip( + _("The depth to cut on each pass,\n" + "when multidepth is enabled.\n" + "It has positive value although\n" + "it is a fraction from the depth\n" + "which has negative value.") + ) + + self.depthperpass_entry = FCDoubleSpinner() + self.depthperpass_entry.set_range(0, 99999) + self.depthperpass_entry.set_precision(self.decimals) + self.depthperpass_entry.setSingleStep(0.1) + self.depthperpass_entry.setWrapping(True) + + grid1.addWidget(dplabel, 2, 0) + grid1.addWidget(self.depthperpass_entry, 2, 1) - self.multidepth_cb = self.option_dict()["geometry_multidepth"].get_field() - self.depthperpass_entry = self.option_dict()["geometry_depthperpass"].get_field() self.ois_multidepth = OptionalInputSection(self.multidepth_cb, [self.depthperpass_entry]) - self.dwell_cb = self.option_dict()["geometry_dwell"].get_field() - self.dwelltime_entry = self.option_dict()["geometry_dwelltime"].get_field() + # Travel Z + travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) + travelzlabel.setToolTip( + _("Height of the tool when\n" + "moving without cutting.") + ) + self.travelz_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.travelz_entry.set_range(0.0001, 9999.9999) + else: + self.travelz_entry.set_range(-9999.9999, 9999.9999) + + self.travelz_entry.set_precision(self.decimals) + self.travelz_entry.setSingleStep(0.1) + self.travelz_entry.setWrapping(True) + + grid1.addWidget(travelzlabel, 3, 0) + grid1.addWidget(self.travelz_entry, 3, 1) + + # Tool change: + self.toolchange_cb = FCCheckBox('%s' % _("Tool change")) + self.toolchange_cb.setToolTip( + _( + "Include tool-change sequence\n" + "in the Machine Code (Pause for tool change)." + ) + ) + grid1.addWidget(self.toolchange_cb, 4, 0, 1, 2) + + # Toolchange Z + toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z')) + toolchangezlabel.setToolTip( + _( + "Z-axis position (height) for\n" + "tool change." + ) + ) + self.toolchangez_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.toolchangez_entry.set_range(0.000, 9999.9999) + else: + self.toolchangez_entry.set_range(-9999.9999, 9999.9999) + + self.toolchangez_entry.set_precision(self.decimals) + self.toolchangez_entry.setSingleStep(0.1) + self.toolchangez_entry.setWrapping(True) + + grid1.addWidget(toolchangezlabel, 5, 0) + grid1.addWidget(self.toolchangez_entry, 5, 1) + + # End move Z + endz_label = QtWidgets.QLabel('%s:' % _('End move Z')) + endz_label.setToolTip( + _("Height of the tool after\n" + "the last move at the end of the job.") + ) + self.endz_entry = FCDoubleSpinner() + + if machinist_setting == 0: + self.endz_entry.set_range(0.000, 9999.9999) + else: + self.endz_entry.set_range(-9999.9999, 9999.9999) + + self.endz_entry.set_precision(self.decimals) + self.endz_entry.setSingleStep(0.1) + self.endz_entry.setWrapping(True) + + grid1.addWidget(endz_label, 6, 0) + grid1.addWidget(self.endz_entry, 6, 1) + + # End Move X,Y + endmove_xy_label = QtWidgets.QLabel('%s:' % _('End move X,Y')) + endmove_xy_label.setToolTip( + _("End move X,Y position. In format (x,y).\n" + "If no value is entered then there is no move\n" + "on X,Y plane at the end of the job.") + ) + self.endxy_entry = FCEntry() + + grid1.addWidget(endmove_xy_label, 7, 0) + grid1.addWidget(self.endxy_entry, 7, 1) + + # Feedrate X-Y + frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y')) + frlabel.setToolTip( + _("Cutting speed in the XY\n" + "plane in units per minute") + ) + self.cncfeedrate_entry = FCDoubleSpinner() + self.cncfeedrate_entry.set_range(0, 99999.9999) + self.cncfeedrate_entry.set_precision(self.decimals) + self.cncfeedrate_entry.setSingleStep(0.1) + self.cncfeedrate_entry.setWrapping(True) + + grid1.addWidget(frlabel, 8, 0) + grid1.addWidget(self.cncfeedrate_entry, 8, 1) + + # Feedrate Z (Plunge) + frz_label = QtWidgets.QLabel('%s:' % _('Feedrate Z')) + frz_label.setToolTip( + _("Cutting speed in the XY\n" + "plane in units per minute.\n" + "It is called also Plunge.") + ) + self.feedrate_z_entry = FCDoubleSpinner() + self.feedrate_z_entry.set_range(0, 99999.9999) + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.setSingleStep(0.1) + self.feedrate_z_entry.setWrapping(True) + + grid1.addWidget(frz_label, 9, 0) + grid1.addWidget(self.feedrate_z_entry, 9, 1) + + # Spindle Speed + spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed')) + spdlabel.setToolTip( + _( + "Speed of the spindle in RPM (optional).\n" + "If LASER preprocessor is used,\n" + "this value is the power of laser." + ) + ) + self.cncspindlespeed_entry = FCSpinner() + self.cncspindlespeed_entry.set_range(0, 1000000) + self.cncspindlespeed_entry.set_step(100) + + grid1.addWidget(spdlabel, 10, 0) + grid1.addWidget(self.cncspindlespeed_entry, 10, 1) + + # Dwell + self.dwell_cb = FCCheckBox(label='%s' % _('Enable Dwell')) + self.dwell_cb.setToolTip( + _("Pause to allow the spindle to reach its\n" + "speed before cutting.") + ) + dwelltime = QtWidgets.QLabel('%s:' % _('Duration')) + dwelltime.setToolTip( + _("Number of time units for spindle to dwell.") + ) + self.dwelltime_entry = FCDoubleSpinner() + self.dwelltime_entry.set_range(0, 99999) + self.dwelltime_entry.set_precision(self.decimals) + self.dwelltime_entry.setSingleStep(0.1) + self.dwelltime_entry.setWrapping(True) + + grid1.addWidget(self.dwell_cb, 11, 0) + grid1.addWidget(dwelltime, 12, 0) + grid1.addWidget(self.dwelltime_entry, 12, 1) + self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry]) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Create CNC Job", - label_tooltip="Create a CNC Job object\n" - "tracing the contours of this\n" - "Geometry object." - ), - DoubleSpinnerOptionUI( - option="geometry_cutz", - label_text="Cut Z", - label_tooltip="Cutting depth (negative)\n" - "below the copper surface.", - min_value=-9999.9999, max_value=(9999.999 if machinist_setting else 0.0), - decimals=self.decimals, step=0.1 - ), - CheckboxOptionUI( - option="geometry_multidepth", - label_text="Multi-Depth", - label_tooltip="Use multiple passes to limit\n" - "the cut depth in each pass. Will\n" - "cut multiple times until Cut Z is\n" - "reached." - ), - DoubleSpinnerOptionUI( - option="geometry_depthperpass", - label_text="Depth/Pass", - label_tooltip="The depth to cut on each pass,\n" - "when multidepth is enabled.\n" - "It has positive value although\n" - "it is a fraction from the depth\n" - "which has negative value.", - min_value=0, max_value=99999, step=0.1, decimals=self.decimals + # preprocessor selection + pp_label = QtWidgets.QLabel('%s:' % _("Preprocessor")) + pp_label.setToolTip( + _("The Preprocessor file that dictates\n" + "the Machine Code (like GCode, RML, HPGL) output.") + ) + self.pp_geometry_name_cb = FCComboBox() + self.pp_geometry_name_cb.setFocusPolicy(Qt.StrongFocus) - ), - DoubleSpinnerOptionUI( - option="geometry_travelz", - label_text="Travel Z", - label_tooltip="Height of the tool when\n" - "moving without cutting.", - min_value=(-9999.9999 if machinist_setting else 0.0001), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - CheckboxOptionUI( - option="geometry_toolchange", - label_text="Tool change", - label_tooltip="Include tool-change sequence\n" - "in the Machine Code (Pause for tool change)." - ), - DoubleSpinnerOptionUI( - option="geometry_toolchangez", - label_text="Toolchange Z", - label_tooltip="Z-axis position (height) for\n" - "tool change.", - min_value=(-9999.9999 if machinist_setting else 0.0), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="geometry_endz", - label_text="End move Z", - label_tooltip="Height of the tool after\n" - "the last move at the end of the job.", - min_value=(-9999.9999 if machinist_setting else 0.0), max_value=9999.9999, - step=0.1, decimals=self.decimals - ), - LineEntryOptionUI( - option="geometry_endxy", - label_text="End move X,Y", - label_tooltip="End move X,Y position. In format (x,y).\n" - "If no value is entered then there is no move\n" - "on X,Y plane at the end of the job." - ), - DoubleSpinnerOptionUI( - option="geometry_feedrate", - label_text="Feedrate X-Y", - label_tooltip="Cutting speed in the XY\n" - "plane in units per minute", - min_value=0, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="geometry_feedrate_z", - label_text="Feedrate Z", - label_tooltip="Cutting speed in the XY\n" - "plane in units per minute.\n" - "It is called also Plunge.", - min_value=0, max_value=99999.9999, step=0.1, decimals=self.decimals - ), - SpinnerOptionUI( - option="geometry_spindlespeed", - label_text="Spindle speed", - label_tooltip="Speed of the spindle in RPM (optional).\n" - "If LASER preprocessor is used,\n" - "this value is the power of laser.", - min_value=0, max_value=1000000, step=100 - ), - CheckboxOptionUI( - option="geometry_dwell", - label_text="Enable Dwell", - label_tooltip="Pause to allow the spindle to reach its\n" - "speed before cutting." - ), - DoubleSpinnerOptionUI( - option="geometry_dwelltime", - label_text="Duration", - label_tooltip="Number of time units for spindle to dwell.", - min_value=0, max_value=999999, step=0.5, decimals=self.decimals - ), - ComboboxOptionUI( - option="geometry_ppname_g", - label_text="Preprocessor", - label_tooltip="The Preprocessor file that dictates\n" - "the Machine Code (like GCode, RML, HPGL) output.", - choices=[] # Populated in App (FIXME) - ) - ] + grid1.addWidget(pp_label, 13, 0) + grid1.addWidget(self.pp_geometry_name_cb, 13, 1) + self.layout.addStretch() diff --git a/flatcamGUI/preferences/geometry/GeometryPreferencesUI.py b/flatcamGUI/preferences/geometry/GeometryPreferencesUI.py index 643b606d..cf906d61 100644 --- a/flatcamGUI/preferences/geometry/GeometryPreferencesUI.py +++ b/flatcamGUI/preferences/geometry/GeometryPreferencesUI.py @@ -1,5 +1,6 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.geometry.GeometryEditorPrefGroupUI import GeometryEditorPrefGroupUI from flatcamGUI.preferences.geometry.GeometryAdvOptPrefGroupUI import GeometryAdvOptPrefGroupUI from flatcamGUI.preferences.geometry.GeometryOptPrefGroupUI import GeometryOptPrefGroupUI @@ -8,30 +9,38 @@ from flatcamGUI.preferences.geometry.GeometryGenPrefGroupUI import GeometryGenPr 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 GeometryPreferencesUI(PreferencesSectionUI): - def __init__(self, decimals, **kwargs): +class GeometryPreferencesUI(QtWidgets.QWidget): + + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals - # FIXME: remove the need for external access to geometry_opt_group + + self.geometry_gen_group = GeometryGenPrefGroupUI(decimals=self.decimals) + self.geometry_gen_group.setMinimumWidth(220) self.geometry_opt_group = GeometryOptPrefGroupUI(decimals=self.decimals) - super().__init__(**kwargs) + self.geometry_opt_group.setMinimumWidth(300) + self.geometry_adv_opt_group = GeometryAdvOptPrefGroupUI(decimals=self.decimals) + self.geometry_adv_opt_group.setMinimumWidth(270) + self.geometry_editor_group = GeometryEditorPrefGroupUI(decimals=self.decimals) + self.geometry_editor_group.setMinimumWidth(250) - def build_groups(self) -> [OptionsGroupUI]: - return [ - GeometryGenPrefGroupUI(decimals=self.decimals), - self.geometry_opt_group, - GeometryAdvOptPrefGroupUI(decimals=self.decimals), - GeometryEditorPrefGroupUI(decimals=self.decimals) - ] - - def get_tab_id(self): - return "geometry_tab" - - def get_tab_label(self): - return _("GEOMETRY") + self.layout.addWidget(self.geometry_gen_group) + self.layout.addWidget(self.geometry_opt_group) + self.layout.addWidget(self.geometry_adv_opt_group) + self.layout.addWidget(self.geometry_editor_group) + self.layout.addStretch() diff --git a/flatcamGUI/preferences/gerber/GerberAdvOptPrefGroupUI.py b/flatcamGUI/preferences/gerber/GerberAdvOptPrefGroupUI.py index af9f28c8..20376bfd 100644 --- a/flatcamGUI/preferences/gerber/GerberAdvOptPrefGroupUI.py +++ b/flatcamGUI/preferences/gerber/GerberAdvOptPrefGroupUI.py @@ -1,6 +1,8 @@ -from flatcamGUI.GUIElements import OptionalInputSection -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCCheckBox, RadioSet, FCDoubleSpinner, FCSpinner, OptionalInputSection +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate @@ -10,113 +12,175 @@ 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 GerberAdvOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GerberAdvOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Gerber Adv. Options Preferences", parent=parent) + super(GerberAdvOptPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Gerber Adv. Options"))) + self.decimals = decimals - self.simplify_cb = self.option_dict()["gerber_simplification"].get_field() - self.simplification_tol_label = self.option_dict()["gerber_simp_tolerance"].label_widget - self.simplification_tol_spinner = self.option_dict()["gerber_simp_tolerance"].get_field() - self.ois_simplif = OptionalInputSection(self.simplify_cb, [self.simplification_tol_label, self.simplification_tol_spinner], logic=True) + # ## Advanced Gerber Parameters + self.adv_param_label = QtWidgets.QLabel('%s:' % _('Advanced Options')) + self.adv_param_label.setToolTip( + _("A list of Gerber advanced parameters.\n" + "Those parameters are available only for\n" + "Advanced App. Level.") + ) + self.layout.addWidget(self.adv_param_label) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Advanced Options", - label_tooltip="A list of Gerber advanced parameters.\n" - "Those parameters are available only for\n" - "Advanced App. Level." - ), - CheckboxOptionUI( - option="gerber_follow", - label_text='"Follow"', - label_tooltip="Generate a 'Follow' geometry.\n" - "This means that it will cut through\n" - "the middle of the trace." - ), - CheckboxOptionUI( - option="gerber_aperture_display", - label_text="Table Show/Hide", - label_tooltip="Toggle the display of the Gerber Apertures Table.\n" - "Also, on hide, it will delete all mark shapes\n" - "that are drawn on canvas." - ), - SeparatorOptionUI(), + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) - RadioSetOptionUI( - option="gerber_tool_type", - label_text="Tool Type", - label_bold=True, - label_tooltip="Choose which tool to use for Gerber isolation:\n" - "'Circular' or 'V-shape'.\n" - "When the 'V-shape' is selected then the tool\n" - "diameter will depend on the chosen cut depth.", - choices=[{'label': 'Circular', 'value': 'circular'}, - {'label': 'V-Shape', 'value': 'v'}] - ), - DoubleSpinnerOptionUI( - option="gerber_vtipdia", - label_text="V-Tip Dia", - label_tooltip="The tip diameter for V-Shape Tool", - min_value=-99.9999, max_value=99.9999, step=0.1, decimals=self.decimals - ), - SpinnerOptionUI( - option="gerber_vtipangle", - label_text="V-Tip Angle", - label_tooltip="The tip angle for V-Shape Tool.\n" - "In degrees.", - min_value=1, max_value=180, step=5 - ), - DoubleSpinnerOptionUI( - option="gerber_vcutz", - label_text="Cut Z", - label_tooltip="Cutting depth (negative)\n" - "below the copper surface.", - min_value=-99.9999, max_value=0.0000, step=0.1, decimals=self.decimals - ), + # Follow Attribute + self.follow_cb = FCCheckBox(label=_('"Follow"')) + self.follow_cb.setToolTip( + _("Generate a 'Follow' geometry.\n" + "This means that it will cut through\n" + "the middle of the trace.") + ) + grid0.addWidget(self.follow_cb, 0, 0, 1, 2) - RadioSetOptionUI( - option="gerber_iso_type", - label_text="Isolation Type", - label_tooltip="Choose how the isolation will be executed:\n" - "- 'Full' -> complete isolation of polygons\n" - "- 'Ext' -> will isolate only on the outside\n" - "- 'Int' -> will isolate only on the inside\n" - "'Exterior' isolation is almost always possible\n" - "(with the right tool) but 'Interior'\n" - "isolation can be done only when there is an opening\n" - "inside of the polygon (e.g polygon is a 'doughnut' shape).", - choices=[{'label': _('Full'), 'value': 'full'}, - {'label': _('Exterior'), 'value': 'ext'}, - {'label': _('Interior'), 'value': 'int'}] - ), - SeparatorOptionUI(), + # Aperture Table Visibility CB + self.aperture_table_visibility_cb = FCCheckBox(label=_('Table Show/Hide')) + self.aperture_table_visibility_cb.setToolTip( + _("Toggle the display of the Gerber Apertures Table.\n" + "Also, on hide, it will delete all mark shapes\n" + "that are drawn on canvas.") - RadioSetOptionUI( - option="gerber_buffering", - label_text="Buffering", - label_tooltip="Buffering type:\n" - "- None --> best performance, fast file loading but no so good display\n" - "- Full --> slow file loading but good visuals. This is the default.\n" - "<>: Don't change this unless you know what you are doing !!!", - choices=[{'label': _('None'), 'value': 'no'}, - {'label': _('Full'), 'value': 'full'}] - ), - CheckboxOptionUI( - option="gerber_simplification", - label_text="Simplify", - label_tooltip="When checked all the Gerber polygons will be\n" - "loaded with simplification having a set tolerance.\n" - "<>: Don't change this unless you know what you are doing !!!" - ), - DoubleSpinnerOptionUI( - option="gerber_simp_tolerance", - label_text="Tolerance", - label_tooltip="Tolerance for polygon simplification.", - min_value=0.0, max_value=0.01, step=0.0001, decimals=self.decimals+1 - ) - ] \ No newline at end of file + ) + grid0.addWidget(self.aperture_table_visibility_cb, 1, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 2, 0, 1, 2) + + # Tool Type + self.tool_type_label = QtWidgets.QLabel('%s' % _('Tool Type')) + self.tool_type_label.setToolTip( + _("Choose which tool to use for Gerber isolation:\n" + "'Circular' or 'V-shape'.\n" + "When the 'V-shape' is selected then the tool\n" + "diameter will depend on the chosen cut depth.") + ) + self.tool_type_radio = RadioSet([{'label': 'Circular', 'value': 'circular'}, + {'label': 'V-Shape', 'value': 'v'}]) + + grid0.addWidget(self.tool_type_label, 3, 0) + grid0.addWidget(self.tool_type_radio, 3, 1, 1, 2) + + # Tip Dia + self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia')) + self.tipdialabel.setToolTip( + _("The tip diameter for V-Shape Tool") + ) + self.tipdia_spinner = FCDoubleSpinner() + self.tipdia_spinner.set_precision(self.decimals) + self.tipdia_spinner.set_range(-99.9999, 99.9999) + self.tipdia_spinner.setSingleStep(0.1) + self.tipdia_spinner.setWrapping(True) + grid0.addWidget(self.tipdialabel, 4, 0) + grid0.addWidget(self.tipdia_spinner, 4, 1, 1, 2) + + # Tip Angle + self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle')) + self.tipanglelabel.setToolTip( + _("The tip angle for V-Shape Tool.\n" + "In degree.") + ) + self.tipangle_spinner = FCSpinner() + self.tipangle_spinner.set_range(1, 180) + self.tipangle_spinner.set_step(5) + self.tipangle_spinner.setWrapping(True) + grid0.addWidget(self.tipanglelabel, 5, 0) + grid0.addWidget(self.tipangle_spinner, 5, 1, 1, 2) + + # Cut Z + self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + self.cutzlabel.setToolTip( + _("Cutting depth (negative)\n" + "below the copper surface.") + ) + self.cutz_spinner = FCDoubleSpinner() + self.cutz_spinner.set_precision(self.decimals) + self.cutz_spinner.set_range(-99.9999, 0.0000) + self.cutz_spinner.setSingleStep(0.1) + self.cutz_spinner.setWrapping(True) + + grid0.addWidget(self.cutzlabel, 6, 0) + grid0.addWidget(self.cutz_spinner, 6, 1, 1, 2) + + # Isolation Type + self.iso_type_label = QtWidgets.QLabel('%s:' % _('Isolation Type')) + self.iso_type_label.setToolTip( + _("Choose how the isolation will be executed:\n" + "- 'Full' -> complete isolation of polygons\n" + "- 'Ext' -> will isolate only on the outside\n" + "- 'Int' -> will isolate only on the inside\n" + "'Exterior' isolation is almost always possible\n" + "(with the right tool) but 'Interior'\n" + "isolation can be done only when there is an opening\n" + "inside of the polygon (e.g polygon is a 'doughnut' shape).") + ) + self.iso_type_radio = RadioSet([{'label': _('Full'), 'value': 'full'}, + {'label': _('Exterior'), 'value': 'ext'}, + {'label': _('Interior'), 'value': 'int'}]) + + grid0.addWidget(self.iso_type_label, 7, 0,) + grid0.addWidget(self.iso_type_radio, 7, 1, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 8, 0, 1, 2) + + # Buffering Type + buffering_label = QtWidgets.QLabel('%s:' % _('Buffering')) + buffering_label.setToolTip( + _("Buffering type:\n" + "- None --> best performance, fast file loading but no so good display\n" + "- Full --> slow file loading but good visuals. This is the default.\n" + "<>: Don't change this unless you know what you are doing !!!") + ) + self.buffering_radio = RadioSet([{'label': _('None'), 'value': 'no'}, + {'label': _('Full'), 'value': 'full'}]) + grid0.addWidget(buffering_label, 9, 0) + grid0.addWidget(self.buffering_radio, 9, 1) + + # Simplification + self.simplify_cb = FCCheckBox(label=_('Simplify')) + self.simplify_cb.setToolTip( + _("When checked all the Gerber polygons will be\n" + "loaded with simplification having a set tolerance.\n" + "<>: Don't change this unless you know what you are doing !!!") + ) + grid0.addWidget(self.simplify_cb, 10, 0, 1, 2) + + # Simplification tolerance + self.simplification_tol_label = QtWidgets.QLabel(_('Tolerance')) + self.simplification_tol_label.setToolTip(_("Tolerance for polygon simplification.")) + + self.simplification_tol_spinner = FCDoubleSpinner() + self.simplification_tol_spinner.set_precision(self.decimals + 1) + self.simplification_tol_spinner.setWrapping(True) + self.simplification_tol_spinner.setRange(0.00000, 0.01000) + self.simplification_tol_spinner.setSingleStep(0.0001) + + grid0.addWidget(self.simplification_tol_label, 11, 0) + grid0.addWidget(self.simplification_tol_spinner, 11, 1) + self.ois_simplif = OptionalInputSection( + self.simplify_cb, + [ + self.simplification_tol_label, self.simplification_tol_spinner + ], + logic=True) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/gerber/GerberEditorPrefGroupUI.py b/flatcamGUI/preferences/gerber/GerberEditorPrefGroupUI.py index 2b9bd49e..3ba0da99 100644 --- a/flatcamGUI/preferences/gerber/GerberEditorPrefGroupUI.py +++ b/flatcamGUI/preferences/gerber/GerberEditorPrefGroupUI.py @@ -1,138 +1,247 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, FCComboBox, FCEntry, RadioSet +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 GerberEditorPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GerberEditorPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Gerber Adv. Options Preferences", parent=parent) + super(GerberEditorPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Gerber Editor"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Parameters", - label_tooltip="A list of Gerber Editor parameters." - ), - SpinnerOptionUI( - option="gerber_editor_sel_limit", - label_text="Selection limit", - label_tooltip="Set the number of selected Gerber geometry\n" - "items above which the utility geometry\n" - "becomes just a selection rectangle.\n" - "Increases the performance when moving a\n" - "large number of geometric elements.", - min_value=0, max_value=9999, step=1 - ), - SpinnerOptionUI( - option="gerber_editor_newcode", - label_text="New Aperture code", - label_tooltip="Code for the new aperture", - min_value=10, max_value=99, step=1 - ), - DoubleSpinnerOptionUI( - option="gerber_editor_newsize", - label_text="New Aperture size", - label_tooltip="Size for the new aperture", - min_value=0.0, max_value=100.0, step=0.1, decimals=self.decimals - ), - ComboboxOptionUI( - option="gerber_editor_newtype", - label_text="New Aperture type", - label_tooltip="Type for the new aperture.\n" - "Can be 'C', 'R' or 'O'.", - choices=['C', 'R', 'O'] - ), - SpinnerOptionUI( - option="gerber_editor_array_size", - label_text="Nr of pads", - label_tooltip="Specify how many pads to be in the array.", - min_value=0, max_value=9999, step=1 - ), - LineEntryOptionUI( - option="gerber_editor_newdim", - label_text="Aperture Dimensions", - label_tooltip="Diameters of the tools, separated by comma.\n" - "The value of the diameter has to use the dot decimals separator.\n" - "Valid values: 0.3, 1.0" - ), + # Advanced Gerber Parameters + self.param_label = QtWidgets.QLabel("%s:" % _("Parameters")) + self.param_label.setToolTip( + _("A list of Gerber Editor parameters.") + ) + self.layout.addWidget(self.param_label) - HeadingOptionUI(label_text="Linear Pad Array"), - RadioSetOptionUI( - option="gerber_editor_lin_axis", - label_text="Linear Direction", - label_tooltip="Direction on which the linear array is oriented:\n" - "- 'X' - horizontal axis \n" - "- 'Y' - vertical axis or \n" - "- 'Angle' - a custom angle for the array inclination", - choices=[{'label': _('X'), 'value': 'X'}, - {'label': _('Y'), 'value': 'Y'}, - {'label': _('Angle'), 'value': 'A'}] - ), - DoubleSpinnerOptionUI( - option="gerber_editor_lin_pitch", - label_text="Pitch", - label_tooltip="Pitch = Distance between elements of the array.", - min_value=-9999.99, max_value=9999.99, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="gerber_editor_lin_angle", - label_text="Angle", - label_tooltip="Angle at which each element in circular array is placed.", # FIXME: this seems wrong - min_value=-360, max_value=360, step=5, decimals=self.decimals - ), + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) - HeadingOptionUI(label_text="Circular Pad Array"), - RadioSetOptionUI( - option="gerber_editor_circ_dir", - label_text="Circular Direction", - label_tooltip="Direction for circular array.\n" - "Can be CW = clockwise or CCW = counter clockwise.", - choices=[{'label': _('CW'), 'value': 'CW'}, - {'label': _('CCW'), 'value': 'CCW'}] - ), - DoubleSpinnerOptionUI( - option="gerber_editor_circ_angle", - label_text="Circular Angle", - label_tooltip="Angle at which each element in circular array is placed.", - min_value=-360, max_value=360, step=5, decimals=self.decimals - ), + # Selection Limit + self.sel_limit_label = QtWidgets.QLabel('%s:' % _("Selection limit")) + self.sel_limit_label.setToolTip( + _("Set the number of selected Gerber geometry\n" + "items above which the utility geometry\n" + "becomes just a selection rectangle.\n" + "Increases the performance when moving a\n" + "large number of geometric elements.") + ) + self.sel_limit_entry = FCSpinner() + self.sel_limit_entry.set_range(0, 9999) - HeadingOptionUI(label_text="Buffer Tool"), - DoubleSpinnerOptionUI( - option="gerber_editor_buff_f", - label_text="Buffer distance", - label_tooltip="Distance at which to buffer the Gerber element.", - min_value=-9999, max_value=9999, step=0.1, decimals=self.decimals - ), + grid0.addWidget(self.sel_limit_label, 0, 0) + grid0.addWidget(self.sel_limit_entry, 0, 1) - HeadingOptionUI(label_text="Scale Tool"), - DoubleSpinnerOptionUI( - option="gerber_editor_scale_f", - label_text="Scale factor", - label_tooltip="Factor to scale the Gerber element.", - min_value=0, max_value=9999, step=0.1, decimals=self.decimals - ), + # New aperture code + self.addcode_entry_lbl = QtWidgets.QLabel('%s:' % _('New Aperture code')) + self.addcode_entry_lbl.setToolTip( + _("Code for the new aperture") + ) - HeadingOptionUI(label_text="Mark Area Tool"), - DoubleSpinnerOptionUI( - option="gerber_editor_ma_low", - label_text="Threshold low", - label_tooltip="Threshold value under which the apertures are not marked.", - min_value=0, max_value=9999, step=0.1, decimals=self.decimals - ), - DoubleSpinnerOptionUI( - option="gerber_editor_ma_high", - label_text="Threshold high", - label_tooltip="Threshold value over which the apertures are not marked.", - min_value=0, max_value=9999, step=0.1, decimals=self.decimals - ) - ] + self.addcode_entry = FCSpinner() + self.addcode_entry.set_range(10, 99) + self.addcode_entry.setWrapping(True) + + grid0.addWidget(self.addcode_entry_lbl, 1, 0) + grid0.addWidget(self.addcode_entry, 1, 1) + + # New aperture size + self.addsize_entry_lbl = QtWidgets.QLabel('%s:' % _('New Aperture size')) + self.addsize_entry_lbl.setToolTip( + _("Size for the new aperture") + ) + + self.addsize_entry = FCDoubleSpinner() + self.addsize_entry.set_range(0, 100) + self.addsize_entry.set_precision(self.decimals) + + grid0.addWidget(self.addsize_entry_lbl, 2, 0) + grid0.addWidget(self.addsize_entry, 2, 1) + + # New aperture type + self.addtype_combo_lbl = QtWidgets.QLabel('%s:' % _('New Aperture type')) + self.addtype_combo_lbl.setToolTip( + _("Type for the new aperture.\n" + "Can be 'C', 'R' or 'O'.") + ) + + self.addtype_combo = FCComboBox() + self.addtype_combo.addItems(['C', 'R', 'O']) + + grid0.addWidget(self.addtype_combo_lbl, 3, 0) + grid0.addWidget(self.addtype_combo, 3, 1) + + # Number of pads in a pad array + self.grb_array_size_label = QtWidgets.QLabel('%s:' % _('Nr of pads')) + self.grb_array_size_label.setToolTip( + _("Specify how many pads to be in the array.") + ) + + self.grb_array_size_entry = FCSpinner() + self.grb_array_size_entry.set_range(0, 9999) + + grid0.addWidget(self.grb_array_size_label, 4, 0) + grid0.addWidget(self.grb_array_size_entry, 4, 1) + + self.adddim_label = QtWidgets.QLabel('%s:' % _('Aperture Dimensions')) + self.adddim_label.setToolTip( + _("Diameters of the tools, separated by comma.\n" + "The value of the diameter has to use the dot decimals separator.\n" + "Valid values: 0.3, 1.0") + ) + grid0.addWidget(self.adddim_label, 5, 0) + self.adddim_entry = FCEntry() + grid0.addWidget(self.adddim_entry, 5, 1) + + self.grb_array_linear_label = QtWidgets.QLabel('%s:' % _('Linear Pad Array')) + grid0.addWidget(self.grb_array_linear_label, 6, 0, 1, 2) + + # Linear Pad Array direction + self.grb_axis_label = QtWidgets.QLabel('%s:' % _('Linear Direction')) + self.grb_axis_label.setToolTip( + _("Direction on which the linear array is oriented:\n" + "- 'X' - horizontal axis \n" + "- 'Y' - vertical axis or \n" + "- 'Angle' - a custom angle for the array inclination") + ) + + self.grb_axis_radio = RadioSet([{'label': _('X'), 'value': 'X'}, + {'label': _('Y'), 'value': 'Y'}, + {'label': _('Angle'), 'value': 'A'}]) + + grid0.addWidget(self.grb_axis_label, 7, 0) + grid0.addWidget(self.grb_axis_radio, 7, 1) + + # Linear Pad Array pitch distance + self.grb_pitch_label = QtWidgets.QLabel('%s:' % _('Pitch')) + self.grb_pitch_label.setToolTip( + _("Pitch = Distance between elements of the array.") + ) + # self.drill_pitch_label.setMinimumWidth(100) + self.grb_pitch_entry = FCDoubleSpinner() + self.grb_pitch_entry.set_precision(self.decimals) + + grid0.addWidget(self.grb_pitch_label, 8, 0) + grid0.addWidget(self.grb_pitch_entry, 8, 1) + + # Linear Pad Array custom angle + self.grb_angle_label = QtWidgets.QLabel('%s:' % _('Angle')) + self.grb_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.grb_angle_entry = FCDoubleSpinner() + self.grb_angle_entry.set_precision(self.decimals) + self.grb_angle_entry.set_range(-360, 360) + self.grb_angle_entry.setSingleStep(5) + + grid0.addWidget(self.grb_angle_label, 9, 0) + grid0.addWidget(self.grb_angle_entry, 9, 1) + + self.grb_array_circ_label = QtWidgets.QLabel('%s:' % _('Circular Pad Array')) + grid0.addWidget(self.grb_array_circ_label, 10, 0, 1, 2) + + # Circular Pad Array direction + self.grb_circular_direction_label = QtWidgets.QLabel('%s:' % _('Circular Direction')) + self.grb_circular_direction_label.setToolTip( + _("Direction for circular array.\n" + "Can be CW = clockwise or CCW = counter clockwise.") + ) + + self.grb_circular_dir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'}, + {'label': _('CCW'), 'value': 'CCW'}]) + + grid0.addWidget(self.grb_circular_direction_label, 11, 0) + grid0.addWidget(self.grb_circular_dir_radio, 11, 1) + + # Circular Pad Array Angle + self.grb_circular_angle_label = QtWidgets.QLabel('%s:' % _('Circular Angle')) + self.grb_circular_angle_label.setToolTip( + _("Angle at which each element in circular array is placed.") + ) + self.grb_circular_angle_entry = FCDoubleSpinner() + self.grb_circular_angle_entry.set_precision(self.decimals) + self.grb_circular_angle_entry.set_range(-360, 360) + + self.grb_circular_angle_entry.setSingleStep(5) + + grid0.addWidget(self.grb_circular_angle_label, 12, 0) + grid0.addWidget(self.grb_circular_angle_entry, 12, 1) + + self.grb_array_tools_b_label = QtWidgets.QLabel('%s:' % _('Buffer Tool')) + grid0.addWidget(self.grb_array_tools_b_label, 13, 0, 1, 2) + + # Buffer Distance + self.grb_buff_label = QtWidgets.QLabel('%s:' % _('Buffer distance')) + self.grb_buff_label.setToolTip( + _("Distance at which to buffer the Gerber element.") + ) + self.grb_buff_entry = FCDoubleSpinner() + self.grb_buff_entry.set_precision(self.decimals) + self.grb_buff_entry.set_range(-9999, 9999) + + grid0.addWidget(self.grb_buff_label, 14, 0) + grid0.addWidget(self.grb_buff_entry, 14, 1) + + self.grb_array_tools_s_label = QtWidgets.QLabel('%s:' % _('Scale Tool')) + grid0.addWidget(self.grb_array_tools_s_label, 15, 0, 1, 2) + + # Scale Factor + self.grb_scale_label = QtWidgets.QLabel('%s:' % _('Scale factor')) + self.grb_scale_label.setToolTip( + _("Factor to scale the Gerber element.") + ) + self.grb_scale_entry = FCDoubleSpinner() + self.grb_scale_entry.set_precision(self.decimals) + self.grb_scale_entry.set_range(0, 9999) + + grid0.addWidget(self.grb_scale_label, 16, 0) + grid0.addWidget(self.grb_scale_entry, 16, 1) + + self.grb_array_tools_ma_label = QtWidgets.QLabel('%s:' % _('Mark Area Tool')) + grid0.addWidget(self.grb_array_tools_ma_label, 17, 0, 1, 2) + + # Mark area Tool low threshold + self.grb_ma_low_label = QtWidgets.QLabel('%s:' % _('Threshold low')) + self.grb_ma_low_label.setToolTip( + _("Threshold value under which the apertures are not marked.") + ) + self.grb_ma_low_entry = FCDoubleSpinner() + self.grb_ma_low_entry.set_precision(self.decimals) + self.grb_ma_low_entry.set_range(0, 9999) + + grid0.addWidget(self.grb_ma_low_label, 18, 0) + grid0.addWidget(self.grb_ma_low_entry, 18, 1) + + # Mark area Tool high threshold + self.grb_ma_high_label = QtWidgets.QLabel('%s:' % _('Threshold high')) + self.grb_ma_high_label.setToolTip( + _("Threshold value over which the apertures are not marked.") + ) + self.grb_ma_high_entry = FCDoubleSpinner() + self.grb_ma_high_entry.set_precision(self.decimals) + self.grb_ma_high_entry.set_range(0, 9999) + + grid0.addWidget(self.grb_ma_high_label, 19, 0) + grid0.addWidget(self.grb_ma_high_entry, 19, 1) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/gerber/GerberExpPrefGroupUI.py b/flatcamGUI/preferences/gerber/GerberExpPrefGroupUI.py index e6e85fb6..01729dc5 100644 --- a/flatcamGUI/preferences/gerber/GerberExpPrefGroupUI.py +++ b/flatcamGUI/preferences/gerber/GerberExpPrefGroupUI.py @@ -1,5 +1,8 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import RadioSet, FCSpinner +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate @@ -9,49 +12,107 @@ 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 GerberExpPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) +class GerberExpPrefGroupUI(OptionsGroupUI): + + def __init__(self, decimals=4, parent=None): + super(GerberExpPrefGroupUI, self).__init__(self, parent=parent) + self.setTitle(str(_("Gerber Export"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Export Options", - label_tooltip="The parameters set here are used in the file exported\n" - "when using the File -> Export -> Export Gerber menu entry." - ), - RadioSetOptionUI( - option="gerber_exp_units", - label_text="Units", - label_tooltip="The units used in the Gerber file.", - choices=[{'label': _('INCH'), 'value': 'IN'}, - {'label': _('MM'), 'value': 'MM'}] - ), - SpinnerOptionUI( - option="gerber_exp_integer", - label_text="Int", - label_tooltip="The number of digits in the whole part of Gerber coordinates", - min_value=0, max_value=9, step=1 - ), - SpinnerOptionUI( - option="gerber_exp_decimals", - label_text="Decimals", - label_tooltip="The number of digits in the decimal part of Gerber coordinates", - min_value=0, max_value=9, step=1 - ), - RadioSetOptionUI( - option="gerber_exp_zeros", - label_text="Zeros", - label_tooltip="This sets the type of Gerber zeros.\n" - "If LZ then Leading Zeros are removed and\n" - "Trailing Zeros are kept.\n" - "If TZ is checked then Trailing Zeros are removed\n" - "and Leading Zeros are kept.", - choices=[{'label': _('LZ'), 'value': 'L'}, - {'label': _('TZ'), 'value': 'T'}] - ) - ] \ No newline at end of file + # Plot options + self.export_options_label = QtWidgets.QLabel("%s:" % _("Export Options")) + self.export_options_label.setToolTip( + _("The parameters set here are used in the file exported\n" + "when using the File -> Export -> Export Gerber menu entry.") + ) + self.layout.addWidget(self.export_options_label) + + form = QtWidgets.QFormLayout() + self.layout.addLayout(form) + + # Gerber Units + self.gerber_units_label = QtWidgets.QLabel('%s:' % _('Units')) + self.gerber_units_label.setToolTip( + _("The units used in the Gerber file.") + ) + + self.gerber_units_radio = RadioSet([{'label': _('INCH'), 'value': 'IN'}, + {'label': _('MM'), 'value': 'MM'}]) + self.gerber_units_radio.setToolTip( + _("The units used in the Gerber file.") + ) + + form.addRow(self.gerber_units_label, self.gerber_units_radio) + + # Gerber format + self.digits_label = QtWidgets.QLabel("%s:" % _("Int/Decimals")) + self.digits_label.setToolTip( + _("The number of digits in the whole part of the number\n" + "and in the fractional part of the number.") + ) + + hlay1 = QtWidgets.QHBoxLayout() + + self.format_whole_entry = FCSpinner() + self.format_whole_entry.set_range(0, 9) + self.format_whole_entry.set_step(1) + self.format_whole_entry.setWrapping(True) + + self.format_whole_entry.setMinimumWidth(30) + self.format_whole_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the whole part of Gerber coordinates.") + ) + hlay1.addWidget(self.format_whole_entry, QtCore.Qt.AlignLeft) + + gerber_separator_label = QtWidgets.QLabel(':') + gerber_separator_label.setFixedWidth(5) + hlay1.addWidget(gerber_separator_label, QtCore.Qt.AlignLeft) + + self.format_dec_entry = FCSpinner() + self.format_dec_entry.set_range(0, 9) + self.format_dec_entry.set_step(1) + self.format_dec_entry.setWrapping(True) + + self.format_dec_entry.setMinimumWidth(30) + self.format_dec_entry.setToolTip( + _("This numbers signify the number of digits in\n" + "the decimal part of Gerber coordinates.") + ) + hlay1.addWidget(self.format_dec_entry, QtCore.Qt.AlignLeft) + hlay1.addStretch() + + form.addRow(self.digits_label, hlay1) + + # Gerber Zeros + self.zeros_label = QtWidgets.QLabel('%s:' % _('Zeros')) + self.zeros_label.setAlignment(QtCore.Qt.AlignLeft) + self.zeros_label.setToolTip( + _("This sets the type of Gerber zeros.\n" + "If LZ then Leading Zeros are removed and\n" + "Trailing Zeros are kept.\n" + "If TZ is checked then Trailing Zeros are removed\n" + "and Leading Zeros are kept.") + ) + + self.zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'L'}, + {'label': _('TZ'), 'value': 'T'}]) + self.zeros_radio.setToolTip( + _("This sets the type of Gerber zeros.\n" + "If LZ then Leading Zeros are removed and\n" + "Trailing Zeros are kept.\n" + "If TZ is checked then Trailing Zeros are removed\n" + "and Leading Zeros are kept.") + ) + + form.addRow(self.zeros_label, self.zeros_radio) + + self.layout.addStretch() diff --git a/flatcamGUI/preferences/gerber/GerberGenPrefGroupUI.py b/flatcamGUI/preferences/gerber/GerberGenPrefGroupUI.py index 33acdfcc..6f52fe45 100644 --- a/flatcamGUI/preferences/gerber/GerberGenPrefGroupUI.py +++ b/flatcamGUI/preferences/gerber/GerberGenPrefGroupUI.py @@ -1,106 +1,273 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCCheckBox, FCSpinner, RadioSet, FCEntry +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI 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 GerberGenPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Gerber General Preferences", parent=parent) + super(GerberGenPrefGroupUI, self).__init__(self, parent=parent) -class GerberGenPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): - self.decimals = decimals - super().__init__(**kwargs) self.setTitle(str(_("Gerber General"))) + self.decimals = decimals - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI(label_text="Plot Options"), - CheckboxOptionUI( - option="gerber_solid", - label_text="Solid", - label_tooltip="Solid color polygons." - ), - CheckboxOptionUI( - option="gerber_multicolored", - label_text="M-Color", - label_tooltip="Draw polygons in different colors." - ), - CheckboxOptionUI( - option="gerber_plot", - label_text="Plot", - label_tooltip="Plot (show) this object." - ), - SpinnerOptionUI( - option="gerber_circle_steps", - label_text="Circle Steps", - label_tooltip="The number of circle steps for Gerber \n" - "circular aperture linear approximation.", - min_value=0, max_value=9999, step=1 - ), - SeparatorOptionUI(), + # ## Plot options + self.plot_options_label = QtWidgets.QLabel("%s:" % _("Plot Options")) + self.layout.addWidget(self.plot_options_label) - HeadingOptionUI( - label_text="Default Values", - label_tooltip="Those values will be used as fallback values\n" - "in case that they are not found in the Gerber file." - ), - RadioSetOptionUI( - option="gerber_def_units", - label_text="Units", - label_tooltip="The units used in the Gerber file.", - choices=[{'label': _('INCH'), 'value': 'IN'}, - {'label': _('MM'), 'value': 'MM'}] - ), - RadioSetOptionUI( - option="gerber_def_zeros", - label_text="Zeros", - label_tooltip="This sets the type of Gerber zeros.\n" - "If LZ then Leading Zeros are removed and\n" - "Trailing Zeros are kept.\n" - "If TZ is checked then Trailing Zeros are removed\n" - "and Leading Zeros are kept.", - choices=[{'label': _('LZ'), 'value': 'L'}, - {'label': _('TZ'), 'value': 'T'}] - ), - SeparatorOptionUI(), + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) - CheckboxOptionUI( - option="gerber_clean_apertures", - label_text="Clean Apertures", - label_tooltip="Will remove apertures that do not have geometry\n" - "thus lowering the number of apertures in the Gerber object." - ), - CheckboxOptionUI( - option="gerber_extra_buffering", - label_text="Polarity change buffer", - label_tooltip="Will apply extra buffering for the\n" - "solid geometry when we have polarity changes.\n" - "May help loading Gerber files that otherwise\n" - "do not load correctly." - ), - SeparatorOptionUI(), + # Solid CB + self.solid_cb = FCCheckBox(label='%s' % _('Solid')) + self.solid_cb.setToolTip( + _("Solid color polygons.") + ) + grid0.addWidget(self.solid_cb, 0, 0) - HeadingOptionUI(label_text="Gerber Object Color"), - ColorOptionUI( - option="gerber_plot_line", - label_text="Outline", - label_tooltip="Set the line color for plotted objects.", - ), - ColorOptionUI( - option="gerber_plot_fill", - label_text="Fill", - label_tooltip="Set the fill color for plotted objects.\n" - "First 6 digits are the color and the last 2\n" - "digits are for alpha (transparency) level." - ), - ColorAlphaSliderOptionUI( - applies_to=["gerber_plot_line", "gerber_plot_fill"], - group=self, - label_text="Alpha", - label_tooltip="Set the transparency for plotted objects." - ) - ] + # Multicolored CB + self.multicolored_cb = FCCheckBox(label='%s' % _('M-Color')) + self.multicolored_cb.setToolTip( + _("Draw polygons in different colors.") + ) + grid0.addWidget(self.multicolored_cb, 0, 1) + # Plot CB + self.plot_cb = FCCheckBox(label='%s' % _('Plot')) + self.plot_options_label.setToolTip( + _("Plot (show) this object.") + ) + grid0.addWidget(self.plot_cb, 0, 2) + + # Number of circle steps for circular aperture linear approximation + self.circle_steps_label = QtWidgets.QLabel('%s:' % _("Circle Steps")) + self.circle_steps_label.setToolTip( + _("The number of circle steps for Gerber \n" + "circular aperture linear approximation.") + ) + self.circle_steps_entry = FCSpinner() + self.circle_steps_entry.set_range(0, 9999) + + grid0.addWidget(self.circle_steps_label, 1, 0) + grid0.addWidget(self.circle_steps_entry, 1, 1, 1, 2) + + grid0.addWidget(QtWidgets.QLabel(''), 2, 0, 1, 3) + + # Default format for Gerber + self.gerber_default_label = QtWidgets.QLabel('%s:' % _('Default Values')) + self.gerber_default_label.setToolTip( + _("Those values will be used as fallback values\n" + "in case that they are not found in the Gerber file.") + ) + + grid0.addWidget(self.gerber_default_label, 3, 0, 1, 3) + + # Gerber Units + self.gerber_units_label = QtWidgets.QLabel('%s:' % _('Units')) + self.gerber_units_label.setToolTip( + _("The units used in the Gerber file.") + ) + + self.gerber_units_radio = RadioSet([{'label': _('INCH'), 'value': 'IN'}, + {'label': _('MM'), 'value': 'MM'}]) + self.gerber_units_radio.setToolTip( + _("The units used in the Gerber file.") + ) + + grid0.addWidget(self.gerber_units_label, 4, 0) + grid0.addWidget(self.gerber_units_radio, 4, 1, 1, 2) + + # Gerber Zeros + self.gerber_zeros_label = QtWidgets.QLabel('%s:' % _('Zeros')) + self.gerber_zeros_label.setAlignment(QtCore.Qt.AlignLeft) + self.gerber_zeros_label.setToolTip( + _("This sets the type of Gerber zeros.\n" + "If LZ then Leading Zeros are removed and\n" + "Trailing Zeros are kept.\n" + "If TZ is checked then Trailing Zeros are removed\n" + "and Leading Zeros are kept.") + ) + + self.gerber_zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'L'}, + {'label': _('TZ'), 'value': 'T'}]) + self.gerber_zeros_radio.setToolTip( + _("This sets the type of Gerber zeros.\n" + "If LZ then Leading Zeros are removed and\n" + "Trailing Zeros are kept.\n" + "If TZ is checked then Trailing Zeros are removed\n" + "and Leading Zeros are kept.") + ) + + grid0.addWidget(self.gerber_zeros_label, 5, 0) + grid0.addWidget(self.gerber_zeros_radio, 5, 1, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 6, 0, 1, 3) + + # Apertures Cleaning + self.gerber_clean_cb = FCCheckBox(label='%s' % _('Clean Apertures')) + self.gerber_clean_cb.setToolTip( + _("Will remove apertures that do not have geometry\n" + "thus lowering the number of apertures in the Gerber object.") + ) + grid0.addWidget(self.gerber_clean_cb, 7, 0, 1, 3) + + # Apply Extra Buffering + self.gerber_extra_buffering = FCCheckBox(label='%s' % _('Polarity change buffer')) + self.gerber_extra_buffering.setToolTip( + _("Will apply extra buffering for the\n" + "solid geometry when we have polarity changes.\n" + "May help loading Gerber files that otherwise\n" + "do not load correctly.") + ) + grid0.addWidget(self.gerber_extra_buffering, 8, 0, 1, 3) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 9, 0, 1, 3) + + # Gerber Object Color + self.gerber_color_label = QtWidgets.QLabel('%s' % _('Gerber Object Color')) + grid0.addWidget(self.gerber_color_label, 10, 0, 1, 3) + + # Plot Line Color + self.pl_color_label = QtWidgets.QLabel('%s:' % _('Outline')) + self.pl_color_label.setToolTip( + _("Set the line color for plotted objects.") + ) + self.pl_color_entry = FCEntry() + self.pl_color_button = QtWidgets.QPushButton() + self.pl_color_button.setFixedSize(15, 15) + + self.form_box_child_2 = QtWidgets.QHBoxLayout() + self.form_box_child_2.addWidget(self.pl_color_entry) + self.form_box_child_2.addWidget(self.pl_color_button) + self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.pl_color_label, 11, 0) + grid0.addLayout(self.form_box_child_2, 11, 1, 1, 2) + + # Plot Fill Color + self.pf_color_label = QtWidgets.QLabel('%s:' % _('Fill')) + self.pf_color_label.setToolTip( + _("Set the fill color for plotted objects.\n" + "First 6 digits are the color and the last 2\n" + "digits are for alpha (transparency) level.") + ) + self.pf_color_entry = FCEntry() + self.pf_color_button = QtWidgets.QPushButton() + self.pf_color_button.setFixedSize(15, 15) + + self.form_box_child_1 = QtWidgets.QHBoxLayout() + self.form_box_child_1.addWidget(self.pf_color_entry) + self.form_box_child_1.addWidget(self.pf_color_button) + self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) + + grid0.addWidget(self.pf_color_label, 12, 0) + grid0.addLayout(self.form_box_child_1, 12, 1, 1, 2) + + # Plot Fill Transparency Level + self.pf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha')) + self.pf_alpha_label.setToolTip( + _("Set the fill transparency for plotted objects.") + ) + self.pf_color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) + self.pf_color_alpha_slider.setMinimum(0) + self.pf_color_alpha_slider.setMaximum(255) + self.pf_color_alpha_slider.setSingleStep(1) + + self.pf_color_alpha_spinner = FCSpinner() + self.pf_color_alpha_spinner.setMinimumWidth(70) + self.pf_color_alpha_spinner.set_range(0, 255) + + self.form_box_child_3 = QtWidgets.QHBoxLayout() + self.form_box_child_3.addWidget(self.pf_color_alpha_slider) + self.form_box_child_3.addWidget(self.pf_color_alpha_spinner) + + grid0.addWidget(self.pf_alpha_label, 13, 0) + grid0.addLayout(self.form_box_child_3, 13, 1, 1, 2) + + self.layout.addStretch() + + # Setting plot colors signals + self.pl_color_entry.editingFinished.connect(self.on_pl_color_entry) + self.pl_color_button.clicked.connect(self.on_pl_color_button) + self.pf_color_entry.editingFinished.connect(self.on_pf_color_entry) + self.pf_color_button.clicked.connect(self.on_pf_color_button) + self.pf_color_alpha_spinner.valueChanged.connect(self.on_pf_color_spinner) + self.pf_color_alpha_slider.valueChanged.connect(self.on_pf_color_slider) + + # Setting plot colors handlers + def on_pf_color_entry(self): + self.app.defaults['gerber_plot_fill'] = self.pf_color_entry.get_value()[:7] + \ + self.app.defaults['gerber_plot_fill'][7:9] + self.pf_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['gerber_plot_fill'])[:7]) + + def on_pf_color_button(self): + current_color = QtGui.QColor(self.app.defaults['gerber_plot_fill'][:7]) + + c_dialog = QtWidgets.QColorDialog() + plot_fill_color = c_dialog.getColor(initial=current_color) + + if plot_fill_color.isValid() is False: + return + + self.pf_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name())) + + new_val = str(plot_fill_color.name()) + str(self.app.defaults['gerber_plot_fill'][7:9]) + self.pf_color_entry.set_value(new_val) + self.app.defaults['gerber_plot_fill'] = new_val + + def on_pf_color_spinner(self): + spinner_value = self.pf_color_alpha_spinner.value() + self.pf_color_alpha_slider.setValue(spinner_value) + self.app.defaults['gerber_plot_fill'] = \ + self.app.defaults['gerber_plot_fill'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + self.app.defaults['gerber_plot_line'] = \ + self.app.defaults['gerber_plot_line'][:7] + \ + (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00') + + def on_pf_color_slider(self): + slider_value = self.pf_color_alpha_slider.value() + self.pf_color_alpha_spinner.setValue(slider_value) + + def on_pl_color_entry(self): + self.app.defaults['gerber_plot_line'] = self.pl_color_entry.get_value()[:7] + \ + self.app.defaults['gerber_plot_line'][7:9] + self.pl_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['gerber_plot_line'])[:7]) + + def on_pl_color_button(self): + current_color = QtGui.QColor(self.app.defaults['gerber_plot_line'][:7]) + # print(current_color) + + c_dialog = QtWidgets.QColorDialog() + plot_line_color = c_dialog.getColor(initial=current_color) + + if plot_line_color.isValid() is False: + return + + self.pl_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name())) + + new_val_line = str(plot_line_color.name()) + str(self.app.defaults['gerber_plot_line'][7:9]) + self.pl_color_entry.set_value(new_val_line) + self.app.defaults['gerber_plot_line'] = new_val_line diff --git a/flatcamGUI/preferences/gerber/GerberOptPrefGroupUI.py b/flatcamGUI/preferences/gerber/GerberOptPrefGroupUI.py index 231c6528..404f17ba 100644 --- a/flatcamGUI/preferences/gerber/GerberOptPrefGroupUI.py +++ b/flatcamGUI/preferences/gerber/GerberOptPrefGroupUI.py @@ -1,5 +1,8 @@ -from flatcamGUI.preferences.OptionUI import * -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI2 +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + +from flatcamGUI.GUIElements import FCDoubleSpinner, FCSpinner, RadioSet, FCCheckBox +from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext import FlatCAMTranslation as fcTranslate @@ -9,103 +12,176 @@ 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 GerberOptPrefGroupUI(OptionsGroupUI2): - def __init__(self, decimals=4, **kwargs): +class GerberOptPrefGroupUI(OptionsGroupUI): + def __init__(self, decimals=4, parent=None): + # OptionsGroupUI.__init__(self, "Gerber Options Preferences", parent=parent) + super(GerberOptPrefGroupUI, self).__init__(self, parent=parent) + self.decimals = decimals - super().__init__(**kwargs) + self.setTitle(str(_("Gerber Options"))) - def build_options(self) -> [OptionUI]: - return [ - HeadingOptionUI( - label_text="Isolation Routing", - label_tooltip="Create a Geometry object with\n" - "toolpaths to cut outside polygons." - ), - DoubleSpinnerOptionUI( - option="gerber_isotooldia", - label_text="Tool dia", - label_tooltip="Diameter of the cutting tool.", - min_value=0.0, max_value=9999.9, step=0.1, decimals=self.decimals - ), - SpinnerOptionUI( - option="gerber_isopasses", - label_text="# Passes", - label_tooltip="Width of the isolation gap in\n" - "number (integer) of tool widths.", - min_value=1, max_value=999, step=1 - ), - DoubleSpinnerOptionUI( - option="gerber_isooverlap", - label_text="Pass overlap", - label_tooltip="How much (percentage) of the tool width to overlap each tool pass.", - min_value=0.0, max_value=99.9999, step=0.1, decimals=self.decimals, suffix="%" - ), - RadioSetOptionUI( - option="gerber_iso_scope", - label_text="Scope", - label_tooltip="Isolation scope. Choose what to isolate:\n" - "- 'All' -> Isolate all the polygons in the object\n" - "- 'Selection' -> Isolate a selection of polygons.", - choices=[{'label': _('All'), 'value': 'all'}, - {'label': _('Selection'), 'value': 'single'}] - ), - RadioSetOptionUI( - option="gerber_milling_type", - label_text="Milling Type", - label_tooltip="Milling type:\n" - "- climb / best for precision milling and to reduce tool usage\n" - "- conventional / useful when there is no backlash compensation", - choices=[{'label': _('Climb'), 'value': 'cl'}, - {'label': _('Conventional'), 'value': 'cv'}] - ), - CheckboxOptionUI( - option="gerber_combine_passes", - label_text="Combine Passes", - label_tooltip="Combine all passes into one object" - ), - SeparatorOptionUI(), + # ## Isolation Routing + self.isolation_routing_label = QtWidgets.QLabel("%s:" % _("Isolation Routing")) + self.isolation_routing_label.setToolTip( + _("Create a Geometry object with\n" + "toolpaths to cut outside polygons.") + ) + self.layout.addWidget(self.isolation_routing_label) - HeadingOptionUI( - label_text="Non-copper regions", - label_tooltip="Create polygons covering the\n" - "areas without copper on the PCB.\n" - "Equivalent to the inverse of this\n" - "object. Can be used to remove all\n" - "copper from a specified region." - ), - DoubleSpinnerOptionUI( - option="gerber_noncoppermargin", - label_text="Boundary Margin", - label_tooltip="Specify the edge of the PCB\n" - "by drawing a box around all\n" - "objects with this minimum\n" - "distance.", - min_value=-9999, max_value=9999, step=0.1, decimals=self.decimals - ), - CheckboxOptionUI( - option="gerber_noncopperrounded", - label_text="Rounded Geo", - label_tooltip="Resulting geometry will have rounded corners." - ), - SeparatorOptionUI(), + # Cutting Tool Diameter + grid0 = QtWidgets.QGridLayout() + self.layout.addLayout(grid0) - HeadingOptionUI(label_text="Bounding Box"), - DoubleSpinnerOptionUI( - option="gerber_bboxmargin", - label_text="Boundary Margin", - label_tooltip="Distance of the edges of the box\n" - "to the nearest polygon.", - min_value=-9999, max_value=9999, step=0.1, decimals=self.decimals - ), - CheckboxOptionUI( - option="gerber_bboxrounded", - label_text="Rounded Geo", - label_tooltip="If the bounding box is \n" - "to have rounded corners\n" - "their radius is equal to\n" - "the margin." - ), - ] \ No newline at end of file + tdlabel = QtWidgets.QLabel('%s:' % _('Tool dia')) + tdlabel.setToolTip( + _("Diameter of the cutting tool.") + ) + grid0.addWidget(tdlabel, 0, 0) + self.iso_tool_dia_entry = FCDoubleSpinner() + self.iso_tool_dia_entry.set_precision(self.decimals) + self.iso_tool_dia_entry.setSingleStep(0.1) + self.iso_tool_dia_entry.set_range(-9999, 9999) + + grid0.addWidget(self.iso_tool_dia_entry, 0, 1) + + # Nr of passes + passlabel = QtWidgets.QLabel('%s:' % _('# Passes')) + passlabel.setToolTip( + _("Width of the isolation gap in\n" + "number (integer) of tool widths.") + ) + self.iso_width_entry = FCSpinner() + self.iso_width_entry.set_range(1, 999) + + grid0.addWidget(passlabel, 1, 0) + grid0.addWidget(self.iso_width_entry, 1, 1) + + # Pass overlap + overlabel = QtWidgets.QLabel('%s:' % _('Pass overlap')) + overlabel.setToolTip( + _("How much (percentage) of the tool width to overlap each tool pass.") + ) + self.iso_overlap_entry = FCDoubleSpinner(suffix='%') + self.iso_overlap_entry.set_precision(self.decimals) + self.iso_overlap_entry.setWrapping(True) + self.iso_overlap_entry.setRange(0.0000, 99.9999) + self.iso_overlap_entry.setSingleStep(0.1) + + grid0.addWidget(overlabel, 2, 0) + grid0.addWidget(self.iso_overlap_entry, 2, 1) + + # Isolation Scope + self.iso_scope_label = QtWidgets.QLabel('%s:' % _('Scope')) + self.iso_scope_label.setToolTip( + _("Isolation scope. Choose what to isolate:\n" + "- 'All' -> Isolate all the polygons in the object\n" + "- 'Selection' -> Isolate a selection of polygons.") + ) + self.iso_scope_radio = RadioSet([{'label': _('All'), 'value': 'all'}, + {'label': _('Selection'), 'value': 'single'}]) + + grid0.addWidget(self.iso_scope_label, 3, 0) + grid0.addWidget(self.iso_scope_radio, 3, 1, 1, 2) + + # Milling Type + milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type')) + milling_type_label.setToolTip( + _("Milling type:\n" + "- climb / best for precision milling and to reduce tool usage\n" + "- conventional / useful when there is no backlash compensation") + ) + grid0.addWidget(milling_type_label, 4, 0) + self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'}, + {'label': _('Conventional'), 'value': 'cv'}]) + grid0.addWidget(self.milling_type_radio, 4, 1) + + # Combine passes + self.combine_passes_cb = FCCheckBox(label=_('Combine Passes')) + self.combine_passes_cb.setToolTip( + _("Combine all passes into one object") + ) + grid0.addWidget(self.combine_passes_cb, 5, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid0.addWidget(separator_line, 6, 0, 1, 2) + + # ## Clear non-copper regions + self.clearcopper_label = QtWidgets.QLabel("%s:" % _("Non-copper regions")) + self.clearcopper_label.setToolTip( + _("Create polygons covering the\n" + "areas without copper on the PCB.\n" + "Equivalent to the inverse of this\n" + "object. Can be used to remove all\n" + "copper from a specified region.") + ) + self.layout.addWidget(self.clearcopper_label) + + grid1 = QtWidgets.QGridLayout() + self.layout.addLayout(grid1) + + # Margin + bmlabel = QtWidgets.QLabel('%s:' % _('Boundary Margin')) + bmlabel.setToolTip( + _("Specify the edge of the PCB\n" + "by drawing a box around all\n" + "objects with this minimum\n" + "distance.") + ) + grid1.addWidget(bmlabel, 0, 0) + self.noncopper_margin_entry = FCDoubleSpinner() + self.noncopper_margin_entry.set_precision(self.decimals) + self.noncopper_margin_entry.setSingleStep(0.1) + self.noncopper_margin_entry.set_range(-9999, 9999) + grid1.addWidget(self.noncopper_margin_entry, 0, 1) + + # Rounded corners + self.noncopper_rounded_cb = FCCheckBox(label=_("Rounded Geo")) + self.noncopper_rounded_cb.setToolTip( + _("Resulting geometry will have rounded corners.") + ) + grid1.addWidget(self.noncopper_rounded_cb, 1, 0, 1, 2) + + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid1.addWidget(separator_line, 2, 0, 1, 2) + + # ## Bounding box + self.boundingbox_label = QtWidgets.QLabel('%s:' % _('Bounding Box')) + self.layout.addWidget(self.boundingbox_label) + + grid2 = QtWidgets.QGridLayout() + self.layout.addLayout(grid2) + + bbmargin = QtWidgets.QLabel('%s:' % _('Boundary Margin')) + bbmargin.setToolTip( + _("Distance of the edges of the box\n" + "to the nearest polygon.") + ) + self.bbmargin_entry = FCDoubleSpinner() + self.bbmargin_entry.set_precision(self.decimals) + self.bbmargin_entry.setSingleStep(0.1) + self.bbmargin_entry.set_range(-9999, 9999) + + grid2.addWidget(bbmargin, 0, 0) + grid2.addWidget(self.bbmargin_entry, 0, 1) + + self.bbrounded_cb = FCCheckBox(label='%s' % _("Rounded Geo")) + self.bbrounded_cb.setToolTip( + _("If the bounding box is \n" + "to have rounded corners\n" + "their radius is equal to\n" + "the margin.") + ) + grid2.addWidget(self.bbrounded_cb, 1, 0, 1, 2) + self.layout.addStretch() diff --git a/flatcamGUI/preferences/gerber/GerberPreferencesUI.py b/flatcamGUI/preferences/gerber/GerberPreferencesUI.py index 8d3b3e90..f9d9f8aa 100644 --- a/flatcamGUI/preferences/gerber/GerberPreferencesUI.py +++ b/flatcamGUI/preferences/gerber/GerberPreferencesUI.py @@ -1,5 +1,6 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.gerber.GerberEditorPrefGroupUI import GerberEditorPrefGroupUI from flatcamGUI.preferences.gerber.GerberExpPrefGroupUI import GerberExpPrefGroupUI from flatcamGUI.preferences.gerber.GerberAdvOptPrefGroupUI import GerberAdvOptPrefGroupUI @@ -9,30 +10,44 @@ from flatcamGUI.preferences.gerber.GerberGenPrefGroupUI import GerberGenPrefGrou 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 GerberPreferencesUI(PreferencesSectionUI): - def __init__(self, decimals, **kwargs): +class GerberPreferencesUI(QtWidgets.QWidget): + + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals - super().__init__(**kwargs) - def build_groups(self) -> [OptionsGroupUI]: - return [ - GerberGenPrefGroupUI(decimals=self.decimals), + self.gerber_gen_group = GerberGenPrefGroupUI(decimals=self.decimals) + self.gerber_gen_group.setMinimumWidth(250) + self.gerber_opt_group = GerberOptPrefGroupUI(decimals=self.decimals) + self.gerber_opt_group.setMinimumWidth(250) + self.gerber_exp_group = GerberExpPrefGroupUI(decimals=self.decimals) + self.gerber_exp_group.setMinimumWidth(230) + self.gerber_adv_opt_group = GerberAdvOptPrefGroupUI(decimals=self.decimals) + self.gerber_adv_opt_group.setMinimumWidth(200) + self.gerber_editor_group = GerberEditorPrefGroupUI(decimals=self.decimals) + self.gerber_editor_group.setMinimumWidth(200) - GerberOptPrefGroupUI(decimals=self.decimals), # FIXME vertical layout with opt and exp - GerberExpPrefGroupUI(decimals=self.decimals), + self.vlay = QtWidgets.QVBoxLayout() + self.vlay.addWidget(self.gerber_opt_group) + self.vlay.addWidget(self.gerber_exp_group) - GerberAdvOptPrefGroupUI(decimals=self.decimals), - GerberEditorPrefGroupUI(decimals=self.decimals) - ] + self.layout.addWidget(self.gerber_gen_group) + self.layout.addLayout(self.vlay) + self.layout.addWidget(self.gerber_adv_opt_group) + self.layout.addWidget(self.gerber_editor_group) - def get_tab_id(self): - return "gerber_tab" - - def get_tab_label(self): - return _("GERBER") + self.layout.addStretch() diff --git a/flatcamGUI/preferences/tools/Tools2PreferencesUI.py b/flatcamGUI/preferences/tools/Tools2PreferencesUI.py index 168940a0..01ed4def 100644 --- a/flatcamGUI/preferences/tools/Tools2PreferencesUI.py +++ b/flatcamGUI/preferences/tools/Tools2PreferencesUI.py @@ -1,5 +1,6 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.tools.Tools2InvertPrefGroupUI import Tools2InvertPrefGroupUI from flatcamGUI.preferences.tools.Tools2PunchGerberPrefGroupUI import Tools2PunchGerberPrefGroupUI from flatcamGUI.preferences.tools.Tools2EDrillsPrefGroupUI import Tools2EDrillsPrefGroupUI @@ -10,46 +11,79 @@ from flatcamGUI.preferences.tools.Tools2QRCodePrefGroupUI import Tools2QRCodePre from flatcamGUI.preferences.tools.Tools2OptimalPrefGroupUI import Tools2OptimalPrefGroupUI from flatcamGUI.preferences.tools.Tools2RulesCheckPrefGroupUI import Tools2RulesCheckPrefGroupUI +import gettext +import FlatCAMTranslation as fcTranslate +import builtins -class Tools2PreferencesUI(PreferencesSectionUI): +fcTranslate.apply_language('strings') +if '_' not in builtins.__dict__: + _ = gettext.gettext - def __init__(self, decimals, **kwargs): +settings = QSettings("Open Source", "FlatCAM") +if settings.contains("machinist"): + machinist_setting = settings.value('machinist', type=int) +else: + machinist_setting = 0 + + +class Tools2PreferencesUI(QtWidgets.QWidget): + + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals + self.tools2_checkrules_group = Tools2RulesCheckPrefGroupUI(decimals=self.decimals) + self.tools2_checkrules_group.setMinimumWidth(220) + self.tools2_optimal_group = Tools2OptimalPrefGroupUI(decimals=self.decimals) + self.tools2_optimal_group.setMinimumWidth(220) + self.tools2_qrcode_group = Tools2QRCodePrefGroupUI(decimals=self.decimals) + self.tools2_qrcode_group.setMinimumWidth(220) + self.tools2_cfill_group = Tools2CThievingPrefGroupUI(decimals=self.decimals) + self.tools2_cfill_group.setMinimumWidth(220) + self.tools2_fiducials_group = Tools2FiducialsPrefGroupUI(decimals=self.decimals) + self.tools2_fiducials_group.setMinimumWidth(220) + self.tools2_cal_group = Tools2CalPrefGroupUI(decimals=self.decimals) + self.tools2_cal_group.setMinimumWidth(220) + self.tools2_edrills_group = Tools2EDrillsPrefGroupUI(decimals=self.decimals) + self.tools2_edrills_group.setMinimumWidth(220) + self.tools2_punch_group = Tools2PunchGerberPrefGroupUI(decimals=self.decimals) + self.tools2_punch_group.setMinimumWidth(220) + self.tools2_invert_group = Tools2InvertPrefGroupUI(decimals=self.decimals) - super().__init__(**kwargs) + self.tools2_invert_group.setMinimumWidth(220) - def build_groups(self) -> [OptionsGroupUI]: - return [ - # fixme column 1 - self.tools2_checkrules_group, - self.tools2_optimal_group, + self.vlay = QtWidgets.QVBoxLayout() + self.vlay.addWidget(self.tools2_checkrules_group) + self.vlay.addWidget(self.tools2_optimal_group) - # fixme column 2 - self.tools2_qrcode_group, - self.tools2_fiducials_group, + self.vlay1 = QtWidgets.QVBoxLayout() + self.vlay1.addWidget(self.tools2_qrcode_group) + self.vlay1.addWidget(self.tools2_fiducials_group) - # fixme column 3 - self.tools2_cfill_group, + self.vlay2 = QtWidgets.QVBoxLayout() + self.vlay2.addWidget(self.tools2_cfill_group) - # fixme column 4 - self.tools2_cal_group, - self.tools2_edrills_group, + self.vlay3 = QtWidgets.QVBoxLayout() + self.vlay3.addWidget(self.tools2_cal_group) + self.vlay3.addWidget(self.tools2_edrills_group) - # fixme column 5 - self.tools2_punch_group, - self.tools2_invert_group, - ] + self.vlay4 = QtWidgets.QVBoxLayout() + self.vlay4.addWidget(self.tools2_punch_group) + self.vlay4.addWidget(self.tools2_invert_group) - def get_tab_id(self): - return "tools2_tab" + self.layout.addLayout(self.vlay) + self.layout.addLayout(self.vlay1) + self.layout.addLayout(self.vlay2) + self.layout.addLayout(self.vlay3) + self.layout.addLayout(self.vlay4) - def get_tab_label(self): - return _("TOOLS 2") \ No newline at end of file + self.layout.addStretch() diff --git a/flatcamGUI/preferences/tools/ToolsPreferencesUI.py b/flatcamGUI/preferences/tools/ToolsPreferencesUI.py index 0c4ffd70..dc3061a8 100644 --- a/flatcamGUI/preferences/tools/ToolsPreferencesUI.py +++ b/flatcamGUI/preferences/tools/ToolsPreferencesUI.py @@ -1,5 +1,6 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings + from flatcamGUI.preferences.tools.ToolsSubPrefGroupUI import ToolsSubPrefGroupUI from flatcamGUI.preferences.tools.ToolsSolderpastePrefGroupUI import ToolsSolderpastePrefGroupUI from flatcamGUI.preferences.tools.ToolsTransformPrefGroupUI import ToolsTransformPrefGroupUI @@ -11,48 +12,83 @@ from flatcamGUI.preferences.tools.Tools2sidedPrefGroupUI import Tools2sidedPrefG from flatcamGUI.preferences.tools.ToolsCutoutPrefGroupUI import ToolsCutoutPrefGroupUI from flatcamGUI.preferences.tools.ToolsNCCPrefGroupUI import ToolsNCCPrefGroupUI +import gettext +import FlatCAMTranslation as fcTranslate +import builtins -class ToolsPreferencesUI(PreferencesSectionUI): +fcTranslate.apply_language('strings') +if '_' not in builtins.__dict__: + _ = gettext.gettext - def __init__(self, decimals, **kwargs): +settings = QSettings("Open Source", "FlatCAM") +if settings.contains("machinist"): + machinist_setting = settings.value('machinist', type=int) +else: + machinist_setting = 0 + + +class ToolsPreferencesUI(QtWidgets.QWidget): + + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals + self.tools_ncc_group = ToolsNCCPrefGroupUI(decimals=self.decimals) + self.tools_ncc_group.setMinimumWidth(220) + self.tools_paint_group = ToolsPaintPrefGroupUI(decimals=self.decimals) + self.tools_paint_group.setMinimumWidth(220) + self.tools_cutout_group = ToolsCutoutPrefGroupUI(decimals=self.decimals) + self.tools_cutout_group.setMinimumWidth(220) + self.tools_2sided_group = Tools2sidedPrefGroupUI(decimals=self.decimals) + self.tools_2sided_group.setMinimumWidth(220) + self.tools_film_group = ToolsFilmPrefGroupUI(decimals=self.decimals) + self.tools_film_group.setMinimumWidth(220) + self.tools_panelize_group = ToolsPanelizePrefGroupUI(decimals=self.decimals) + self.tools_panelize_group.setMinimumWidth(220) + self.tools_calculators_group = ToolsCalculatorsPrefGroupUI(decimals=self.decimals) + self.tools_calculators_group.setMinimumWidth(220) + self.tools_transform_group = ToolsTransformPrefGroupUI(decimals=self.decimals) + self.tools_transform_group.setMinimumWidth(200) + self.tools_solderpaste_group = ToolsSolderpastePrefGroupUI(decimals=self.decimals) + self.tools_solderpaste_group.setMinimumWidth(200) + self.tools_sub_group = ToolsSubPrefGroupUI(decimals=self.decimals) - super().__init__(**kwargs) + self.tools_sub_group.setMinimumWidth(200) - def build_groups(self) -> [OptionsGroupUI]: - return [ - # fixme column 1 - self.tools_ncc_group, - self.tools_cutout_group, + self.vlay = QtWidgets.QVBoxLayout() + self.vlay.addWidget(self.tools_ncc_group) + self.vlay.addWidget(self.tools_cutout_group) - # fixme column 2 - self.tools_paint_group, - self.tools_panelize_group, + self.vlay1 = QtWidgets.QVBoxLayout() + self.vlay1.addWidget(self.tools_paint_group) + self.vlay1.addWidget(self.tools_panelize_group) - # fixme column 3 - self.tools_transform_group, - self.tools_2sided_group, - self.tools_sub_group, + self.vlay2 = QtWidgets.QVBoxLayout() + self.vlay2.addWidget(self.tools_transform_group) + self.vlay2.addWidget(self.tools_2sided_group) + self.vlay2.addWidget(self.tools_sub_group) - # fixme column 4 - self.tools_film_group, - self.tools_calculators_group, + self.vlay3 = QtWidgets.QVBoxLayout() + self.vlay3.addWidget(self.tools_film_group) + self.vlay3.addWidget(self.tools_calculators_group) - # fixme column 5 - self.tools_solderpaste_group, - ] + self.vlay4 = QtWidgets.QVBoxLayout() + self.vlay4.addWidget(self.tools_solderpaste_group) - def get_tab_id(self): - return "tools_tab" + self.layout.addLayout(self.vlay) + self.layout.addLayout(self.vlay1) + self.layout.addLayout(self.vlay2) + self.layout.addLayout(self.vlay3) + self.layout.addLayout(self.vlay4) - def get_tab_label(self): - return _("TOOLS") + self.layout.addStretch() diff --git a/flatcamGUI/preferences/utilities/UtilPreferencesUI.py b/flatcamGUI/preferences/utilities/UtilPreferencesUI.py index 9e2f40b1..ae9e2110 100644 --- a/flatcamGUI/preferences/utilities/UtilPreferencesUI.py +++ b/flatcamGUI/preferences/utilities/UtilPreferencesUI.py @@ -1,31 +1,37 @@ -from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI -from flatcamGUI.preferences.PreferencesSectionUI import PreferencesSectionUI +from PyQt5 import QtWidgets + from flatcamGUI.preferences.utilities.AutoCompletePrefGroupUI import AutoCompletePrefGroupUI from flatcamGUI.preferences.utilities.FAGrbPrefGroupUI import FAGrbPrefGroupUI from flatcamGUI.preferences.utilities.FAGcoPrefGroupUI import FAGcoPrefGroupUI from flatcamGUI.preferences.utilities.FAExcPrefGroupUI import FAExcPrefGroupUI -class UtilPreferencesUI(PreferencesSectionUI): +class UtilPreferencesUI(QtWidgets.QWidget): - def __init__(self, decimals, **kwargs): + def __init__(self, decimals, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + self.layout = QtWidgets.QHBoxLayout() + self.setLayout(self.layout) self.decimals = decimals + + self.vlay = QtWidgets.QVBoxLayout() self.fa_excellon_group = FAExcPrefGroupUI(decimals=self.decimals) + self.fa_excellon_group.setMinimumWidth(260) + self.fa_gcode_group = FAGcoPrefGroupUI(decimals=self.decimals) + self.fa_gcode_group.setMinimumWidth(260) + + self.vlay.addWidget(self.fa_excellon_group) + self.vlay.addWidget(self.fa_gcode_group) + self.fa_gerber_group = FAGrbPrefGroupUI(decimals=self.decimals) + self.fa_gerber_group.setMinimumWidth(260) + self.kw_group = AutoCompletePrefGroupUI(decimals=self.decimals) - super().__init__(**kwargs) + self.kw_group.setMinimumWidth(260) - def build_groups(self) -> [OptionsGroupUI]: - return [ - self.fa_excellon_group, # fixme column with fa_excellon and fa_gcode - self.fa_gcode_group, - self.fa_gerber_group, - self.kw_group, - ] + self.layout.addLayout(self.vlay) + self.layout.addWidget(self.fa_gerber_group) + self.layout.addWidget(self.kw_group) - def get_tab_id(self): - return "fa_tab" - - def get_tab_label(self): - return _("UTILITIES") \ No newline at end of file + self.layout.addStretch() diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py index f6c85731..d6fd310a 100644 --- a/flatcamTools/ToolCopperThieving.py +++ b/flatcamTools/ToolCopperThieving.py @@ -910,22 +910,16 @@ class ToolCopperThieving(FlatCAMTool): edge_width=self.app.defaults["global_cursor_width"], size=self.app.defaults["global_cursor_size"]) + # update the positions on status bar + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (curr_pos[0], curr_pos[1])) if self.cursor_pos is None: self.cursor_pos = (0, 0) self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) - - # # update the positions on status bar - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (curr_pos[0], curr_pos[1])) - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units) + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if self.first_click: diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py index bcc506fb..ea62c64e 100644 --- a/flatcamTools/ToolDistance.py +++ b/flatcamTools/ToolDistance.py @@ -544,16 +544,11 @@ class Distance(FlatCAMTool): else: pos = (pos_canvas[0], pos_canvas[1]) - # self.app.ui.position_label.setText( - # "    X: {}   Y: {}".format( - # '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1]) - # ) - # ) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - 0.0000, units, 0.0000, units, pos[0], units, pos[1], units) + self.app.ui.position_label.setText( + "    X: {}   Y: {}".format( + '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1]) + ) + ) if self.rel_point1 is not None: dx = pos[0] - float(self.rel_point1[0]) diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py index d01f02de..0b80c735 100644 --- a/flatcamTools/ToolNCC.py +++ b/flatcamTools/ToolNCC.py @@ -1825,22 +1825,16 @@ class NonCopperClear(FlatCAMTool, Gerber): edge_width=self.app.defaults["global_cursor_width"], size=self.app.defaults["global_cursor_size"]) + # update the positions on status bar + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (curr_pos[0], curr_pos[1])) if self.cursor_pos is None: self.cursor_pos = (0, 0) self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) - - # # update the positions on status bar - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (curr_pos[0], curr_pos[1])) - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units) + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if shape_type == "square": diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py index ae1b23cc..4dda2d36 100644 --- a/flatcamTools/ToolPaint.py +++ b/flatcamTools/ToolPaint.py @@ -1724,22 +1724,16 @@ class ToolPaint(FlatCAMTool, Gerber): edge_width=self.app.defaults["global_cursor_width"], size=self.app.defaults["global_cursor_size"]) + # update the positions on status bar + self.app.ui.position_label.setText("    X: %.4f   " + "Y: %.4f" % (curr_pos[0], curr_pos[1])) if self.cursor_pos is None: self.cursor_pos = (0, 0) self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) - - # # update the positions on status bar - # self.app.ui.position_label.setText("    X: %.4f   " - # "Y: %.4f" % (curr_pos[0], curr_pos[1])) - # self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - # "%.4f    " % (self.app.dx, self.app.dy)) - - units = self.app.defaults["units"].lower() - self.plotcanvas.text_hud.text = \ - 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format( - self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units) + self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if shape_type == "square":