Просмотр исходного кода

Merged in marius_stanciu/flatcam_beta/Beta (pull request #293)

Beta - NCC Tool MAY NOT work
Marius Stanciu 6 лет назад
Родитель
Сommit
5a2ae4877c

+ 82 - 25
FlatCAMApp.py

@@ -1631,7 +1631,7 @@ class App(QtCore.QObject):
         self.toggle_units_ignore = False
         self.toggle_units_ignore = False
 
 
         # #############################################################################
         # #############################################################################
-        # ########################## LOAD POSTPROCESSORS ##############################
+        # ########################## LOAD PREPROCESSORS ###############################
         # #############################################################################
         # #############################################################################
 
 
         # a dictionary that have as keys the name of the preprocessor files and the value is the class from
         # a dictionary that have as keys the name of the preprocessor files and the value is the class from
@@ -1846,7 +1846,7 @@ class App(QtCore.QObject):
         # signal to be called when the app is quiting
         # signal to be called when the app is quiting
         self.app_quit.connect(self.quit_application, type=Qt.QueuedConnection)
         self.app_quit.connect(self.quit_application, type=Qt.QueuedConnection)
         self.message.connect(self.message_dialog)
         self.message.connect(self.message_dialog)
-        self.progress.connect(self.set_progress_bar)
+        # self.progress.connect(self.set_progress_bar)
 
 
         # signals that are emitted when object state changes
         # signals that are emitted when object state changes
         self.object_created.connect(self.on_object_created)
         self.object_created.connect(self.on_object_created)
@@ -2464,7 +2464,10 @@ class App(QtCore.QObject):
         self.fiducial_tool = None
         self.fiducial_tool = None
 
 
         # always install tools only after the shell is initialized because the self.inform.emit() depends on shell
         # always install tools only after the shell is initialized because the self.inform.emit() depends on shell
-        self.install_tools()
+        try:
+            self.install_tools()
+        except AttributeError:
+            pass
 
 
         # ##################################################################################
         # ##################################################################################
         # ########################### SETUP RECENT ITEMS ###################################
         # ########################### SETUP RECENT ITEMS ###################################
@@ -2628,7 +2631,10 @@ class App(QtCore.QObject):
         # Storage for shapes, storage that can be used by FlatCAm tools for utility geometry
         # Storage for shapes, storage that can be used by FlatCAm tools for utility geometry
         # VisPy visuals
         # VisPy visuals
         if self.is_legacy is False:
         if self.is_legacy is False:
-            self.tool_shapes = ShapeCollection(parent=self.plotcanvas.view.scene, layers=1)
+            try:
+                self.tool_shapes = ShapeCollection(parent=self.plotcanvas.view.scene, layers=1)
+            except AttributeError:
+                self.tool_shapes = None
         else:
         else:
             from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
             from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
             self.tool_shapes = ShapeCollectionLegacy(obj=self, app=self, name="tool")
             self.tool_shapes = ShapeCollectionLegacy(obj=self, app=self, name="tool")
@@ -2639,9 +2645,20 @@ class App(QtCore.QObject):
 
 
         # watch out for the position of the editors instantiation ... if it is done before a save of the default values
         # watch out for the position of the editors instantiation ... if it is done before a save of the default values
         # at the first launch of the App , the editors will not be functional.
         # at the first launch of the App , the editors will not be functional.
-        self.geo_editor = FlatCAMGeoEditor(self, disabled=True)
-        self.exc_editor = FlatCAMExcEditor(self)
-        self.grb_editor = FlatCAMGrbEditor(self)
+        try:
+            self.geo_editor = FlatCAMGeoEditor(self, disabled=True)
+        except AttributeError:
+            pass
+
+        try:
+            self.exc_editor = FlatCAMExcEditor(self)
+        except AttributeError:
+            pass
+
+        try:
+            self.grb_editor = FlatCAMGrbEditor(self)
+        except AttributeError:
+            pass
         self.log.debug("Finished adding FlatCAM Editor's.")
         self.log.debug("Finished adding FlatCAM Editor's.")
 
 
         self.set_ui_title(name=_("New Project - Not saved"))
         self.set_ui_title(name=_("New Project - Not saved"))
@@ -3136,7 +3153,11 @@ class App(QtCore.QObject):
         self.ui.menutoolshell.triggered.connect(self.on_toggle_shell)
         self.ui.menutoolshell.triggered.connect(self.on_toggle_shell)
 
 
         # third install all of them
         # third install all of them
-        self.install_tools()
+        try:
+            self.install_tools()
+        except AttributeError:
+            pass
+
         self.log.debug("Tools are initialized.")
         self.log.debug("Tools are initialized.")
 
 
     # def parse_system_fonts(self):
     # def parse_system_fonts(self):
@@ -6625,7 +6646,7 @@ class App(QtCore.QObject):
         self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT'])
         self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT'])
 
 
     def on_workspace(self):
     def on_workspace(self):
-        if self.ui.general_defaults_form.general_gui_group.workspace_cb.get_value():
+        if self.ui.general_defaults_form.general_app_set_group.workspace_cb.get_value():
             self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT'])
             self.plotcanvas.draw_workspace(workspace_size=self.defaults['global_workspaceT'])
         else:
         else:
             self.plotcanvas.delete_workspace()
             self.plotcanvas.delete_workspace()
@@ -6633,13 +6654,13 @@ class App(QtCore.QObject):
         # self.save_defaults(silent=True)
         # self.save_defaults(silent=True)
 
 
     def on_workspace_toggle(self):
     def on_workspace_toggle(self):
-        state = False if self.ui.general_defaults_form.general_gui_group.workspace_cb.get_value() else True
+        state = False if self.ui.general_defaults_form.general_app_set_group.workspace_cb.get_value() else True
         try:
         try:
-            self.ui.general_defaults_form.general_gui_group.workspace_cb.stateChanged.disconnect(self.on_workspace)
+            self.ui.general_defaults_form.general_app_set_group.workspace_cb.stateChanged.disconnect(self.on_workspace)
         except TypeError:
         except TypeError:
             pass
             pass
-        self.ui.general_defaults_form.general_gui_group.workspace_cb.set_value(state)
-        self.ui.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace)
+        self.ui.general_defaults_form.general_app_set_group.workspace_cb.set_value(state)
+        self.ui.general_defaults_form.general_app_set_group.workspace_cb.stateChanged.connect(self.on_workspace)
         self.on_workspace()
         self.on_workspace()
 
 
     def on_layout(self, index=None, lay=None):
     def on_layout(self, index=None, lay=None):
@@ -10874,13 +10895,11 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
 
             self.new_object(obj_type, name, obj_init, autoselected=False)
             self.new_object(obj_type, name, obj_init, autoselected=False)
-            self.progress.emit(20)
             # Register recent file
             # Register recent file
             self.file_opened.emit("dxf", filename)
             self.file_opened.emit("dxf", filename)
 
 
             # GUI feedback
             # GUI feedback
             self.inform.emit('[success] %s: %s' % (_("Opened"), filename))
             self.inform.emit('[success] %s: %s' % (_("Opened"), filename))
-            self.progress.emit(100)
 
 
     def open_gerber(self, filename, outname=None):
     def open_gerber(self, filename, outname=None):
         """
         """
@@ -10956,7 +10975,6 @@ class App(QtCore.QObject):
 
 
         # How the object should be initialized
         # How the object should be initialized
         def obj_init(excellon_obj, app_obj):
         def obj_init(excellon_obj, app_obj):
-            # self.progress.emit(20)
 
 
             try:
             try:
                 ret = excellon_obj.parse_file(filename=filename)
                 ret = excellon_obj.parse_file(filename=filename)
@@ -10969,7 +10987,6 @@ class App(QtCore.QObject):
                 app_obj.inform.emit('[ERROR_NOTCL] %s: %s' %
                 app_obj.inform.emit('[ERROR_NOTCL] %s: %s' %
                                     (_("Cannot open file"), filename))
                                     (_("Cannot open file"), filename))
                 log.debug("Could not open Excellon object.")
                 log.debug("Could not open Excellon object.")
-                self.progress.emit(0)  # TODO: self and app_bjj mixed
                 return "fail"
                 return "fail"
             except Exception:
             except Exception:
                 msg = '[ERROR_NOTCL] %s' % \
                 msg = '[ERROR_NOTCL] %s' % \
@@ -11611,6 +11628,11 @@ class App(QtCore.QObject):
 
 
         }
         }
 
 
+        try:
+            image_opener = self.image_tool.import_image
+        except AttributeError:
+            image_opener = None
+
         openers = {
         openers = {
             'gerber': lambda fname: self.worker_task.emit({'fcn': self.open_gerber, 'params': [fname]}),
             'gerber': lambda fname: self.worker_task.emit({'fcn': self.open_gerber, 'params': [fname]}),
             'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}),
             'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}),
@@ -11621,7 +11643,7 @@ class App(QtCore.QObject):
             'project': self.open_project,
             'project': self.open_project,
             'svg': self.import_svg,
             'svg': self.import_svg,
             'dxf': self.import_dxf,
             'dxf': self.import_dxf,
-            'image': self.image_tool.import_image,
+            'image': image_opener,
             'pdf': lambda fname: self.worker_task.emit({'fcn': self.pdf_tool.open_pdf, 'params': [fname]})
             'pdf': lambda fname: self.worker_task.emit({'fcn': self.pdf_tool.open_pdf, 'params': [fname]})
         }
         }
 
 
@@ -11950,7 +11972,7 @@ class App(QtCore.QObject):
 
 
     def on_plotcanvas_setup(self, container=None):
     def on_plotcanvas_setup(self, container=None):
         """
         """
-        This is doing the setup for the plot area (VisPy canvas)
+        This is doing the setup for the plot area (canvas)
 
 
         :param container: widget where to install the canvas
         :param container: widget where to install the canvas
         :return: None
         :return: None
@@ -11961,7 +11983,18 @@ class App(QtCore.QObject):
             plot_container = self.ui.right_layout
             plot_container = self.ui.right_layout
 
 
         if self.is_legacy is False:
         if self.is_legacy is False:
-            self.plotcanvas = PlotCanvas(plot_container, self)
+            try:
+                self.plotcanvas = PlotCanvas(plot_container, self)
+            except Exception as er:
+                msg_txt = traceback.format_exc()
+                log.debug("App.on_plotcanvas_setup() failed -> %s" % str(er))
+                log.debug("OpenGL canvas initialization failed with the following error.\n" + msg_txt)
+                msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n")
+                msg += _("OpenGL canvas initialization failed. HW or HW configuration not supported."
+                         "Change the graphic engine to Legacy(2D) in Edit -> Preferences -> General tab.\n\n")
+                msg += msg_txt
+                self.inform.emit(msg)
+                return 'fail'
         else:
         else:
             self.plotcanvas = PlotCanvasLegacy(plot_container, self)
             self.plotcanvas = PlotCanvasLegacy(plot_container, self)
 
 
@@ -12044,8 +12077,7 @@ class App(QtCore.QObject):
         log.debug("App.on_enable_sel_plot()")
         log.debug("App.on_enable_sel_plot()")
         object_list = self.collection.get_selected()
         object_list = self.collection.get_selected()
         self.enable_plots(objects=object_list)
         self.enable_plots(objects=object_list)
-        self.inform.emit('[success] %s' %
-                         _("Selected plots enabled..."))
+        self.inform.emit('[success] %s' % _("Selected plots enabled..."))
 
 
     def on_disable_sel_plots(self):
     def on_disable_sel_plots(self):
         log.debug("App.on_disable_sel_plot()")
         log.debug("App.on_disable_sel_plot()")
@@ -12053,8 +12085,7 @@ class App(QtCore.QObject):
         # self.inform.emit(_("Disabling plots ..."))
         # self.inform.emit(_("Disabling plots ..."))
         object_list = self.collection.get_selected()
         object_list = self.collection.get_selected()
         self.disable_plots(objects=object_list)
         self.disable_plots(objects=object_list)
-        self.inform.emit('[success] %s' %
-                         _("Selected plots disabled..."))
+        self.inform.emit('[success] %s' % _("Selected plots disabled..."))
 
 
     def enable_plots(self, objects):
     def enable_plots(self, objects):
         """
         """
@@ -12070,6 +12101,20 @@ class App(QtCore.QObject):
             if obj.options['plot'] is False:
             if obj.options['plot'] is False:
                 obj.options.set_change_callback(lambda x: None)
                 obj.options.set_change_callback(lambda x: None)
                 obj.options['plot'] = True
                 obj.options['plot'] = True
+                try:
+                    # only the Gerber obj has on_plot_cb_click() method
+                    obj.ui.plot_cb.stateChanged.disconnect(obj.on_plot_cb_click)
+                    # disable this cb while disconnected,
+                    # in case the operation takes time the user is not allowed to change it
+                    obj.ui.plot_cb.setDisabled(True)
+                except AttributeError:
+                    pass
+                obj.set_form_item("plot")
+                try:
+                    obj.ui.plot_cb.stateChanged.connect(obj.on_plot_cb_click)
+                    obj.ui.plot_cb.setDisabled(False)
+                except AttributeError:
+                    pass
                 obj.options.set_change_callback(obj.on_options_change)
                 obj.options.set_change_callback(obj.on_options_change)
 
 
         def worker_task(objs):
         def worker_task(objs):
@@ -12104,6 +12149,18 @@ class App(QtCore.QObject):
             if obj.options['plot'] is True:
             if obj.options['plot'] is True:
                 obj.options.set_change_callback(lambda x: None)
                 obj.options.set_change_callback(lambda x: None)
                 obj.options['plot'] = False
                 obj.options['plot'] = False
+                try:
+                    # only the Gerber obj has on_plot_cb_click() method
+                    obj.ui.plot_cb.stateChanged.disconnect(obj.on_plot_cb_click)
+                    obj.ui.plot_cb.setDisabled(True)
+                except AttributeError:
+                    pass
+                obj.set_form_item("plot")
+                try:
+                    obj.ui.plot_cb.stateChanged.connect(obj.on_plot_cb_click)
+                    obj.ui.plot_cb.setDisabled(False)
+                except AttributeError:
+                    pass
                 obj.options.set_change_callback(obj.on_options_change)
                 obj.options.set_change_callback(obj.on_options_change)
 
 
         try:
         try:
@@ -12242,7 +12299,7 @@ class App(QtCore.QObject):
             try:
             try:
                 self.collection.get_active().read_form()
                 self.collection.get_active().read_form()
             except Exception as e:
             except Exception as e:
-                self.log.debug("There was no active object. %s" % str(e))
+                self.log.debug("save_project() --> There was no active object. Skipping read_form. %s" % str(e))
                 pass
                 pass
 
 
             # Serialize the whole project
             # Serialize the whole project

+ 2 - 17
FlatCAMObj.py

@@ -1811,7 +1811,6 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             visibility = kwargs['visible']
             visibility = kwargs['visible']
 
 
         with self.app.proc_container.new(_("Plotting Apertures")):
         with self.app.proc_container.new(_("Plotting Apertures")):
-            self.app.progress.emit(30)
 
 
             def job_thread(app_obj):
             def job_thread(app_obj):
                 try:
                 try:
@@ -3080,7 +3079,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         def geo_init(geo_obj, app_obj):
         def geo_init(geo_obj, app_obj):
             assert isinstance(geo_obj, FlatCAMGeometry), \
             assert isinstance(geo_obj, FlatCAMGeometry), \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
-            app_obj.progress.emit(20)
 
 
             # ## Add properties to the object
             # ## Add properties to the object
 
 
@@ -3110,7 +3108,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         if use_thread:
         if use_thread:
             def geo_thread(app_obj):
             def geo_thread(app_obj):
                 app_obj.new_object("geometry", outname, geo_init, plot=plot)
                 app_obj.new_object("geometry", outname, geo_init, plot=plot)
-                app_obj.progress.emit(100)
 
 
             # Create a promise with the new name
             # Create a promise with the new name
             self.app.collection.promise(outname)
             self.app.collection.promise(outname)
@@ -3173,7 +3170,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         def geo_init(geo_obj, app_obj):
         def geo_init(geo_obj, app_obj):
             assert isinstance(geo_obj, FlatCAMGeometry), \
             assert isinstance(geo_obj, FlatCAMGeometry), \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
-            app_obj.progress.emit(20)
 
 
             # ## Add properties to the object
             # ## Add properties to the object
 
 
@@ -3217,7 +3213,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         if use_thread:
         if use_thread:
             def geo_thread(app_obj):
             def geo_thread(app_obj):
                 app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
                 app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
-                app_obj.progress.emit(100)
 
 
             # Create a promise with the new name
             # Create a promise with the new name
             self.app.collection.promise(outname)
             self.app.collection.promise(outname)
@@ -3358,7 +3353,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         def job_thread(app_obj):
         def job_thread(app_obj):
             with self.app.proc_container.new(_("Generating CNC Code")):
             with self.app.proc_container.new(_("Generating CNC Code")):
                 app_obj.new_object("cncjob", job_name, job_init)
                 app_obj.new_object("cncjob", job_name, job_init)
-                app_obj.progress.emit(100)
 
 
         # Create promise for the new name.
         # Create promise for the new name.
         self.app.collection.promise(job_name)
         self.app.collection.promise(job_name)
@@ -5425,11 +5419,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             # Propagate options
             # Propagate options
             job_obj.options["tooldia"] = tooldia
             job_obj.options["tooldia"] = tooldia
 
 
-            app_obj.progress.emit(20)
-
             job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"]
             job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"]
             job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"]
             job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"]
-            app_obj.progress.emit(40)
 
 
             job_obj.options['type'] = 'Geometry'
             job_obj.options['type'] = 'Geometry'
             job_obj.options['tool_dia'] = tooldia
             job_obj.options['tool_dia'] = tooldia
