Przeglądaj źródła

- started to rework the NCC Tool GUI in preparation for adding a Tool DB feature

Marius Stanciu 6 lat temu
rodzic
commit
fd9d18b52b
3 zmienionych plików z 348 dodań i 56 usunięć
  1. 7 3
      README.md
  2. 3 3
      flatcamGUI/PreferencesUI.py
  3. 338 50
      flatcamTools/ToolNonCopperClear.py

+ 7 - 3
README.md

@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+2.01.2020
+
+- started to rework the NCC Tool GUI in preparation for adding a Tool DB feature
+
 1.01.2020
 1.01.2020
 
 
 - fixed bug in NCC Tool: after trying to add a tool already in the Tool Table when trying to change the Tool Type the GUI does not change
 - fixed bug in NCC Tool: after trying to add a tool already in the Tool Table when trying to change the Tool Type the GUI does not change
@@ -29,7 +33,7 @@ CAD program, and create G-Code for Isolation routing.
 - some small updates in the NCC Tool
 - some small updates in the NCC Tool
 - changes in the Preferences UI for NCC and Paint Tool in Tool Dia entry field
 - changes in the Preferences UI for NCC and Paint Tool in Tool Dia entry field
 - fixed Tcl commands that use the overlap parameter to switch from fraction to percentage
 - fixed Tcl commands that use the overlap parameter to switch from fraction to percentage
-- in Transform Tool mae sure that the buffer sub-tool parameters are better explained in tooltips
+- in Transform Tool made sure that the buffer sub-tool parameters are better explained in tooltips
 - attempt to make TclCommand quit_flatcam work under Linux
 - attempt to make TclCommand quit_flatcam work under Linux
 - some fixes in the NCC Tcl command (using the bool() method on some params)
 - some fixes in the NCC Tcl command (using the bool() method on some params)
 - another attempt to make TclCommand quit_flatcam work under Linux
 - another attempt to make TclCommand quit_flatcam work under Linux
@@ -42,8 +46,8 @@ CAD program, and create G-Code for Isolation routing.
 - the Gerber UI is built only once now so the process is lighter on CPU
 - the Gerber UI is built only once now so the process is lighter on CPU
 - the Gerber apertures marking shapes storage is now built only once because the more are built the more sluggish is the interface
 - the Gerber apertures marking shapes storage is now built only once because the more are built the more sluggish is the interface
 - added a new function called by shortcut key combo CTRL+G when the current widget in Plot Area is an Code Editor. It will jump to the specified line in the text.
 - added a new function called by shortcut key combo CTRL+G when the current widget in Plot Area is an Code Editor. It will jump to the specified line in the text.
-- fixed a small where the app tried to hide a label that I've removed previously
-- in Paint Tool Preferences allowed to add a list of initial tools separated by comma
+- fixed a small bug where the app tried to hide a label that I've removed previously
+- in Paint Tool Preferences is allowed to add a list of initial tools separated by comma
 - in Geometry Paint Tool fixed the Overlap rate to work between 0 and 99.9999%
 - in Geometry Paint Tool fixed the Overlap rate to work between 0 and 99.9999%
 
 
 28.12.2019
 28.12.2019

+ 3 - 3
flatcamGUI/PreferencesUI.py

@@ -2081,7 +2081,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
         )
         )
         grid0.addWidget(milling_type_label, 4, 0)
         grid0.addWidget(milling_type_label, 4, 0)
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
-                                            {'label': _('Conv.'), 'value': 'cv'}])
+                                            {'label': _('Conventional'), 'value': 'cv'}])
         grid0.addWidget(self.milling_type_radio, 4, 1)
         grid0.addWidget(self.milling_type_radio, 4, 1)
 
 
         # Combine passes
         # Combine passes
@@ -4379,7 +4379,7 @@ class GeometryEditorPrefGroupUI(OptionsGroupUI):
               "- conventional / useful when there is no backlash compensation")
               "- conventional / useful when there is no backlash compensation")
         )
         )
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
-                                            {'label': _('Conv.'), 'value': 'cv'}])
+                                            {'label': _('Conventional'), 'value': 'cv'}])
         grid0.addWidget(milling_type_label, 1, 0)
         grid0.addWidget(milling_type_label, 1, 0)
         grid0.addWidget(self.milling_type_radio, 1, 1)
         grid0.addWidget(self.milling_type_radio, 1, 1)
 
 
