Parcourir la source

- when multiple tools are selected in Excellon UI and parameters are modified it will applied to all selected
- in Excellon UI, Paint Tool and NCC Tool finished the "Apply parameters to all tools" functionality
- updated Paint Tool and NCC Tool in the UI functionality

Marius Stanciu il y a 6 ans
Parent
commit
a9c6db73bf
6 fichiers modifiés avec 331 ajouts et 343 suppressions
  1. 1 1
      FlatCAMApp.py
  2. 73 88
      FlatCAMObj.py
  3. 4 1
      README.md
  4. 1 1
      flatcamGUI/PreferencesUI.py
  5. 78 81
      flatcamTools/ToolNonCopperClear.py
  6. 174 171
      flatcamTools/ToolPaint.py

+ 1 - 1
FlatCAMApp.py

@@ -806,7 +806,7 @@ class App(QtCore.QObject):
             "tools_paintorder": 'rev',
             "tools_paintoverlap": 20,
             "tools_paintmargin": 0.0,
-            "tools_paintmethod": _("Seed-based"),
+            "tools_paintmethod": _("Seed"),
             "tools_selectmethod": "all",
             "tools_pathconnect": True,
             "tools_paintcontour": True,

+ 73 - 88
FlatCAMObj.py

@@ -2778,10 +2778,8 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.generate_milling_slots_button.show()
 
         # set the text on tool_data_label after loading the object
-        sel_rows = list()
         sel_items = self.ui.tools_table.selectedItems()
-        for it in sel_items:
-            sel_rows.append(it.row())
+        sel_rows = [it.row() for it in sel_items]
         if len(sel_rows) > 1:
             self.ui.tool_data_label.setText(
                 "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
@@ -2909,8 +2907,17 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.ui.operation_radio.activated_custom.connect(self.on_operation_type)
 
         self.ui.pp_excellon_name_cb.activated.connect(self.on_pp_changed)
+
+        self.ui.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
         self.units_found = self.app.defaults['units']
 
+        # ########################################
+        # #######3 TEMP SETTINGS #################
+        # ########################################
+        self.ui.operation_radio.set_value("drill")
+        self.ui.operation_radio.setEnabled(False)
+
     def ui_connect(self):
 
         # selective plotting
@@ -3029,7 +3036,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         for form_key in self.form_fields:
             for storage_key in dict_storage:
                 if form_key == storage_key and form_key not in \
-                        ["toolchangez", "startz", "endz", "ppname_e", "ppname_g"]:
+                        ["toolchange", "toolchangez", "startz", "endz", "ppname_e", "ppname_g"]:
                     try:
                         self.form_fields[form_key].set_value(dict_storage[form_key])
                     except Exception as e:
@@ -3047,19 +3054,20 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         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
+        # row = self.ui.tools_table.currentRow()
+        rows = sorted(set(index.row() for index in self.ui.tools_table.selectedIndexes()))
+        for row in rows:
+            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()
 
@@ -3858,57 +3866,33 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.shapes.clear(update=True)
 
     def on_apply_param_to_all_clicked(self):
-        if self.tools_table.rowCount() == 0:
+        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
-            log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
+            log.debug("FlatCAMExcellon.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
             return
 
-        self.blockSignals(True)
+        self.ui_disconnect()
 
-        row = self.tools_table.currentRow()
+        row = self.ui.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()
+        tooluid_item = int(self.ui.tools_table.item(row, 0).text())
+        temp_tool_data = dict()
 
-                elif key == 'solid_geometry':
-                    temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
-                else:
-                    temp_dia[key] = deepcopy(value)
+        for tooluid_key, tooluid_val in self.tools.items():
+            if int(tooluid_key) == tooluid_item:
+                # this will hold the 'data' key of the self.tools[tool] dictionary that corresponds to
+                # the current row in the tool table
+                temp_tool_data = tooluid_val['data']
+                break
 
-                temp_tools[tooluid_key] = deepcopy(temp_dia)
+        for tooluid_key, tooluid_val in self.tools.items():
+            tooluid_val['data'] = deepcopy(temp_tool_data)
 
-        self.ncc_tools.clear()
-        self.ncc_tools = deepcopy(temp_tools)
-        temp_tools.clear()
+        self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
 
-        self.blockSignals(False)
+        self.ui_connect()
 
 
 class FlatCAMGeometry(FlatCAMObj, Geometry):
@@ -4584,42 +4568,43 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                 self.ui.tool_data_label.setText(
                     "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), tooluid)
                 )
+
+                # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
+                # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
+                try:
+                    item = self.ui.geo_tools_table.cellWidget(current_row, 4)
+                    if item is not None:
+                        tool_type_txt = item.currentText()
+                        self.ui_update_v_shape(tool_type_txt=tool_type_txt)
+                    else:
+                        self.ui_connect()
+                        return
+                except Exception as e:
+                    log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
+                    return
+
+                try:
+                    # set the form with data from the newly selected tool
+                    for tooluid_key, tooluid_value in self.tools.items():
+                        if int(tooluid_key) == tooluid:
+                            for key, value in tooluid_value.items():
+                                if key == 'data':
+                                    form_value_storage = tooluid_value['data']
+                                    self.update_form(form_value_storage)
+                                if key == 'offset_value':
+                                    # update the offset value in the entry even if the entry is hidden
+                                    self.ui.tool_offset_entry.set_value(tooluid_value['offset_value'])
+
+                                if key == 'tool_type' and value == 'V':
+                                    self.update_cutz()
+                except Exception as e:
+                    log.debug("FlatCAMGeometry.update_ui() -> %s " % str(e))
+
             else:
                 self.ui.tool_data_label.setText(
                     "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
                 )
 
-            # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
-            # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
-            try:
-                item = self.ui.geo_tools_table.cellWidget(current_row, 4)
-                if item is not None:
-                    tool_type_txt = item.currentText()
-                    self.ui_update_v_shape(tool_type_txt=tool_type_txt)
-                else:
-                    self.ui_connect()
-                    return
-            except Exception as e:
-                log.debug("Tool missing in ui_update_v_shape(). Add a tool in Geo Tool Table. %s" % str(e))
-                return
-
-            try:
-                # set the form with data from the newly selected tool
-                for tooluid_key, tooluid_value in self.tools.items():
-                    if int(tooluid_key) == tooluid:
-                        for key, value in tooluid_value.items():
-                            if key == 'data':
-                                form_value_storage = tooluid_value['data']
-                                self.update_form(form_value_storage)
-                            if key == 'offset_value':
-                                # update the offset value in the entry even if the entry is hidden
-                                self.ui.tool_offset_entry.set_value(tooluid_value['offset_value'])
-
-                            if key == 'tool_type' and value == 'V':
-                                self.update_cutz()
-            except Exception as e:
-                log.debug("FlatCAMGeometry.update_ui() -> %s " % str(e))
-
         self.ui_connect()
 
     def on_tool_add(self, dia=None):

+ 4 - 1
README.md

@@ -17,9 +17,12 @@ CAD program, and create G-Code for Isolation routing.
 - updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
 - updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
 - in Excellon UI protected the values that are common parameters from change on tool selection change
-- fixed some issues realted to the usage of the new confirmation message in FlatCAM Tools
+- fixed some issues related to the usage of the new confirmation message in FlatCAM Tools
 - made sure that the FlatCAM Tools UI initialization is done only in set_tool_ui() method and not in the constructor
 - adapted the GCode generation from Excellon to work with multiple tools data and modified the preprocessors header
+- when multiple tools are selected in Excellon UI and parameters are modified it will applied to all selected
+- in Excellon UI, Paint Tool and NCC Tool finished the "Apply parameters to all tools" functionality
+- updated Paint Tool and NCC Tool in the UI functionality
 
 16.02.2020
 

+ 1 - 1
flatcamGUI/PreferencesUI.py

@@ -5826,7 +5826,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
         # ], orientation='vertical', stretch=False)
         self.paintmethod_combo = FCComboBox()
         self.paintmethod_combo.addItems(
-            [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+            [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
         )
 
         grid0.addWidget(methodlabel, 11, 0)

+ 78 - 81
flatcamTools/ToolNonCopperClear.py

@@ -8,7 +8,8 @@
 from PyQt5 import QtWidgets, QtCore, QtGui
 
 from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, FCComboBox
+from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton, FCComboBox, \
+    OptionalInputSection
 from flatcamParsers.ParseGerber import Gerber
 
 import FlatCAMApp
@@ -70,7 +71,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # ################################################
         # ##### Type of object to be copper cleaned ######
         # ################################################
-        # self.type_obj_combo = QtWidgets.QComboBox()
+        # self.type_obj_combo = FCComboBox()
         # self.type_obj_combo.addItem("Gerber")
         # self.type_obj_combo.addItem("Excellon")
         # self.type_obj_combo.addItem("Geometry")
@@ -97,7 +98,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # ################################################
         # ##### The object to be copper cleaned ##########
         # ################################################
-        self.object_combo = QtWidgets.QComboBox()
+        self.object_combo = FCComboBox()
         self.object_combo.setModel(self.app.collection)
         self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
         self.object_combo.setCurrentIndex(1)
@@ -439,14 +440,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         )
         self.grid3.addWidget(self.ncc_choice_offset_cb, 19, 0)
 
-        # ## NCC Offset value
-        # self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
-        # self.ncc_offset_label.setToolTip(
-        #     _("If used, it will add an offset to the copper features.\n"
-        #       "The copper clearing will finish to a distance\n"
-        #       "from the copper features.\n"
-        #       "The value can be between 0 and 10 FlatCAM units.")
-        # )
+        # ## NCC Offset Entry
         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)
@@ -459,12 +453,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
         else:
             self.ncc_offset_spinner.setSingleStep(0.01)
 
-        # self.grid3.addWidget(self.ncc_offset_label, 20, 0)
         self.grid3.addWidget(self.ncc_offset_spinner, 19, 1)
-
-        # self.ncc_offset_label.hide()
-        self.ncc_offset_spinner.setEnabled(False)
-
+        
+        self.ois_ncc_offset = OptionalInputSection(self.ncc_choice_offset_cb, [self.ncc_offset_spinner])
+        
         separator_line = QtWidgets.QFrame()
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
@@ -530,7 +522,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
             _("The type of FlatCAM object to be used as non copper clearing reference.\n"
               "It can be Gerber, Excellon or Geometry.")
         )
-        self.box_combo_type = QtWidgets.QComboBox()
+        self.box_combo_type = FCComboBox()
         self.box_combo_type.addItem(_("Reference Gerber"))
         self.box_combo_type.addItem(_("Reference Excellon"))
         self.box_combo_type.addItem(_("Reference Geometry"))
@@ -540,7 +532,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.box_combo_label.setToolTip(
             _("The FlatCAM object to be used as non copper clearing reference.")
         )
-        self.box_combo = QtWidgets.QComboBox()
+        self.box_combo = FCComboBox()
         self.box_combo.setModel(self.app.collection)
         self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
         self.box_combo.setCurrentIndex(1)
@@ -683,11 +675,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
         self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
         self.reference_radio.group_toggle_fn = self.on_toggle_reference
-        self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
+
         self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
         self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
 
         self.type_obj_combo.activated_custom.connect(self.on_type_obj_index_changed)
+
+        self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
         self.reset_button.clicked.connect(self.set_tool_ui)
 
     def on_type_obj_index_changed(self, val):
@@ -696,48 +691,46 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.object_combo.setCurrentIndex(0)
 
     def on_row_selection_change(self):
-        self.update_ui()
-
-    def update_ui(self, row=None):
         self.blockSignals(True)
 
-        if row is None:
-            try:
-                current_row = self.tools_table.currentRow()
-            except Exception:
-                current_row = 0
-        else:
-            current_row = row
+        sel_rows = [it.row() for it in self.tools_table.selectedItems()]
+        # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
 
-        if current_row < 0:
-            current_row = 0
+        if not sel_rows:
+            sel_rows = [0]
 
-        # populate the form with the data from the tool associated with the row parameter
-        try:
-            item = self.tools_table.item(current_row, 3)
-            if item is not None:
-                tooluid = int(item.text())
-            else:
+        for current_row in sel_rows:
+            # populate the form with the data from the tool associated with the row parameter
+            try:
+                item = self.tools_table.item(current_row, 3)
+                if item is not None:
+                    tooluid = int(item.text())
+                else:
+                    return
+            except Exception as e:
+                log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
                 return
-        except Exception as e:
-            log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
-            return
-
-        # update the QLabel that shows for which Tool we have the parameters in the UI form
-        self.tool_data_label.setText(
-            "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), (current_row + 1))
-        )
 
-        try:
-            # set the form with data from the newly selected tool
-            for tooluid_key, tooluid_value in list(self.ncc_tools.items()):
-                if int(tooluid_key) == tooluid:
-                    for key, value in tooluid_value.items():
-                        if key == 'data':
-                            form_value_storage = tooluid_value[key]
-                            self.storage_to_form(form_value_storage)
-        except Exception as e:
-            log.debug("NonCopperClear ---> update_ui() " + str(e))
+            # update the QLabel that shows for which Tool we have the parameters in the UI form
+            if len(sel_rows) == 1:
+                cr = current_row + 1
+                self.tool_data_label.setText(
+                    "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), cr)
+                )
+                try:
+                    # set the form with data from the newly selected tool
+                    for tooluid_key, tooluid_value in list(self.ncc_tools.items()):
+                        if int(tooluid_key) == tooluid:
+                            for key, value in tooluid_value.items():
+                                if key == 'data':
+                                    form_value_storage = tooluid_value[key]
+                                    self.storage_to_form(form_value_storage)
+                except Exception as e:
+                    log.debug("NonCopperClear ---> update_ui() " + str(e))
+            else:
+                self.tool_data_label.setText(
+                    "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
+                )
 
         self.blockSignals(False)
 
@@ -761,19 +754,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
         wdg_objname = widget_changed.objectName()
         option_changed = self.name2option[wdg_objname]
 
-        row = self.tools_table.currentRow()
-
-        if row < 0:
-            row = 0
-        tooluid_item = int(self.tools_table.item(row, 3).text())
-
-        for tooluid_key, tooluid_val in self.ncc_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
+        # row = self.tools_table.currentRow()
+        rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+        for row in rows:
+            if row < 0:
+                row = 0
+            tooluid_item = int(self.tools_table.item(row, 3).text())
+
+            for tooluid_key, tooluid_val in self.ncc_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.blockSignals(False)
 
@@ -828,6 +822,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.ncc_tools = deepcopy(temp_tools)
         temp_tools.clear()
 
+        self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
+
         self.blockSignals(False)
 
     def on_add_tool_by_key(self):
@@ -1027,16 +1023,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
-                    tool_type_item = QtWidgets.QComboBox()
-                    for item in self.tool_type_item_options:
-                        tool_type_item.addItem(item)
+                    tool_type_item = FCComboBox()
+                    tool_type_item.addItems(self.tool_type_item_options)
+
                         # tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
                     idx = tool_type_item.findText(tooluid_value['tool_type'])
                     tool_type_item.setCurrentIndex(idx)
 
                     tool_uid_item = QtWidgets.QTableWidgetItem(str(int(tooluid_key)))
 
-                    operation_type = QtWidgets.QComboBox()
+                    operation_type = FCComboBox()
                     operation_type.addItem('iso_op')
                     # operation_type.setStyleSheet('background-color: rgb(255,255,255)')
                     operation_type.addItem('clear_op')
@@ -1082,6 +1078,16 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
         self.ui_connect()
 
+        # set the text on tool_data_label after loading the object
+        sel_rows = list()
+        sel_items = self.tools_table.selectedItems()
+        for it in sel_items:
+            sel_rows.append(it.row())
+        if len(sel_rows) > 1:
+            self.tool_data_label.setText(
+                "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
+            )
+
     def ui_connect(self):
         self.tools_table.itemChanged.connect(self.on_tool_edit)
 
@@ -1222,15 +1228,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
             self.box_combo_type.show()
             self.box_combo_type_label.show()
 
-    def on_offset_choice(self, state):
-        # if state:
-        #     self.ncc_offset_label.show()
-        #     self.ncc_offset_spinner.show()
-        # else:
-        #     self.ncc_offset_label.hide()
-        #     self.ncc_offset_spinner.hide()
-        self.ncc_offset_spinner.setEnabled(state)
-
     def on_order_changed(self, order):
         if order != 'no':
             self.build_ui()

+ 174 - 171
flatcamTools/ToolPaint.py

@@ -205,7 +205,7 @@ class ToolPaint(FlatCAMTool, Gerber):
               "- 'V-shape'\n"
               "- Circular")
         )
