Browse Source

- updated the Excellon UI to hold data for each tool
- in Excellon UI removed the tools table column for Offset Z and used the UI form parameter
- updated the Excellon Editor to add for each tool a 'data' dictionary
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside

Marius Stanciu 6 năm trước cách đây
mục cha
commit
1e9232aeaa

+ 17 - 5
FlatCAMApp.py

@@ -622,7 +622,9 @@ class App(QtCore.QObject):
             "excellon_zeros": "L",
             "excellon_units": "INCH",
             "excellon_update": True,
+
             "excellon_optimization_type": 'B',
+
             "excellon_search_time": 3,
             "excellon_save_filters": "Excellon File (*.txt);;Excellon File (*.drd);;Excellon File (*.drl);;"
                                      "Excellon File (*.exc);;Excellon File (*.ncd);;Excellon File (*.tap);;"
@@ -631,12 +633,17 @@ class App(QtCore.QObject):
             "excellon_plot_line": '#750000BF',
 
             # Excellon Options
-            "excellon_drillz": -1.7,
+            "excellon_operation": "drill",
+            "excellon_milling_type": "drills",
+
+            "excellon_milling_dia": 0.8,
+
+            "excellon_cutz": -1.7,
             "excellon_multidepth": False,
             "excellon_depthperpass": 0.7,
             "excellon_travelz": 2,
             "excellon_endz": 0.5,
-            "excellon_feedrate": 300,
+            "excellon_feedrate_z": 300,
             "excellon_spindlespeed": 0,
             "excellon_dwell": False,
             "excellon_dwelltime": 1,
@@ -1308,12 +1315,17 @@ class App(QtCore.QObject):
             "excellon_plot_line": self.ui.excellon_defaults_form.excellon_gen_group.line_color_entry,
 
             # Excellon Options
-            "excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
+            "excellon_operation": self.ui.excellon_defaults_form.excellon_opt_group.operation_radio,
+            "excellon_milling_type": self.ui.excellon_defaults_form.excellon_opt_group.milling_type_radio,
+
+            "excellon_milling_dia": self.ui.excellon_defaults_form.excellon_opt_group.mill_dia_entry,
+
+            "excellon_cutz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
             "excellon_multidepth": self.ui.excellon_defaults_form.excellon_opt_group.mpass_cb,
             "excellon_depthperpass": self.ui.excellon_defaults_form.excellon_opt_group.maxdepth_entry,
             "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
             "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.endz_entry,
-            "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
+            "excellon_feedrate_z": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry,
             "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
             "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
             "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry,
@@ -5944,7 +5956,7 @@ class App(QtCore.QObject):
         dimensions = ['gerber_isotooldia', 'gerber_noncoppermargin', 'gerber_bboxmargin', "gerber_isooverlap",
                       "gerber_editor_newsize", "gerber_editor_lin_pitch", "gerber_editor_buff_f",
 
-                      'excellon_drillz',  'excellon_travelz', "excellon_toolchangexy",
+                      'excellon_cutz',  'excellon_travelz', "excellon_toolchangexy", 'excellon_offset',
                       'excellon_feedrate', 'excellon_feedrate_rapid', 'excellon_toolchangez',
                       'excellon_tooldia', 'excellon_slot_tooldia', 'excellon_endz', "excellon_feedrate_probe",
                       "excellon_z_pdepth", "excellon_editor_newdia", "excellon_editor_lin_pitch",

+ 204 - 110
FlatCAMObj.py

@@ -2323,34 +2323,46 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.options.update({
             "plot": True,
             "solid": False,
-            "drillz": -0.1,
+
+            "operation": "drill",
+            "milling_type": "drills",
+
+            "milling_dia": 0.04,
+
+            "cutz": -0.1,
             "multidepth": False,
             "depthperpass": 0.7,
             "travelz": 0.1,
-            "feedrate": 5.0,
+            "feedrate": self.app.defaults["geometry_feedrate"],
+            "feedrate_z": 5.0,
             "feedrate_rapid": 5.0,
             "tooldia": 0.1,
             "slot_tooldia": 0.1,
             "toolchange": False,
             "toolchangez": 1.0,
             "toolchangexy": "0.0, 0.0",
+            "extracut": self.app.defaults["geometry_extracut"],
+            "extracut_length":self.app.defaults["geometry_extracut_length"],
             "endz": 2.0,
             "startz": None,
+            "offset": 0.0,
             "spindlespeed": 0,
             "dwell": True,
             "dwelltime": 1000,
-            "ppname_e": 'defaults',
+            "ppname_e": 'default',
+            "ppname_g": self.app.defaults["geometry_ppname_g"],
             "z_pdepth": -0.02,
             "feedrate_probe": 3.0,
-            "optimization_type": "R",
-            "gcode_type": "drills"
+            "optimization_type": "B",
         })
 
         # TODO: Document this.
         self.tool_cbs = dict()
 
-        # dict to hold the tool number as key and tool offset as value
-        self.tool_offset = dict()
+        # dict that holds the object names and the option name
+        # the key is the object name (defines in ObjectUI) for each UI element that is a parameter
+        # particular for a tool and the value is the actual name of the option that the UI element is changing
+        self.name2option = dict()
 
         # default set of data to be added to each tool in self.tools as self.tools[tool]['data'] = self.default_data
         self.default_data = dict()
@@ -2598,8 +2610,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         sorted_tools = sorted(sort, key=lambda t1: t1[1])
         tools = [i[0] for i in sorted_tools]
 
+        new_options = dict()
+        for opt in self.options:
+            new_options[opt] = self.options[opt]
+
         for tool_no in tools:
 
+            # add the data dictionary for each tool with the default values
+            self.tools[tool_no]['data'] = deepcopy(new_options)
+            # self.tools[tool_no]['data']["tooldia"] = self.tools[tool_no]["C"]
+            # self.tools[tool_no]['data']["slot_tooldia"] = self.tools[tool_no]["C"]
+
             drill_cnt = 0  # variable to store the nr of drills per tool
             slot_cnt = 0  # variable to store the nr of slots per tool
 
@@ -2631,18 +2652,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             slot_count_item = QtWidgets.QTableWidgetItem(slot_count_str)
             slot_count_item.setFlags(QtCore.Qt.ItemIsEnabled)
 
-            try:
-                t_offset = self.tool_offset[float('%.*f' % (self.decimals, float(self.tools[tool_no]['C'])))]
-            except KeyError:
-                t_offset = self.app.defaults['excellon_offset']
-
-            tool_offset_item = FCDoubleSpinner()
-            tool_offset_item.set_precision(self.decimals)
-            tool_offset_item.set_range(-9999.9999, 9999.9999)
-            tool_offset_item.setWrapping(True)
-            tool_offset_item.setSingleStep(0.1) if self.units == 'MM' else tool_offset_item.setSingleStep(0.01)
-            tool_offset_item.set_value(t_offset)
-
             plot_item = FCCheckBox()
             plot_item.setLayoutDirection(QtCore.Qt.RightToLeft)
             if self.ui.plot_cb.isChecked():
@@ -2652,7 +2661,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.tools_table.setItem(self.tool_row, 1, dia_item)  # Diameter
             self.ui.tools_table.setItem(self.tool_row, 2, drill_count_item)  # Number of drills per tool
             self.ui.tools_table.setItem(self.tool_row, 3, slot_count_item)  # Number of drills per tool
-            self.ui.tools_table.setCellWidget(self.tool_row, 4, tool_offset_item)  # Tool offset
             empty_plot_item = QtWidgets.QTableWidgetItem('')
             empty_plot_item.setFlags(~QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
             self.ui.tools_table.setItem(self.tool_row, 5, empty_plot_item)
@@ -2679,7 +2687,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.ui.tools_table.setItem(self.tool_row, 1, label_tot_drill_count)
         self.ui.tools_table.setItem(self.tool_row, 2, tot_drill_count)  # Total number of drills
         self.ui.tools_table.setItem(self.tool_row, 3, empty_1_1)
-        self.ui.tools_table.setItem(self.tool_row, 4, empty_1_2)
         self.ui.tools_table.setItem(self.tool_row, 5, empty_1_3)
 
         font = QtGui.QFont()
@@ -2711,7 +2718,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.ui.tools_table.setItem(self.tool_row, 1, label_tot_slot_count)
         self.ui.tools_table.setItem(self.tool_row, 2, empty_2_1)
         self.ui.tools_table.setItem(self.tool_row, 3, tot_slot_count)  # Total number of slots
-        self.ui.tools_table.setItem(self.tool_row, 4, empty_2_2)
         self.ui.tools_table.setItem(self.tool_row, 5, empty_2_3)
 
         for kl in [1, 2, 3]:
@@ -2737,13 +2743,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         horizontal_header.setDefaultSectionSize(70)
         horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
         horizontal_header.resizeSection(0, 20)
-        if self.app.defaults["global_app_level"] == 'b':
-            horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
-        else:
-            horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
+
+        horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
+
         horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
         horizontal_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
-        horizontal_header.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch)
         horizontal_header.setSectionResizeMode(5, QtWidgets.QHeaderView.Fixed)
         horizontal_header.resizeSection(5, 17)
         self.ui.tools_table.setColumnWidth(5, 17)
@@ -2773,14 +2777,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.slot_tooldia_entry.show()
             self.ui.generate_milling_slots_button.show()
 
-        # we reactivate the signals after the after the tool adding as we don't need to see the tool been populated
-        for row in range(self.ui.tools_table.rowCount()):
-            try:
-                offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
-                offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit)
-            except (TypeError, AttributeError):
-                pass
-
         # set the text on tool_data_label after loading the object
         sel_rows = list()
         sel_items = self.ui.tools_table.selectedItems()
@@ -2811,33 +2807,71 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.form_fields.update({
             "plot": self.ui.plot_cb,
             "solid": self.ui.solid_cb,
-            "drillz": self.ui.cutz_entry,
+
+            "operation": self.ui.operation_radio,
+            "milling_type": self.ui.milling_type_radio,
+
+            "milling_dia": self.ui.mill_dia_entry,
+            "cutz": self.ui.cutz_entry,
             "multidepth": self.ui.mpass_cb,
             "depthperpass": self.ui.maxdepth_entry,
             "travelz": self.ui.travelz_entry,
-            "feedrate": self.ui.feedrate_z_entry,
+            "feedrate_z": self.ui.feedrate_z_entry,
+            "feedrate": self.ui.xyfeedrate_entry,
             "feedrate_rapid": self.ui.feedrate_rapid_entry,
             "tooldia": self.ui.tooldia_entry,
             "slot_tooldia": self.ui.slot_tooldia_entry,
             "toolchange": self.ui.toolchange_cb,
             "toolchangez": self.ui.toolchangez_entry,
+            "extracut": self.ui.extracut_cb,
+            "extracut_length": self.ui.e_cut_entry,
+
             "spindlespeed": self.ui.spindlespeed_entry,
             "dwell": self.ui.dwell_cb,
             "dwelltime": self.ui.dwelltime_entry,
+
             "startz": self.ui.estartz_entry,
             "endz": self.ui.endz_entry,
+            "offset": self.ui.offset_entry,
+
             "ppname_e": self.ui.pp_excellon_name_cb,
+            "ppname_g": self.ui.pp_geo_name_cb,
             "z_pdepth": self.ui.pdepth_entry,
             "feedrate_probe": self.ui.feedrate_probe_entry,
-            "gcode_type": self.ui.excellon_gcode_type_radio
+            # "gcode_type": self.ui.excellon_gcode_type_radio
         })
 
+        self.name2option = {
+            "e_operation": "operation",
+            "e_milling_type": "milling_type",
+            "e_milling_dia": "milling_dia",
+            "e_cutz" : "cutz",
+            "e_multidepth" : "multidepth",
+            "e_depthperpass" : "depthperpass",
+
+            "e_travelz" : "travelz",
+            "e_feedratexy" : "feedrate",
+            "e_feedratez" : "feedrate_z",
+            "e_fr_rapid" : "feedrate_rapid",
+            "e_extracut" : "extracut",
+            "e_extracut_length" : "extracut_length",
+            "e_spindlespeed" : "spindlespeed",
+            "e_dwell" : "dwell",
+            "e_dwelltime" : "dwelltime",
+            "e_offset" : "offset",
+        }
+
+        # populate Excellon preprocessor combobox list
         for name in list(self.app.preprocessors.keys()):
             # the HPGL preprocessor is only for Geometry not for Excellon job therefore don't add it
             if name == 'hpgl':
                 continue
             self.ui.pp_excellon_name_cb.addItem(name)
 