@@ -5459,24 +5450,18 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                 pp_geometry_name=ppname_g
                 pp_geometry_name=ppname_g
             )
             )
 
 
-            app_obj.progress.emit(50)
             # tell gcode_parse from which point to start drawing the lines depending on what kind of object is the
             # tell gcode_parse from which point to start drawing the lines depending on what kind of object is the
             # source of gcode
             # source of gcode
             job_obj.toolchange_xy_type = "geometry"
             job_obj.toolchange_xy_type = "geometry"
             job_obj.gcode_parse()
             job_obj.gcode_parse()
-            self.app.inform.emit('[success] %s' %
-                                 _("Finished G-Code processing..."))
-
-            app_obj.progress.emit(80)
+            self.app.inform.emit('[success] %s' % _("Finished G-Code processing..."))
 
 
         if use_thread:
         if use_thread:
             # To be run in separate thread
             # To be run in separate thread
             def job_thread(app_obj):
             def job_thread(app_obj):
                 with self.app.proc_container.new(_("Generating CNC Code")):
                 with self.app.proc_container.new(_("Generating CNC Code")):
                     app_obj.new_object("cncjob", outname, job_init, plot=plot)
                     app_obj.new_object("cncjob", outname, job_init, plot=plot)
-                    app_obj.inform.emit('[success] %s: %s' %
-                                        (_("CNCjob created")), outname)
-                    app_obj.progress.emit(100)
+                    app_obj.inform.emit('[success] %s: %s' % (_("CNCjob created")), outname)
 
 
             # Create a promise with the name
             # Create a promise with the name
             self.app.collection.promise(outname)
             self.app.collection.promise(outname)

+ 18 - 0
README.md

@@ -9,11 +9,29 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+8.01.2019
+
+- working in NCC Tool
+- selected rows in the Tools Tables will stay colored in blue after loosing focus instead of the default gray
+- in NCC Tool the Tool name in the Parameters section will be the Tool ID in the Tool Table
+- added an exception catch in case the plotcanvas init failed for the OpenGL graphic engine and warn user about what happened
+
+7.01.2019
+
+- solved issue #368 - when using the Enable/Disable prj context menu entries the plotted status is not updated in the object properties
+- updates in NCC Tool
+
+6.01.2019
+
+- working on new NCC Tool
+
 2.01.2020
 2.01.2020
 
 
 - started to rework the NCC Tool GUI in preparation for adding a Tool DB feature
 - started to rework the NCC Tool GUI in preparation for adding a Tool DB feature
 - for auto-completer, now clicking an entry in the completer popup will select that entry and insert it
 - for auto-completer, now clicking an entry in the completer popup will select that entry and insert it
 - made available only for Linux and Windows (not OSX) the starting of the thread that checks if another instance of FlatCAM is already running at the launch of FLatCAM
 - made available only for Linux and Windows (not OSX) the starting of the thread that checks if another instance of FlatCAM is already running at the launch of FLatCAM
+- modified Toggle Workspace function to work in the new Preferences UI configuration
+- cleaned the app from progress signal usage since it is not used anymore
 
 
 1.01.2020
 1.01.2020
 
 

+ 1 - 5
flatcamEditors/FlatCAMExcEditor.py

@@ -3305,7 +3305,6 @@ class FlatCAMExcEditor(QtCore.QObject):
         # How the object should be initialized
         # How the object should be initialized
         def obj_init(excellon_obj, app_obj):
         def obj_init(excellon_obj, app_obj):
 
 
-            # self.progress.emit(20)
             excellon_obj.drills = deepcopy(new_drills)
             excellon_obj.drills = deepcopy(new_drills)
             excellon_obj.tools = deepcopy(new_tools)
             excellon_obj.tools = deepcopy(new_tools)
             excellon_obj.slots = deepcopy(new_slots)
             excellon_obj.slots = deepcopy(new_slots)
@@ -3335,12 +3334,9 @@ class FlatCAMExcEditor(QtCore.QObject):
                                                                   use_thread=False)
                                                                   use_thread=False)
             except Exception as e:
             except Exception as e:
                 log.error("Error on Edited object creation: %s" % str(e))
                 log.error("Error on Edited object creation: %s" % str(e))
-                self.app.progress.emit(100)
                 return
                 return
 
 
-            self.app.inform.emit('[success] %s' %
-                                 _("Excellon editing finished."))
-            # self.progress.emit(100)
+            self.app.inform.emit('[success] %s' % _("Excellon editing finished."))
 
 
     def on_tool_select(self, tool):
     def on_tool_select(self, tool):
         """
         """

+ 8 - 34
flatcamEditors/FlatCAMGeoEditor.py

@@ -1272,8 +1272,6 @@ class TransformEditorTool(FlatCAMTool):
                     xmaximal = max(xmaxlist)
                     xmaximal = max(xmaxlist)
                     ymaximal = max(ymaxlist)
                     ymaximal = max(ymaxlist)
 
 
-                    self.app.progress.emit(20)
-
                     for sel_sha in shape_list:
                     for sel_sha in shape_list:
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)
@@ -1284,11 +1282,7 @@ class TransformEditorTool(FlatCAMTool):
 
 
                     # self.draw_app.transform_complete.emit()
                     # self.draw_app.transform_complete.emit()
 
 
-                    self.app.inform.emit('[success] %s' %
-                                         _("Done. Rotate completed."))
-
-                    self.app.progress.emit(100)
-
+                    self.app.inform.emit('[success] %s' % _("Done. Rotate completed."))
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Rotation action was not executed"), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Rotation action was not executed"), str(e)))
                     return
                     return
@@ -1329,8 +1323,6 @@ class TransformEditorTool(FlatCAMTool):
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)
 
 
-                    self.app.progress.emit(20)
-
                     # execute mirroring
                     # execute mirroring
                     for sha in shape_list:
                     for sha in shape_list:
                         if axis is 'X':
                         if axis is 'X':
@@ -1347,8 +1339,6 @@ class TransformEditorTool(FlatCAMTool):
                     #
                     #
                     # self.draw_app.transform_complete.emit()
                     # self.draw_app.transform_complete.emit()
 
 
-                    self.app.progress.emit(100)
-
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Flip action was not executed"), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Flip action was not executed"), str(e)))
                     return
                     return
@@ -1375,8 +1365,6 @@ class TransformEditorTool(FlatCAMTool):
                     xminimal = min(xminlist)
                     xminimal = min(xminlist)
                     yminimal = min(yminlist)
                     yminimal = min(yminlist)
 
 
-                    self.app.progress.emit(20)
-
                     for sha in shape_list:
                     for sha in shape_list:
                         if axis is 'X':
                         if axis is 'X':
                             sha.skew(num, 0, point=(xminimal, yminimal))
                             sha.skew(num, 0, point=(xminimal, yminimal))
@@ -1388,12 +1376,9 @@ class TransformEditorTool(FlatCAMTool):
                     #
                     #
                     # self.draw_app.transform_complete.emit()
                     # self.draw_app.transform_complete.emit()
                     if axis == 'X':
                     if axis == 'X':
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Skew on the X axis done'))
+                        self.app.inform.emit('[success] %s...' % _('Skew on the X axis done'))
                     else:
                     else:
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Skew on the Y axis done'))
-                    self.app.progress.emit(100)
+                        self.app.inform.emit('[success] %s...' % _('Skew on the Y axis done'))
 
 
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Skew action was not executed"), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Skew action was not executed"), str(e)))
@@ -1407,8 +1392,7 @@ class TransformEditorTool(FlatCAMTool):
         ymaxlist = []
         ymaxlist = []
 
 
         if not shape_list:
         if not shape_list:
-            self.app.inform.emit('[WARNING_NOTCL] %s' %
-                                 _("No shape selected. Please Select a shape to scale!"))
+            self.app.inform.emit('[WARNING_NOTCL] %s' % _("No shape selected. Please Select a shape to scale!"))
             return
             return
         else:
         else:
             with self.app.proc_container.new(_("Applying Scale")):
             with self.app.proc_container.new(_("Applying Scale")):
@@ -1427,8 +1411,6 @@ class TransformEditorTool(FlatCAMTool):
                     xmaximal = max(xmaxlist)
                     xmaximal = max(xmaxlist)
                     ymaximal = max(ymaxlist)
                     ymaximal = max(ymaxlist)
 
 
-                    self.app.progress.emit(20)
-
                     if point is None:
                     if point is None:
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)
@@ -1445,12 +1427,9 @@ class TransformEditorTool(FlatCAMTool):
                     # self.draw_app.transform_complete.emit()
                     # self.draw_app.transform_complete.emit()
 
 
                     if str(axis) == 'X':
                     if str(axis) == 'X':
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Scale on the X axis done'))
+                        self.app.inform.emit('[success] %s...' % _('Scale on the X axis done'))
                     else:
                     else:
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Scale on the Y axis done'))
-                    self.app.progress.emit(100)
+                        self.app.inform.emit('[success] %s...' % _('Scale on the Y axis done'))
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Scale action was not executed"), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Scale action was not executed"), str(e)))
                     return
                     return
@@ -1467,8 +1446,6 @@ class TransformEditorTool(FlatCAMTool):
         else:
         else:
             with self.app.proc_container.new(_("Applying Offset")):
             with self.app.proc_container.new(_("Applying Offset")):
                 try:
                 try:
-                    self.app.progress.emit(20)
-
                     for sha in shape_list:
                     for sha in shape_list:
                         if axis is 'X':
                         if axis is 'X':
                             sha.offset((num, 0))
                             sha.offset((num, 0))
@@ -1477,12 +1454,9 @@ class TransformEditorTool(FlatCAMTool):
                         self.draw_app.replot()
                         self.draw_app.replot()
 
 
                     if axis == 'X':
                     if axis == 'X':
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Offset on the X axis done'))
+                        self.app.inform.emit('[success] %s...' % _('Offset on the X axis done'))
                     else:
                     else:
-                        self.app.inform.emit('[success] %s...' %
-                                             _('Offset on the Y axis done'))
-                    self.app.progress.emit(100)
+                        self.app.inform.emit('[success] %s...' % _('Offset on the Y axis done'))
 
 
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Offset action was not executed"), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Offset action was not executed"), str(e)))

+ 2 - 16
flatcamEditors/FlatCAMGrbEditor.py

@@ -5761,7 +5761,6 @@ class TransformEditorTool(FlatCAMTool):
                 xmaximal = max(xmaxlist)
                 xmaximal = max(xmaxlist)
                 ymaximal = max(ymaxlist)
                 ymaximal = max(ymaxlist)
 
 
-                self.app.progress.emit(20)
                 px = 0.5 * (xminimal + xmaximal)
                 px = 0.5 * (xminimal + xmaximal)
                 py = 0.5 * (yminimal + ymaximal)
                 py = 0.5 * (yminimal + ymaximal)
 
 
@@ -5775,12 +5774,9 @@ class TransformEditorTool(FlatCAMTool):
                         sel_el['clear'] = affinity.rotate(sel_el['clear'], angle=-num, origin=(px, py))
                         sel_el['clear'] = affinity.rotate(sel_el['clear'], angle=-num, origin=(px, py))
                 self.draw_app.plot_all()
                 self.draw_app.plot_all()
 
 
-                self.app.inform.emit('[success] %s' %
-                                     _("Done. Rotate completed."))
-                self.app.progress.emit(100)
+                self.app.inform.emit('[success] %s' % _("Done. Rotate completed."))
             except Exception as e:
             except Exception as e:
-                self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
-                                     (_("Rotation action was not executed."), str(e)))
+                self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Rotation action was not executed."), str(e)))
                 return
                 return
 
 
     def on_flip(self, axis):
     def on_flip(self, axis):
@@ -5827,8 +5823,6 @@ class TransformEditorTool(FlatCAMTool):
                     px = 0.5 * (xminimal + xmaximal)
                     px = 0.5 * (xminimal + xmaximal)
                     py = 0.5 * (yminimal + ymaximal)
                     py = 0.5 * (yminimal + ymaximal)
 
 
-                self.app.progress.emit(20)
-
                 # execute mirroring
                 # execute mirroring
                 for sel_el_shape in elem_list:
                 for sel_el_shape in elem_list:
                     sel_el = sel_el_shape.geo
                     sel_el = sel_el_shape.geo
@@ -5851,8 +5845,6 @@ class TransformEditorTool(FlatCAMTool):
                         self.app.inform.emit('[success] %s...' %
                         self.app.inform.emit('[success] %s...' %
                                              _('Flip on the X axis done'))
                                              _('Flip on the X axis done'))
                 self.draw_app.plot_all()
                 self.draw_app.plot_all()
-                self.app.progress.emit(100)
-
             except Exception as e:
             except Exception as e:
                 self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
                 self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
                                      (_("Flip action was not executed."), str(e)))
                                      (_("Flip action was not executed."), str(e)))
@@ -5889,8 +5881,6 @@ class TransformEditorTool(FlatCAMTool):
                     xminimal = min(xminlist)
                     xminimal = min(xminlist)
                     yminimal = min(yminlist)
                     yminimal = min(yminlist)
 
 
-                    self.app.progress.emit(20)
-
                     for sel_el_shape in elem_list:
                     for sel_el_shape in elem_list:
                         sel_el = sel_el_shape.geo
                         sel_el = sel_el_shape.geo
                         if axis is 'X':
                         if axis is 'X':
@@ -5913,8 +5903,6 @@ class TransformEditorTool(FlatCAMTool):
                         self.app.inform.emit('[success] %s...' % _('Skew on the X axis done'))
                         self.app.inform.emit('[success] %s...' % _('Skew on the X axis done'))
                     else:
                     else:
                         self.app.inform.emit('[success] %s...' % _('Skew on the Y axis done'))
                         self.app.inform.emit('[success] %s...' % _('Skew on the Y axis done'))
-                    self.app.progress.emit(100)
-
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Skew action was not executed."), str(e)))
                     self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Skew action was not executed."), str(e)))
                     return
                     return
@@ -5958,8 +5946,6 @@ class TransformEditorTool(FlatCAMTool):
                     xmaximal = max(xmaxlist)
                     xmaximal = max(xmaxlist)
                     ymaximal = max(ymaxlist)
                     ymaximal = max(ymaxlist)
 
 
-                    self.app.progress.emit(20)
-
                     if point is None:
                     if point is None:
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)

+ 8 - 4
flatcamGUI/FlatCAMGUI.py

@@ -2221,9 +2221,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.infobar.addWidget(self.units_label)
         self.infobar.addWidget(self.units_label)
 
 
         # disabled
         # disabled
-        self.progress_bar = QtWidgets.QProgressBar()
-        self.progress_bar.setMinimum(0)
-        self.progress_bar.setMaximum(100)
+        # self.progress_bar = QtWidgets.QProgressBar()
+        # self.progress_bar.setMinimum(0)
+        # self.progress_bar.setMaximum(100)
         # infobar.addWidget(self.progress_bar)
         # infobar.addWidget(self.progress_bar)
 
 
         # ########################################################################
         # ########################################################################
@@ -2262,6 +2262,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.grb_editor_cmenu.menuAction().setVisible(False)
         self.grb_editor_cmenu.menuAction().setVisible(False)
         self.e_editor_cmenu.menuAction().setVisible(False)
         self.e_editor_cmenu.menuAction().setVisible(False)
 
 
+        # ########################################################################
+        # ######################## BUILD PREFERENCES #############################
+        # ########################################################################
+
         self.general_defaults_form = GeneralPreferencesUI(decimals=self.decimals)
         self.general_defaults_form = GeneralPreferencesUI(decimals=self.decimals)
         self.gerber_defaults_form = GerberPreferencesUI(decimals=self.decimals)
         self.gerber_defaults_form = GerberPreferencesUI(decimals=self.decimals)
         self.excellon_defaults_form = ExcellonPreferencesUI(decimals=self.decimals)
         self.excellon_defaults_form = ExcellonPreferencesUI(decimals=self.decimals)
@@ -2358,7 +2362,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         :param event: QT event to filter
         :param event: QT event to filter
         :return:
         :return:
         """
         """
-        if self.general_defaults_form.general_app_set_group.toggle_tooltips_cb.get_value() is False:
+        if self.app.defaults["global_toggle_tooltips"] is False:
             if event.type() == QtCore.QEvent.ToolTip:
             if event.type() == QtCore.QEvent.ToolTip:
                 return True
                 return True
             else:
             else:

+ 5 - 0
flatcamGUI/GUIElements.py

@@ -2006,6 +2006,11 @@ class FCTable(QtWidgets.QTableWidget):
     def __init__(self, drag_drop=False, protected_rows=None, parent=None):
     def __init__(self, drag_drop=False, protected_rows=None, parent=None):
         super(FCTable, self).__init__(parent)
         super(FCTable, self).__init__(parent)
 
 
+        palette = QtGui.QPalette()
+        palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight,
+                         palette.color(QtGui.QPalette.Active, QtGui.QPalette.Highlight))
+        self.setPalette(palette)
+
         if drag_drop:
         if drag_drop:
             self.setDragEnabled(True)
             self.setDragEnabled(True)
             self.setAcceptDrops(True)
             self.setAcceptDrops(True)

+ 10 - 15
flatcamGUI/PreferencesUI.py

@@ -1661,18 +1661,13 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         separator_line = QtWidgets.QFrame()
         separator_line = QtWidgets.QFrame()
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShape(QtWidgets.QFrame.HLine)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
         separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
