From 6edd7f051ac0a307b7078f261cb338575c4a70bb Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Wed, 8 Jul 2020 15:51:03 +0300 Subject: [PATCH] - Tool Drilling - working on the UI - Tool Drilling - added more tool parameters; laying the ground for adding "Drilling Slots" feature --- CHANGELOG.md | 5 + appGUI/preferences/PreferencesUIManager.py | 3 + .../excellon/ExcellonAdvOptPrefGroupUI.py | 38 ++++++ appObjects/FlatCAMObj.py | 3 + appObjects/ObjectCollection.py | 2 + appTools/ToolDrilling.py | 124 ++++++++++++++---- appTools/ToolIsolation.py | 2 +- defaults.py | 3 + 8 files changed, 152 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9bf667..7eb6d84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta ================================================= +8.07.2020 + +- Tool Drilling - working on the UI +- Tool Drilling - added more tool parameters; laying the ground for adding "Drilling Slots" feature + 7.07.2020 - updated the Panelize Tool to save the source code for the panelized Excellon objects so it can be saved from the Save project tab context menu entry diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index 7203fd59..440add86 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -222,6 +222,9 @@ class PreferencesUIManager: "excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio, "excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb, "excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb, + "excellon_drill_slots": self.ui.excellon_defaults_form.excellon_adv_opt_group.drill_slots_cb, + "excellon_drill_overlap": self.ui.excellon_defaults_form.excellon_adv_opt_group.drill_overlap_entry, + "excellon_last_drill": self.ui.excellon_defaults_form.excellon_adv_opt_group.last_drill_cb, # Excellon Export "excellon_exp_units": self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio, diff --git a/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py b/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py index 94d9986b..571475a4 100644 --- a/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py +++ b/appGUI/preferences/excellon/ExcellonAdvOptPrefGroupUI.py @@ -152,4 +152,42 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI): grid1.addWidget(self.fretract_cb, 8, 0, 1, 2) + separator_line = QtWidgets.QFrame() + separator_line.setFrameShape(QtWidgets.QFrame.HLine) + separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) + grid1.addWidget(separator_line, 9, 0, 1, 2) + + # DRILL SLOTS LABEL + self.dslots_label = QtWidgets.QLabel('%s:' % _('Drilling Slots')) + grid1.addWidget(self.dslots_label, 10, 0, 1, 2) + + # Drill slots + self.drill_slots_cb = FCCheckBox('%s' % _('Drill slots')) + self.drill_slots_cb.setToolTip( + _("If the selected tool has slots then they will be drilled.") + ) + grid1.addWidget(self.drill_slots_cb, 11, 0, 1, 2) + + # Drill Overlap + self.drill_overlap_label = QtWidgets.QLabel('%s:' % _('Overlap')) + self.drill_overlap_label.setToolTip( + _("How much (percentage) of the tool diameter to overlap previous drill hole.") + ) + + self.drill_overlap_entry = FCDoubleSpinner() + self.drill_overlap_entry.set_precision(self.decimals) + self.drill_overlap_entry.set_range(0.0, 9999.9999) + self.drill_overlap_entry.setSingleStep(0.1) + + grid1.addWidget(self.drill_overlap_label, 12, 0) + grid1.addWidget(self.drill_overlap_entry, 12, 1) + + # Last drill in slot + self.last_drill_cb = FCCheckBox('%s' % _('Last drill')) + self.last_drill_cb.setToolTip( + _("If the slot length is not completely covered by drill holes,\n" + "add a drill hole on the slot end point.") + ) + grid1.addWidget(self.last_drill_cb, 14, 0, 1, 2) + self.layout.addStretch() diff --git a/appObjects/FlatCAMObj.py b/appObjects/FlatCAMObj.py index 5c58d036..cf05994a 100644 --- a/appObjects/FlatCAMObj.py +++ b/appObjects/FlatCAMObj.py @@ -67,6 +67,9 @@ class FlatCAMObj(QtCore.QObject): # View self.ui = None + # set True by the collection.append() when the object load is complete + self.load_complete = None + self.options = LoudDict(name=name) self.options.set_change_callback(self.on_options_change) diff --git a/appObjects/ObjectCollection.py b/appObjects/ObjectCollection.py index 587da614..65751ab9 100644 --- a/appObjects/ObjectCollection.py +++ b/appObjects/ObjectCollection.py @@ -570,6 +570,8 @@ class ObjectCollection(QtCore.QAbstractItemModel): obj.options["name"] = name obj.set_ui(obj.ui_type(app=self.app)) + # a way to signal that the object was fully loaded + obj.load_complete = True # Required before appending (Qt MVC) group = self.group_items[obj.kind] diff --git a/appTools/ToolDrilling.py b/appTools/ToolDrilling.py index 3cf7106d..93e728f8 100644 --- a/appTools/ToolDrilling.py +++ b/appTools/ToolDrilling.py @@ -138,22 +138,30 @@ class ToolDrilling(AppTool, Excellon): "dwell": self.t_ui.dwell_cb, "dwelltime": self.t_ui.dwelltime_entry, - "offset": self.t_ui.offset_entry + "offset": self.t_ui.offset_entry, + + "drill_slots": self.t_ui.drill_slots_cb, + "drill_overlap": self.t_ui.drill_overlap_entry, + "last_drill": self.t_ui.last_drill_cb } self.name2option = { - "e_cutz": "cutz", - "e_multidepth": "multidepth", - "e_depthperpass": "depthperpass", - "e_travelz": "travelz", - "e_feedratez": "feedrate_z", - "e_fr_rapid": "feedrate_rapid", + "e_cutz": "cutz", + "e_multidepth": "multidepth", + "e_depthperpass": "depthperpass", + "e_travelz": "travelz", + "e_feedratez": "feedrate_z", + "e_fr_rapid": "feedrate_rapid", - "e_spindlespeed": "spindlespeed", - "e_dwell": "dwell", - "e_dwelltime": "dwelltime", + "e_spindlespeed": "spindlespeed", + "e_dwell": "dwell", + "e_dwelltime": "dwelltime", - "e_offset": "offset" + "e_offset": "offset", + + "e_drill_slots": "drill_slots", + "e_drill_slots_overlap": "drill_overlap", + "e_drill_last_drill": "last_drill", } self.old_tool_dia = None @@ -188,9 +196,9 @@ class ToolDrilling(AppTool, Excellon): AppTool.run(self) - self.on_object_changed() self.set_tool_ui() - self.build_ui() + self.on_object_changed() + # self.build_tool_ui() # all the tools are selected by default self.t_ui.tools_table.selectAll() @@ -338,6 +346,11 @@ class ToolDrilling(AppTool, Excellon): "f_plunge": self.app.defaults["excellon_f_plunge"], "f_retract": self.app.defaults["excellon_f_retract"], + # Drill Slots + "drill_slots": self.app.defaults["excellon_drill_slots"], + "drill_overlap": self.app.defaults["excellon_drill_overlap"], + "last_drill": self.app.defaults["excellon_last_drill"], + "gcode": '', "gcode_parsed": '', "geometry": [], @@ -362,10 +375,13 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.tools_table.setMinimumHeight(self.t_ui.tools_table.getHeight()) self.t_ui.tools_table.setMaximumHeight(self.t_ui.tools_table.getHeight()) - if self.excellon_obj: - # make sure to update the UI on init + # make sure to update the UI on init + try: self.excellon_tools = self.excellon_obj.tools - self.build_ui() + except AttributeError: + # no object loaded + pass + self.build_tool_ui() # ######################################## # ######################################## @@ -394,6 +410,18 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.over_z_entry.set_value(self.app.defaults["excellon_area_overz"]) self.t_ui.area_shape_radio.set_value(self.app.defaults["excellon_area_shape"]) + # Drill slots - part of the Advanced Excellon params + self.t_ui.drill_slots_cb.set_value(self.app.defaults["excellon_drill_slots"]) + self.t_ui.drill_overlap_entry.set_value(self.app.defaults["excellon_drill_overlap"]) + self.t_ui.last_drill_cb.set_value(self.app.defaults["excellon_last_drill"]) + # if the app mode is Basic then disable this feature + if app_mode == 'b': + self.t_ui.drill_slots_cb.set_value(False) + self.t_ui.drill_slots_cb.hide() + self.t_ui.drill_overlap_label.hide() + self.t_ui.drill_overlap_entry.hide() + self.t_ui.last_drill_cb.hide() + try: self.t_ui.object_combo.currentTextChanged.disconnect() except (AttributeError, TypeError): @@ -420,10 +448,10 @@ class ToolDrilling(AppTool, Excellon): self.excellon_tools = new_tools # the tools table changed therefore we need to rebuild it - QtCore.QTimer.singleShot(20, self.build_ui) + QtCore.QTimer.singleShot(20, self.build_tool_ui) - def build_ui(self): - log.debug("ToolDrilling.build_ui()") + def build_tool_ui(self): + log.debug("ToolDrilling.build_tool_ui()") self.ui_disconnect() # order the tools by tool diameter if it's the case @@ -588,7 +616,7 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.tools_table.setMaximumHeight(self.t_ui.tools_table.getHeight()) # all the tools are selected by default - # self.t_ui.tools_table.selectAll() + self.t_ui.tools_table.selectAll() # Build Exclusion Areas section e_len = len(self.app.exc_areas.exclusion_areas_storage) @@ -676,7 +704,7 @@ class ToolDrilling(AppTool, Excellon): return if self.excellon_obj is None: - self.excellon_tools = [] + self.excellon_tools = {} self.t_ui.exc_param_frame.setDisabled(True) self.set_tool_ui() else: @@ -685,7 +713,7 @@ class ToolDrilling(AppTool, Excellon): self.t_ui.exc_param_frame.setDisabled(False) self.excellon_tools = self.excellon_obj.tools - self.build_ui() + self.build_tool_ui() sel_rows = set() table_items = self.t_ui.tools_table.selectedItems() @@ -709,7 +737,7 @@ class ToolDrilling(AppTool, Excellon): self.app.exc_areas.e_shape_modified.disconnect() except (TypeError, AttributeError): pass - # then connect it to the current build_ui() method + # then connect it to the current build_tool_ui() method self.app.exc_areas.e_shape_modified.connect(self.update_exclusion_table) # rows selected @@ -977,7 +1005,7 @@ class ToolDrilling(AppTool, Excellon): def on_order_changed(self, order): if order != 'no': - self.build_ui() + self.build_tool_ui() def on_tooltable_cellwidget_change(self): cw = self.sender() @@ -1441,7 +1469,7 @@ class ToolDrilling(AppTool, Excellon): def update_exclusion_table(self): self.exclusion_area_cb_is_checked = True if self.t_ui.exclusion_cb.isChecked() else False - self.build_ui() + self.build_tool_ui() self.t_ui.exclusion_cb.set_value(self.exclusion_area_cb_is_checked) def on_strategy(self, val): @@ -2144,7 +2172,7 @@ class ToolDrilling(AppTool, Excellon): # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # APPLY Offset only when using the appGUI, for TclCommand this will create an error - # because the values for Z offset are created in build_ui() + # because the values for Z offset are created in build_tool_ui() # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! try: z_offset = float(tool_dict['offset']) * (-1) @@ -2373,7 +2401,7 @@ class ToolDrilling(AppTool, Excellon): # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # APPLY Offset only when using the appGUI, for TclCommand this will create an error - # because the values for Z offset are created in build_ui() + # because the values for Z offset are created in build_tool_ui() # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! try: z_offset = float(self.exc_tools[one_tool]['data']['offset']) * (-1) @@ -2879,6 +2907,48 @@ class DrillingUI: self.grid1.addWidget(self.tool_offset_label, 25, 0) self.grid1.addWidget(self.offset_entry, 25, 1) + # Drill slots + self.drill_slots_cb = FCCheckBox('%s' % _('Drill slots')) + self.drill_slots_cb.setToolTip( + _("If the selected tool has slots then they will be drilled.") + ) + self.drill_slots_cb.setObjectName("e_drill_slots") + self.grid1.addWidget(self.drill_slots_cb, 27, 0, 1, 2) + + # Drill Overlap + self.drill_overlap_label = QtWidgets.QLabel('%s:' % _('Overlap')) + self.drill_overlap_label.setToolTip( + _("How much (percentage) of the tool diameter to overlap previous drill hole.") + ) + + self.drill_overlap_entry = FCDoubleSpinner(callback=self.confirmation_message) + self.drill_overlap_entry.set_precision(self.decimals) + self.drill_overlap_entry.set_range(0.0, 9999.9999) + self.drill_overlap_entry.setSingleStep(0.1) + + self.drill_overlap_entry.setObjectName("e_drill_slots_overlap") + + self.grid1.addWidget(self.drill_overlap_label, 28, 0) + self.grid1.addWidget(self.drill_overlap_entry, 28, 1) + + # Last drill in slot + self.last_drill_cb = FCCheckBox('%s' % _('Last drill')) + self.last_drill_cb.setToolTip( + _("If the slot length is not completely covered by drill holes,\n" + "add a drill hole on the slot end point.") + ) + self.last_drill_cb.setObjectName("e_drill_last_drill") + self.grid1.addWidget(self.last_drill_cb, 30, 0, 1, 2) + + self.ois_drill_overlap = OptionalInputSection( + self.drill_slots_cb, + [ + self.drill_overlap_label, + self.drill_overlap_entry, + self.last_drill_cb + ] + ) + # ################################################################# # ################# GRID LAYOUT 5 ############################### # ################################################################# diff --git a/appTools/ToolIsolation.py b/appTools/ToolIsolation.py index b50dda27..4dd088c8 100644 --- a/appTools/ToolIsolation.py +++ b/appTools/ToolIsolation.py @@ -3160,7 +3160,7 @@ class IsoUI: self.exc_obj_combo.setModel(self.app.collection) self.exc_obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex())) self.exc_obj_combo.is_last = True - self.exc_obj_combo.obj_type = self.type_excobj_radio.get_value() + self.exc_obj_combo.obj_type = "gerber" self.grid3.addWidget(self.exc_obj_combo, 29, 0, 1, 2) diff --git a/defaults.py b/defaults.py index 96294d41..83053262 100644 --- a/defaults.py +++ b/defaults.py @@ -287,6 +287,9 @@ class FlatCAMDefaults: "excellon_spindledir": 'CW', "excellon_f_plunge": False, "excellon_f_retract": False, + "excellon_drill_slots": False, + "excellon_drill_overlap": 0.0, + "excellon_last_drill": True, # Excellon Export "excellon_exp_units": 'INCH',