Explorar el Código

- upgraded the Fiducials Tool to create new objects instead of updating in place the source objects
- upgraded the Copper Thieving Tool to create new objects instead of updating in place the source objects
- updated translation strings

Marius Stanciu hace 5 años
padre
commit
84ef0f8a03

+ 3 - 0
CHANGELOG.md

@@ -17,6 +17,9 @@ CHANGELOG for FlatCAM beta
 - made sure that the object selection will not work while in Editors or in the App Tools
 - made sure that the object selection will not work while in Editors or in the App Tools
 - some minor changes to strings and icons
 - some minor changes to strings and icons
 - in Corner Markers Tool - the new Gerber object will have also follow_geometry
 - in Corner Markers Tool - the new Gerber object will have also follow_geometry
+- upgraded the Fiducials Tool to create new objects instead of updating in place the source objects
+- upgraded the Copper Thieving Tool to create new objects instead of updating in place the source objects
+- updated translation strings
 
 
 1.11.2020
 1.11.2020
 
 

+ 1 - 1
appGUI/preferences/tools/ToolsCornersPrefGroupUI.py

@@ -93,7 +93,7 @@ class ToolsCornersPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.l_entry, 8, 1)
         grid0.addWidget(self.l_entry, 8, 1)
 
 
         # Drill Tool Diameter
         # Drill Tool Diameter
-        self.drill_dia_label = FCLabel('%s:' % _("Tool Dia"))
+        self.drill_dia_label = FCLabel('%s:' % _("Drill Dia"))
         self.drill_dia_label.setToolTip(
         self.drill_dia_label.setToolTip(
             '%s.' % _("Drill Diameter")
             '%s.' % _("Drill Diameter")
         )
         )

+ 230 - 188
appTools/ToolCopperThieving.py

@@ -69,7 +69,7 @@ class ToolCopperThieving(AppTool):
         self.cursor_pos = (0, 0)
         self.cursor_pos = (0, 0)
         self.first_click = False
         self.first_click = False
 
 
-        self.area_method = False
+        self.handlers_connected = False
 
 
         # Tool properties
         # Tool properties
         self.clearance_val = None
         self.clearance_val = None
@@ -90,9 +90,9 @@ class ToolCopperThieving(AppTool):
         self.ui.reference_radio.group_toggle_fn = self.on_toggle_reference
         self.ui.reference_radio.group_toggle_fn = self.on_toggle_reference
         self.ui.fill_type_radio.activated_custom.connect(self.on_thieving_type)
         self.ui.fill_type_radio.activated_custom.connect(self.on_thieving_type)
 
 
-        self.ui.fill_button.clicked.connect(self.execute)
-        self.ui.rb_button.clicked.connect(self.add_robber_bar)
-        self.ui.ppm_button.clicked.connect(self.on_add_ppm)
+        self.ui.fill_button.clicked.connect(self.on_add_copper_thieving_click)
+        self.ui.rb_button.clicked.connect(self.on_add_robber_bar_click)
+        self.ui.ppm_button.clicked.connect(self.on_add_ppm_click)
         self.ui.reset_button.clicked.connect(self.set_tool_ui)
         self.ui.reset_button.clicked.connect(self.set_tool_ui)
 
 
         self.work_finished.connect(self.on_new_pattern_plating_object)
         self.work_finished.connect(self.on_new_pattern_plating_object)
@@ -150,7 +150,7 @@ class ToolCopperThieving(AppTool):
         self.ui.clearance_ppm_entry.set_value(self.app.defaults["tools_copper_thieving_mask_clearance"])
         self.ui.clearance_ppm_entry.set_value(self.app.defaults["tools_copper_thieving_mask_clearance"])
 
 
         # INIT SECTION
         # INIT SECTION
-        self.area_method = False
+        self.handlers_connected = False
         self.robber_geo = None
         self.robber_geo = None
         self.robber_line = None
         self.robber_line = None
         self.new_solid_geometry = None
         self.new_solid_geometry = None
@@ -211,7 +211,7 @@ class ToolCopperThieving(AppTool):
             self.ui.squares_frame.hide()
             self.ui.squares_frame.hide()
             self.ui.lines_frame.show()
             self.ui.lines_frame.show()
 
 
-    def add_robber_bar(self):
+    def on_add_robber_bar_click(self):
         rb_margin = self.ui.rb_margin_entry.get_value()
         rb_margin = self.ui.rb_margin_entry.get_value()
         self.rb_thickness = self.ui.rb_thickness_entry.get_value()
         self.rb_thickness = self.ui.rb_thickness_entry.get_value()
 
 
@@ -222,13 +222,13 @@ class ToolCopperThieving(AppTool):
         try:
         try:
             self.grb_object = model_index.internalPointer().obj
             self.grb_object = model_index.internalPointer().obj
         except Exception as e:
         except Exception as e:
-            log.debug("ToolCopperThieving.add_robber_bar() --> %s" % str(e))
+            log.debug("ToolCopperThieving.on_add_robber_bar_click() --> %s" % str(e))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             return
             return
 
 
         try:
         try:
             outline_pol = self.grb_object.solid_geometry.envelope
             outline_pol = self.grb_object.solid_geometry.envelope
-        except TypeError:
+        except (TypeError, AttributeError):
             outline_pol = MultiPolygon(self.grb_object.solid_geometry).envelope
             outline_pol = MultiPolygon(self.grb_object.solid_geometry).envelope
 
 
         rb_distance = rb_margin + (self.rb_thickness / 2.0)
         rb_distance = rb_margin + (self.rb_thickness / 2.0)
@@ -238,6 +238,7 @@ class ToolCopperThieving(AppTool):
 
 
         self.app.proc_container.update_view_text(' %s' % _("Append geometry"))
         self.app.proc_container.update_view_text(' %s' % _("Append geometry"))
 
 
+        new_apertures = deepcopy(self.grb_object.apertures)
         aperture_found = None
         aperture_found = None
         for ap_id, ap_val in self.grb_object.apertures.items():
         for ap_id, ap_val in self.grb_object.apertures.items():
             if ap_val['type'] == 'C' and ap_val['size'] == self.rb_thickness:
             if ap_val['type'] == 'C' and ap_val['size'] == self.rb_thickness:
@@ -246,46 +247,66 @@ class ToolCopperThieving(AppTool):
 
 
         if aperture_found:
         if aperture_found:
             geo_elem = {'solid': self.robber_geo, 'follow': self.robber_line}
             geo_elem = {'solid': self.robber_geo, 'follow': self.robber_line}
-            self.grb_object.apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
+            new_apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
         else:
         else:
-            ap_keys = list(self.grb_object.apertures.keys())
+            ap_keys = list(new_apertures.keys())
             if ap_keys:
             if ap_keys:
                 new_apid = str(int(max(ap_keys)) + 1)
                 new_apid = str(int(max(ap_keys)) + 1)
             else:
             else:
                 new_apid = '10'
                 new_apid = '10'
 
 
-            self.grb_object.apertures[new_apid] = {}
-            self.grb_object.apertures[new_apid]['type'] = 'C'
-            self.grb_object.apertures[new_apid]['size'] = self.rb_thickness
-            self.grb_object.apertures[new_apid]['geometry'] = []
+            new_apertures[new_apid] = {
+                'type': 'C',
+                'size': deepcopy(self.rb_thickness),
+                'geometry': []
+            }
 
 
             geo_elem = {'solid': self.robber_geo, 'follow': self.robber_line}
             geo_elem = {'solid': self.robber_geo, 'follow': self.robber_line}
-            self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
+            new_apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
 
 
-        geo_obj = self.grb_object.solid_geometry
+        geo_obj = deepcopy(self.grb_object.solid_geometry)
         if isinstance(geo_obj, MultiPolygon):
         if isinstance(geo_obj, MultiPolygon):
             s_list = []
             s_list = []
             for pol in geo_obj.geoms:
             for pol in geo_obj.geoms:
                 s_list.append(pol)
                 s_list.append(pol)
-            s_list.append(self.robber_geo)
+            s_list.append(deepcopy(self.robber_geo))
             geo_obj = MultiPolygon(s_list)
             geo_obj = MultiPolygon(s_list)
         elif isinstance(geo_obj, list):
         elif isinstance(geo_obj, list):
-            geo_obj.append(self.robber_geo)
+            geo_obj.append(deepcopy(self.robber_geo))
         elif isinstance(geo_obj, Polygon):
         elif isinstance(geo_obj, Polygon):