+        # populate Geometry (milling) preprocessor combobox list
+        for name in list(self.app.preprocessors.keys()):
+            self.ui.pp_geo_name_cb.addItem(name)
+
         # Fill form fields
         self.to_form()
 
@@ -2846,13 +2880,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         # self.ui.pp_excellon_name_cb combobox
         self.on_pp_changed()
 
-        # initialize the dict that holds the tools offset
-        t_default_offset = self.app.defaults["excellon_offset"]
-        if not self.tool_offset:
-            for value in self.tools.values():
-                dia = float('%.*f' % (self.decimals, float(value['C'])))
-                self.tool_offset[dia] = t_default_offset
-
         # Show/Hide Advanced Options
         if self.app.defaults["global_app_level"] == 'b':
             self.ui.level.setText('<span style="color:green;"><b>%s</b></span>' % _('Basic'))
@@ -2895,6 +2922,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.ui.tools_table.clicked.connect(self.on_row_selection_change)
         self.ui.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
 
+        # value changed in the particular parameters of a tool
+        for key, option in self.name2option.items():
+            current_widget = self.form_fields[option]
+
+            if isinstance(current_widget, FCCheckBox):
+                current_widget.stateChanged.connect(self.form_to_storage)
+            if isinstance(current_widget, RadioSet):
+                current_widget.activated_custom.connect(self.form_to_storage)
+            elif isinstance(current_widget, FCDoubleSpinner) or isinstance(current_widget, FCSpinner):
+                current_widget.returnPressed.connect(self.form_to_storage)
+
     def ui_disconnect(self):
         # selective plotting
         for row in range(self.ui.tools_table.rowCount()):
@@ -2917,19 +2955,33 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         except (TypeError, AttributeError):
             pass
 
-    def on_row_selection_change(self):
-        self.update_ui()
+        # value changed in the particular parameters of a tool
+        for key, option in self.name2option.items():
+            current_widget = self.form_fields[option]
 
-    def update_ui(self, row=None):
+            if isinstance(current_widget, FCCheckBox):
+                try:
+                    current_widget.stateChanged.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+            if isinstance(current_widget, RadioSet):
+                try:
+                    current_widget.activated_custom.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+            elif isinstance(current_widget, FCDoubleSpinner) or isinstance(current_widget, FCSpinner):
+                try:
+                    current_widget.returnPressed.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+
+    def on_row_selection_change(self):
         self.ui_disconnect()
 
-        if row is None:
-            sel_rows = list()
-            sel_items = self.ui.tools_table.selectedItems()
-            for it in sel_items:
-                sel_rows.append(it.row())
-        else:
-            sel_rows = row if type(row) == list else [row]
+        sel_rows = list()
+        sel_items = self.ui.tools_table.selectedItems()
+        for it in sel_items:
+            sel_rows.append(it.row())
 
         if not sel_rows:
             self.ui.tool_data_label.setText(
@@ -2961,7 +3013,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             try:
                 item = self.ui.tools_table.item(c_row, 0)
                 if type(item) is not None:
-                    tooluid = int(item.text())
+                    tooluid = item.text()
+                    self.storage_to_form(self.tools[str(tooluid)]['data'])
                 else:
                     self.ui_connect()
                     return
@@ -2970,23 +3023,49 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                 self.ui_connect()
                 return
 
-            # try:
-            #     # set the form with data from the newly selected tool
-            #     for tooluid_key, tooluid_value in list(self.tools.items()):
-            #         if int(tooluid_key) == tooluid:
-            #             for key, value in tooluid_value.items():
-            #                 if key == 'data':
-            #                     form_value_storage = tooluid_value[key]
-            #                     self.update_form(form_value_storage)
-            # except Exception as e:
-            #     log.debug("FlatCAMObj ---> update_ui() " + str(e))
+        self.ui_connect()
+
+    def storage_to_form(self, dict_storage):
+        for form_key in self.form_fields:
+            for storage_key in dict_storage:
+                if form_key == storage_key:
+                    try:
+                        self.form_fields[form_key].set_value(dict_storage[form_key])
+                    except Exception as e:
+                        log.debug("FlatCAMExcellon.storage_to_form() --> %s" % str(e))
+                        pass
+
+    def form_to_storage(self):
+        if self.ui.tools_table.rowCount() == 0:
+            # there is no tool in tool table so we can't save the GUI elements values to storage
+            return
+
+        self.ui_disconnect()
+
+        widget_changed = self.sender()
+        wdg_objname = widget_changed.objectName()
+        option_changed = self.name2option[wdg_objname]
+
+        row = self.ui.tools_table.currentRow()
+
+        if row < 0:
+            row = 0
+        tooluid_item = int(self.ui.tools_table.item(row, 0).text())
+
+        for tooluid_key, tooluid_val in self.tools.items():
+            if int(tooluid_key) == tooluid_item:
+                new_option_value = self.form_fields[option_changed].get_value()
+                if option_changed in tooluid_val:
+                    tooluid_val[option_changed] = new_option_value
+                if option_changed in tooluid_val['data']:
+                    tooluid_val['data'][option_changed] = new_option_value
 
         self.ui_connect()
 
     def on_operation_type(self, val):
         if val == 'mill':
             self.ui.mill_type_label.show()
-            self.ui.mill_type_radio.show()
+            self.ui.milling_type_radio.show()
             self.ui.mill_dia_label.show()
             self.ui.mill_dia_entry.show()
             self.ui.frxylabel.show()
@@ -2999,7 +3078,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             #     self.ui.maxdepth_entry.show()
         else:
             self.ui.mill_type_label.hide()
-            self.ui.mill_type_radio.hide()
+            self.ui.milling_type_radio.hide()
             self.ui.mill_dia_label.hide()
             self.ui.mill_dia_entry.hide()
             # self.ui.mpass_cb.hide()
@@ -3009,32 +3088,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.extracut_cb.hide()
             self.ui.e_cut_entry.hide()
 
-    def on_tool_offset_edit(self):
-        # if connected, disconnect the signal from the slot on item_changed as it creates issues
-        for row in range(self.ui.tools_table.rowCount()):
-            try:
-                # if connected, disconnect the signal from the slot on item_changed as it creates issues
-                offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
-                offset_spin_widget.valueChanged.disconnect()
-            except (TypeError, AttributeError):
-                pass
-
-        self.units = self.app.defaults['units'].upper()
-        self.is_modified = True
-
-        row_of_item_changed = self.ui.tools_table.currentRow()
-        dia = float('%.*f' % (self.decimals, float(self.ui.tools_table.item(row_of_item_changed, 1).text())))
-
-        self.tool_offset[dia] = self.sender().get_value()
-
-        # we reactivate the signals after the after the tool editing
-        for row in range(self.ui.tools_table.rowCount()):
-            try:
-                offset_spin_widget = self.ui.tools_table.cellWidget(row, 4)
-                offset_spin_widget.valueChanged.connect(self.on_tool_offset_edit)
-            except (TypeError, AttributeError):
-                pass
-
     def get_selected_tools_list(self):
         """
         Returns the keys to the self.tools dictionary corresponding
@@ -3590,15 +3643,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             job_obj.options['type'] = 'Excellon'
             job_obj.options['ppname_e'] = pp_excellon_name
 
-            job_obj.z_cut = float(self.options["drillz"])
+            job_obj.z_cut = float(self.options["cutz"])
 
             job_obj.multidepth = self.options["multidepth"]
             job_obj.z_depthpercut = self.options["depthperpass"]
 
-            job_obj.tool_offset = self.tool_offset
             job_obj.z_move = float(self.options["travelz"])
-            job_obj.feedrate = float(self.options["feedrate"])
-            job_obj.z_feedrate = float(self.options["feedrate"])
+            job_obj.feedrate = float(self.options["feedrate_z"])
+            job_obj.z_feedrate = float(self.options["feedrate_z"])
             job_obj.feedrate_rapid = float(self.options["feedrate_rapid"])
 
             job_obj.spindlespeed = float(self.options["spindlespeed"]) if self.options["spindlespeed"] != 0 else None
@@ -3627,7 +3679,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             tools_csv = ','.join(tools)
             ret_val = job_obj.generate_from_excellon_by_tool(
                 self, tools_csv,
-                drillz=float(self.options['drillz']),
+                drillz=float(self.options['cutz']),
                 toolchange=self.options["toolchange"],
                 toolchangexy=self.app.defaults["excellon_toolchangexy"],
                 toolchangez=float(self.options["toolchangez"]),
@@ -3754,17 +3806,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.plot_cb.setChecked(True)
         self.ui_connect()
 
-    # def plot_element(self, element, color='red', visible=None, layer=None):
-    #
-    #     visible = visible if visible else self.options['plot']
-    #
-    #     try:
-    #         for sub_el in element:
-    #             self.plot_element(sub_el)
-    #
-    #     except TypeError:  # Element is not iterable...
-    #         self.add_shape(shape=element, color=color, visible=visible, layer=0)
-
     def plot(self, visible=None, kind=None):
 
         # Does all the required setup and returns False
@@ -3819,6 +3860,59 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         except (ObjectDeleted, AttributeError):
             self.shapes.clear(update=True)
 
+    def on_apply_param_to_all_clicked(self):
+        if self.tools_table.rowCount() == 0:
+            # there is no tool in tool table so we can't save the GUI elements values to storage
+            log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
+            return
+
+        self.blockSignals(True)
+
+        row = self.tools_table.currentRow()
+        if row < 0:
+            row = 0
+
+        # store all the data associated with the row parameter to the self.tools storage
+        tooldia_item = float(self.tools_table.item(row, 1).text())
+        type_item = self.tools_table.cellWidget(row, 2).currentText()
+        operation_type_item = self.ui.geo_tools_table.cellWidget(row, 4).currentText()
+
+        nccoffset_item = self.ncc_choice_offset_cb.get_value()
+        nccoffset_value_item = float(self.ncc_offset_spinner.get_value())
+
+        # this new dict will hold the actual useful data, another dict that is the value of key 'data'
+        temp_tools = {}
+        temp_dia = {}
+        temp_data = {}
+
+        for tooluid_key, tooluid_value in self.ncc_tools.items():
+            for key, value in tooluid_value.items():
+                if key == 'data':
+                    # update the 'data' section
+                    for data_key in tooluid_value[key].keys():
+                        for form_key, form_value in self.form_fields.items():
+                            if form_key == data_key:
+                                temp_data[data_key] = form_value.get_value()
+                        # make sure we make a copy of the keys not in the form (we may use 'data' keys that are
+                        # updated from self.app.defaults
+                        if data_key not in self.form_fields:
+                            temp_data[data_key] = value[data_key]
+                    temp_dia[key] = deepcopy(temp_data)
+                    temp_data.clear()
+
+                elif key == 'solid_geometry':
+                    temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+                else:
+                    temp_dia[key] = deepcopy(value)
+
+                temp_tools[tooluid_key] = deepcopy(temp_dia)
+
+        self.ncc_tools.clear()
+        self.ncc_tools = deepcopy(temp_tools)
+        temp_tools.clear()
+
+        self.blockSignals(False)
+
 
 class FlatCAMGeometry(FlatCAMObj, Geometry):
     """

+ 22 - 0
FlatCAMTool.py

@@ -11,6 +11,14 @@ from PyQt5.QtCore import Qt
 
 from shapely.geometry import Polygon
 
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
+
 
 class FlatCAMTool(QtWidgets.QWidget):
 
@@ -138,3 +146,17 @@ class FlatCAMTool(QtWidgets.QWidget):
     def delete_tool_selection_shape(self):
         self.app.tool_shapes.clear()
         self.app.tool_shapes.redraw()
+
+    def confirmation_message(self, accepted, minval, maxval):
+        if accepted is False:
+            self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
+                                 (_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
+        else:
+            self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
+
+    def confirmation_message_int(self, accepted, minval, maxval):
+        if accepted is False:
+            self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
+                                 (_("Edited value is out of range"), minval, maxval))
+        else:
+            self.app.inform.emit('[success] %s' % _("Edited value is within limits."))

+ 7 - 0
README.md

@@ -9,6 +9,13 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+17.02.2020
+
+- updated the Excellon UI to hold data for each tool
+- in Excellon UI removed the tools table column for Offset Z and used the UI form parameter
+- updated the Excellon Editor to add for each tool a 'data' dictionary
+- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
+
 16.02.2020
 
 - small update to NCC Tool UI

+ 4 - 5
camlib.py

@@ -2432,7 +2432,6 @@ class CNCjob(Geometry):
         self.units = units
 
         self.z_cut = z_cut
-        self.tool_offset = dict()
 
         self.z_move = z_move
 
@@ -2728,7 +2727,7 @@ class CNCjob(Geometry):
                             )
 
                     try:
