From 365c1f4c715edf87076b2a9e5a90227fc810670c Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sat, 2 Feb 2019 01:25:35 +0200 Subject: [PATCH] - remade the way FlatCAM saves the GUI position data from a file (previously) to use PyQt QSettings - added a 'theme' combo selection in Edit -> Preferences. Two themes are available: standard and compact. - some code cleanup --- FlatCAMApp.py | 182 +++++++++++++++++------- FlatCAMEditor.py | 94 +++++++++---- FlatCAMGUI.py | 359 ++++++++++++++++++++++++++++++----------------- README.md | 4 +- 4 files changed, 433 insertions(+), 206 deletions(-) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 2b464e7d..3139bd92 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -22,6 +22,8 @@ import subprocess import tkinter as tk from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport +from PyQt5.QtCore import QSettings + import time # Just used for debugging. Double check before removing. import urllib.request, urllib.parse, urllib.error import webbrowser @@ -91,7 +93,7 @@ class App(QtCore.QObject): # Version version = 8.906 - version_date = "2019/02/1" + version_date = "2019/02/2" beta = True # URL for update checks and statistics @@ -264,9 +266,9 @@ class App(QtCore.QObject): self.FC_dark_blue = '#0000ffbf' QtCore.QObject.__init__(self) - self.ui = FlatCAMGUI(self.version, self.beta, self) + # self.connect(self.ui, # QtCore.SIGNAL("geomUpdate(int, int, int, int, int)"), # self.save_geometry) PyQt4 @@ -300,6 +302,7 @@ class App(QtCore.QObject): "global_send_stats": self.general_defaults_form.general_app_group.send_stats_cb, "global_gridx": self.general_defaults_form.general_gui_group.gridx_entry, "global_gridy": self.general_defaults_form.general_gui_group.gridy_entry, + "global_snap_max": self.general_defaults_form.general_gui_group.snap_max_dist_entry, "global_plot_fill": self.general_defaults_form.general_gui_group.pf_color_entry, "global_plot_line": self.general_defaults_form.general_gui_group.pl_color_entry, "global_sel_fill": self.general_defaults_form.general_gui_group.sf_color_entry, @@ -313,7 +316,6 @@ class App(QtCore.QObject): # "global_pan_with_space_key": self.general_defaults_form.general_gui_group.pan_with_space_cb, "global_workspace": self.general_defaults_form.general_gui_group.workspace_cb, "global_workspaceT": self.general_defaults_form.general_gui_group.wk_cb, - "global_theme": self.general_defaults_form.general_gui_group.theme_combo, "gerber_plot": self.gerber_defaults_form.gerber_gen_group.plot_cb, "gerber_solid": self.gerber_defaults_form.gerber_gen_group.solid_cb, @@ -439,6 +441,8 @@ class App(QtCore.QObject): "global_send_stats": True, "global_gridx": 1.0, "global_gridy": 1.0, + "global_snap_max": 0.05, + "global_plot_fill": '#BBF268BF', "global_plot_line": '#006E20BF', "global_sel_fill": '#a5a5ffbf', @@ -452,7 +456,7 @@ class App(QtCore.QObject): # "global_pan_with_space_key": False, "global_workspace": False, "global_workspaceT": "A4P", - "global_toolbar_view": 31, + "global_toolbar_view": 127, "global_background_timeout": 300000, # Default value is 5 minutes "global_verbose_error_level": 0, # Shell verbosity 0 = default @@ -469,7 +473,6 @@ class App(QtCore.QObject): "global_def_win_y": 100, "global_def_win_w": 1024, "global_def_win_h": 650, - "global_theme": 'standard', # Constants... "global_defaults_save_period_ms": 20000, # Time between default saves. @@ -625,7 +628,7 @@ class App(QtCore.QObject): "units": self.general_options_form.general_app_group.units_radio, "global_gridx": self.general_options_form.general_gui_group.gridx_entry, "global_gridy": self.general_options_form.general_gui_group.gridy_entry, - "global_theme": self.general_options_form.general_gui_group.theme_combo, + "global_snap_max": self.general_options_form.general_gui_group.snap_max_dist_entry, "gerber_plot": self.gerber_options_form.gerber_gen_group.plot_cb, "gerber_solid": self.gerber_options_form.gerber_gen_group.solid_cb, @@ -729,11 +732,11 @@ class App(QtCore.QObject): "units": "IN", "global_gridx": 1.0, "global_gridy": 1.0, + "global_snap_max": 0.05, "global_background_timeout": 300000, # Default value is 5 minutes "global_verbose_error_level": 0, # Shell verbosity: # 0 = default(python trace only for unknown errors), # 1 = show trace(show trace allways), 2 = (For the future). - "global_theme": 'standard', "gerber_plot": True, "gerber_solid": True, @@ -924,12 +927,6 @@ class App(QtCore.QObject): self.geo_editor = FlatCAMGeoEditor(self, disabled=True) self.exc_editor = FlatCAMExcEditor(self) - # start with GRID activated - self.ui.grid_snap_btn.trigger() - self.ui.corner_snap_btn.setVisible(False) - self.ui.snap_magnet.setVisible(False) - self.ui.g_editor_cmenu.setEnabled(False) - self.ui.e_editor_cmenu.setEnabled(False) #### Adjust tabs width #### # self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() + @@ -1157,7 +1154,7 @@ class App(QtCore.QObject): self.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified) self.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace) - self.general_defaults_form.general_gui_group.theme_combo.currentIndexChanged.connect(self.on_theme) + self.general_defaults_form.general_gui_group.theme_combo.activated.connect(self.on_theme) # Modify G-CODE Plot Area TAB self.ui.code_editor.textChanged.connect(self.handleTextChanged) @@ -1497,26 +1494,21 @@ class App(QtCore.QObject): self.ui.popmenu_edit.setVisible(False) self.ui.popmenu_save.setVisible(True) - if isinstance(self.collection.get_active(), FlatCAMGeometry): - edited_object = self.collection.get_active() + edited_object = self.collection.get_active() + + if isinstance(edited_object, FlatCAMGeometry): # for now, if the Geometry is MultiGeo do not allow the editing if edited_object.multigeo is True: self.inform.emit("[warning_notcl]Editing a MultiGeo Geometry is not possible for the moment.") return - self.ui.update_obj_btn.setEnabled(True) + self.geo_editor.edit_fcgeometry(edited_object) - self.ui.g_editor_cmenu.setEnabled(True) # set call source to the Editor we go into self.call_source = 'geo_editor' - # prevent the user to change anything in the Selected Tab while the Geo Editor is active - sel_tab_widget_list = self.ui.selected_tab.findChildren(QtWidgets.QWidget) - for w in sel_tab_widget_list: - w.setEnabled(False) - elif isinstance(self.collection.get_active(), FlatCAMExcellon): - self.ui.update_obj_btn.setEnabled(True) - self.exc_editor.edit_exc_obj(self.collection.get_active()) - self.ui.e_editor_cmenu.setEnabled(True) + elif isinstance(edited_object, FlatCAMExcellon): + self.exc_editor.edit_fcexcellon(edited_object) + # set call source to the Editor we go into self.call_source = 'exc_editor' else: @@ -1529,7 +1521,6 @@ class App(QtCore.QObject): # delete any selection shape that might be active as they are not relevant in Editor self.delete_selection_shape() - self.ui.plot_tab_area.setTabText(0, "EDITOR Area") self.ui.plot_tab_area.protectTab(0) self.inform.emit("[warning_notcl]Editor is activated ...") @@ -1552,17 +1543,8 @@ class App(QtCore.QObject): obj_type = "Geometry" self.geo_editor.update_fcgeometry(edited_obj) self.geo_editor.update_options(edited_obj) - self.geo_editor.deactivate() - # edited_obj.on_tool_delete(all=True) - # edited_obj.on_tool_add(dia=edited_obj.options['cnctooldia']) - - self.ui.corner_snap_btn.setEnabled(False) - self.ui.update_obj_btn.setEnabled(False) - self.ui.g_editor_cmenu.setEnabled(False) - self.ui.e_editor_cmenu.setEnabled(False) - # update the geo object options so it is including the bounding box values try: xmin, ymin, xmax, ymax = edited_obj.bounds() @@ -1575,15 +1557,18 @@ class App(QtCore.QObject): elif isinstance(edited_obj, FlatCAMExcellon): obj_type = "Excellon" - - self.exc_editor.update_exc_obj(edited_obj) - + self.exc_editor.update_fcexcellon(edited_obj) self.exc_editor.deactivate() - self.ui.corner_snap_btn.setEnabled(False) - self.ui.update_obj_btn.setEnabled(False) - self.ui.g_editor_cmenu.setEnabled(False) - self.ui.e_editor_cmenu.setEnabled(False) + # update the exc object options so it is including the bounding box values + try: + xmin, ymin, xmax, ymax = edited_obj.bounds() + edited_obj.options['xmin'] = xmin + edited_obj.options['ymin'] = ymin + edited_obj.options['xmax'] = xmax + edited_obj.options['ymax'] = ymax + except AttributeError: + self.inform.emit("[warning] Object empty after edit.") else: self.inform.emit("[warning_notcl]Select a Geometry or Excellon Object to update.") return @@ -1860,6 +1845,16 @@ class App(QtCore.QObject): self.ui.toolbartools.setVisible(False) if tb & 16: + self.ui.exc_edit_toolbar.setVisible(True) + else: + self.ui.exc_edit_toolbar.setVisible(False) + + if tb & 32: + self.ui.geo_edit_toolbar.setVisible(True) + else: + self.ui.geo_edit_toolbar.setVisible(False) + + if tb & 64: self.ui.snap_toolbar.setVisible(True) else: self.ui.snap_toolbar.setVisible(False) @@ -1879,14 +1874,14 @@ class App(QtCore.QObject): self.log.error("Could not load defaults file.") self.inform.emit("[error] Could not load defaults file.") # in case the defaults file can't be loaded, show all toolbars - self.defaults["global_toolbar_view"] = 31 + self.defaults["global_toolbar_view"] = 127 return try: defaults = json.loads(options) except: # in case the defaults file can't be loaded, show all toolbars - self.defaults["global_toolbar_view"] = 31 + self.defaults["global_toolbar_view"] = 127 e = sys.exc_info()[0] App.log.error(str(e)) self.inform.emit("[error] Failed to parse defaults file.") @@ -2404,9 +2399,15 @@ class App(QtCore.QObject): if self.ui.toolbartools.isVisible(): tb_status += 8 - if self.ui.snap_toolbar.isVisible(): + if self.ui.exc_edit_toolbar.isVisible(): tb_status += 16 + if self.ui.geo_edit_toolbar.isVisible(): + tb_status += 32 + + if self.ui.snap_toolbar.isVisible(): + tb_status += 64 + self.defaults["global_toolbar_view"] = tb_status if not silent: @@ -3129,7 +3130,94 @@ class App(QtCore.QObject): self.on_workspace() def on_theme(self): - self.defaults["global_theme"] = self.general_defaults_form.general_gui_group.theme_combo.get_value() + current_theme= self.general_defaults_form.general_gui_group.theme_combo.get_value().lower() + + settings = QSettings("Open Source", "FlatCAM") + settings.setValue('theme', current_theme) + + # This will write the setting to the platform specific storage. + del settings + + # first remove the toolbars: + self.ui.removeToolBar(self.ui.toolbarfile) + self.ui.removeToolBar(self.ui.toolbargeo) + self.ui.removeToolBar(self.ui.toolbarview) + self.ui.removeToolBar(self.ui.toolbartools) + self.ui.removeToolBar(self.ui.exc_edit_toolbar) + self.ui.removeToolBar(self.ui.geo_edit_toolbar) + self.ui.removeToolBar(self.ui.snap_toolbar) + + if current_theme == 'standard': + ### TOOLBAR INSTALLATION ### + self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') + self.ui.toolbarfile.setObjectName('File_TB') + self.ui.addToolBar(self.ui.toolbarfile) + + self.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') + self.ui.toolbargeo.setObjectName('Edit_TB') + self.ui.addToolBar(self.ui.toolbargeo) + + self.ui.toolbarview = QtWidgets.QToolBar('View Toolbar') + self.ui.toolbarview.setObjectName('View_TB') + self.ui.addToolBar(self.ui.toolbarview) + + self.ui.toolbartools = QtWidgets.QToolBar('Tools Toolbar') + self.ui.toolbartools.setObjectName('Tools_TB') + self.ui.addToolBar(self.ui.toolbartools) + + self.ui.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') + self.ui.exc_edit_toolbar.setVisible(False) + self.ui.exc_edit_toolbar.setObjectName('ExcEditor_TB') + self.ui.addToolBar(self.ui.exc_edit_toolbar) + + self.ui.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') + self.ui.geo_edit_toolbar.setVisible(False) + self.ui.geo_edit_toolbar.setObjectName('GeoEditor_TB') + self.ui.addToolBar(self.ui.geo_edit_toolbar) + + self.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') + self.ui.snap_toolbar.setObjectName('Snap_TB') + # self.ui.snap_toolbar.setMaximumHeight(30) + self.ui.addToolBar(self.ui.snap_toolbar) + + self.ui.corner_snap_btn.setVisible(False) + self.ui.snap_magnet.setVisible(False) + elif current_theme == 'compact': + ### TOOLBAR INSTALLATION ### + self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') + self.ui.toolbarfile.setObjectName('File_TB') + self.ui.addToolBar(Qt.LeftToolBarArea, self.ui.toolbarfile) + self.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar') + self.ui.toolbargeo.setObjectName('Edit_TB') + self.ui.addToolBar(Qt.LeftToolBarArea, self.ui.toolbargeo) + self.ui.toolbarview = QtWidgets.QToolBar('View Toolbar') + self.ui.toolbarview.setObjectName('View_TB') + self.ui.addToolBar(Qt.LeftToolBarArea, self.ui.toolbarview) + self.ui.toolbartools = QtWidgets.QToolBar('Tools Toolbar') + self.ui.toolbartools.setObjectName('Tools_TB') + self.ui.addToolBar(Qt.LeftToolBarArea, self.ui.toolbartools) + self.ui.exc_edit_toolbar = QtWidgets.QToolBar('Excellon Editor Toolbar') + self.ui.exc_edit_toolbar.setObjectName('ExcEditor_TB') + self.ui.addToolBar(Qt.LeftToolBarArea, self.ui.exc_edit_toolbar) + self.ui.geo_edit_toolbar = QtWidgets.QToolBar('Geometry Editor Toolbar') + self.ui.geo_edit_toolbar.setVisible(False) + self.ui.geo_edit_toolbar.setObjectName('GeoEditor_TB') + self.ui.addToolBar(Qt.RightToolBarArea, self.ui.geo_edit_toolbar) + self.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') + self.ui.snap_toolbar.setObjectName('Snap_TB') + self.ui.snap_toolbar.setMaximumHeight(30) + self.ui.splitter_left.addWidget(self.ui.snap_toolbar) + + self.ui.corner_snap_btn.setVisible(True) + self.ui.snap_magnet.setVisible(True) + + self.ui.populate_toolbars() + + self.ui.grid_snap_btn.setChecked(True) + self.ui.grid_gap_x_entry.setText(str(self.defaults["global_gridx"])) + self.ui.grid_gap_y_entry.setText(str(self.defaults["global_gridy"])) + self.ui.snap_max_dist_entry.setText(str(self.defaults["global_snap_max"])) + self.ui.grid_gap_link_cb.setChecked(True) def on_save_button(self): self.save_defaults(silent=False) diff --git a/FlatCAMEditor.py b/FlatCAMEditor.py index 01d68051..0df5e937 100644 --- a/FlatCAMEditor.py +++ b/FlatCAMEditor.py @@ -7,7 +7,7 @@ ############################################################ from PyQt5 import QtGui, QtCore, QtWidgets -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QSettings import FlatCAMApp from camlib import * from FlatCAMTool import FlatCAMTool @@ -1890,9 +1890,6 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app = app self.canvas = app.plotcanvas - self.app.ui.geo_edit_toolbar.setDisabled(True) - self.app.ui.snap_magnet.setVisible(False) - self.app.ui.geo_add_circle_menuitem.triggered.connect(lambda: self.select_tool('circle')) self.app.ui.geo_add_arc_menuitem.triggered.connect(lambda: self.select_tool('arc')) self.app.ui.geo_add_rectangle_menuitem.triggered.connect(lambda: self.select_tool('rectangle')) @@ -1996,7 +1993,7 @@ class FlatCAMGeoEditor(QtCore.QObject): self.options = { "global_gridx": 0.1, "global_gridy": 0.1, - "snap_max": 0.05, + "global_snap_max": 0.05, "grid_snap": True, "corner_snap": False, "grid_gap_link": True @@ -2009,7 +2006,7 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app.ui.grid_gap_x_entry.setText(str(self.options["global_gridx"])) self.app.ui.grid_gap_y_entry.setText(str(self.options["global_gridy"])) - self.app.ui.snap_max_dist_entry.setText(str(self.options["snap_max"])) + self.app.ui.snap_max_dist_entry.setText(str(self.options["global_snap_max"])) self.app.ui.grid_gap_link_cb.setChecked(True) self.rtree_index = rtindex.Index() @@ -2053,6 +2050,19 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app.ui.geo_editor_menu.setDisabled(False) self.app.ui.geo_editor_menu.menuAction().setVisible(True) + + self.app.ui.update_obj_btn.setEnabled(True) + self.app.ui.g_editor_cmenu.setEnabled(True) + + self.app.ui.geo_edit_toolbar.setDisabled(False) + self.app.ui.geo_edit_toolbar.setVisible(True) + self.app.ui.snap_toolbar.setDisabled(False) + + # prevent the user to change anything in the Selected Tab while the Geo Editor is active + sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget) + for w in sel_tab_widget_list: + w.setEnabled(False) + # Tell the App that the editor is active self.editor_active = True @@ -2060,11 +2070,20 @@ class FlatCAMGeoEditor(QtCore.QObject): self.disconnect_canvas_event_handlers() self.clear() self.app.ui.geo_edit_toolbar.setDisabled(True) - self.app.ui.geo_edit_toolbar.setVisible(False) - self.app.ui.snap_magnet.setVisible(False) - self.app.ui.corner_snap_btn.setVisible(False) - # never deactivate the snap toolbar - MS - # self.app.ui.snap_toolbar.setDisabled(True) # TODO: Combine and move into tool + + settings = QSettings("Open Source", "FlatCAM") + if settings.contains("theme"): + theme = settings.value('theme', type=str) + if theme == 'standard': + self.app.ui.geo_edit_toolbar.setVisible(False) + self.app.ui.snap_magnet.setVisible(False) + self.app.ui.corner_snap_btn.setVisible(False) + elif theme == 'compact': + pass + else: + self.app.ui.geo_edit_toolbar.setVisible(False) + self.app.ui.snap_magnet.setVisible(False) + self.app.ui.corner_snap_btn.setVisible(False) # Disable visuals self.shapes.enabled = False @@ -2073,6 +2092,12 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app.ui.geo_editor_menu.setDisabled(True) self.app.ui.geo_editor_menu.menuAction().setVisible(False) + + self.app.ui.corner_snap_btn.setEnabled(False) + self.app.ui.update_obj_btn.setEnabled(False) + self.app.ui.g_editor_cmenu.setEnabled(False) + self.app.ui.e_editor_cmenu.setEnabled(False) + # Tell the app that the editor is no longer active self.editor_active = False @@ -2232,9 +2257,7 @@ class FlatCAMGeoEditor(QtCore.QObject): self.add_shape(DrawToolShape(shape)) self.replot() - self.app.ui.geo_edit_toolbar.setDisabled(False) - self.app.ui.geo_edit_toolbar.setVisible(True) - self.app.ui.snap_toolbar.setDisabled(False) + # start with GRID toolbar activated if self.app.ui.grid_snap_btn.isChecked() == False: @@ -2947,7 +2970,7 @@ class FlatCAMGeoEditor(QtCore.QObject): nearest_pt, shape = self.storage.nearest((x, y)) nearest_pt_distance = distance((x, y), nearest_pt) - if nearest_pt_distance <= self.options["snap_max"]: + if nearest_pt_distance <= self.options["global_snap_max"]: snap_distance = nearest_pt_distance snap_x, snap_y = nearest_pt except (StopIteration, AssertionError): @@ -4191,6 +4214,17 @@ class FlatCAMExcEditor(QtCore.QObject): self.app.ui.exc_editor_menu.setDisabled(False) self.app.ui.exc_editor_menu.menuAction().setVisible(True) + self.app.ui.update_obj_btn.setEnabled(True) + self.app.ui.e_editor_cmenu.setEnabled(True) + + self.app.ui.exc_edit_toolbar.setDisabled(False) + self.app.ui.exc_edit_toolbar.setVisible(True) + # self.app.ui.snap_toolbar.setDisabled(False) + + # start with GRID toolbar activated + if self.app.ui.grid_snap_btn.isChecked() is False: + self.app.ui.grid_snap_btn.trigger() + # Tell the App that the editor is active self.editor_active = True @@ -4198,9 +4232,18 @@ class FlatCAMExcEditor(QtCore.QObject): self.disconnect_canvas_event_handlers() self.clear() self.app.ui.exc_edit_toolbar.setDisabled(True) - self.app.ui.exc_edit_toolbar.setVisible(False) - self.app.ui.snap_magnet.setVisible(False) - self.app.ui.corner_snap_btn.setVisible(False) + + settings = QSettings("Open Source", "FlatCAM") + if settings.contains("theme"): + theme = settings.value('theme', type=str) + if theme == 'standard': + self.app.ui.exc_edit_toolbar.setVisible(False) + self.app.ui.snap_magnet.setVisible(False) + self.app.ui.corner_snap_btn.setVisible(False) + elif theme == 'compact': + pass + else: + pass # Disable visuals self.shapes.enabled = False @@ -4212,6 +4255,10 @@ class FlatCAMExcEditor(QtCore.QObject): self.app.ui.exc_editor_menu.setDisabled(True) self.app.ui.exc_editor_menu.menuAction().setVisible(False) + self.app.ui.corner_snap_btn.setEnabled(False) + self.app.ui.update_obj_btn.setEnabled(False) + self.app.ui.g_editor_cmenu.setEnabled(False) + self.app.ui.e_editor_cmenu.setEnabled(False) # Show original geometry if self.exc_obj: @@ -4270,7 +4317,7 @@ class FlatCAMExcEditor(QtCore.QObject): # self.storage = FlatCAMExcEditor.make_storage() self.replot() - def edit_exc_obj(self, exc_obj): + def edit_fcexcellon(self, exc_obj): """ Imports the geometry from the given FlatCAM Excellon object into the editor. @@ -4318,15 +4365,8 @@ class FlatCAMExcEditor(QtCore.QObject): self.storage_dict[tool_dia] = storage_elem self.replot() - self.app.ui.exc_edit_toolbar.setDisabled(False) - self.app.ui.exc_edit_toolbar.setVisible(True) - self.app.ui.snap_toolbar.setDisabled(False) - # start with GRID toolbar activated - if self.app.ui.grid_snap_btn.isChecked() is False: - self.app.ui.grid_snap_btn.trigger() - - def update_exc_obj(self, exc_obj): + def update_fcexcellon(self, exc_obj): """ Create a new Excellon object that contain the edited content of the source Excellon object diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py index e3205ffe..0057922a 100644 --- a/FlatCAMGUI.py +++ b/FlatCAMGUI.py @@ -7,7 +7,7 @@ ############################################################ from PyQt5 import QtGui, QtCore, QtWidgets -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QSettings from GUIElements import * import platform @@ -405,136 +405,19 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.exc_edit_toolbar.setObjectName('ExcEditor_TB') self.addToolBar(self.exc_edit_toolbar) 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.geo_edit_toolbar) - self.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') - self.snap_toolbar.setObjectName('Snap_TB') - # self.snap_toolbar.setMaximumHeight(30) - self.addToolBar(self.snap_toolbar) - - ### File Toolbar ### - self.file_open_gerber_btn = self.toolbarfile.addAction(QtGui.QIcon('share/flatcam_icon32.png'), - "Open GERBER") - self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), "Open EXCELLON") - self.toolbarfile.addSeparator() - self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), "Open project") - self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/floppy32.png'), "Save project") - - ### Edit Toolbar ### - self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), "New Blank Geometry") - self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), "New Blank Excellon") - self.toolbargeo.addSeparator() - self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), "Editor") - self.update_obj_btn = self.toolbargeo.addAction( - QtGui.QIcon('share/edit_ok32_bis.png'), "Save Object and close the Editor" - ) - self.update_obj_btn.setEnabled(False) - self.toolbargeo.addSeparator() - self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/cancel_edit32.png'), "&Delete") - - ### View Toolbar ### - self.replot_btn = self.toolbarview.addAction(QtGui.QIcon('share/replot32.png'), "&Replot") - self.clear_plot_btn = self.toolbarview.addAction(QtGui.QIcon('share/clear_plot32.png'), "&Clear plot") - self.zoom_in_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_in32.png'), "Zoom In") - self.zoom_out_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_out32.png'), "Zoom Out") - self.zoom_fit_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_fit32.png'), "Zoom Fit") - - # self.toolbarview.setVisible(False) - - ### Tools Toolbar ### - self.shell_btn = self.toolbartools.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line") - - ### Drill Editor Toolbar ### - self.select_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'") - self.add_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/plus16.png'), 'Add Drill Hole') - self.add_drill_array_btn = self.exc_edit_toolbar.addAction( - QtGui.QIcon('share/addarray16.png'), 'Add Drill Hole Array') - self.resize_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/resize16.png'), 'Resize Drill') - self.exc_edit_toolbar.addSeparator() - - self.copy_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/copy32.png'), 'Copy Drill') - self.delete_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Drill") - - self.exc_edit_toolbar.addSeparator() - self.move_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Drill") - - self.exc_edit_toolbar.setDisabled(True) - self.exc_edit_toolbar.setVisible(False) - - ### Geometry Editor Toolbar ### - self.geo_select_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'") - self.geo_add_circle_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/circle32.png'), 'Add Circle') - self.geo_add_arc_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/arc32.png'), 'Add Arc') - self.geo_add_rectangle_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle') - - self.geo_edit_toolbar.addSeparator() - self.geo_add_path_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/path32.png'), 'Add Path') - self.geo_add_polygon_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon') - self.geo_edit_toolbar.addSeparator() - self.geo_add_text_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/text32.png'), 'Add Text') - self.geo_add_buffer_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/buffer16-2.png'), 'Add Buffer') - self.geo_add_paint_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/paint20_1.png'), 'Paint Shape') - - self.geo_edit_toolbar.addSeparator() - self.geo_union_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/union32.png'), 'Polygon Union') - self.geo_intersection_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), - 'Polygon Intersection') - self.geo_subtract_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), 'Polygon Subtraction') - - self.geo_edit_toolbar.addSeparator() - self.geo_cutpath_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/cutpath32.png'), 'Cut Path') - self.geo_copy_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/copy32.png'), "Copy Objects 'c'") - self.geo_rotate_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/rotate.png'), "Rotate Objects 'Space'") - self.geo_delete_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Shape '-'") - - self.geo_edit_toolbar.addSeparator() - self.geo_move_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Objects 'm'") - - ### Snap Toolbar ### - # Snap GRID toolbar is always active to facilitate usage of measurements done on GRID - # self.addToolBar(self.snap_toolbar) - - self.grid_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/grid32.png'), 'Snap to grid') - self.grid_gap_x_entry = FCEntry2() - self.grid_gap_x_entry.setMaximumWidth(70) - self.grid_gap_x_entry.setToolTip("Grid X distance") - self.snap_toolbar.addWidget(self.grid_gap_x_entry) - - self.grid_gap_y_entry = FCEntry2() - self.grid_gap_y_entry.setMaximumWidth(70) - self.grid_gap_y_entry.setToolTip("Grid Y distance") - self.snap_toolbar.addWidget(self.grid_gap_y_entry) - - self.grid_space_label = QtWidgets.QLabel(" ") - self.snap_toolbar.addWidget(self.grid_space_label) - self.grid_gap_link_cb = FCCheckBox() - self.grid_gap_link_cb.setToolTip("When active, value on Grid_X\n" - "is copied to the Grid_Y value.") - self.snap_toolbar.addWidget(self.grid_gap_link_cb) - - self.ois_grid = OptionalInputSection(self.grid_gap_link_cb, [self.grid_gap_y_entry], logic=False) - - self.corner_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/corner32.png'), 'Snap to corner') - - self.snap_max_dist_entry = FCEntry() - self.snap_max_dist_entry.setMaximumWidth(70) - self.snap_max_dist_entry.setToolTip("Max. magnet distance") - self.snap_magnet = self.snap_toolbar.addWidget(self.snap_max_dist_entry) - - self.grid_snap_btn.setCheckable(True) - self.corner_snap_btn.setCheckable(True) - ################ ### Splitter ### ################ + + # IMPORTANT # + # The order: SPITTER -> NOTEBOOK -> SNAP TOOLBAR is important and without it the GUI will not be initialized as + # desired. self.splitter = QtWidgets.QSplitter() self.setCentralWidget(self.splitter) - ################ - ### Notebook ### - ################ self.notebook = QtWidgets.QTabWidget() self.splitter.addWidget(self.notebook) @@ -543,6 +426,28 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.splitter_left.addWidget(self.notebook) self.splitter_left.setHandleWidth(0) + self.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar') + self.snap_toolbar.setObjectName('Snap_TB') + + settings = QSettings("Open Source", "FlatCAM") + if settings.contains("theme"): + theme = settings.value('theme', type=str) + if theme == 'standard': + self.addToolBar(self.snap_toolbar) + elif theme == 'compact': + self.snap_toolbar.setMaximumHeight(30) + self.splitter_left.addWidget(self.snap_toolbar) + else: + self.addToolBar(self.snap_toolbar) + + # add the actions/widgets to the toolbars + self.populate_toolbars() + + + ################ + ### Notebook ### + ################ + ### Project ### self.project_tab = QtWidgets.QWidget() # project_tab.setMinimumWidth(250) # Hack @@ -879,14 +784,190 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.filename = "" self.setAcceptDrops(True) + # # restore the Toolbar State from file + # try: + # with open(self.app.data_path + '\gui_state.config', 'rb') as stream: + # self.restoreState(QtCore.QByteArray(stream.read())) + # log.debug("FlatCAMGUI.__init__() --> UI state restored.") + # except IOError: + # log.debug("FlatCAMGUI.__init__() --> UI state not restored. IOError") + # pass + + ###################### + ### INITIALIZE GUI ### + ###################### + + self.grid_snap_btn.setCheckable(True) + self.corner_snap_btn.setCheckable(True) + self.update_obj_btn.setEnabled(False) + # start with GRID activated + self.grid_snap_btn.trigger() + # restore the Toolbar State from file - try: - with open(self.app.data_path + '\gui_state.config', 'rb') as stream: - self.restoreState(QtCore.QByteArray(stream.read())) + settings = QSettings("Open Source", "FlatCAM") + if settings.contains("saved_gui_state"): + saved_gui_state = settings.value('saved_gui_state') + self.restoreState(saved_gui_state) log.debug("FlatCAMGUI.__init__() --> UI state restored.") - except IOError: - log.debug("FlatCAMGUI.__init__() --> UI state not restored. IOError") - pass + + if settings.contains("theme"): + theme = settings.value('theme', type=str) + if theme == 'standard': + self.exc_edit_toolbar.setVisible(False) + self.exc_edit_toolbar.setDisabled(True) + self.geo_edit_toolbar.setVisible(False) + self.geo_edit_toolbar.setDisabled(True) + + self.g_editor_cmenu.setEnabled(False) + self.e_editor_cmenu.setEnabled(False) + + self.corner_snap_btn.setVisible(False) + self.snap_magnet.setVisible(False) + elif theme == 'compact': + self.exc_edit_toolbar.setDisabled(True) + self.geo_edit_toolbar.setDisabled(True) + self.snap_magnet.setVisible(True) + self.corner_snap_btn.setVisible(True) + else: + self.exc_edit_toolbar.setVisible(False) + self.exc_edit_toolbar.setDisabled(True) + self.geo_edit_toolbar.setVisible(False) + self.geo_edit_toolbar.setDisabled(True) + + self.g_editor_cmenu.setEnabled(False) + self.e_editor_cmenu.setEnabled(False) + + self.corner_snap_btn.setVisible(False) + self.snap_magnet.setVisible(False) + + def populate_toolbars(self): + ### File Toolbar ### + self.file_open_gerber_btn = self.toolbarfile.addAction(QtGui.QIcon('share/flatcam_icon32.png'), + "Open GERBER") + self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), "Open EXCELLON") + self.toolbarfile.addSeparator() + self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), "Open project") + self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/floppy32.png'), "Save project") + + ### Edit Toolbar ### + self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), "New Blank Geometry") + self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), "New Blank Excellon") + self.toolbargeo.addSeparator() + self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), "Editor") + self.update_obj_btn = self.toolbargeo.addAction( + QtGui.QIcon('share/edit_ok32_bis.png'), "Save Object and close the Editor" + ) + + self.toolbargeo.addSeparator() + self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/cancel_edit32.png'), "&Delete") + + ### View Toolbar ### + self.replot_btn = self.toolbarview.addAction(QtGui.QIcon('share/replot32.png'), "&Replot") + self.clear_plot_btn = self.toolbarview.addAction(QtGui.QIcon('share/clear_plot32.png'), "&Clear plot") + self.zoom_in_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_in32.png'), "Zoom In") + self.zoom_out_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_out32.png'), "Zoom Out") + self.zoom_fit_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_fit32.png'), "Zoom Fit") + + # self.toolbarview.setVisible(False) + + ### Tools Toolbar ### + self.shell_btn = self.toolbartools.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line") + + ### Drill Editor Toolbar ### + self.select_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'") + self.add_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/plus16.png'), 'Add Drill Hole') + self.add_drill_array_btn = self.exc_edit_toolbar.addAction( + QtGui.QIcon('share/addarray16.png'), 'Add Drill Hole Array') + self.resize_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/resize16.png'), 'Resize Drill') + self.exc_edit_toolbar.addSeparator() + + self.copy_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/copy32.png'), 'Copy Drill') + self.delete_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Drill") + + self.exc_edit_toolbar.addSeparator() + self.move_drill_btn = self.exc_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Drill") + + ### Geometry Editor Toolbar ### + self.geo_select_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'") + self.geo_add_circle_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/circle32.png'), 'Add Circle') + self.geo_add_arc_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/arc32.png'), 'Add Arc') + self.geo_add_rectangle_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle') + + self.geo_edit_toolbar.addSeparator() + self.geo_add_path_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/path32.png'), 'Add Path') + self.geo_add_polygon_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon') + self.geo_edit_toolbar.addSeparator() + self.geo_add_text_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/text32.png'), 'Add Text') + self.geo_add_buffer_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/buffer16-2.png'), 'Add Buffer') + self.geo_add_paint_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/paint20_1.png'), 'Paint Shape') + + self.geo_edit_toolbar.addSeparator() + self.geo_union_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/union32.png'), 'Polygon Union') + self.geo_intersection_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), + 'Polygon Intersection') + self.geo_subtract_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), 'Polygon Subtraction') + + self.geo_edit_toolbar.addSeparator() + self.geo_cutpath_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/cutpath32.png'), 'Cut Path') + self.geo_copy_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/copy32.png'), "Copy Objects 'c'") + self.geo_rotate_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/rotate.png'), "Rotate Objects 'Space'") + self.geo_delete_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Shape '-'") + + self.geo_edit_toolbar.addSeparator() + self.geo_move_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Objects 'm'") + + ### Snap Toolbar ### + # Snap GRID toolbar is always active to facilitate usage of measurements done on GRID + # self.addToolBar(self.snap_toolbar) + + self.grid_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/grid32.png'), 'Snap to grid') + self.grid_gap_x_entry = FCEntry2() + self.grid_gap_x_entry.setMaximumWidth(70) + self.grid_gap_x_entry.setToolTip("Grid X distance") + self.snap_toolbar.addWidget(self.grid_gap_x_entry) + + self.grid_gap_y_entry = FCEntry2() + self.grid_gap_y_entry.setMaximumWidth(70) + self.grid_gap_y_entry.setToolTip("Grid Y distance") + self.snap_toolbar.addWidget(self.grid_gap_y_entry) + + self.grid_space_label = QtWidgets.QLabel(" ") + self.snap_toolbar.addWidget(self.grid_space_label) + self.grid_gap_link_cb = FCCheckBox() + self.grid_gap_link_cb.setToolTip("When active, value on Grid_X\n" + "is copied to the Grid_Y value.") + self.snap_toolbar.addWidget(self.grid_gap_link_cb) + + self.ois_grid = OptionalInputSection(self.grid_gap_link_cb, [self.grid_gap_y_entry], logic=False) + + self.corner_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/corner32.png'), 'Snap to corner') + + self.snap_max_dist_entry = FCEntry() + self.snap_max_dist_entry.setMaximumWidth(70) + self.snap_max_dist_entry.setToolTip("Max. magnet distance") + self.snap_magnet = self.snap_toolbar.addWidget(self.snap_max_dist_entry) + + settings = QSettings("Open Source", "FlatCAM") + if settings.contains("theme"): + theme = settings.value('theme', type=str) + if theme == 'standard': + self.exc_edit_toolbar.setVisible(False) + self.exc_edit_toolbar.setDisabled(True) + self.geo_edit_toolbar.setVisible(False) + self.geo_edit_toolbar.setDisabled(True) + + self.corner_snap_btn.setVisible(False) + self.snap_magnet.setVisible(False) + elif theme == 'compact': + self.exc_edit_toolbar.setVisible(True) + self.exc_edit_toolbar.setDisabled(True) + self.geo_edit_toolbar.setVisible(True) + self.geo_edit_toolbar.setDisabled(True) + + self.corner_snap_btn.setVisible(True) + self.snap_magnet.setVisible(True) + self.corner_snap_btn.setDisabled(True) + self.snap_magnet.setDisabled(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls: @@ -954,10 +1035,19 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.final_save.emit() if self.app.should_we_quit is True: + # # save toolbar state to file + # with open(self.app.data_path + '\gui_state.config', 'wb') as stream: + # stream.write(self.saveState().data()) + # log.debug("FlatCAMGUI.__init__() --> UI state saved.") + # QtWidgets.qApp.quit() + # save toolbar state to file - with open(self.app.data_path + '\gui_state.config', 'wb') as stream: - stream.write(self.saveState().data()) - log.debug("FlatCAMGUI.__init__() --> UI state saved.") + settings = QSettings("Open Source", "FlatCAM") + settings.setValue('saved_gui_state', self.saveState()) + + # This will write the setting to the platform specific storage. + del settings + log.debug("FlatCAMGUI.__init__() --> UI state saved.") QtWidgets.qApp.quit() else: self.app.should_we_quit = True @@ -1119,6 +1209,11 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI): ) self.gridy_entry = LengthEntry() + # Snap Max Entry + self.snap_max_label = QtWidgets.QLabel('Snap Max:') + self.snap_max_label.setToolTip("Max. magnet distance") + self.snap_max_dist_entry = FCEntry() + # Workspace self.workspace_lbl = QtWidgets.QLabel('Workspace:') self.workspace_lbl.setToolTip( @@ -1324,6 +1419,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI): self.theme_combo = FCComboBox() self.theme_combo.addItem("Standard") self.theme_combo.addItem("Compact") + self.theme_combo.setCurrentIndex(0) # Just to add empty rows self.spacelabel = QtWidgets.QLabel('') @@ -1334,6 +1430,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI): self.form_box.addRow(self.gridx_label, self.gridx_entry) self.form_box.addRow(self.gridy_label, self.gridy_entry) + self.form_box.addRow(self.snap_max_label, self.snap_max_dist_entry) self.form_box.addRow(self.workspace_lbl, self.workspace_cb) self.form_box.addRow(self.workspace_type_lbl, self.wk_cb) diff --git a/README.md b/README.md index 4f9c9ac1..4619c7b5 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,9 @@ CAD program, and create G-Code for Isolation routing. - All the tabs in the GUI right side are (Plot Are, Preferences etc) are now detachable to a separate windows which when closed it returns in the previous location in the toolbar. Those detached tabs can be also reattached by drag and drop. - fixed postprocessor files so now the bounds values are right aligned (assuming max string length of 9 chars which means 4 digits and 4 decimals) - corrected small type in list_sys Tcl command; added a protection of the Plot Area Tab after a successful edit. - +- remade the way FlatCAM saves the GUI position data from a file (previously) to use PyQt QSettings +- added a 'theme' combo selection in Edit -> Preferences. Two themes are available: standard and compact. +- some code cleanup 30.01.2019