-            geo_obj = MultiPolygon([geo_obj, self.robber_geo])
+            geo_obj = MultiPolygon([geo_obj, deepcopy(self.robber_geo)])
+
+        outname = '%s_%s' % (str(self.grb_object.options['name']), 'robber')
 
 
-        self.grb_object.solid_geometry = geo_obj
+        def initialize(grb_obj, app_obj):
+            grb_obj.options = {}
+            for opt in self.grb_object.options:
+                if opt != 'name':
+                    grb_obj.options[opt] = deepcopy(self.grb_object.options[opt])
+            grb_obj.options['name'] = outname
+            grb_obj.multitool = False
+            grb_obj.multigeo = False
+            grb_obj.follow = deepcopy(self.grb_object.follow)
+            grb_obj.apertures = new_apertures
+            grb_obj.solid_geometry = unary_union(geo_obj)
+            grb_obj.follow_geometry = deepcopy(self.grb_object.follow_geometry) + [deepcopy(self.robber_line)]
 
 
-        self.app.proc_container.update_view_text(' %s' % _("Append source file"))
-        # update the source file with the new geometry:
-        self.grb_object.source_file = self.app.f_handlers.export_gerber(obj_name=self.grb_object.options['name'],
-                                                                        filename=None, local_use=self.grb_object,
-                                                                        use_thread=False)
+            app_obj.proc_container.update_view_text(' %s' % _("Append source file"))
+            # update the source file with the new geometry:
+            grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None, local_use=grb_obj,
+                                                                   use_thread=False)
+
+        ret_val = self.app.app_obj.new_object('gerber', outname, initialize, plot=True)
         self.app.proc_container.update_view_text(' %s' % '')
         self.app.proc_container.update_view_text(' %s' % '')
+        if ret_val == 'fail':
+            self.app.call_source = "app"
+            self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+            return
+
         self.on_exit()
         self.on_exit()
         self.app.inform.emit('[success] %s' % _("Copper Thieving Tool done."))
         self.app.inform.emit('[success] %s' % _("Copper Thieving Tool done."))
 
 
-    def execute(self):
+    def on_add_copper_thieving_click(self):
         self.app.call_source = "copper_thieving_tool"
         self.app.call_source = "copper_thieving_tool"
 
 
         self.clearance_val = self.ui.clearance_entry.get_value()
         self.clearance_val = self.ui.clearance_entry.get_value()
@@ -299,7 +320,7 @@ class ToolCopperThieving(AppTool):
         try:
         try:
             self.grb_object = model_index.internalPointer().obj
             self.grb_object = model_index.internalPointer().obj
         except Exception as e:
         except Exception as e:
-            log.debug("ToolCopperThieving.execute() --> %s" % str(e))
+            log.debug("ToolCopperThieving.on_add_copper_thieving_click() --> %s" % str(e))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             return
             return
 
 
@@ -321,20 +342,7 @@ class ToolCopperThieving(AppTool):
 
 
         elif reference_method == 'area':
         elif reference_method == 'area':
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
-
-            self.area_method = True
-
-            if self.app.is_legacy is False:
-                self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
-                self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
-                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-            else:
-                self.app.plotcanvas.graph_event_disconnect(self.app.mp)
-                self.app.plotcanvas.graph_event_disconnect(self.app.mm)
-                self.app.plotcanvas.graph_event_disconnect(self.app.mr)
-
-            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
-            self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
+            self.connect_event_handlers()
 
 
         elif reference_method == 'box':
         elif reference_method == 'box':
             bound_obj_name = self.ui.ref_combo.currentText()
             bound_obj_name = self.ui.ref_combo.currentText()
@@ -401,24 +409,10 @@ class ToolCopperThieving(AppTool):
                 return
                 return
 
 
         elif event.button == right_button and self.mouse_is_dragging is False:
         elif event.button == right_button and self.mouse_is_dragging is False:
-            self.area_method = False
             self.first_click = False
             self.first_click = False
 
 
             self.delete_tool_selection_shape()
             self.delete_tool_selection_shape()
-
-            if self.app.is_legacy is False:
-                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
-                self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
-            else:
-                self.app.plotcanvas.graph_event_disconnect(self.mr)
-                self.app.plotcanvas.graph_event_disconnect(self.mm)
-
-            self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
-                                                                  self.app.on_mouse_click_over_plot)
-            self.app.mm = self.app.plotcanvas.graph_event_connect('mouse_move',
-                                                                  self.app.on_mouse_move_over_plot)
-            self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
-                                                                  self.app.on_mouse_click_release_over_plot)
+            self.disconnect_event_handlers()
 
 
             if len(self.sel_rect) == 0:
             if len(self.sel_rect) == 0:
                 return
                 return
@@ -530,16 +524,16 @@ class ToolCopperThieving(AppTool):
         if not isinstance(self.grb_object.solid_geometry, Iterable):
         if not isinstance(self.grb_object.solid_geometry, Iterable):
             self.grb_object.solid_geometry = [self.grb_object.solid_geometry]
             self.grb_object.solid_geometry = [self.grb_object.solid_geometry]
 
 
-        def job_thread_thieving(app_obj):
-            # #########################################################################################
-            # Prepare isolation polygon. This will create the clearance over the Gerber features ######
-            # #########################################################################################
+        def job_thread_thieving(tool_obj):
+            # #########################################################################################################
+            # Prepare isolation polygon. This will create the clearance over the Gerber features
+            # #########################################################################################################
             log.debug("Copper Thieving Tool. Preparing isolation polygons.")
             log.debug("Copper Thieving Tool. Preparing isolation polygons.")
-            app_obj.app.inform.emit(_("Copper Thieving Tool. Preparing isolation polygons."))
+            tool_obj.app.inform.emit(_("Copper Thieving Tool. Preparing isolation polygons."))
 
 
             # variables to display the percentage of work done
             # variables to display the percentage of work done
             try:
             try:
-                geo_len = len(app_obj.grb_object.solid_geometry)
+                geo_len = len(tool_obj.grb_object.solid_geometry)
             except TypeError:
             except TypeError:
                 geo_len = 1
                 geo_len = 1
 
 
@@ -548,37 +542,37 @@ class ToolCopperThieving(AppTool):
 
 
             clearance_geometry = []
             clearance_geometry = []
             try:
             try:
-                for pol in app_obj.grb_object.solid_geometry:
-                    if app_obj.app.abort_flag:
+                for pol in tool_obj.grb_object.solid_geometry:
+                    if tool_obj.app.abort_flag:
                         # graceful abort requested by the user
                         # graceful abort requested by the user
                         raise grace
                         raise grace
 
 
                     clearance_geometry.append(
                     clearance_geometry.append(
-                        pol.buffer(c_val, int(int(app_obj.geo_steps_per_circle) / 4))
+                        pol.buffer(c_val, int(int(tool_obj.geo_steps_per_circle) / 4))
                     )
                     )
 
 
                     pol_nr += 1
                     pol_nr += 1
                     disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
                     disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
 
 
                     if old_disp_number < disp_number <= 100:
                     if old_disp_number < disp_number <= 100:
-                        app_obj.app.proc_container.update_view_text(' %s ... %d%%' %
-                                                                    (_("Thieving"), int(disp_number)))
+                        msg = ' %s ... %d%%' % (_("Thieving"), int(disp_number))
+                        tool_obj.app.proc_container.update_view_text(msg)
                         old_disp_number = disp_number
                         old_disp_number = disp_number
             except TypeError:
             except TypeError:
                 # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
                 # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
                 # MultiPolygon (not an iterable)
                 # MultiPolygon (not an iterable)
                 clearance_geometry.append(
                 clearance_geometry.append(
-                    app_obj.grb_object.solid_geometry.buffer(c_val, int(int(app_obj.geo_steps_per_circle) / 4))
+                    tool_obj.grb_object.solid_geometry.buffer(c_val, int(int(tool_obj.geo_steps_per_circle) / 4))
                 )
                 )
 
 
-            app_obj.app.proc_container.update_view_text(' %s ...' % _("Buffering"))
+            tool_obj.app.proc_container.update_view_text(' %s ...' % _("Buffering"))
             clearance_geometry = unary_union(clearance_geometry)
             clearance_geometry = unary_union(clearance_geometry)
 
 
-            # #########################################################################################
-            # Prepare the area to fill with copper. ###################################################
-            # #########################################################################################
+            # #########################################################################################################
+            # Prepare the area to fill with copper.
+            # #########################################################################################################
             log.debug("Copper Thieving Tool. Preparing areas to fill with copper.")
             log.debug("Copper Thieving Tool. Preparing areas to fill with copper.")