@@ -5123,7 +5123,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
         )
         )
 
 
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
-                                            {'label': _('Conv.'), 'value': 'cv'}])
+                                            {'label': _('Conventional'), 'value': 'cv'}])
         self.milling_type_radio.setToolTip(
         self.milling_type_radio.setToolTip(
             _("Milling type when the selected tool is of type: 'iso_op':\n"
             _("Milling type when the selected tool is of type: 'iso_op':\n"
               "- climb / best for precision milling and to reduce tool usage\n"
               "- climb / best for precision milling and to reduce tool usage\n"

+ 338 - 50
flatcamTools/ToolNonCopperClear.py

@@ -7,7 +7,7 @@
 
 
 from PyQt5 import QtWidgets, QtCore, QtGui
 from PyQt5 import QtWidgets, QtCore, QtGui
 from FlatCAMTool import FlatCAMTool
 from FlatCAMTool import FlatCAMTool
-from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog
+from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog, FCButton
 from flatcamParsers.ParseGerber import Gerber
 from flatcamParsers.ParseGerber import Gerber
 from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
 from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
 import FlatCAMApp
 import FlatCAMApp
@@ -102,8 +102,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         form_layout.addRow(self.object_label, self.object_combo)
         form_layout.addRow(self.object_label, self.object_combo)
 
 
-        e_lab_0 = QtWidgets.QLabel('')
-        form_layout.addRow(e_lab_0)
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.tools_box.addWidget(separator_line)
 
 
         # ### Tools ## ##
         # ### Tools ## ##
         self.tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('Tools Table'))
         self.tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('Tools Table'))
@@ -167,7 +169,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         )
         )
 
 
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
         self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
-                                            {'label': _('Conv.'), 'value': 'cv'}])
+                                            {'label': _('Conventional'), 'value': 'cv'}])
         self.milling_type_radio.setToolTip(
         self.milling_type_radio.setToolTip(
             _("Milling type when the selected tool is of type: 'iso_op':\n"
             _("Milling type when the selected tool is of type: 'iso_op':\n"
               "- climb / best for precision milling and to reduce tool usage\n"
               "- climb / best for precision milling and to reduce tool usage\n"
@@ -178,7 +180,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         grid1.addWidget(self.milling_type_radio, 0, 1)
         grid1.addWidget(self.milling_type_radio, 0, 1)
 
 
         # Tool order
         # Tool order
-        self.ncc_order_label = QtWidgets.QLabel('<b>%s:</b>' % _('Tool order'))
+        self.ncc_order_label = QtWidgets.QLabel('%s:' % _('Tool order'))
         self.ncc_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
         self.ncc_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
                                           "'No' --> means that the used order is the one in the tool table\n"
                                           "'No' --> means that the used order is the one in the tool table\n"
                                           "'Forward' --> means that the tools will be ordered from small to big\n"
                                           "'Forward' --> means that the tools will be ordered from small to big\n"
@@ -198,7 +200,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         grid1.addWidget(self.ncc_order_label, 1, 0)
         grid1.addWidget(self.ncc_order_label, 1, 0)
         grid1.addWidget(self.ncc_order_radio, 1, 1)
         grid1.addWidget(self.ncc_order_radio, 1, 1)
-        grid1.addWidget(QtWidgets.QLabel(''), 2, 0)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid1.addWidget(separator_line, 2, 0, 1, 2)
 
 
         self.milling_type_label.hide()
         self.milling_type_label.hide()
         self.milling_type_radio.hide()
         self.milling_type_radio.hide()
@@ -206,8 +212,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # #############################################################
         # #############################################################
         # ############### Tool selection ##############################
         # ############### Tool selection ##############################
         # #############################################################
         # #############################################################
+
+        self.grid3 = QtWidgets.QGridLayout()
+        self.tools_box.addLayout(self.grid3)
+        self.grid3.setColumnStretch(0, 0)
+        self.grid3.setColumnStretch(1, 1)
+
         self.tool_sel_label = QtWidgets.QLabel('<b>%s</b>' % _("Tool Selection"))
         self.tool_sel_label = QtWidgets.QLabel('<b>%s</b>' % _("Tool Selection"))
-        grid1.addWidget(self.tool_sel_label, 3, 0, 1, 2)
+        self.grid3.addWidget(self.tool_sel_label, 1, 0, 1, 2)
 
 
         # Tool Type Radio Button
         # Tool Type Radio Button
         self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
         self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
@@ -224,8 +236,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "- 'V-shape'\n"
               "- 'V-shape'\n"
               "- Circular")
               "- Circular")
         )
         )
