From 4458249ee52c14c8e9c82f83ad45cc1fe2c89351 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Tue, 14 Nov 2023 21:49:17 +0200 Subject: [PATCH] - trying to solve an idiosyncrasy of MacOS which do not allow modifying the main menu in a non-main thread which is done after editing an object --- CHANGELOG.md | 10 +++-- appDatabase.py | 2 +- appEditors/AppExcEditor.py | 2 +- appEditors/AppGeoEditor.py | 2 +- appEditors/AppGerberEditor.py | 81 ++++++++++++++++------------------- appEditors/appGCodeEditor.py | 4 +- appGUI/MainGUI.py | 10 ++--- appHandlers/AppIO.py | 2 +- appMain.py | 70 ++++++++++++++++-------------- appObjects/CNCJobObject.py | 2 +- appObjects/ExcellonObject.py | 2 +- appObjects/GeometryObject.py | 6 +-- appObjects/GerberObject.py | 2 +- 13 files changed, 100 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27af8936..bd915fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM Evo beta ================================================= +14.11.2023 + +- trying to solve an idiosyncrasy of MacOS which do not allow modifying the main menu in a non-main thread which is done after editing an object + 29.10.2023 - when failing to save a project make sure that we can still close the app correctly @@ -3430,7 +3434,7 @@ RELEASE 8.993 - changes some icons - added a new GUI element which is a evaluated LineEdit that accepts only float numbers and /,*,+,-,% chars - finished the Etch Compensation Tool -- fixed unreliable work of Gerber Editor and optimized the App.editor2object() method +- fixed unreliable work of Gerber Editor and optimized the App.on_editing_finished() method - updated the Gerber parser such that it will parse correctly Gerber files that have only one solid polygon inside with multiple clear polygons (like those generated by the Invert Tool) - fixed a small bug in the Geometry UI that made updating the storage from GUI not to work - some small changes in Gerber Editor @@ -6153,7 +6157,7 @@ RELEASE 8.993 - fixed plotting in Gerber Editor - working on GUI in Gerber Editor - added a Gcode end_command: default is M02 -- modified the calling of the editor2object() slot function to fix an issue with updating geometry imported from SVG file, after edit +- modified the calling of the on_editing_finished() slot function to fix an issue with updating geometry imported from SVG file, after edit - working on Gerber Editor - added the key shortcuts: wip - made saving of the project file non-blocking and also while saving the project file, if the user tries again to close the app while project file is being saved, the app will close only after saving is complete (the project file size is non zero) - fixed the camlib.Geometry.import_svg() and camlib.Gerber.bounds() to work when importing SVG files as Gerber @@ -6847,7 +6851,7 @@ RELEASE 8.993 28.12.2018 - changed the workspace drawing from 'gl' to 'agg'. 'gl' has better performance but it messes with the overlapping graphics -- removed the initial obj.build_ui() in App.editor2object() +- removed the initial obj.build_ui() in App.on_editing_finished() 25.12.2018 diff --git a/appDatabase.py b/appDatabase.py index 7d5d47f1..03b1aacd 100644 --- a/appDatabase.py +++ b/appDatabase.py @@ -2010,7 +2010,7 @@ class ToolsDB2(QtWidgets.QWidget): new_name = "new_tool_1" dict_elem = {'name': new_name} - if type(self.app.options["tools_mill_tooldia"]) == float: + if isinstance(self.app.options["tools_mill_tooldia"], float): dict_elem['tooldia'] = self.app.options["tools_mill_tooldia"] else: try: diff --git a/appEditors/AppExcEditor.py b/appEditors/AppExcEditor.py index be532191..37a0f1ba 100644 --- a/appEditors/AppExcEditor.py +++ b/appEditors/AppExcEditor.py @@ -3140,7 +3140,7 @@ class AppExcEditor(QtCore.QObject): self.app.ui.exc_delete_drill_menuitem.triggered.connect(self.on_delete_btn) self.app.ui.exc_move_drill_menuitem.triggered.connect(self.exc_move_drills) - self.ui.exit_editor_button.clicked.connect(lambda: self.app.editor2object()) + self.ui.exit_editor_button.clicked.connect(lambda: self.app.on_editing_finished()) # ############################################################################################################# # ############################### TOOLS TABLE context menu #################################################### diff --git a/appEditors/AppGeoEditor.py b/appEditors/AppGeoEditor.py index 7dd0b4d1..29617c9e 100644 --- a/appEditors/AppGeoEditor.py +++ b/appEditors/AppGeoEditor.py @@ -5715,7 +5715,7 @@ class AppGeoEditorUI: # Signals self.level.toggled.connect(self.on_level_changed) - self.exit_editor_button.clicked.connect(lambda: self.app.editor2object()) + self.exit_editor_button.clicked.connect(lambda: self.app.on_editing_finished()) def on_param_click(self): if self.param_button.get_value(): diff --git a/appEditors/AppGerberEditor.py b/appEditors/AppGerberEditor.py index 651cea3d..c4b0dcfd 100644 --- a/appEditors/AppGerberEditor.py +++ b/appEditors/AppGerberEditor.py @@ -292,7 +292,7 @@ class PadEditorGrb(ShapeToolEditorGrb): self.draw_app.app.inform.emit('[success] %s' % _("Done.")) def draw_cursor_data(self, pos=None, delete=False): - if self.cursor_data_control is False: + if not self.cursor_data_control: self.draw_app.app.plotcanvas.text_cursor.text = "" return @@ -307,16 +307,12 @@ class PadEditorGrb(ShapeToolEditorGrb): # font size qsettings = QtCore.QSettings("Open Source", "FlatCAM_EVO") - if qsettings.contains("hud_font_size"): - fsize = qsettings.value('hud_font_size', type=int) - else: - fsize = 8 + fsize = qsettings.value('hud_font_size', type=int, defaultValue=8) old_x = self.ui.x_entry.get_value() old_y = self.ui.y_entry.get_value() - x = pos[0] - y = pos[1] + x, y = pos try: length = abs(np.sqrt((x - old_x) ** 2 + (y - old_y) ** 2)) except IndexError: @@ -347,15 +343,14 @@ class PadEditorGrb(ShapeToolEditorGrb): def on_key(self, key): # Jump to coords - if key == QtCore.Qt.Key.Key_J or key == 'J': + if key in [QtCore.Qt.Key.Key_J, 'J']: self.draw_app.app.on_jump_to() - if key in [str(i) for i in range(10)] + ['.', ',', '+', '-', '/', '*'] or \ - key in [QtCore.Qt.Key.Key_0, QtCore.Qt.Key.Key_0, QtCore.Qt.Key.Key_1, QtCore.Qt.Key.Key_2, - QtCore.Qt.Key.Key_3, QtCore.Qt.Key.Key_4, QtCore.Qt.Key.Key_5, QtCore.Qt.Key.Key_6, - QtCore.Qt.Key.Key_7, QtCore.Qt.Key.Key_8, QtCore.Qt.Key.Key_9, QtCore.Qt.Key.Key_Minus, - QtCore.Qt.Key.Key_Plus, QtCore.Qt.Key.Key_Comma, QtCore.Qt.Key.Key_Period, - QtCore.Qt.Key.Key_Slash, QtCore.Qt.Key.Key_Asterisk]: + valid_keys = [str(i) for i in range(10)] + ['.', ',', '+', '-', '/', '*'] + valid_keys += [getattr(QtCore.Qt.Key, "Key_%d" % i) for i in range(10)] + valid_keys += [QtCore.Qt.Key.Key_Minus, QtCore.Qt.Key.Key_Plus, QtCore.Qt.Key.Key_Comma, + QtCore.Qt.Key.Key_Period, QtCore.Qt.Key.Key_Slash, QtCore.Qt.Key.Key_Asterisk] + if key in valid_keys: try: # VisPy keys if self.pad_tool.length == self.draw_app.last_length: @@ -369,7 +364,7 @@ class PadEditorGrb(ShapeToolEditorGrb): else: self.pad_tool.length = str(self.pad_tool.length) + chr(key) - if key == 'Enter' or key == QtCore.Qt.Key.Key_Return or key == QtCore.Qt.Key.Key_Enter: + if key in ['Enter', QtCore.Qt.Key.Key_Return, QtCore.Qt.Key.Key_Enter]: if self.pad_tool.length != 0: target_length = self.pad_tool.length if target_length is None: @@ -399,7 +394,7 @@ class PadEditorGrb(ShapeToolEditorGrb): self.draw_app.app.inform.emit(msg) # self.interpolate_length = '' # return "Click on next point or hit ENTER to complete ..." - if key == 'C' or key == QtCore.Qt.Key.Key_C: + if key in ['C', QtCore.Qt.Key.Key_C]: self.cursor_data_control = not self.cursor_data_control def clean_up(self): @@ -2085,7 +2080,7 @@ class DiscEditorGrb(ShapeToolEditorGrb): except KeyError: size_ap = 0.0 # self.draw_app.app.inform.emit( - # '[ERROR_NOTCL] %s' % _("You need to preselect a aperture in the Aperture Table that has a size.")) + # '[ERROR_NOTCL] %s' % _("You need to preselect an aperture in the Aperture Table that has a size.")) # try: # QtGui.QGuiApplication.restoreOverrideCursor() # except Exception: @@ -2360,7 +2355,7 @@ class DiscSemiEditorGrb(ShapeToolEditorGrb): t = distance(data, a) # Which side? Cross product with c. - # cross(M-A, B-A), where line is AB and M is test point. + # cross(M-A, B-A), where line is AB and M is a test point. side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0] t *= np.sign(side) @@ -2433,7 +2428,7 @@ class DiscSemiEditorGrb(ShapeToolEditorGrb): t = distance(pc, a) # Which side? Cross product with c. - # cross(M-A, B-A), where line is AB and M is test point. + # cross(M-A, B-A), where line is AB and M is a test point. side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0] t *= np.sign(side) @@ -3083,7 +3078,7 @@ class EraserEditorGrb(ShapeToolEditorGrb): # all shapes that are `cut` will be stored in the 0 aperture intersection_geo_list = [] - # if at least one of the apertures have zero geometry left then we delete it so we need to rebuild UI + # if at least one of the apertures have zero geometry left then we delete it, so we need to rebuild UI should_build = False # populate intersection list for storage in list(self.draw_app.storage_dict.keys()): @@ -3706,7 +3701,6 @@ class ImportEditorGrb(QtCore.QObject, DrawTool): :param selection_type: True if selection is left-to-tight mouse drag, False if right-to-left mouse drag :type selection_type: :return: None - :rtype: None """ poly_selection = Polygon([start_pos, (end_pos[0], start_pos[1]), end_pos, (start_pos[0], end_pos[1])]) @@ -4095,7 +4089,7 @@ class AppGerberEditor(QtCore.QObject): self.ui.apertures_table.cellPressed.connect(self.on_row_selected) self.ui.apertures_table.selectionModel().selectionChanged.connect(self.on_table_selection) # noqa - self.ui.exit_editor_button.clicked.connect(lambda: self.app.editor2object()) + self.ui.exit_editor_button.clicked.connect(lambda: self.app.on_editing_finished()) self.conversion_factor = 1 @@ -4349,7 +4343,7 @@ class AppGerberEditor(QtCore.QObject): # Switch notebook to Properties page self.app.ui.notebook.setCurrentWidget(self.app.ui.properties_tab) - # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated + # we reactivate the signals after the tool adding as we don't need to see the tool been populated self.ui.apertures_table.itemChanged.connect(self.on_tool_edit) self.ui.apertures_table.cellPressed.connect(self.on_row_selected) @@ -4357,7 +4351,7 @@ class AppGerberEditor(QtCore.QObject): try: self.ui.apcode_entry.set_value(max(self.tid2apcode.values()) + 1) except ValueError: - # this means that the edited object has no apertures so we start with 10 (Gerber specifications) + # this means that the edited object has no apertures, so we start with 10 (Gerber specifications) self.ui.apcode_entry.set_value(self.app.options["gerber_editor_newcode"]) def on_aperture_add(self, apcode=None): @@ -4408,8 +4402,8 @@ class AppGerberEditor(QtCore.QObject): } self.ui.apsize_entry.set_value(size_val) - # self.oldapcode_newapcode dict keeps the evidence on current aperture codes as keys and gets - # updated on values each time a aperture code is edited or added + # 'self.oldapcode_newapcode' dict keeps the evidence on current aperture codes as keys and gets + # updated on values each time an aperture code is edited or added self.oldapcode_newapcode[ap_code] = ap_code except Exception as e: self.app.log.error("AppGerberEditor.on_aperture_add() --> " @@ -4427,13 +4421,13 @@ class AppGerberEditor(QtCore.QObject): } # self.oldapcode_newapcode dict keeps the evidence on current aperture codes as keys and gets - # updated on values each time a aperture code is edited or added + # updated on values each time an aperture code is edited or added self.oldapcode_newapcode[ap_code] = ap_code else: self.app.inform.emit('[WARNING_NOTCL] %s' % _("Aperture already in the aperture table.")) return - # since we add a new tool, we update also the initial state of the plugin_table through it's dictionary + # since we add a new tool, we update also the initial state of the plugin_table through its dictionary # we add a new entry in the tid2apcode dict self.tid2apcode[len(self.oldapcode_newapcode)] = int(ap_code) @@ -4444,7 +4438,7 @@ class AppGerberEditor(QtCore.QObject): self.last_aperture_selected = ap_code if ap_code != 0: - # make a quick sort through the tid2apcode dict so we find which row to select + # make a quick sort through the tid2apcode dict, so we find which row to select row_to_be_selected = None for key in sorted(self.tid2apcode): if self.tid2apcode[key] == int(ap_code): @@ -4529,7 +4523,7 @@ class AppGerberEditor(QtCore.QObject): row_of_item_changed = self.ui.apertures_table.currentRow() col_of_item_changed = self.ui.apertures_table.currentColumn() - # rows start with 0, tools start with 1 so we adjust the value by 1 + # rows start with 0, tools start with 1, so we adjust the value by 1 key_in_tid2apcode = row_of_item_changed + 1 ap_code_old = self.tid2apcode[key_in_tid2apcode] @@ -4582,7 +4576,7 @@ class AppGerberEditor(QtCore.QObject): # In case we edited the Aperture Code therefore the val_edited holds a new Aperture Code # TODO Edit of the Aperture Code is not active yet if col_of_item_changed == 1: - # aperture code is not used so we create a new Aperture with the desired Aperture Code + # aperture code is not used, so we create a new Aperture with the desired Aperture Code if val_edited not in self.oldapcode_newapcode.values(): # update the dict that holds as keys old Aperture Codes and as values the new Aperture Codes self.oldapcode_newapcode[ap_code_old] = val_edited @@ -4593,7 +4587,7 @@ class AppGerberEditor(QtCore.QObject): self.storage_dict[val_edited] = old_aperture_val else: - # aperture code is already in use so we move the pads from the prior tool to the new tool + # aperture code is already in use so, we move the pads from the prior tool to the new tool # but only if they are of the same type if self.storage_dict[ap_code_old]['type'] == self.storage_dict[ap_code_new]['type']: @@ -4692,7 +4686,7 @@ class AppGerberEditor(QtCore.QObject): self.plot_all() - # we reactivate the signals after the after the tool editing + # we reactivate the signals after the tool editing self.ui.apertures_table.itemChanged.connect(self.on_tool_edit) # self.ui.apertures_table.cellPressed.connect(self.on_row_selected) @@ -4903,7 +4897,7 @@ class AppGerberEditor(QtCore.QObject): self.app.ui.corner_snap_btn.setVisible(False) self.app.ui.snap_magnet.setVisible(False) - # set the Editor Toolbar visibility to what was before entering in the Editor + # set the Editor Toolbar visibility to what it was before entering the Editor self.app.ui.grb_edit_toolbar.setVisible(False) if self.toolbar_old_state is False \ else self.app.ui.grb_edit_toolbar.setVisible(True) @@ -5104,7 +5098,7 @@ class AppGerberEditor(QtCore.QObject): def edit_fcgerber(self, orig_grb_obj): """ - Imports the geometry found in self.tools from the given FlatCAM Gerber object + Imports the geometry found in "self.tools" from the given FlatCAM Gerber object into the editor. :param orig_grb_obj: ExcellonObject @@ -5259,7 +5253,7 @@ class AppGerberEditor(QtCore.QObject): global_clear_geo = [global_clear_geo] # we subtract the big "negative" (clear) geometry from each solid polygon but only the part of - # clear geometry that fits inside the solid. otherwise we may loose the solid + # clear geometry that fits inside the solid. otherwise we may lose the solid for ap_code in app_obj.gerber_obj.tools: temp_solid_geometry = [] if 'geometry' in app_obj.gerber_obj.tools[ap_code]: @@ -6152,7 +6146,6 @@ class AppGerberEditor(QtCore.QObject): Plots all shapes in the editor. :return: None - :rtype: None """ with self.app.proc_container.new('%s ...' % _("Plotting")): self.shapes.clear(update=True) @@ -6194,7 +6187,7 @@ class AppGerberEditor(QtCore.QObject): Plots a geometric object or list of objects without rendering. Plotted objects are returned as a list. This allows for efficient/animated rendering. - :param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such) + :param geometry: Geometry to be plotted (Any "Shapely.geom" kind or list of such) :param color: Shape color :param linewidth: Width of lines in # of pixels. :return: List of plotted elements. @@ -6206,7 +6199,7 @@ class AppGerberEditor(QtCore.QObject): try: self.shapes.add(shape=geometry.geo, color=color, face_color=color, layer=0, tolerance=self.tolerance) except AttributeError: - if type(geometry) == Point: + if isinstance(geometry, Point): return if len(color) == 9: color = color[:7] + 'AF' @@ -6249,7 +6242,7 @@ class AppGerberEditor(QtCore.QObject): # def start_delayed_plot(self, check_period): # """ - # This function starts an QTImer and it will periodically check if all the workers finish the plotting functions + # This function starts an QTImer, and it will periodically check if all the workers finish the plotting functions # # :param check_period: time at which to check periodically if all plots finished to be plotted # :return: @@ -6449,7 +6442,7 @@ class AppGerberEditor(QtCore.QObject): return def scale_recursion(geom_el, selection): - if type(geom_el) == list: + if isinstance(geom_el, list): geoms = [] for local_geom in geom_el: geoms.append(scale_recursion(local_geom, selection=selection)) @@ -6545,7 +6538,7 @@ class AppGerberEditor(QtCore.QObject): self.select_tool('eraser') def on_transform(self): - if type(self.active_tool) == TransformEditorGrb: + if isinstance(self.active_tool, TransformEditorGrb): self.select_tool('select') else: self.select_tool('transform') @@ -7726,7 +7719,7 @@ class TransformEditorTool(AppTool): """ Skew geometry - :param axis: Axis on which to deform, skew + :param axis: Axis on which to deform (or skew) :param xval: Skew value on X axis :param yval: Skew value on Y axis :param point: Point of reference for deformation: tuple @@ -7988,7 +7981,7 @@ class TransformEditorTool(AppTool): maxy = max(maxy, maxy_) return minx, miny, maxx, maxy except TypeError: - # it's an object, return it's bounds + # it's an object, return its bounds return lst.bounds return bounds_rec(shapelist) diff --git a/appEditors/appGCodeEditor.py b/appEditors/appGCodeEditor.py index 2923d298..02288524 100644 --- a/appEditors/appGCodeEditor.py +++ b/appEditors/appGCodeEditor.py @@ -53,7 +53,7 @@ class AppGCodeEditor(QtCore.QObject): self.ui.name_entry.returnPressed.connect(self.on_name_activate) self.ui.update_gcode_button.clicked.connect(self.insert_code_snippet_1) self.ui.update_gcode_sec_button.clicked.connect(self.insert_code_snippet_2) - self.ui.exit_editor_button.clicked.connect(lambda: self.app.editor2object(force_cancel=True)) + self.ui.exit_editor_button.clicked.connect(lambda: self.app.on_editing_finished(force_cancel=True)) self.app.log.debug("Initialization of the GCode Editor is finished ...") @@ -77,7 +77,7 @@ class AppGCodeEditor(QtCore.QObject): self.edit_area.add_action_to_context_menu(text=_("Exit Editor"), shortcut=_("Ctrl+S"), icon=QtGui.QIcon(self.app.resource_location + '/power16.png'), - callback=self.app.editor2object, + callback=self.app.on_editing_finished, separator='before') # add the tab if it was closed diff --git a/appGUI/MainGUI.py b/appGUI/MainGUI.py index 9928ff0a..fd1a4e33 100644 --- a/appGUI/MainGUI.py +++ b/appGUI/MainGUI.py @@ -3336,7 +3336,7 @@ class MainGUI(QtWidgets.QMainWindow): # Copy Object Name if key == QtCore.Qt.Key.Key_E: - self.app.object2editor() + self.app.on_editing_start() # Grid toggle if key == QtCore.Qt.Key.Key_G: @@ -3421,7 +3421,7 @@ class MainGUI(QtWidgets.QMainWindow): if modifiers == QtCore.Qt.KeyboardModifier.ControlModifier: # save (update) the current geometry and return to the App if key == QtCore.Qt.Key.Key_S or key == 'S': - self.app.editor2object() + self.app.on_editing_finished() return # toggle the measurement tool @@ -3740,7 +3740,7 @@ class MainGUI(QtWidgets.QMainWindow): # save (update) the current geometry and return to the App if key == QtCore.Qt.Key.Key_S or key == 'S': - self.app.editor2object() + self.app.on_editing_finished() return # toggle the measurement tool @@ -3976,7 +3976,7 @@ class MainGUI(QtWidgets.QMainWindow): # save (update) the current geometry and return to the App if key == QtCore.Qt.Key.Key_S or key == 'S': - self.app.editor2object() + self.app.on_editing_finished() return # toggle the measurement tool @@ -4243,7 +4243,7 @@ class MainGUI(QtWidgets.QMainWindow): if modifiers == QtCore.Qt.KeyboardModifier.ControlModifier: # save (update) the current geometry and return to the App if key == QtCore.Qt.Key.Key_S or key == 'S': - self.app.editor2object(force_cancel=True) + self.app.on_editing_finished(force_cancel=True) return # SHIFT elif modifiers == QtCore.Qt.KeyboardModifier.ShiftModifier: diff --git a/appHandlers/AppIO.py b/appHandlers/AppIO.py index 1b966b1e..29ad05bb 100644 --- a/appHandlers/AppIO.py +++ b/appHandlers/AppIO.py @@ -815,7 +815,7 @@ class AppIO(QtCore.QObject): # close any editor that might be open if self.app.call_source != 'app': - self.app.editor2object(cleanup=True) + self.app.on_editing_finished(cleanup=True) # ## EDITOR section self.app.geo_editor = AppGeoEditor(self.app) self.app.exc_editor = AppExcEditor(self.app) diff --git a/appMain.py b/appMain.py index 86a742ce..119ebe83 100644 --- a/appMain.py +++ b/appMain.py @@ -9,7 +9,7 @@ from PyQt6 import QtGui, QtWidgets from PyQt6.QtCore import QSettings, pyqtSlot -from PyQt6.QtCore import Qt, pyqtSignal +from PyQt6.QtCore import Qt, pyqtSignal, QMetaObject from PyQt6.QtGui import QAction, QTextCursor import os.path @@ -276,6 +276,8 @@ class App(QtCore.QObject): restore_project = pyqtSignal(object, str, bool, bool, bool, bool) # used when loading a project and restoring objects restore_project_objects_sig = pyqtSignal(object, str, bool, bool) + # post-Edit actions + post_edit_sig = pyqtSignal() def __init__(self, qapp, user_defaults=True): """ @@ -1199,6 +1201,9 @@ class App(QtCore.QObject): # when the options dictionary values change self.options.set_change_callback(callback=self.on_options_value_changed) + # post_edit signal + self.post_edit_sig.connect(self.on_editing_final_action, type=Qt.ConnectionType.QueuedConnection) + # ########################################################################################################### # ########################################## Standard signals ############################################### # ########################################################################################################### @@ -1892,8 +1897,8 @@ class App(QtCore.QObject): def connect_editmenu_signals(self): self.ui.menufile_exit.triggered.connect(self.final_save) - self.ui.menueditedit.triggered.connect(lambda: self.object2editor()) - self.ui.menueditok.triggered.connect(lambda: self.editor2object()) + self.ui.menueditedit.triggered.connect(lambda: self.on_editing_start()) + self.ui.menueditok.triggered.connect(lambda: self.on_editing_finished()) self.ui.menuedit_join2geo.triggered.connect(self.on_edit_join) self.ui.menuedit_join_exc2exc.triggered.connect(self.on_edit_join_exc) @@ -1981,7 +1986,7 @@ class App(QtCore.QObject): self.ui.menuprojectviewsource.triggered.connect(self.on_view_source) self.ui.menuprojectcopy.triggered.connect(self.on_copy_command) - self.ui.menuprojectedit.triggered.connect(self.object2editor) + self.ui.menuprojectedit.triggered.connect(self.on_editing_start) self.ui.menuprojectdelete.triggered.connect(self.on_delete) self.ui.menuprojectsave.triggered.connect(self.on_project_context_save) @@ -2012,8 +2017,8 @@ class App(QtCore.QObject): self.ui.popmenu_copy.triggered.connect(self.on_copy_command) self.ui.popmenu_delete.triggered.connect(self.on_delete) - self.ui.popmenu_edit.triggered.connect(self.object2editor) - self.ui.popmenu_save.triggered.connect(lambda: self.editor2object()) + self.ui.popmenu_edit.triggered.connect(self.on_editing_start) + self.ui.popmenu_save.triggered.connect(lambda: self.on_editing_finished()) self.ui.popmenu_numeric_move.triggered.connect(lambda: self.on_numeric_move()) self.ui.popmenu_move.triggered.connect(self.obj_move) self.ui.popmenu_move2origin.triggered.connect(self.on_move2origin) @@ -2094,8 +2099,8 @@ class App(QtCore.QObject): self.ui.zoom_out_btn.triggered.connect(lambda: self.plotcanvas.zoom(1.5)) # Edit Toolbar Signals - self.ui.editor_start_btn.triggered.connect(self.object2editor) - self.ui.editor_exit_btn.clicked.connect(lambda: self.editor2object(force_cancel=True)) + self.ui.editor_start_btn.triggered.connect(self.on_editing_start) + self.ui.editor_exit_btn.clicked.connect(lambda: self.on_editing_finished(force_cancel=True)) self.ui.copy_btn.triggered.connect(self.on_copy_command) self.ui.delete_btn.triggered.connect(self.on_delete) @@ -2284,13 +2289,13 @@ class App(QtCore.QObject): self.ui.snap_max_dist_entry.setText(str(self.options["global_snap_max"])) self.ui.grid_gap_link_cb.setChecked(True) - def object2editor(self): + def on_editing_start(self): """ - Send the current Geometry, Gerber, Excellon object or CNCJob (if any) its editor. + Send the current Geometry, Gerber, "Excellon" object or CNCJob (if any) its editor. :return: None """ - self.defaults.report_usage("object2editor()") + self.defaults.report_usage("on_editing_start()") edited_object = self.collection.get_active() if edited_object is None: @@ -2435,17 +2440,17 @@ class App(QtCore.QObject): self.should_we_save = True - def editor2object(self, cleanup=None, force_cancel=None): + def on_editing_finished(self, cleanup=None, force_cancel=None): """ - Transfers the Geometry or Excellon from its editor to the current object. + Transfers the Geometry or an "Excellon", from its editor to the current object. :param cleanup: if True then we closed the app when the editor was open, so we close first the editor :param force_cancel: if True always add Cancel button :return: None """ - self.defaults.report_usage("editor2object()") + self.defaults.report_usage("on_editing_finished()") - # do not update a Geometry/Excellon/Gerber/GCode object unless it comes out of an editor + # do not update a Geometry/"Excellon"/Gerber/GCode object unless it comes out of an editor if self.call_source == 'app': return @@ -2516,7 +2521,7 @@ class App(QtCore.QObject): edited_obj.obj_options['ymax'] = ymax except (AttributeError, ValueError) as e: self.inform.emit('[WARNING] %s' % _("Object empty after edit.")) - self.log.debug("App.editor2object() --> Geometry --> %s" % str(e)) + self.log.debug("App.on_editing_finished() --> Geometry --> %s" % str(e)) edited_obj.build_ui() edited_obj.plot() @@ -2669,10 +2674,17 @@ class App(QtCore.QObject): _("Select a Gerber, Geometry, Excellon or CNCJob object to update.")) return + self.post_edit_sig.emit() + + def on_editing_final_action(self): + self.log.debug("######################### Closing the EDITOR ################################") + self.call_source = 'app' + # if notebook is hidden we show it if self.ui.splitter.sizes()[0] == 0: self.ui.splitter.setSizes([1, 1]) + # change back the tab name for idx in range(self.ui.notebook.count()): # restore the Properties Tab text and color if self.ui.notebook.tabText(idx) == _("Editor"): @@ -2683,25 +2695,21 @@ class App(QtCore.QObject): if self.ui.notebook.tabText(idx) == _("Project"): self.ui.notebook.tabBar.setTabEnabled(idx, True) + self.ui.plot_tab_area.setTabText(0, _("Plot Area")) + self.ui.plot_tab_area.protectTab(0) + + # make sure that we re-enable the selection on Project Tab after returning from Editor Mode: + self.ui.project_frame.setDisabled(False) + + QMetaObject.invokeMethod(self, "modify_menu_items", Qt.ConnectionType.QueuedConnection) + + @QtCore.pyqtSlot() + def modify_menu_items(self): # re-enable the objects menu that was disabled on entry in Editor mode self.ui.menuobjects.setDisabled(False) # re-enable the tool menu that was disabled on entry in Editor mode self.ui.menu_plugins.setDisabled(False) - # restore the call_source to app - self.call_source = 'app' - self.log.debug("######################### Closing the EDITOR ################################") - - # edited_obj.plot() - self.ui.plot_tab_area.setTabText(0, _("Plot Area")) - self.ui.plot_tab_area.protectTab(0) - - # restore the notebook tab close method to the app - # self.ui.notebook.callback_on_close = self.on_close_notebook_tab - - # make sure that we reenable the selection on Project Tab after returning from Editor Mode: - self.ui.project_frame.setDisabled(False) - def get_last_folder(self): """ Get the folder path from where the last file was opened. @@ -6022,7 +6030,7 @@ class App(QtCore.QObject): self.area_3d_tab.deleteLater() self.area_3d_tab = QtWidgets.QWidget() elif tab_obj_name == "gcode_editor_tab": - self.editor2object() + self.on_editing_finished() else: pass diff --git a/appObjects/CNCJobObject.py b/appObjects/CNCJobObject.py index 83250a15..df410c17 100644 --- a/appObjects/CNCJobObject.py +++ b/appObjects/CNCJobObject.py @@ -545,7 +545,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.ui.review_gcode_button.clicked.connect(self.on_review_code_click) # Editor Signal - self.ui.editor_button.clicked.connect(lambda: self.app.object2editor()) + self.ui.editor_button.clicked.connect(lambda: self.app.on_editing_start()) # Properties self.ui.info_button.toggled.connect(self.on_properties) diff --git a/appObjects/ExcellonObject.py b/appObjects/ExcellonObject.py index 9168ce84..2577c348 100644 --- a/appObjects/ExcellonObject.py +++ b/appObjects/ExcellonObject.py @@ -164,7 +164,7 @@ class ExcellonObject(FlatCAMObj, Excellon): self.ui.autoload_db_cb.stateChanged.connect(self.on_autoload_db_toggled) # Editor - self.ui.editor_button.clicked.connect(lambda: self.app.object2editor()) + self.ui.editor_button.clicked.connect(lambda: self.app.on_editing_start()) # Properties self.ui.info_button.toggled.connect(self.on_properties) diff --git a/appObjects/GeometryObject.py b/appObjects/GeometryObject.py index 084fe9d0..2f44577f 100644 --- a/appObjects/GeometryObject.py +++ b/appObjects/GeometryObject.py @@ -389,7 +389,7 @@ class GeometryObject(FlatCAMObj, Geometry): self.ui.multicolored_cb.stateChanged.connect(self.on_multicolored_cb_click) # Editor Signal - self.ui.editor_button.clicked.connect(self.app.object2editor) + self.ui.editor_button.clicked.connect(self.app.on_editing_start) # Properties self.ui.info_button.toggled.connect(self.on_properties) @@ -1060,7 +1060,7 @@ class GeometryObject(FlatCAMObj, Geometry): endxy = endxy if endxy else self.obj_options["tools_mill_endxy"] if isinstance(endxy, str): - endxy = re.sub('[()\[\]]', '', endxy) + endxy = re.sub(r'[()\[\]]', '', endxy) if endxy and endxy != '': endxy = [float(eval(a)) for a in endxy.split(",")] @@ -1068,7 +1068,7 @@ class GeometryObject(FlatCAMObj, Geometry): toolchangexy = toolchangexy if toolchangexy else self.obj_options["tools_mill_toolchangexy"] if isinstance(toolchangexy, str): - toolchangexy = re.sub('[()\[\]]', '', toolchangexy) + toolchangexy = re.sub(r'[()\[\]]', '', toolchangexy) if toolchangexy and toolchangexy != '': toolchangexy = [float(eval(a)) for a in toolchangexy.split(",")] diff --git a/appObjects/GerberObject.py b/appObjects/GerberObject.py index 200e466e..85f68061 100644 --- a/appObjects/GerberObject.py +++ b/appObjects/GerberObject.py @@ -156,7 +156,7 @@ class GerberObject(FlatCAMObj, Gerber): self.ui.multicolored_cb.stateChanged.connect(self.on_multicolored_cb_click) # Editor - self.ui.editor_button.clicked.connect(lambda: self.app.object2editor()) + self.ui.editor_button.clicked.connect(lambda: self.app.on_editing_start()) # Properties self.ui.info_button.toggled.connect(self.on_properties)