-            app_obj.app.inform.emit(_("Copper Thieving Tool. Preparing areas to fill with copper."))
+            tool_obj.app.inform.emit(_("Copper Thieving Tool. Preparing areas to fill with copper."))
 
 
             try:
             try:
                 if ref_obj is None or ref_obj == 'itself':
                 if ref_obj is None or ref_obj == 'itself':
@@ -589,12 +583,16 @@ class ToolCopperThieving(AppTool):
                 log.debug("ToolCopperThieving.on_copper_thieving() --> %s" % str(e))
                 log.debug("ToolCopperThieving.on_copper_thieving() --> %s" % str(e))
                 return 'fail'
                 return 'fail'
 
 
-            app_obj.app.proc_container.update_view_text(' %s' % _("Working..."))
+            tool_obj.app.proc_container.update_view_text(' %s' % _("Working..."))
+
+            # #########################################################################################################
+            # generate the bounding box geometry
+            # #########################################################################################################
             if ref_selected == 'itself':
             if ref_selected == 'itself':
-                geo_n = working_obj.solid_geometry
+                geo_n = deepcopy(working_obj.solid_geometry)
 
 
                 try:
                 try:
-                    if app_obj.ui.bbox_type_radio.get_value() == 'min':
+                    if tool_obj.ui.bbox_type_radio.get_value() == 'min':
                         if isinstance(geo_n, MultiPolygon):
                         if isinstance(geo_n, MultiPolygon):
                             env_obj = geo_n.convex_hull
                             env_obj = geo_n.convex_hull
                         elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
                         elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
@@ -617,20 +615,20 @@ class ToolCopperThieving(AppTool):
                             geo = box(x0, y0, x1, y1)
                             geo = box(x0, y0, x1, y1)
                             bounding_box = geo.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
                             bounding_box = geo.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
                         else:
                         else:
-                            app_obj.app.inform.emit(
+                            tool_obj.app.inform.emit(
                                 '[ERROR_NOTCL] %s: %s' % (_("Geometry not supported for bounding box"), type(geo_n))
                                 '[ERROR_NOTCL] %s: %s' % (_("Geometry not supported for bounding box"), type(geo_n))
                             )
                             )
                             return 'fail'
                             return 'fail'
 
 
                 except Exception as e:
                 except Exception as e:
                     log.debug("ToolCopperFIll.on_copper_thieving()  'itself'  --> %s" % str(e))
                     log.debug("ToolCopperFIll.on_copper_thieving()  'itself'  --> %s" % str(e))
-                    app_obj.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
+                    tool_obj.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available."))
                     return 'fail'
                     return 'fail'
             elif ref_selected == 'area':
             elif ref_selected == 'area':
                 geo_buff_list = []
                 geo_buff_list = []
                 try:
                 try:
                     for poly in working_obj:
                     for poly in working_obj:
-                        if app_obj.app.abort_flag:
+                        if tool_obj.app.abort_flag:
                             # graceful abort requested by the user
                             # graceful abort requested by the user
                             raise grace
                             raise grace
                         geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
                         geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
@@ -650,7 +648,7 @@ class ToolCopperThieving(AppTool):
 
 
                     geo_buff_list = []
                     geo_buff_list = []
                     for poly in geo_n:
                     for poly in geo_n:
-                        if app_obj.app.abort_flag:
+                        if tool_obj.app.abort_flag:
                             # graceful abort requested by the user
                             # graceful abort requested by the user
                             raise grace
                             raise grace
                         geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
                         geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
@@ -661,18 +659,18 @@ class ToolCopperThieving(AppTool):
                     bounding_box = unary_union(thieving_obj.solid_geometry).convex_hull.intersection(geo_n)
                     bounding_box = unary_union(thieving_obj.solid_geometry).convex_hull.intersection(geo_n)
                     bounding_box = bounding_box.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
                     bounding_box = bounding_box.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
                 else:
                 else:
-                    app_obj.app.inform.emit('[ERROR_NOTCL] %s' % _("The reference object type is not supported."))
+                    tool_obj.app.inform.emit('[ERROR_NOTCL] %s' % _("The reference object type is not supported."))
                     return 'fail'
                     return 'fail'
 
 
             log.debug("Copper Thieving Tool. Finished creating areas to fill with copper.")
             log.debug("Copper Thieving Tool. Finished creating areas to fill with copper.")
 
 
-            app_obj.app.inform.emit(_("Copper Thieving Tool. Appending new geometry and buffering."))
+            tool_obj.app.inform.emit(_("Copper Thieving Tool. Appending new geometry and buffering."))
 
 
-            # #########################################################################################
-            # ########## Generate filling geometry. ###################################################
-            # #########################################################################################
+            # #########################################################################################################
+            # ########## Generate filling geometry.
+            # #########################################################################################################
 
 
-            app_obj.new_solid_geometry = bounding_box.difference(clearance_geometry)
+            tool_obj.new_solid_geometry = bounding_box.difference(clearance_geometry)
 
 
             # determine the bounding box polygon for the entire Gerber object to which we add copper thieving
             # determine the bounding box polygon for the entire Gerber object to which we add copper thieving
             # if isinstance(geo_n, list):
             # if isinstance(geo_n, list):
@@ -682,8 +680,11 @@ class ToolCopperThieving(AppTool):
             #
             #
             # x0, y0, x1, y1 = env_obj.bounds
             # x0, y0, x1, y1 = env_obj.bounds
             # bounding_box = box(x0, y0, x1, y1)
             # bounding_box = box(x0, y0, x1, y1)
-            app_obj.app.proc_container.update_view_text(' %s' % _("Create geometry"))
+            tool_obj.app.proc_container.update_view_text(' %s' % _("Create geometry"))
 
 
+            # #########################################################################################################
+            # apply the 'margin' to the bounding box geometry
+            # #########################################################################################################
             try:
             try:
                 bounding_box = thieving_obj.solid_geometry.envelope.buffer(
                 bounding_box = thieving_obj.solid_geometry.envelope.buffer(
                     distance=margin,
                     distance=margin,
@@ -696,6 +697,9 @@ class ToolCopperThieving(AppTool):
                 )
                 )
             x0, y0, x1, y1 = bounding_box.bounds
             x0, y0, x1, y1 = bounding_box.bounds
 
 
+            # #########################################################################################################
+            # add Thieving geometry
+            # #########################################################################################################
             if fill_type == 'dot' or fill_type == 'square':
             if fill_type == 'dot' or fill_type == 'square':
                 # build the MultiPolygon of dots/squares that will fill the entire bounding box
                 # build the MultiPolygon of dots/squares that will fill the entire bounding box
                 thieving_list = []
                 thieving_list = []
@@ -731,9 +735,9 @@ class ToolCopperThieving(AppTool):
                 thieving_box_geo = affinity.translate(thieving_box_geo, xoff=dx, yoff=dy)
                 thieving_box_geo = affinity.translate(thieving_box_geo, xoff=dx, yoff=dy)
 
 
                 try:
                 try:
-                    _it = iter(app_obj.new_solid_geometry)
+                    _it = iter(tool_obj.new_solid_geometry)
                 except TypeError:
                 except TypeError:
-                    app_obj.new_solid_geometry = [app_obj.new_solid_geometry]
+                    tool_obj.new_solid_geometry = [tool_obj.new_solid_geometry]
 
 
                 try:
                 try:
                     _it = iter(thieving_box_geo)
                     _it = iter(thieving_box_geo)
@@ -742,11 +746,11 @@ class ToolCopperThieving(AppTool):
 
 
                 thieving_geo = []
                 thieving_geo = []
                 for dot_geo in thieving_box_geo:
                 for dot_geo in thieving_box_geo:
-                    for geo_t in app_obj.new_solid_geometry:
+                    for geo_t in tool_obj.new_solid_geometry:
                         if dot_geo.within(geo_t):
                         if dot_geo.within(geo_t):
                             thieving_geo.append(dot_geo)
                             thieving_geo.append(dot_geo)
 
 
-                app_obj.new_solid_geometry = thieving_geo
+                tool_obj.new_solid_geometry = thieving_geo
 
 
             if fill_type == 'line':
             if fill_type == 'line':
                 half_thick_line = line_size / 2.0
                 half_thick_line = line_size / 2.0
@@ -754,33 +758,33 @@ class ToolCopperThieving(AppTool):
                 # create a thick polygon-line that surrounds the copper features
                 # create a thick polygon-line that surrounds the copper features
                 outline_geometry = []
                 outline_geometry = []
                 try:
                 try:
-                    for pol in app_obj.grb_object.solid_geometry:
-                        if app_obj.app.abort_flag:
+                    for pol in tool_obj.grb_object.solid_geometry:
+                        if tool_obj.app.abort_flag:
                             # graceful abort requested by the user
                             # graceful abort requested by the user
                             raise grace
                             raise grace
 
 
                         outline_geometry.append(
                         outline_geometry.append(
-                            pol.buffer(c_val+half_thick_line, int(int(app_obj.geo_steps_per_circle) / 4))
+                            pol.buffer(c_val+half_thick_line, int(int(tool_obj.geo_steps_per_circle) / 4))
                         )
                         )
 
 
                         pol_nr += 1
                         pol_nr += 1
                         disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
                         disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
 
 
                         if old_disp_number < disp_number <= 100:
                         if old_disp_number < disp_number <= 100:
-                            app_obj.app.proc_container.update_view_text(' %s ... %d%%' %
-                                                                        (_("Buffering"), int(disp_number)))
+                            msg = ' %s ... %d%%' % (_("Buffering"), int(disp_number))
+                            tool_obj.app.proc_container.update_view_text(msg)
                             old_disp_number = disp_number
                             old_disp_number = disp_number
                 except TypeError:
                 except TypeError:
                     # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
                     # taking care of the case when the self.solid_geometry is just a single Polygon, not a list or a
                     # MultiPolygon (not an iterable)
                     # MultiPolygon (not an iterable)
                     outline_geometry.append(
                     outline_geometry.append(
-                        app_obj.grb_object.solid_geometry.buffer(
+                        tool_obj.grb_object.solid_geometry.buffer(
                             c_val+half_thick_line,
                             c_val+half_thick_line,
-                            int(int(app_obj.geo_steps_per_circle) / 4)
+                            int(int(tool_obj.geo_steps_per_circle) / 4)
                         )
                         )
                     )
                     )
 
 
-                app_obj.app.proc_container.update_view_text(' %s' % _("Buffering"))
+                tool_obj.app.proc_container.update_view_text(' %s' % _("Buffering"))
                 outline_geometry = unary_union(outline_geometry)
                 outline_geometry = unary_union(outline_geometry)
 
 
                 outline_line = []
                 outline_line = []
@@ -788,13 +792,13 @@ class ToolCopperThieving(AppTool):
                     for geo_o in outline_geometry:
                     for geo_o in outline_geometry:
                         outline_line.append(
                         outline_line.append(
                             geo_o.exterior.buffer(
                             geo_o.exterior.buffer(
-                                half_thick_line, resolution=int(int(app_obj.geo_steps_per_circle) / 4)
+                                half_thick_line, resolution=int(int(tool_obj.geo_steps_per_circle) / 4)
                             )
                             )
                         )
                         )
                 except TypeError:
                 except TypeError:
                     outline_line.append(
                     outline_line.append(
                         outline_geometry.exterior.buffer(
                         outline_geometry.exterior.buffer(
-                            half_thick_line, resolution=int(int(app_obj.geo_steps_per_circle) / 4)
+                            half_thick_line, resolution=int(int(tool_obj.geo_steps_per_circle) / 4)
                         )
                         )
                     )
                     )
 
 
@@ -805,7 +809,7 @@ class ToolCopperThieving(AppTool):
                 box_outline_geo_exterior = box_outline_geo.exterior
                 box_outline_geo_exterior = box_outline_geo.exterior
                 box_outline_geometry = box_outline_geo_exterior.buffer(
                 box_outline_geometry = box_outline_geo_exterior.buffer(
                     half_thick_line,
                     half_thick_line,
-                    resolution=int(int(app_obj.geo_steps_per_circle) / 4)
+                    resolution=int(int(tool_obj.geo_steps_per_circle) / 4)
                 )
                 )
 
 
                 bx0, by0, bx1, by1 = box_outline_geo.bounds
                 bx0, by0, bx1, by1 = box_outline_geo.bounds
@@ -815,7 +819,7 @@ class ToolCopperThieving(AppTool):
                 while new_x <= x1 - half_thick_line:
                 while new_x <= x1 - half_thick_line:
                     line_geo = LineString([(new_x, by0), (new_x, by1)]).buffer(
                     line_geo = LineString([(new_x, by0), (new_x, by1)]).buffer(
                         half_thick_line,
                         half_thick_line,
-                        resolution=int(int(app_obj.geo_steps_per_circle) / 4)
+                        resolution=int(int(tool_obj.geo_steps_per_circle) / 4)
                     )
                     )
                     thieving_lines_geo.append(line_geo)
                     thieving_lines_geo.append(line_geo)
                     new_x += line_size + line_spacing
                     new_x += line_size + line_spacing
@@ -823,7 +827,7 @@ class ToolCopperThieving(AppTool):
                 while new_y <= y1 - half_thick_line:
                 while new_y <= y1 - half_thick_line:
                     line_geo = LineString([(bx0, new_y), (bx1, new_y)]).buffer(
                     line_geo = LineString([(bx0, new_y), (bx1, new_y)]).buffer(
                         half_thick_line,
                         half_thick_line,
-                        resolution=int(int(app_obj.geo_steps_per_circle) / 4)
+                        resolution=int(int(tool_obj.geo_steps_per_circle) / 4)
                     )
                     )
                     thieving_lines_geo.append(line_geo)
                     thieving_lines_geo.append(line_geo)
                     new_y += line_size + line_spacing
                     new_y += line_size + line_spacing
@@ -833,53 +837,76 @@ class ToolCopperThieving(AppTool):
                 for line_poly in thieving_lines_geo:
                 for line_poly in thieving_lines_geo:
                     rest_line = line_poly.difference(clearance_geometry)
                     rest_line = line_poly.difference(clearance_geometry)
                     diff_lines_geo.append(rest_line)
                     diff_lines_geo.append(rest_line)
-                app_obj.flatten([outline_geometry, box_outline_geometry, diff_lines_geo])
-                app_obj.new_solid_geometry = app_obj.flat_geometry
-
-            app_obj.app.proc_container.update_view_text(' %s' % _("Append geometry"))
-            geo_list = app_obj.grb_object.solid_geometry
-            if isinstance(app_obj.grb_object.solid_geometry, MultiPolygon):
-                geo_list = list(app_obj.grb_object.solid_geometry.geoms)
-
-            if '0' not in app_obj.grb_object.apertures:
-                app_obj.grb_object.apertures['0'] = {}
-                app_obj.grb_object.apertures['0']['geometry'] = []
-                app_obj.grb_object.apertures['0']['type'] = 'REG'
-                app_obj.grb_object.apertures['0']['size'] = 0.0
+                tool_obj.flatten([outline_geometry, box_outline_geometry, diff_lines_geo])
+                tool_obj.new_solid_geometry = tool_obj.flat_geometry
+
+            tool_obj.app.proc_container.update_view_text(' %s' % _("Append geometry"))
+            geo_list = deepcopy(tool_obj.grb_object.solid_geometry)
+            if isinstance(tool_obj.grb_object.solid_geometry, MultiPolygon):
+                geo_list = list(geo_list.geoms)
+
+            new_apertures = deepcopy(tool_obj.grb_object.apertures)
+            if '0' not in new_apertures:
+                new_apertures['0'] = {
+                    'type': 'REG',
+                    'size': 0.0,
+                    'geometry': []
+                }
 
 
             try:
             try:
-                for poly in app_obj.new_solid_geometry:
+                for poly in tool_obj.new_solid_geometry:
                     # append to the new solid geometry
                     # append to the new solid geometry
                     geo_list.append(poly)
                     geo_list.append(poly)
 
 
                     # append into the '0' aperture
                     # append into the '0' aperture
                     geo_elem = {'solid': poly, 'follow': poly.exterior}
                     geo_elem = {'solid': poly, 'follow': poly.exterior}
-                    app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
+                    new_apertures['0']['geometry'].append(deepcopy(geo_elem))
             except TypeError:
             except TypeError:
                 # append to the new solid geometry
                 # append to the new solid geometry
-                geo_list.append(app_obj.new_solid_geometry)
+                geo_list.append(tool_obj.new_solid_geometry)
 
 
                 # append into the '0' aperture
                 # append into the '0' aperture