-        grid1.addWidget(self.tool_type_label, 4, 0)
-        grid1.addWidget(self.tool_type_radio, 4, 1)
+        self.grid3.addWidget(self.tool_type_label, 2, 0)
+        self.grid3.addWidget(self.tool_type_radio, 2, 1)
 
 
         # Tip Dia
         # Tip Dia
         self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
         self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
@@ -235,8 +247,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.tipdia_entry.set_precision(self.decimals)
         self.tipdia_entry.set_precision(self.decimals)
         self.tipdia_entry.setSingleStep(0.1)
         self.tipdia_entry.setSingleStep(0.1)
 
 
-        grid1.addWidget(self.tipdialabel, 5, 0)
-        grid1.addWidget(self.tipdia_entry, 5, 1)
+        self.grid3.addWidget(self.tipdialabel, 3, 0)
+        self.grid3.addWidget(self.tipdia_entry, 3, 1)
 
 
         # Tip Angle
         # Tip Angle
         self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
         self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
@@ -247,8 +259,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.setSingleStep(5)
         self.tipangle_entry.setSingleStep(5)
 
 
-        grid1.addWidget(self.tipanglelabel, 6, 0)
-        grid1.addWidget(self.tipangle_entry, 6, 1)
+        self.grid3.addWidget(self.tipanglelabel, 4, 0)
+        self.grid3.addWidget(self.tipangle_entry, 4, 1)
 
 
         # Cut Z entry
         # Cut Z entry
         cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
         cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
@@ -264,8 +276,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
            _("Depth of cut into material. Negative value.\n"
            _("Depth of cut into material. Negative value.\n"
              "In FlatCAM units.")
              "In FlatCAM units.")
         )
         )
-        grid1.addWidget(cutzlabel, 7, 0)
-        grid1.addWidget(self.cutz_entry, 7, 1)
+        self.grid3.addWidget(cutzlabel, 5, 0)
+        self.grid3.addWidget(self.cutz_entry, 5, 1)
 
 
         # ### Tool Diameter ####
         # ### Tool Diameter ####
         self.addtool_entry_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Tool Dia'))
         self.addtool_entry_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Tool Dia'))
@@ -277,11 +289,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.addtool_entry = FCDoubleSpinner()
         self.addtool_entry = FCDoubleSpinner()
         self.addtool_entry.set_precision(self.decimals)
         self.addtool_entry.set_precision(self.decimals)
 
 
-        grid1.addWidget(self.addtool_entry_lbl, 8, 0)
-        grid1.addWidget(self.addtool_entry, 8, 1)
+        self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
+        self.grid3.addWidget(self.addtool_entry, 6, 1)
+
+        self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add Tool from DataBase'))
+        self.addtool_from_db_btn.setToolTip(
+            _("Add a new tool to the Tool Table\n"
+              "from the Tool DataBase.")
+        )
+        self.grid3.addWidget(self.addtool_from_db_btn, 7, 0, 1, 2)
 
 
-        grid2 = QtWidgets.QGridLayout()
-        self.tools_box.addLayout(grid2)
+        hlay = QtWidgets.QHBoxLayout()
 
 
         self.addtool_btn = QtWidgets.QPushButton(_('Add'))
         self.addtool_btn = QtWidgets.QPushButton(_('Add'))
         self.addtool_btn.setToolTip(
         self.addtool_btn.setToolTip(
@@ -289,31 +307,33 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "with the diameter specified above.")
               "with the diameter specified above.")
         )
         )
 
 