-        self.layout.addWidget(separator_line)
-
-        grid1 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid1)
-        grid1.setColumnStretch(0, 0)
-        grid1.setColumnStretch(1, 1)
+        grid0.addWidget(separator_line, 31, 0, 1, 2)
 
 
         self.pdf_param_label = QtWidgets.QLabel('<B>%s:</b>' % _("Text to PDF parameters"))
         self.pdf_param_label = QtWidgets.QLabel('<B>%s:</b>' % _("Text to PDF parameters"))
         self.pdf_param_label.setToolTip(
         self.pdf_param_label.setToolTip(
             _("Used when saving text in Code Editor or in FlatCAM Document objects.")
             _("Used when saving text in Code Editor or in FlatCAM Document objects.")
         )
         )
-        grid1.addWidget(self.pdf_param_label, 0, 0, 1, 2)
+        grid0.addWidget(self.pdf_param_label, 32, 0, 1, 2)
 
 
         # Top Margin value
         # Top Margin value
         self.tmargin_entry = FCDoubleSpinner()
         self.tmargin_entry = FCDoubleSpinner()
@@ -1684,8 +1679,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
             _("Distance between text body and the top of the PDF file.")
             _("Distance between text body and the top of the PDF file.")
         )
         )
 
 
-        grid1.addWidget(self.tmargin_label, 1, 0)
-        grid1.addWidget(self.tmargin_entry, 1, 1)
+        grid0.addWidget(self.tmargin_label, 33, 0)
+        grid0.addWidget(self.tmargin_entry, 33, 1)
 
 
         # Bottom Margin value
         # Bottom Margin value
         self.bmargin_entry = FCDoubleSpinner()
         self.bmargin_entry = FCDoubleSpinner()
@@ -1697,8 +1692,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
             _("Distance between text body and the bottom of the PDF file.")
             _("Distance between text body and the bottom of the PDF file.")
         )
         )
 
 
-        grid1.addWidget(self.bmargin_label, 2, 0)
-        grid1.addWidget(self.bmargin_entry, 2, 1)
+        grid0.addWidget(self.bmargin_label, 34, 0)
+        grid0.addWidget(self.bmargin_entry, 34, 1)
 
 
         # Left Margin value
         # Left Margin value
         self.lmargin_entry = FCDoubleSpinner()
         self.lmargin_entry = FCDoubleSpinner()
@@ -1710,8 +1705,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
             _("Distance between text body and the left of the PDF file.")
             _("Distance between text body and the left of the PDF file.")
         )
         )
 
 
-        grid1.addWidget(self.lmargin_label, 3, 0)
-        grid1.addWidget(self.lmargin_entry, 3, 1)
+        grid0.addWidget(self.lmargin_label, 35, 0)
+        grid0.addWidget(self.lmargin_entry, 35, 1)
 
 
         # Right Margin value
         # Right Margin value
         self.rmargin_entry = FCDoubleSpinner()
         self.rmargin_entry = FCDoubleSpinner()
@@ -1723,8 +1718,8 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
             _("Distance between text body and the right of the PDF file.")
             _("Distance between text body and the right of the PDF file.")
         )
         )
 
 
-        grid1.addWidget(self.rmargin_label, 4, 0)
-        grid1.addWidget(self.rmargin_entry, 4, 1)
+        grid0.addWidget(self.rmargin_label, 36, 0)
+        grid0.addWidget(self.rmargin_entry, 36, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 

+ 1212 - 571
flatcamTools/ToolNonCopperClear.py

@@ -6,10 +6,11 @@
 # ##########################################################
 # ##########################################################
 
 
 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, FCButton
 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
+
 import FlatCAMApp
 import FlatCAMApp
 
 
 from copy import deepcopy
 from copy import deepcopy
@@ -175,6 +176,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "- climb / best for precision milling and to reduce tool usage\n"
               "- climb / best for precision milling and to reduce tool usage\n"
               "- conventional / useful when there is no backlash compensation")
               "- conventional / useful when there is no backlash compensation")
         )
         )
+        self.milling_type_radio.setObjectName(_("Milling Type"))
 
 
         grid1.addWidget(self.milling_type_label, 0, 0)
         grid1.addWidget(self.milling_type_label, 0, 0)
         grid1.addWidget(self.milling_type_radio, 0, 1)
         grid1.addWidget(self.milling_type_radio, 0, 1)
@@ -218,7 +220,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.grid3.setColumnStretch(0, 0)
         self.grid3.setColumnStretch(0, 0)
         self.grid3.setColumnStretch(1, 1)
         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>' % _("New Tool"))
         self.grid3.addWidget(self.tool_sel_label, 1, 0, 1, 2)
         self.grid3.addWidget(self.tool_sel_label, 1, 0, 1, 2)
 
 
         # Tool Type Radio Button
         # Tool Type Radio Button
@@ -236,6 +238,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "- 'V-shape'\n"
               "- 'V-shape'\n"
               "- Circular")
               "- Circular")
         )
         )
+        self.tool_type_radio.setObjectName(_("Tool Type"))
+
         self.grid3.addWidget(self.tool_type_label, 2, 0)
         self.grid3.addWidget(self.tool_type_label, 2, 0)
         self.grid3.addWidget(self.tool_type_radio, 2, 1)
         self.grid3.addWidget(self.tool_type_radio, 2, 1)
 
 
@@ -245,7 +249,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
             _("The tip diameter for V-Shape Tool"))
             _("The tip diameter for V-Shape Tool"))
         self.tipdia_entry = FCDoubleSpinner()
         self.tipdia_entry = FCDoubleSpinner()
         self.tipdia_entry.set_precision(self.decimals)
         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.setSingleStep(0.1)
+        self.tipdia_entry.setObjectName(_("V-Tip Dia"))
 
 
         self.grid3.addWidget(self.tipdialabel, 3, 0)
         self.grid3.addWidget(self.tipdialabel, 3, 0)
         self.grid3.addWidget(self.tipdia_entry, 3, 1)
         self.grid3.addWidget(self.tipdia_entry, 3, 1)
@@ -257,7 +263,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "In degree."))
               "In degree."))
         self.tipangle_entry = FCDoubleSpinner()
         self.tipangle_entry = FCDoubleSpinner()
         self.tipangle_entry.set_precision(self.decimals)
         self.tipangle_entry.set_precision(self.decimals)
+        self.tipangle_entry.set_range(0.0000, 180.0000)
         self.tipangle_entry.setSingleStep(5)
         self.tipangle_entry.setSingleStep(5)
+        self.tipangle_entry.setObjectName(_("V-Tip Angle"))
 
 
         self.grid3.addWidget(self.tipanglelabel, 4, 0)
         self.grid3.addWidget(self.tipanglelabel, 4, 0)
         self.grid3.addWidget(self.tipangle_entry, 4, 1)
         self.grid3.addWidget(self.tipangle_entry, 4, 1)
@@ -271,6 +279,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.cutz_entry = FCDoubleSpinner()
         self.cutz_entry = FCDoubleSpinner()
         self.cutz_entry.set_precision(self.decimals)
         self.cutz_entry.set_precision(self.decimals)
         self.cutz_entry.set_range(-99999.9999, 0.0000)
         self.cutz_entry.set_range(-99999.9999, 0.0000)
+        self.cutz_entry.setObjectName(_("Cut Z"))
 
 
         self.cutz_entry.setToolTip(
         self.cutz_entry.setToolTip(
            _("Depth of cut into material. Negative value.\n"
            _("Depth of cut into material. Negative value.\n"
@@ -288,17 +297,12 @@ 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)
+        self.addtool_entry.set_range(0.000, 9999.9999)
+        self.addtool_entry.setObjectName(_("Tool Dia"))
 
 
         self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
         self.grid3.addWidget(self.addtool_entry_lbl, 6, 0)
         self.grid3.addWidget(self.addtool_entry, 6, 1)
         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)
-
         hlay = QtWidgets.QHBoxLayout()
         hlay = QtWidgets.QHBoxLayout()
 
 
         self.addtool_btn = QtWidgets.QPushButton(_('Add'))
         self.addtool_btn = QtWidgets.QPushButton(_('Add'))
@@ -316,7 +320,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
         hlay.addWidget(self.addtool_btn)
         hlay.addWidget(self.addtool_btn)
         hlay.addWidget(self.deltool_btn)
         hlay.addWidget(self.deltool_btn)
 
 
-        self.grid3.addLayout(hlay, 8, 0, 1, 2)
+        self.grid3.addLayout(hlay, 7, 0, 1, 2)
+
+        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, 8, 0, 1, 2)
 
 
         self.grid3.addWidget(QtWidgets.QLabel(''), 9, 0, 1, 2)
         self.grid3.addWidget(QtWidgets.QLabel(''), 9, 0, 1, 2)
 
 
@@ -351,16 +362,20 @@ 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)
+        self.ncc_overlap_entry.setObjectName(_("Overlap Rate"))
 
 
         self.grid3.addWidget(nccoverlabel, 12, 0)
         self.grid3.addWidget(nccoverlabel, 12, 0)
         self.grid3.addWidget(self.ncc_overlap_entry, 12, 1)
         self.grid3.addWidget(self.ncc_overlap_entry, 12, 1)
 
 
+        # Margin
         nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
         nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
         nccmarginlabel.setToolTip(
         nccmarginlabel.setToolTip(
             _("Bounding box margin.")
             _("Bounding box margin.")
         )
         )
         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)
+        self.ncc_margin_entry.set_range(-9999.9999, 9999.9999)
+        self.ncc_margin_entry.setObjectName(_("Margin"))
 
 
         self.grid3.addWidget(nccmarginlabel, 13, 0)
         self.grid3.addWidget(nccmarginlabel, 13, 0)
         self.grid3.addWidget(self.ncc_margin_entry, 13, 1)
         self.grid3.addWidget(self.ncc_margin_entry, 13, 1)