-                geo_elem = {'solid': app_obj.new_solid_geometry, 'follow': app_obj.new_solid_geometry.exterior}
-                app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
-
-            app_obj.grb_object.solid_geometry = MultiPolygon(geo_list).buffer(0.0000001).buffer(-0.0000001)
+                geo_elem = {'solid': tool_obj.new_solid_geometry, 'follow': tool_obj.new_solid_geometry.exterior}
+                new_apertures['0']['geometry'].append(deepcopy(geo_elem))
+
+            new_solid_geo = MultiPolygon(geo_list).buffer(0.0000001).buffer(-0.0000001)
+
+            outname = '%s_%s' % (str(self.grb_object.options['name']), 'thief')
+
+            def initialize(grb_obj, app_obj):
+                grb_obj.options = {}
+                for opt in self.grb_object.options:
+                    if opt != 'name':
+                        grb_obj.options[opt] = deepcopy(self.grb_object.options[opt])
+                grb_obj.options['name'] = outname
+                grb_obj.multitool = False
+                grb_obj.multigeo = False
+                grb_obj.follow = deepcopy(self.grb_object.follow)
+                grb_obj.apertures = new_apertures
+                grb_obj.solid_geometry = deepcopy(new_solid_geo)
+                grb_obj.follow_geometry = deepcopy(self.grb_object.follow_geometry)
+
+                app_obj.proc_container.update_view_text(' %s' % _("Append source file"))
+                grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None,
+                                                                       local_use=grb_obj,
+                                                                       use_thread=False)
+
+            ret_val = self.app.app_obj.new_object('gerber', outname, initialize, plot=True)
+            tool_obj.app.proc_container.update_view_text(' %s' % '')
+            if ret_val == 'fail':
+                self.app.call_source = "app"
+                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+                return
 
 
-            app_obj.app.proc_container.update_view_text(' %s' % _("Append source file"))
-            # update the source file with the new geometry:
-            app_obj.grb_object.source_file = app_obj.app.f_handlers.export_gerber(
-                obj_name=app_obj.grb_object.options['name'], filename=None, local_use=app_obj.grb_object,
-                use_thread=False)
-            app_obj.app.proc_container.update_view_text(' %s' % '')
-            app_obj.on_exit()
-            app_obj.app.inform.emit('[success] %s' % _("Copper Thieving Tool done."))
+            tool_obj.on_exit()
+            tool_obj.app.inform.emit('[success] %s' % _("Copper Thieving Tool done."))
 
 
         if run_threaded:
         if run_threaded:
             self.app.worker_task.emit({'fcn': job_thread_thieving, 'params': [self]})
             self.app.worker_task.emit({'fcn': job_thread_thieving, 'params': [self]})
         else:
         else:
             job_thread_thieving(self)
             job_thread_thieving(self)
 
 
-    def on_add_ppm(self):
+    def on_add_ppm_click(self):
         run_threaded = True
         run_threaded = True
 
 
         if run_threaded:
         if run_threaded:
@@ -895,6 +922,9 @@ class ToolCopperThieving(AppTool):
             self.on_new_pattern_plating_object()
             self.on_new_pattern_plating_object()
 
 
     def on_new_pattern_plating_object(self):
     def on_new_pattern_plating_object(self):
+        ppm_clearance = self.ui.clearance_ppm_entry.get_value()
+        rb_thickness = self.rb_thickness
+
         # get the Gerber object on which the Copper thieving will be inserted
         # get the Gerber object on which the Copper thieving will be inserted
         selection_index = self.ui.sm_object_combo.currentIndex()
         selection_index = self.ui.sm_object_combo.currentIndex()
         model_index = self.app.collection.index(selection_index, 0, self.ui.sm_object_combo.rootModelIndex())
         model_index = self.app.collection.index(selection_index, 0, self.ui.sm_object_combo.rootModelIndex())
@@ -902,13 +932,10 @@ class ToolCopperThieving(AppTool):
         try:
         try:
             self.sm_object = model_index.internalPointer().obj
             self.sm_object = model_index.internalPointer().obj
         except Exception as e:
         except Exception as e:
-            log.debug("ToolCopperThieving.on_add_ppm() --> %s" % str(e))
+            log.debug("ToolCopperThieving.on_add_ppm_click() --> %s" % str(e))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
             return
             return
 
 
-        ppm_clearance = self.ui.clearance_ppm_entry.get_value()
-        rb_thickness = self.rb_thickness
-
         self.app.proc_container.update_view_text(' %s' % _("Append PP-M geometry"))
         self.app.proc_container.update_view_text(' %s' % _("Append PP-M geometry"))
         geo_list = self.sm_object.solid_geometry
         geo_list = self.sm_object.solid_geometry
         if isinstance(self.sm_object.solid_geometry, MultiPolygon):
         if isinstance(self.sm_object.solid_geometry, MultiPolygon):
@@ -932,11 +959,16 @@ class ToolCopperThieving(AppTool):
             plated_area += self.robber_geo.area
             plated_area += self.robber_geo.area
         self.ui.plated_area_entry.set_value(plated_area)
         self.ui.plated_area_entry.set_value(plated_area)
 
 
-        thieving_solid_geo = self.new_solid_geometry
-        robber_solid_geo = self.robber_geo
-        robber_line = self.robber_line
+        thieving_solid_geo = deepcopy(self.new_solid_geometry)
+        robber_solid_geo = deepcopy(self.robber_geo)
+        robber_line = deepcopy(self.robber_line)
 
 
         def obj_init(grb_obj, app_obj):
         def obj_init(grb_obj, app_obj):
+            grb_obj.options = {}
+            for opt in self.sm_object.options:
+                if opt != 'name':
+                    grb_obj.options[opt] = deepcopy(self.sm_object.options[opt])
+            grb_obj.options['name'] = outname
             grb_obj.multitool = False
             grb_obj.multitool = False
             grb_obj.source_file = []
             grb_obj.source_file = []
             grb_obj.multigeo = False
             grb_obj.multigeo = False
@@ -947,10 +979,11 @@ class ToolCopperThieving(AppTool):
             # if we have copper thieving geometry, add it
             # if we have copper thieving geometry, add it
             if thieving_solid_geo:
             if thieving_solid_geo:
                 if '0' not in grb_obj.apertures:
                 if '0' not in grb_obj.apertures:
-                    grb_obj.apertures['0'] = {}
-                    grb_obj.apertures['0']['geometry'] = []
-                    grb_obj.apertures['0']['type'] = 'REG'
-                    grb_obj.apertures['0']['size'] = 0.0
+                    grb_obj.apertures['0'] = {
+                        'type': 'REG',
+                        'size': 0.0,
+                        'geometry': []
+                    }
 
 
                 try:
                 try:
                     for poly in thieving_solid_geo:
                     for poly in thieving_solid_geo:
@@ -967,6 +1000,7 @@ class ToolCopperThieving(AppTool):
                         grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
                         grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
                 except TypeError:
                 except TypeError:
                     # append to the new solid geometry
                     # append to the new solid geometry
+                    assert isinstance(thieving_solid_geo, Polygon)
                     geo_list.append(thieving_solid_geo.buffer(ppm_clearance))
                     geo_list.append(thieving_solid_geo.buffer(ppm_clearance))
 
 
                     # append into the '0' aperture
                     # append into the '0' aperture
@@ -995,10 +1029,11 @@ class ToolCopperThieving(AppTool):
                     else:
                     else:
                         new_apid = '10'
                         new_apid = '10'
 
 
-                    grb_obj.apertures[new_apid] = {}
-                    grb_obj.apertures[new_apid]['type'] = 'C'
-                    grb_obj.apertures[new_apid]['size'] = rb_thickness + ppm_clearance
-                    grb_obj.apertures[new_apid]['geometry'] = []
+                    grb_obj.apertures[new_apid] = {
+                        'type': 'C',
+                        'size': rb_thickness + ppm_clearance,
+                        'geometry': []
+                    }
 
 
                     geo_elem = {
                     geo_elem = {
                         'solid': robber_solid_geo.buffer(ppm_clearance),
                         'solid': robber_solid_geo.buffer(ppm_clearance),
@@ -1012,61 +1047,49 @@ class ToolCopperThieving(AppTool):
 
 
             app_obj.proc_container.update_view_text(' %s' % _("Append source file"))
             app_obj.proc_container.update_view_text(' %s' % _("Append source file"))
             # update the source file with the new geometry:
             # update the source file with the new geometry:
-            grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=name, filename=None, local_use=grb_obj,
+            grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None, local_use=grb_obj,
                                                                    use_thread=False)
                                                                    use_thread=False)
             app_obj.proc_container.update_view_text(' %s' % '')
             app_obj.proc_container.update_view_text(' %s' % '')
 
 
         # Object name
         # Object name
         obj_name, separatpr, obj_extension = self.sm_object.options['name'].rpartition('.')
         obj_name, separatpr, obj_extension = self.sm_object.options['name'].rpartition('.')
-        name = '%s_%s.%s' % (obj_name, 'plating_mask', obj_extension)
+        outname = '%s_%s.%s' % (obj_name, 'plating_mask', obj_extension)
 
 
-        self.app.app_obj.new_object('gerber', name, obj_init, autoselected=False)
+        ret_val = self.app.app_obj.new_object('gerber', outname, obj_init, autoselected=False)
+        if ret_val == 'fail':
+            self.app.call_source = "app"
+            self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+            return
 
 
         # Register recent file
         # Register recent file