-        # self.copytool_btn = QtWidgets.QPushButton('Copy')
-        # self.copytool_btn.setToolTip(
-        #     "Copy a selection of tools in the Tool Table\n"
-        #     "by first selecting a row in the Tool Table."
-        # )
-
         self.deltool_btn = QtWidgets.QPushButton(_('Delete'))
         self.deltool_btn = QtWidgets.QPushButton(_('Delete'))
         self.deltool_btn.setToolTip(
         self.deltool_btn.setToolTip(
             _("Delete a selection of tools in the Tool Table\n"
             _("Delete a selection of tools in the Tool Table\n"
               "by first selecting a row(s) in the Tool Table.")
               "by first selecting a row(s) in the Tool Table.")
         )
         )
 
 
-        grid2.addWidget(self.addtool_btn, 0, 0)
-        grid2.addWidget(self.deltool_btn, 0, 2)
+        hlay.addWidget(self.addtool_btn)
+        hlay.addWidget(self.deltool_btn)
+
+        self.grid3.addLayout(hlay, 8, 0, 1, 2)
 
 
-        self.empty_label_0 = QtWidgets.QLabel('')
-        self.tools_box.addWidget(self.empty_label_0)
+        self.grid3.addWidget(QtWidgets.QLabel(''), 9, 0, 1, 2)
 
 
-        grid3 = QtWidgets.QGridLayout()
-        self.tools_box.addLayout(grid3)
-        grid3.setColumnStretch(0, 0)
-        grid3.setColumnStretch(1, 1)
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid3.addWidget(separator_line, 10, 0, 1, 2)
 
 
-        e_lab_1 = QtWidgets.QLabel('<b>%s:</b>' % _("Parameters"))
-        grid3.addWidget(e_lab_1, 0, 0)
+        self.tool_data_label = QtWidgets.QLabel(
+            "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), int(1)))
+        self.tool_data_label.setToolTip(
+            _(
+                "The data used for creating GCode.\n"
+                "Each tool store it's own set of such data."
+            )
+        )
+        self.grid3.addWidget(self.tool_data_label, 11, 0, 1, 2)
 
 
         # Overlap Entry
         # Overlap Entry
         nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
         nccoverlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
@@ -331,18 +351,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.ncc_overlap_entry.setWrapping(True)
         self.ncc_overlap_entry.setWrapping(True)
         self.ncc_overlap_entry.setRange(0.000, 99.9999)
         self.ncc_overlap_entry.setRange(0.000, 99.9999)
         self.ncc_overlap_entry.setSingleStep(0.1)
         self.ncc_overlap_entry.setSingleStep(0.1)
-        grid3.addWidget(nccoverlabel, 2, 0)
-        grid3.addWidget(self.ncc_overlap_entry, 2, 1)
+
+        self.grid3.addWidget(nccoverlabel, 12, 0)
+        self.grid3.addWidget(self.ncc_overlap_entry, 12, 1)
 
 
         nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
         nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
         nccmarginlabel.setToolTip(
         nccmarginlabel.setToolTip(
             _("Bounding box margin.")
             _("Bounding box margin.")
         )
         )
-        grid3.addWidget(nccmarginlabel, 3, 0)
         self.ncc_margin_entry = FCDoubleSpinner()
         self.ncc_margin_entry = FCDoubleSpinner()
         self.ncc_margin_entry.set_precision(self.decimals)
         self.ncc_margin_entry.set_precision(self.decimals)
 
 
-        grid3.addWidget(self.ncc_margin_entry, 3, 1)
+        self.grid3.addWidget(nccmarginlabel, 13, 0)
+        self.grid3.addWidget(self.ncc_margin_entry, 13, 1)
 
 
         # Method
         # Method
         methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
         methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
@@ -352,13 +373,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "<B>Seed-based</B>: Outwards from seed.<BR>"
               "<B>Seed-based</B>: Outwards from seed.<BR>"
               "<B>Line-based</B>: Parallel lines.")
               "<B>Line-based</B>: Parallel lines.")
         )
         )
-        grid3.addWidget(methodlabel, 4, 0)
         self.ncc_method_radio = RadioSet([
         self.ncc_method_radio = RadioSet([
             {"label": _("Standard"), "value": "standard"},
             {"label": _("Standard"), "value": "standard"},
             {"label": _("Seed-based"), "value": "seed"},
             {"label": _("Seed-based"), "value": "seed"},
             {"label": _("Straight lines"), "value": "lines"}
             {"label": _("Straight lines"), "value": "lines"}
         ], orientation='vertical', stretch=False)
         ], orientation='vertical', stretch=False)
