From 59e12cf295dd581477919df62771ddf701ba4846 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sat, 9 Feb 2019 16:00:47 +0200 Subject: [PATCH] - fixed an error in Excellon Editor -> add drill array that could appear by starting the function to add a drill array by shortcut before any mouse move is registered while in Editor - changed the messages from status bar on new object creation/selection - in Geometry Editor fixed the handler for the Rotate shortcut key ('R') --- FlatCAMApp.py | 55 ++++++++++++------- FlatCAMEditor.py | 97 +++++++++++++++++++++++++-------- FlatCAMGUI.py | 49 ++++++++++++----- README.md | 3 + flatcamTools/ToolCalculators.py | 66 +++++++++++----------- 5 files changed, 181 insertions(+), 89 deletions(-) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index deab459c..4f6ffe52 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -257,6 +257,8 @@ class App(QtCore.QObject): # Create multiprocessing pool self.pool = Pool() + # variable to store mouse coordinates + self.mouse = [0, 0] #################### ## Initialize GUI ## @@ -1059,7 +1061,7 @@ class App(QtCore.QObject): self.ui.menufilesavedefaults.triggered.connect(self.on_file_savedefaults) self.ui.menufile_exit.triggered.connect(self.on_app_exit) - self.ui.menueditnew.triggered.connect(lambda: self.new_object('geometry', 'new_g', lambda x, y: None)) + self.ui.menueditnew.triggered.connect(self.new_geometry_object) self.ui.menueditnewexc.triggered.connect(self.new_excellon_object) self.ui.menueditedit.triggered.connect(self.object2editor) self.ui.menueditok.triggered.connect(self.editor2object) @@ -1140,7 +1142,7 @@ class App(QtCore.QObject): self.ui.zoom_in_btn.triggered.connect(lambda: self.plotcanvas.zoom(1 / 1.5)) self.ui.zoom_out_btn.triggered.connect(lambda: self.plotcanvas.zoom(1.5)) - self.ui.newgeo_btn.triggered.connect(lambda: self.new_object('geometry', 'new_g', lambda x, y: None)) + self.ui.newgeo_btn.triggered.connect(self.new_geometry_object) self.ui.newexc_btn.triggered.connect(self.new_excellon_object) self.ui.editgeo_btn.triggered.connect(self.object2editor) self.ui.update_obj_btn.triggered.connect(self.editor2object) @@ -1150,7 +1152,7 @@ class App(QtCore.QObject): # Context Menu self.ui.popmenu_disable.triggered.connect(lambda: self.disable_plots(self.collection.get_selected())) - self.ui.popmenu_new_geo.triggered.connect(lambda: self.new_object('geometry', 'new_g', lambda x, y: None)) + self.ui.popmenu_new_geo.triggered.connect(self.new_geometry_object) self.ui.popmenu_new_exc.triggered.connect(self.new_excellon_object) self.ui.popmenu_new_prj.triggered.connect(self.on_file_new) @@ -1665,7 +1667,7 @@ class App(QtCore.QObject): edited_obj.plot() self.ui.plot_tab_area.setTabText(0, "Plot Area") self.ui.plot_tab_area.protectTab(0) - self.inform.emit("[success] %s is updated, returning to App..." % obj_type) + self.inform.emit("[selected] %s is updated, returning to App..." % obj_type) # reset the Object UI to original settings # edited_obj.set_ui(edited_obj.ui_type()) @@ -2271,6 +2273,8 @@ class App(QtCore.QObject): obj.options['ymax'] = ymax except: log.warning("The object has no bounds properties.") + # don't plot objects with no bounds, there is nothing to plot + self.plot = False pass FlatCAMApp.App.log.debug("Moving new object back to main thread.") @@ -2284,7 +2288,15 @@ class App(QtCore.QObject): def new_excellon_object(self): self.report_usage("new_excellon_object()") - self.new_object('excellon', 'new_e', lambda x, y: None) + self.new_object('excellon', 'new_e', lambda x, y: None, plot=False) + + def new_geometry_object(self): + self.report_usage("new_geometry_object()") + + def initialize(obj, self): + obj.multitool = False + + self.new_object('geometry', 'new_g', initialize, plot=False) def on_object_created(self, obj, plot, autoselect): """ @@ -2302,8 +2314,20 @@ class App(QtCore.QObject): # after adding the object to the collection always update the list of objects that are in the collection self.all_objects_list = self.collection.get_list() - self.inform.emit("[success]Object (%s) created: %s" % (obj.kind, obj.options['name'])) - self.new_object_available.emit(obj) + + if obj.kind == 'gerber': + self.inform.emit('[selected]%s created/selected: %s' % + (obj.kind.capitalize(), 'green', str(obj.options['name']))) + elif obj.kind == 'excellon': + self.inform.emit('[selected]%s created/selected: %s' % + (obj.kind.capitalize(), 'brown', str(obj.options['name']))) + elif obj.kind == 'cncjob': + self.inform.emit('[selected]%s created/selected: %s' % + (obj.kind.capitalize(), 'blue', str(obj.options['name']))) + elif obj.kind == 'geometry': + self.inform.emit('[selected]%s created/selected: %s' % + (obj.kind.capitalize(), 'red', str(obj.options['name']))) + # self.new_object_available.emit(obj) # update the SHELL auto-completer model with the name of the new object self.myKeywords.append(obj.options['name']) @@ -2327,7 +2351,7 @@ class App(QtCore.QObject): # Send to worker # self.worker.add_task(worker_task, [self]) - if plot: + if plot is True: self.worker_task.emit({'fcn': worker_task, 'params': [obj]}) def on_object_changed(self, obj): @@ -3560,15 +3584,6 @@ class App(QtCore.QObject): # Mark end of undo block cursor.endEditBlock() - def on_new_geometry(self): - self.report_usage("on_new_geometry()") - - def initialize(obj, self): - obj.multitool = False - - self.new_object('geometry', 'new_g', initialize) - self.plot_all() - def on_delete(self): """ Delete the currently selected FlatCAMObjs. @@ -4362,11 +4377,9 @@ class App(QtCore.QObject): def on_double_click_over_plot(self, event): # make double click work only for the LMB if event.button == 1: - if not self.collection.get_selected(): - pass - else: + if self.collection.get_selected(): self.ui.notebook.setCurrentWidget(self.ui.selected_tab) - #delete the selection shape(S) as it may be in the way + # delete the selection shape(S) as it may be in the way self.delete_selection_shape() def on_mouse_move_over_plot(self, event, origin_click=None): diff --git a/FlatCAMEditor.py b/FlatCAMEditor.py index 38c333b8..3b94c51c 100644 --- a/FlatCAMEditor.py +++ b/FlatCAMEditor.py @@ -583,6 +583,8 @@ class FCCircle(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_circle' + self.start_msg = "Click on CENTER ..." self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"] @@ -620,6 +622,8 @@ class FCCircle(FCShapeTool): class FCArc(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_arc' + self.start_msg = "Click on CENTER ..." # Direction of rotation between point 1 and 2. @@ -808,6 +812,8 @@ class FCRectangle(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_rectangle' + self.start_msg = "Click on 1st corner ..." def click(self, point): @@ -846,6 +852,8 @@ class FCPolygon(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_polygon' + self.start_msg = "Click on 1st point ..." def click(self, point): @@ -891,6 +899,8 @@ class FCPath(FCPolygon): def make(self): self.geometry = DrawToolShape(LineString(self.points)) + self.name = 'fc_path' + self.draw_app.in_action = False self.complete = True self.draw_app.app.inform.emit("[success]Done. Path completed.") @@ -912,6 +922,8 @@ class FCPath(FCPolygon): class FCSelect(DrawTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_select' + self.storage = self.draw_app.storage # self.shape_buffer = self.draw_app.shape_buffer # self.selected = self.draw_app.selected @@ -989,6 +1001,7 @@ class FCSelect(DrawTool): class FCDrillSelect(DrawTool): def __init__(self, exc_editor_app): DrawTool.__init__(self, exc_editor_app) + self.name = 'fc_drill_select' self.exc_editor_app = exc_editor_app self.storage = self.exc_editor_app.storage_dict @@ -1146,6 +1159,8 @@ class FCDrillSelect(DrawTool): class FCMove(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) + self.name = 'fc_move' + # self.shape_buffer = self.draw_app.shape_buffer self.origin = None self.destination = None @@ -1211,6 +1226,9 @@ class FCMove(FCShapeTool): class FCCopy(FCMove): + def __init__(self, draw_app): + FCMove.__init__(self, draw_app) + self.name = 'fc_copy' def make(self): # Create new geometry @@ -1225,6 +1243,8 @@ class FCCopy(FCMove): class FCText(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) + self.name = 'fc_text' + # self.shape_buffer = self.draw_app.shape_buffer self.draw_app = draw_app self.app = draw_app.app @@ -1275,6 +1295,8 @@ class FCText(FCShapeTool): class FCBuffer(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) + self.name = 'fc_buffer' + # self.shape_buffer = self.draw_app.shape_buffer self.draw_app = draw_app self.app = draw_app.app @@ -1341,6 +1363,8 @@ class FCBuffer(FCShapeTool): class FCPaint(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) + self.name = 'fc_paint' + # self.shape_buffer = self.draw_app.shape_buffer self.draw_app = draw_app self.app = draw_app.app @@ -1355,6 +1379,7 @@ class FCPaint(FCShapeTool): class FCRotate(FCShapeTool): def __init__(self, draw_app): FCShapeTool.__init__(self, draw_app) + self.name = 'fc_rotate' geo = self.utility_geometry(data=(self.draw_app.snap_x, self.draw_app.snap_y)) @@ -1366,7 +1391,6 @@ class FCRotate(FCShapeTool): def set_origin(self, origin): self.origin = origin - def make(self): # Create new geometry # dx = self.origin[0] @@ -1382,9 +1406,9 @@ class FCRotate(FCShapeTool): #self.draw_app.select_tool("select") def on_key(self, key): - if key == 'Enter': - if self.complete == True: - self.make() + if key == 'Enter' or key == QtCore.Qt.Key_Enter: + self.make() + return "Done" def click(self, point): self.make() @@ -1408,6 +1432,7 @@ class FCDrillAdd(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_drill_add' self.selected_dia = None try: @@ -1443,11 +1468,17 @@ class FCDrillAdd(FCShapeTool): return DrawToolUtilityShape(self.util_shape(data)) def util_shape(self, point): + if point[0] is None and point[1] is None: + point_x = self.draw_app.x + point_y = self.draw_app.y + else: + point_x = point[0] + point_y = point[1] - start_hor_line = ((point[0] - (self.selected_dia / 2)), point[1]) - stop_hor_line = ((point[0] + (self.selected_dia / 2)), point[1]) - start_vert_line = (point[0], (point[1] - (self.selected_dia / 2))) - stop_vert_line = (point[0], (point[1] + (self.selected_dia / 2))) + start_hor_line = ((point_x - (self.selected_dia / 2)), point_y) + stop_hor_line = ((point_x + (self.selected_dia / 2)), point_y) + start_vert_line = (point_x, (point_y - (self.selected_dia / 2))) + stop_vert_line = (point_x, (point_y + (self.selected_dia / 2))) return MultiLineString([(start_hor_line, stop_hor_line), (start_vert_line, stop_vert_line)]) @@ -1473,6 +1504,7 @@ class FCDrillArray(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_drill_array' self.draw_app.array_frame.show() @@ -1558,17 +1590,16 @@ class FCDrillArray(FCShapeTool): return if self.drill_array == 'Linear': - # if self.origin is None: - # self.origin = (0, 0) - # - # dx = data[0] - self.origin[0] - # dy = data[1] - self.origin[1] - dx = data[0] - dy = data[1] + if data[0] is None and data[1] is None: + dx = self.draw_app.x + dy = self.draw_app.y + else: + dx = data[0] + dy = data[1] geo_list = [] geo = None - self.points = data + self.points = [dx, dy] for item in range(self.drill_array_size): if self.drill_axis == 'X': @@ -1592,16 +1623,30 @@ class FCDrillArray(FCShapeTool): self.last_dy = dy return DrawToolUtilityShape(geo_list) else: + if data[0] is None and data[1] is None: + cdx = self.draw_app.x + cdy = self.draw_app.y + else: + cdx = data[0] + cdy = data[1] + if len(self.pt) > 0: temp_points = [x for x in self.pt] - temp_points.append(data) + temp_points.append([cdx, cdy]) return DrawToolUtilityShape(LineString(temp_points)) def util_shape(self, point): - start_hor_line = ((point[0] - (self.selected_dia / 2)), point[1]) - stop_hor_line = ((point[0] + (self.selected_dia / 2)), point[1]) - start_vert_line = (point[0], (point[1] - (self.selected_dia / 2))) - stop_vert_line = (point[0], (point[1] + (self.selected_dia / 2))) + if point[0] is None and point[1] is None: + point_x = self.draw_app.x + point_y = self.draw_app.y + else: + point_x = point[0] + point_y = point[1] + + start_hor_line = ((point_x - (self.selected_dia / 2)), point_y) + stop_hor_line = ((point_x + (self.selected_dia / 2)), point_y) + start_vert_line = (point_x, (point_y - (self.selected_dia / 2))) + stop_vert_line = (point_x, (point_y + (self.selected_dia / 2))) return MultiLineString([(start_hor_line, stop_hor_line), (start_vert_line, stop_vert_line)]) @@ -1656,10 +1701,12 @@ class FCDrillArray(FCShapeTool): self.draw_app.array_frame.hide() return -class FCDrillResize(FCShapeTool): +class FCDrillResize(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_drill_resize' + self.draw_app.app.inform.emit("Click on the Drill(s) to resize ...") self.resize_dia = None self.draw_app.resize_frame.show() @@ -1761,6 +1808,8 @@ class FCDrillResize(FCShapeTool): class FCDrillMove(FCShapeTool): def __init__(self, draw_app): DrawTool.__init__(self, draw_app) + self.name = 'fc_drill_move' + # self.shape_buffer = self.draw_app.shape_buffer self.origin = None self.destination = None @@ -1850,6 +1899,9 @@ class FCDrillMove(FCShapeTool): class FCDrillCopy(FCDrillMove): + def __init__(self, draw_app): + FCDrillMove.__init__(self, draw_app) + self.name = 'fc_drill_copy' def make(self): # Create new geometry @@ -1977,6 +2029,7 @@ class FlatCAMGeoEditor(QtCore.QObject): self.geo_key_modifiers = None self.x = None # Current mouse cursor pos self.y = None + # Current snapped mouse pos self.snap_x = None self.snap_y = None diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py index 9065d647..91690f9b 100644 --- a/FlatCAMGUI.py +++ b/FlatCAMGUI.py @@ -1738,7 +1738,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # New Geometry if key == QtCore.Qt.Key_N: - self.app.on_new_geometry() + self.app.new_geometry_object() # Set Origin if key == QtCore.Qt.Key_O: @@ -1820,15 +1820,26 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # complete automatically, like a polygon or path. if key == QtCore.Qt.Key_Enter or key == 'Enter': if isinstance(self.app.geo_editor.active_tool, FCShapeTool): - self.app.geo_editor.active_tool.click( - self.app.geo_editor.snap(self.app.geo_editor.x, self.app.geo_editor.y)) - self.app.geo_editor.active_tool.make() - if self.app.geo_editor.active_tool.complete: - self.app.geo_editor.on_shape_complete() - self.app.inform.emit("[success]Done.") - # automatically make the selection tool active after completing current action - self.app.geo_editor.select_tool('select') - return + if self.app.geo_editor.active_tool.name == 'fc_rotate': + self.app.geo_editor.active_tool.make() + + if self.app.geo_editor.active_tool.complete: + self.app.geo_editor.on_shape_complete() + self.app.inform.emit("[success]Done.") + # automatically make the selection tool active after completing current action + self.app.geo_editor.select_tool('select') + return + else: + self.app.geo_editor.active_tool.click( + self.app.geo_editor.snap(self.app.geo_editor.x, self.app.geo_editor.y)) + + self.app.geo_editor.active_tool.make() + + if self.app.geo_editor.active_tool.complete: + self.app.geo_editor.on_shape_complete() + self.app.inform.emit("[success]Done.") + # automatically make the selection tool active after completing current action + self.app.geo_editor.select_tool('select') # Abort the current action if key == QtCore.Qt.Key_Escape or key == 'Escape': @@ -1887,7 +1898,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): if key == QtCore.Qt.Key_C or key == 'C': self.app.ui.geo_copy_btn.setChecked(True) self.app.geo_editor.on_tool_select('copy') - self.app.geo_editor.active_tool.set_origin(self.snap(self.x, self.y)) + self.app.geo_editor.active_tool.set_origin(self.app.geo_editor.snap( + self.app.geo_editor.x, self.app.geo_editor.y)) self.app.inform.emit("Click on target point.") # Substract Tool @@ -2004,7 +2016,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # Propagate to tool response = None if self.app.geo_editor.active_tool is not None: - response = self.app.geo_editor.active_tool.on_key(event) + response = self.app.geo_editor.active_tool.on_key(key=key) if response is not None: self.app.inform.emit(response) @@ -2094,6 +2106,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.exc_editor.launched_from_shortcuts = True self.app.inform.emit("Click on target point.") self.app.ui.add_drill_array_btn.setChecked(True) + + self.app.exc_editor.x = self.app.mouse[0] + self.app.exc_editor.y = self.app.mouse[1] + self.app.exc_editor.select_tool('add_array') return @@ -2115,6 +2131,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.exc_editor.launched_from_shortcuts = True self.app.inform.emit("Click on target point.") self.app.ui.add_drill_btn.setChecked(True) + + self.app.exc_editor.x = self.app.mouse[0] + self.app.exc_editor.y = self.app.mouse[1] + self.app.exc_editor.select_tool('add') return @@ -2142,7 +2162,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.app.inform.emit("Click on target point.") self.app.ui.move_drill_btn.setChecked(True) self.app.exc_editor.on_tool_select('move') - self.app.exc_editor.active_tool.set_origin((self.snap_x, self.snap_y)) + self.app.exc_editor.active_tool.set_origin( + (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y)) else: self.app.inform.emit("[WARNING_NOTCL]Cancelled. Nothing selected to move.") return @@ -2182,7 +2203,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # Propagate to tool response = None if self.app.exc_editor.active_tool is not None: - response = self.app.exc_editor.active_tool.on_key(event) + response = self.app.exc_editor.active_tool.on_key(key=key) if response is not None: self.app.inform.emit(response) diff --git a/README.md b/README.md index dbc03b4f..24f67c8f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ CAD program, and create G-Code for Isolation routing. - added a protection for when saving a file first time, it require a saved path and if none then it use the current working directory - added into Preferences the Calculator Tools - made the Preferences window scrollable on the horizontal side (it was only vertically scrollable before) +- fixed an error in Excellon Editor -> add drill array that could appear by starting the function to add a drill array by shortcut before any mouse move is registered while in Editor +- changed the messages from status bar on new object creation/selection +- in Geometry Editor fixed the handler for the Rotate shortcut key ('R') 8.02.2019 diff --git a/flatcamTools/ToolCalculators.py b/flatcamTools/ToolCalculators.py index fc09ebd6..e74393ed 100644 --- a/flatcamTools/ToolCalculators.py +++ b/flatcamTools/ToolCalculators.py @@ -21,6 +21,40 @@ class ToolCalculator(FlatCAMTool): title_label = QtWidgets.QLabel("%s" % self.toolName) self.layout.addWidget(title_label) + ###################### + ## Units Calculator ## + ###################### + + self.unists_spacer_label = QtWidgets.QLabel(" ") + self.layout.addWidget(self.unists_spacer_label) + + ## Title of the Units Calculator + units_label = QtWidgets.QLabel("%s" % self.unitsName) + self.layout.addWidget(units_label) + + #Grid Layout + grid_units_layout = QtWidgets.QGridLayout() + self.layout.addLayout(grid_units_layout) + + inch_label = QtWidgets.QLabel("INCH") + mm_label = QtWidgets.QLabel("MM") + grid_units_layout.addWidget(mm_label, 0, 0) + grid_units_layout.addWidget( inch_label, 0, 1) + + self.inch_entry = FCEntry() + # self.inch_entry.setFixedWidth(70) + self.inch_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) + self.inch_entry.setToolTip("Here you enter the value to be converted from INCH to MM") + + self.mm_entry = FCEntry() + # self.mm_entry.setFixedWidth(130) + self.mm_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) + self.mm_entry.setToolTip("Here you enter the value to be converted from MM to INCH") + + grid_units_layout.addWidget(self.mm_entry, 1, 0) + grid_units_layout.addWidget(self.inch_entry, 1, 1) + + ############################ ## V-shape Tool Calculator ## ############################ @@ -83,38 +117,6 @@ class ToolCalculator(FlatCAMTool): form_layout.addRow(self.empty_label, self.calculate_vshape_button) - ###################### - ## Units Calculator ## - ###################### - - self.unists_spacer_label = QtWidgets.QLabel(" ") - self.layout.addWidget(self.unists_spacer_label) - - ## Title of the Units Calculator - units_label = QtWidgets.QLabel("%s" % self.unitsName) - self.layout.addWidget(units_label) - - #Grid Layout - grid_units_layout = QtWidgets.QGridLayout() - self.layout.addLayout(grid_units_layout) - - inch_label = QtWidgets.QLabel("INCH") - mm_label = QtWidgets.QLabel("MM") - grid_units_layout.addWidget(mm_label, 0, 0) - grid_units_layout.addWidget( inch_label, 0, 1) - - self.inch_entry = FCEntry() - # self.inch_entry.setFixedWidth(70) - self.inch_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) - self.inch_entry.setToolTip("Here you enter the value to be converted from INCH to MM") - - self.mm_entry = FCEntry() - # self.mm_entry.setFixedWidth(130) - self.mm_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) - self.mm_entry.setToolTip("Here you enter the value to be converted from MM to INCH") - - grid_units_layout.addWidget(self.mm_entry, 1, 0) - grid_units_layout.addWidget(self.inch_entry, 1, 1) #################################### ## ElectroPlating Tool Calculator ##