-                        z_off = float(self.tool_offset[it[1]]) * (-1)
+                        z_off = float(exobj.tools[it[0]]['data']['offset']) * (-1)
                     except KeyError:
                         z_off = 0
 
@@ -2936,7 +2935,7 @@ class CNCjob(Geometry):
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # because the values for Z offset are created in build_ui()
                             try:
-                                z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+                                z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
                             except KeyError:
                                 z_offset = 0
                             self.z_cut = z_offset + old_zcut
@@ -3104,7 +3103,7 @@ class CNCjob(Geometry):
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # because the values for Z offset are created in build_ui()
                             try:
-                                z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+                                z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
                             except KeyError:
                                 z_offset = 0
                             self.z_cut = z_offset + old_zcut
@@ -3230,7 +3229,7 @@ class CNCjob(Geometry):
                         # TODO apply offset only when using the GUI, for TclCommand this will create an error
                         # because the values for Z offset are created in build_ui()
                         try:
-                            z_offset = float(self.tool_offset[current_tooldia]) * (-1)
+                            z_offset = float(exobj.tools[tool]['data']['offset']) * (-1)
                         except KeyError:
                             z_offset = 0
                         self.z_cut = z_offset + old_zcut

+ 45 - 9
flatcamEditors/FlatCAMExcEditor.py

@@ -2074,7 +2074,6 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.new_drills = list()
         self.new_tools = dict()
         self.new_slots = list()
-        self.new_tool_offset = dict()
 
         # dictionary to store the tool_row and diameters in Tool_table
         # it will be updated everytime self.build_ui() is called
@@ -2186,6 +2185,42 @@ class FlatCAMExcEditor(QtCore.QObject):
             if option in self.app.options:
                 self.options[option] = self.app.options[option]
 
+        self.data_defaults = {
+            "plot": self.app.defaults["excellon_plot"],
+            "solid": self.app.defaults["excellon_solid"],
+
+            "operation": self.app.defaults["excellon_operation"],
+            "milling_type": self.app.defaults["excellon_milling_type"],
+
+            "milling_dia":self.app.defaults["excellon_milling_dia"],
+
+            "cutz": self.app.defaults["excellon_cutz"],
+            "multidepth": self.app.defaults["excellon_multidepth"],
+            "depthperpass": self.app.defaults["excellon_depthperpass"],
+            "travelz": self.app.defaults["excellon_travelz"],
+            "feedrate": self.app.defaults["geometry_feedrate"],
+            "feedrate_z": self.app.defaults["excellon_feedrate_z"],
+            "feedrate_rapid": self.app.defaults["excellon_feedrate_rapid"],
+            "tooldia": self.app.defaults["excellon_tooldia"],
+            "slot_tooldia": self.app.defaults["excellon_slot_tooldia"],
+            "toolchange": self.app.defaults["excellon_toolchange"],
+            "toolchangez": self.app.defaults["excellon_toolchangez"],
+            "toolchangexy": self.app.defaults["excellon_toolchangexy"],
+            "extracut": self.app.defaults["geometry_extracut"],
+            "extracut_length": self.app.defaults["geometry_extracut_length"],
+            "endz": self.app.defaults["excellon_endz"],
+            "startz": self.app.defaults["excellon_startz"],
+            "offset": self.app.defaults["excellon_offset"],
+            "spindlespeed": self.app.defaults["excellon_spindlespeed"],
+            "dwell": self.app.defaults["excellon_dwell"],
+            "dwelltime": self.app.defaults["excellon_dwelltime"],
+            "ppname_e": self.app.defaults["excellon_ppname_e"],
+            "ppname_g": self.app.defaults["geometry_ppname_g"],
+            "z_pdepth": self.app.defaults["excellon_z_pdepth"],
+            "feedrate_probe": self.app.defaults["excellon_feedrate_probe"],
+            "optimization_type": self.app.defaults["excellon_optimization_type"]
+        }
+
         self.rtree_exc_index = rtindex.Index()
         # flag to show if the object was modified
         self.is_modified = False
@@ -2592,9 +2627,6 @@ class FlatCAMExcEditor(QtCore.QObject):
 
         for deleted_tool_dia in deleted_tool_dia_list:
 
-            # delete de tool offset
-            self.exc_obj.tool_offset.pop(float(deleted_tool_dia), None)
-
             # delete the storage used for that tool
             storage_elem = FlatCAMGeoEditor.make_storage()
             self.storage_dict[deleted_tool_dia] = storage_elem
@@ -2795,7 +2827,7 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.new_drills = []
         self.new_tools = {}
         self.new_slots = []
-        self.new_tool_offset = {}
+
         self.olddia_newdia = {}
 
         self.shapes.enabled = True
@@ -3036,8 +3068,8 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.exc_obj = exc_obj
         exc_obj.visible = False
 
-        self.points_edit = {}
-        self.slot_points_edit = {}
+        self.points_edit = dict()
+        self.slot_points_edit = dict()
 
         # Set selection tolerance
         # DrawToolShape.tolerance = fc_excellon.drawing_tolerance * 10
@@ -3268,7 +3300,6 @@ class FlatCAMExcEditor(QtCore.QObject):
                     self.edited_obj_name += "_1"
             else:
                 self.edited_obj_name += "_edit"
-        self.new_tool_offset = self.exc_obj.tool_offset
 
         self.app.worker_task.emit({'fcn': self.new_edited_excellon,
                                    'params': [self.edited_obj_name,
@@ -3316,9 +3347,14 @@ class FlatCAMExcEditor(QtCore.QObject):
             excellon_obj.drills = deepcopy(new_drills)
             excellon_obj.tools = deepcopy(new_tools)
             excellon_obj.slots = deepcopy(new_slots)
-            excellon_obj.tool_offset = self.new_tool_offset
+
             excellon_obj.options['name'] = outname
 
+            # add a 'data' dict for each tool with the default values
+            for tool in excellon_obj.tools:
+                excellon_obj.tools[tool]['data'] = dict()
+                excellon_obj.tools[tool]['data'].update(deepcopy(self.data_defaults))
+
             try:
                 excellon_obj.create_geometry()
             except KeyError:

+ 106 - 74
flatcamGUI/ObjectUI.py

@@ -779,7 +779,7 @@ class ExcellonObjectUI(ObjectUI):
 
         self.tools_table.setColumnCount(6)
         self.tools_table.setHorizontalHeaderLabels(['#', _('Diameter'), _('Drills'), _('Slots'),
-                                                    _('Offset Z'), 'P'])
+                                                    "NOT USED", 'P'])
         self.tools_table.setSortingEnabled(False)
 
         self.tools_table.horizontalHeaderItem(0).setToolTip(
@@ -796,14 +796,13 @@ class ExcellonObjectUI(ObjectUI):
         self.tools_table.horizontalHeaderItem(3).setToolTip(
             _("The number of Slot holes. Holes that are created by\n"
               "milling them with an endmill bit."))
-        self.tools_table.horizontalHeaderItem(4).setToolTip(
-            _("Some drill bits (the larger ones) need to drill deeper\n"
-              "to create the desired exit hole diameter due of the tip shape.\n"
-              "The value here can compensate the Cut Z parameter."))
         self.tools_table.horizontalHeaderItem(5).setToolTip(
             _("Toggle display of the drills for the current tool.\n"
               "This does not select the tools for G-code generation."))
 
+        # this column is not used; reserved for future usage
+        self.tools_table.setColumnHidden(4, True)
+
         self.tools_box.addWidget(QtWidgets.QLabel(''))
 
         # ###########################################################
@@ -855,6 +854,7 @@ class ExcellonObjectUI(ObjectUI):
                 {'label': _("Milling"), 'value': 'mill'}
             ]
         )
+        self.operation_radio.setObjectName("e_operation")
 
         self.grid3.addWidget(self.operation_label, 0, 0)
         self.grid3.addWidget(self.operation_radio, 0, 1)
@@ -871,16 +871,17 @@ class ExcellonObjectUI(ObjectUI):
               "- Slots -> will mill the slots associated with this tool\n"
               "- Both -> will mill both drills and mills or whatever is available")
         )
-        self.mill_type_radio = RadioSet(
+        self.milling_type_radio = RadioSet(
             [
                 {'label': _('Drills'), 'value': 'drills'},
                 {'label': _("Slots"), 'value': 'slots'},
                 {'label': _("Both"), 'value': 'both'},
             ]
         )
+        self.milling_type_radio.setObjectName("e_milling_type")
 
         self.grid3.addWidget(self.mill_type_label, 2, 0)
-        self.grid3.addWidget(self.mill_type_radio, 2, 1)
+        self.grid3.addWidget(self.milling_type_radio, 2, 1)
 
         self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
         self.mill_dia_label.setToolTip(
@@ -890,6 +891,7 @@ class ExcellonObjectUI(ObjectUI):
         self.mill_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.mill_dia_entry.set_precision(self.decimals)
         self.mill_dia_entry.set_range(0.0000, 9999.9999)
+        self.mill_dia_entry.setObjectName("e_milling_dia")
 
         self.grid3.addWidget(self.mill_dia_label, 3, 0)
         self.grid3.addWidget(self.mill_dia_entry, 3, 1)
@@ -910,6 +912,7 @@ class ExcellonObjectUI(ObjectUI):
             self.cutz_entry.set_range(-9999.9999, 9999.9999)
 
         self.cutz_entry.setSingleStep(0.1)
+        self.cutz_entry.setObjectName("e_cutz")
 
         self.grid3.addWidget(self.cutzlabel, 4, 0)
         self.grid3.addWidget(self.cutz_entry, 4, 1)
@@ -924,6 +927,7 @@ class ExcellonObjectUI(ObjectUI):
                 "reached."
             )
         )
+        self.mpass_cb.setObjectName("e_multidepth")
 
         self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.maxdepth_entry.set_precision(self.decimals)
@@ -931,6 +935,8 @@ class ExcellonObjectUI(ObjectUI):
         self.maxdepth_entry.setSingleStep(0.1)
 
         self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
+        self.maxdepth_entry.setObjectName("e_depthperpass")
+
         self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
 
         self.grid3.addWidget(self.mpass_cb, 5, 0)
@@ -952,6 +958,7 @@ class ExcellonObjectUI(ObjectUI):
             self.travelz_entry.set_range(-9999.9999, 9999.9999)
 
         self.travelz_entry.setSingleStep(0.1)
+        self.travelz_entry.setObjectName("e_travelz")
 
         self.grid3.addWidget(self.travelzlabel, 6, 0)
         self.grid3.addWidget(self.travelz_entry, 6, 1)
@@ -966,6 +973,7 @@ class ExcellonObjectUI(ObjectUI):
         self.xyfeedrate_entry.set_precision(self.decimals)
         self.xyfeedrate_entry.set_range(0, 9999.9999)
         self.xyfeedrate_entry.setSingleStep(0.1)
+        self.xyfeedrate_entry.setObjectName("e_feedratexy")
 
         self.grid3.addWidget(self.frxylabel, 12, 0)
         self.grid3.addWidget(self.xyfeedrate_entry, 12, 1)
@@ -982,6 +990,7 @@ class ExcellonObjectUI(ObjectUI):
         self.feedrate_z_entry.set_precision(self.decimals)
         self.feedrate_z_entry.set_range(0.0, 99999.9999)
         self.feedrate_z_entry.setSingleStep(0.1)
+        self.feedrate_z_entry.setObjectName("e_feedratez")
 
         self.grid3.addWidget(self.frzlabel, 14, 0)
         self.grid3.addWidget(self.feedrate_z_entry, 14, 1)
