diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 8c5e2780..44572693 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -629,7 +629,7 @@ class App(QtCore.QObject): "global_def_win_y": 100, "global_def_win_w": 1024, "global_def_win_h": 650, - + "global_def_notebook_width": 1, # Constants... "global_defaults_save_period_ms": 20000, # Time between default saves. "global_shell_shape": [500, 300], # Shape of the shell in pixels. @@ -1847,7 +1847,7 @@ class App(QtCore.QObject): if not factory_defaults: self.save_factory_defaults(silent=False) # ONLY AT FIRST STARTUP INIT THE GUI LAYOUT TO 'COMPACT' - initial_lay = 'Compact' + initial_lay = 'compact' self.on_layout(index=None, lay=initial_lay) # Set the combobox in Preferences to the current layout idx = self.ui.general_defaults_form.general_gui_set_group.layout_combo.findText(initial_lay) @@ -2675,7 +2675,7 @@ class App(QtCore.QObject): self.defaults["global_def_win_y"] = y self.defaults["global_def_win_w"] = width self.defaults["global_def_win_h"] = height - self.defaults["def_notebook_width"] = notebook_width + self.defaults["global_def_notebook_width"] = notebook_width self.save_defaults() def message_dialog(self, title, message, kind="info"): @@ -3084,15 +3084,6 @@ class App(QtCore.QObject): defaults.update(self.defaults) self.propagate_defaults(silent=True) - # Save update options - try: - f = open(self.data_path + "/current_defaults.FlatConfig", "w") - json.dump(defaults, f, default=to_dict, indent=2, sort_keys=True) - f.close() - except: - self.inform.emit(_("[ERROR_NOTCL] Failed to write defaults to file.")) - return - # Save the toolbar view tb_status = 0 if self.ui.toolbarfile.isVisible(): @@ -3124,6 +3115,15 @@ class App(QtCore.QObject): self.defaults["global_toolbar_view"] = tb_status + # Save update options + try: + f = open(self.data_path + "/current_defaults.FlatConfig", "w") + json.dump(defaults, f, default=to_dict, indent=2, sort_keys=True) + f.close() + except: + self.inform.emit(_("[ERROR_NOTCL] Failed to write defaults to file.")) + return + if not silent: self.inform.emit(_("[success] Defaults saved.")) @@ -3201,7 +3201,7 @@ class App(QtCore.QObject): elif response == QtWidgets.QMessageBox.Cancel: return else: - QtWidgets.qApp.quit() + self.quit_application() def quit_application(self): self.save_defaults() @@ -4009,7 +4009,7 @@ class App(QtCore.QObject): except: pass - if current_layout == 'Standard': + if current_layout == 'standard': ### TOOLBAR INSTALLATION ### self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') self.ui.toolbarfile.setObjectName('File_TB') @@ -4053,7 +4053,7 @@ class App(QtCore.QObject): self.ui.corner_snap_btn.setVisible(False) self.ui.snap_magnet.setVisible(False) - elif current_layout == 'Compact': + elif current_layout == 'compact': ### TOOLBAR INSTALLATION ### self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') self.ui.toolbarfile.setObjectName('File_TB') @@ -4405,7 +4405,7 @@ class App(QtCore.QObject): self.plotcanvas.vis_connect('mouse_press', self.on_set_zero_click) - def on_jump_to(self): + def on_jump_to(self, custom_location=None): """ Jump to a location by setting the mouse cursor location :return: @@ -4413,20 +4413,23 @@ class App(QtCore.QObject): """ self.report_usage("on_jump_to()") - dia_box = Dialog_box(title=_("Jump to ..."), - label=_("Enter the coordinates in format X,Y:"), - icon=QtGui.QIcon('share/jump_to16.png')) + if custom_location is None: + dia_box = Dialog_box(title=_("Jump to ..."), + label=_("Enter the coordinates in format X,Y:"), + icon=QtGui.QIcon('share/jump_to16.png')) - if dia_box.ok is True: - try: - location = eval(dia_box.location) - if not isinstance(location, tuple): - self.inform.emit(_("Wrong coordinates. Enter coordinates in format: X,Y")) + if dia_box.ok is True: + try: + location = eval(dia_box.location) + if not isinstance(location, tuple): + self.inform.emit(_("Wrong coordinates. Enter coordinates in format: X,Y")) + return + except: return - except: + else: return else: - return + location = custom_location self.plotcanvas.fit_center(loc=location) @@ -7270,15 +7273,15 @@ class App(QtCore.QObject): self.defaults["global_def_win_y"], self.defaults["global_def_win_w"], self.defaults["global_def_win_h"]) - self.ui.splitter.setSizes([self.defaults["def_notebook_width"], 0]) + self.ui.splitter.setSizes([self.defaults["global_def_notebook_width"], 0]) settings = QSettings("Open Source", "FlatCAM") if settings.contains("maximized_gui"): maximized_ui = settings.value('maximized_gui', type=bool) if maximized_ui is True: self.ui.showMaximized() - except KeyError: - pass + except KeyError as e: + log.debug("App.restore_main_win_geom() --> %s" % str(e)) def plot_all(self, zoom=True): """ @@ -7951,31 +7954,36 @@ The normal flow when working in FlatCAM is the following:

self.inform.emit(_("[ERROR_NOTCL] Failed to save project file: %s. Retry to save it.") % filename) if quit: - t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename)) - t.start() + # t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename)) + # t.start() + self.start_delayed_quit(delay=500, filename=filename) - def check_project_file_size(self, delay, filename): + def start_delayed_quit(self, delay, filename): """ - Using Alfe's answer from here: - https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds-in-python - :param delay: period of checking if project file size is more than zero; in seconds - :param filename: the name of the project file to be checked for size more than zero + :param delay: period of checking if project file size is more than zero; in seconds + :param filename: the name of the project file to be checked periodically for size more than zero :return: """ - next_time = time.time() + delay - while True: - time.sleep(max(0, next_time - time.time())) - try: - statinfo = os.stat(filename) - if statinfo: - self.app_quit.emit() - except Exception: - traceback.print_exc() - # in production code you might want to have this instead of course: - # logger.exception("Problem while executing repetitive task.") - # skip tasks if we are behind schedule: - next_time += (time.time() - next_time) // delay * delay + delay + + self.quit_timer = QtCore.QTimer() + self.quit_timer.setInterval(delay) + self.quit_timer.timeout.connect(lambda : self.check_project_file_size(filename=filename)) + self.quit_timer.start() + + def check_project_file_size(self, filename): + """ + + :param filename: the name of the project file to be checked periodically for size more than zero + :return: + """ + + try: + if os.stat(filename).st_size > 0: + self.quit_timer.stop() + self.app_quit.emit() + except Exception: + traceback.print_exc() def on_options_app2project(self): """ diff --git a/FlatCAMTranslation.py b/FlatCAMTranslation.py index 931a0616..ec86e44d 100644 --- a/FlatCAMTranslation.py +++ b/FlatCAMTranslation.py @@ -112,6 +112,12 @@ def apply_language(domain, lang=None): name = settings.value('language') else: name = settings.value('English') + # in case the 'language' parameter is not in QSettings add it to QSettings and it's value is + # the default language, English + settings.setValue('language', 'English') + + # This will write the setting to the platform specific storage. + del settings else: name = str(lang) diff --git a/README.md b/README.md index 79d4791a..47180e61 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ CAD program, and create G-Code for Isolation routing. - WIP in Gerber Editor: geometry is no longer stored in a Rtree storage as it is not needed - changed the way delayed plot is working in Gerber Editor to use a Qtimer instead of python threading module - WIP in Gerber Editor +- fixed bug in saving the maximized state +- fixed bug in applying default language on first start +- on activating 'V' key shortcut (zoom fit) the mouse cursor is now jumping to origin (0, 0) +- fixed bug in saving toolbars state; the file was saved before setting the self.defaults['global_toolbar_view] 4.04.2019 diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py index 3c206ae4..0036fd1c 100644 --- a/flatcamEditors/FlatCAMGeoEditor.py +++ b/flatcamEditors/FlatCAMGeoEditor.py @@ -1882,6 +1882,33 @@ class DrawTool(object): def utility_geometry(self, data=None): return None + def bounds(self, obj): + def bounds_rec(o): + if type(o) is list: + minx = Inf + miny = Inf + maxx = -Inf + maxy = -Inf + + for k in o: + try: + minx_, miny_, maxx_, maxy_ = bounds_rec(k) + except Exception as e: + log.debug("camlib.Gerber.bounds() --> %s" % str(e)) + return + + minx = min(minx, minx_) + miny = min(miny, miny_) + maxx = max(maxx, maxx_) + maxy = max(maxy, maxy_) + return minx, miny, maxx, maxy + else: + # it's a Shapely object, return it's bounds + return o.geo.bounds + + bounds_coords = bounds_rec(obj) + return bounds_coords + class FCShapeTool(DrawTool): """ @@ -2843,14 +2870,14 @@ class FlatCAMGeoEditor(QtCore.QObject): settings = QSettings("Open Source", "FlatCAM") if settings.contains("layout"): layout = settings.value('layout', type=str) - if layout == 'Standard': + if layout == 'standard': # self.app.ui.geo_edit_toolbar.setVisible(False) self.app.ui.snap_max_dist_entry.setEnabled(False) self.app.ui.corner_snap_btn.setEnabled(False) self.app.ui.snap_magnet.setVisible(False) self.app.ui.corner_snap_btn.setVisible(False) - elif layout == 'Compact': + elif layout == 'compact': # self.app.ui.geo_edit_toolbar.setVisible(True) self.app.ui.snap_max_dist_entry.setEnabled(False) diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index a7846f38..343716fe 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -116,7 +116,7 @@ class FCApertureResize(FCShapeTool): sel_shapes_to_be_deleted = [] self.draw_app.build_ui() - self.draw_app.replot() + self.draw_app.plot_all() self.draw_app.resize_frame.hide() self.complete = True @@ -287,9 +287,10 @@ class FCApertureSelect(DrawTool): self.grb_editor_app.apertures_table.clearSelection() for storage in self.grb_editor_app.storage_dict: - for shape in self.grb_editor_app.storage_dict[storage]: + for shape in self.grb_editor_app.storage_dict[storage]['solid_geometry']: if Point(pos).within(shape.geo): - self.sel_storage.append(DrawToolShape(shape.geo)) + self.sel_storage.append(shape) + xmin, ymin, xmax, ymax = self.bounds(self.sel_storage) if pos[0] < xmin or pos[0] > xmax or pos[1] < ymin or pos[1] > ymax: self.grb_editor_app.selected = [] @@ -1028,7 +1029,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.app.inform.emit(_("[success] Deleted tool with dia: {del_dia} {units}").format(del_dia=str(deleted_tool_dia), units=str(self.units))) - self.replot() + self.plot_all() # self.app.inform.emit("Could not delete selected tool") self.build_ui() @@ -1069,7 +1070,7 @@ class FlatCAMGrbEditor(QtCore.QObject): modified_offset = self.gerber_obj.tool_offset.pop(dia_changed) self.gerber_obj.tool_offset[current_table_dia_edited] = modified_offset - self.replot() + self.plot_all() else: # tool diameter is already in use so we move the drills from the prior tool to the new tool factor = current_table_dia_edited / dia_changed @@ -1217,7 +1218,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.tool_shape.clear(update=True) # self.storage = FlatCAMExcEditor.make_storage() - self.replot() + self.plot_all() def edit_fcgerber(self, exc_obj): """ @@ -1274,8 +1275,12 @@ class FlatCAMGrbEditor(QtCore.QObject): else: self.storage_dict[apid][k] = v + apid_promise = apid + # Check promises and clear if exists - self.app.collection.plot_remove_promise(apid) + self.app.collection.plot_remove_promise(apid_promise) + # if apid_promise in self.app.collection.plot_promises: + # self.app.collection.plot_promises.remove(apid_promise) for apid in self.gerber_obj.apertures: self.app.worker_task.emit({'fcn': job_thread, 'params': [apid]}) @@ -1291,6 +1296,12 @@ class FlatCAMGrbEditor(QtCore.QObject): :return: None """ + # if the 'delayed plot' malfunctioned stop the QTimer + try: + self.plot_thread.stop() + except: + pass + if "_edit" in self.edited_obj_name: try: id = int(self.edited_obj_name[-1]) + 1 @@ -1310,7 +1321,7 @@ class FlatCAMGrbEditor(QtCore.QObject): # restore GUI to the Selected TAB # Remove anything else in the GUI - self.app.ui.tool_scroll_area.takeWidget() + self.app.ui.selected_scroll_area.takeWidget() # Switch notebook to Selected page self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab) @@ -1443,7 +1454,7 @@ class FlatCAMGrbEditor(QtCore.QObject): except Exception as e: self.app.log.debug(str(e)) - self.replot() + self.plot_all() def toolbar_tool_toggle(self, key): self.options[key] = self.sender().isChecked() @@ -1500,7 +1511,7 @@ class FlatCAMGrbEditor(QtCore.QObject): if isinstance(self.active_tool, FCApertureSelect): # self.app.log.debug("Replotting after click.") - self.replot() + self.plot_all() else: self.app.log.debug("No active tool to respond to click!") @@ -1519,7 +1530,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.tool_shape.clear(update=True) # Replot and reset tool. - self.replot() + self.plot_all() # self.active_tool = type(self.active_tool)(self) def add_gerber_shape(self, shape, storage): @@ -1617,7 +1628,7 @@ class FlatCAMGrbEditor(QtCore.QObject): # msg = self.active_tool.click_release((self.pos[0], self.pos[1])) # self.app.inform.emit(msg) self.active_tool.click_release((self.pos[0], self.pos[1])) - self.replot() + self.plot_all() except Exception as e: log.warning("Error: %s" % str(e)) raise @@ -1658,7 +1669,7 @@ class FlatCAMGrbEditor(QtCore.QObject): # item.setSelected(True) # self.grb_editor_app.apertures_table.selectItem(key - 1) - self.replot() + self.plot_all() def on_canvas_move(self, event): """ @@ -1783,9 +1794,6 @@ class FlatCAMGrbEditor(QtCore.QObject): self.tool_shape.redraw() - def replot(self): - self.plot_all() - def plot_all(self): """ Plots all shapes in the editor. @@ -1817,14 +1825,17 @@ class FlatCAMGrbEditor(QtCore.QObject): def start_delayed_plot(self, check_period): # self.plot_thread = threading.Thread(target=lambda: self.check_plot_finished(check_period)) # self.plot_thread.start() + log.debug("FlatCAMGrbEditor --> Delayed Plot started.") self.plot_thread = QtCore.QTimer() self.plot_thread.setInterval(check_period) self.plot_thread.timeout.connect(self.check_plot_finished) self.plot_thread.start() def check_plot_finished(self): + print(self.app.collection.plot_promises) try: - if self.app.collection.has_plot_promises() is False: + has_promise = self.app.collection.has_plot_promises() + if has_promise == False: self.plot_thread.stop() self.plot_all() log.debug("FlatCAMGrbEditor --> delayed_plot finished") @@ -1890,7 +1901,7 @@ class FlatCAMGrbEditor(QtCore.QObject): self.tool_shape.clear(update=True) # Replot and reset tool. - self.replot() + self.plot_all() # self.active_tool = type(self.active_tool)(self) def get_selected(self): @@ -1947,7 +1958,7 @@ class FlatCAMGrbEditor(QtCore.QObject): def on_delete_btn(self): self.delete_selected() - self.replot() + self.plot_all() def select_tool(self, toolname): """ diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index a43636d6..ca41f790 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -567,9 +567,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow): settings = QSettings("Open Source", "FlatCAM") if settings.contains("layout"): layout = settings.value('layout', type=str) - if layout == 'Standard': + if layout == 'standard': pass - elif layout == 'Compact': + elif layout == 'compact': self.removeToolBar(self.snap_toolbar) self.snap_toolbar.setMaximumHeight(30) self.splitter_left.addWidget(self.snap_toolbar) @@ -672,13 +672,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.grb_select_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), _("Select")) - - - - - - - ### Snap Toolbar ### # Snap GRID toolbar is always active to facilitate usage of measurements done on GRID # self.addToolBar(self.snap_toolbar) @@ -1616,7 +1609,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.corner_snap_btn.setVisible(False) self.snap_magnet.setVisible(False) - elif layout == 'Compact': + elif layout == 'compact': self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setDisabled(True) self.grb_edit_toolbar.setDisabled(True) @@ -1746,12 +1739,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.geo_edit_toolbar.addSeparator() self.geo_move_btn = self.geo_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), _("Move Objects")) - ### Geometry Editor Toolbar ### + ### Gerber Editor Toolbar ### self.grb_select_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), _("Select")) - - ### Snap Toolbar ### # Snap GRID toolbar is always active to facilitate usage of measurements done on GRID # self.addToolBar(self.snap_toolbar) @@ -1802,7 +1793,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.corner_snap_btn.setVisible(False) self.snap_magnet.setVisible(False) - elif layout == 'Compact': + elif layout == 'compact': self.exc_edit_toolbar.setVisible(True) self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setVisible(True) @@ -2097,6 +2088,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # Zoom Fit if key == QtCore.Qt.Key_V: self.app.on_zoom_fit(None) + # and move mouse cursor to origin + self.app.on_jump_to(custom_location=(0, 0)) # Mirror on X the selected object(s) if key == QtCore.Qt.Key_X: @@ -2362,6 +2355,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): if key == QtCore.Qt.Key_V or key == 'V': self.app.on_zoom_fit(None) + # and move mouse cursor to origin + self.app.on_jump_to(custom_location=(0, 0)) # Flip on X axis if key == QtCore.Qt.Key_X or key == 'X': @@ -2541,6 +2536,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): if key == QtCore.Qt.Key_V or key == 'V': self.app.grb_editor.launched_from_shortcuts = True self.app.on_zoom_fit(None) + # and move mouse cursor to origin + self.app.on_jump_to(custom_location=(0, 0)) return # Propagate to tool @@ -2738,6 +2735,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): if key == QtCore.Qt.Key_V or key == 'V': self.app.exc_editor.launched_from_shortcuts = True self.app.on_zoom_fit(None) + # and move mouse cursor to origin + self.app.on_jump_to(custom_location=(0, 0)) return # Propagate to tool @@ -3287,8 +3286,8 @@ class GeneralGUISetGroupUI(OptionsGroupUI): ) 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("standard") + self.layout_combo.addItem("compact") # Set the current index for layout_combo settings = QSettings("Open Source", "FlatCAM")