-        grid3.addWidget(self.ncc_method_radio, 4, 1)
+
+        self.grid3.addWidget(methodlabel, 14, 0)
+        self.grid3.addWidget(self.ncc_method_radio, 14, 1)
 
 
         # Connect lines
         # Connect lines
         self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
         self.ncc_connect_cb = FCCheckBox('%s' % _("Connect"))
@@ -366,14 +388,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
             _("Draw lines between resulting\n"
             _("Draw lines between resulting\n"
               "segments to minimize tool lifts.")
               "segments to minimize tool lifts.")
         )
         )
-        grid3.addWidget(self.ncc_connect_cb, 5, 0, 1, 2)
+        self.grid3.addWidget(self.ncc_connect_cb, 15, 0, 1, 2)
 
 
         self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
         self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
         self.ncc_contour_cb.setToolTip(
         self.ncc_contour_cb.setToolTip(
             _("Cut around the perimeter of the polygon\n"
             _("Cut around the perimeter of the polygon\n"
               "to trim rough edges.")
               "to trim rough edges.")
         )
         )
-        grid3.addWidget(self.ncc_contour_cb, 6, 0, 1, 2)
+        self.grid3.addWidget(self.ncc_contour_cb, 16, 0, 1, 2)
 
 
         # Rest Machining
         # Rest Machining
         self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
         self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
@@ -387,7 +409,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "If not checked, use the standard algorithm.")
               "If not checked, use the standard algorithm.")
         )
         )
 
 
-        grid3.addWidget(self.ncc_rest_cb, 7, 0, 1, 2)
+        self.grid3.addWidget(self.ncc_rest_cb, 17, 0, 1, 2)
 
 
         # ## NCC Offset choice
         # ## NCC Offset choice
         self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
         self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
@@ -397,7 +419,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "from the copper features.\n"
               "from the copper features.\n"
               "The value can be between 0 and 10 FlatCAM units.")
               "The value can be between 0 and 10 FlatCAM units.")
         )
         )
-        grid3.addWidget(self.ncc_choice_offset_cb, 8, 0, 1, 2)
+        self.grid3.addWidget(self.ncc_choice_offset_cb, 18, 0, 1, 2)
 
 
         # ## NCC Offset value
         # ## NCC Offset value
         self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
         self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
@@ -407,7 +429,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "from the copper features.\n"
               "from the copper features.\n"
               "The value can be between 0 and 10 FlatCAM units.")
               "The value can be between 0 and 10 FlatCAM units.")
         )
         )
-        grid3.addWidget(self.ncc_offset_label, 9, 0)
         self.ncc_offset_spinner = FCDoubleSpinner()
         self.ncc_offset_spinner = FCDoubleSpinner()
         self.ncc_offset_spinner.set_range(0.00, 10.00)
         self.ncc_offset_spinner.set_range(0.00, 10.00)
         self.ncc_offset_spinner.set_precision(4)
         self.ncc_offset_spinner.set_precision(4)
@@ -419,7 +440,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
         else:
         else:
             self.ncc_offset_spinner.setSingleStep(0.01)
             self.ncc_offset_spinner.setSingleStep(0.01)
 
 
-        grid3.addWidget(self.ncc_offset_spinner, 9, 1)
+        self.grid3.addWidget(self.ncc_offset_label, 19, 0)
+        self.grid3.addWidget(self.ncc_offset_spinner, 19, 1)
 
 
         self.ncc_offset_label.hide()
         self.ncc_offset_label.hide()
         self.ncc_offset_spinner.hide()
         self.ncc_offset_spinner.hide()
@@ -436,11 +458,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
               "- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
               "- 'Reference Object' - will do non copper clearing within the area specified by another object.")
               "- 'Reference Object' - will do non copper clearing within the area specified by another object.")
         )
         )
-        grid3.addWidget(self.reference_label, 10, 0)
-        grid3.addWidget(self.reference_radio, 10, 1)
+        self.grid3.addWidget(self.reference_label, 20, 0)
+        self.grid3.addWidget(self.reference_radio, 20, 1)
 
 
         form1 = QtWidgets.QFormLayout()
         form1 = QtWidgets.QFormLayout()
-        self.tools_box.addLayout(form1)
+        self.grid3.addLayout(form1, 21, 0, 1, 2)
 
 
         self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
         self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
         self.box_combo_type_label.setToolTip(
         self.box_combo_type_label.setToolTip(
@@ -468,6 +490,18 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.box_combo_type.hide()
         self.box_combo_type.hide()
         self.box_combo_type_label.hide()
         self.box_combo_type_label.hide()
 
 
+        separator_line2 = QtWidgets.QFrame()
+        separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.grid3.addWidget(separator_line2, 22, 0, 1, 2)
+
+        self.apply_param_to_all = FCButton(_("Apply parameters to all tools"))
+        self.apply_param_to_all.setToolTip(
+            _("The parameters in the current form will be applied\n"
+              "on all the tools from the Tool Table.")
+        )
+        self.grid3.addWidget(self.apply_param_to_all, 23, 0, 1, 2)
+
         self.generate_ncc_button = QtWidgets.QPushButton(_('Generate Geometry'))
         self.generate_ncc_button = QtWidgets.QPushButton(_('Generate Geometry'))
         self.generate_ncc_button.setToolTip(
         self.generate_ncc_button.setToolTip(
             _("Create the Geometry Object\n"
             _("Create the Geometry Object\n"
@@ -573,11 +607,265 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
         self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
         self.reset_button.clicked.connect(self.set_tool_ui)
         self.reset_button.clicked.connect(self.set_tool_ui)
 
 
+        self.tools_table.currentItemChanged.connect(self.on_row_selection_change)
+
     def on_type_obj_index_changed(self, index):
     def on_type_obj_index_changed(self, index):
         obj_type = self.type_obj_combo.currentIndex()
         obj_type = self.type_obj_combo.currentIndex()
         self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
         self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
         self.object_combo.setCurrentIndex(0)
         self.object_combo.setCurrentIndex(0)
 
 
+    def on_row_selection_change(self):
+        self.update_ui()
+
+    def update_ui(self, row=None):
+        self.ui_disconnect()
+
+        if row is None:
+            try:
+                current_row = self.tools_table.currentRow()
+            except Exception:
+                current_row = 0
+        else:
+            current_row = row
+
+        if current_row < 0:
+            current_row = 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 type(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
+
+        # 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"), tooluid)
+        )
+
+        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.update_form(form_value_storage)
+                        if key == 'offset_value':
+                            # update the offset value in the entry even if the entry is hidden
+                            self.ncc_offset_spinner.set_value(tooluid_value[key])
+
+                        if key == 'tool_type' and value == 'V':
+                            self.update_cutz()
+        except Exception as e:
+            log.debug("FlatCAMObj ---> update_ui() " + str(e))
+        self.ui_connect()
+
+    def update_cutz(self):
+        vdia = float(self.tipdia_entry.get_value())
+        half_vangle = float(self.tipangle_entry.get_value()) / 2
+
+        row = self.tools_table.currentRow()
+        tool_uid_item = self.tools_table.item(row, 3)
+        if tool_uid_item is None:
+            return
+        tool_uid = int(tool_uid_item.text())
+
+        tool_dia_item = self.tools_table.item(row, 1)
+        if tool_dia_item is None:
+            return
+        tooldia = float(tool_dia_item.text())
+
+        new_cutz = (tooldia - vdia) / (2 * math.tan(math.radians(half_vangle)))
+        new_cutz = float('%.*f' % (self.decimals, new_cutz)) * -1.0   # this value has to be negative
+
+        self.cutz_entry.set_value(new_cutz)
+
+        # store the new CutZ value into storage (self.ncc_tools)
+        for tooluid_key, tooluid_value in self.ncc_tools.items():
+            if int(tooluid_key) == tool_uid:
+                tooluid_value['data']['cutz'] = new_cutz
+
+    def on_tooltable_cellwidget_change(self):
+        cw = self.sender()
+        cw_index = self.tools_table.indexAt(cw.pos())
+        cw_row = cw_index.row()
+        cw_col = cw_index.column()
+        current_uid = int(self.tools_table.item(cw_row, 3).text())
+
+        # store the text of the cellWidget that changed it's index in the self.tools
+        for tooluid_key, tooluid_value in self.ncc_tools.items():
+            if int(tooluid_key) == current_uid:
+                cb_txt = cw.currentText()
+                if cw_col == 2:
+                    tooluid_value['tool_type'] = cb_txt
+
+    def update_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(str(e))
+
+        # this is done here because those buttons control through OptionalInputSelection if some entry's are Enabled
+        # or not. But due of using the ui_disconnect() status is no longer updated and I had to do it here
+        self.ui.ois_dwell_geo.on_cb_change()
+        self.ui.ois_mpass_geo.on_cb_change()
+        self.ui.ois_tcz_geo.on_cb_change()
+
+    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.ui_disconnect()
+
+        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()
+
+        offset_item = self.ncc_choice_offset_cb.get_value()
+        offset_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 == 'tooldia':
+                    temp_dia[key] = tooldia_item
+                # update the 'offset', 'type' and 'tool_type' sections
+                if key == 'offset':
+                    temp_dia[key] = offset_item
+                if key == 'type':
+                    temp_dia[key] = type_item
+                if key == 'offset_value':
+                    temp_dia[key] = offset_value_item
+
+                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()
+
+                if key == 'solid_geometry':
+                    temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+
+                temp_tools[tooluid_key] = deepcopy(temp_dia)
+
+        self.ncc_tools.clear()
+        self.ncc_tools = deepcopy(temp_tools)
+        temp_tools.clear()
+
+        self.ui_connect()
+
+    def gui_form_to_storage(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.gui_form_to_storage() --> no tool in Tools Table, aborting.")
+            return
+
+        self.ui_disconnect()
+        widget_changed = self.sender()
+        try:
+            widget_idx = self.grid3.indexOf(widget_changed)
+        except Exception as e:
+            return
+
+        # those are the indexes for the V-Tip Dia and V-Tip Angle, if edited calculate the new Cut Z
+        if widget_idx == 1 or widget_idx == 3:
+            self.update_cutz()
+
+        # the original connect() function of the OptionalInputSelection is no longer working because of the
+        # ui_diconnect() so I use this 'hack'
+        # if isinstance(widget_changed, FCCheckBox):
+        #     if widget_changed.text() == 'Multi-Depth:':
+        #         self.ui.ois_mpass_geo.on_cb_change()
+        #
+        #     if widget_changed.text() == 'Tool change':
+        #         self.ui.ois_tcz_geo.on_cb_change()
+        #
+        #     if widget_changed.text() == 'Dwell:':
+        #         self.ui.ois_dwell_geo.on_cb_change()
+
+        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())
+        tool_type_item = self.tools_table.cellWidget(row, 2).currentText()
+        operation_type_item = self.ui.geo_tools_table.cellWidget(row, 4).currentText()
+
+        offset_item = self.ncc_choice_offset_cb.get_value()
+        offset_value_item = float(self.ncc_offset_spinner.get_value())
+
+        tooluid_item = int(self.ui.geo_tools_table.item(row, 3).text())
+
+        # 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.tools.items():
+            if int(tooluid_key) == tooluid_item:
+                for key, value in tooluid_value.items():
+                    if key == 'tooldia':
+                        temp_dia[key] = tooldia_item
+                    # update the 'offset', 'type' and 'tool_type' sections
+                    if key == 'offset':
+                        temp_dia[key] = offset_item
+                    if key == 'tool_type':
+                        temp_dia[key] = tool_type_item
+                    if key == 'offset_value':
+                        temp_dia[key] = offset_value_item
+
+                    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()
+
+                    if key == 'solid_geometry':
+                        temp_dia[key] = deepcopy(self.ncc_tools[tooluid_key]['solid_geometry'])
+
+                    temp_tools[tooluid_key] = deepcopy(temp_dia)
+            else:
+                temp_tools[tooluid_key] = deepcopy(tooluid_value)
+
+        self.ncc_tools.clear()
+        self.ncc_tools = deepcopy(temp_tools)
+        temp_tools.clear()
+        self.ui_connect()
+
     def on_add_tool_by_key(self):
     def on_add_tool_by_key(self):
         tool_add_popup = FCInputDialog(title='%s...' % _("New Tool"),
         tool_add_popup = FCInputDialog(title='%s...' % _("New Tool"),
                                        text='%s:' % _('Enter a Tool Diameter'),
                                        text='%s:' % _('Enter a Tool Diameter'),