-        self.tool_type_radio.setObjectName(_("Tool Type"))
+        self.tool_type_radio.setObjectName('p_tool_type')
 
         self.grid3.addWidget(self.tool_type_label, 2, 0)
         self.grid3.addWidget(self.tool_type_radio, 2, 1)
@@ -218,7 +218,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.tipdia_entry.set_precision(self.decimals)
         self.tipdia_entry.set_range(0.0000, 9999.9999)
         self.tipdia_entry.setSingleStep(0.1)
-        self.tipdia_entry.setObjectName(_("V-Tip Dia"))
+        self.tipdia_entry.setObjectName('p_vtip_dia')
 
         self.grid3.addWidget(self.tipdialabel, 3, 0)
         self.grid3.addWidget(self.tipdia_entry, 3, 1)
@@ -232,7 +232,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.set_range(0.0000, 180.0000)
         self.tipangle_entry.setSingleStep(5)
-        self.tipangle_entry.setObjectName(_("V-Tip Angle"))
+        self.tipangle_entry.setObjectName('p_vtip_angle')
 
         self.grid3.addWidget(self.tipanglelabel, 4, 0)
         self.grid3.addWidget(self.tipangle_entry, 4, 1)
@@ -246,7 +246,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         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"))
+        self.cutz_entry.setObjectName('p_cutz')
 
         self.cutz_entry.setToolTip(
             _("Depth of cut into material. Negative value.\n"
@@ -265,7 +265,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         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"))
+        self.addtool_entry.setObjectName('p_tool_dia')
 
         self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
         self.grid3.addWidget(self.addtool_entry, 6, 1)
@@ -339,7 +339,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.paintoverlap_entry.setWrapping(True)
         self.paintoverlap_entry.setRange(0.0000, 99.9999)
         self.paintoverlap_entry.setSingleStep(0.1)
-        self.paintoverlap_entry.setObjectName(_("Overlap"))
+        self.paintoverlap_entry.setObjectName('p_overlap')
 
         grid4.addWidget(ovlabel, 1, 0)
         grid4.addWidget(self.paintoverlap_entry, 1, 1)
@@ -354,7 +354,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         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"))
+        self.paintmargin_entry.setObjectName('p_margin')
 
         grid4.addWidget(marginlabel, 2, 0)
         grid4.addWidget(self.paintmargin_entry, 2, 1)
@@ -373,45 +373,38 @@ class ToolPaint(FlatCAMTool, Gerber):
         )
         # self.paintmethod_combo = RadioSet([
         #     {"label": _("Standard"), "value": "standard"},
-        #     {"label": _("Seed-based"), "value": "seed"},
-        #     {"label": _("Straight lines"), "value": "lines"},
-        #     {"label": _("Laser lines"), "value": "laser_lines"},
-        #     {"label": _("Combo"), "value": "combo"}
+        #     {"label": _("Seed-based"), "value": _("Seed")},
+        #     {"label": _("Straight lines"), "value": _("Lines")},
+        #     {"label": _("Laser lines"), "value": _("Laser_lines")},
+        #     {"label": _("Combo"), "value": _("Combo")}
         # ], orientation='vertical', stretch=False)
 
         # for choice in self.paintmethod_combo.choices:
-        #     if choice['value'] == "laser_lines":
+        #     if choice['value'] == _("Laser_lines"):
         #         choice["radio"].setEnabled(False)
 
         self.paintmethod_combo = FCComboBox()
         self.paintmethod_combo.addItems(
-            [_("Standard"), _("Seed-based"), _("Straight lines"), _("Laser lines"), _("Combo")]
+            [_("Standard"), _("Seed"), _("Lines"), _("Laser_lines"), _("Combo")]
         )
-        self.p_mth = {
-            _("Standard"): "standard",
-            _("Seed-based"): "seed",
-            _("Straight lines"): "lines",
-            _("Laser lines"): "laser_lines",
-            _("Combo"): "combo"
-        }
-        idx = self.paintmethod_combo.findText(_("Laser lines"))
+        idx = self.paintmethod_combo.findText(_("Laser_lines"))
         self.paintmethod_combo.model().item(idx).setEnabled(False)
 
-        self.paintmethod_combo.setObjectName(_("Method"))
+        self.paintmethod_combo.setObjectName('p_method')
 
         grid4.addWidget(methodlabel, 7, 0)
         grid4.addWidget(self.paintmethod_combo, 7, 1)
 
         # Connect lines
         self.pathconnect_cb = FCCheckBox('%s' % _("Connect"))
-        self.pathconnect_cb.setObjectName(_("Connect"))
+        self.pathconnect_cb.setObjectName('p_connect')
         self.pathconnect_cb.setToolTip(
             _("Draw lines between resulting\n"
               "segments to minimize tool lifts.")
         )
 
         self.paintcontour_cb = FCCheckBox('%s' % _("Contour"))
-        self.paintcontour_cb.setObjectName(_("Contour"))
+        self.paintcontour_cb.setObjectName('p_contour')
         self.paintcontour_cb.setToolTip(
             _("Cut around the perimeter of the polygon\n"
               "to trim rough edges.")
@@ -445,7 +438,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         grid4.addWidget(self.gen_param_label, 15, 0, 1, 2)
 
         self.rest_cb = FCCheckBox('%s' % _("Rest Machining"))
-        self.rest_cb.setObjectName(_("Rest Machining"))
+        self.rest_cb.setObjectName('p_rest_machining')
         self.rest_cb.setToolTip(
             _("If checked, use 'rest machining'.\n"
               "Basically it will clear copper outside PCB features,\n"
@@ -476,7 +469,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             {"label": _("All Polygons"), "value": "all"},
             {"label": _("Reference Object"), "value": "ref"}
         ], orientation='vertical', stretch=False)
-        self.selectmethod_combo.setObjectName(_("Selection"))
+        self.selectmethod_combo.setObjectName('p_selection')
         self.selectmethod_combo.setToolTip(
             _("How to select Polygons to be painted.\n"
               "- 'Polygon Selection' - left mouse click to add/remove polygons to be painted.\n"
@@ -574,7 +567,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.select_method = None
 
         self.units = ''
-        self.paint_tools = {}
+        self.paint_tools = dict()
         self.tooluid = 0
         self.first_click = False
         self.cursor_pos = None
@@ -584,7 +577,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.mp = None
         self.mr = None
 
-        self.sel_rect = []
+        self.sel_rect = list()
 
         # store here if the grid snapping is active
         self.grid_status_memory = False
@@ -606,11 +599,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         }
 
         self.name2option = {
-            _('Overlap'): "paintoverlap",
-            _('Margin'): "paintmargin",
-            _('Method'): "paintmethod",
-            _("Connect"): "pathconnect",
-            _("Contour"): "paintcontour",
+            'p_overlap': "paintoverlap",
+            'p_margin': "paintmargin",
+            'p_method': "paintmethod",
+            'p_connect': "pathconnect",
+            'p_contour': "paintcontour",
         }
 
         self.old_tool_dia = None
@@ -628,7 +621,7 @@ class ToolPaint(FlatCAMTool, Gerber):
 
         # self.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
         # self.tools_table.itemChanged.connect(self.on_tool_edit)
-        self.tools_table.currentItemChanged.connect(self.on_row_selection_change)
+        self.tools_table.clicked.connect(self.on_row_selection_change)
 
         self.generate_paint_button.clicked.connect(self.on_paint_button_click)
         self.selectmethod_combo.activated_custom.connect(self.on_radio_selection)
@@ -637,6 +630,9 @@ class ToolPaint(FlatCAMTool, Gerber):
 
         self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
         self.type_obj_combo.activated_custom.connect(self.on_type_obj_changed)
+
+        self.apply_param_to_all.clicked.connect(self.on_apply_param_to_all_clicked)
+
         self.reset_button.clicked.connect(self.set_tool_ui)
 
         # #############################################################################
@@ -660,13 +656,13 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
         self.obj_combo.setCurrentIndex(0)
 
-        idx = self.paintmethod_combo.findText(_("Laser lines"))
+        idx = self.paintmethod_combo.findText(_("Laser_lines"))
         if self.type_obj_combo.get_value().lower() == 'gerber':
             self.paintmethod_combo.model().item(idx).setEnabled(True)
         else:
             self.paintmethod_combo.model().item(idx).setEnabled(False)
-            if self.paintmethod_combo.get_value() == _("Laser lines"):
-                self.paintmethod_combo.set_value(_("Straight lines"))
+            if self.paintmethod_combo.get_value() == _("Laser_lines"):
+                self.paintmethod_combo.set_value(_("Lines"))
 
     def install(self, icon=None, separator=None, **kwargs):
         FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
@@ -700,48 +696,46 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.app.ui.notebook.setTabText(2, _("Paint Tool"))
 
     def on_row_selection_change(self):
-        self.update_ui()
-
-    def update_ui(self, row=None):
         self.blockSignals(True)
 
-        if row is None:
-            try:
-                current_row = self.tools_table.currentRow()
-            except Exception:
-                current_row = 0
-        else:
-            current_row = row
+        sel_rows = [it.row() for it in self.tools_table.selectedItems()]
+        # sel_rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
 
-        if current_row < 0:
-            current_row = 0
+        if not sel_rows:
+            sel_rows = [0]
 
-        # populate the form with the data from the tool associated with the row parameter
-        try:
-            item = self.tools_table.item(current_row, 3)
-            if item is not None:
+        for current_row in sel_rows:
+            # populate the form with the data from the tool associated with the row parameter
+            try:
+                item = self.tools_table.item(current_row, 3)
+                if item is None:
+                    return 'fail'
                 tooluid = int(item.text())
-            else:
+            except Exception as e:
+                log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
                 return
-        except Exception as e:
-            log.debug("Tool missing. Add a tool in the Tool Table. %s" % str(e))
-            return
 
-        # update the QLabel that shows for which Tool we have the parameters in the UI form
-        self.tool_data_label.setText(
-            "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), (current_row + 1))
-        )
+            # update the QLabel that shows for which Tool we have the parameters in the UI form
+            if len(sel_rows) == 1:
+                cr = self.tools_table.item(current_row, 0).text()
+                self.tool_data_label.setText(
+                    "<b>%s: <font color='#0000FF'>%s %s</font></b>" % (_('Parameters for'), _("Tool"), cr)
+                )
 
-        try:
-            # set the form with data from the newly selected tool
-            for tooluid_key, tooluid_value in list(self.paint_tools.items()):
-                if int(tooluid_key) == tooluid:
-                    for key, value in tooluid_value.items():
-                        if key == 'data':
-                            form_value_storage = tooluid_value[key]
-                            self.storage_to_form(form_value_storage)
-        except Exception as e:
-            log.debug("ToolPaint ---> update_ui() " + str(e))
+                try:
+                    # set the form with data from the newly selected tool
+                    for tooluid_key, tooluid_value in list(self.paint_tools.items()):
+                        if int(tooluid_key) == tooluid:
+                            for key, value in tooluid_value.items():
+                                if key == 'data':
+                                    form_value_storage = tooluid_value[key]
+                                    self.storage_to_form(form_value_storage)
+                except Exception as e:
+                    log.debug("ToolPaint ---> update_ui() " + str(e))
+            else:
+                self.tool_data_label.setText(
+                    "<b>%s: <font color='#0000FF'>%s</font></b>" % (_('Parameters for'), _("Multiple Tools"))
+                )
 
         self.blockSignals(False)
 
@@ -765,18 +759,20 @@ class ToolPaint(FlatCAMTool, Gerber):
         wdg_objname = widget_changed.objectName()
         option_changed = self.name2option[wdg_objname]
 
-        row = self.tools_table.currentRow()
-        if row < 0:
-            row = 0
-        tooluid_item = int(self.tools_table.item(row, 3).text())
-
-        for tooluid_key, tooluid_val in self.paint_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
+        # row = self.tools_table.currentRow()
+        rows = sorted(set(index.row() for index in self.tools_table.selectedIndexes()))
+        for row in rows:
+            if row < 0:
+                row = 0
+            tooluid_item = int(self.tools_table.item(row, 3).text())
+
+            for tooluid_key, tooluid_val in self.paint_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.blockSignals(False)
 
@@ -788,40 +784,24 @@ class ToolPaint(FlatCAMTool, Gerber):
 
         self.blockSignals(True)
 
-        # row = self.tools_table.currentRow()
-        # if row < 0:
-        #     row = 0
-
-        # 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.paint_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)
+        row = self.tools_table.currentRow()
+        if row < 0:
+            row = 0
 
-                temp_tools[tooluid_key] = deepcopy(temp_dia)
+        tooluid_item = int(self.tools_table.item(row, 3).text())
+        temp_tool_data = dict()
 
-        self.paint_tools.clear()
-        self.paint_tools = deepcopy(temp_tools)
-        temp_tools.clear()
+        for tooluid_key, tooluid_val in self.paint_tools.items():
+            if int(tooluid_key) == tooluid_item:
+                # this will hold the 'data' key of the self.tools[tool] dictionary that corresponds to
+                # the current row in the tool table
+                temp_tool_data = tooluid_val['data']
+                break
+
+        for tooluid_key, tooluid_val in self.paint_tools.items():
+            tooluid_val['data'] = deepcopy(temp_tool_data)
+
+        self.app.inform.emit('[success] %s' % _("Current Tool parameters were applied to all tools."))
 
         self.blockSignals(False)
 
@@ -1682,7 +1662,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         :param outname: Name of the resulting Geometry Object.
         :param connect: Connect lines to avoid tool lifts.
         :param contour: Paint around the edges.
-        :param method: choice out of 'seed', 'normal', 'lines'
+        :param method: choice out of _("Seed"), 'normal', 'lines'
         :param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
         Usage of the different one is related to when this function is called from a TcL command.
         :return: None
@@ -1717,7 +1697,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             self.app.inform.emit('[WARNING] %s' % _('No polygon found.'))
             return
 
-        paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+        paint_method = method if method is not None else self.paintmethod_combo.get_value()
         paint_margin = float(self.paintmargin_entry.get_value()) if margin is None else margin
         # determine if to use the progressive plotting
         prog_plot = True if self.app.defaults["tools_paint_plotting"] == 'progressive' else False
@@ -1757,7 +1737,17 @@ class ToolPaint(FlatCAMTool, Gerber):
             def paint_p(polyg, tooldiameter):
                 cpoly = None
                 try:
-                    if paint_method == "seed":
+                    if paint_method == _("Standard"):
+                        # Type(cp) == FlatCAMRTreeStorage | None
+                        cpoly = self.clear_polygon(polyg,
+                                                   tooldia=tooldiameter,
+                                                   steps_per_circle=self.app.defaults["geometry_circle_steps"],
+                                                   overlap=over,
+                                                   contour=cont,
+                                                   connect=conn,
+                                                   prog_plot=prog_plot)
+
+                    elif paint_method == _("Seed"):
                         # Type(cp) == FlatCAMRTreeStorage | None
                         cpoly = self.clear_polygon2(polyg,
                                                     tooldia=tooldiameter,
@@ -1767,7 +1757,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     connect=conn,
                                                     prog_plot=prog_plot)
 
-                    elif paint_method == "lines":
+                    elif paint_method == _("Lines"):
                         # Type(cp) == FlatCAMRTreeStorage | None
                         cpoly = self.clear_polygon3(polyg,
                                                     tooldia=tooldiameter,
@@ -1777,16 +1767,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     connect=conn,
                                                     prog_plot=prog_plot)
 
-                    elif paint_method == "standard":
-                        # Type(cp) == FlatCAMRTreeStorage | None
-                        cpoly = self.clear_polygon(polyg,
-                                                   tooldia=tooldiameter,
-                                                   steps_per_circle=self.app.defaults["geometry_circle_steps"],
-                                                   overlap=over,
-                                                   contour=cont,
-                                                   connect=conn,
-                                                   prog_plot=prog_plot)
-                    elif paint_method == "laser_lines":
+                    elif paint_method == _("Laser_lines"):
                         # line = None
                         # aperture_size = None
 
@@ -1833,7 +1814,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                         pads_lines_list = list()
 
                         # process the flashes found in the selected polygon with the 'lines' method for rectangular
-                        # flashes and with 'seed' for oblong and circular flashes
+                        # flashes and with _("Seed") for oblong and circular flashes
                         # and pads (flahes) need the contour therefore I override the GUI settings with always True
                         for ap_type in flash_el_dict:
                             for elem in flash_el_dict[ap_type]:
@@ -1933,7 +1914,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                         #                                  connect=conn,
                         #                                  prog_plot=prog_plot)
 
-                    elif paint_method == "combo":
+                    elif paint_method == _("Combo"):
                         self.app.inform.emit(_("Painting polygon with method: lines."))
                         cpoly = self.clear_polygon3(polyg,
                                                     tooldia=tooldiameter,
@@ -2127,12 +2108,12 @@ class ToolPaint(FlatCAMTool, Gerber):
         :param outname: name of the resulting object
         :param connect: Connect lines to avoid tool lifts.
         :param contour: Paint around the edges.
-        :param method: choice out of 'seed', 'normal', 'lines'
+        :param method: choice out of _("Seed"), 'normal', 'lines'
         :param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
         Usage of the different one is related to when this function is called from a TcL command.
         :return:
         """
-        paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+        paint_method = method if method is not None else self.paintmethod_combo.get_value()
 
         if margin is not None:
             paint_margin = margin
@@ -2306,7 +2287,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                             for pol in poly_buf:
                                 if pol is not None and isinstance(pol, Polygon):
                                     cp = None
-                                    if paint_method == 'standard':
+                                    if paint_method == _("Standard"):
                                         cp = self.clear_polygon(pol,
                                                                 tooldia=tool_dia,
                                                                 steps_per_circle=self.app.defaults[
@@ -2315,7 +2296,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                                 contour=cont,
                                                                 connect=conn,
                                                                 prog_plot=prog_plot)
-                                    elif paint_method == 'seed':
+                                    elif paint_method == _("Seed"):
                                         cp = self.clear_polygon2(pol,
                                                                  tooldia=tool_dia,
                                                                  steps_per_circle=self.app.defaults[
@@ -2324,7 +2305,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                                  contour=cont,
                                                                  connect=conn,
                                                                  prog_plot=prog_plot)
-                                    elif paint_method == "standard":
+                                    elif paint_method == _("Lines"):
                                         cp = self.clear_polygon3(pol,
                                                                  tooldia=tool_dia,
                                                                  steps_per_circle=self.app.defaults[
@@ -2333,7 +2314,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                                  contour=cont,
                                                                  connect=conn,
                                                                  prog_plot=prog_plot)
-                                    elif paint_method == "laser_lines":
+                                    elif paint_method == _("Laser_lines"):
                                         # line = None
                                         # aperture_size = None
 
@@ -2381,7 +2362,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                         pads_lines_list = list()
 
                                         # process the flashes found in the selected polygon with the 'lines' method
-                                        # for rectangular flashes and with 'seed' for oblong and circular flashes
+                                        # for rectangular flashes and with _("Seed") for oblong and circular flashes
                                         # and pads (flahes) need the contour therefore I override the GUI settings
                                         # with always True
                                         for ap_type in flash_el_dict:
@@ -2459,7 +2440,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     cp.insert(lin)
                                         except TypeError:
                                             cp.insert(lines_union)
-                                    elif paint_method == "combo":
+                                    elif paint_method == _("Combo"):
                                         self.app.inform.emit(_("Painting polygons with method: lines."))
                                         cp = self.clear_polygon3(pol,
                                                                  tooldia=tool_dia,
@@ -2508,7 +2489,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                         except TypeError:
                             if isinstance(poly_buf, Polygon):
                                 cp = None
-                                if paint_method == 'standard':
+                                if paint_method == _("Standard"):
                                     cp = self.clear_polygon(poly_buf,
                                                             tooldia=tool_dia,
                                                             steps_per_circle=self.app.defaults[
@@ -2517,7 +2498,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                             contour=cont,
                                                             connect=conn,
                                                             prog_plot=prog_plot)
-                                elif paint_method == 'seed':
+                                elif paint_method == _("Seed"):
                                     cp = self.clear_polygon2(poly_buf,
                                                              tooldia=tool_dia,
                                                              steps_per_circle=self.app.defaults[
@@ -2526,7 +2507,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                              contour=cont,
                                                              connect=conn,
                                                              prog_plot=prog_plot)
-                                elif paint_method == 'standard':
+                                elif paint_method == _("Lines"):
                                     cp = self.clear_polygon3(poly_buf,
                                                              tooldia=tool_dia,
                                                              steps_per_circle=self.app.defaults[
@@ -2535,7 +2516,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                              contour=cont,
                                                              connect=conn,
                                                              prog_plot=prog_plot)
-                                elif paint_method == "laser_lines":
+                                elif paint_method == _("Laser_lines"):
                                     # line = None
                                     # aperture_size = None
 
@@ -2583,7 +2564,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                     pads_lines_list = list()
 
                                     # process the flashes found in the selected polygon with the 'lines' method
-                                    # for rectangular flashes and with 'seed' for oblong and circular flashes
+                                    # for rectangular flashes and with _("Seed") for oblong and circular flashes
                                     # and pads (flahes) need the contour therefore I override the GUI settings
                                     # with always True
                                     for ap_type in flash_el_dict:
@@ -2661,7 +2642,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                 cp.insert(lin)
                                     except TypeError:
                                         cp.insert(lines_union)
-                                elif paint_method == "combo":
+                                elif paint_method == _("Combo"):
                                     self.app.inform.emit(_("Painting polygons with method: lines."))
                                     cp = self.clear_polygon3(poly_buf,
                                                              tooldia=tool_dia,
@@ -2721,7 +2702,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                     #         continue
                     #     poly_buf = geo.buffer(-paint_margin)
                     #
-                    #     if paint_method == "seed":
+                    #     if paint_method == _("Seed"):
                     #         # Type(cp) == FlatCAMRTreeStorage | None
                     #         cp = self.clear_polygon2(poly_buf,
                     #                                  tooldia=tool_dia,
@@ -2731,7 +2712,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                     #                                  connect=conn,
                     #                                  prog_plot=prog_plot)
                     #
-                    #     elif paint_method == "lines":
+                    #     elif paint_method == _("Lines"):
                     #         # Type(cp) == FlatCAMRTreeStorage | None
                     #         cp = self.clear_polygon3(poly_buf,
                     #                                  tooldia=tool_dia,
@@ -2893,27 +2874,27 @@ class ToolPaint(FlatCAMTool, Gerber):
                         poly_buf = geo.buffer(-paint_margin)
                         cp = None
 
-                        if paint_method == "standard":
+                        if paint_method == _("Standard"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over, contour=cont, connect=conn,
                                                     prog_plot=prog_plot)
 
-                        elif paint_method == "seed":
+                        elif paint_method == _("Seed"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over, contour=cont, connect=conn,
                                                      prog_plot=prog_plot)
 
-                        elif paint_method == "lines":
+                        elif paint_method == _("Lines"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over, contour=cont, connect=conn,
                                                      prog_plot=prog_plot)
-                        elif paint_method == "laser_lines":
+                        elif paint_method == _("Laser_lines"):
                             # line = None
                             # aperture_size = None
 
@@ -2961,7 +2942,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                             pads_lines_list = list()
 
                             # process the flashes found in the selected polygon with the 'lines' method
-                            # for rectangular flashes and with 'seed' for oblong and circular flashes
+                            # for rectangular flashes and with _("Seed") for oblong and circular flashes
                             # and pads (flahes) need the contour therefore I override the GUI settings
                             # with always True
                             for ap_type in flash_el_dict:
@@ -3039,7 +3020,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                         cp.insert(lin)
                             except TypeError:
                                 cp.insert(lines_union)
-                        elif paint_method == "combo":
+                        elif paint_method == _("Combo"):
                             self.app.inform.emit(_("Painting polygons with method: lines."))
                             cp = self.clear_polygon3(poly_buf,
                                                      tooldia=tool_dia,
@@ -3192,12 +3173,12 @@ class ToolPaint(FlatCAMTool, Gerber):
         :param outname: name of the resulting object
         :param connect: Connect lines to avoid tool lifts.
         :param contour: Paint around the edges.
-        :param method: choice out of 'seed', 'normal', 'lines'
+        :param method: choice out of _("Seed"), 'normal', 'lines'
         :param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
         Usage of the different one is related to when this function is called from a TcL command.
         :return:
         """
-        paint_method = method if method is not None else self.p_mth[self.paintmethod_combo.get_value()]
+        paint_method = method if method is not None else self.paintmethod_combo.get_value()
 
         if margin is not None:
             paint_margin = margin
@@ -3364,7 +3345,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                         poly_buf = geo.buffer(-paint_margin)
 
                         cp = None
-                        if paint_method == "seed":
+                        if paint_method == _("Seed"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon2(poly_buf,
                                                      tooldia=tool_dia,
@@ -3374,7 +3355,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      connect=conn,
                                                      prog_plot=prog_plot)
 
-                        elif paint_method == "lines":
+                        elif paint_method == _("Lines"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon3(poly_buf,
                                                      tooldia=tool_dia,
@@ -3384,7 +3365,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                      connect=conn,
                                                      prog_plot=prog_plot)
 
-                        elif paint_method == 'standard':
+                        elif paint_method == _("Standard"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon(poly_buf,
                                                     tooldia=tool_dia,
@@ -3393,7 +3374,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                                     contour=cont,
                                                     connect=conn,
                                                     prog_plot=prog_plot)
-                        elif paint_method == "laser_lines":
+                        elif paint_method == _("Laser_lines"):
                             # line = None
                             # aperture_size = None
 
@@ -3441,7 +3422,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                             pads_lines_list = list()
 
                             # process the flashes found in the selected polygon with the 'lines' method
-                            # for rectangular flashes and with 'seed' for oblong and circular flashes
+                            # for rectangular flashes and with _("Seed") for oblong and circular flashes
                             # and pads (flahes) need the contour therefore I override the GUI settings
                             # with always True
                             for ap_type in flash_el_dict:
@@ -3519,7 +3500,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                         cp.insert(lin)
                             except TypeError:
                                 cp.insert(lines_union)
-                        elif paint_method == "combo":
+                        elif paint_method == _("Combo"):
                             self.app.inform.emit(_("Painting polygons with method: lines."))
                             cp = self.clear_polygon3(poly_buf,
                                                      tooldia=tool_dia,
@@ -3693,27 +3674,27 @@ class ToolPaint(FlatCAMTool, Gerber):
                         poly_buf = geo.buffer(-paint_margin)
                         cp = None
 
-                        if paint_method == "standard":
+                        if paint_method == _("Standard"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon(poly_buf, tooldia=tool_dia,
                                                     steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                     overlap=over, contour=cont, connect=conn,
                                                     prog_plot=prog_plot)
 
-                        elif paint_method == "seed":
+                        elif paint_method == _("Seed"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon2(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over, contour=cont, connect=conn,
                                                      prog_plot=prog_plot)
 
-                        elif paint_method == "lines":
+                        elif paint_method == _("Lines"):
                             # Type(cp) == FlatCAMRTreeStorage | None
                             cp = self.clear_polygon3(poly_buf, tooldia=tool_dia,
                                                      steps_per_circle=self.app.defaults["geometry_circle_steps"],
                                                      overlap=over, contour=cont, connect=conn,
                                                      prog_plot=prog_plot)
-                        elif paint_method == "laser_lines":
+                        elif paint_method == _("Laser_lines"):
                             # line = None
                             # aperture_size = None
 
@@ -3761,7 +3742,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                             pads_lines_list = list()
 
                             # process the flashes found in the selected polygon with the 'lines' method
-                            # for rectangular flashes and with 'seed' for oblong and circular flashes
+                            # for rectangular flashes and with _("Seed") for oblong and circular flashes
                             # and pads (flahes) need the contour therefore I override the GUI settings
                             # with always True
                             for ap_type in flash_el_dict:
@@ -3839,7 +3820,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                                         cp.insert(lin)
                             except TypeError:
                                 cp.insert(lines_union)
-                        elif paint_method == "combo":
+                        elif paint_method == _("Combo"):
                             self.app.inform.emit(_("Painting polygons with method: lines."))
                             cp = self.clear_polygon3(poly_buf,
                                                      tooldia=tool_dia,
@@ -3989,7 +3970,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         :param outname: name of the resulting object
         :param connect: Connect lines to avoid tool lifts.
         :param contour: Paint around the edges.
-        :param method: choice out of 'seed', 'normal', 'lines'
+        :param method: choice out of _("Seed"), 'normal', 'lines'
         :param tools_storage: whether to use the current tools_storage self.paints_tools or a different one.
         Usage of the different one is related to when this function is called from a TcL command.
         :return:
@@ -4027,6 +4008,10 @@ class ToolPaint(FlatCAMTool, Gerber):
     def ui_connect(self):
         self.tools_table.itemChanged.connect(self.on_tool_edit)
 
+        # rows selected
+        self.tools_table.clicked.connect(self.on_row_selection_change)
+        self.tools_table.horizontalHeader().sectionClicked.connect(self.on_row_selection_change)
+
         for row in range(self.tools_table.rowCount()):
             try:
                 self.tools_table.cellWidget(row, 2).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
@@ -4068,6 +4053,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                 current_widget.activated_custom.connect(self.form_to_storage)
             elif isinstance(current_widget, FCDoubleSpinner):
                 current_widget.returnPressed.connect(self.form_to_storage)
+            elif isinstance(current_widget, FCComboBox):
+                current_widget.currentIndexChanged.connect(self.form_to_storage)
 
         self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
         self.order_radio.activated_custom[str].connect(self.on_order_changed)
@@ -4079,6 +4066,17 @@ class ToolPaint(FlatCAMTool, Gerber):
         except (TypeError, AttributeError):
             pass
 
+        # rows selected
+        try:
+            self.tools_table.clicked.disconnect(self.on_row_selection_change)
+        except (TypeError, AttributeError):
+            pass
+
+        try:
+            self.tools_table.horizontalHeader().sectionClicked.disconnect(self.on_row_selection_change)
+        except (TypeError, AttributeError):
+            pass
+
         try:
             # if connected, disconnect the signal from the slot on item_changed as it creates issues
             self.tool_type_radio.activated_custom.disconnect()
@@ -4096,17 +4094,22 @@ class ToolPaint(FlatCAMTool, Gerber):
             current_widget = self.form_fields[opt]
             if isinstance(current_widget, FCCheckBox):
                 try:
-                    current_widget.stateChanged.disconnect()
+                    current_widget.stateChanged.disconnect(self.form_to_storage)
                 except (TypeError, ValueError):
                     pass
             if isinstance(current_widget, RadioSet):
                 try:
-                    current_widget.activated_custom.disconnect()
+                    current_widget.activated_custom.disconnect(self.form_to_storage)
                 except (TypeError, ValueError):
                     pass
             elif isinstance(current_widget, FCDoubleSpinner):
                 try:
-                    current_widget.returnPressed.disconnect()
+                    current_widget.returnPressed.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+            elif isinstance(current_widget, FCComboBox):
+                try:
+                    current_widget.currentIndexChanged.connect(self.form_to_storage)
                 except (TypeError, ValueError):
                     pass