@@ -999,6 +1008,7 @@ class ExcellonObjectUI(ObjectUI):
         self.feedrate_rapid_entry.set_precision(self.decimals)
         self.feedrate_rapid_entry.set_range(0.0, 99999.9999)
         self.feedrate_rapid_entry.setSingleStep(0.1)
+        self.feedrate_rapid_entry.setObjectName("e_fr_rapid")
 
         self.grid3.addWidget(self.feedrate_rapid_label, 16, 0)
         self.grid3.addWidget(self.feedrate_rapid_entry, 16, 1)
@@ -1015,6 +1025,7 @@ class ExcellonObjectUI(ObjectUI):
               "meet with last cut, we generate an\n"
               "extended cut over the first cut section.")
         )
+        self.extracut_cb.setObjectName("e_extracut")
 
         self.e_cut_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.e_cut_entry.set_range(0, 99999)
@@ -1027,6 +1038,7 @@ class ExcellonObjectUI(ObjectUI):
               "meet with last cut, we generate an\n"
               "extended cut over the first cut section.")
         )
+        self.e_cut_entry.setObjectName("e_extracut_length")
 
         self.ois_recut = OptionalInputSection(self.extracut_cb, [self.e_cut_entry])
 
@@ -1043,6 +1055,7 @@ class ExcellonObjectUI(ObjectUI):
         self.spindlespeed_entry = FCSpinner(callback=self.confirmation_message_int)
         self.spindlespeed_entry.set_range(0, 1000000)
         self.spindlespeed_entry.setSingleStep(100)
+        self.spindlespeed_entry.setObjectName("e_spindlespeed")
 
         self.grid3.addWidget(self.spindle_label, 19, 0)
         self.grid3.addWidget(self.spindlespeed_entry, 19, 1)
@@ -1053,6 +1066,8 @@ class ExcellonObjectUI(ObjectUI):
             _("Pause to allow the spindle to reach its\n"
               "speed before cutting.")
         )
+        self.dwell_cb.setObjectName("e_dwell")
+
         self.dwelltime_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dwelltime_entry.set_precision(self.decimals)
         self.dwelltime_entry.set_range(0.0, 9999.9999)
@@ -1061,47 +1076,13 @@ class ExcellonObjectUI(ObjectUI):
         self.dwelltime_entry.setToolTip(
             _("Number of time units for spindle to dwell.")
         )
+        self.dwelltime_entry.setObjectName("e_dwelltime")
 
         self.grid3.addWidget(self.dwell_cb, 20, 0)
         self.grid3.addWidget(self.dwelltime_entry, 20, 1)
 
         self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
 
-        # Probe depth
-        self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
-        self.pdepth_label.setToolTip(
-            _("The maximum depth that the probe is allowed\n"
-              "to probe. Negative value, in current units.")
-        )
-
-        self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
-        self.pdepth_entry.set_precision(self.decimals)
-        self.pdepth_entry.set_range(-9999.9999, 9999.9999)
-        self.pdepth_entry.setSingleStep(0.1)
-
-        self.grid3.addWidget(self.pdepth_label, 22, 0)
-        self.grid3.addWidget(self.pdepth_entry, 22, 1)
-
-        self.pdepth_label.hide()
-        self.pdepth_entry.setVisible(False)
-
-        # Probe feedrate
-        self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
-        self.feedrate_probe_label.setToolTip(
-            _("The feedrate used while the probe is probing.")
-        )
-
-        self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
-        self.feedrate_probe_entry.set_precision(self.decimals)
-        self.feedrate_probe_entry.set_range(0.0, 9999.9999)
-        self.feedrate_probe_entry.setSingleStep(0.1)
-
-        self.grid3.addWidget(self.feedrate_probe_label, 24, 0)
-        self.grid3.addWidget(self.feedrate_probe_entry, 24, 1)
-
-        self.feedrate_probe_label.hide()
-        self.feedrate_probe_entry.setVisible(False)
-
         # Tool Offset
         self.tool_offset_label = QtWidgets.QLabel('%s:' % _('Offset Z'))
         self.tool_offset_label.setToolTip(
@@ -1113,6 +1094,7 @@ class ExcellonObjectUI(ObjectUI):
         self.offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.offset_entry.set_precision(self.decimals)
         self.offset_entry.set_range(-9999.9999, 9999.9999)
+        self.offset_entry.setObjectName("e_offset")
 
         self.grid3.addWidget(self.tool_offset_label, 25, 0)
         self.grid3.addWidget(self.offset_entry, 25, 1)
@@ -1121,37 +1103,38 @@ class ExcellonObjectUI(ObjectUI):
         # ################# GRID LAYOUT 4   ###############################
         # #################################################################
 
-        self.grid4 = QtWidgets.QGridLayout()
-        self.exc_tools_box.addLayout(self.grid4)
-        self.grid4.setColumnStretch(0, 0)
-        self.grid4.setColumnStretch(1, 1)
-
-        # choose_tools_label = QtWidgets.QLabel(
-        #     _("Select from the Tools Table above the hole dias to be\n"
-        #       "drilled. Use the # column to make the selection.")
+        # self.grid4 = QtWidgets.QGridLayout()
+        # self.exc_tools_box.addLayout(self.grid4)
+        # self.grid4.setColumnStretch(0, 0)
+        # self.grid4.setColumnStretch(1, 1)
+        #
+        # # choose_tools_label = QtWidgets.QLabel(
+        # #     _("Select from the Tools Table above the hole dias to be\n"
+        # #       "drilled. Use the # column to make the selection.")
+        # # )
+        # # grid2.addWidget(choose_tools_label, 0, 0, 1, 3)
+        #
+        # # ### Choose what to use for Gcode creation: Drills, Slots or Both
+        # gcode_type_label = QtWidgets.QLabel('<b>%s</b>' % _('Gcode'))
+        # gcode_type_label.setToolTip(
+        #     _("Choose what to use for GCode generation:\n"
+        #       "'Drills', 'Slots' or 'Both'.\n"
+        #       "When choosing 'Slots' or 'Both', slots will be\n"
+        #       "converted to a series of drills.")
         # )
-        # grid2.addWidget(choose_tools_label, 0, 0, 1, 3)
-
-        # ### Choose what to use for Gcode creation: Drills, Slots or Both
-        gcode_type_label = QtWidgets.QLabel('<b>%s</b>' % _('Gcode'))
-        gcode_type_label.setToolTip(
-            _("Choose what to use for GCode generation:\n"
-              "'Drills', 'Slots' or 'Both'.\n"
-              "When choosing 'Slots' or 'Both', slots will be\n"
-              "converted to a series of drills.")
-        )
-        self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
-                                                   {'label': 'Slots', 'value': 'slots'},
-                                                   {'label': 'Both', 'value': 'both'}])
-        self.grid4.addWidget(gcode_type_label, 1, 0)
-        self.grid4.addWidget(self.excellon_gcode_type_radio, 1, 1)
-        # temporary action until I finish the feature
-        self.excellon_gcode_type_radio.setVisible(False)
-        gcode_type_label.hide()
+        # self.excellon_gcode_type_radio = RadioSet([{'label': 'Drills', 'value': 'drills'},
+        #                                            {'label': 'Slots', 'value': 'slots'},
+        #                                            {'label': 'Both', 'value': 'both'}])
+        # self.grid4.addWidget(gcode_type_label, 1, 0)
+        # self.grid4.addWidget(self.excellon_gcode_type_radio, 1, 1)
+        # # temporary action until I finish the feature
+        # self.excellon_gcode_type_radio.setVisible(False)
+        # gcode_type_label.hide()
 
         # #################################################################
         # ################# GRID LAYOUT 5   ###############################
         # #################################################################
+        # ################# COMMON PARAMETERS #############################
 
         self.grid5 = QtWidgets.QGridLayout()
         self.grid5.setColumnStretch(0, 0)
@@ -1236,21 +1219,70 @@ class ExcellonObjectUI(ObjectUI):
         self.grid5.addWidget(self.endz_label, 11, 0)
         self.grid5.addWidget(self.endz_entry, 11, 1)
 
-        # Preprocessor selection
-        pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor"))
+        # Probe depth
+        self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
+        self.pdepth_label.setToolTip(
+            _("The maximum depth that the probe is allowed\n"
+              "to probe. Negative value, in current units.")
+        )
+
+        self.pdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
+        self.pdepth_entry.set_precision(self.decimals)
+        self.pdepth_entry.set_range(-9999.9999, 9999.9999)
+        self.pdepth_entry.setSingleStep(0.1)
+
+        self.grid5.addWidget(self.pdepth_label, 12, 0)
+        self.grid5.addWidget(self.pdepth_entry, 12, 1)
+
+        self.pdepth_label.hide()
+        self.pdepth_entry.setVisible(False)
+
+        # Probe feedrate
+        self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
+        self.feedrate_probe_label.setToolTip(
+            _("The feedrate used while the probe is probing.")
+        )
+
+        self.feedrate_probe_entry = FCDoubleSpinner(callback=self.confirmation_message)
+        self.feedrate_probe_entry.set_precision(self.decimals)
+        self.feedrate_probe_entry.set_range(0.0, 9999.9999)
+        self.feedrate_probe_entry.setSingleStep(0.1)
+        self.feedrate_probe_entry.setObjectName(_("e_fr_probe"))
+
+        self.grid5.addWidget(self.feedrate_probe_label, 13, 0)
+        self.grid5.addWidget(self.feedrate_probe_entry, 13, 1)
+
+        self.feedrate_probe_label.hide()
+        self.feedrate_probe_entry.setVisible(False)
+
+        # Preprocessor Excellon selection
+        pp_excellon_label = QtWidgets.QLabel('%s:' % _("Preprocessor E"))
         pp_excellon_label.setToolTip(
             _("The preprocessor JSON file that dictates\n"
-              "Gcode output.")
+              "Gcode output for Excellon Objects.")
         )
         self.pp_excellon_name_cb = FCComboBox()
         self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
-        self.grid5.addWidget(pp_excellon_label, 12, 0)
-        self.grid5.addWidget(self.pp_excellon_name_cb, 12, 1)
+
+        self.grid5.addWidget(pp_excellon_label, 14, 0)
+        self.grid5.addWidget(self.pp_excellon_name_cb, 14, 1)
+
+        # Preprocessor Geometry selection
+        pp_geo_label = QtWidgets.QLabel('%s:' % _("Preprocessor G"))
+        pp_geo_label.setToolTip(
+            _("The preprocessor JSON file that dictates\n"
+              "Gcode output for Geometry (Milling) Objects.")
+        )
+        self.pp_geo_name_cb = FCComboBox()
+        self.pp_geo_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
+
+        self.grid5.addWidget(pp_geo_label, 15, 0)
+        self.grid5.addWidget(self.pp_geo_name_cb, 15, 1)
 
         separator_line = QtWidgets.QFrame()
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        self.grid5.addWidget(separator_line, 13, 0, 1, 2)
+        self.grid5.addWidget(separator_line, 16, 0, 1, 2)
 
         # #################################################################
         # ################# GRID LAYOUT 6   ###############################

+ 60 - 13
flatcamGUI/PreferencesUI.py

@@ -3079,6 +3079,53 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         grid2.setColumnStretch(0, 0)
         grid2.setColumnStretch(1, 1)
 