@@ -378,19 +393,25 @@ class NonCopperClear(FlatCAMTool, Gerber):
             {"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)
+        self.ncc_method_radio.setObjectName(_("Method"))
 
 
         self.grid3.addWidget(methodlabel, 14, 0)
         self.grid3.addWidget(methodlabel, 14, 0)
         self.grid3.addWidget(self.ncc_method_radio, 14, 1)
         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"))
+        self.ncc_connect_cb.setObjectName(_("Connect"))
+
         self.ncc_connect_cb.setToolTip(
         self.ncc_connect_cb.setToolTip(
             _("Draw lines between resulting\n"
             _("Draw lines between resulting\n"
               "segments to minimize tool lifts.")
               "segments to minimize tool lifts.")
         )
         )
         self.grid3.addWidget(self.ncc_connect_cb, 15, 0, 1, 2)
         self.grid3.addWidget(self.ncc_connect_cb, 15, 0, 1, 2)
 
 
+        # Contour
         self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
         self.ncc_contour_cb = FCCheckBox('%s' % _("Contour"))
+        self.ncc_contour_cb.setObjectName(_("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.")
@@ -399,6 +420,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         # Rest Machining
         # Rest Machining
         self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
         self.ncc_rest_cb = FCCheckBox('%s' % _("Rest Machining"))
+        self.ncc_rest_cb.setObjectName(_("Rest Machining"))
+
         self.ncc_rest_cb.setToolTip(
         self.ncc_rest_cb.setToolTip(
             _("If checked, use 'rest machining'.\n"
             _("If checked, use 'rest machining'.\n"
               "Basically it will clear copper outside PCB features,\n"
               "Basically it will clear copper outside PCB features,\n"
@@ -413,6 +436,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         # ## NCC Offset choice
         # ## NCC Offset choice
         self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
         self.ncc_choice_offset_cb = FCCheckBox('%s' % _("Offset"))
+        self.ncc_choice_offset_cb.setObjectName(_("Offset"))
+
         self.ncc_choice_offset_cb.setToolTip(
         self.ncc_choice_offset_cb.setToolTip(
             _("If used, it will add an offset to the copper features.\n"
             _("If used, it will add an offset to the copper features.\n"
               "The copper clearing will finish to a distance\n"
               "The copper clearing will finish to a distance\n"
@@ -433,6 +458,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         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)
         self.ncc_offset_spinner.setWrapping(True)
         self.ncc_offset_spinner.setWrapping(True)
+        self.ncc_offset_spinner.setObjectName(_("Offset value"))
 
 
         units = self.app.defaults['units'].upper()
         units = self.app.defaults['units'].upper()
         if units == 'MM':
         if units == 'MM':
@@ -452,7 +478,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
             {"label": _("Area Selection"), "value": "area"},
             {"label": _("Area Selection"), "value": "area"},
             {'label':  _("Reference Object"), 'value': 'box'}
             {'label':  _("Reference Object"), 'value': 'box'}
         ], orientation='vertical', stretch=False)
         ], orientation='vertical', stretch=False)
-        self.reference_label = QtWidgets.QLabel(_("Reference:"))
+        self.reference_radio.setObjectName(_("Reference"))
+
+        self.reference_label = QtWidgets.QLabel('%s:' % _("Reference"))
         self.reference_label.setToolTip(
         self.reference_label.setToolTip(
             _("- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
             _("- 'Itself' - the non copper clearing extent is based on the object that is copper cleared.\n "
               "- '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"
@@ -586,6 +614,32 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         self.tooldia = None
         self.tooldia = None
 
 
+        self.form_fields = {
+            "nccoverlap": self.ncc_overlap_entry,
+            "nccmargin": self.ncc_margin_entry,
+            "nccmethod": self.ncc_method_radio,
+            "nccconnect": self.ncc_connect_cb,
+            "ncccontour": self.ncc_contour_cb,
+            "nccrest": self.ncc_rest_cb,
+            "nccoffset": self.ncc_choice_offset_cb,
+            "nccoffset_value": self.ncc_offset_spinner,
+            "nccref":  self.reference_radio,
+            "milling_type": self.milling_type_radio
+        }
+
+        self.name2option = {
+            _('Overlap Rate'): "nccoverlap",
+            _('Margin'): "nccmargin",
+            _('Method'): "nccmethod",
+            _("Connect"): "nccconnect",
+            _("Contour"): "ncccontour",
+            _("Rest Machining"): "nccrest",
+            _("Offset"): "nccoffset",
+            _("Offset value"): "nccoffset_value",
+            _("Reference"): "nccref",
+            _('Milling Type'): "milling_type",
+        }
+
         # #############################################################################
         # #############################################################################
         # ############################ SGINALS ########################################
         # ############################ SGINALS ########################################
         # #############################################################################
         # #############################################################################
@@ -618,7 +672,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.update_ui()
         self.update_ui()
 
 
     def update_ui(self, row=None):
     def update_ui(self, row=None):
-        self.ui_disconnect()
+        self.blockSignals(True)
 
 
         if row is None:
         if row is None:
             try:
             try:
@@ -634,7 +688,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # populate the form with the data from the tool associated with the row parameter
         # populate the form with the data from the tool associated with the row parameter
         try:
         try:
             item = self.tools_table.item(current_row, 3)
             item = self.tools_table.item(current_row, 3)
-            if type(item) is not None:
+            if item is not None:
                 tooluid = int(item.text())
                 tooluid = int(item.text())
             else:
             else:
                 return
                 return
@@ -644,7 +698,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         # update the QLabel that shows for which Tool we have the parameters in the UI form
         # update the QLabel that shows for which Tool we have the parameters in the UI form
         self.tool_data_label.setText(
         self.tool_data_label.setText(
-            "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), tooluid)
+            "<b>%s: <font color='#0000FF'>%s %d</font></b>" % (_('Parameters for'), _("Tool"), (current_row + 1))
         )
         )
 
 
         try:
         try:
@@ -654,70 +708,46 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     for key, value in tooluid_value.items():
                     for key, value in tooluid_value.items():
                         if key == 'data':
                         if key == 'data':
                             form_value_storage = tooluid_value[key]
                             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()
+                            self.storage_to_form(form_value_storage)
         except Exception as e:
         except Exception as e:
             log.debug("FlatCAMObj ---> update_ui() " + str(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
+        self.blockSignals(False)
 
 
-        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())
+    def storage_to_form(self, dict_storage):
+        for form_key in self.form_fields:
+            for storage_key in dict_storage:
+                if form_key == storage_key:
+                    try:
+                        self.form_fields[form_key].set_value(dict_storage[form_key])
+                    except Exception:
+                        pass
 
 
-        tool_dia_item = self.tools_table.item(row, 1)
-        if tool_dia_item is None:
+    def 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
             return
             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
+        self.blockSignals(True)
 
 
-    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())
+        widget_changed = self.sender()
+        wdg_objname = widget_changed.objectName()
+        option_changed = self.name2option[wdg_objname]
 
 
-        # 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
+        row = self.tools_table.currentRow()
+        if row < 0:
+            row = 0
+        tooluid_item = int(self.tools_table.item(row, 3).text())
 
 
-    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))
+        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
 
 
-        # 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()
+        self.blockSignals(False)
 
 
     def on_apply_param_to_all_clicked(self):
     def on_apply_param_to_all_clicked(self):
         if self.tools_table.rowCount() == 0:
         if self.tools_table.rowCount() == 0:
@@ -725,7 +755,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
             log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
             log.debug("NonCopperClear.on_apply_param_to_all_clicked() --> no tool in Tools Table, aborting.")
             return
             return
 
 
-        self.ui_disconnect()
+        self.blockSignals(True)
 
 
         row = self.tools_table.currentRow()
         row = self.tools_table.currentRow()
         if row < 0:
         if row < 0:
@@ -736,8 +766,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
         type_item = self.tools_table.cellWidget(row, 2).currentText()
         type_item = self.tools_table.cellWidget(row, 2).currentText()
         operation_type_item = self.ui.geo_tools_table.cellWidget(row, 4).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())
+        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'
         # this new dict will hold the actual useful data, another dict that is the value of key 'data'
         temp_tools = {}
         temp_tools = {}
@@ -746,16 +776,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         for tooluid_key, tooluid_value in self.ncc_tools.items():
         for tooluid_key, tooluid_value in self.ncc_tools.items():
             for key, value in tooluid_value.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':
                 if key == 'data':
                     # update the 'data' section
                     # update the 'data' section
                     for data_key in tooluid_value[key].keys():
                     for data_key in tooluid_value[key].keys():
@@ -769,8 +789,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     temp_dia[key] = deepcopy(temp_data)
                     temp_dia[key] = deepcopy(temp_data)
                     temp_data.clear()
                     temp_data.clear()
 
 
-                if key == 'solid_geometry':
+                elif key == 'solid_geometry':
                     temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
                     temp_dia[key] = deepcopy(self.tools[tooluid_key]['solid_geometry'])
+                else:
+                    temp_dia[key] = deepcopy(value)
 
 
                 temp_tools[tooluid_key] = deepcopy(temp_dia)
                 temp_tools[tooluid_key] = deepcopy(temp_dia)
 
 
@@ -778,93 +800,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.ncc_tools = deepcopy(temp_tools)
         self.ncc_tools = deepcopy(temp_tools)
         temp_tools.clear()
         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()
+        self.blockSignals(False)
 
 
     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"),
@@ -931,6 +867,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.ncc_connect_cb.set_value(self.app.defaults["tools_nccconnect"])
         self.ncc_connect_cb.set_value(self.app.defaults["tools_nccconnect"])
         self.ncc_contour_cb.set_value(self.app.defaults["tools_ncccontour"])
         self.ncc_contour_cb.set_value(self.app.defaults["tools_ncccontour"])
         self.ncc_rest_cb.set_value(self.app.defaults["tools_nccrest"])
         self.ncc_rest_cb.set_value(self.app.defaults["tools_nccrest"])
+        self.ncc_choice_offset_cb.set_value(self.app.defaults["tools_ncc_offset_choice"])
+        self.ncc_offset_spinner.set_value(self.app.defaults["tools_ncc_offset_value"])
+
         self.reference_radio.set_value(self.app.defaults["tools_nccref"])
         self.reference_radio.set_value(self.app.defaults["tools_nccref"])
         self.milling_type_radio.set_value(self.app.defaults["tools_nccmilling_type"])
         self.milling_type_radio.set_value(self.app.defaults["tools_nccmilling_type"])
         self.cutz_entry.set_value(self.app.defaults["tools_ncccutz"])
         self.cutz_entry.set_value(self.app.defaults["tools_ncccutz"])
@@ -943,7 +882,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         # init the working variables
         # init the working variables
         self.default_data.clear()
         self.default_data.clear()
-        self.default_data.update({
+        self.default_data = {
             "name": '_ncc',
             "name": '_ncc',
             "plot": self.app.defaults["geometry_plot"],
             "plot": self.app.defaults["geometry_plot"],
             "cutz": float(self.cutz_entry.get_value()),
             "cutz": float(self.cutz_entry.get_value()),
@@ -967,21 +906,17 @@ class NonCopperClear(FlatCAMTool, Gerber):
             "toolchangexy": self.app.defaults["geometry_toolchangexy"],
             "toolchangexy": self.app.defaults["geometry_toolchangexy"],
             "startz": self.app.defaults["geometry_startz"],
             "startz": self.app.defaults["geometry_startz"],
 
 
-            "tooldia": self.app.defaults["tools_painttooldia"],
-            "paintmargin": self.app.defaults["tools_paintmargin"],
-            "paintmethod": self.app.defaults["tools_paintmethod"],
-            "selectmethod": self.app.defaults["tools_selectmethod"],
-            "pathconnect": self.app.defaults["tools_pathconnect"],
-            "paintcontour": self.app.defaults["tools_paintcontour"],
-            "paintoverlap": self.app.defaults["tools_paintoverlap"],
-
             "nccmargin": self.app.defaults["tools_nccmargin"],
             "nccmargin": self.app.defaults["tools_nccmargin"],
             "nccmethod": self.app.defaults["tools_nccmethod"],
             "nccmethod": self.app.defaults["tools_nccmethod"],
             "nccconnect": self.app.defaults["tools_nccconnect"],
             "nccconnect": self.app.defaults["tools_nccconnect"],
             "ncccontour": self.app.defaults["tools_ncccontour"],
             "ncccontour": self.app.defaults["tools_ncccontour"],
             "nccoverlap": self.app.defaults["tools_nccoverlap"],
             "nccoverlap": self.app.defaults["tools_nccoverlap"],
-            "nccrest": self.app.defaults["tools_nccrest"]
-        })
+            "nccrest": self.app.defaults["tools_nccrest"],
+            "nccref": self.app.defaults["tools_nccref"],
+            "nccoffset": self.app.defaults["tools_ncc_offset_choice"],
+            "nccoffset_value": self.app.defaults["tools_ncc_offset_value"],
+
+        }
 
 
         try:
         try:
             dias = [float(self.app.defaults["tools_ncctools"])]
             dias = [float(self.app.defaults["tools_ncctools"])]
@@ -1118,21 +1053,56 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.tools_table.itemChanged.connect(self.on_tool_edit)
         self.tools_table.itemChanged.connect(self.on_tool_edit)
 
 
         for row in range(self.tools_table.rowCount()):
         for row in range(self.tools_table.rowCount()):
-            for col in [2, 4]:
-                self.tools_table.cellWidget(row, col).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
+            try:
+                self.tools_table.cellWidget(row, 2).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
+            except AttributeError:
+                pass
+
+            try:
+                self.tools_table.cellWidget(row, 4).currentIndexChanged.connect(self.on_tooltable_cellwidget_change)
+            except AttributeError:
+                pass
 
 
         self.tool_type_radio.activated_custom.connect(self.on_tool_type)
         self.tool_type_radio.activated_custom.connect(self.on_tool_type)
 
 
+        # first disconnect
+        for opt in self.form_fields:
+            current_widget = self.form_fields[opt]
+            if isinstance(current_widget, FCCheckBox):
+                try:
+                    current_widget.stateChanged.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+            if isinstance(current_widget, RadioSet):
+                try:
+                    current_widget.activated_custom.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+            elif isinstance(current_widget, FCDoubleSpinner):
+                try:
+                    current_widget.returnPressed.disconnect(self.form_to_storage)
+                except (TypeError, ValueError):
+                    pass
+
+        for opt in self.form_fields:
+            current_widget = self.form_fields[opt]
+            if isinstance(current_widget, FCCheckBox):
+                current_widget.stateChanged.connect(self.form_to_storage)
+            if isinstance(current_widget, RadioSet):
+                current_widget.activated_custom.connect(self.form_to_storage)
+            elif isinstance(current_widget, FCDoubleSpinner):
+                current_widget.returnPressed.connect(self.form_to_storage)
+
     def ui_disconnect(self):
     def ui_disconnect(self):
         try:
         try:
             # if connected, disconnect the signal from the slot on item_changed as it creates issues
             # if connected, disconnect the signal from the slot on item_changed as it creates issues
-            self.tools_table.itemChanged.disconnect(self.on_tool_edit)
+            self.tools_table.itemChanged.disconnect()
         except (TypeError, AttributeError):
         except (TypeError, AttributeError):
             pass
             pass
 
 
         try:
         try:
             # if connected, disconnect the signal from the slot on item_changed as it creates issues
             # if connected, disconnect the signal from the slot on item_changed as it creates issues
-            self.tool_type_radio.activated_custom.disconnect(self.on_tool_type)
+            self.tool_type_radio.activated_custom.disconnect()
         except (TypeError, AttributeError):
         except (TypeError, AttributeError):
             pass
             pass
 
 
@@ -1143,6 +1113,24 @@ class NonCopperClear(FlatCAMTool, Gerber):
                 except (TypeError, AttributeError):
                 except (TypeError, AttributeError):
                     pass
                     pass
 
 
+        for opt in self.form_fields:
+            current_widget = self.form_fields[opt]
+            if isinstance(current_widget, FCCheckBox):
+                try:
+                    current_widget.stateChanged.disconnect()
+                except (TypeError, ValueError):
+                    pass
+            if isinstance(current_widget, RadioSet):
+                try:
+                    current_widget.activated_custom.disconnect()
+                except (TypeError, ValueError):
+                    pass
+            elif isinstance(current_widget, FCDoubleSpinner):
+                try:
+                    current_widget.returnPressed.disconnect()
+                except (TypeError, ValueError):
+                    pass
+
     def on_combo_box_type(self):
     def on_combo_box_type(self):
         obj_type = self.box_combo_type.currentIndex()
         obj_type = self.box_combo_type.currentIndex()
         self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
         self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
@@ -1189,32 +1177,30 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         current_uid = int(self.tools_table.item(cw_row, 3).text())
         current_uid = int(self.tools_table.item(cw_row, 3).text())
 
 
-        hide_iso_type = True
-        for row in range(self.tools_table.rowCount()):
-            if self.tools_table.cellWidget(row, 4).currentText() == 'iso_op':
-                hide_iso_type = False
-                break
-
-        if hide_iso_type is False:
-            self.milling_type_label.show()
-            self.milling_type_radio.show()
-        else:
-            self.milling_type_label.hide()
-            self.milling_type_radio.hide()
-
         # if the sender is in the column with index 2 then we update the tool_type key
         # if the sender is in the column with index 2 then we update the tool_type key
         if cw_col == 2:
         if cw_col == 2:
             tt = cw.currentText()
             tt = cw.currentText()
-            if tt == 'V':
-                typ = 'Iso'
-            else:
-                typ = "Rough"
+            typ = 'Iso' if tt == 'V' else "Rough"
 
 
             self.ncc_tools[current_uid].update({
             self.ncc_tools[current_uid].update({
                 'type': typ,
                 'type': typ,
                 'tool_type': tt,
                 'tool_type': tt,
             })
             })
 
 
+        if cw_col == 4:
+            op = cw.currentText()
+
+            if op == 'iso_op':
+                self.milling_type_label.show()
+                self.milling_type_radio.show()
+            else:
+                self.milling_type_label.hide()
+                self.milling_type_radio.hide()
+
+            self.ncc_tools[current_uid].update({
+                'operation': op
+            })
+
     def on_tool_type(self, val):
     def on_tool_type(self, val):
         if val == 'V':
         if val == 'V':
             self.addtool_entry_lbl.setDisabled(True)
             self.addtool_entry_lbl.setDisabled(True)
@@ -1254,7 +1240,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
             return float(self.addtool_entry.get_value())
             return float(self.addtool_entry.get_value())
 
 
     def on_tool_add(self, dia=None, muted=None):
     def on_tool_add(self, dia=None, muted=None):
-        self.ui_disconnect()
+        self.blockSignals(True)
+
         self.units = self.app.defaults['units'].upper()
         self.units = self.app.defaults['units'].upper()
 
 
         if dia:
         if dia:
@@ -1296,7 +1283,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
             if muted is None:
             if muted is None:
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding tool cancelled. Tool already in Tool Table."))
             # self.tools_table.itemChanged.connect(self.on_tool_edit)
             # self.tools_table.itemChanged.connect(self.on_tool_edit)
-            self.ui_connect()
+            self.blockSignals(False)
+
             return
             return
         else:
         else:
             if muted is None:
             if muted is None:
@@ -1314,10 +1302,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
                 }
                 }
             })
             })
 
 
+        self.blockSignals(False)
+
         self.build_ui()
         self.build_ui()
 
 
     def on_tool_edit(self):
     def on_tool_edit(self):
-        self.ui_disconnect()
+        self.blockSignals(True)
 
 
         old_tool_dia = ''
         old_tool_dia = ''
         tool_dias = []
         tool_dias = []
@@ -1335,8 +1325,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
                 try:
                 try:
                     new_tool_dia = float(self.tools_table.item(row, 1).text().replace(',', '.'))
                     new_tool_dia = float(self.tools_table.item(row, 1).text().replace(',', '.'))
                 except ValueError:
                 except ValueError:
-                    self.app.inform.emit('[ERROR_NOTCL]  %s' % _("Wrong value format entered, "
-                                         "use a number."))
+                    self.app.inform.emit('[ERROR_NOTCL]  %s' % _("Wrong value format entered, use a number."))
+                    self.blockSignals(False)
                     return
                     return
 
 
             tooluid = int(self.tools_table.item(row, 3).text())
             tooluid = int(self.tools_table.item(row, 3).text())
@@ -1345,6 +1335,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
             if new_tool_dia not in tool_dias:
             if new_tool_dia not in tool_dias:
                 self.ncc_tools[tooluid]['tooldia'] = new_tool_dia
                 self.ncc_tools[tooluid]['tooldia'] = new_tool_dia
                 self.app.inform.emit('[success] %s' % _("Tool from Tool Table was edited."))
                 self.app.inform.emit('[success] %s' % _("Tool from Tool Table was edited."))
+                self.blockSignals(False)
                 self.build_ui()
                 self.build_ui()
                 return
                 return
             else:
             else:
@@ -1357,6 +1348,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                 restore_dia_item.setText(str(old_tool_dia))
                 restore_dia_item.setText(str(old_tool_dia))
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Edit cancelled. "
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Edit cancelled. "
                                                               "New diameter value is already in the Tool Table."))
                                                               "New diameter value is already in the Tool Table."))
+        self.blockSignals(False)
         self.build_ui()
         self.build_ui()
 
 
     def on_tool_delete(self, rows_to_delete=None, all_tools=None):
     def on_tool_delete(self, rows_to_delete=None, all_tools=None):
@@ -1367,12 +1359,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
         :param all_tools: delete all tools in the tool table
         :param all_tools: delete all tools in the tool table
         :return:
         :return:
         """
         """
-        self.ui_disconnect()
+        self.blockSignals(True)
 
 
         deleted_tools_list = []
         deleted_tools_list = []
 
 
         if all_tools:
         if all_tools:
             self.paint_tools.clear()
             self.paint_tools.clear()
+            self.blockSignals(False)
             self.build_ui()
             self.build_ui()
             return
             return
 
 
@@ -1382,10 +1375,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     tooluid_del = int(self.tools_table.item(row, 3).text())
                     tooluid_del = int(self.tools_table.item(row, 3).text())
                     deleted_tools_list.append(tooluid_del)
                     deleted_tools_list.append(tooluid_del)
             except TypeError:
             except TypeError:
-                deleted_tools_list.append(rows_to_delete)
+                tooluid_del = int(self.tools_table.item(rows_to_delete, 3).text())
+                deleted_tools_list.append(tooluid_del)
 
 
             for t in deleted_tools_list:
             for t in deleted_tools_list:
                 self.ncc_tools.pop(t, None)
                 self.ncc_tools.pop(t, None)
+
+            self.blockSignals(False)
             self.build_ui()
             self.build_ui()
             return
             return
 
 
@@ -1403,11 +1399,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         except AttributeError:
         except AttributeError:
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Delete failed. Select a tool to delete."))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Delete failed. Select a tool to delete."))
+            self.blockSignals(False)
             return
             return
         except Exception as e:
         except Exception as e:
             log.debug(str(e))
             log.debug(str(e))
 
 
         self.app.inform.emit('[success] %s' % _("Tool(s) deleted from Tool Table."))
         self.app.inform.emit('[success] %s' % _("Tool(s) deleted from Tool Table."))
+        self.blockSignals(False)
         self.build_ui()
         self.build_ui()
 
 
     def on_ncc_click(self):
     def on_ncc_click(self):
@@ -1720,7 +1718,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
             ncc_select = self.reference_radio.get_value()
             ncc_select = self.reference_radio.get_value()
 
 
         overlap = overlap if overlap is not None else float(self.app.defaults["tools_nccoverlap"]) / 100.0
         overlap = overlap if overlap is not None else float(self.app.defaults["tools_nccoverlap"]) / 100.0
-
         connect = connect if connect else self.app.defaults["tools_nccconnect"]
         connect = connect if connect else self.app.defaults["tools_nccconnect"]
         contour = contour if contour else self.app.defaults["tools_ncccontour"]
         contour = contour if contour else self.app.defaults["tools_ncccontour"]
         order = order if order else self.ncc_order_radio.get_value()
         order = order if order else self.ncc_order_radio.get_value()
@@ -1818,7 +1815,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
 
         elif ncc_select == 'box':
         elif ncc_select == 'box':
             geo_n = ncc_sel_obj.solid_geometry
             geo_n = ncc_sel_obj.solid_geometry
-            if isinstance(ncc_sel_obj, FlatCAMGeometry):
+            if ncc_sel_obj.kind == 'geometry':
                 try:
                 try:
                     __ = iter(geo_n)
                     __ = iter(geo_n)
                 except Exception as e:
                 except Exception as e:
@@ -1833,7 +1830,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
                     geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
 
 
                 bounding_box = cascaded_union(geo_buff_list)
                 bounding_box = cascaded_union(geo_buff_list)
-            elif isinstance(ncc_sel_obj, FlatCAMGerber):
+            elif ncc_sel_obj.kind == 'gerber':
                 geo_n = cascaded_union(geo_n).convex_hull
                 geo_n = cascaded_union(geo_n).convex_hull
                 bounding_box = cascaded_union(self.ncc_obj.solid_geometry).convex_hull.intersection(geo_n)
                 bounding_box = cascaded_union(self.ncc_obj.solid_geometry).convex_hull.intersection(geo_n)
                 bounding_box = bounding_box.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
                 bounding_box = bounding_box.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
@@ -1856,7 +1853,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # Initializes the new geometry object ######################################################
         # Initializes the new geometry object ######################################################
         # ##########################################################################################
         # ##########################################################################################
         def gen_clear_area(geo_obj, app_obj):
         def gen_clear_area(geo_obj, app_obj):
-            assert isinstance(geo_obj, FlatCAMGeometry), \
+            assert geo_obj.kind == 'geometry', \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
 
 
             # provide the app with a way to process the GUI events when in a blocking loop
             # provide the app with a way to process the GUI events when in a blocking loop
@@ -1898,7 +1895,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
             log.debug("NCC Tool. Calculate 'empty' area.")
             log.debug("NCC Tool. Calculate 'empty' area.")
             self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
             self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
 
 
-            if isinstance(ncc_obj, FlatCAMGerber) and not isotooldia:
+            if ncc_obj.kind == 'gerber' and not isotooldia:
                 # unfortunately for this function to work time efficient,
                 # unfortunately for this function to work time efficient,
                 # if the Gerber was loaded without buffering then it require the buffering now.
                 # if the Gerber was loaded without buffering then it require the buffering now.
                 if self.app.defaults['gerber_buffering'] == 'no':
                 if self.app.defaults['gerber_buffering'] == 'no':
@@ -1919,7 +1916,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[ERROR_NOTCL] %s' %
                     app_obj.inform.emit('[ERROR_NOTCL] %s' %
                                         _("Could not get the extent of the area to be non copper cleared."))
                                         _("Could not get the extent of the area to be non copper cleared."))
                     return 'fail'
                     return 'fail'
-            elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
+            elif ncc_obj.kind == 'gerber' and isotooldia:
                 isolated_geo = []
                 isolated_geo = []
 
 
                 # unfortunately for this function to work time efficient,
                 # unfortunately for this function to work time efficient,
@@ -2024,7 +2021,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                         _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
                                         _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
                     return 'fail'
                     return 'fail'
 
 
-            elif isinstance(ncc_obj, FlatCAMGeometry):
+            elif ncc_obj.kind == 'geometry':
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
                 if has_offset is True:
                 if has_offset is True:
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
@@ -2295,7 +2292,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         # Initializes the new geometry object for the case of the rest-machining ####################
         # Initializes the new geometry object for the case of the rest-machining ####################
         # ###########################################################################################
         # ###########################################################################################
         def gen_clear_area_rest(geo_obj, app_obj):
         def gen_clear_area_rest(geo_obj, app_obj):
-            assert isinstance(geo_obj, FlatCAMGeometry), \
+            assert geo_obj.kind == 'geometry', \
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
                 "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
 
 
             log.debug("NCC Tool. Rest machining copper clearing task started.")
             log.debug("NCC Tool. Rest machining copper clearing task started.")
@@ -2328,7 +2325,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
             # ###################################################################################################
             # ###################################################################################################
             # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
             # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
             # ###################################################################################################
             # ###################################################################################################
-            if isinstance(ncc_obj, FlatCAMGerber) and not isotooldia:
+            if ncc_obj.kind == 'gerber' and not isotooldia:
                 sol_geo = ncc_obj.solid_geometry
                 sol_geo = ncc_obj.solid_geometry
                 if has_offset is True:
                 if has_offset is True:
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
@@ -2342,7 +2339,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     app_obj.inform.emit('[ERROR_NOTCL] %s' %
                     app_obj.inform.emit('[ERROR_NOTCL] %s' %
                                         _("Could not get the extent of the area to be non copper cleared."))
                                         _("Could not get the extent of the area to be non copper cleared."))
                     return 'fail'
                     return 'fail'
-            elif isinstance(ncc_obj, FlatCAMGerber) and isotooldia:
+            elif ncc_obj.kind == 'gerber' and isotooldia:
                 isolated_geo = []
                 isolated_geo = []
                 self.solid_geometry = ncc_obj.solid_geometry
                 self.solid_geometry = ncc_obj.solid_geometry
 
 
@@ -2444,7 +2441,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                                         _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
                                         _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
                     return 'fail'
                     return 'fail'
 
 
-            elif isinstance(ncc_obj, FlatCAMGeometry):
+            elif ncc_obj.kind == 'geometry':
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
                 sol_geo = cascaded_union(ncc_obj.solid_geometry)
                 if has_offset is True:
                 if has_offset is True:
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
                     app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
@@ -2715,359 +2712,1003 @@ class NonCopperClear(FlatCAMTool, Gerber):
         else:
         else:
             job_thread(app_obj=self.app)
             job_thread(app_obj=self.app)
 
 
-    # def on_ncc(self):
-    #
-    #     # Prepare non-copper polygons
-    #     if self.reference_radio.get_value() == 'area':
-    #         geo_n = self.sel_rect
-    #
-    #         geo_buff_list = []
-    #         for poly in geo_n:
-    #             geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
-    #         bounding_box = cascaded_union(geo_buff_list)
-    #     else:
-    #         geo_n = self.bound_obj.solid_geometry
-    #
-    #         try:
-    #             if isinstance(geo_n, MultiPolygon):
-    #                 env_obj = geo_n.convex_hull
-    #             elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
-    #                     (isinstance(geo_n, list) and len(geo_n) == 1) and isinstance(geo_n[0], Polygon):
-    #                 env_obj = cascaded_union(geo_n)
-    #             else:
-    #                 env_obj = cascaded_union(geo_n)
-    #                 env_obj = env_obj.convex_hull
-    #             bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
-    #         except Exception as e:
-    #             log.debug("NonCopperClear.on_ncc() --> %s" % str(e))
-    #             self.app.inform.emit(_("[ERROR_NOTCL] No object available."))
-    #             return
-    #
-    #     # calculate the empty area by subtracting the solid_geometry from the object bounding box geometry
-    #     if isinstance(self.ncc_obj, FlatCAMGerber):
-    #         if self.ncc_choice_offset_cb.isChecked():
-    #             self.app.inform.emit(_("[WARNING_NOTCL] Buffering ..."))
-    #             offseted_geo = self.ncc_obj.solid_geometry.buffer(distance=ncc_offset_value)
-    #             self.app.inform.emit(_("[success] Buffering finished ..."))
-    #             empty = self.get_ncc_empty_area(target=offseted_geo, boundary=bounding_box)
-    #         else:
-    #             empty = self.get_ncc_empty_area(target=self.ncc_obj.solid_geometry, boundary=bounding_box)
-    #     elif isinstance(self.ncc_obj, FlatCAMGeometry):
-    #         sol_geo = cascaded_union(self.ncc_obj.solid_geometry)
-    #         if self.ncc_choice_offset_cb.isChecked():
-    #             self.app.inform.emit(_("[WARNING_NOTCL] Buffering ..."))
-    #             offseted_geo = sol_geo.buffer(distance=ncc_offset_value)
-    #             self.app.inform.emit(_("[success] Buffering finished ..."))
-    #             empty = self.get_ncc_empty_area(target=offseted_geo, boundary=bounding_box)
-    #         else:
-    #             empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
-    #     else:
-    #         self.inform.emit(_('[ERROR_NOTCL] The selected object is not suitable for copper clearing.'))
-    #         return
-    #
-    #     if type(empty) is Polygon:
-    #         empty = MultiPolygon([empty])
-    #
-    #     if empty.is_empty:
-    #         self.app.inform.emit(_("[ERROR_NOTCL] Could not get the extent of the area to be non copper cleared."))
-    #         return
-    #
-    #     # clear non copper using standard algorithm
-    #     if clearing_method is False:
-    #         self.clear_non_copper(
-    #             empty=empty,
-    #             over=over,
-    #             pol_method=pol_method,
-    #             connect=connect,
-    #             contour=contour
-    #         )
-    #     # clear non copper using rest machining algorithm
-    #     else:
-    #         self.clear_non_copper_rest(
-    #             empty=empty,
-    #             over=over,
-    #             pol_method=pol_method,
-    #             connect=connect,
-    #             contour=contour
-    #         )
-    #
-    # def clear_non_copper(self, empty, over, pol_method, outname=None, connect=True, contour=True):
-    #
-    #     name = outname if outname else self.obj_name + "_ncc"
-    #
-    #     # Sort tools in descending order
-    #     sorted_tools = []
-    #     for k, v in self.ncc_tools.items():
-    #         sorted_tools.append(float('%.4f' % float(v['tooldia'])))
-    #
-    #     order = self.ncc_order_radio.get_value()
-    #     if order == 'fwd':
-    #         sorted_tools.sort(reverse=False)
-    #     elif order == 'rev':
-    #         sorted_tools.sort(reverse=True)
-    #     else:
-    #         pass
-    #
-    #     # Do job in background
-    #     proc = self.app.proc_container.new(_("Clearing Non-Copper areas."))
-    #
-    #     def initialize(geo_obj, app_obj):
-    #         assert isinstance(geo_obj, FlatCAMGeometry), \
-    #             "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
-    #
-    #         cleared_geo = []
-    #         # Already cleared area
-    #         cleared = MultiPolygon()
-    #
-    #         # flag for polygons not cleared
-    #         app_obj.poly_not_cleared = False
-    #
-    #         # Generate area for each tool
-    #         offset = sum(sorted_tools)
-    #         current_uid = int(1)
-    #         tool = eval(self.app.defaults["tools_ncctools"])[0]
-    #
-    #         for tool in sorted_tools:
-    #             self.app.inform.emit(_('[success] Non-Copper Clearing with ToolDia = %s started.') % str(tool))
-    #             cleared_geo[:] = []
-    #
-    #             # Get remaining tools offset
-    #             offset -= (tool - 1e-12)
-    #
-    #             # Area to clear
-    #             area = empty.buffer(-offset)
-    #             try:
-    #                 area = area.difference(cleared)
-    #             except Exception as e:
-    #                 continue
-    #
-    #             # Transform area to MultiPolygon
-    #             if type(area) is Polygon:
-    #                 area = MultiPolygon([area])
-    #
-    #             if area.geoms:
-    #                 if len(area.geoms) > 0:
-    #                     for p in area.geoms:
-    #                         try:
-    #                             if pol_method == 'standard':
-    #                                 cp = self.clear_polygon(p, tool, self.app.defaults["gerber_circle_steps"],
-    #                                                         overlap=over, contour=contour, connect=connect)
-    #                             elif pol_method == 'seed':
-    #                                 cp = self.clear_polygon2(p, tool, self.app.defaults["gerber_circle_steps"],
-    #                                                          overlap=over, contour=contour, connect=connect)
-    #                             else:
-    #                                 cp = self.clear_polygon3(p, tool, self.app.defaults["gerber_circle_steps"],
-    #                                                          overlap=over, contour=contour, connect=connect)
-    #                             if cp:
-    #                                 cleared_geo += list(cp.get_objects())
-    #                         except Exception as e:
-    #                             log.warning("Polygon can not be cleared. %s" % str(e))
-    #                             app_obj.poly_not_cleared = True
-    #                             continue
-    #
-    #                     # check if there is a geometry at all in the cleared geometry
-    #                     if cleared_geo:
-    #                         # Overall cleared area
-    #                         cleared = empty.buffer(-offset * (1 + over)).buffer(-tool / 1.999999).buffer(
-    #                             tool / 1.999999)
-    #
-    #                         # clean-up cleared geo
-    #                         cleared = cleared.buffer(0)
-    #
-    #                         # find the tooluid associated with the current tool_dia so we know where to add the tool
-    #                         # solid_geometry
-    #                         for k, v in self.ncc_tools.items():
-    #                             if float('%.4f' % v['tooldia']) == float('%.4f' % tool):
-    #                                 current_uid = int(k)
-    #
-    #                                 # add the solid_geometry to the current too in self.paint_tools dictionary
-    #                                 # and then reset the temporary list that stored that solid_geometry
-    #                                 v['solid_geometry'] = deepcopy(cleared_geo)
-    #                                 v['data']['name'] = name
-    #                                 break
-    #                         geo_obj.tools[current_uid] = dict(self.ncc_tools[current_uid])
-    #                     else:
-    #                         log.debug("There are no geometries in the cleared polygon.")
-    #
-    #         geo_obj.options["cnctooldia"] = str(tool)
-    #         geo_obj.multigeo = True
-    #
-    #     def job_thread(app_obj):
-    #         try:
-    #             app_obj.new_object("geometry", name, initialize)
-    #         except Exception as e:
-    #             proc.done()
-    #             self.app.inform.emit(_('[ERROR_NOTCL] NCCTool.clear_non_copper() --> %s') % str(e))
-    #             return
-    #         proc.done()
-    #
-    #         if app_obj.poly_not_cleared is False:
-    #             self.app.inform.emit(_('[success] NCC Tool finished.'))
-    #         else:
-    #             self.app.inform.emit(_('[WARNING_NOTCL] NCC Tool finished but some PCB features could not be cleared. '
-    #                                  'Check the result.'))
-    #         # reset the variable for next use
-    #         app_obj.poly_not_cleared = False
-    #
-    #         # focus on Selected Tab
-    #         self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
-    #
-    #     # Promise object with the new name
-    #     self.app.collection.promise(name)
-    #
-    #     # Background
-    #     self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
-    #
-    # # clear copper with 'rest-machining' algorithm
-    # def clear_non_copper_rest(self, empty, over, pol_method, outname=None, connect=True, contour=True):
-    #
-    #     name = outname if outname is not None else self.obj_name + "_ncc_rm"
-    #
-    #     # Sort tools in descending order
-    #     sorted_tools = []
-    #     for k, v in self.ncc_tools.items():
-    #         sorted_tools.append(float('%.4f' % float(v['tooldia'])))
-    #     sorted_tools.sort(reverse=True)
-    #
-    #     # Do job in background
-    #     proc = self.app.proc_container.new(_("Clearing Non-Copper areas."))
-    #
-    #     def initialize_rm(geo_obj, app_obj):
-    #         assert isinstance(geo_obj, FlatCAMGeometry), \
-    #             "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
-    #
-    #         cleared_geo = []
-    #         cleared_by_last_tool = []
-    #         rest_geo = []
-    #         current_uid = 1
-    #         tool = eval(self.app.defaults["tools_ncctools"])[0]
-    #
-    #         # repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
-    #         app_obj.poly_not_cleared = True
-    #
-    #         area = empty.buffer(0)
-    #         # Generate area for each tool
-    #         while sorted_tools:
-    #             tool = sorted_tools.pop(0)
-    #             self.app.inform.emit(_('[success] Non-Copper Rest Clearing with ToolDia = %s started.') % str(tool))
-    #
-    #             tool_used = tool - 1e-12
-    #             cleared_geo[:] = []
-    #
-    #             # Area to clear
-    #             for poly in cleared_by_last_tool:
-    #                 try:
-    #                     area = area.difference(poly)
-    #                 except Exception as e:
-    #                     pass
-    #             cleared_by_last_tool[:] = []
-    #
-    #             # Transform area to MultiPolygon
-    #             if type(area) is Polygon:
-    #                 area = MultiPolygon([area])
-    #
-    #             # add the rest that was not able to be cleared previously; area is a MultyPolygon
-    #             # and rest_geo it's a list
-    #             allparts = [p.buffer(0) for p in area.geoms]
-    #             allparts += deepcopy(rest_geo)
-    #             rest_geo[:] = []
-    #             area = MultiPolygon(deepcopy(allparts))
-    #             allparts[:] = []
-    #
-    #             if area.geoms:
-    #                 if len(area.geoms) > 0:
-    #                     for p in area.geoms:
-    #                         try:
-    #                             if pol_method == 'standard':
-    #                                 cp = self.clear_polygon(p, tool_used, self.app.defaults["gerber_circle_steps"],
-    #                                                         overlap=over, contour=contour, connect=connect)
-    #                             elif pol_method == 'seed':
-    #                                 cp = self.clear_polygon2(p, tool_used,
-    #                                                          self.app.defaults["gerber_circle_steps"],
-    #                                                          overlap=over, contour=contour, connect=connect)
-    #                             else:
-    #                                 cp = self.clear_polygon3(p, tool_used,
-    #                                                          self.app.defaults["gerber_circle_steps"],
-    #                                                          overlap=over, contour=contour, connect=connect)
-    #                             cleared_geo.append(list(cp.get_objects()))
-    #                         except:
-    #                             log.warning("Polygon can't be cleared.")
-    #                             # this polygon should be added to a list and then try clear it with a smaller tool
-    #                             rest_geo.append(p)
-    #
-    #                     # check if there is a geometry at all in the cleared geometry
-    #                     if cleared_geo:
-    #                         # Overall cleared area
-    #                         cleared_area = list(self.flatten_list(cleared_geo))
-    #
-    #                         # cleared = MultiPolygon([p.buffer(tool_used / 2).buffer(-tool_used / 2)
-    #                         #                         for p in cleared_area])
-    #
-    #                         # here we store the poly's already processed in the original geometry by the current tool
-    #                         # into cleared_by_last_tool list
-    #                         # this will be sustracted from the original geometry_to_be_cleared and make data for
-    #                         # the next tool
-    #                         buffer_value = tool_used / 2
-    #                         for p in cleared_area:
-    #                             poly = p.buffer(buffer_value)
-    #                             cleared_by_last_tool.append(poly)
-    #
-    #                         # find the tooluid associated with the current tool_dia so we know
-    #                         # where to add the tool solid_geometry
-    #                         for k, v in self.ncc_tools.items():
-    #                             if float('%.4f' % v['tooldia']) == float('%.4f' % tool):
-    #                                 current_uid = int(k)
-    #
-    #                                 # add the solid_geometry to the current too in self.paint_tools dictionary
-    #                                 # and then reset the temporary list that stored that solid_geometry
-    #                                 v['solid_geometry'] = deepcopy(cleared_area)
-    #                                 v['data']['name'] = name
-    #                                 cleared_area[:] = []
-    #                                 break
-    #
-    #                         geo_obj.tools[current_uid] = dict(self.ncc_tools[current_uid])
-    #                     else:
-    #                         log.debug("There are no geometries in the cleared polygon.")
-    #
-    #         geo_obj.multigeo = True
-    #         geo_obj.options["cnctooldia"] = str(tool)
-    #
-    #         # check to see if geo_obj.tools is empty
-    #         # it will be updated only if there is a solid_geometry for tools
-    #         if geo_obj.tools:
-    #             return
-    #         else:
-    #             # I will use this variable for this purpose although it was meant for something else
-    #             # signal that we have no geo in the object therefore don't create it
-    #             app_obj.poly_not_cleared = False
-    #             return "fail"
-    #
-    #     def job_thread(app_obj):
-    #         try:
-    #             app_obj.new_object("geometry", name, initialize_rm)
-    #         except Exception as e:
-    #             proc.done()
-    #             app_obj.inform.emit(_('[ERROR_NOTCL] NCCTool.clear_non_copper_rest() --> %s') % str(e))
-    #             return
-    #
-    #         if app_obj.poly_not_cleared is True:
-    #             app_obj.inform.emit('[success] NCC Tool finished.')
-    #             # focus on Selected Tab
-    #             app_obj.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
-    #         else:
-    #             app_obj.inform.emit(_('[ERROR_NOTCL] NCC Tool finished but could not clear the object '
-    #                                  'with current settings.'))
-    #             # focus on Project Tab
-    #             app_obj.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
-    #         proc.done()
-    #         # reset the variable for next use
-    #         app_obj.poly_not_cleared = False
-    #
-    #     # Promise object with the new name
-    #     self.app.collection.promise(name)
-    #
-    #     # Background
-    #     self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+    def clear_copper_tcl(self, ncc_obj,
+                         sel_obj=None,
+                         ncctooldia=None,
+                         isotooldia=None,
+                         margin=None,
+                         has_offset=None,
+                         offset=None,
+                         select_method=None,
+                         outname=None,
+                         overlap=None,
+                         connect=None,
+                         contour=None,
+                         order=None,
+                         method=None,
+                         rest=None,
+                         tools_storage=None,
+                         plot=True,
+                         run_threaded=False):
+        """
+        Clear the excess copper from the entire object. To be used only in a TCL command.
+
+        :param ncc_obj: ncc cleared object
+        :param ncctooldia: a tuple or single element made out of diameters of the tools to be used to ncc clear
+        :param isotooldia: a tuple or single element made out of diameters of the tools to be used for isolation
+        :param overlap: value by which the paths will overlap
+        :param order: if the tools are ordered and how
+        :param select_method: if to do ncc on the whole object, on an defined area or on an area defined by
+        another object
+        :param has_offset: True if an offset is needed
+        :param offset: distance from the copper features where the copper clearing is stopping
+        :param margin: a border around cleared area
+        :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 rest: True if to use rest-machining
+        :param tools_storage: whether to use the current tools_storage self.ncc_tools or a different one.
+        Usage of the different one is related to when this function is called from a TcL command.
+        :param plot: if True after the job is finished the result will be plotted, else it will not.
+        :param run_threaded: If True the method will be run in a threaded way suitable for GUI usage; if False it will
+        run non-threaded for TclShell usage
+        :return:
+        """
+        if run_threaded:
+            proc = self.app.proc_container.new(_("Non-Copper clearing ..."))
+        else:
+            self.app.proc_container.view.set_busy(_("Non-Copper clearing ..."))
+            QtWidgets.QApplication.processEvents()
+
+        # #####################################################################
+        # ####### Read the parameters #########################################
+        # #####################################################################
+
+        units = self.app.defaults['units']
+
+        log.debug("NCC Tool started. Reading parameters.")
+        self.app.inform.emit(_("NCC Tool started. Reading parameters."))
+
+        ncc_method = method
+        ncc_margin = margin
+        ncc_select = select_method
+        overlap = overlap
+
+        connect = connect
+        contour = contour
+        order = order
+
+        if tools_storage is not None:
+            tools_storage = tools_storage
+        else:
+            tools_storage = self.ncc_tools
+
+        ncc_offset = 0.0
+        if has_offset is True:
+            ncc_offset = offset
+
+        # ######################################################################################################
+        # # Read the tooldia parameter and create a sorted list out them - they may be more than one diameter ##
+        # ######################################################################################################
+        sorted_tools = []
+        try:
+            sorted_tools = [float(eval(dia)) for dia in ncctooldia.split(",") if dia != '']
+        except AttributeError:
+            if not isinstance(ncctooldia, list):
+                sorted_tools = [float(ncctooldia)]
+            else:
+                sorted_tools = ncctooldia
+
+        # ##############################################################################################################
+        # Prepare non-copper polygons. Create the bounding box area from which the copper features will be subtracted ##
+        # ##############################################################################################################
+        log.debug("NCC Tool. Preparing non-copper polygons.")
+        self.app.inform.emit(_("NCC Tool. Preparing non-copper polygons."))
+
+        try:
+            if sel_obj is None or sel_obj == 'itself':
+                ncc_sel_obj = ncc_obj
+            else:
+                ncc_sel_obj = sel_obj
+        except Exception as e:
+            log.debug("NonCopperClear.clear_copper() --> %s" % str(e))
+            return 'fail'
+
+        bounding_box = None
+        if ncc_select == 'itself':
+            geo_n = ncc_sel_obj.solid_geometry
+
+            try:
+                if isinstance(geo_n, MultiPolygon):
+                    env_obj = geo_n.convex_hull
+                elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
+                        (isinstance(geo_n, list) and len(geo_n) == 1) and isinstance(geo_n[0], Polygon):
+                    env_obj = cascaded_union(geo_n)
+                else:
+                    env_obj = cascaded_union(geo_n)
+                    env_obj = env_obj.convex_hull
+
+                bounding_box = env_obj.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
+            except Exception as e:
+                log.debug("NonCopperClear.clear_copper() 'itself'  --> %s" % str(e))
+                self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
+                return 'fail'
+
+        elif ncc_select == 'area':
+            geo_n = cascaded_union(self.sel_rect)
+            try:
+                __ = iter(geo_n)
+            except Exception as e:
+                log.debug("NonCopperClear.clear_copper() 'area' --> %s" % str(e))
+                geo_n = [geo_n]
+
+            geo_buff_list = []
+            for poly in geo_n:
+                if self.app.abort_flag:
+                    # graceful abort requested by the user
+                    raise FlatCAMApp.GracefulException
+                geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
+
+            bounding_box = cascaded_union(geo_buff_list)
+
+        elif ncc_select == 'box':
+            geo_n = ncc_sel_obj.solid_geometry
+            if ncc_sel_obj.kind == 'geometry':
+                try:
+                    __ = iter(geo_n)
+                except Exception as e:
+                    log.debug("NonCopperClear.clear_copper() 'box' --> %s" % str(e))
+                    geo_n = [geo_n]
+
+                geo_buff_list = []
+                for poly in geo_n:
+                    if self.app.abort_flag:
+                        # graceful abort requested by the user
+                        raise FlatCAMApp.GracefulException
+                    geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
+
+                bounding_box = cascaded_union(geo_buff_list)
+            elif ncc_sel_obj.kind == 'gerber':
+                geo_n = cascaded_union(geo_n).convex_hull
+                bounding_box = cascaded_union(self.ncc_obj.solid_geometry).convex_hull.intersection(geo_n)
+                bounding_box = bounding_box.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)
+            else:
+                self.app.inform.emit('[ERROR_NOTCL] %s' % _("The reference object type is not supported."))
+                return 'fail'
+
+        log.debug("NCC Tool. Finished non-copper polygons.")
+        # ########################################################################################################
+        # set the name for the future Geometry object
+        # I do it here because it is also stored inside the gen_clear_area() and gen_clear_area_rest() methods
+        # ########################################################################################################
+        rest_machining_choice = rest
+        if rest_machining_choice is True:
+            name = outname if outname is not None else self.obj_name + "_ncc_rm"
+        else:
+            name = outname if outname is not None else self.obj_name + "_ncc"
+
+        # ##########################################################################################
+        # Initializes the new geometry object ######################################################
+        # ##########################################################################################
+        def gen_clear_area(geo_obj, app_obj):
+            assert geo_obj.kind == 'geometry', \
+                "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
+
+            # provide the app with a way to process the GUI events when in a blocking loop
+            if not run_threaded:
+                QtWidgets.QApplication.processEvents()
+
+            log.debug("NCC Tool. Normal copper clearing task started.")
+            self.app.inform.emit(_("NCC Tool. Finished non-copper polygons. Normal copper clearing task started."))
+
+            # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
+            # will store the number of tools for which the isolation is broken
+            warning_flag = 0
+
+            if order == 'fwd':
+                sorted_tools.sort(reverse=False)
+            elif order == 'rev':
+                sorted_tools.sort(reverse=True)
+            else:
+                pass
+
+            cleared_geo = []
+            # Already cleared area
+            cleared = MultiPolygon()
+
+            # flag for polygons not cleared
+            app_obj.poly_not_cleared = False
+
+            # Generate area for each tool
+            offset = sum(sorted_tools)
+            current_uid = int(1)
+            try:
+                tool = eval(self.app.defaults["tools_ncctools"])[0]
+            except TypeError:
+                tool = eval(self.app.defaults["tools_ncctools"])
+
+            # ###################################################################################################
+            # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
+            # ###################################################################################################
+            log.debug("NCC Tool. Calculate 'empty' area.")
+            self.app.inform.emit(_("NCC Tool. Calculate 'empty' area."))
+
+            if ncc_obj.kind == 'gerber' and not isotooldia:
+                # unfortunately for this function to work time efficient,
+                # if the Gerber was loaded without buffering then it require the buffering now.
+                if self.app.defaults['gerber_buffering'] == 'no':
+                    sol_geo = ncc_obj.solid_geometry.buffer(0)
+                else:
+                    sol_geo = ncc_obj.solid_geometry
+
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Could not get the extent of the area to be non copper cleared."))
+                    return 'fail'
+            elif ncc_obj.kind == 'gerber' and isotooldia:
+                isolated_geo = []
+
+                # unfortunately for this function to work time efficient,
+                # if the Gerber was loaded without buffering then it require the buffering now.
+                if self.app.defaults['gerber_buffering'] == 'no':
+                    self.solid_geometry = ncc_obj.solid_geometry.buffer(0)
+                else:
+                    self.solid_geometry = ncc_obj.solid_geometry
+
+                # if milling type is climb then the move is counter-clockwise around features
+                milling_type = self.app.defaults["tools_nccmilling_type"]
+
+                for tool_iso in isotooldia:
+                    new_geometry = []
+
+                    if milling_type == 'cl':
+                        isolated_geo = self.generate_envelope(tool_iso / 2, 1)
+                    else:
+                        isolated_geo = self.generate_envelope(tool_iso / 2, 0)
+
+                    if isolated_geo == 'fail':
+                        app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
+                    else:
+                        if ncc_margin < tool_iso:
+                            app_obj.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
+                                                                         "than isolation tool diameter."))
+                        try:
+                            for geo_elem in isolated_geo:
+                                # provide the app with a way to process the GUI events when in a blocking loop
+                                QtWidgets.QApplication.processEvents()
+
+                                if self.app.abort_flag:
+                                    # graceful abort requested by the user
+                                    raise FlatCAMApp.GracefulException
+
+                                if isinstance(geo_elem, Polygon):
+                                    for ring in self.poly2rings(geo_elem):
+                                        new_geo = ring.intersection(bounding_box)
+                                        if new_geo and not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, MultiPolygon):
+                                    for poly in geo_elem:
+                                        for ring in self.poly2rings(poly):
+                                            new_geo = ring.intersection(bounding_box)
+                                            if new_geo and not new_geo.is_empty:
+                                                new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, LineString):
+                                    new_geo = geo_elem.intersection(bounding_box)
+                                    if new_geo:
+                                        if not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, MultiLineString):
+                                    for line_elem in geo_elem:
+                                        new_geo = line_elem.intersection(bounding_box)
+                                        if new_geo and not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                        except TypeError:
+                            if isinstance(isolated_geo, Polygon):
+                                for ring in self.poly2rings(isolated_geo):
+                                    new_geo = ring.intersection(bounding_box)
+                                    if new_geo:
+                                        if not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                            elif isinstance(isolated_geo, LineString):
+                                new_geo = isolated_geo.intersection(bounding_box)
+                                if new_geo and not new_geo.is_empty:
+                                    new_geometry.append(new_geo)
+                            elif isinstance(isolated_geo, MultiLineString):
+                                for line_elem in isolated_geo:
+                                    new_geo = line_elem.intersection(bounding_box)
+                                    if new_geo and not new_geo.is_empty:
+                                        new_geometry.append(new_geo)
+
+                        # a MultiLineString geometry element will show that the isolation is broken for this tool
+                        for geo_e in new_geometry:
+                            if type(geo_e) == MultiLineString:
+                                warning_flag += 1
+                                break
+
+                        for k, v in tools_storage.items():
+                            if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
+                                                                                                tool_iso)):
+                                current_uid = int(k)
+                                # add the solid_geometry to the current too in self.paint_tools dictionary
+                                # and then reset the temporary list that stored that solid_geometry
+                                v['solid_geometry'] = deepcopy(new_geometry)
+                                v['data']['name'] = name
+                                break
+                        geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
+
+                sol_geo = cascaded_union(isolated_geo)
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
+                    return 'fail'
+
+            elif ncc_obj.kind == 'geometry':
+                sol_geo = cascaded_union(ncc_obj.solid_geometry)
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' %  _("Buffering finished"))
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Could not get the extent of the area to be non copper cleared."))
+                    return 'fail'
+
+            else:
+                app_obj.inform.emit('[ERROR_NOTCL] %s' %  _('The selected object is not suitable for copper clearing.'))
+                return 'fail'
+
+            if type(empty) is Polygon:
+                empty = MultiPolygon([empty])
+
+            log.debug("NCC Tool. Finished calculation of 'empty' area.")
+            self.app.inform.emit(_("NCC Tool. Finished calculation of 'empty' area."))
+
+            # COPPER CLEARING #
+            cp = None
+            for tool in sorted_tools:
+                log.debug("Starting geometry processing for tool: %s" % str(tool))
+                if self.app.abort_flag:
+                    # graceful abort requested by the user
+                    raise FlatCAMApp.GracefulException
+
+                # provide the app with a way to process the GUI events when in a blocking loop
+                QtWidgets.QApplication.processEvents()
+
+                app_obj.inform.emit('[success] %s = %s%s %s' % (
+                    _('NCC Tool clearing with tool diameter'), str(tool), units.lower(), _('started.'))
+                )
+                app_obj.proc_container.update_view_text(' %d%%' % 0)
+
+                cleared_geo[:] = []
+
+                # Get remaining tools offset
+                offset -= (tool - 1e-12)
+
+                # Area to clear
+                area = empty.buffer(-offset)
+                try:
+                    area = area.difference(cleared)
+                except Exception as e:
+                    continue
+
+                # Transform area to MultiPolygon
+                if type(area) is Polygon:
+                    area = MultiPolygon([area])
+
+                # variables to display the percentage of work done
+                geo_len = len(area.geoms)
+
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                if area.geoms:
+                    if len(area.geoms) > 0:
+                        pol_nr = 0
+                        for p in area.geoms:
+                            # provide the app with a way to process the GUI events when in a blocking loop
+                            QtWidgets.QApplication.processEvents()
+
+                            if self.app.abort_flag:
+                                # graceful abort requested by the user
+                                raise FlatCAMApp.GracefulException
+
+                            # clean the polygon
+                            p = p.buffer(0)
+
+                            if p is not None and p.is_valid:
+                                poly_processed = list()
+                                try:
+                                    for pol in p:
+                                        if pol is not None and isinstance(pol, Polygon):
+                                            if ncc_method == 'standard':
+                                                cp = self.clear_polygon(pol, tool,
+                                                                        self.grb_circle_steps,
+                                                                        overlap=overlap, contour=contour,
+                                                                        connect=connect,
+                                                                        prog_plot=False)
+                                            elif ncc_method == 'seed':
+                                                cp = self.clear_polygon2(pol, tool,
+                                                                         self.grb_circle_steps,
+                                                                         overlap=overlap, contour=contour,
+                                                                         connect=connect,
+                                                                         prog_plot=False)
+                                            else:
+                                                cp = self.clear_polygon3(pol, tool,
+                                                                         self.grb_circle_steps,
+                                                                         overlap=overlap, contour=contour,
+                                                                         connect=connect,
+                                                                         prog_plot=False)
+                                            if cp:
+                                                cleared_geo += list(cp.get_objects())
+                                                poly_processed.append(True)
+                                            else:
+                                                poly_processed.append(False)
+                                                log.warning("Polygon in MultiPolygon can not be cleared.")
+                                        else:
+                                            log.warning("Geo in Iterable can not be cleared because it is not Polygon. "
+                                                        "It is: %s" % str(type(pol)))
+                                except TypeError:
+                                    if isinstance(p, Polygon):
+                                        if ncc_method == 'standard':
+                                            cp = self.clear_polygon(p, tool, self.grb_circle_steps,
+                                                                    overlap=overlap, contour=contour, connect=connect,
+                                                                    prog_plot=False)
+                                        elif ncc_method == 'seed':
+                                            cp = self.clear_polygon2(p, tool, self.grb_circle_steps,
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=False)
+                                        else:
+                                            cp = self.clear_polygon3(p, tool, self.grb_circle_steps,
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=False)
+                                        if cp:
+                                            cleared_geo += list(cp.get_objects())
+                                            poly_processed.append(True)
+                                        else:
+                                            poly_processed.append(False)
+                                            log.warning("Polygon can not be cleared.")
+                                    else:
+                                        log.warning("Geo can not be cleared because it is: %s" % str(type(p)))
+
+                                p_cleared = poly_processed.count(True)
+                                p_not_cleared = poly_processed.count(False)
+
+                                if p_not_cleared:
+                                    app_obj.poly_not_cleared = True
+
+                                if p_cleared == 0:
+                                    continue
+
+                                pol_nr += 1
+                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
+                                # log.debug("Polygons cleared: %d" % pol_nr)
+
+                                if old_disp_number < disp_number <= 100:
+                                    self.app.proc_container.update_view_text(' %d%%' % disp_number)
+                                    old_disp_number = disp_number
+                                    # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
+                            # check if there is a geometry at all in the cleared geometry
+                        if cleared_geo:
+                            # Overall cleared area
+                            cleared = empty.buffer(-offset * (1 + overlap)).buffer(-tool / 1.999999).buffer(
+                                tool / 1.999999)
+
+                            # clean-up cleared geo
+                            cleared = cleared.buffer(0)
+
+                            # find the tooluid associated with the current tool_dia so we know where to add the tool
+                            # solid_geometry
+                            for k, v in tools_storage.items():
+                                if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
+                                                                                                    tool)):
+                                    current_uid = int(k)
+
+                                    # add the solid_geometry to the current too in self.paint_tools dictionary
+                                    # and then reset the temporary list that stored that solid_geometry
+                                    v['solid_geometry'] = deepcopy(cleared_geo)
+                                    v['data']['name'] = name
+                                    break
+                            geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
+                        else:
+                            log.debug("There are no geometries in the cleared polygon.")
+
+            # delete tools with empty geometry
+            # look for keys in the tools_storage dict that have 'solid_geometry' values empty
+            for uid, uid_val in list(tools_storage.items()):
+                try:
+                    # if the solid_geometry (type=list) is empty
+                    if not uid_val['solid_geometry']:
+                        tools_storage.pop(uid, None)
+                except KeyError:
+                    tools_storage.pop(uid, None)
+
+            geo_obj.options["cnctooldia"] = str(tool)
+
+            geo_obj.multigeo = True
+            geo_obj.tools.clear()
+            geo_obj.tools = dict(tools_storage)
+
+            # test if at least one tool has solid_geometry. If no tool has solid_geometry we raise an Exception
+            has_solid_geo = 0
+            for tooluid in geo_obj.tools:
+                if geo_obj.tools[tooluid]['solid_geometry']:
+                    has_solid_geo += 1
+            if has_solid_geo == 0:
+                app_obj.inform.emit('[ERROR] %s' %
+                                    _("There is no NCC Geometry in the file.\n"
+                                      "Usually it means that the tool diameter is too big for the painted geometry.\n"
+                                      "Change the painting parameters and try again."))
+                return 'fail'
+
+            # check to see if geo_obj.tools is empty
+            # it will be updated only if there is a solid_geometry for tools
+            if geo_obj.tools:
+                if warning_flag == 0:
+                    self.app.inform.emit('[success] %s' % _("NCC Tool clear all done."))
+                else:
+                    self.app.inform.emit('[WARNING] %s: %s %s.' % (
+                        _("NCC Tool clear all done but the copper features isolation is broken for"),
+                        str(warning_flag),
+                        _("tools")))
+                    return
+
+                # create the solid_geometry
+                geo_obj.solid_geometry = list()
+                for tooluid in geo_obj.tools:
+                    if geo_obj.tools[tooluid]['solid_geometry']:
+                        try:
+                            for geo in geo_obj.tools[tooluid]['solid_geometry']:
+                                geo_obj.solid_geometry.append(geo)
+                        except TypeError:
+                            geo_obj.solid_geometry.append(geo_obj.tools[tooluid]['solid_geometry'])
+            else:
+                # I will use this variable for this purpose although it was meant for something else
+                # signal that we have no geo in the object therefore don't create it
+                app_obj.poly_not_cleared = False
+                return "fail"
+
+        # ###########################################################################################
+        # Initializes the new geometry object for the case of the rest-machining ####################
+        # ###########################################################################################
+        def gen_clear_area_rest(geo_obj, app_obj):
+            assert geo_obj.kind == 'geometry', \
+                "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
+
+            log.debug("NCC Tool. Rest machining copper clearing task started.")
+            app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.')
+
+            # provide the app with a way to process the GUI events when in a blocking loop
+            if not run_threaded:
+                QtWidgets.QApplication.processEvents()
+
+            # a flag to signal that the isolation is broken by the bounding box in 'area' and 'box' cases
+            # will store the number of tools for which the isolation is broken
+            warning_flag = 0
+
+            sorted_tools.sort(reverse=True)
+
+            cleared_geo = []
+            cleared_by_last_tool = []
+            rest_geo = []
+            current_uid = 1
+            try:
+                tool = eval(self.app.defaults["tools_ncctools"])[0]
+            except TypeError:
+                tool = eval(self.app.defaults["tools_ncctools"])
+
+            # repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
+            app_obj.poly_not_cleared = True
+            log.debug("NCC Tool. Calculate 'empty' area.")
+            app_obj.inform.emit("NCC Tool. Calculate 'empty' area.")
+
+            # ###################################################################################################
+            # Calculate the empty area by subtracting the solid_geometry from the object bounding box geometry ##
+            # ###################################################################################################
+            if ncc_obj.kind == 'gerber' and not isotooldia:
+                sol_geo = ncc_obj.solid_geometry
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' %  _("Buffering finished"))
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Could not get the extent of the area to be non copper cleared."))
+                    return 'fail'
+            elif ncc_obj.kind == 'gerber' and isotooldia:
+                isolated_geo = []
+                self.solid_geometry = ncc_obj.solid_geometry
+
+                # if milling type is climb then the move is counter-clockwise around features
+                milling_type = self.app.defaults["tools_nccmilling_type"]
+
+                for tool_iso in isotooldia:
+                    new_geometry = []
+
+                    if milling_type == 'cl':
+                        isolated_geo = self.generate_envelope(tool_iso, 1)
+                    else:
+                        isolated_geo = self.generate_envelope(tool_iso, 0)
+
+                    if isolated_geo == 'fail':
+                        app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Isolation geometry could not be generated."))
+                    else:
+                        app_obj.inform.emit('[WARNING_NOTCL] %s' % _("Isolation geometry is broken. Margin is less "
+                                                                     "than isolation tool diameter."))
+
+                        try:
+                            for geo_elem in isolated_geo:
+                                # provide the app with a way to process the GUI events when in a blocking loop
+                                QtWidgets.QApplication.processEvents()
+
+                                if self.app.abort_flag:
+                                    # graceful abort requested by the user
+                                    raise FlatCAMApp.GracefulException
+
+                                if isinstance(geo_elem, Polygon):
+                                    for ring in self.poly2rings(geo_elem):
+                                        new_geo = ring.intersection(bounding_box)
+                                        if new_geo and not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, MultiPolygon):
+                                    for poly in geo_elem:
+                                        for ring in self.poly2rings(poly):
+                                            new_geo = ring.intersection(bounding_box)
+                                            if new_geo and not new_geo.is_empty:
+                                                new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, LineString):
+                                    new_geo = geo_elem.intersection(bounding_box)
+                                    if new_geo:
+                                        if not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                                elif isinstance(geo_elem, MultiLineString):
+                                    for line_elem in geo_elem:
+                                        new_geo = line_elem.intersection(bounding_box)
+                                        if new_geo and not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                        except TypeError:
+                            try:
+                                if isinstance(isolated_geo, Polygon):
+                                    for ring in self.poly2rings(isolated_geo):
+                                        new_geo = ring.intersection(bounding_box)
+                                        if new_geo:
+                                            if not new_geo.is_empty:
+                                                new_geometry.append(new_geo)
+                                elif isinstance(isolated_geo, LineString):
+                                    new_geo = isolated_geo.intersection(bounding_box)
+                                    if new_geo and not new_geo.is_empty:
+                                        new_geometry.append(new_geo)
+                                elif isinstance(isolated_geo, MultiLineString):
+                                    for line_elem in isolated_geo:
+                                        new_geo = line_elem.intersection(bounding_box)
+                                        if new_geo and not new_geo.is_empty:
+                                            new_geometry.append(new_geo)
+                            except Exception as e:
+                                pass
+
+                        # a MultiLineString geometry element will show that the isolation is broken for this tool
+                        for geo_e in new_geometry:
+                            if type(geo_e) == MultiLineString:
+                                warning_flag += 1
+                                break
+
+                        for k, v in tools_storage.items():
+                            if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
+                                                                                                tool_iso)):
+                                current_uid = int(k)
+                                # add the solid_geometry to the current too in self.paint_tools dictionary
+                                # and then reset the temporary list that stored that solid_geometry
+                                v['solid_geometry'] = deepcopy(new_geometry)
+                                v['data']['name'] = name
+                                break
+                        geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
+
+                sol_geo = cascaded_union(isolated_geo)
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Isolation geometry is broken. Margin is less than isolation tool diameter."))
+                    return 'fail'
+
+            elif ncc_obj.kind == 'geometry':
+                sol_geo = cascaded_union(ncc_obj.solid_geometry)
+                if has_offset is True:
+                    app_obj.inform.emit('[WARNING_NOTCL] %s ...' % _("Buffering"))
+                    sol_geo = sol_geo.buffer(distance=ncc_offset)
+                    app_obj.inform.emit('[success] %s ...' % _("Buffering finished"))
+                empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
+                if empty == 'fail':
+                    return 'fail'
+
+                if empty.is_empty:
+                    app_obj.inform.emit('[ERROR_NOTCL] %s' %
+                                        _("Could not get the extent of the area to be non copper cleared."))
+                    return 'fail'
+            else:
+                app_obj.inform.emit('[ERROR_NOTCL] %s' % _('The selected object is not suitable for copper clearing.'))
+                return
+
+            if self.app.abort_flag:
+                # graceful abort requested by the user
+                raise FlatCAMApp.GracefulException
+
+            if type(empty) is Polygon:
+                empty = MultiPolygon([empty])
+
+            area = empty.buffer(0)
+
+            log.debug("NCC Tool. Finished calculation of 'empty' area.")
+            app_obj.inform.emit("NCC Tool. Finished calculation of 'empty' area.")
+
+            # Generate area for each tool
+            while sorted_tools:
+                if self.app.abort_flag:
+                    # graceful abort requested by the user
+                    raise FlatCAMApp.GracefulException
+
+                tool = sorted_tools.pop(0)
+                log.debug("Starting geometry processing for tool: %s" % str(tool))
+
+                app_obj.inform.emit('[success] %s = %s%s %s' % (
+                    _('NCC Tool clearing with tool diameter'), str(tool), units.lower(), _('started.'))
+                )
+                app_obj.proc_container.update_view_text(' %d%%' % 0)
+
+                tool_used = tool - 1e-12
+                cleared_geo[:] = []
+
+                # Area to clear
+                for poly in cleared_by_last_tool:
+                    # provide the app with a way to process the GUI events when in a blocking loop
+                    QtWidgets.QApplication.processEvents()
+
+                    if self.app.abort_flag:
+                        # graceful abort requested by the user
+                        raise FlatCAMApp.GracefulException
+                    try:
+                        area = area.difference(poly)
+                    except Exception as e:
+                        pass
+                cleared_by_last_tool[:] = []
+
+                # Transform area to MultiPolygon
+                if type(area) is Polygon:
+                    area = MultiPolygon([area])
+
+                # add the rest that was not able to be cleared previously; area is a MultyPolygon
+                # and rest_geo it's a list
+                allparts = [p.buffer(0) for p in area.geoms]
+                allparts += deepcopy(rest_geo)
+                rest_geo[:] = []
+                area = MultiPolygon(deepcopy(allparts))
+                allparts[:] = []
+
+                # variables to display the percentage of work done
+                geo_len = len(area.geoms)
+                disp_number = 0
+                old_disp_number = 0
+                log.warning("Total number of polygons to be cleared. %s" % str(geo_len))
+
+                if area.geoms:
+                    if len(area.geoms) > 0:
+                        pol_nr = 0
+                        for p in area.geoms:
+                            if self.app.abort_flag:
+                                # graceful abort requested by the user
+                                raise FlatCAMApp.GracefulException
+
+                            # clean the polygon
+                            p = p.buffer(0)
+
+                            if p is not None and p.is_valid:
+                                # provide the app with a way to process the GUI events when in a blocking loop
+                                QtWidgets.QApplication.processEvents()
+
+                                if isinstance(p, Polygon):
+                                    try:
+                                        if ncc_method == 'standard':
+                                            cp = self.clear_polygon(p, tool_used,
+                                                                    self.grb_circle_steps,
+                                                                    overlap=overlap, contour=contour, connect=connect,
+                                                                    prog_plot=False)
+                                        elif ncc_method == 'seed':
+                                            cp = self.clear_polygon2(p, tool_used,
+                                                                     self.grb_circle_steps,
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=False)
+                                        else:
+                                            cp = self.clear_polygon3(p, tool_used,
+                                                                     self.grb_circle_steps,
+                                                                     overlap=overlap, contour=contour, connect=connect,
+                                                                     prog_plot=False)
+                                        cleared_geo.append(list(cp.get_objects()))
+                                    except Exception as e:
+                                        log.warning("Polygon can't be cleared. %s" % str(e))
+                                        # this polygon should be added to a list and then try clear it with
+                                        # a smaller tool
+                                        rest_geo.append(p)
+                                elif isinstance(p, MultiPolygon):
+                                    for poly in p:
+                                        if poly is not None:
+                                            # provide the app with a way to process the GUI events when
+                                            # in a blocking loop
+                                            QtWidgets.QApplication.processEvents()
+
+                                            try:
+                                                if ncc_method == 'standard':
+                                                    cp = self.clear_polygon(poly, tool_used,
+                                                                            self.grb_circle_steps,
+                                                                            overlap=overlap, contour=contour,
+                                                                            connect=connect,
+                                                                            prog_plot=False)
+                                                elif ncc_method == 'seed':
+                                                    cp = self.clear_polygon2(poly, tool_used,
+                                                                             self.grb_circle_steps,
+                                                                             overlap=overlap, contour=contour,
+                                                                             connect=connect,
+                                                                             prog_plot=False)
+                                                else:
+                                                    cp = self.clear_polygon3(poly, tool_used,
+                                                                             self.grb_circle_steps,
+                                                                             overlap=overlap, contour=contour,
+                                                                             connect=connect,
+                                                                             prog_plot=False)
+                                                cleared_geo.append(list(cp.get_objects()))
+                                            except Exception as e:
+                                                log.warning("Polygon can't be cleared. %s" % str(e))
+                                                # this polygon should be added to a list and then try clear it with
+                                                # a smaller tool
+                                                rest_geo.append(poly)
+
+                                pol_nr += 1
+                                disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
+                                # log.debug("Polygons cleared: %d" % pol_nr)
+
+                                if old_disp_number < disp_number <= 100:
+                                    self.app.proc_container.update_view_text(' %d%%' % disp_number)
+                                    old_disp_number = disp_number
+                                    # log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
+
+                        if self.app.abort_flag:
+                            # graceful abort requested by the user
+                            raise FlatCAMApp.GracefulException
+
+                        # check if there is a geometry at all in the cleared geometry
+                        if cleared_geo:
+                            # Overall cleared area
+                            cleared_area = list(self.flatten_list(cleared_geo))
+
+                            # cleared = MultiPolygon([p.buffer(tool_used / 2).buffer(-tool_used / 2)
+                            #                         for p in cleared_area])
+
+                            # here we store the poly's already processed in the original geometry by the current tool
+                            # into cleared_by_last_tool list
+                            # this will be sutracted from the original geometry_to_be_cleared and make data for
+                            # the next tool
+                            buffer_value = tool_used / 2
+                            for p in cleared_area:
+                                if self.app.abort_flag:
+                                    # graceful abort requested by the user
+                                    raise FlatCAMApp.GracefulException
+
+                                poly = p.buffer(buffer_value)
+                                cleared_by_last_tool.append(poly)
+
+                            # find the tooluid associated with the current tool_dia so we know
+                            # where to add the tool solid_geometry
+                            for k, v in tools_storage.items():
+                                if float('%.*f' % (self.decimals, v['tooldia'])) == float('%.*f' % (self.decimals,
+                                                                                                    tool)):
+                                    current_uid = int(k)
+
+                                    # add the solid_geometry to the current too in self.paint_tools dictionary
+                                    # and then reset the temporary list that stored that solid_geometry
+                                    v['solid_geometry'] = deepcopy(cleared_area)
+                                    v['data']['name'] = name
+                                    cleared_area[:] = []
+                                    break
+
+                            geo_obj.tools[current_uid] = dict(tools_storage[current_uid])
+                        else:
+                            log.debug("There are no geometries in the cleared polygon.")
+
+            geo_obj.multigeo = True
+            geo_obj.options["cnctooldia"] = str(tool)
+
+            # check to see if geo_obj.tools is empty
+            # it will be updated only if there is a solid_geometry for tools
+            if geo_obj.tools:
+                if warning_flag == 0:
+                    self.app.inform.emit('[success] %s' % _("NCC Tool Rest Machining clear all done."))
+                else:
+                    self.app.inform.emit(
+                        '[WARNING] %s: %s %s.' % (_("NCC Tool Rest Machining clear all done but the copper features "
+                                                    "isolation is broken for"), str(warning_flag), _("tools")))
+                    return
+
+                # create the solid_geometry
+                geo_obj.solid_geometry = list()
+                for tooluid in geo_obj.tools:
+                    if geo_obj.tools[tooluid]['solid_geometry']:
+                        try:
+                            for geo in geo_obj.tools[tooluid]['solid_geometry']:
+                                geo_obj.solid_geometry.append(geo)
+                        except TypeError:
+                            geo_obj.solid_geometry.append(geo_obj.tools[tooluid]['solid_geometry'])
+            else:
+                # I will use this variable for this purpose although it was meant for something else
+                # signal that we have no geo in the object therefore don't create it
+                app_obj.poly_not_cleared = False
+                return "fail"
+
+        # ###########################################################################################
+        # Create the Job function and send it to the worker to be processed in another thread #######
+        # ###########################################################################################
+        def job_thread(app_obj):
+            try:
+                if rest_machining_choice is True:
+                    app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
+                else:
+                    app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
+            except FlatCAMApp.GracefulException:
+                if run_threaded:
+                    proc.done()
+                return
+            except Exception:
+                if run_threaded:
+                    proc.done()
+                traceback.print_stack()
+                return
+
+            if run_threaded:
+                proc.done()
+            else:
+                app_obj.proc_container.view.set_idle()
+
+            # focus on Selected Tab
+            self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
+
+        if run_threaded:
+            # Promise object with the new name
+            self.app.collection.promise(name)
+
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
 
     def get_ncc_empty_area(self, target, boundary=None):
     def get_ncc_empty_area(self, target, boundary=None):
         """
         """

+ 0 - 3
flatcamTools/ToolPanelize.py

@@ -484,11 +484,8 @@ class Panelize(FlatCAMTool):
             if panel_obj is not None:
             if panel_obj is not None:
                 self.app.inform.emit(_("Generating panel ... "))
                 self.app.inform.emit(_("Generating panel ... "))
 
 
-                self.app.progress.emit(0)
-
                 def job_init_excellon(obj_fin, app_obj):
                 def job_init_excellon(obj_fin, app_obj):
                     currenty = 0.0
                     currenty = 0.0
-                    self.app.progress.emit(10)
                     obj_fin.tools = copied_tools
                     obj_fin.tools = copied_tools
                     obj_fin.drills = []
                     obj_fin.drills = []
                     obj_fin.slots = []
                     obj_fin.slots = []

+ 2 - 6
flatcamTools/ToolPcbWizard.py

@@ -417,8 +417,6 @@ class PcbWizard(FlatCAMTool):
 
 
         # How the object should be initialized
         # How the object should be initialized
         def obj_init(excellon_obj, app_obj):
         def obj_init(excellon_obj, app_obj):
-            # self.progress.emit(20)
-
             try:
             try:
                 ret = excellon_obj.parse_file(file_obj=excellon_fileobj)
                 ret = excellon_obj.parse_file(file_obj=excellon_fileobj)
                 if ret == "fail":
                 if ret == "fail":
@@ -427,10 +425,8 @@ class PcbWizard(FlatCAMTool):
                                         _("This is not Excellon file."))
                                         _("This is not Excellon file."))
                     return "fail"
                     return "fail"
             except IOError:
             except IOError:
-                app_obj.inform.emit('[ERROR_NOTCL] %s: %s' % (
-                        _("Cannot parse file"), self.outname))
+                app_obj.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Cannot parse file"), self.outname))
                 app_obj.log.debug("Could not import Excellon object.")
                 app_obj.log.debug("Could not import Excellon object.")
-                app_obj.progress.emit(0)
                 return "fail"
                 return "fail"
             except Exception as e:
             except Exception as e:
                 app_obj.log.debug("PcbWizard.on_import_excellon().obj_init() %s" % str(e))
                 app_obj.log.debug("PcbWizard.on_import_excellon().obj_init() %s" % str(e))
@@ -443,7 +439,7 @@ class PcbWizard(FlatCAMTool):
             if ret == 'fail':
             if ret == 'fail':
                 app_obj.log.debug("Could not create geometry for Excellon object.")
                 app_obj.log.debug("Could not create geometry for Excellon object.")
                 return "fail"
                 return "fail"
-            app_obj.progress.emit(100)
+
             for tool in excellon_obj.tools:
             for tool in excellon_obj.tools:
                 if excellon_obj.tools[tool]['solid_geometry']:
                 if excellon_obj.tools[tool]['solid_geometry']:
                     return
                     return

+ 0 - 6
flatcamTools/ToolSolderPaste.py

@@ -1348,8 +1348,6 @@ class SolderPaste(FlatCAMTool):
             job_obj.options['ymax'] = ymax
             job_obj.options['ymax'] = ymax
 
 
             for tooluid_key, tooluid_value in obj.tools.items():
             for tooluid_key, tooluid_value in obj.tools.items():
-                app_obj.progress.emit(20)
-
                 # find the tool_dia associated with the tooluid_key
                 # find the tool_dia associated with the tooluid_key
                 tool_dia = tooluid_value['tooldia']
                 tool_dia = tooluid_value['tooldia']
                 tool_cnc_dict = deepcopy(tooluid_value)
                 tool_cnc_dict = deepcopy(tooluid_value)
@@ -1380,8 +1378,6 @@ class SolderPaste(FlatCAMTool):
                 # tell gcode_parse from which point to start drawing the lines depending on what kind of
                 # tell gcode_parse from which point to start drawing the lines depending on what kind of
                 # object is the source of gcode
                 # object is the source of gcode
                 job_obj.toolchange_xy_type = "geometry"
                 job_obj.toolchange_xy_type = "geometry"
-                app_obj.progress.emit(80)
-
                 job_obj.cnc_tools.update({
                 job_obj.cnc_tools.update({
                     tooluid_key: deepcopy(tool_cnc_dict)
                     tooluid_key: deepcopy(tool_cnc_dict)
                 })
                 })
@@ -1394,8 +1390,6 @@ class SolderPaste(FlatCAMTool):
                     if app_obj.new_object("cncjob", name, job_init) != 'fail':
                     if app_obj.new_object("cncjob", name, job_init) != 'fail':
                         app_obj.inform.emit('[success] [success] %s: %s' %
                         app_obj.inform.emit('[success] [success] %s: %s' %
                                             (_("ToolSolderPaste CNCjob created"), name))
                                             (_("ToolSolderPaste CNCjob created"), name))
-                        app_obj.progress.emit(100)
-
             # Create a promise with the name
             # Create a promise with the name
             self.app.collection.promise(name)
             self.app.collection.promise(name)
             # Send to worker
             # Send to worker

+ 2 - 23
flatcamTools/ToolTransform.py

@@ -682,8 +682,6 @@ class ToolTransform(FlatCAMTool):
                     xmaximal = max(xmaxlist)
                     xmaximal = max(xmaxlist)
                     ymaximal = max(ymaxlist)
                     ymaximal = max(ymaxlist)
 
 
-                    self.app.progress.emit(20)
-
                     px = 0.5 * (xminimal + xmaximal)
                     px = 0.5 * (xminimal + xmaximal)
                     py = 0.5 * (yminimal + ymaximal)
                     py = 0.5 * (yminimal + ymaximal)
                     for sel_obj in obj_list:
                     for sel_obj in obj_list:
@@ -697,8 +695,6 @@ class ToolTransform(FlatCAMTool):
                         sel_obj.options['rotate'] = num
                         sel_obj.options['rotate'] = num
                         sel_obj.plot()
                         sel_obj.plot()
                     self.app.inform.emit('[success] %s...' % _('Rotate done'))
                     self.app.inform.emit('[success] %s...' % _('Rotate done'))
-                    self.app.progress.emit(100)
-
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                                          (_("Due of"), str(e), _("action was not executed.")))
                                          (_("Due of"), str(e), _("action was not executed.")))
@@ -743,8 +739,6 @@ class ToolTransform(FlatCAMTool):
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)
 
 
-                    self.app.progress.emit(20)
-
                     # execute mirroring
                     # execute mirroring
                     for sel_obj in obj_list:
                     for sel_obj in obj_list:
                         if isinstance(sel_obj, FlatCAMCNCjob):
                         if isinstance(sel_obj, FlatCAMCNCjob):
@@ -768,12 +762,9 @@ class ToolTransform(FlatCAMTool):
                                     sel_obj.options['mirror_x'] = not sel_obj.options['mirror_x']
                                     sel_obj.options['mirror_x'] = not sel_obj.options['mirror_x']
                                 else:
                                 else:
                                     sel_obj.options['mirror_x'] = True
                                     sel_obj.options['mirror_x'] = True
-                                self.app.inform.emit('[success] %s...' %
-                                                     _('Flip on the X axis done'))
+                                self.app.inform.emit('[success] %s...' % _('Flip on the X axis done'))
                             self.app.object_changed.emit(sel_obj)
                             self.app.object_changed.emit(sel_obj)
                         sel_obj.plot()
                         sel_obj.plot()
-                    self.app.progress.emit(100)
-
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                                          (_("Due of"), str(e), _("action was not executed.")))
                                          (_("Due of"), str(e), _("action was not executed.")))
@@ -809,8 +800,6 @@ class ToolTransform(FlatCAMTool):
                     xminimal = min(xminlist)
                     xminimal = min(xminlist)
                     yminimal = min(yminlist)
                     yminimal = min(yminlist)
 
 
-                    self.app.progress.emit(20)
-
                     for sel_obj in obj_list:
                     for sel_obj in obj_list:
                         if isinstance(sel_obj, FlatCAMCNCjob):
                         if isinstance(sel_obj, FlatCAMCNCjob):
                             self.app.inform.emit(_("CNCJob objects can't be skewed."))
                             self.app.inform.emit(_("CNCJob objects can't be skewed."))
@@ -825,10 +814,7 @@ class ToolTransform(FlatCAMTool):
                                 sel_obj.options['skew_y'] = num
                                 sel_obj.options['skew_y'] = num
                             self.app.object_changed.emit(sel_obj)
                             self.app.object_changed.emit(sel_obj)
                         sel_obj.plot()
                         sel_obj.plot()
-                    self.app.inform.emit('[success] %s %s %s...' %
-                                         (_('Skew on the'),  str(axis), _("axis done")))
-                    self.app.progress.emit(100)
-
+                    self.app.inform.emit('[success] %s %s %s...' % (_('Skew on the'),  str(axis), _("axis done")))
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                                          (_("Due of"), str(e), _("action was not executed.")))
                                          (_("Due of"), str(e), _("action was not executed.")))
@@ -865,8 +851,6 @@ class ToolTransform(FlatCAMTool):
                     xmaximal = max(xmaxlist)
                     xmaximal = max(xmaxlist)
                     ymaximal = max(ymaxlist)
                     ymaximal = max(ymaxlist)
 
 
-                    self.app.progress.emit(20)
-
                     if point is None:
                     if point is None:
                         px = 0.5 * (xminimal + xmaximal)
                         px = 0.5 * (xminimal + xmaximal)
                         py = 0.5 * (yminimal + ymaximal)
                         py = 0.5 * (yminimal + ymaximal)
@@ -887,7 +871,6 @@ class ToolTransform(FlatCAMTool):
 
 
                     self.app.inform.emit('[success] %s %s %s...' %
                     self.app.inform.emit('[success] %s %s %s...' %
                                          (_('Scale on the'), str(axis), _('axis done')))
                                          (_('Scale on the'), str(axis), _('axis done')))
-                    self.app.progress.emit(100)
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                                          (_("Due of"), str(e), _("action was not executed.")))
                                          (_("Due of"), str(e), _("action was not executed.")))
@@ -903,8 +886,6 @@ class ToolTransform(FlatCAMTool):
         else:
         else:
             with self.app.proc_container.new(_("Applying Offset")):
             with self.app.proc_container.new(_("Applying Offset")):
                 try:
                 try:
-                    self.app.progress.emit(20)
-
                     for sel_obj in obj_list:
                     for sel_obj in obj_list:
                         if isinstance(sel_obj, FlatCAMCNCjob):
                         if isinstance(sel_obj, FlatCAMCNCjob):
                             self.app.inform.emit(_("CNCJob objects can't be offset."))
                             self.app.inform.emit(_("CNCJob objects can't be offset."))
@@ -922,8 +903,6 @@ class ToolTransform(FlatCAMTool):
 
 
                     self.app.inform.emit('[success] %s %s %s...' %
                     self.app.inform.emit('[success] %s %s %s...' %
                                          (_('Offset on the'), str(axis), _('axis done')))
                                          (_('Offset on the'), str(axis), _('axis done')))
-                    self.app.progress.emit(100)
-
                 except Exception as e:
                 except Exception as e:
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                     self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
                                          (_("Due of"), str(e),  _("action was not executed.")))
                                          (_("Due of"), str(e),  _("action was not executed.")))

+ 33 - 33
tclCommands/TclCommandCopperClear.py

@@ -219,22 +219,22 @@ class TclCommandCopperClear(TclCommand):
 
 
         # Non-Copper clear all polygons in the non-copper clear object
         # Non-Copper clear all polygons in the non-copper clear object
         if 'all' in args and bool(args['all']):
         if 'all' in args and bool(args['all']):
-            self.app.ncclear_tool.clear_copper(ncc_obj=obj,
-                                               select_method='itself',
-                                               ncctooldia=tooldia,
-                                               overlap=overlap,
-                                               order=order,
-                                               margin=margin,
-                                               has_offset=has_offset,
-                                               offset=offset,
-                                               method=method,
-                                               outname=outname,
-                                               connect=connect,
-                                               contour=contour,
-                                               rest=rest,
-                                               tools_storage=ncc_tools,
-                                               plot=False,
-                                               run_threaded=False)
+            self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
+                                                   select_method='itself',
+                                                   ncctooldia=tooldia,
+                                                   overlap=overlap,
+                                                   order=order,
+                                                   margin=margin,
+                                                   has_offset=has_offset,
+                                                   offset=offset,
+                                                   method=method,
+                                                   outname=outname,
+                                                   connect=connect,
+                                                   contour=contour,
+                                                   rest=rest,
+                                                   tools_storage=ncc_tools,
+                                                   plot=False,
+                                                   run_threaded=False)
             return
             return
 
 
         # Non-Copper clear all polygons found within the box object from the the non_copper cleared object
         # Non-Copper clear all polygons found within the box object from the the non_copper cleared object
@@ -252,23 +252,23 @@ class TclCommandCopperClear(TclCommand):
                     self.raise_tcl_error("%s: %s" % (_("Could not retrieve box object"), name))
                     self.raise_tcl_error("%s: %s" % (_("Could not retrieve box object"), name))
                     return "Could not retrieve object: %s" % name
                     return "Could not retrieve object: %s" % name
 
 
-                self.app.ncclear_tool.clear_copper(ncc_obj=obj,
-                                                   sel_obj=box_obj,
-                                                   select_method='box',
-                                                   ncctooldia=tooldia,
-                                                   overlap=overlap,
-                                                   order=order,
-                                                   margin=margin,
-                                                   has_offset=has_offset,
-                                                   offset=offset,
-                                                   method=method,
-                                                   outname=outname,
-                                                   connect=connect,
-                                                   contour=contour,
-                                                   rest=rest,
-                                                   tools_storage=ncc_tools,
-                                                   plot=False,
-                                                   run_threaded=False)
+                self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
+                                                       sel_obj=box_obj,
+                                                       select_method='box',
+                                                       ncctooldia=tooldia,
+                                                       overlap=overlap,
+                                                       order=order,
+                                                       margin=margin,
+                                                       has_offset=has_offset,
+                                                       offset=offset,
+                                                       method=method,
+                                                       outname=outname,
+                                                       connect=connect,
+                                                       contour=contour,
+                                                       rest=rest,
+                                                       tools_storage=ncc_tools,
+                                                       plot=False,
+                                                       run_threaded=False)
             return
             return
         else:
         else:
             self.raise_tcl_error("%s:" % _("None of the following args: 'ref', 'all' were found or none was set to 1.\n"
             self.raise_tcl_error("%s:" % _("None of the following args: 'ref', 'all' were found or none was set to 1.\n"

+ 0 - 6
tclCommands/TclCommandPanelize.py

@@ -177,11 +177,8 @@ class TclCommandPanelize(TclCommand):
             if obj is not None:
             if obj is not None:
                 self.app.inform.emit("Generating panel ... Please wait.")
                 self.app.inform.emit("Generating panel ... Please wait.")
 
 
-                self.app.progress.emit(0)
-
                 def job_init_excellon(obj_fin, app_obj):
                 def job_init_excellon(obj_fin, app_obj):
                     currenty = 0.0
                     currenty = 0.0
-                    self.app.progress.emit(10)
                     obj_fin.tools = obj.tools.copy()
                     obj_fin.tools = obj.tools.copy()
                     obj_fin.drills = []
                     obj_fin.drills = []
                     obj_fin.slots = []
                     obj_fin.slots = []
@@ -247,7 +244,6 @@ class TclCommandPanelize(TclCommand):
                             for tool in obj.tools:
                             for tool in obj.tools:
                                 obj_fin.tools[tool]['solid_geometry'][:] = []
                                 obj_fin.tools[tool]['solid_geometry'][:] = []
 
 
-                    self.app.progress.emit(0)
                     for row in range(rows):
                     for row in range(rows):
                         currentx = 0.0
                         currentx = 0.0
 
 
@@ -271,10 +267,8 @@ class TclCommandPanelize(TclCommand):
                         currenty += lenghty
                         currenty += lenghty
 
 
                 if isinstance(obj, FlatCAMExcellon):
                 if isinstance(obj, FlatCAMExcellon):
-                    self.app.progress.emit(50)
                     self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
                     self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
                 else:
                 else:
-                    self.app.progress.emit(50)
                     self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
                     self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
 
 
         if threaded is True:
         if threaded is True: