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

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

Beta
Marius Stanciu 6 лет назад
Родитель
Сommit
aa45b57ee1

+ 64 - 24
FlatCAMApp.py

@@ -94,8 +94,8 @@ class App(QtCore.QObject):
     log.addHandler(handler)
     log.addHandler(handler)
 
 
     # Version
     # Version
-    version = 8.918
-    version_date = "2019/06/11"
+    version = 8.919
+    version_date = "2019/06/22"
     beta = True
     beta = True
 
 
     # current date now
     # current date now
@@ -2108,11 +2108,10 @@ class App(QtCore.QObject):
         self.paste_tool.install(icon=QtGui.QIcon('share/solderpastebis32.png'))
         self.paste_tool.install(icon=QtGui.QIcon('share/solderpastebis32.png'))
 
 
         self.calculator_tool = ToolCalculator(self)
         self.calculator_tool = ToolCalculator(self)
-        self.calculator_tool.install(icon=QtGui.QIcon('share/calculator24.png'))
+        self.calculator_tool.install(icon=QtGui.QIcon('share/calculator24.png'), separator=True)
 
 
         self.sub_tool = ToolSub(self)
         self.sub_tool = ToolSub(self)
-        self.sub_tool.install(icon=QtGui.QIcon('share/sub32.png'), pos=self.ui.menuedit_convert,
-                              before=self.ui.menuedit_convert_sg2mg)
+        self.sub_tool.install(icon=QtGui.QIcon('share/sub32.png'), pos=self.ui.menutool, separator=True)
 
 
         self.move_tool = ToolMove(self)
         self.move_tool = ToolMove(self)
         self.move_tool.install(icon=QtGui.QIcon('share/move16.png'), pos=self.ui.menuedit,
         self.move_tool.install(icon=QtGui.QIcon('share/move16.png'), pos=self.ui.menuedit,
@@ -2245,7 +2244,18 @@ class App(QtCore.QObject):
                     self.inform.emit(_("[WARNING_NOTCL] Simultanoeus editing of tools geometry in a MultiGeo Geometry "
                     self.inform.emit(_("[WARNING_NOTCL] Simultanoeus editing of tools geometry in a MultiGeo Geometry "
                                        "is not possible.\n"
                                        "is not possible.\n"
                                        "Edit only one geometry at a time."))
                                        "Edit only one geometry at a time."))
-                self.geo_editor.edit_fcgeometry(edited_object, multigeo_tool=edited_tools[0])
+
+                # determine the tool dia of the selected tool
+                selected_tooldia = float(edited_object.ui.geo_tools_table.item((edited_tools[0] - 1), 1).text())
+
+                # now find the key in the edited_object.tools that has this tooldia
+                multi_tool = 1
+                for tool in edited_object.tools:
+                    if edited_object.tools[tool]['tooldia'] == selected_tooldia:
+                        multi_tool = tool
+                        break
+
+                self.geo_editor.edit_fcgeometry(edited_object, multigeo_tool=multi_tool)
             else:
             else:
                 self.geo_editor.edit_fcgeometry(edited_object)
                 self.geo_editor.edit_fcgeometry(edited_object)
 
 
@@ -3618,9 +3628,10 @@ class App(QtCore.QObject):
         if self.toggle_units_ignore:
         if self.toggle_units_ignore:
             return
             return
 
 
+        new_units = self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
+
         # If option is the same, then ignore
         # If option is the same, then ignore
-        if self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == \
-                self.defaults["units"].upper():
+        if new_units == self.defaults["units"].upper():
             self.log.debug("on_toggle_units(): Same as defaults, so ignoring.")
             self.log.debug("on_toggle_units(): Same as defaults, so ignoring.")
             return
             return
 
 
@@ -3667,16 +3678,24 @@ class App(QtCore.QObject):
                     coords_xy[0] *= sfactor
                     coords_xy[0] *= sfactor
                     coords_xy[1] *= sfactor
                     coords_xy[1] *= sfactor
                     self.options['geometry_toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1])
                     self.options['geometry_toolchangexy'] = "%f, %f" % (coords_xy[0], coords_xy[1])
+                elif dim == 'geometry_cnctooldia':
+                    self.options['geometry_cnctooldia'] = ''
+                    tools_diameters = [float(eval(a)) for a in self.defaults["geometry_cnctooldia"].split(",")]
+                    for t in range(len(tools_diameters)):
+                        tools_diameters[t] *= sfactor
+                        self.options['geometry_cnctooldia'] += "%f, " % tools_diameters[t]
                 elif dim == 'tools_ncctools':
                 elif dim == 'tools_ncctools':
+                    self.options['tools_ncctools'] = ''
                     ncctols = [float(eval(a)) for a in self.defaults["tools_ncctools"].split(",")]
                     ncctols = [float(eval(a)) for a in self.defaults["tools_ncctools"].split(",")]
-                    ncctols[0] *= sfactor
-                    ncctols[1] *= sfactor
-                    self.options['tools_ncctools'] = "%f, %f" % (ncctols[0], ncctols[1])
+                    for t in range(len(ncctols)):
+                        ncctols[t] *= sfactor
+                        self.options['tools_ncctools'] += "%f, " % ncctols[t]
                 elif dim == 'tools_solderpaste_tools':
                 elif dim == 'tools_solderpaste_tools':
+                    self.options['tools_solderpaste_tools'] = ""
                     sp_tools = [float(eval(a)) for a in self.defaults["tools_solderpaste_tools"].split(",")]
                     sp_tools = [float(eval(a)) for a in self.defaults["tools_solderpaste_tools"].split(",")]
-                    sp_tools[0] *= sfactor
-                    sp_tools[1] *= sfactor
-                    self.options['tools_solderpaste_tools'] = "%f, %f" % (sp_tools[0], sp_tools[1])
+                    for t in range(len(sp_tools)):
+                        sp_tools[t] *= sfactor
+                        self.options['tools_solderpaste_tools'] = "%f, " % sp_tools[t]
                 elif dim == 'tools_solderpaste_xy_toolchange':
                 elif dim == 'tools_solderpaste_xy_toolchange':
                     sp_coords = [float(eval(a)) for a in self.defaults["tools_solderpaste_xy_toolchange"].split(",")]
                     sp_coords = [float(eval(a)) for a in self.defaults["tools_solderpaste_xy_toolchange"].split(",")]
                     sp_coords[0] *= sfactor
                     sp_coords[0] *= sfactor
@@ -3700,16 +3719,24 @@ class App(QtCore.QObject):
                     coords_xy[0] *= sfactor
                     coords_xy[0] *= sfactor
                     coords_xy[1] *= sfactor
                     coords_xy[1] *= sfactor
                     self.defaults['geometry_toolchangexy'] = "%.4f, %.4f" % (coords_xy[0], coords_xy[1])
                     self.defaults['geometry_toolchangexy'] = "%.4f, %.4f" % (coords_xy[0], coords_xy[1])
+                elif dim == 'geometry_cnctooldia':
+                    self.defaults['geometry_cnctooldia'] = ''
+                    tools_diameters = [float(eval(a)) for a in self.defaults["geometry_cnctooldia"].split(",")]
+                    for t in range(len(tools_diameters)):
+                        tools_diameters[t] *= sfactor
+                        self.defaults['geometry_cnctooldia'] += "%.4f, " % tools_diameters[t]
                 elif dim == 'tools_ncctools':
                 elif dim == 'tools_ncctools':
+                    self.defaults['tools_ncctools'] = ''
                     ncctols = [float(eval(a)) for a in self.defaults["tools_ncctools"].split(",")]
                     ncctols = [float(eval(a)) for a in self.defaults["tools_ncctools"].split(",")]
-                    ncctols[0] *= sfactor
-                    ncctols[1] *= sfactor
-                    self.defaults['tools_ncctools'] = "%.4f, %.4f" % (ncctols[0], ncctols[1])
+                    for t in range(len(ncctols)):
+                        ncctols[t] *= sfactor
+                        self.defaults['tools_ncctools'] += "%.4f, " % ncctols[t]
                 elif dim == 'tools_solderpaste_tools':
                 elif dim == 'tools_solderpaste_tools':
+                    self.defaults['tools_solderpaste_tools'] = ""
                     sp_tools = [float(eval(a)) for a in self.defaults["tools_solderpaste_tools"].split(",")]
                     sp_tools = [float(eval(a)) for a in self.defaults["tools_solderpaste_tools"].split(",")]
-                    sp_tools[0] *= sfactor
-                    sp_tools[1] *= sfactor
-                    self.defaults['tools_solderpaste_tools'] = "%.4f, %.4f" % (sp_tools[0], sp_tools[1])
+                    for t in range(len(sp_tools)):
+                        sp_tools[t] *= sfactor
+                        self.defaults['tools_solderpaste_tools'] = "%.4f, " % sp_tools[t]
                 elif dim == 'tools_solderpaste_xy_toolchange':
                 elif dim == 'tools_solderpaste_xy_toolchange':
                     sp_coords = [float(eval(a)) for a in self.defaults["tools_solderpaste_xy_toolchange"].split(",")]
                     sp_coords = [float(eval(a)) for a in self.defaults["tools_solderpaste_xy_toolchange"].split(",")]
                     sp_coords[0] *= sfactor
                     sp_coords[0] *= sfactor
@@ -3723,7 +3750,7 @@ class App(QtCore.QObject):
 
 
         # The scaling factor depending on choice of units.
         # The scaling factor depending on choice of units.
         factor = 1/25.4
         factor = 1/25.4
-        if self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == 'MM':
+        if new_units == 'MM':
             factor = 25.4
             factor = 25.4
 
 
         # Changing project units. Warn user.
         # Changing project units. Warn user.
@@ -3757,8 +3784,12 @@ class App(QtCore.QObject):
                 self.plotcanvas.draw_workspace()
                 self.plotcanvas.draw_workspace()
 
 
             # adjust the grid values on the main toolbar
             # adjust the grid values on the main toolbar
-            self.ui.grid_gap_x_entry.set_value(float(self.ui.grid_gap_x_entry.get_value()) * factor)
-            self.ui.grid_gap_y_entry.set_value(float(self.ui.grid_gap_y_entry.get_value()) * factor)
+            dec = 6 if new_units == 'IN'else 4
+            val_x = float(self.ui.grid_gap_x_entry.get_value()) * factor
+            self.ui.grid_gap_x_entry.set_value(val_x, decimals=dec)
+            if not self.ui.grid_gap_link_cb.isChecked():
+                val_y = float(self.ui.grid_gap_y_entry.get_value()) * factor
+                self.ui.grid_gap_y_entry.set_value(val_y, decimals=dec)
 
 
             units = self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
             units = self.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
             for obj in self.collection.get_list():
             for obj in self.collection.get_list():
@@ -5249,6 +5280,7 @@ class App(QtCore.QObject):
         if index.isValid():
         if index.isValid():
             if index.internalPointer().parent_item != self.collection.root_item:
             if index.internalPointer().parent_item != self.collection.root_item:
                 self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
                 self.ui.notebook.setCurrentWidget(self.ui.selected_tab)
+        self.collection.on_item_activated(index)
 
 
     def grid_status(self):
     def grid_status(self):
         if self.ui.grid_snap_btn.isChecked():
         if self.ui.grid_snap_btn.isChecked():
@@ -5423,6 +5455,7 @@ class App(QtCore.QObject):
                     self.click_noproject = True
                     self.click_noproject = True
 
 
                     self.clipboard.setText(self.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1]))
                     self.clipboard.setText(self.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1]))
+                    self.inform.emit(_("[success] Coordinates copied to clipboard."))
                     return
                     return
 
 
             self.on_mouse_move_over_plot(event, origin_click=True)
             self.on_mouse_move_over_plot(event, origin_click=True)
@@ -5579,6 +5612,10 @@ class App(QtCore.QObject):
                             if self.command_active is None:
                             if self.command_active is None:
                                 self.select_objects(key='CTRL')
                                 self.select_objects(key='CTRL')
                                 self.delete_hover_shape()
                                 self.delete_hover_shape()
+                        elif modifiers == QtCore.Qt.ShiftModifier:
+                            # if SHIFT was pressed and LMB is clicked then we have a coordinates copy to clipboard
+                            # therefore things should stay as they are
+                            pass
                         else:
                         else:
                             # If there is no active command (self.command_active is None) then we check if we clicked
                             # If there is no active command (self.command_active is None) then we check if we clicked
                             # on a object by checking the bounding limits against mouse click position
                             # on a object by checking the bounding limits against mouse click position
@@ -8252,7 +8289,10 @@ The normal flow when working in FlatCAM is the following:</span></p>
         """
         """
         FlatCAMObj.app = self
         FlatCAMObj.app = self
         ObjectCollection.app = self
         ObjectCollection.app = self
-
+        Gerber.app = self
+        Excellon.app = self
+        Geometry.app = self
+        CNCjob.app = self
         FCProcess.app = self
         FCProcess.app = self
         FCProcessContainer.app = self
         FCProcessContainer.app = self
 
 

+ 99 - 56
FlatCAMObj.py

@@ -68,6 +68,9 @@ class FlatCAMObj(QtCore.QObject):
 
 
         self.form_fields = {}
         self.form_fields = {}
 
 
+        # store here the default data for Geometry Data
+        self.default_data = {}
+
         self.kind = None  # Override with proper name
         self.kind = None  # Override with proper name
 
 
         # self.shapes = ShapeCollection(parent=self.app.plotcanvas.vispy_canvas.view.scene)
         # self.shapes = ShapeCollection(parent=self.app.plotcanvas.vispy_canvas.view.scene)
@@ -137,7 +140,7 @@ class FlatCAMObj(QtCore.QObject):
         if key == 'plot':
         if key == 'plot':
             self.visible = self.options['plot']
             self.visible = self.options['plot']
 
 
-        # self.optionChanged.emit(key)
+        self.optionChanged.emit(key)
 
 
     def set_ui(self, ui):
     def set_ui(self, ui):
         self.ui = ui
         self.ui = ui
@@ -199,6 +202,8 @@ class FlatCAMObj(QtCore.QObject):
                 log.debug("on_name_activate() --> Could not remove the old object name from auto-completer model list")
                 log.debug("on_name_activate() --> Could not remove the old object name from auto-completer model list")
 
 
             self.options["name"] = self.ui.name_entry.get_value()
             self.options["name"] = self.ui.name_entry.get_value()
+            self.default_data["name"] = self.ui.name_entry.get_value()
+            self.app.collection.update_view()
             self.app.inform.emit(_("[success] Name changed from {old} to {new}").format(old=old_name, new=new_name))
             self.app.inform.emit(_("[success] Name changed from {old} to {new}").format(old=old_name, new=new_name))
 
 
     def on_offset_button_click(self):
     def on_offset_button_click(self):
@@ -338,7 +343,7 @@ class FlatCAMObj(QtCore.QObject):
         return self.shapes.visible
         return self.shapes.visible
 
 
     @visible.setter
     @visible.setter
-    def visible(self, value):
+    def visible(self, value, threaded=False):
         log.debug("FlatCAMObj.visible()")
         log.debug("FlatCAMObj.visible()")
 
 
         def worker_task(app_obj):
         def worker_task(app_obj):
@@ -350,7 +355,10 @@ class FlatCAMObj(QtCore.QObject):
             except Exception as e:
             except Exception as e:
                 pass
                 pass
 
 
-        self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
+        if threaded is False:
+            worker_task(self)
+        else:
+            self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
 
 
     @property
     @property
     def drawing_tolerance(self):
     def drawing_tolerance(self):
@@ -810,7 +818,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
 
 
         def follow_init(follow_obj, app):
         def follow_init(follow_obj, app):
             # Propagate options
             # Propagate options
-            follow_obj.options["cnctooldia"] = float(self.options["isotooldia"])
+            follow_obj.options["cnctooldia"] = str(self.options["isotooldia"])
             follow_obj.solid_geometry = self.follow_geometry
             follow_obj.solid_geometry = self.follow_geometry
 
 
         # TODO: Do something if this is None. Offer changing name?
         # TODO: Do something if this is None. Offer changing name?
@@ -832,7 +840,6 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         :return: None
         :return: None
         """
         """
 
 
-
         if dia is None:
         if dia is None:
             dia = float(self.options["isotooldia"])
             dia = float(self.options["isotooldia"])
         if passes is None:
         if passes is None:
@@ -893,7 +900,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             # TODO: This is ugly. Create way to pass data into init function.
             # TODO: This is ugly. Create way to pass data into init function.
             def iso_init(geo_obj, app_obj):
             def iso_init(geo_obj, app_obj):
                 # Propagate options
                 # Propagate options
-                geo_obj.options["cnctooldia"] = float(self.options["isotooldia"])
+                geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
                 geo_obj.solid_geometry = []
                 geo_obj.solid_geometry = []
                 for i in range(passes):
                 for i in range(passes):
                     iso_offset = (((2 * i + 1) / 2.0) * dia) - (i * overlap * dia)
                     iso_offset = (((2 * i + 1) / 2.0) * dia) - (i * overlap * dia)
@@ -950,7 +957,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                 # TODO: This is ugly. Create way to pass data into init function.
                 # TODO: This is ugly. Create way to pass data into init function.
                 def iso_init(geo_obj, app_obj):
                 def iso_init(geo_obj, app_obj):
                     # Propagate options
                     # Propagate options
-                    geo_obj.options["cnctooldia"] = float(self.options["isotooldia"])
+                    geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
 
 
                     # if milling type is climb then the move is counter-clockwise around features
                     # if milling type is climb then the move is counter-clockwise around features
                     if milling_type == 'cl':
                     if milling_type == 'cl':
@@ -1638,7 +1645,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                         exc.app.log.warning("Failed to copy option.", option)
                         exc.app.log.warning("Failed to copy option.", option)
 
 
             for drill in exc.drills:
             for drill in exc.drills:
-                exc_tool_dia = float('%.3f' % exc.tools[drill['tool']]['C'])
+                exc_tool_dia = float('%.4f' % exc.tools[drill['tool']]['C'])
 
 
                 if exc_tool_dia not in custom_dict_drills:
                 if exc_tool_dia not in custom_dict_drills:
                     custom_dict_drills[exc_tool_dia] = [drill['point']]
                     custom_dict_drills[exc_tool_dia] = [drill['point']]
@@ -1646,7 +1653,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                     custom_dict_drills[exc_tool_dia].append(drill['point'])
                     custom_dict_drills[exc_tool_dia].append(drill['point'])
 
 
             for slot in exc.slots:
             for slot in exc.slots:
-                exc_tool_dia = float('%.3f' % exc.tools[slot['tool']]['C'])
+                exc_tool_dia = float('%.4f' % exc.tools[slot['tool']]['C'])
 
 
                 if exc_tool_dia not in custom_dict_slots:
                 if exc_tool_dia not in custom_dict_slots:
                     custom_dict_slots[exc_tool_dia] = [[slot['start'], slot['stop']]]
                     custom_dict_slots[exc_tool_dia] = [[slot['start'], slot['stop']]]
@@ -1739,7 +1746,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                 temp_tools[tool_name_temp] = spec_temp
                 temp_tools[tool_name_temp] = spec_temp
 
 
                 for drill in exc_final.drills:
                 for drill in exc_final.drills:
-                    exc_tool_dia = float('%.3f' % exc_final.tools[drill['tool']]['C'])
+                    exc_tool_dia = float('%.4f' % exc_final.tools[drill['tool']]['C'])
                     if exc_tool_dia == ordered_dia:
                     if exc_tool_dia == ordered_dia:
                         temp_drills.append(
                         temp_drills.append(
                             {
                             {
@@ -1749,7 +1756,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                         )
                         )
 
 
                 for slot in exc_final.slots:
                 for slot in exc_final.slots:
-                    slot_tool_dia = float('%.3f' % exc_final.tools[slot['tool']]['C'])
+                    slot_tool_dia = float('%.4f' % exc_final.tools[slot['tool']]['C'])
                     if slot_tool_dia == ordered_dia:
                     if slot_tool_dia == ordered_dia:
                         temp_slots.append(
                         temp_slots.append(
                             {
                             {
@@ -1825,7 +1832,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             if self.units == 'MM':
             if self.units == 'MM':
                 dia = QtWidgets.QTableWidgetItem('%.2f' % (self.tools[tool_no]['C']))
                 dia = QtWidgets.QTableWidgetItem('%.2f' % (self.tools[tool_no]['C']))
             else:
             else:
-                dia = QtWidgets.QTableWidgetItem('%.3f' % (self.tools[tool_no]['C']))
+                dia = QtWidgets.QTableWidgetItem('%.4f' % (self.tools[tool_no]['C']))
 
 
             dia.setFlags(QtCore.Qt.ItemIsEnabled)
             dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
 
@@ -1843,7 +1850,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                 if self.units == 'MM':
                 if self.units == 'MM':
                     t_offset = self.tool_offset[float('%.2f' % float(self.tools[tool_no]['C']))]
                     t_offset = self.tool_offset[float('%.2f' % float(self.tools[tool_no]['C']))]
                 else:
                 else:
-                    t_offset = self.tool_offset[float('%.3f' % float(self.tools[tool_no]['C']))]
+                    t_offset = self.tool_offset[float('%.4f' % float(self.tools[tool_no]['C']))]
             except KeyError:
             except KeyError:
                     t_offset = self.app.defaults['excellon_offset']
                     t_offset = self.app.defaults['excellon_offset']
             tool_offset_item = QtWidgets.QTableWidgetItem('%s' % str(t_offset))
             tool_offset_item = QtWidgets.QTableWidgetItem('%s' % str(t_offset))
@@ -1934,10 +1941,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         self.ui.tools_table.setColumnWidth(5, 17)
         self.ui.tools_table.setColumnWidth(5, 17)
 
 
         # horizontal_header.setStretchLastSection(True)
         # horizontal_header.setStretchLastSection(True)
-
-
-
-
         # horizontal_header.setColumnWidth(2, QtWidgets.QHeaderView.ResizeToContents)
         # horizontal_header.setColumnWidth(2, QtWidgets.QHeaderView.ResizeToContents)
 
 
         # horizontal_header.setStretchLastSection(True)
         # horizontal_header.setStretchLastSection(True)
@@ -2022,7 +2025,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                 if self.units == 'MM':
                 if self.units == 'MM':
                     dia = float('%.2f' % float(value['C']))
                     dia = float('%.2f' % float(value['C']))
                 else:
                 else:
-                    dia = float('%.3f' % float(value['C']))
+                    dia = float('%.4f' % float(value['C']))
                 self.tool_offset[dia] = t_default_offset
                 self.tool_offset[dia] = t_default_offset
 
 
         # Show/Hide Advanced Options
         # Show/Hide Advanced Options
@@ -2086,7 +2089,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         if self.units == 'MM':
         if self.units == 'MM':
             dia = float('%.2f' % float(self.ui.tools_table.item(row_of_item_changed, 1).text()))
             dia = float('%.2f' % float(self.ui.tools_table.item(row_of_item_changed, 1).text()))
         else:
         else:
-            dia = float('%.3f' % float(self.ui.tools_table.item(row_of_item_changed, 1).text()))
+            dia = float('%.4f' % float(self.ui.tools_table.item(row_of_item_changed, 1).text()))
 
 
         current_table_offset_edited = None
         current_table_offset_edited = None
         if self.ui.tools_table.currentItem() is not None:
         if self.ui.tools_table.currentItem() is not None:
@@ -2349,6 +2352,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
 
             geo_obj.options['Tools_in_use'] = tool_table_items
             geo_obj.options['Tools_in_use'] = tool_table_items
             geo_obj.options['type'] = 'Excellon Geometry'
             geo_obj.options['type'] = 'Excellon Geometry'
+            geo_obj.options["cnctooldia"] = str(tooldia)
 
 
             geo_obj.solid_geometry = []
             geo_obj.solid_geometry = []
 
 
@@ -2443,6 +2447,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
 
             geo_obj.options['Tools_in_use'] = tool_table_items
             geo_obj.options['Tools_in_use'] = tool_table_items
             geo_obj.options['type'] = 'Excellon Geometry'
             geo_obj.options['type'] = 'Excellon Geometry'
+            geo_obj.options["cnctooldia"] = str(tooldia)
 
 
             geo_obj.solid_geometry = []
             geo_obj.solid_geometry = []
 
 
@@ -2953,6 +2958,14 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
 
 
         if "cnctooldia" not in self.options:
         if "cnctooldia" not in self.options:
             self.options["cnctooldia"] =  self.app.defaults["geometry_cnctooldia"]
             self.options["cnctooldia"] =  self.app.defaults["geometry_cnctooldia"]
+            # try:
+            #     self.options["cnctooldia"] = [
+            #         float(eval(dia)) for dia in str(self.app.defaults["geometry_cnctooldia"]).split(",")
+            #     ]
+            # except Exception as e:
+            #     log.error("At least one tool diameter needed. Verify in Edit -> Preferences -> Geometry General -> "
+            #               "Tool dia. %s" % str(e))
+            #     return
 
 
         self.options["startz"] = self.app.defaults["geometry_startz"]
         self.options["startz"] = self.app.defaults["geometry_startz"]
 
 
@@ -2998,9 +3011,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         self.old_pp_state = ''
         self.old_pp_state = ''
         self.old_toolchangeg_state = ''
         self.old_toolchangeg_state = ''
 
 
-        # store here the default data for Geometry Data
-        self.default_data = {}
-
         # Attributes to be included in serialization
         # Attributes to be included in serialization
         # Always append to it because it carries contents
         # Always append to it because it carries contents
         # from predecessors.
         # from predecessors.
@@ -3009,7 +3019,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
     def build_ui(self):
     def build_ui(self):
 
 
         self.ui_disconnect()
         self.ui_disconnect()
-
         FlatCAMObj.build_ui(self)
         FlatCAMObj.build_ui(self)
 
 
         offset = 0
         offset = 0
@@ -3147,6 +3156,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         self.set_tool_offset_visibility(selected_row)
         self.set_tool_offset_visibility(selected_row)
         self.ui_connect()
         self.ui_connect()
 
 
+        # HACK: for whatever reasons the name in Selected tab is reverted to the original one after a successful rename
+        # done in the collection view but only for Geometry objects. Perhaps some references remains. Should be fixed.
+        self.ui.name_entry.set_value(self.options['name'])
+
     def set_ui(self, ui):
     def set_ui(self, ui):
         FlatCAMObj.set_ui(self, ui)
         FlatCAMObj.set_ui(self, ui)
 
 
@@ -3221,21 +3234,33 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         for def_key in self.default_data:
         for def_key in self.default_data:
             for opt_key, opt_val in self.options.items():
             for opt_key, opt_val in self.options.items():
                 if def_key == opt_key:
                 if def_key == opt_key:
-                    self.default_data[def_key] = opt_val
+                    self.default_data[def_key] = deepcopy(opt_val)
+
+        try:
+            tools_list = [
+                float(eval(dia)) for dia in self.options["cnctooldia"].split(",")
+            ]
+        except Exception as e:
+            log.error("At least one tool diameter needed. Verify in Edit -> Preferences -> Geometry General -> "
+                      "Tool dia. %s" % str(e))
+            return
 
 
         self.tooluid += 1
         self.tooluid += 1
+
         if not self.tools:
         if not self.tools:
-            self.tools.update({
-                self.tooluid: {
-                    'tooldia': float(self.options["cnctooldia"]),
-                    'offset': ('Path'),
-                    'offset_value': 0.0,
-                    'type': _('Rough'),
-                    'tool_type': 'C1',
-                    'data': self.default_data,
-                    'solid_geometry': self.solid_geometry
-                }
-            })
+            for toold in tools_list:
+                self.tools.update({
+                    self.tooluid: {
+                        'tooldia': float(toold),
+                        'offset': ('Path'),
+                        'offset_value': 0.0,
+                        'type': _('Rough'),
+                        'tool_type': 'C1',
+                        'data': self.default_data,
+                        'solid_geometry': self.solid_geometry
+                    }
+                })
+                self.tooluid += 1
         else:
         else:
             # if self.tools is not empty then it can safely be assumed that it comes from an opened project.
             # if self.tools is not empty then it can safely be assumed that it comes from an opened project.
             # Because of the serialization the self.tools list on project save, the dict keys (members of self.tools
             # Because of the serialization the self.tools list on project save, the dict keys (members of self.tools
@@ -3321,10 +3346,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             return
             return
 
 
     def on_offset_value_edited(self):
     def on_offset_value_edited(self):
-        '''
-        This will save the offset_value into self.tools storage whenever the oofset value is edited
+        """
+        This will save the offset_value into self.tools storage whenever the offset value is edited
         :return:
         :return:
-        '''
+        """
+
         for current_row in self.ui.geo_tools_table.selectedItems():
         for current_row in self.ui.geo_tools_table.selectedItems():
             # sometime the header get selected and it has row number -1
             # sometime the header get selected and it has row number -1
             # we don't want to do anything with the header :)
             # we don't want to do anything with the header :)
@@ -3367,7 +3393,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                     # works for Entry
                     # works for Entry
                     try:
                     try:
                         self.ui.grid3.itemAt(i).widget().editingFinished.connect(self.gui_form_to_storage)
                         self.ui.grid3.itemAt(i).widget().editingFinished.connect(self.gui_form_to_storage)
-                    except:
+                    except Exception as e3:
                         pass
                         pass
 
 
         for row in range(self.ui.geo_tools_table.rowCount()):
         for row in range(self.ui.geo_tools_table.rowCount()):
@@ -3405,56 +3431,56 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                         isinstance(self.ui.grid3.itemAt(i).widget(), IntEntry) or \
                         isinstance(self.ui.grid3.itemAt(i).widget(), IntEntry) or \
                         isinstance(self.ui.grid3.itemAt(i).widget(), FCEntry):
                         isinstance(self.ui.grid3.itemAt(i).widget(), FCEntry):
                     self.ui.grid3.itemAt(i).widget().editingFinished.disconnect()
                     self.ui.grid3.itemAt(i).widget().editingFinished.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             for row in range(self.ui.geo_tools_table.rowCount()):
             for row in range(self.ui.geo_tools_table.rowCount()):
                 for col in [2, 3, 4]:
                 for col in [2, 3, 4]:
                     self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.disconnect()
                     self.ui.geo_tools_table.cellWidget(row, col).currentIndexChanged.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         # I use lambda's because the connected functions have parameters that could be used in certain scenarios
         # I use lambda's because the connected functions have parameters that could be used in certain scenarios
         try:
         try:
             self.ui.addtool_btn.clicked.disconnect()
             self.ui.addtool_btn.clicked.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             self.ui.copytool_btn.clicked.disconnect()
             self.ui.copytool_btn.clicked.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             self.ui.deltool_btn.clicked.disconnect()
             self.ui.deltool_btn.clicked.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             self.ui.geo_tools_table.currentItemChanged.disconnect()
             self.ui.geo_tools_table.currentItemChanged.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             self.ui.geo_tools_table.itemChanged.disconnect()
             self.ui.geo_tools_table.itemChanged.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         try:
         try:
             self.ui.tool_offset_entry.editingFinished.disconnect()
             self.ui.tool_offset_entry.editingFinished.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
         for row in range(self.ui.geo_tools_table.rowCount()):
         for row in range(self.ui.geo_tools_table.rowCount()):
             try:
             try:
                 self.ui.geo_tools_table.cellWidget(row, 6).clicked.disconnect()
                 self.ui.geo_tools_table.cellWidget(row, 6).clicked.disconnect()
-            except:
+            except Exception as e:
                 pass
                 pass
 
 
         try:
         try:
             self.ui.plot_cb.stateChanged.disconnect()
             self.ui.plot_cb.stateChanged.disconnect()
-        except:
+        except Exception as e:
             pass
             pass
 
 
     def on_tool_add(self, dia=None):
     def on_tool_add(self, dia=None):
@@ -3475,7 +3501,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                     tooldia = float(self.ui.addtool_entry.get_value().replace(',', '.'))
                     tooldia = float(self.ui.addtool_entry.get_value().replace(',', '.'))
                 except ValueError:
                 except ValueError:
                     change_message = True
                     change_message = True
-                    tooldia = float(self.app.defaults["geometry_cnctooldia"])
+                    tooldia = self.options["cnctooldia"][0]
 
 
             if tooldia is None:
             if tooldia is None:
                 self.build_ui()
                 self.build_ui()
@@ -3541,6 +3567,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
                 }
                 }
             })
             })
 
 
+        self.tools[self.tooluid]['data']['name'] = self.options['name']
+
         self.ui.tool_offset_entry.hide()
         self.ui.tool_offset_entry.hide()
         self.ui.tool_offset_lbl.hide()
         self.ui.tool_offset_lbl.hide()
 
 
@@ -3772,7 +3800,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
 
 
         # 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:
-            tooluid = int(self.ui.geo_tools_table.item(current_row, 5).text())
+            item = self.ui.geo_tools_table.item(current_row, 5)
+            if item is not None:
+                tooluid = int(item.text())
+            else:
+                return
         except Exception as e:
         except Exception as e:
             log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
             log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
             return
             return
@@ -3780,8 +3812,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
         # update the form with the V-Shape fields if V-Shape selected in the geo_tool_table
         # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
         # also modify the Cut Z form entry to reflect the calculated Cut Z from values got from V-Shape Fields
         try:
         try:
-            tool_type_txt = self.ui.geo_tools_table.cellWidget(current_row, 4).currentText()
-            self.ui_update_v_shape(tool_type_txt=tool_type_txt)
+            item = self.ui.geo_tools_table.cellWidget(current_row, 4)
+            if item is not None:
+                tool_type_txt = item.currentText()
+                self.ui_update_v_shape(tool_type_txt=tool_type_txt)
+            else:
+                return
         except Exception as e:
         except Exception as e:
             log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
             log.debug("Tool missing. Add a tool in Geo Tool Table. %s" % str(e))
             return
             return
@@ -4137,7 +4173,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.ui.cncfeedrate_rapid_entry.hide()
             self.ui.cncfeedrate_rapid_entry.hide()
 
 
     def on_generatecnc_button_click(self, *args):
     def on_generatecnc_button_click(self, *args):
-
+        log.debug("Generating CNCJob from Geometry ...")
         self.app.report_usage("geometry_on_generatecnc_button")
         self.app.report_usage("geometry_on_generatecnc_button")
         self.read_form()
         self.read_form()
 
 
@@ -5291,6 +5327,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
         else:
         else:
             self.ui.cnc_tools_table.hide()
             self.ui.cnc_tools_table.hide()
 
 
+        self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
 
 
         offset = 0
         offset = 0
         tool_idx = 0
         tool_idx = 0
@@ -5891,13 +5928,19 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
             self.shapes.clear(update=True)
             self.shapes.clear(update=True)
             self.annotation.clear(update=True)
             self.annotation.clear(update=True)
 
 
+        if self.ui.annotation_cb.get_value() and self.ui.plot_cb.get_value():
+            self.app.plotcanvas.text_collection.enabled = True
+        else:
+            self.app.plotcanvas.text_collection.enabled = False
+
     def on_annotation_change(self):
     def on_annotation_change(self):
         if self.ui.annotation_cb.get_value():
         if self.ui.annotation_cb.get_value():
             self.app.plotcanvas.text_collection.enabled = True
             self.app.plotcanvas.text_collection.enabled = True
         else:
         else:
             self.app.plotcanvas.text_collection.enabled = False
             self.app.plotcanvas.text_collection.enabled = False
-        kind = self.ui.cncplot_method_combo.get_value()
-        self.plot(kind=kind)
+        # kind = self.ui.cncplot_method_combo.get_value()
+        # self.plot(kind=kind)
+        self.annotation.redraw()
 
 
     def convert_units(self, units):
     def convert_units(self, units):
         factor = CNCjob.convert_units(self, units)
         factor = CNCjob.convert_units(self, units)

+ 4 - 4
ObjectCollection.py

@@ -263,10 +263,9 @@ class ObjectCollection(QtCore.QAbstractItemModel):
 
 
         # ## GUI Events
         # ## GUI Events
         self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
         self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
-        self.view.activated.connect(self.on_item_activated)
-        # self.view.keyPressed.connect(self.on_key)
+        # self.view.activated.connect(self.on_item_activated)
         self.view.keyPressed.connect(self.app.ui.keyPressEvent)
         self.view.keyPressed.connect(self.app.ui.keyPressEvent)
-        self.view.clicked.connect(self.on_mouse_down)
+        # self.view.clicked.connect(self.on_mouse_down)
         self.view.customContextMenuRequested.connect(self.on_menu_request)
         self.view.customContextMenuRequested.connect(self.on_menu_request)
 
 
         self.click_modifier = None
         self.click_modifier = None
@@ -398,8 +397,9 @@ class ObjectCollection(QtCore.QAbstractItemModel):
     def setData(self, index, data, role=None):
     def setData(self, index, data, role=None):
         if index.isValid():
         if index.isValid():
             obj = index.internalPointer().obj
             obj = index.internalPointer().obj
+
             if obj:
             if obj:
-                old_name = obj.options['name']
+                old_name = deepcopy(obj.options['name'])
                 new_name = str(data)
                 new_name = str(data)
                 if old_name != new_name and new_name != '':
                 if old_name != new_name and new_name != '':
                     # rename the object
                     # rename the object

+ 43 - 0
README.md

@@ -9,6 +9,49 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+22.06.2019
+
+- some GUI layout optimizations in Edit -> Preferences
+- added the possibility for multiple tool diameters in the Edit -> Preferences -> Geometry -> Geometry General -> Tool dia separated by comma
+- fixed scaling for the multiple tool diameters in Edit -> Preferences -> Geometry -> Geometry General -> Tool dia, for NCC tools more than 2 and for Solderpaste nozzles more than 2
+- fixed bug in CNCJob where the CNC Tools table will show always only 2 decimals for Tool diameters regardless of the current measuring units
+- made the tools diameters decimals in case of INCH FlatCAM units to be 4 instead of 3
+- fixed bug in updating Grid values whenever toggling the FlatCAM units and the X, Y Grid values are linked, bugs which caused the Y value to be scaled incorrectly
+- set the decimals for Grid values to be set to 6 if the units of FlatCAM is INCH and to set to 4 if FlatCAM units are METRIC
+- updated translations
+- updated the Russian translation from 51% complete to 69% complete using the Yandex translation engine
+- fixed recently introduced bug in milling drills/slots functions
+- moved Substract Tool from Menu -> Edit -> Conversions to Menu -> Tool
+- fixed bug in Gerber isolation (Geometry expects now a value in string format and not float)
+- fixed bug in Paint tool: now it is possible to paint geometry generated by External Isolation (or Internal isolation)
+- fixed bug in editing a multigeo Geometry object if previously a tool was deleted
+- optimized the toggle of annotations; now there is no need to replot the entire CNCJob object too on toggling of the annotations
+- on toggling off the plot visibility the annotations are turned off too
+- updated translations; Russian translation at 76% (using Yandex translator engine - needs verification by a native speaker of Russian)
+- RELEASE 8.919
+
+20.06.2019
+
+- fixed Scale and Buffer Tool in Gerber Editor
+- fixed Editor Transform Tool in Gerber Editor
+- added a message in the status bar when copying coordinates to clipboard with SHIFT + LMB click combo
+- languages update
+
+19.06.2019
+
+- milling an Excellon file (holes and/or slots) will now transfer the chosen milling bit diameter to the resulting Geometry object
+
+17.06.2019
+
+- fixed bug where for Geometry objects after a successful object rename done in the Object collection view (Project tab), deselect the object and reselect it and then in the Selected tab the name is not the new one but the old one
+- for Geometry objects, adding a new tool to the Tools table after a successful rename will now store the new name in the tool data
+
+15.06.2019
+
+- fixed bug in Gerber parser that made the Gerber files generated by Altium Designer 18 not to be loaded
+- fixed bug in Gerber editor - on multiple edits on the same object, the aperture size and dims were continuously multiplied due of the file units not being updated
+- restored the FlatCAMObj.visible() to a non-threaded default
+
 11.06.2019
 11.06.2019
 
 
 - fixed the Edit -> Conversion -> Join ... functions (merge() functions)
 - fixed the Edit -> Conversion -> Join ... functions (merge() functions)

+ 11 - 8
camlib.py

@@ -112,9 +112,9 @@ class Geometry(object):
 
 
         self.geo_steps_per_circle = geo_steps_per_circle
         self.geo_steps_per_circle = geo_steps_per_circle
 
 
-        if geo_steps_per_circle is None:
-            geo_steps_per_circle = int(Geometry.defaults["geo_steps_per_circle"])
-        self.geo_steps_per_circle = geo_steps_per_circle
+        # if geo_steps_per_circle is None:
+        #     geo_steps_per_circle = int(Geometry.defaults["geo_steps_per_circle"])
+        # self.geo_steps_per_circle = geo_steps_per_circle
 
 
     def make_index(self):
     def make_index(self):
         self.flatten()
         self.flatten()
@@ -1849,6 +1849,8 @@ class ApertureMacro:
 
 
 class Gerber (Geometry):
 class Gerber (Geometry):
     """
     """
+    Here it is done all the Gerber parsing.
+
     **ATTRIBUTES**
     **ATTRIBUTES**
 
 
     * ``apertures`` (dict): The keys are names/identifiers of each aperture.
     * ``apertures`` (dict): The keys are names/identifiers of each aperture.
@@ -2452,7 +2454,6 @@ class Gerber (Geometry):
                         # --- Buffered ---
                         # --- Buffered ---
                         try:
                         try:
                             log.debug("Bare op-code %d." % current_operation_code)
                             log.debug("Bare op-code %d." % current_operation_code)
-
                             geo_dict = dict()
                             geo_dict = dict()
                             flash = self.create_flash_geometry(
                             flash = self.create_flash_geometry(
                                 Point(current_x, current_y), self.apertures[current_aperture],
                                 Point(current_x, current_y), self.apertures[current_aperture],
@@ -2467,7 +2468,7 @@ class Gerber (Geometry):
                                 else:
                                 else:
                                     geo_dict['solid'] = flash
                                     geo_dict['solid'] = flash
 
 
-                                if last_path_aperture not in self.apertures:
+                                if current_aperture not in self.apertures:
                                     self.apertures[current_aperture] = dict()
                                     self.apertures[current_aperture] = dict()
                                 if 'geometry' not in self.apertures[current_aperture]:
                                 if 'geometry' not in self.apertures[current_aperture]:
                                     self.apertures[current_aperture]['geometry'] = []
                                     self.apertures[current_aperture]['geometry'] = []
@@ -3598,6 +3599,8 @@ class Gerber (Geometry):
 
 
 class Excellon(Geometry):
 class Excellon(Geometry):
     """
     """
+    Here it is done all the Excellon parsing.
+
     *ATTRIBUTES*
     *ATTRIBUTES*
 
 
     * ``tools`` (dict): The key is the tool name and the value is
     * ``tools`` (dict): The key is the tool name and the value is
@@ -5350,7 +5353,7 @@ class CNCjob(Geometry):
                             if self.units == 'MM':
                             if self.units == 'MM':
                                 current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                                 current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                             else:
                             else:
-                                current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
+                                current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
 
 
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # because the values for Z offset are created in build_ui()
                             # because the values for Z offset are created in build_ui()
@@ -5448,7 +5451,7 @@ class CNCjob(Geometry):
                             if self.units == 'MM':
                             if self.units == 'MM':
                                 current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                                 current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                             else:
                             else:
-                                current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
+                                current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
 
 
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # TODO apply offset only when using the GUI, for TclCommand this will create an error
                             # because the values for Z offset are created in build_ui()
                             # because the values for Z offset are created in build_ui()
@@ -5504,7 +5507,7 @@ class CNCjob(Geometry):
                         if self.units == 'MM':
                         if self.units == 'MM':
                             current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                             current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
                         else:
                         else:
-                            current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
+                            current_tooldia = float('%.4f' % float(exobj.tools[tool]["C"]))
 
 
                         # TODO apply offset only when using the GUI, for TclCommand this will create an error
                         # TODO apply offset only when using the GUI, for TclCommand this will create an error
                         # because the values for Z offset are created in build_ui()
                         # because the values for Z offset are created in build_ui()

+ 3 - 3
flatcamEditors/FlatCAMExcEditor.py

@@ -1209,7 +1209,7 @@ class FlatCAMExcEditor(QtCore.QObject):
         for drill in self.exc_obj.drills:
         for drill in self.exc_obj.drills:
             if drill['tool'] in self.exc_obj.tools:
             if drill['tool'] in self.exc_obj.tools:
                 if self.units == 'IN':
                 if self.units == 'IN':
-                    tool_dia = float('%.3f' % self.exc_obj.tools[drill['tool']]['C'])
+                    tool_dia = float('%.4f' % self.exc_obj.tools[drill['tool']]['C'])
                 else:
                 else:
                     tool_dia = float('%.2f' % self.exc_obj.tools[drill['tool']]['C'])
                     tool_dia = float('%.2f' % self.exc_obj.tools[drill['tool']]['C'])
 
 
@@ -1238,7 +1238,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             # but use the real order found in the exc_obj.tools
             # but use the real order found in the exc_obj.tools
             for k, v in self.exc_obj.tools.items():
             for k, v in self.exc_obj.tools.items():
                 if self.units == 'IN':
                 if self.units == 'IN':
-                    tool_dia = float('%.3f' % v['C'])
+                    tool_dia = float('%.4f' % v['C'])
                 else:
                 else:
                     tool_dia = float('%.2f' % v['C'])
                     tool_dia = float('%.2f' % v['C'])
                 self.tool2tooldia[int(k)] = tool_dia
                 self.tool2tooldia[int(k)] = tool_dia
@@ -1324,7 +1324,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             if self.units == 'MM':
             if self.units == 'MM':
                 dia = QtWidgets.QTableWidgetItem('%.2f' % self.olddia_newdia[tool_no])
                 dia = QtWidgets.QTableWidgetItem('%.2f' % self.olddia_newdia[tool_no])
             else:
             else:
-                dia = QtWidgets.QTableWidgetItem('%.3f' % self.olddia_newdia[tool_no])
+                dia = QtWidgets.QTableWidgetItem('%.4f' % self.olddia_newdia[tool_no])
 
 
             dia.setFlags(QtCore.Qt.ItemIsEnabled)
             dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
 

+ 5 - 2
flatcamEditors/FlatCAMGeoEditor.py

@@ -3059,8 +3059,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
                 val = float(self.app.ui.grid_gap_x_entry.get_value())
                 val = float(self.app.ui.grid_gap_x_entry.get_value())
             except ValueError:
             except ValueError:
                 return
                 return
+
+            units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
+            dec = 6 if units == 'IN' else 4
             if self.app.ui.grid_gap_link_cb.isChecked():
             if self.app.ui.grid_gap_link_cb.isChecked():
-                self.app.ui.grid_gap_y_entry.set_value(val)
+                self.app.ui.grid_gap_y_entry.set_value(val, decimals=dec)
 
 
         self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator())
         self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator())
         self.app.ui.grid_gap_x_entry.textChanged.connect(
         self.app.ui.grid_gap_x_entry.textChanged.connect(
@@ -3999,7 +4002,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
 
 
     def update_options(self, obj):
     def update_options(self, obj):
         if self.paint_tooldia:
         if self.paint_tooldia:
-            obj.options['cnctooldia'] = self.paint_tooldia
+            obj.options['cnctooldia'] = deepcopy(str(self.paint_tooldia))
             self.paint_tooldia = None
             self.paint_tooldia = None
             return True
             return True
         else:
         else:

+ 83 - 66
flatcamEditors/FlatCAMGrbEditor.py

@@ -3445,7 +3445,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
 
 
         file_units = self.gerber_obj.gerber_units if self.gerber_obj.gerber_units else 'IN'
         file_units = self.gerber_obj.gerber_units if self.gerber_obj.gerber_units else 'IN'
         app_units = self.app.defaults['units']
         app_units = self.app.defaults['units']
-
         self.conversion_factor = 25.4 if file_units == 'IN' else (1 / 25.4) if file_units != app_units else 1
         self.conversion_factor = 25.4 if file_units == 'IN' else (1 / 25.4) if file_units != app_units else 1
 
 
         # Hide original geometry
         # Hide original geometry
@@ -3478,6 +3477,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
                     conv_apertures[apid][key] = self.gerber_obj.apertures[apid][key]
                     conv_apertures[apid][key] = self.gerber_obj.apertures[apid][key]
 
 
         self.gerber_obj.apertures = conv_apertures
         self.gerber_obj.apertures = conv_apertures
+        self.gerber_obj.gerber_units = app_units
 
 
         # ############################################################# ##
         # ############################################################# ##
         # APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
         # APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
@@ -3575,7 +3575,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
 
 
         :return: None
         :return: None
         """
         """
-
         new_grb_name = self.edited_obj_name
         new_grb_name = self.edited_obj_name
 
 
         # if the 'delayed plot' malfunctioned stop the QTimer
         # if the 'delayed plot' malfunctioned stop the QTimer
@@ -3710,6 +3709,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
             grb_obj.source_file = []
             grb_obj.source_file = []
             grb_obj.multigeo = False
             grb_obj.multigeo = False
             grb_obj.follow = False
             grb_obj.follow = False
+            grb_obj.gerber_units = app_obj.defaults['units']
 
 
             try:
             try:
                 grb_obj.create_geometry()
                 grb_obj.create_geometry()
@@ -3890,7 +3890,17 @@ class FlatCAMGrbEditor(QtCore.QObject):
                                                    "%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (0, 0))
                                                    "%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (0, 0))
 
 
             # Selection with left mouse button
             # Selection with left mouse button
-            if self.active_tool is not None and event.button is 1:
+            if self.active_tool is not None:
+                modifiers = QtWidgets.QApplication.keyboardModifiers()
+
+                # If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
+                if modifiers == QtCore.Qt.ShiftModifier:
+                    self.app.clipboard.setText(
+                        self.app.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1])
+                    )
+                    self.app.inform.emit(_("[success] Coordinates copied to clipboard."))
+                    return
+
                 # Dispatch event to active_tool
                 # Dispatch event to active_tool
                 self.active_tool.click(self.app.geo_editor.snap(self.pos[0], self.pos[1]))
                 self.active_tool.click(self.app.geo_editor.snap(self.pos[0], self.pos[1]))
 
 
@@ -4406,19 +4416,13 @@ class FlatCAMGrbEditor(QtCore.QObject):
                 if geom_el in selection:
                 if geom_el in selection:
                     geometric_data = geom_el.geo
                     geometric_data = geom_el.geo
                     buffered_geom_el = dict()
                     buffered_geom_el = dict()
-                    if 'solid' in geom_el:
-                        buffered_geom_el['solid'] = DrawToolShape(
-                            geometric_data['solid'].buffer(buff_value, join_style=join_style)
-                        )
-                    if 'follow' in geom_el:
-                        buffered_geom_el['follow'] = DrawToolShape(
-                            geometric_data['follow'].buffer(buff_value, join_style=join_style)
-                        )
-                    if 'clear' in geom_el:
-                        buffered_geom_el['clear'] = DrawToolShape(
-                            geometric_data['clear'].buffer(buff_value, join_style=join_style)
-                        )
-                    return buffered_geom_el
+                    if 'solid' in geometric_data:
+                        buffered_geom_el['solid'] = geometric_data['solid'].buffer(buff_value, join_style=join_style)
+                    if 'follow' in geometric_data:
+                        buffered_geom_el['follow'] = geometric_data['follow'].buffer(buff_value, join_style=join_style)
+                    if 'clear' in geometric_data:
+                        buffered_geom_el['clear'] = geometric_data['clear'].buffer(buff_value, join_style=join_style)
+                    return DrawToolShape(buffered_geom_el)
                 else:
                 else:
                     return geom_el
                     return geom_el
 
 
@@ -4435,9 +4439,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
                 temp_storage = deepcopy(buffer_recursion(self.storage_dict[apid]['geometry'], self.selected))
                 temp_storage = deepcopy(buffer_recursion(self.storage_dict[apid]['geometry'], self.selected))
                 self.storage_dict[apid]['geometry'] = []
                 self.storage_dict[apid]['geometry'] = []
                 self.storage_dict[apid]['geometry'] = temp_storage
                 self.storage_dict[apid]['geometry'] = temp_storage
-
             except Exception as e:
             except Exception as e:
-                log.debug("FlatCAMGrbEditor.buffer() --> %s" % str(e))
+                log.debug("FlatCAMGrbEditor.buffer() --> %s\n%s" % str(e))
+                self.app.inform.emit(_("[ERROR_NOTCL] Failed.\n%s") % str(traceback.print_exc()))
+                return
         self.plot_all()
         self.plot_all()
         self.app.inform.emit(_("[success] Done. Buffer Tool completed."))
         self.app.inform.emit(_("[success] Done. Buffer Tool completed."))
 
 
@@ -4467,17 +4472,20 @@ class FlatCAMGrbEditor(QtCore.QObject):
                 if geom_el in selection:
                 if geom_el in selection:
                     geometric_data = geom_el.geo
                     geometric_data = geom_el.geo
                     scaled_geom_el = dict()
                     scaled_geom_el = dict()
-                    if 'solid' in geom_el:
-                        scaled_geom_el['solid'] = DrawToolShape(
-                            affinity.scale(geometric_data['solid'], scale_factor, scale_factor, origin='center'))
-                    if 'follow' in geom_el:
-                        scaled_geom_el['follow'] = DrawToolShape(
-                            affinity.scale(geometric_data['follow'], scale_factor, scale_factor, origin='center'))
-                    if 'clear' in geom_el:
-                        scaled_geom_el['clear'] = DrawToolShape(
-                            affinity.scale(geometric_data['clear'], scale_factor, scale_factor, origin='center'))
-
-                    return scaled_geom_el
+                    if 'solid' in geometric_data:
+                        scaled_geom_el['solid'] = affinity.scale(
+                            geometric_data['solid'], scale_factor, scale_factor, origin='center'
+                        )
+                    if 'follow' in geometric_data:
+                        scaled_geom_el['follow'] = affinity.scale(
+                            geometric_data['follow'], scale_factor, scale_factor, origin='center'
+                        )
+                    if 'clear' in geometric_data:
+                        scaled_geom_el['clear'] = affinity.scale(
+                            geometric_data['clear'], scale_factor, scale_factor, origin='center'
+                        )
+
+                    return DrawToolShape(scaled_geom_el)
                 else:
                 else:
                     return geom_el
                     return geom_el
 
 
@@ -5229,9 +5237,10 @@ class TransformEditorTool(FlatCAMTool):
             try:
             try:
                 # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                 # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                 # bounding box
                 # bounding box
-                for el in elem_list:
+                for el_shape in elem_list:
+                    el = el_shape.geo
                     if 'solid' in el:
                     if 'solid' in el:
-                        xmin, ymin, xmax, ymax = el['solid'].bounds()
+                        xmin, ymin, xmax, ymax = el['solid'].bounds
                         xminlist.append(xmin)
                         xminlist.append(xmin)
                         yminlist.append(ymin)
                         yminlist.append(ymin)
                         xmaxlist.append(xmax)
                         xmaxlist.append(xmax)
@@ -5247,13 +5256,14 @@ class TransformEditorTool(FlatCAMTool):
                 px = 0.5 * (xminimal + xmaximal)
                 px = 0.5 * (xminimal + xmaximal)
                 py = 0.5 * (yminimal + ymaximal)
                 py = 0.5 * (yminimal + ymaximal)
 
 
-                for sel_el in elem_list:
+                for sel_el_shape in elem_list:
+                    sel_el = sel_el_shape.geo
                     if 'solid' in sel_el:
                     if 'solid' in sel_el:
-                        sel_el['solid'].rotate(-num, point=(px, py))
+                        sel_el['solid'] = affinity.rotate(sel_el['solid'], angle=-num, origin=(px, py))
                     if 'follow' in sel_el:
                     if 'follow' in sel_el:
-                        sel_el['follow'].rotate(-num, point=(px, py))
+                        sel_el['follow'] = affinity.rotate(sel_el['follow'], angle=-num, origin=(px, py))
                     if 'clear' in sel_el:
                     if 'clear' in sel_el:
-                        sel_el['clear'].rotate(-num, point=(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] Done. Rotate completed."))
                 self.app.inform.emit(_("[success] Done. Rotate completed."))
@@ -5287,9 +5297,10 @@ class TransformEditorTool(FlatCAMTool):
                 else:
                 else:
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # bounding box
                     # bounding box
-                    for el in elem_list:
+                    for el_shape in elem_list:
+                        el = el_shape.geo
                         if 'solid' in el:
                         if 'solid' in el:
-                            xmin, ymin, xmax, ymax = el['solid'].bounds()
+                            xmin, ymin, xmax, ymax = el['solid'].bounds
                             xminlist.append(xmin)
                             xminlist.append(xmin)
                             yminlist.append(ymin)
                             yminlist.append(ymin)
                             xmaxlist.append(xmax)
                             xmaxlist.append(xmax)
@@ -5307,22 +5318,23 @@ class TransformEditorTool(FlatCAMTool):
                 self.app.progress.emit(20)
                 self.app.progress.emit(20)
 
 
                 # execute mirroring
                 # execute mirroring
-                for sel_el in elem_list:
+                for sel_el_shape in elem_list:
+                    sel_el = sel_el_shape.geo
                     if axis is 'X':
                     if axis is 'X':
                         if 'solid' in sel_el:
                         if 'solid' in sel_el:
-                            sel_el['solid'].mirror('X', (px, py))
+                            sel_el['solid'] = affinity.scale(sel_el['solid'], xfact=1, yfact=-1, origin=(px, py))
                         if 'follow' in sel_el:
                         if 'follow' in sel_el:
-                            sel_el['follow'].mirror('X', (px, py))
+                            sel_el['follow'] = affinity.scale(sel_el['follow'], xfact=1, yfact=-1, origin=(px, py))
                         if 'clear' in sel_el:
                         if 'clear' in sel_el:
-                            sel_el['clear'].mirror('X', (px, py))
+                            sel_el['clear'] = affinity.scale(sel_el['clear'], xfact=1, yfact=-1, origin=(px, py))
                         self.app.inform.emit(_('[success] Flip on the Y axis done ...'))
                         self.app.inform.emit(_('[success] Flip on the Y axis done ...'))
                     elif axis is 'Y':
                     elif axis is 'Y':
                         if 'solid' in sel_el:
                         if 'solid' in sel_el:
-                            sel_el['solid'].mirror('Y', (px, py))
+                            sel_el['solid'] = affinity.scale(sel_el['solid'], xfact=-1, yfact=1, origin=(px, py))
                         if 'follow' in sel_el:
                         if 'follow' in sel_el:
-                            sel_el['follow'].mirror('Y', (px, py))
+                            sel_el['follow'] = affinity.scale(sel_el['follow'], xfact=-1, yfact=1, origin=(px, py))
                         if 'clear' in sel_el:
                         if 'clear' in sel_el:
-                            sel_el['clear'].mirror('Y', (px, py))
+                            sel_el['clear'] = affinity.scale(sel_el['clear'], xfact=-1, yfact=1, origin=(px, py))
                         self.app.inform.emit(_('[success] Flip on the X axis done ...'))
                         self.app.inform.emit(_('[success] Flip on the X axis done ...'))
                 self.draw_app.plot_all()
                 self.draw_app.plot_all()
                 self.app.progress.emit(100)
                 self.app.progress.emit(100)
@@ -5350,9 +5362,10 @@ class TransformEditorTool(FlatCAMTool):
                 try:
                 try:
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # bounding box
                     # bounding box
-                    for el in elem_list:
+                    for el_shape in elem_list:
+                        el = el_shape.geo
                         if 'solid' in el:
                         if 'solid' in el:
-                            xmin, ymin, xmax, ymax = el['solid'].bounds()
+                            xmin, ymin, xmax, ymax = el['solid'].bounds
                             xminlist.append(xmin)
                             xminlist.append(xmin)
                             yminlist.append(ymin)
                             yminlist.append(ymin)
 
 
@@ -5362,21 +5375,22 @@ class TransformEditorTool(FlatCAMTool):
 
 
                     self.app.progress.emit(20)
                     self.app.progress.emit(20)
 
 
-                    for sel_el in elem_list:
+                    for sel_el_shape in elem_list:
+                        sel_el = sel_el_shape.geo
                         if axis is 'X':
                         if axis is 'X':
                             if 'solid' in sel_el:
                             if 'solid' in sel_el:
-                                sel_el['solid'].skew(num, 0, point=(xminimal, yminimal))
+                                sel_el['solid'] = affinity.skew(sel_el['solid'], num, 0, origin=(xminimal, yminimal))
                             if 'follow' in sel_el:
                             if 'follow' in sel_el:
-                                sel_el['follow'].skew(num, 0, point=(xminimal, yminimal))
+                                sel_el['follow'] = affinity.skew(sel_el['follow'], num, 0, origin=(xminimal, yminimal))
                             if 'clear' in sel_el:
                             if 'clear' in sel_el:
-                                sel_el['clear'].skew(num, 0, point=(xminimal, yminimal))
+                                sel_el['clear'] = affinity.skew(sel_el['clear'], num, 0, origin=(xminimal, yminimal))
                         elif axis is 'Y':
                         elif axis is 'Y':
                             if 'solid' in sel_el:
                             if 'solid' in sel_el:
-                                sel_el['solid'].skew(0, num, point=(xminimal, yminimal))
+                                sel_el['solid'] = affinity.skew(sel_el['solid'], 0, num, origin=(xminimal, yminimal))
                             if 'follow' in sel_el:
                             if 'follow' in sel_el:
-                                sel_el['follow'].skew(0, num, point=(xminimal, yminimal))
+                                sel_el['follow'] = affinity.skew(sel_el['follow'], 0, num, origin=(xminimal, yminimal))
                             if 'clear' in sel_el:
                             if 'clear' in sel_el:
-                                sel_el['clear'].skew(0, num, point=(xminimal, yminimal))
+                                sel_el['clear'] = affinity.skew(sel_el['clear'], 0, num, origin=(xminimal, yminimal))
                     self.draw_app.plot_all()
                     self.draw_app.plot_all()
 
 
                     self.app.inform.emit(_('[success] Skew on the %s axis done ...') % str(axis))
                     self.app.inform.emit(_('[success] Skew on the %s axis done ...') % str(axis))
@@ -5409,9 +5423,10 @@ class TransformEditorTool(FlatCAMTool):
                 try:
                 try:
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # first get a bounding box to fit all; we use only the 'solids' as those should provide the biggest
                     # bounding box
                     # bounding box
-                    for el in elem_list:
+                    for el_shape in elem_list:
+                        el = el_shape.geo
                         if 'solid' in el:
                         if 'solid' in el:
-                            xmin, ymin, xmax, ymax = el['solid'].bounds()
+                            xmin, ymin, xmax, ymax = el['solid'].bounds
                             xminlist.append(xmin)
                             xminlist.append(xmin)
                             yminlist.append(ymin)
                             yminlist.append(ymin)
                             xmaxlist.append(xmax)
                             xmaxlist.append(xmax)
@@ -5432,13 +5447,14 @@ class TransformEditorTool(FlatCAMTool):
                         px = 0
                         px = 0
                         py = 0
                         py = 0
 
 
-                    for sel_el in elem_list:
+                    for sel_el_shape in elem_list:
+                        sel_el = sel_el_shape.geo
                         if 'solid' in sel_el:
                         if 'solid' in sel_el:
-                            sel_el['solid'].scale(xfactor, yfactor, point=(px, py))
+                            sel_el['solid'] = affinity.scale(sel_el['solid'], xfactor, yfactor, origin=(px, py))
                         if 'follow' in sel_el:
                         if 'follow' in sel_el:
-                            sel_el['follow'].scale(xfactor, yfactor, point=(px, py))
+                            sel_el['follow'] = affinity.scale(sel_el['follow'], xfactor, yfactor, origin=(px, py))
                         if 'clear' in sel_el:
                         if 'clear' in sel_el:
-                            sel_el['clear'].scale(xfactor, yfactor, point=(px, py))
+                            sel_el['clear'] = affinity.scale(sel_el['clear'], xfactor, yfactor, origin=(px, py))
                     self.draw_app.plot_all()
                     self.draw_app.plot_all()
 
 
                     self.app.inform.emit(_('[success] Scale on the %s axis done ...') % str(axis))
                     self.app.inform.emit(_('[success] Scale on the %s axis done ...') % str(axis))
@@ -5464,21 +5480,22 @@ class TransformEditorTool(FlatCAMTool):
                 try:
                 try:
                     self.app.progress.emit(20)
                     self.app.progress.emit(20)
 
 
-                    for sel_el in elem_list:
+                    for sel_el_shape in elem_list:
+                        sel_el = sel_el_shape.geo
                         if axis is 'X':
                         if axis is 'X':
                             if 'solid' in sel_el:
                             if 'solid' in sel_el:
-                                sel_el['solid'].offset((num, 0))
+                                sel_el['solid'] = affinity.translate(sel_el['solid'], num, 0)
                             if 'follow' in sel_el:
                             if 'follow' in sel_el:
-                                sel_el['follow'].offset((num, 0))
+                                sel_el['follow'] = affinity.translate(sel_el['follow'], num, 0)
                             if 'clear' in sel_el:
                             if 'clear' in sel_el:
-                                sel_el['clear'].offset((num, 0))
+                                sel_el['clear'] = affinity.translate(sel_el['clear'], num, 0)
                         elif axis is 'Y':
                         elif axis is 'Y':
                             if 'solid' in sel_el:
                             if 'solid' in sel_el:
-                                sel_el['solid'].offset((0, num))
+                                sel_el['solid'] = affinity.translate(sel_el['solid'], 0, num)
                             if 'follow' in sel_el:
                             if 'follow' in sel_el:
-                                sel_el['follow'].offset((0, num))
+                                sel_el['follow'] = affinity.translate(sel_el['follow'], 0, num)
                             if 'clear' in sel_el:
                             if 'clear' in sel_el:
-                                sel_el['clear'].offset((0, num))
+                                sel_el['clear'] = affinity.translate(sel_el['clear'], 0, num)
                         self.draw_app.plot_all()
                         self.draw_app.plot_all()
 
 
                     self.app.inform.emit(_('[success] Offset on the %s axis done ...') % str(axis))
                     self.app.inform.emit(_('[success] Offset on the %s axis done ...') % str(axis))

+ 26 - 47
flatcamGUI/FlatCAMGUI.py

@@ -4096,7 +4096,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
         self.combine_passes_cb.setToolTip(
         self.combine_passes_cb.setToolTip(
             _("Combine all passes into one object")
             _("Combine all passes into one object")
         )
         )
-        grid0.addWidget(self.combine_passes_cb, 4, 0)
+        grid0.addWidget(self.combine_passes_cb, 4, 0, 1, 2)
 
 
         # ## Clear non-copper regions
         # ## Clear non-copper regions
         self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear non-copper:</b>"))
         self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear non-copper:</b>"))
@@ -4468,8 +4468,8 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
         hlay2.addWidget(self.excellon_format_lower_mm_entry, QtCore.Qt.AlignLeft)
         hlay2.addWidget(self.excellon_format_lower_mm_entry, QtCore.Qt.AlignLeft)
         hlay2.addStretch()
         hlay2.addStretch()
 
 
-        hlay3 = QtWidgets.QHBoxLayout()
-        self.layout.addLayout(hlay3)
+        grid2 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid2)
 
 
         self.excellon_zeros_label = QtWidgets.QLabel(_('Default <b>Zeros</b>:'))
         self.excellon_zeros_label = QtWidgets.QLabel(_('Default <b>Zeros</b>:'))
         self.excellon_zeros_label.setAlignment(QtCore.Qt.AlignLeft)
         self.excellon_zeros_label.setAlignment(QtCore.Qt.AlignLeft)
@@ -4480,7 +4480,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "If TZ is checked then Trailing Zeros are kept\n"
               "If TZ is checked then Trailing Zeros are kept\n"
               "and Leading Zeros are removed.")
               "and Leading Zeros are removed.")
         )
         )
-        hlay3.addWidget(self.excellon_zeros_label)
+        grid2.addWidget(self.excellon_zeros_label, 0, 0)
 
 
         self.excellon_zeros_radio = RadioSet([{'label': 'LZ', 'value': 'L'},
         self.excellon_zeros_radio = RadioSet([{'label': 'LZ', 'value': 'L'},
                                               {'label': 'TZ', 'value': 'T'}])
                                               {'label': 'TZ', 'value': 'T'}])
@@ -4493,11 +4493,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "If TZ is checked then Trailing Zeros are kept\n"
               "If TZ is checked then Trailing Zeros are kept\n"
               "and Leading Zeros are removed.")
               "and Leading Zeros are removed.")
         )
         )
-        hlay3.addStretch()
-        hlay3.addWidget(self.excellon_zeros_radio, QtCore.Qt.AlignRight)
-
-        hlay4 = QtWidgets.QHBoxLayout()
-        self.layout.addLayout(hlay4)
+        grid2.addWidget(self.excellon_zeros_radio, 0, 1)
 
 
         self.excellon_units_label = QtWidgets.QLabel(_('Default <b>Units</b>:'))
         self.excellon_units_label = QtWidgets.QLabel(_('Default <b>Units</b>:'))
         self.excellon_units_label.setAlignment(QtCore.Qt.AlignLeft)
         self.excellon_units_label.setAlignment(QtCore.Qt.AlignLeft)
@@ -4508,7 +4504,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "Some Excellon files don't have an header\n"
               "Some Excellon files don't have an header\n"
               "therefore this parameter will be used.")
               "therefore this parameter will be used.")
         )
         )
-        hlay4.addWidget(self.excellon_units_label)
+        grid2.addWidget(self.excellon_units_label, 1, 0)
 
 
         self.excellon_units_radio = RadioSet([{'label': 'INCH', 'value': 'INCH'},
         self.excellon_units_radio = RadioSet([{'label': 'INCH', 'value': 'INCH'},
                                               {'label': 'MM', 'value': 'METRIC'}])
                                               {'label': 'MM', 'value': 'METRIC'}])
@@ -4517,27 +4513,14 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "Some Excellon files don't have an header\n"
               "Some Excellon files don't have an header\n"
               "therefore this parameter will be used.")
               "therefore this parameter will be used.")
         )
         )
-        hlay4.addStretch()
-        hlay4.addWidget(self.excellon_units_radio, QtCore.Qt.AlignRight)
+        grid2.addWidget(self.excellon_units_radio, 1, 1)
 
 
-        hlay5 = QtWidgets.QVBoxLayout()
-        self.layout.addLayout(hlay5)
-
-        self.empty_label = QtWidgets.QLabel("")
-        hlay5.addWidget(self.empty_label)
-
-        hlay6 = QtWidgets.QVBoxLayout()
-        self.layout.addLayout(hlay6)
+        grid2.addWidget(QtWidgets.QLabel(""), 2, 0)
 
 
         self.excellon_general_label = QtWidgets.QLabel(_("<b>Excellon Optimization:</b>"))
         self.excellon_general_label = QtWidgets.QLabel(_("<b>Excellon Optimization:</b>"))
-        hlay6.addWidget(self.excellon_general_label)
-
-        # Create a form layout for the Excellon general settings
-        form_box_excellon = QtWidgets.QFormLayout()
-        hlay6.addLayout(form_box_excellon)
+        grid2.addWidget(self.excellon_general_label, 3, 0, 1, 2)
 
 
         self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm:   '))
         self.excellon_optimization_label = QtWidgets.QLabel(_('Algorithm:   '))
-        self.excellon_optimization_label.setAlignment(QtCore.Qt.AlignLeft)
         self.excellon_optimization_label.setToolTip(
         self.excellon_optimization_label.setToolTip(
             _("This sets the optimization type for the Excellon drill path.\n"
             _("This sets the optimization type for the Excellon drill path.\n"
               "If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
               "If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
@@ -4548,6 +4531,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
               "If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
               "Travelling Salesman algorithm for path optimization.")
               "Travelling Salesman algorithm for path optimization.")
         )
         )
+        grid2.addWidget(self.excellon_optimization_label, 4, 0)
 
 
         self.excellon_optimization_radio = RadioSet([{'label': 'MH', 'value': 'M'},
         self.excellon_optimization_radio = RadioSet([{'label': 'MH', 'value': 'M'},
                                      {'label': 'Basic', 'value': 'B'}])
                                      {'label': 'Basic', 'value': 'B'}])
@@ -4561,8 +4545,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
               "If DISABLED, then FlatCAM works in 32bit mode and it uses \n"
               "Travelling Salesman algorithm for path optimization.")
               "Travelling Salesman algorithm for path optimization.")
         )
         )
-
-        form_box_excellon.addRow(self.excellon_optimization_label, self.excellon_optimization_radio)
+        grid2.addWidget(self.excellon_optimization_radio, 4, 1)
 
 
         self.optimization_time_label = QtWidgets.QLabel(_('Optimization Time:   '))
         self.optimization_time_label = QtWidgets.QLabel(_('Optimization Time:   '))
         self.optimization_time_label.setAlignment(QtCore.Qt.AlignLeft)
         self.optimization_time_label.setAlignment(QtCore.Qt.AlignLeft)
@@ -4573,10 +4556,11 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
               "In seconds.")
               "In seconds.")
 
 
         )
         )
+        grid2.addWidget(self.optimization_time_label, 5, 0)
 
 
         self.optimization_time_entry = IntEntry()
         self.optimization_time_entry = IntEntry()
         self.optimization_time_entry.setValidator(QtGui.QIntValidator(0, 999))
         self.optimization_time_entry.setValidator(QtGui.QIntValidator(0, 999))
-        form_box_excellon.addRow(self.optimization_time_label, self.optimization_time_entry)
+        grid2.addWidget(self.optimization_time_entry, 5, 1)
 
 
         current_platform = platform.architecture()[0]
         current_platform = platform.architecture()[0]
         if current_platform == '64bit':
         if current_platform == '64bit':
@@ -4744,25 +4728,23 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.mill_hole_label.setToolTip(
         self.mill_hole_label.setToolTip(
             _("Create Geometry for milling holes.")
             _("Create Geometry for milling holes.")
         )
         )
-        self.layout.addWidget(self.mill_hole_label)
+        grid2.addWidget(excellon_gcode_type_label, 11, 0, 1, 2)
 
 
-        grid3 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid3)
         tdlabel = QtWidgets.QLabel(_('Drill Tool dia:'))
         tdlabel = QtWidgets.QLabel(_('Drill Tool dia:'))
         tdlabel.setToolTip(
         tdlabel.setToolTip(
             _("Diameter of the cutting tool.")
             _("Diameter of the cutting tool.")
         )
         )
-        grid3.addWidget(tdlabel, 0, 0)
+        grid2.addWidget(tdlabel, 12, 0)
         self.tooldia_entry = LengthEntry()
         self.tooldia_entry = LengthEntry()
-        grid3.addWidget(self.tooldia_entry, 0, 1)
+        grid2.addWidget(self.tooldia_entry, 12, 1)
         stdlabel = QtWidgets.QLabel(_('Slot Tool dia:'))
         stdlabel = QtWidgets.QLabel(_('Slot Tool dia:'))
         stdlabel.setToolTip(
         stdlabel.setToolTip(
             _("Diameter of the cutting tool\n"
             _("Diameter of the cutting tool\n"
               "when milling slots.")
               "when milling slots.")
         )
         )
-        grid3.addWidget(stdlabel, 1, 0)
+        grid2.addWidget(stdlabel, 13, 0)
         self.slot_tooldia_entry = LengthEntry()
         self.slot_tooldia_entry = LengthEntry()
-        grid3.addWidget(self.slot_tooldia_entry, 1, 1)
+        grid2.addWidget(self.slot_tooldia_entry, 13, 1)
 
 
         grid4 = QtWidgets.QGridLayout()
         grid4 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid4)
         self.layout.addLayout(grid4)
@@ -5162,6 +5144,7 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
 
 
         grid0 = QtWidgets.QGridLayout()
         grid0 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid0)
         self.layout.addLayout(grid0)
+
         # Number of circle steps for circular aperture linear approximation
         # Number of circle steps for circular aperture linear approximation
         self.circle_steps_label = QtWidgets.QLabel(_("Circle Steps:"))
         self.circle_steps_label = QtWidgets.QLabel(_("Circle Steps:"))
         self.circle_steps_label.setToolTip(
         self.circle_steps_label.setToolTip(
@@ -5173,21 +5156,17 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.circle_steps_entry, 1, 1)
         grid0.addWidget(self.circle_steps_entry, 1, 1)
 
 
         # Tools
         # Tools
-        self.tools_label = QtWidgets.QLabel(_("<b>Tools</b>"))
-        self.layout.addWidget(self.tools_label)
-
-        grid0_b = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid0_b)
+        self.tools_label = QtWidgets.QLabel(_("<b>Tools:</b>"))
+        grid0.addWidget(self.tools_label, 2, 0, 1, 2)
 
 
         # Tooldia
         # Tooldia
-        tdlabel = QtWidgets.QLabel(_('Tool dia:                   '))
+        tdlabel = QtWidgets.QLabel(_('Tool dia:'))
         tdlabel.setToolTip(
         tdlabel.setToolTip(
-            _("The diameter of the cutting\n"
-              "tool..")
+            _("Diameters of the cutting tools, separated by ','")
         )
         )
-        grid0_b.addWidget(tdlabel, 0, 0)
-        self.cnctooldia_entry = LengthEntry()
-        grid0_b.addWidget(self.cnctooldia_entry, 0, 1)
+        grid0.addWidget(tdlabel, 3, 0)
+        self.cnctooldia_entry = FCEntry()
+        grid0.addWidget(self.cnctooldia_entry, 3, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 

+ 8 - 7
flatcamGUI/GUIElements.py

@@ -390,12 +390,13 @@ class FCEntry2(FCEntry):
     def on_edit_finished(self):
     def on_edit_finished(self):
         self.clearFocus()
         self.clearFocus()
 
 
-    def set_value(self, val):
+    def set_value(self, val, decimals=4):
         try:
         try:
             fval = float(val)
             fval = float(val)
         except ValueError:
         except ValueError:
             return
             return
-        self.setText('%.4f' % fval)
+
+        self.setText('%.*f' % (decimals, fval))
 
 
 
 
 class EvalEntry(QtWidgets.QLineEdit):
 class EvalEntry(QtWidgets.QLineEdit):
@@ -1059,7 +1060,6 @@ class FCDetachableTab(QtWidgets.QTabWidget):
             # Re-attach the tab at the given index
             # Re-attach the tab at the given index
             self.attachTab(contentWidget, name, icon, index)
             self.attachTab(contentWidget, name, icon, index)
 
 
-
         # If the drop did not occur on an existing tab, determine if the drop
         # If the drop did not occur on an existing tab, determine if the drop
         # occurred in the tab bar area (the area to the side of the QTabBar)
         # occurred in the tab bar area (the area to the side of the QTabBar)
         else:
         else:
@@ -1227,14 +1227,17 @@ class FCDetachableTab(QtWidgets.QTabWidget):
             :return:
             :return:
             """
             """
             # Determine if the current movement is detected as a drag
             # Determine if the current movement is detected as a drag
-            if not self.dragStartPos.isNull() and ((event.pos() - self.dragStartPos).manhattanLength() < QtWidgets.QApplication.startDragDistance()):
+            if not self.dragStartPos.isNull() and \
+                    ((event.pos() - self.dragStartPos).manhattanLength() < QtWidgets.QApplication.startDragDistance()):
                 self.dragInitiated = True
                 self.dragInitiated = True
 
 
             # If the current movement is a drag initiated by the left button
             # If the current movement is a drag initiated by the left button
             if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated):
             if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated):
 
 
                 # Stop the move event
                 # Stop the move event
-                finishMoveEvent = QtGui.QMouseEvent(QtCore.QEvent.MouseMove, event.pos(), QtCore.Qt.NoButton, QtCore.Qt.NoButton, QtCore.Qt.NoModifier)
+                finishMoveEvent = QtGui.QMouseEvent(
+                    QtCore.QEvent.MouseMove, event.pos(), QtCore.Qt.NoButton, QtCore.Qt.NoButton, QtCore.Qt.NoModifier
+                )
                 QtWidgets.QTabBar.mouseMoveEvent(self, finishMoveEvent)
                 QtWidgets.QTabBar.mouseMoveEvent(self, finishMoveEvent)
 
 
                 # Convert the move event into a drag
                 # Convert the move event into a drag
@@ -1261,13 +1264,11 @@ class FCDetachableTab(QtWidgets.QTabWidget):
                 # Initiate the drag
                 # Initiate the drag
                 dropAction = drag.exec_(QtCore.Qt.MoveAction | QtCore.Qt.CopyAction)
                 dropAction = drag.exec_(QtCore.Qt.MoveAction | QtCore.Qt.CopyAction)
 
 
-
                 # For Linux:  Here, drag.exec_() will not return MoveAction on Linux.  So it
                 # For Linux:  Here, drag.exec_() will not return MoveAction on Linux.  So it
                 #             must be set manually
                 #             must be set manually
                 if self.dragDropedPos.x() != 0 and self.dragDropedPos.y() != 0:
                 if self.dragDropedPos.x() != 0 and self.dragDropedPos.y() != 0:
                     dropAction = QtCore.Qt.MoveAction
                     dropAction = QtCore.Qt.MoveAction
 
 
-
                 # If the drag completed outside of the tab bar, detach the tab and move
                 # If the drag completed outside of the tab bar, detach the tab and move
                 # the content to the current cursor position
                 # the content to the current cursor position
                 if dropAction == QtCore.Qt.IgnoreAction:
                 if dropAction == QtCore.Qt.IgnoreAction:

+ 2 - 2
flatcamParsers/ParseDXF.py

@@ -91,7 +91,7 @@ def dxfarc2shapely(arc, n_points=100):
     #     angle += step_angle
     #     angle += step_angle
     #
     #
     #
     #
-    # log.debug("X = %.3f, Y = %.3f, Radius = %.3f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.3f, dir=%s" %
+    # log.debug("X = %.4f, Y = %.4f, Radius = %.4f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.4f, dir=%s" %
     #           (center_x, center_y, radius, start_angle, end_angle, step_angle, dir))
     #           (center_x, center_y, radius, start_angle, end_angle, step_angle, dir))
     #
     #
     # geo = LineString(point_list)
     # geo = LineString(point_list)
@@ -142,7 +142,7 @@ def dxfarc2shapely(arc, n_points=100):
             y = center_y + radius * math.sin(math.radians(- end_angle))
             y = center_y + radius * math.sin(math.radians(- end_angle))
         point_list.append((x, y))
         point_list.append((x, y))
 
 
-    # log.debug("X = %.3f, Y = %.3f, Radius = %.3f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.3f" %
+    # log.debug("X = %.4f, Y = %.4f, Radius = %.4f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.4f" %
     #           (center_x, center_y, radius, start_angle, end_angle, step_angle))
     #           (center_x, center_y, radius, start_angle, end_angle, step_angle))
 
 
     geo = LineString(point_list)
     geo = LineString(point_list)

+ 3 - 3
flatcamTools/ToolNonCopperClear.py

@@ -404,7 +404,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                     if self.units == 'MM':
                     if self.units == 'MM':
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                     else:
                     else:
-                        dia = QtWidgets.QTableWidgetItem('%.3f' % tooluid_value['tooldia'])
+                        dia = QtWidgets.QTableWidgetItem('%.4f' % tooluid_value['tooldia'])
 
 
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
 
@@ -787,7 +787,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                         else:
                         else:
                             log.debug("There are no geometries in the cleared polygon.")
                             log.debug("There are no geometries in the cleared polygon.")
 
 
-            geo_obj.options["cnctooldia"] = tool
+            geo_obj.options["cnctooldia"] = str(tool)
             geo_obj.multigeo = True
             geo_obj.multigeo = True
 
 
         def job_thread(app_obj):
         def job_thread(app_obj):
@@ -929,7 +929,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                             log.debug("There are no geometries in the cleared polygon.")
                             log.debug("There are no geometries in the cleared polygon.")
 
 
             geo_obj.multigeo = True
             geo_obj.multigeo = True
-            geo_obj.options["cnctooldia"] = tool
+            geo_obj.options["cnctooldia"] = str(tool)
 
 
             # check to see if geo_obj.tools is empty
             # check to see if geo_obj.tools is empty
             # it will be updated only if there is a solid_geometry for tools
             # it will be updated only if there is a solid_geometry for tools

+ 12 - 8
flatcamTools/ToolPaint.py

@@ -468,7 +468,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                     if self.units == 'MM':
                     if self.units == 'MM':
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                     else:
                     else:
-                        dia = QtWidgets.QTableWidgetItem('%.3f' % tooluid_value['tooldia'])
+                        dia = QtWidgets.QTableWidgetItem('%.4f' % tooluid_value['tooldia'])
 
 
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
 
@@ -920,7 +920,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                 log.debug("Could not Paint the polygons. %s" % str(e))
                 log.debug("Could not Paint the polygons. %s" % str(e))
                 self.app.inform.emit(
                 self.app.inform.emit(
                     _("[ERROR] Could not do Paint. Try a different combination of parameters. "
                     _("[ERROR] Could not do Paint. Try a different combination of parameters. "
-                    "Or a different strategy of paint\n%s") % str(e))
+                      "Or a different strategy of paint\n%s") % str(e))
                 return
                 return
 
 
             if cp is not None:
             if cp is not None:
@@ -930,7 +930,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                 else:
                 else:
                     geo_obj.solid_geometry = list(cp.get_objects())
                     geo_obj.solid_geometry = list(cp.get_objects())
 
 
-            geo_obj.options["cnctooldia"] = tooldia
+            geo_obj.options["cnctooldia"] = str(tooldia)
             # this turn on the FlatCAMCNCJob plot for multiple tools
             # this turn on the FlatCAMCNCJob plot for multiple tools
             geo_obj.multigeo = False
             geo_obj.multigeo = False
             geo_obj.multitool = True
             geo_obj.multitool = True
@@ -1043,7 +1043,11 @@ class ToolPaint(FlatCAMTool, Gerber):
 
 
             # ## Not iterable, do the actual indexing and add.
             # ## Not iterable, do the actual indexing and add.
             except TypeError:
             except TypeError:
-                self.flat_geometry.append(geometry)
+                if isinstance(geometry, LinearRing):
+                    g = Polygon(geometry)
+                    self.flat_geometry.append(g)
+                else:
+                    self.flat_geometry.append(geometry)
 
 
             return self.flat_geometry
             return self.flat_geometry
 
 
@@ -1127,7 +1131,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                 self.paint_tools[current_uid]['data']['name'] = name
                 self.paint_tools[current_uid]['data']['name'] = name
                 total_geometry[:] = []
                 total_geometry[:] = []
 
 
-            geo_obj.options["cnctooldia"] = tool_dia
+            geo_obj.options["cnctooldia"] = str(tool_dia)
             # this turn on the FlatCAMCNCJob plot for multiple tools
             # this turn on the FlatCAMCNCJob plot for multiple tools
             geo_obj.multigeo = True
             geo_obj.multigeo = True
             geo_obj.multitool = True
             geo_obj.multitool = True
@@ -1141,8 +1145,8 @@ class ToolPaint(FlatCAMTool, Gerber):
                     has_solid_geo += 1
                     has_solid_geo += 1
             if has_solid_geo == 0:
             if has_solid_geo == 0:
                 self.app.inform.emit(_("[ERROR] There is no Painting Geometry in the file.\n"
                 self.app.inform.emit(_("[ERROR] There is no Painting 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."))
+                                       "Usually it means that the tool diameter is too big for the painted geometry.\n"
+                                       "Change the painting parameters and try again."))
                 return
                 return
 
 
             # Experimental...
             # Experimental...
@@ -1222,7 +1226,7 @@ class ToolPaint(FlatCAMTool, Gerber):
                 self.paint_tools[current_uid]['data']['name'] = name
                 self.paint_tools[current_uid]['data']['name'] = name
                 cleared_geo[:] = []
                 cleared_geo[:] = []
 
 
-            geo_obj.options["cnctooldia"] = tool_dia
+            geo_obj.options["cnctooldia"] = str(tool_dia)
             # this turn on the FlatCAMCNCJob plot for multiple tools
             # this turn on the FlatCAMCNCJob plot for multiple tools
             geo_obj.multigeo = True
             geo_obj.multigeo = True
             geo_obj.multitool = True
             geo_obj.multitool = True

+ 1 - 1
flatcamTools/ToolSolderPaste.py

@@ -548,7 +548,7 @@ class SolderPaste(FlatCAMTool):
                     if self.units == 'MM':
                     if self.units == 'MM':
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                         dia = QtWidgets.QTableWidgetItem('%.2f' % tooluid_value['tooldia'])
                     else:
                     else:
-                        dia = QtWidgets.QTableWidgetItem('%.3f' % tooluid_value['tooldia'])
+                        dia = QtWidgets.QTableWidgetItem('%.4f' % tooluid_value['tooldia'])
 
 
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
                     dia.setFlags(QtCore.Qt.ItemIsEnabled)
 
 

BIN
locale/de/LC_MESSAGES/strings.mo


Разница между файлами не показана из-за своего большого размера
+ 202 - 198
locale/de/LC_MESSAGES/strings.po


BIN
locale/en/LC_MESSAGES/strings.mo


Разница между файлами не показана из-за своего большого размера
+ 202 - 198
locale/en/LC_MESSAGES/strings.po


BIN
locale/ro/LC_MESSAGES/strings.mo


Разница между файлами не показана из-за своего большого размера
+ 199 - 195
locale/ro/LC_MESSAGES/strings.po


BIN
locale/ru/LC_MESSAGES/strings.mo


Разница между файлами не показана из-за своего большого размера
+ 282 - 253
locale/ru/LC_MESSAGES/strings.po


Разница между файлами не показана из-за своего большого размера
+ 206 - 202
locale_template/strings.pot


Некоторые файлы не были показаны из-за большого количества измененных файлов