+        # Operation Type
+        self.operation_label = QtWidgets.QLabel('<b>%s:</b>' % _('Operation'))
+        self.operation_label.setToolTip(
+            _("Operation type:\n"
+              "- Drilling -> will drill the drills/slots associated with this tool\n"
+              "- Milling -> will mill the drills/slots")
+        )
+        self.operation_radio = RadioSet(
+            [
+                {'label': _('Drilling'), 'value': 'drill'},
+                {'label': _("Milling"), 'value': 'mill'}
+            ]
+        )
+
+        grid2.addWidget(self.operation_label, 0, 0)
+        grid2.addWidget(self.operation_radio, 0, 1)
+
+        self.mill_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
+        self.mill_type_label.setToolTip(
+            _("Milling type:\n"
+              "- Drills -> will mill the drills associated with this tool\n"
+              "- Slots -> will mill the slots associated with this tool\n"
+              "- Both -> will mill both drills and mills or whatever is available")
+        )
+        self.milling_type_radio = RadioSet(
+            [
+                {'label': _('Drills'), 'value': 'drills'},
+                {'label': _("Slots"), 'value': 'slots'},
+                {'label': _("Both"), 'value': 'both'},
+            ]
+        )
+
+        grid2.addWidget(self.mill_type_label, 1, 0)
+        grid2.addWidget(self.milling_type_radio, 1, 1)
+
+        self.mill_dia_label = QtWidgets.QLabel('%s:' % _('Milling Diameter'))
+        self.mill_dia_label.setToolTip(
+            _("The diameter of the tool who will do the milling")
+        )
+
+        self.mill_dia_entry = FCDoubleSpinner()
+        self.mill_dia_entry.set_precision(self.decimals)
+        self.mill_dia_entry.set_range(0.0000, 9999.9999)
+
+        grid2.addWidget(self.mill_dia_label, 2, 0)
+        grid2.addWidget(self.mill_dia_entry, 2, 1)
+
         # Cut Z
         cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
         cutzlabel.setToolTip(
@@ -3096,8 +3143,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.cutz_entry.setSingleStep(0.1)
         self.cutz_entry.set_precision(self.decimals)
 
-        grid2.addWidget(cutzlabel, 0, 0)
-        grid2.addWidget(self.cutz_entry, 0, 1)
+        grid2.addWidget(cutzlabel, 3, 0)
+        grid2.addWidget(self.cutz_entry, 3, 1)
 
         # Multi-Depth
         self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
@@ -3117,8 +3164,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
 
         self.maxdepth_entry.setToolTip(_("Depth of each pass (positive)."))
 
-        grid2.addWidget(self.mpass_cb, 1, 0)
-        grid2.addWidget(self.maxdepth_entry, 1, 1)
+        grid2.addWidget(self.mpass_cb, 4, 0)
+        grid2.addWidget(self.maxdepth_entry, 4, 1)
 
         # Travel Z
         travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
@@ -3135,8 +3182,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         else:
             self.travelz_entry.set_range(-9999.9999, 9999.9999)
 
-        grid2.addWidget(travelzlabel, 2, 0)
-        grid2.addWidget(self.travelz_entry, 2, 1)
+        grid2.addWidget(travelzlabel, 5, 0)
+        grid2.addWidget(self.travelz_entry, 5, 1)
 
         # Tool change:
         self.toolchange_cb = FCCheckBox('%s' % _("Tool change"))
@@ -3144,7 +3191,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
             _("Include tool-change sequence\n"
               "in G-Code (Pause for tool change).")
         )
-        grid2.addWidget(self.toolchange_cb, 3, 0, 1, 2)
+        grid2.addWidget(self.toolchange_cb, 6, 0, 1, 2)
 
         # Tool Change Z
         toolchangezlabel = QtWidgets.QLabel('%s:' % _('Toolchange Z'))
@@ -3161,8 +3208,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         else:
             self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
 
-        grid2.addWidget(toolchangezlabel, 4, 0)
-        grid2.addWidget(self.toolchangez_entry, 4, 1)
+        grid2.addWidget(toolchangezlabel, 7, 0)
+        grid2.addWidget(self.toolchangez_entry, 7, 1)
 
         # End Move Z
         endz_label = QtWidgets.QLabel('%s:' % _('End move Z'))
@@ -3178,8 +3225,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         else:
             self.endz_entry.set_range(-9999.9999, 9999.9999)
 
-        grid2.addWidget(endz_label, 5, 0)
-        grid2.addWidget(self.endz_entry, 5, 1)
+        grid2.addWidget(endz_label, 8, 0)
+        grid2.addWidget(self.endz_entry, 8, 1)
 
         # Feedrate Z
         frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
@@ -3193,8 +3240,8 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.feedrate_z_entry.set_precision(self.decimals)
         self.feedrate_z_entry.set_range(0, 99999.9999)
 
-        grid2.addWidget(frlabel, 6, 0)
-        grid2.addWidget(self.feedrate_z_entry, 6, 1)
+        grid2.addWidget(frlabel, 9, 0)
+        grid2.addWidget(self.feedrate_z_entry, 9, 1)
 
         # Spindle speed
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))

+ 1 - 0
flatcamParsers/ParseExcellon.py

@@ -43,6 +43,7 @@ class Excellon(Geometry):
     ================  ====================================
     C                 Diameter of the tool
     solid_geometry    Geometry list for each tool
+    data              dictionary which holds the options for each tool
     Others            Not supported (Ignored).
     ================  ====================================
 

+ 9 - 9
flatcamTools/ToolCalculators.py

@@ -92,7 +92,7 @@ class ToolCalculator(FlatCAMTool):
         self.layout.addLayout(form_layout)
 
         self.tipDia_label = QtWidgets.QLabel('%s:' % _("Tip Diameter"))
-        self.tipDia_entry = FCDoubleSpinner()
+        self.tipDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.tipDia_entry.set_precision(self.decimals)
         self.tipDia_entry.set_range(0.0, 9999.9999)
         self.tipDia_entry.setSingleStep(0.1)
@@ -112,7 +112,7 @@ class ToolCalculator(FlatCAMTool):
                                          "It is specified by manufacturer."))
 
         self.cutDepth_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
-        self.cutDepth_entry = FCDoubleSpinner()
+        self.cutDepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cutDepth_entry.set_range(-9999.9999, 9999.9999)
         self.cutDepth_entry.set_precision(self.decimals)
 
@@ -121,7 +121,7 @@ class ToolCalculator(FlatCAMTool):
                                          "In the CNCJob is the CutZ parameter."))
 
         self.effectiveToolDia_label = QtWidgets.QLabel('%s:' % _("Tool Diameter"))
-        self.effectiveToolDia_entry = FCDoubleSpinner()
+        self.effectiveToolDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.effectiveToolDia_entry.set_precision(self.decimals)
 
         # self.effectiveToolDia_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
@@ -165,7 +165,7 @@ class ToolCalculator(FlatCAMTool):
         self.layout.addLayout(plate_form_layout)
 
         self.pcblengthlabel = QtWidgets.QLabel('%s:' % _("Board Length"))
-        self.pcblength_entry = FCDoubleSpinner()
+        self.pcblength_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.pcblength_entry.set_precision(self.decimals)
         self.pcblength_entry.set_range(0.0, 9999.9999)
 
@@ -173,7 +173,7 @@ class ToolCalculator(FlatCAMTool):
         self.pcblengthlabel.setToolTip(_('This is the board length. In centimeters.'))
 
         self.pcbwidthlabel = QtWidgets.QLabel('%s:' % _("Board Width"))
-        self.pcbwidth_entry = FCDoubleSpinner()
+        self.pcbwidth_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.pcbwidth_entry.set_precision(self.decimals)
         self.pcbwidth_entry.set_range(0.0, 9999.9999)
 
@@ -181,7 +181,7 @@ class ToolCalculator(FlatCAMTool):
         self.pcbwidthlabel.setToolTip(_('This is the board width.In centimeters.'))
 
         self.cdensity_label = QtWidgets.QLabel('%s:' % _("Current Density"))
-        self.cdensity_entry = FCDoubleSpinner()
+        self.cdensity_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cdensity_entry.set_precision(self.decimals)
         self.cdensity_entry.set_range(0.0, 9999.9999)
         self.cdensity_entry.setSingleStep(0.1)
@@ -191,7 +191,7 @@ class ToolCalculator(FlatCAMTool):
                                          "In Amps per Square Feet ASF."))
 
         self.growth_label = QtWidgets.QLabel('%s:' % _("Copper Growth"))
-        self.growth_entry = FCDoubleSpinner()
+        self.growth_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.growth_entry.set_precision(self.decimals)
         self.growth_entry.set_range(0.0, 9999.9999)
         self.growth_entry.setSingleStep(0.01)
@@ -203,7 +203,7 @@ class ToolCalculator(FlatCAMTool):
         # self.growth_entry.setEnabled(False)
 
         self.cvaluelabel = QtWidgets.QLabel('%s:' % _("Current Value"))
-        self.cvalue_entry = FCDoubleSpinner()
+        self.cvalue_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cvalue_entry.set_precision(self.decimals)
         self.cvalue_entry.set_range(0.0, 9999.9999)
         self.cvalue_entry.setSingleStep(0.1)
@@ -214,7 +214,7 @@ class ToolCalculator(FlatCAMTool):
         self.cvalue_entry.setReadOnly(True)
 
         self.timelabel = QtWidgets.QLabel('%s:' % _("Time"))
-        self.time_entry = FCDoubleSpinner()
+        self.time_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.time_entry.set_precision(self.decimals)
         self.time_entry.set_range(0.0, 9999.9999)
         self.time_entry.setSingleStep(0.1)

+ 11 - 11
flatcamTools/ToolCalibration.py

@@ -76,7 +76,7 @@ class ToolCalibration(FlatCAMTool):
             _("Height (Z) for travelling between the points.")
         )
 
-        self.travelz_entry = FCDoubleSpinner()
+        self.travelz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.travelz_entry.set_range(-9999.9999, 9999.9999)
         self.travelz_entry.set_precision(self.decimals)
         self.travelz_entry.setSingleStep(0.1)
@@ -90,7 +90,7 @@ class ToolCalibration(FlatCAMTool):
             _("Height (Z) for checking the point.")
         )
 
-        self.verz_entry = FCDoubleSpinner()
+        self.verz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.verz_entry.set_range(-9999.9999, 9999.9999)
         self.verz_entry.set_precision(self.decimals)
         self.verz_entry.setSingleStep(0.1)
@@ -113,7 +113,7 @@ class ToolCalibration(FlatCAMTool):
             _("Height (Z) for mounting the verification probe.")
         )
 
-        self.toolchangez_entry = FCDoubleSpinner()
+        self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.toolchangez_entry.set_range(0.0000, 9999.9999)
         self.toolchangez_entry.set_precision(self.decimals)
         self.toolchangez_entry.setSingleStep(0.1)
@@ -471,7 +471,7 @@ class ToolCalibration(FlatCAMTool):
         self.scalex_label.setToolTip(
             _("Factor for Scale action over X axis.")
         )
-        self.scalex_entry = FCDoubleSpinner()
+        self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.scalex_entry.set_range(0, 9999.9999)
         self.scalex_entry.set_precision(self.decimals)
         self.scalex_entry.setSingleStep(0.1)
@@ -483,7 +483,7 @@ class ToolCalibration(FlatCAMTool):
         self.scaley_label.setToolTip(
             _("Factor for Scale action over Y axis.")
         )
-        self.scaley_entry = FCDoubleSpinner()
+        self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.scaley_entry.set_range(0, 9999.9999)
         self.scaley_entry.set_precision(self.decimals)
         self.scaley_entry.setSingleStep(0.1)
@@ -508,7 +508,7 @@ class ToolCalibration(FlatCAMTool):
             _("Angle for Skew action, in degrees.\n"
               "Float number between -360 and 359.")
         )
-        self.skewx_entry = FCDoubleSpinner()
+        self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.skewx_entry.set_range(-360, 360)
         self.skewx_entry.set_precision(self.decimals)
         self.skewx_entry.setSingleStep(0.1)
@@ -521,7 +521,7 @@ class ToolCalibration(FlatCAMTool):
             _("Angle for Skew action, in degrees.\n"
               "Float number between -360 and 359.")
         )
-        self.skewy_entry = FCDoubleSpinner()
+        self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.skewy_entry.set_range(-360, 360)
         self.skewy_entry.set_precision(self.decimals)
         self.skewy_entry.setSingleStep(0.1)
@@ -552,7 +552,7 @@ class ToolCalibration(FlatCAMTool):
         # self.fin_scalex_label.setToolTip(
         #     _("Final factor for Scale action over X axis.")
         # )
-        # self.fin_scalex_entry = FCDoubleSpinner()
+        # self.fin_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.fin_scalex_entry.set_range(0, 9999.9999)
         # self.fin_scalex_entry.set_precision(self.decimals)
         # self.fin_scalex_entry.setSingleStep(0.1)
@@ -564,7 +564,7 @@ class ToolCalibration(FlatCAMTool):
         # self.fin_scaley_label.setToolTip(
         #     _("Final factor for Scale action over Y axis.")
         # )
-        # self.fin_scaley_entry = FCDoubleSpinner()
+        # self.fin_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.fin_scaley_entry.set_range(0, 9999.9999)
         # self.fin_scaley_entry.set_precision(self.decimals)
         # self.fin_scaley_entry.setSingleStep(0.1)
@@ -577,7 +577,7 @@ class ToolCalibration(FlatCAMTool):
         #     _("Final value for angle for Skew action, in degrees.\n"
         #       "Float number between -360 and 359.")
         # )
-        # self.fin_skewx_entry = FCDoubleSpinner()
+        # self.fin_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.fin_skewx_entry.set_range(-360, 360)
         # self.fin_skewx_entry.set_precision(self.decimals)
         # self.fin_skewx_entry.setSingleStep(0.1)
@@ -590,7 +590,7 @@ class ToolCalibration(FlatCAMTool):
         #     _("Final value for angle for Skew action, in degrees.\n"
         #       "Float number between -360 and 359.")
         # )
-        # self.fin_skewy_entry = FCDoubleSpinner()
+        # self.fin_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.fin_skewy_entry.set_range(-360, 360)
         # self.fin_skewy_entry.set_precision(self.decimals)
         # self.fin_skewy_entry.setSingleStep(0.1)

+ 11 - 11
flatcamTools/ToolCopperThieving.py

@@ -99,7 +99,7 @@ class ToolCopperThieving(FlatCAMTool):
               "(the polygon fill may be split in multiple polygons)\n"
               "and the copper traces in the Gerber file.")
         )
-        self.clearance_entry = FCDoubleSpinner()
+        self.clearance_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_entry.set_range(0.00001, 9999.9999)
         self.clearance_entry.set_precision(self.decimals)
         self.clearance_entry.setSingleStep(0.1)
@@ -112,7 +112,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.margin_label.setToolTip(
             _("Bounding box margin.")
         )
-        self.margin_entry = FCDoubleSpinner()
+        self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.margin_entry.set_range(0.0, 9999.9999)
         self.margin_entry.set_precision(self.decimals)
         self.margin_entry.setSingleStep(0.1)
@@ -221,7 +221,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.dotdia_label.setToolTip(
             _("Dot diameter in Dots Grid.")
         )
-        self.dot_dia_entry = FCDoubleSpinner()
+        self.dot_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dot_dia_entry.set_range(0.0, 9999.9999)
         self.dot_dia_entry.set_precision(self.decimals)
         self.dot_dia_entry.setSingleStep(0.1)
@@ -234,7 +234,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.dotspacing_label.setToolTip(
             _("Distance between each two dots in Dots Grid.")
         )
-        self.dot_spacing_entry = FCDoubleSpinner()
+        self.dot_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dot_spacing_entry.set_range(0.0, 9999.9999)
         self.dot_spacing_entry.set_precision(self.decimals)
         self.dot_spacing_entry.setSingleStep(0.1)
@@ -261,7 +261,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.square_size_label.setToolTip(
             _("Square side size in Squares Grid.")
         )
-        self.square_size_entry = FCDoubleSpinner()
+        self.square_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.square_size_entry.set_range(0.0, 9999.9999)
         self.square_size_entry.set_precision(self.decimals)
         self.square_size_entry.setSingleStep(0.1)
@@ -274,7 +274,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.squares_spacing_label.setToolTip(
             _("Distance between each two squares in Squares Grid.")
         )
-        self.squares_spacing_entry = FCDoubleSpinner()
+        self.squares_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.squares_spacing_entry.set_range(0.0, 9999.9999)
         self.squares_spacing_entry.set_precision(self.decimals)
         self.squares_spacing_entry.setSingleStep(0.1)
@@ -301,7 +301,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.line_size_label.setToolTip(
             _("Line thickness size in Lines Grid.")
         )
-        self.line_size_entry = FCDoubleSpinner()
+        self.line_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.line_size_entry.set_range(0.0, 9999.9999)
         self.line_size_entry.set_precision(self.decimals)
         self.line_size_entry.setSingleStep(0.1)
@@ -314,7 +314,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.lines_spacing_label.setToolTip(
             _("Distance between each two lines in Lines Grid.")
         )
-        self.lines_spacing_entry = FCDoubleSpinner()
+        self.lines_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.lines_spacing_entry.set_range(0.0, 9999.9999)
         self.lines_spacing_entry.set_precision(self.decimals)
         self.lines_spacing_entry.setSingleStep(0.1)
@@ -362,7 +362,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.rb_margin_label.setToolTip(
             _("Bounding box margin for robber bar.")
         )
-        self.rb_margin_entry = FCDoubleSpinner()
+        self.rb_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.rb_margin_entry.set_range(-9999.9999, 9999.9999)
         self.rb_margin_entry.set_precision(self.decimals)
         self.rb_margin_entry.setSingleStep(0.1)
@@ -375,7 +375,7 @@ class ToolCopperThieving(FlatCAMTool):
         self.rb_thickness_label.setToolTip(
             _("The robber bar thickness.")
         )
-        self.rb_thickness_entry = FCDoubleSpinner()
+        self.rb_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.rb_thickness_entry.set_range(0.0000, 9999.9999)
         self.rb_thickness_entry.set_precision(self.decimals)
         self.rb_thickness_entry.setSingleStep(0.1)
@@ -431,7 +431,7 @@ class ToolCopperThieving(FlatCAMTool):
             _("The distance between the possible copper thieving elements\n"
               "and/or robber bar and the actual openings in the mask.")
         )
-        self.clearance_ppm_entry = FCDoubleSpinner()
+        self.clearance_ppm_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_ppm_entry.set_range(-9999.9999, 9999.9999)
         self.clearance_ppm_entry.set_precision(self.decimals)
         self.clearance_ppm_entry.setSingleStep(0.1)

+ 5 - 5
flatcamTools/ToolCutOut.py

@@ -123,7 +123,7 @@ class CutOut(FlatCAMTool):
         grid0.addWidget(self.param_label, 6, 0, 1, 2)
 
         # Tool Diameter
-        self.dia = FCDoubleSpinner()
+        self.dia = FCDoubleSpinner(callback=self.confirmation_message)
         self.dia.set_precision(self.decimals)
         self.dia.set_range(0.0000, 9999.9999)
 
@@ -143,7 +143,7 @@ class CutOut(FlatCAMTool):
                 "below the copper surface."
             )
         )
-        self.cutz_entry = FCDoubleSpinner()
+        self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cutz_entry.set_precision(self.decimals)
 
         if machinist_setting == 0:
@@ -167,7 +167,7 @@ class CutOut(FlatCAMTool):
             )
         )
 
-        self.maxdepth_entry = FCDoubleSpinner()
+        self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.maxdepth_entry.set_precision(self.decimals)
         self.maxdepth_entry.setRange(0, 9999.9999)
         self.maxdepth_entry.setSingleStep(0.1)
@@ -183,7 +183,7 @@ class CutOut(FlatCAMTool):
         grid0.addWidget(self.maxdepth_entry, 10, 1)
 
         # Margin
-        self.margin = FCDoubleSpinner()
+        self.margin = FCDoubleSpinner(callback=self.confirmation_message)
         self.margin.set_range(-9999.9999, 9999.9999)
         self.margin.setSingleStep(0.1)
         self.margin.set_precision(self.decimals)
@@ -198,7 +198,7 @@ class CutOut(FlatCAMTool):
         grid0.addWidget(self.margin, 11, 1)
 
         # Gapsize
-        self.gapsize = FCDoubleSpinner()
+        self.gapsize = FCDoubleSpinner(callback=self.confirmation_message)
         self.gapsize.set_precision(self.decimals)
 
         self.gapsize_label = QtWidgets.QLabel('%s:' % _("Gap size"))

+ 5 - 5
flatcamTools/ToolDblSided.py

@@ -254,7 +254,7 @@ class DblSidedTool(FlatCAMTool):
         grid_lay2.addWidget(self.bv_label, 6, 0, 1, 2)
 
         # Xmin value
-        self.xmin_entry = FCDoubleSpinner()
+        self.xmin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.xmin_entry.set_precision(self.decimals)
         self.xmin_entry.set_range(-9999.9999, 9999.9999)
 
@@ -268,7 +268,7 @@ class DblSidedTool(FlatCAMTool):
         grid_lay2.addWidget(self.xmin_entry, 7, 1)
 
         # Ymin value
-        self.ymin_entry = FCDoubleSpinner()
+        self.ymin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.ymin_entry.set_precision(self.decimals)
         self.ymin_entry.set_range(-9999.9999, 9999.9999)
 
@@ -282,7 +282,7 @@ class DblSidedTool(FlatCAMTool):
         grid_lay2.addWidget(self.ymin_entry, 8, 1)
 
         # Xmax value
-        self.xmax_entry = FCDoubleSpinner()
+        self.xmax_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.xmax_entry.set_precision(self.decimals)
         self.xmax_entry.set_range(-9999.9999, 9999.9999)
 
@@ -296,7 +296,7 @@ class DblSidedTool(FlatCAMTool):
         grid_lay2.addWidget(self.xmax_entry, 9, 1)
 
         # Ymax value
-        self.ymax_entry = FCDoubleSpinner()
+        self.ymax_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.ymax_entry.set_precision(self.decimals)
         self.ymax_entry.set_range(-9999.9999, 9999.9999)
 
@@ -359,7 +359,7 @@ class DblSidedTool(FlatCAMTool):
             _("Diameter of the drill for the alignment holes.")
         )
 
-        self.drill_dia = FCDoubleSpinner()
+        self.drill_dia = FCDoubleSpinner(callback=self.confirmation_message)
         self.drill_dia.setToolTip(
             _("Diameter of the drill for the alignment holes.")
         )

+ 6 - 6
flatcamTools/ToolExtractDrills.py

@@ -156,7 +156,7 @@ class ToolExtractDrills(FlatCAMTool):
         grid1.addWidget(self.fixed_label, 6, 0, 1, 2)
 
         # Diameter value
-        self.dia_entry = FCDoubleSpinner()
+        self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dia_entry.set_precision(self.decimals)
         self.dia_entry.set_range(0.0000, 9999.9999)
 
@@ -202,7 +202,7 @@ class ToolExtractDrills(FlatCAMTool):
             _("The size of annular ring for circular pads.")
         )
 
-        self.circular_ring_entry = FCDoubleSpinner()
+        self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.circular_ring_entry.set_precision(self.decimals)
         self.circular_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -215,7 +215,7 @@ class ToolExtractDrills(FlatCAMTool):
             _("The size of annular ring for oblong pads.")
         )
 
-        self.oblong_ring_entry = FCDoubleSpinner()
+        self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.oblong_ring_entry.set_precision(self.decimals)
         self.oblong_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -228,7 +228,7 @@ class ToolExtractDrills(FlatCAMTool):
             _("The size of annular ring for square pads.")
         )
 
-        self.square_ring_entry = FCDoubleSpinner()
+        self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.square_ring_entry.set_precision(self.decimals)
         self.square_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -241,7 +241,7 @@ class ToolExtractDrills(FlatCAMTool):
             _("The size of annular ring for rectangular pads.")
         )
 
-        self.rectangular_ring_entry = FCDoubleSpinner()
+        self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.rectangular_ring_entry.set_precision(self.decimals)
         self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -254,7 +254,7 @@ class ToolExtractDrills(FlatCAMTool):
             _("The size of annular ring for other pads.")
         )
 
-        self.other_ring_entry = FCDoubleSpinner()
+        self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.other_ring_entry.set_precision(self.decimals)
         self.other_ring_entry.set_range(0.0000, 9999.9999)
 

+ 3 - 3
flatcamTools/ToolFiducials.py

@@ -159,7 +159,7 @@ class ToolFiducials(FlatCAMTool):
               "otherwise is the size of the fiducial.\n"
               "The soldermask opening is double than that.")
         )
-        self.fid_size_entry = FCDoubleSpinner()
+        self.fid_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.fid_size_entry.set_range(1.0000, 3.0000)
         self.fid_size_entry.set_precision(self.decimals)
         self.fid_size_entry.setWrapping(True)
@@ -173,7 +173,7 @@ class ToolFiducials(FlatCAMTool):
         self.margin_label.setToolTip(
             _("Bounding box margin.")
         )
-        self.margin_entry = FCDoubleSpinner()
+        self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.margin_entry.set_range(-9999.9999, 9999.9999)
         self.margin_entry.set_precision(self.decimals)
         self.margin_entry.setSingleStep(0.1)
@@ -236,7 +236,7 @@ class ToolFiducials(FlatCAMTool):
         self.line_thickness_label.setToolTip(
             _("Bounding box margin.")
         )
-        self.line_thickness_entry = FCDoubleSpinner()
+        self.line_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.line_thickness_entry.set_range(0.00001, 9999.9999)
         self.line_thickness_entry.set_precision(self.decimals)
         self.line_thickness_entry.setSingleStep(0.1)

+ 7 - 7
flatcamTools/ToolFilm.py

@@ -160,7 +160,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_scale_cb, 6, 0, 1, 2)
 
         self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
-        self.film_scalex_entry = FCDoubleSpinner()
+        self.film_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.film_scalex_entry.set_range(-999.9999, 999.9999)
         self.film_scalex_entry.set_precision(self.decimals)
         self.film_scalex_entry.setSingleStep(0.01)
@@ -169,7 +169,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_scalex_entry, 7, 1)
 
         self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
-        self.film_scaley_entry = FCDoubleSpinner()
+        self.film_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.film_scaley_entry.set_range(-999.9999, 999.9999)
         self.film_scaley_entry.set_precision(self.decimals)
         self.film_scaley_entry.setSingleStep(0.01)
@@ -199,7 +199,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
 
         self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
-        self.film_skewx_entry = FCDoubleSpinner()
+        self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.film_skewx_entry.set_range(-999.9999, 999.9999)
         self.film_skewx_entry.set_precision(self.decimals)
         self.film_skewx_entry.setSingleStep(0.01)
@@ -208,7 +208,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_skewx_entry, 11, 1)
 
         self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
-        self.film_skewy_entry = FCDoubleSpinner()
+        self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.film_skewy_entry.set_range(-999.9999, 999.9999)
         self.film_skewy_entry.set_precision(self.decimals)
         self.film_skewy_entry.setSingleStep(0.01)
@@ -275,7 +275,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
 
         # Scale Stroke size
-        self.film_scale_stroke_entry = FCDoubleSpinner()
+        self.film_scale_stroke_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.film_scale_stroke_entry.set_range(-999.9999, 999.9999)
         self.film_scale_stroke_entry.setSingleStep(0.01)
         self.film_scale_stroke_entry.set_precision(self.decimals)
@@ -308,7 +308,7 @@ class Film(FlatCAMTool):
         grid0.addWidget(self.film_type, 21, 1)
 
         # Boundary for negative film generation
-        self.boundary_entry = FCDoubleSpinner()
+        self.boundary_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.boundary_entry.set_range(-999.9999, 999.9999)
         self.boundary_entry.setSingleStep(0.01)
         self.boundary_entry.set_precision(self.decimals)
@@ -378,7 +378,7 @@ class Film(FlatCAMTool):
 
         self.punch_size_label = QtWidgets.QLabel('%s:' % _("Punch Size"))
         self.punch_size_label.setToolTip(_("The value here will control how big is the punch hole in the pads."))
-        self.punch_size_spinner = FCDoubleSpinner()
+        self.punch_size_spinner = FCDoubleSpinner(callback=self.confirmation_message)
         self.punch_size_spinner.set_range(0, 999.9999)
         self.punch_size_spinner.setSingleStep(0.1)
         self.punch_size_spinner.set_precision(self.decimals)

+ 1 - 1
flatcamTools/ToolInvertGerber.py

@@ -89,7 +89,7 @@ class ToolInvertGerber(FlatCAMTool):
             _("Distance by which to avoid\n"
               "the edges of the Gerber object.")
         )
-        self.margin_entry = FCDoubleSpinner()
+        self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.margin_entry.set_precision(self.decimals)
         self.margin_entry.set_range(0.0000, 9999.9999)
         self.margin_entry.setObjectName(_("Margin"))

+ 6 - 6
flatcamTools/ToolNonCopperClear.py

@@ -251,7 +251,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
         self.tipdialabel.setToolTip(
             _("The tip diameter for V-Shape Tool"))
-        self.tipdia_entry = FCDoubleSpinner()
+        self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.tipdia_entry.set_precision(self.decimals)
         self.tipdia_entry.set_range(0.0000, 9999.9999)
         self.tipdia_entry.setSingleStep(0.1)
@@ -265,7 +265,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.tipanglelabel.setToolTip(
             _("The tip angle for V-Shape Tool.\n"
               "In degree."))
-        self.tipangle_entry = FCDoubleSpinner()
+        self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.set_range(0.0000, 180.0000)
         self.tipangle_entry.setSingleStep(5)
@@ -280,7 +280,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
            _("Depth of cut into material. Negative value.\n"
              "In FlatCAM units.")
         )
-        self.cutz_entry = FCDoubleSpinner()
+        self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cutz_entry.set_precision(self.decimals)
         self.cutz_entry.set_range(-99999.9999, 0.0000)
         self.cutz_entry.setObjectName(_("Cut Z"))
@@ -299,7 +299,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "If the tool is V-shape type then this value is automatically\n"
               "calculated from the other parameters.")
         )
-        self.addtool_entry = FCDoubleSpinner()
+        self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.addtool_entry.set_precision(self.decimals)
         self.addtool_entry.set_range(0.000, 9999.9999)
         self.addtool_entry.setObjectName(_("Tool Dia"))
@@ -381,7 +381,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         nccmarginlabel.setToolTip(
             _("Bounding box margin.")
         )
-        self.ncc_margin_entry = FCDoubleSpinner()
+        self.ncc_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.ncc_margin_entry.set_precision(self.decimals)
         self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
         self.ncc_margin_entry.setObjectName(_("Margin"))
@@ -447,7 +447,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         #       "from the copper features.\n"
         #       "The value can be between 0 and 10 FlatCAM units.")
         # )
-        self.ncc_offset_spinner = FCDoubleSpinner()
+        self.ncc_offset_spinner = FCDoubleSpinner(callback=self.confirmation_message)
         self.ncc_offset_spinner.set_range(0.00, 10.00)
         self.ncc_offset_spinner.set_precision(4)
         self.ncc_offset_spinner.setWrapping(True)

+ 5 - 5
flatcamTools/ToolPaint.py

@@ -214,7 +214,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
         self.tipdialabel.setToolTip(
             _("The tip diameter for V-Shape Tool"))
-        self.tipdia_entry = FCDoubleSpinner()
+        self.tipdia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.tipdia_entry.set_precision(self.decimals)
         self.tipdia_entry.set_range(0.0000, 9999.9999)
         self.tipdia_entry.setSingleStep(0.1)
@@ -228,7 +228,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.tipanglelabel.setToolTip(
             _("The tip angle for V-Shape Tool.\n"
               "In degree."))
-        self.tipangle_entry = FCDoubleSpinner()
+        self.tipangle_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.set_range(0.0000, 180.0000)
         self.tipangle_entry.setSingleStep(5)
@@ -243,7 +243,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             _("Depth of cut into material. Negative value.\n"
               "In FlatCAM units.")
         )
-        self.cutz_entry = FCDoubleSpinner()
+        self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.cutz_entry.set_precision(self.decimals)
         self.cutz_entry.set_range(-99999.9999, 0.0000)
         self.cutz_entry.setObjectName(_("Cut Z"))
@@ -262,7 +262,7 @@ class ToolPaint(FlatCAMTool, Gerber):
               "If the tool is V-shape type then this value is automatically\n"
               "calculated from the other parameters.")
         )
-        self.addtool_entry = FCDoubleSpinner()
+        self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.addtool_entry.set_precision(self.decimals)
         self.addtool_entry.set_range(0.000, 9999.9999)
         self.addtool_entry.setObjectName(_("Tool Dia"))
@@ -351,7 +351,7 @@ class ToolPaint(FlatCAMTool, Gerber):
               "the edges of the polygon to\n"
               "be painted.")
         )
-        self.paintmargin_entry = FCDoubleSpinner()
+        self.paintmargin_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.paintmargin_entry.set_precision(self.decimals)
         self.paintmargin_entry.set_range(-9999.9999, 9999.9999)
         self.paintmargin_entry.setObjectName(_("Margin"))

+ 4 - 4
flatcamTools/ToolPanelize.py

@@ -158,7 +158,7 @@ class Panelize(FlatCAMTool):
         form_layout.addRow(panel_data_label)
 
         # Spacing Columns
-        self.spacing_columns = FCDoubleSpinner()
+        self.spacing_columns = FCDoubleSpinner(callback=self.confirmation_message)
         self.spacing_columns.set_range(0, 9999)
         self.spacing_columns.set_precision(4)
 
@@ -170,7 +170,7 @@ class Panelize(FlatCAMTool):
         form_layout.addRow(self.spacing_columns_label, self.spacing_columns)
 
         # Spacing Rows
-        self.spacing_rows = FCDoubleSpinner()
+        self.spacing_rows = FCDoubleSpinner(callback=self.confirmation_message)
         self.spacing_rows.set_range(0, 9999)
         self.spacing_rows.set_precision(4)
 
@@ -225,7 +225,7 @@ class Panelize(FlatCAMTool):
         )
         form_layout.addRow(self.constrain_cb)
 
-        self.x_width_entry = FCDoubleSpinner()
+        self.x_width_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.x_width_entry.set_precision(4)
         self.x_width_entry.set_range(0, 9999)
 
@@ -236,7 +236,7 @@ class Panelize(FlatCAMTool):
         )
         form_layout.addRow(self.x_width_lbl, self.x_width_entry)
 
-        self.y_height_entry = FCDoubleSpinner()
+        self.y_height_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.y_height_entry.set_range(0, 9999)
         self.y_height_entry.set_precision(4)
 

+ 6 - 6
flatcamTools/ToolPunchGerber.py

@@ -183,7 +183,7 @@ class ToolPunchGerber(FlatCAMTool):
         grid0.addWidget(self.fixed_label, 6, 0, 1, 2)
 
         # Diameter value
-        self.dia_entry = FCDoubleSpinner()
+        self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dia_entry.set_precision(self.decimals)
         self.dia_entry.set_range(0.0000, 9999.9999)
 
@@ -229,7 +229,7 @@ class ToolPunchGerber(FlatCAMTool):
             _("The size of annular ring for circular pads.")
         )
 
-        self.circular_ring_entry = FCDoubleSpinner()
+        self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.circular_ring_entry.set_precision(self.decimals)
         self.circular_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -242,7 +242,7 @@ class ToolPunchGerber(FlatCAMTool):
             _("The size of annular ring for oblong pads.")
         )
 
-        self.oblong_ring_entry = FCDoubleSpinner()
+        self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.oblong_ring_entry.set_precision(self.decimals)
         self.oblong_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -255,7 +255,7 @@ class ToolPunchGerber(FlatCAMTool):
             _("The size of annular ring for square pads.")
         )
 
-        self.square_ring_entry = FCDoubleSpinner()
+        self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.square_ring_entry.set_precision(self.decimals)
         self.square_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -268,7 +268,7 @@ class ToolPunchGerber(FlatCAMTool):
             _("The size of annular ring for rectangular pads.")
         )
 
-        self.rectangular_ring_entry = FCDoubleSpinner()
+        self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.rectangular_ring_entry.set_precision(self.decimals)
         self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
 
@@ -281,7 +281,7 @@ class ToolPunchGerber(FlatCAMTool):
             _("The size of annular ring for other pads.")
         )
 
-        self.other_ring_entry = FCDoubleSpinner()
+        self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.other_ring_entry.set_precision(self.decimals)
         self.other_ring_entry.set_range(0.0000, 9999.9999)
 

+ 10 - 10
flatcamTools/ToolRulesCheck.py

@@ -260,7 +260,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.trace_size_cb)
 
         # Trace size value
-        self.trace_size_entry = FCDoubleSpinner()
+        self.trace_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.trace_size_entry.set_range(0.00001, 999.99999)
         self.trace_size_entry.set_precision(self.decimals)
         self.trace_size_entry.setSingleStep(0.1)
@@ -282,7 +282,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_copper2copper_cb)
 
         # Copper2copper clearance value
-        self.clearance_copper2copper_entry = FCDoubleSpinner()
+        self.clearance_copper2copper_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_copper2copper_entry.set_range(0.00001, 999.99999)
         self.clearance_copper2copper_entry.set_precision(self.decimals)
         self.clearance_copper2copper_entry.setSingleStep(0.1)
@@ -305,7 +305,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_copper2ol_cb)
 
         # Copper2outline clearance value
-        self.clearance_copper2ol_entry = FCDoubleSpinner()
+        self.clearance_copper2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_copper2ol_entry.set_range(0.00001, 999.99999)
         self.clearance_copper2ol_entry.set_precision(self.decimals)
         self.clearance_copper2ol_entry.setSingleStep(0.1)
@@ -328,7 +328,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_silk2silk_cb)
 
         # Copper2silkscreen clearance value
-        self.clearance_silk2silk_entry = FCDoubleSpinner()
+        self.clearance_silk2silk_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_silk2silk_entry.set_range(0.00001, 999.99999)
         self.clearance_silk2silk_entry.set_precision(self.decimals)
         self.clearance_silk2silk_entry.setSingleStep(0.1)
@@ -351,7 +351,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_silk2sm_cb)
 
         # Silkscreen2soldermask clearance value
-        self.clearance_silk2sm_entry = FCDoubleSpinner()
+        self.clearance_silk2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_silk2sm_entry.set_range(0.00001, 999.99999)
         self.clearance_silk2sm_entry.set_precision(self.decimals)
         self.clearance_silk2sm_entry.setSingleStep(0.1)
@@ -374,7 +374,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_silk2ol_cb)
 
         # Silk2outline clearance value
-        self.clearance_silk2ol_entry = FCDoubleSpinner()
+        self.clearance_silk2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_silk2ol_entry.set_range(0.00001, 999.99999)
         self.clearance_silk2ol_entry.set_precision(self.decimals)
         self.clearance_silk2ol_entry.setSingleStep(0.1)
@@ -397,7 +397,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_sm2sm_cb)
 
         # Soldermask2soldermask clearance value
-        self.clearance_sm2sm_entry = FCDoubleSpinner()
+        self.clearance_sm2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_sm2sm_entry.set_range(0.00001, 999.99999)
         self.clearance_sm2sm_entry.set_precision(self.decimals)
         self.clearance_sm2sm_entry.setSingleStep(0.1)
@@ -420,7 +420,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.ring_integrity_cb)
 
         # Ring integrity value
-        self.ring_integrity_entry = FCDoubleSpinner()
+        self.ring_integrity_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.ring_integrity_entry.set_range(0.00001, 999.99999)
         self.ring_integrity_entry.set_precision(self.decimals)
         self.ring_integrity_entry.setSingleStep(0.1)
@@ -445,7 +445,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.clearance_d2d_cb)
 
         # Hole2Hole clearance value
-        self.clearance_d2d_entry = FCDoubleSpinner()
+        self.clearance_d2d_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.clearance_d2d_entry.set_range(0.00001, 999.99999)
         self.clearance_d2d_entry.set_precision(self.decimals)
         self.clearance_d2d_entry.setSingleStep(0.1)
@@ -468,7 +468,7 @@ class RulesCheck(FlatCAMTool):
         self.form_layout_1.addRow(self.drill_size_cb)
 
         # Drile holes value
-        self.drill_size_entry = FCDoubleSpinner()
+        self.drill_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.drill_size_entry.set_range(0.00001, 999.99999)
         self.drill_size_entry.set_precision(self.decimals)
         self.drill_size_entry.setSingleStep(0.1)

+ 11 - 11
flatcamTools/ToolSolderPaste.py

@@ -105,7 +105,7 @@ class SolderPaste(FlatCAMTool):
         self.addtool_entry_lbl.setToolTip(
             _("Diameter for the new Nozzle tool to add in the Tool Table")
         )
-        self.addtool_entry = FCDoubleSpinner()
+        self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.addtool_entry.set_range(0.0000001, 9999.9999)
         self.addtool_entry.set_precision(self.decimals)
         self.addtool_entry.setSingleStep(0.1)
@@ -174,7 +174,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_box.addLayout(self.gcode_form_layout)
 
         # Z dispense start
-        self.z_start_entry = FCDoubleSpinner()
+        self.z_start_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.z_start_entry.set_range(0.0000001, 9999.9999)
         self.z_start_entry.set_precision(self.decimals)
         self.z_start_entry.setSingleStep(0.1)
@@ -186,7 +186,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.z_start_label, self.z_start_entry)
 
         # Z dispense
-        self.z_dispense_entry = FCDoubleSpinner()
+        self.z_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.z_dispense_entry.set_range(0.0000001, 9999.9999)
         self.z_dispense_entry.set_precision(self.decimals)
         self.z_dispense_entry.setSingleStep(0.1)
@@ -198,7 +198,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.z_dispense_label, self.z_dispense_entry)
 
         # Z dispense stop
-        self.z_stop_entry = FCDoubleSpinner()
+        self.z_stop_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.z_stop_entry.set_range(0.0000001, 9999.9999)
         self.z_stop_entry.set_precision(self.decimals)
         self.z_stop_entry.setSingleStep(0.1)
@@ -210,7 +210,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.z_stop_label, self.z_stop_entry)
 
         # Z travel
-        self.z_travel_entry = FCDoubleSpinner()
+        self.z_travel_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.z_travel_entry.set_range(0.0000001, 9999.9999)
         self.z_travel_entry.set_precision(self.decimals)
         self.z_travel_entry.setSingleStep(0.1)
@@ -223,7 +223,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.z_travel_label, self.z_travel_entry)
 
         # Z toolchange location
-        self.z_toolchange_entry = FCDoubleSpinner()
+        self.z_toolchange_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.z_toolchange_entry.set_range(0.0000001, 9999.9999)
         self.z_toolchange_entry.set_precision(self.decimals)
         self.z_toolchange_entry.setSingleStep(0.1)
@@ -244,7 +244,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.xy_toolchange_label, self.xy_toolchange_entry)
 
         # Feedrate X-Y
-        self.frxy_entry = FCDoubleSpinner()
+        self.frxy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.frxy_entry.set_range(0.0000, 99999.9999)
         self.frxy_entry.set_precision(self.decimals)
         self.frxy_entry.setSingleStep(0.1)
@@ -256,7 +256,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.frxy_label, self.frxy_entry)
 
         # Feedrate Z
-        self.frz_entry = FCDoubleSpinner()
+        self.frz_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.frz_entry.set_range(0.0000, 99999.9999)
         self.frz_entry.set_precision(self.decimals)
         self.frz_entry.setSingleStep(0.1)
@@ -269,7 +269,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.frz_label, self.frz_entry)
 
         # Feedrate Z Dispense
-        self.frz_dispense_entry = FCDoubleSpinner()
+        self.frz_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.frz_dispense_entry.set_range(0.0000, 99999.9999)
         self.frz_dispense_entry.set_precision(self.decimals)
         self.frz_dispense_entry.setSingleStep(0.1)
@@ -294,7 +294,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.speedfwd_label, self.speedfwd_entry)
 
         # Dwell Forward
-        self.dwellfwd_entry = FCDoubleSpinner()
+        self.dwellfwd_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dwellfwd_entry.set_range(0.0000001, 9999.9999)
         self.dwellfwd_entry.set_precision(self.decimals)
         self.dwellfwd_entry.setSingleStep(0.1)
@@ -318,7 +318,7 @@ class SolderPaste(FlatCAMTool):
         self.gcode_form_layout.addRow(self.speedrev_label, self.speedrev_entry)
 
         # Dwell Reverse
-        self.dwellrev_entry = FCDoubleSpinner()
+        self.dwellrev_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.dwellrev_entry.set_range(0.0000001, 9999.9999)
         self.dwellrev_entry.set_precision(self.decimals)
         self.dwellrev_entry.setSingleStep(0.1)

+ 8 - 8
flatcamTools/ToolTransform.py

@@ -68,7 +68,7 @@ class ToolTransform(FlatCAMTool):
               "Negative numbers for CCW motion.")
         )
 
-        self.rotate_entry = FCDoubleSpinner()
+        self.rotate_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.rotate_entry.set_precision(self.decimals)
         self.rotate_entry.setSingleStep(45)
         self.rotate_entry.setWrapping(True)
@@ -103,7 +103,7 @@ class ToolTransform(FlatCAMTool):
             _("Angle for Skew action, in degrees.\n"
               "Float number between -360 and 360.")
         )
-        self.skewx_entry = FCDoubleSpinner()
+        self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.skewx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.skewx_entry.set_precision(self.decimals)
         self.skewx_entry.set_range(-360, 360)
@@ -125,7 +125,7 @@ class ToolTransform(FlatCAMTool):
             _("Angle for Skew action, in degrees.\n"
               "Float number between -360 and 360.")
         )
-        self.skewy_entry = FCDoubleSpinner()
+        self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.skewy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.skewy_entry.set_precision(self.decimals)
         self.skewy_entry.set_range(-360, 360)
@@ -155,7 +155,7 @@ class ToolTransform(FlatCAMTool):
         self.scalex_label.setToolTip(
             _("Factor for scaling on X axis.")
         )
-        self.scalex_entry = FCDoubleSpinner()
+        self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.scalex_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.scalex_entry.set_precision(self.decimals)
         self.scalex_entry.setMinimum(-1e6)
@@ -176,7 +176,7 @@ class ToolTransform(FlatCAMTool):
         self.scaley_label.setToolTip(
             _("Factor for scaling on Y axis.")
         )
-        self.scaley_entry = FCDoubleSpinner()
+        self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.scaley_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.scaley_entry.set_precision(self.decimals)
         self.scaley_entry.setMinimum(-1e6)
@@ -228,7 +228,7 @@ class ToolTransform(FlatCAMTool):
         self.offx_label.setToolTip(
             _("Distance to offset on X axis. In current units.")
         )
-        self.offx_entry = FCDoubleSpinner()
+        self.offx_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.offx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.offx_entry.set_precision(self.decimals)
         self.offx_entry.setMinimum(-1e6)
@@ -249,7 +249,7 @@ class ToolTransform(FlatCAMTool):
         self.offy_label.setToolTip(
             _("Distance to offset on Y axis. In current units.")
         )
-        self.offy_entry = FCDoubleSpinner()
+        self.offy_entry = FCDoubleSpinner(callback=self.confirmation_message)
         # self.offy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.offy_entry.set_precision(self.decimals)
         self.offy_entry.setMinimum(-1e6)
@@ -353,7 +353,7 @@ class ToolTransform(FlatCAMTool):
               "or decreased with the 'distance'.")
         )
 
-        self.buffer_entry = FCDoubleSpinner()
+        self.buffer_entry = FCDoubleSpinner(callback=self.confirmation_message)
         self.buffer_entry.set_precision(self.decimals)
         self.buffer_entry.setSingleStep(0.1)
         self.buffer_entry.setWrapping(True)

+ 7 - 0
preprocessors/default.py

@@ -37,6 +37,13 @@ class default(FlatCAMPostProc):
         gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
         gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
 
+        if str(p['options']['type']) == 'Excellon':
+            gcode += '\n(Tools Offset: )\n'
+            for tool, val in p['exc_cnc_tools'].items():
+                gcode += '(Tool: %s -> ' % str(val['tool']) + 'Dia: %s -> ' % str(tool) + \
+                         'Offset Z: %s' % str(val['offset_z']) + ')\n'
+            gcode += '\n'
+
         if p['multidepth'] is True:
             gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
                      str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'

+ 1 - 4
tclCommands/TclCommandDrillcncjob.py

@@ -169,7 +169,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
                 else:
                     return "fail"
 
-            drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["drillz"]
+            drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["cutz"]
 
             if "toolchangez" in args:
                 toolchange = True
@@ -229,9 +229,6 @@ class TclCommandDrillcncjob(TclCommandSignaled):
                     float(job_obj.exc_cnc_tools[t_item]['offset_z']) + float(drillz)
                 job_obj.exc_cnc_tools[t_item]['data']['ppname_e'] = obj.options['ppname_e']
 
-                # for now there is no tool offset support in this Tcl Command so we write the 0.0 value here
-                job_obj.tool_offset[t_item] = 0.0
-
             job_obj.origin_kind = 'excellon'
 
             job_obj.gcode_parse()