-        self.app.file_opened.emit("gerber", name)
+        self.app.file_opened.emit("gerber", outname)
 
 
         self.on_exit()
         self.on_exit()
         self.app.inform.emit('[success] %s' % _("Generating Pattern Plating Mask done."))
         self.app.inform.emit('[success] %s' % _("Generating Pattern Plating Mask done."))
 
 
-    def replot(self, obj):
+    def replot(self, obj, run_thread=True):
         def worker_task():
         def worker_task():
             with self.app.proc_container.new('%s...' % _("Plotting")):
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 obj.plot()
                 obj.plot()
+                self.app.app_obj.object_plotted.emit(obj)
 
 
-        self.app.worker_task.emit({'fcn': worker_task, 'params': []})
+        if run_thread:
+            self.app.worker_task.emit({'fcn': worker_task, 'params': []})
+        else:
+            worker_task()
 
 
-    def on_exit(self):
+    def on_exit(self, obj=None):
         # plot the objects
         # plot the objects
-        if self.grb_object:
-            self.replot(obj=self.grb_object)
-
-        if self.sm_object:
-            self.replot(obj=self.sm_object)
-
-        # update the bounding box values
-        try:
-            a, b, c, d = self.grb_object.bounds()
-            self.grb_object.options['xmin'] = a
-            self.grb_object.options['ymin'] = b
-            self.grb_object.options['xmax'] = c
-            self.grb_object.options['ymax'] = d
-        except Exception as e:
-            log.debug("ToolCopperThieving.on_exit() bounds -> copper thieving Gerber error --> %s" % str(e))
-
-        # update the bounding box values
-        try:
-            a, b, c, d = self.sm_object.bounds()
-            self.sm_object.options['xmin'] = a
-            self.sm_object.options['ymin'] = b
-            self.sm_object.options['xmax'] = c
-            self.sm_object.options['ymax'] = d
-        except Exception as e:
-            log.debug("ToolCopperThieving.on_exit() bounds -> pattern plating mask error --> %s" % str(e))
+        if obj:
+            try:
+                for ob in obj:
+                    self.replot(obj=ob)
+            except (AttributeError, TypeError):
+                self.replot(obj=obj)
+            except Exception:
+                return
 
 
         # reset the variables
         # reset the variables
-        self.grb_object = None
-        self.sm_object = None
-        self.ref_obj = None
         self.sel_rect = []
         self.sel_rect = []
 
 
         # Events ID
         # Events ID
@@ -1079,10 +1102,31 @@ class ToolCopperThieving(AppTool):
         self.first_click = False
         self.first_click = False
 
 
         # if True it means we exited from tool in the middle of area adding therefore disconnect the events
         # if True it means we exited from tool in the middle of area adding therefore disconnect the events
-        if self.area_method is True:
+        if self.handlers_connected is True:
             self.app.delete_selection_shape()
             self.app.delete_selection_shape()
-            self.area_method = False
 
 
+        self.disconnect_event_handlers()
+
+        self.app.call_source = "app"
+        self.app.inform.emit('[success] %s' % _("Copper Thieving Tool exit."))
+
+    def connect_event_handlers(self):
+        if self.handlers_connected is False:
+            if self.app.is_legacy is False:
+                self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
+                self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
+                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
+            else:
+                self.app.plotcanvas.graph_event_disconnect(self.app.mp)
+                self.app.plotcanvas.graph_event_disconnect(self.app.mm)
+                self.app.plotcanvas.graph_event_disconnect(self.app.mr)
+
+            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
+            self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
+            self.handlers_connected = True
+
+    def disconnect_event_handlers(self):
+        if self.handlers_connected is True:
             if self.app.is_legacy is False:
             if self.app.is_legacy is False:
                 self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
                 self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
                 self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
                 self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
@@ -1096,9 +1140,7 @@ class ToolCopperThieving(AppTool):
                                                                   self.app.on_mouse_move_over_plot)
                                                                   self.app.on_mouse_move_over_plot)
             self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
             self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
                                                                   self.app.on_mouse_click_release_over_plot)
                                                                   self.app.on_mouse_click_release_over_plot)
-
-        self.app.call_source = "app"
-        self.app.inform.emit('[success] %s' % _("Copper Thieving Tool exit."))
+            self.handlers_connected = False
 
 
     def flatten(self, geometry):
     def flatten(self, geometry):
         """
         """

+ 15 - 6
appTools/ToolCorners.py

@@ -304,6 +304,11 @@ class ToolCorners(AppTool):
         outname = '%s_%s' % (str(self.grb_object.options['name']), 'corners')
         outname = '%s_%s' % (str(self.grb_object.options['name']), 'corners')
 
 
         def initialize(grb_obj, app_obj):
         def initialize(grb_obj, app_obj):
+            grb_obj.options = {}
+            for opt in g_obj.options:
+                if opt != 'name':
+                    grb_obj.options[opt] = deepcopy(g_obj.options[opt])
+            grb_obj.options['name'] = outname
             grb_obj.multitool = False
             grb_obj.multitool = False
             grb_obj.multigeo = False
             grb_obj.multigeo = False
             grb_obj.follow = deepcopy(g_obj.follow)
             grb_obj.follow = deepcopy(g_obj.follow)
@@ -417,12 +422,16 @@ class ToolCorners(AppTool):
         else:
         else:
             worker_task()
             worker_task()
 
 
-    def on_exit(self, corner_gerber_obj):
+    def on_exit(self, corner_gerber_obj=None):
         # plot the object
         # plot the object
-        try:
-            self.replot(obj=corner_gerber_obj)
-        except (AttributeError, TypeError):
-            return
+        if corner_gerber_obj:
+            try:
+                for ob in corner_gerber_obj:
+                    self.replot(obj=ob)
+            except (AttributeError, TypeError):
+                self.replot(obj=corner_gerber_obj)
+            except Exception:
+                return
 
 
         # update the bounding box values
         # update the bounding box values
         try:
         try:
@@ -613,7 +622,7 @@ class CornersUI:
         grid_lay.addWidget(self.drills_label, 16, 0, 1, 2)
         grid_lay.addWidget(self.drills_label, 16, 0, 1, 2)
 
 
         # Drill Tooldia #
         # Drill Tooldia #
-        self.drill_dia_label = FCLabel('%s:' % _("Tool Dia"))
+        self.drill_dia_label = FCLabel('%s:' % _("Drill Dia"))
         self.drill_dia_label.setToolTip(
         self.drill_dia_label.setToolTip(
             '%s.' % _("Drill Diameter")
             '%s.' % _("Drill Diameter")
         )
         )

+ 1 - 1
appTools/ToolDblSided.py

@@ -824,7 +824,7 @@ class DsidedUI:
         grid4.addWidget(self.alignment_label, 0, 0, 1, 2)
         grid4.addWidget(self.alignment_label, 0, 0, 1, 2)
 
 
         # ## Drill diameter for alignment holes
         # ## Drill diameter for alignment holes
-        self.dt_label = FCLabel("%s:" % _('Drill Diameter'))
+        self.dt_label = FCLabel("%s:" % _('Drill Dia'))
         self.dt_label.setToolTip(
         self.dt_label.setToolTip(
             _("Diameter of the drill for the alignment holes.")
             _("Diameter of the drill for the alignment holes.")
         )
         )

+ 107 - 70
appTools/ToolFiducials.py

@@ -12,6 +12,7 @@ from appGUI.GUIElements import FCDoubleSpinner, RadioSet, EvalEntry, FCTable, FC
 
 
 from shapely.geometry import Point, Polygon, MultiPolygon, LineString
 from shapely.geometry import Point, Polygon, MultiPolygon, LineString
 from shapely.geometry import box as box
 from shapely.geometry import box as box
+from shapely.ops import unary_union
 
 
 import math
 import math
 import logging
 import logging
@@ -76,6 +77,8 @@ class ToolFiducials(AppTool):
 
 
         self.click_points = []
         self.click_points = []
 
 
+        self.handlers_connected = False
+
         # SIGNALS
         # SIGNALS
         self.ui.add_cfid_button.clicked.connect(self.add_fiducials)
         self.ui.add_cfid_button.clicked.connect(self.add_fiducials)
         self.ui.add_sm_opening_button.clicked.connect(self.add_soldermask_opening)
         self.ui.add_sm_opening_button.clicked.connect(self.add_soldermask_opening)
@@ -147,12 +150,13 @@ class ToolFiducials(AppTool):
     def on_method_change(self, val):
     def on_method_change(self, val):
         """
         """
         Make sure that on method change we disconnect the event handlers and reset the points storage
         Make sure that on method change we disconnect the event handlers and reset the points storage
-        :param val: value of the Radio button which trigger this method
-        :return: None
+
+        :param val:     value of the Radio button which trigger this method
+        :return:        None
         """
         """
-        if val == 'auto':
-            self.click_points = []
+        self.click_points = []
 
 
+        if val == 'auto':
             try:
             try:
                 self.disconnect_event_handlers()
                 self.disconnect_event_handlers()
             except TypeError:
             except TypeError:
@@ -228,10 +232,14 @@ class ToolFiducials(AppTool):
                 )
                 )
                 self.ui.sec_points_coords_entry.set_value('(%.*f, %.*f)' % (self.decimals, x1, self.decimals, y0))
                 self.ui.sec_points_coords_entry.set_value('(%.*f, %.*f)' % (self.decimals, x1, self.decimals, y0))
 
 
-            self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
-            self.grb_object.source_file = self.app.f_handlers.export_gerber(obj_name=self.grb_object.options['name'],
-                                                                            filename=None,
-                                                                            local_use=self.grb_object, use_thread=False)
+            ret_val = self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
+            self.app.call_source = "app"
+            if ret_val == 'fail':
+                self.app.call_source = "app"
+                self.disconnect_event_handlers()
+                self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+                return
+
             self.on_exit()
             self.on_exit()
         else:
         else:
             self.app.inform.emit(_("Click to add first Fiducial. Bottom Left..."))
             self.app.inform.emit(_("Click to add first Fiducial. Bottom Left..."))
@@ -259,6 +267,8 @@ class ToolFiducials(AppTool):
 
 
         radius = fid_size / 2.0
         radius = fid_size / 2.0
 
 
+        new_apertures = deepcopy(g_obj.apertures)
+
         if fid_type == 'circular':
         if fid_type == 'circular':
             geo_list = [Point(pt).buffer(radius, self.grb_steps_per_circle) for pt in points_list]
             geo_list = [Point(pt).buffer(radius, self.grb_steps_per_circle) for pt in points_list]
 
 
@@ -271,7 +281,7 @@ class ToolFiducials(AppTool):
             if aperture_found:
             if aperture_found:
                 for geo in geo_list:
                 for geo in geo_list:
                     dict_el = {'follow': geo.centroid, 'solid': geo}
                     dict_el = {'follow': geo.centroid, 'solid': geo}
-                    g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
             else:
             else:
                 ap_keys = list(g_obj.apertures.keys())
                 ap_keys = list(g_obj.apertures.keys())
                 if ap_keys:
                 if ap_keys:
@@ -279,14 +289,15 @@ class ToolFiducials(AppTool):
                 else:
                 else:
                     new_apid = '10'
                     new_apid = '10'
 
 
-                g_obj.apertures[new_apid] = {}
-                g_obj.apertures[new_apid]['type'] = 'C'
-                g_obj.apertures[new_apid]['size'] = fid_size
-                g_obj.apertures[new_apid]['geometry'] = []
+                new_apertures[new_apid] = {
+                    'type': 'C',
+                    'size': fid_size,
+                    'geometry': []
+                }
 
 
                 for geo in geo_list:
                 for geo in geo_list:
                     dict_el = {'follow': geo.centroid, 'solid': geo}
                     dict_el = {'follow': geo.centroid, 'solid': geo}
-                    g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
 
 
             s_list = []
             s_list = []
             if g_obj.solid_geometry:
             if g_obj.solid_geometry:
@@ -297,7 +308,6 @@ class ToolFiducials(AppTool):
                     s_list.append(g_obj.solid_geometry)
                     s_list.append(g_obj.solid_geometry)
 
 
             s_list += geo_list
             s_list += geo_list
-            g_obj.solid_geometry = MultiPolygon(s_list)
         elif fid_type == 'cross':
         elif fid_type == 'cross':
             geo_list = []
             geo_list = []
 
 
@@ -327,10 +337,9 @@ class ToolFiducials(AppTool):
                     geo_buff_list.append(geo_buff_v)
                     geo_buff_list.append(geo_buff_v)
 
 
                     dict_el = {'follow': geo_buff_h.centroid, 'solid': geo_buff_h}
                     dict_el = {'follow': geo_buff_h.centroid, 'solid': geo_buff_h}
-                    g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
-                    dict_el['follow'] = geo_buff_v.centroid
-                    dict_el['solid'] = geo_buff_v
-                    g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
+                    dict_el = {'follow': geo_buff_v.centroid, 'solid': geo_buff_v}
+                    new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
             else:
             else:
                 ap_keys = list(g_obj.apertures.keys())
                 ap_keys = list(g_obj.apertures.keys())
                 if ap_keys:
                 if ap_keys:
@@ -338,7 +347,7 @@ class ToolFiducials(AppTool):
                 else:
                 else:
                     new_apid = '10'
                     new_apid = '10'
 
 
-                g_obj.apertures[new_apid] = {
+                new_apertures[new_apid] = {
                     'type': 'C',
                     'type': 'C',
                     'size': line_thickness,
                     'size': line_thickness,
                     'geometry': []
                     'geometry': []
@@ -351,10 +360,9 @@ class ToolFiducials(AppTool):
                     geo_buff_list.append(geo_buff_v)
                     geo_buff_list.append(geo_buff_v)
 
 
                     dict_el = {'follow': geo_buff_h.centroid, 'solid': geo_buff_h}
                     dict_el = {'follow': geo_buff_h.centroid, 'solid': geo_buff_h}
-                    g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
-                    dict_el['follow'] = geo_buff_v.centroid
-                    dict_el['solid'] = geo_buff_v
-                    g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
+                    dict_el = {'follow': geo_buff_v.centroid, 'solid': geo_buff_v}
+                    new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
 
 
             s_list = []
             s_list = []
             if g_obj.solid_geometry:
             if g_obj.solid_geometry:
@@ -368,7 +376,6 @@ class ToolFiducials(AppTool):
             geo_buff_list = geo_buff_list.buffer(0)
             geo_buff_list = geo_buff_list.buffer(0)
             for poly in geo_buff_list:
             for poly in geo_buff_list:
                 s_list.append(poly)
                 s_list.append(poly)
-            g_obj.solid_geometry = MultiPolygon(s_list)
         else:
         else:
             # chess pattern fiducial type
             # chess pattern fiducial type
             geo_list = []
             geo_list = []
@@ -406,7 +413,7 @@ class ToolFiducials(AppTool):
                     geo_buff_list.append(geo)
                     geo_buff_list.append(geo)
 
 
                     dict_el = {'follow': geo.centroid, 'solid': geo}
                     dict_el = {'follow': geo.centroid, 'solid': geo}
-                    g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
             else:
             else:
                 ap_keys = list(g_obj.apertures.keys())
                 ap_keys = list(g_obj.apertures.keys())
                 if ap_keys:
                 if ap_keys:
@@ -414,7 +421,7 @@ class ToolFiducials(AppTool):
                 else:
                 else:
                     new_apid = '10'
                     new_apid = '10'
 
 
-                g_obj.apertures[new_apid] = {
+                new_apertures[new_apid] = {
                     'type': 'R',
                     'type': 'R',
                     'size': new_ap_size,
                     'size': new_ap_size,
                     'width': fid_size,
                     'width': fid_size,
@@ -426,7 +433,7 @@ class ToolFiducials(AppTool):
                     geo_buff_list.append(geo)
                     geo_buff_list.append(geo)
 
 
                     dict_el = {'follow': geo.centroid, 'solid': geo}
                     dict_el = {'follow': geo.centroid, 'solid': geo}
-                    g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
+                    new_apertures[new_apid]['geometry'].append(deepcopy(dict_el))
 
 
             s_list = []
             s_list = []
             if g_obj.solid_geometry:
             if g_obj.solid_geometry:
@@ -438,7 +445,28 @@ class ToolFiducials(AppTool):
 
 
             for poly in geo_buff_list:
             for poly in geo_buff_list:
                 s_list.append(poly)
                 s_list.append(poly)
-            g_obj.solid_geometry = MultiPolygon(s_list)
+
+        outname = '%s_%s' % (str(g_obj.options['name']), 'fid')
+
+        def initialize(grb_obj, app_obj):
+            grb_obj.options = {}
+            for opt in g_obj.options:
+                if opt != 'name':
+                    grb_obj.options[opt] = deepcopy(g_obj.options[opt])
+            grb_obj.options['name'] = outname
+            grb_obj.multitool = False
+            grb_obj.multigeo = False
+            grb_obj.follow = deepcopy(g_obj.follow)
+            grb_obj.apertures = new_apertures
+            grb_obj.solid_geometry = unary_union(s_list)
+            grb_obj.follow_geometry = deepcopy(g_obj.follow_geometry) + geo_list
+
+            grb_obj.source_file = app_obj.f_handlers.export_gerber(obj_name=outname, filename=None, local_use=grb_obj,
+                                                                   use_thread=False)
+
+        ret = self.app.app_obj.new_object('gerber', outname, initialize, plot=True)
+
+        return ret
 
 
     def add_soldermask_opening(self):
     def add_soldermask_opening(self):
         sm_opening_dia = self.ui.fid_size_entry.get_value() * 2.0
         sm_opening_dia = self.ui.fid_size_entry.get_value() * 2.0
@@ -455,12 +483,15 @@ class ToolFiducials(AppTool):
             return
             return
 
 
         self.sm_obj_set.add(self.sm_object.options['name'])
         self.sm_obj_set.add(self.sm_object.options['name'])
-        self.add_fiducials_geo(self.click_points, g_obj=self.sm_object, fid_size=sm_opening_dia, fid_type='circular')
+        ret_val = self.add_fiducials_geo(
+            self.click_points, g_obj=self.sm_object, fid_size=sm_opening_dia, fid_type='circular')
+        self.app.call_source = "app"
+        if ret_val == 'fail':
+            self.app.call_source = "app"
+            self.disconnect_event_handlers()
+            self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+            return
 
 
-        self.sm_object.source_file = self.app.f_handlers.export_gerber(obj_name=self.sm_object.options['name'],
-                                                                       filename=None,
-                                                                       local_use=self.sm_object,
-                                                                       use_thread=False)
         self.on_exit()
         self.on_exit()
 
 
     def on_mouse_release(self, event):
     def on_mouse_release(self, event):
@@ -486,7 +517,7 @@ class ToolFiducials(AppTool):
             self.check_points()
             self.check_points()
 
 
     def check_points(self):
     def check_points(self):
-        fid_type = self.fid_type_radio.get_value()
+        fid_type = self.ui.fid_type_radio.get_value()
 
 
         if len(self.click_points) == 1:
         if len(self.click_points) == 1:
             self.ui.bottom_left_coords_entry.set_value(self.click_points[0])
             self.ui.bottom_left_coords_entry.set_value(self.click_points[0])
@@ -499,19 +530,29 @@ class ToolFiducials(AppTool):
             elif len(self.click_points) == 3:
             elif len(self.click_points) == 3:
                 self.ui.sec_points_coords_entry.set_value(self.click_points[2])
                 self.ui.sec_points_coords_entry.set_value(self.click_points[2])
                 self.app.inform.emit('[success] %s' % _("Done. All fiducials have been added."))
                 self.app.inform.emit('[success] %s' % _("Done. All fiducials have been added."))
-                self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
-                self.grb_object.source_file = self.app.f_handlers.export_gerber(
-                    obj_name=self.grb_object.options['name'], filename=None, local_use=self.grb_object,
-                    use_thread=False)
+
+                ret_val = self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
+                self.app.call_source = "app"
+
+                if ret_val == 'fail':
+                    self.app.call_source = "app"
+                    self.disconnect_event_handlers()
+                    self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+                    return
                 self.on_exit()
                 self.on_exit()
         else:
         else:
             if len(self.click_points) == 2:
             if len(self.click_points) == 2:
                 self.ui.top_right_coords_entry.set_value(self.click_points[1])
                 self.ui.top_right_coords_entry.set_value(self.click_points[1])
                 self.app.inform.emit('[success] %s' % _("Done. All fiducials have been added."))
                 self.app.inform.emit('[success] %s' % _("Done. All fiducials have been added."))
-                self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
-                self.grb_object.source_file = self.app.f_handlers.export_gerber(
-                    obj_name=self.grb_object.options['name'], filename=None,
-                    local_use=self.grb_object, use_thread=False)
+
+                ret_val = self.add_fiducials_geo(self.click_points, g_obj=self.grb_object, fid_type=fid_type)
+                self.app.call_source = "app"
+
+                if ret_val == 'fail':
+                    self.app.call_source = "app"
+                    self.disconnect_event_handlers()
+                    self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
+                    return
                 self.on_exit()
                 self.on_exit()
 
 
     def on_mouse_move(self, event):
     def on_mouse_move(self, event):
@@ -521,6 +562,7 @@ class ToolFiducials(AppTool):
         def worker_task():
         def worker_task():
             with self.app.proc_container.new('%s...' % _("Plotting")):
             with self.app.proc_container.new('%s...' % _("Plotting")):
                 obj.plot()
                 obj.plot()
+                self.app.app_obj.object_plotted.emit(obj)
 
 
         if run_thread:
         if run_thread:
             self.app.worker_task.emit({'fcn': worker_task, 'params': []})
             self.app.worker_task.emit({'fcn': worker_task, 'params': []})
@@ -569,10 +611,6 @@ class ToolFiducials(AppTool):
             except Exception as e:
             except Exception as e:
                 log.debug("ToolFiducials.on_exit() sm_obj bounds error --> %s" % str(e))
                 log.debug("ToolFiducials.on_exit() sm_obj bounds error --> %s" % str(e))
 
 
-        # reset the variables
-        self.grb_object = None
-        self.sm_object = None
-
         # Events ID
         # Events ID
         self.mr = None
         self.mr = None
         # self.mm = None
         # self.mm = None
@@ -587,32 +625,31 @@ class ToolFiducials(AppTool):
         self.app.inform.emit('[success] %s' % _("Fiducials Tool exit."))
         self.app.inform.emit('[success] %s' % _("Fiducials Tool exit."))
 
 
     def connect_event_handlers(self):
     def connect_event_handlers(self):
-        if self.app.is_legacy is False:
-            self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
-            # self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
-            self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-        else:
-            self.app.plotcanvas.graph_event_disconnect(self.app.mp)
-            # self.app.plotcanvas.graph_event_disconnect(self.app.mm)
-            self.app.plotcanvas.graph_event_disconnect(self.app.mr)
+        if self.handlers_connected is False:
+            if self.app.is_legacy is False:
+                self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
+                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
+            else:
+                self.app.plotcanvas.graph_event_disconnect(self.app.mp)
+                self.app.plotcanvas.graph_event_disconnect(self.app.mr)
 
 
-        self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
-        # self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
+            self.mr = self.app.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_release)
+
+            self.handlers_connected = True
 
 
     def disconnect_event_handlers(self):
     def disconnect_event_handlers(self):
-        if self.app.is_legacy is False:
-            self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
-            # self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
-        else:
-            self.app.plotcanvas.graph_event_disconnect(self.mr)
-            # self.app.plotcanvas.graph_event_disconnect(self.mm)
-
-        self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
-                                                              self.app.on_mouse_click_over_plot)
-        # self.app.mm = self.app.plotcanvas.graph_event_connect('mouse_move',
-        #                                                       self.app.on_mouse_move_over_plot)
-        self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
-                                                              self.app.on_mouse_click_release_over_plot)
+        if self.handlers_connected is True:
+            if self.app.is_legacy is False:
+                self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
+            else:
+                self.app.plotcanvas.graph_event_disconnect(self.mr)
+
+            self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
+                                                                  self.app.on_mouse_click_over_plot)
+
+            self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
+                                                                  self.app.on_mouse_click_release_over_plot)
+            self.handlers_connected = False
 
 
     def flatten(self, geometry):
     def flatten(self, geometry):
         """
         """

BIN
locale/de/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 195 - 195
locale/de/LC_MESSAGES/strings.po


BIN
locale/en/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 199 - 199
locale/en/LC_MESSAGES/strings.po


BIN
locale/es/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 195 - 195
locale/es/LC_MESSAGES/strings.po


BIN
locale/fr/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 199 - 199
locale/fr/LC_MESSAGES/strings.po


BIN
locale/it/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 199 - 199
locale/it/LC_MESSAGES/strings.po


BIN
locale/pt_BR/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 199 - 199
locale/pt_BR/LC_MESSAGES/strings.po


BIN
locale/ro/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 195 - 195
locale/ro/LC_MESSAGES/strings.po


BIN
locale/ru/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 198 - 198
locale/ru/LC_MESSAGES/strings.po


BIN
locale/tr/LC_MESSAGES/strings.mo


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 202 - 202
locale/tr/LC_MESSAGES/strings.po


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 220 - 221
locale_template/strings.pot


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio