Explorar el Código

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

Beta - improvements
Marius Stanciu hace 6 años
padre
commit
a67a2ef37e
Se han modificado 100 ficheros con 3024 adiciones y 2515 borrados
  1. 327 550
      FlatCAMApp.py
  2. 101 78
      FlatCAMCommon.py
  3. 32 16
      FlatCAMObj.py
  4. 40 1
      README.md
  5. 19 5
      camlib.py
  6. 110 25
      flatcamEditors/FlatCAMExcEditor.py
  7. 116 6
      flatcamEditors/FlatCAMGeoEditor.py
  8. 56 9
      flatcamEditors/FlatCAMGrbEditor.py
  9. 144 146
      flatcamGUI/FlatCAMGUI.py
  10. 1 0
      flatcamGUI/PlotCanvas.py
  11. 32 14
      flatcamGUI/PlotCanvasLegacy.py
  12. 600 325
      flatcamGUI/PreferencesUI.py
  13. 2 2
      flatcamGUI/VisPyPatches.py
  14. 90 67
      flatcamParsers/ParseGerber.py
  15. 1 0
      flatcamTools/ToolCopperThieving.py
  16. 1 0
      flatcamTools/ToolDistance.py
  17. 2 1
      flatcamTools/ToolNonCopperClear.py
  18. 1 0
      flatcamTools/ToolPaint.py
  19. 41 46
      flatcamTools/ToolPanelize.py
  20. BIN
      locale/de/LC_MESSAGES/strings.mo
  21. 238 221
      locale/de/LC_MESSAGES/strings.po
  22. BIN
      locale/en/LC_MESSAGES/strings.mo
  23. 238 221
      locale/en/LC_MESSAGES/strings.po
  24. BIN
      locale/es/LC_MESSAGES/strings.mo
  25. 238 223
      locale/es/LC_MESSAGES/strings.po
  26. BIN
      locale/fr/LC_MESSAGES/strings.mo
  27. 237 220
      locale/fr/LC_MESSAGES/strings.po
  28. 357 339
      locale_template/strings.pot
  29. BIN
      share/clear_plot32.png
  30. BIN
      share/copy32.png
  31. BIN
      share/cutpath16.png
  32. BIN
      share/cutpath24.png
  33. BIN
      share/cutpath32.png
  34. BIN
      share/dark_resources/about32.png
  35. BIN
      share/dark_resources/active.gif
  36. BIN
      share/dark_resources/active_2.gif
  37. BIN
      share/dark_resources/active_2_static.png
  38. BIN
      share/dark_resources/active_3.gif
  39. BIN
      share/dark_resources/active_3_static.png
  40. BIN
      share/dark_resources/active_4.gif
  41. BIN
      share/dark_resources/active_4_static.png
  42. BIN
      share/dark_resources/active_static.png
  43. BIN
      share/dark_resources/addarray16.png
  44. BIN
      share/dark_resources/addarray20.png
  45. BIN
      share/dark_resources/addarray32.png
  46. BIN
      share/dark_resources/aero.png
  47. BIN
      share/dark_resources/aero_arc.png
  48. BIN
      share/dark_resources/aero_array.png
  49. BIN
      share/dark_resources/aero_buffer.png
  50. BIN
      share/dark_resources/aero_circle.png
  51. BIN
      share/dark_resources/aero_circle_geo.png
  52. BIN
      share/dark_resources/aero_disc.png
  53. BIN
      share/dark_resources/aero_drill.png
  54. BIN
      share/dark_resources/aero_drill_array.png
  55. BIN
      share/dark_resources/aero_path1.png
  56. BIN
      share/dark_resources/aero_path2.png
  57. BIN
      share/dark_resources/aero_path3.png
  58. BIN
      share/dark_resources/aero_path4.png
  59. BIN
      share/dark_resources/aero_path5.png
  60. BIN
      share/dark_resources/aero_semidisc.png
  61. BIN
      share/dark_resources/aero_slot.png
  62. BIN
      share/dark_resources/aero_text.png
  63. BIN
      share/dark_resources/align_center32.png
  64. BIN
      share/dark_resources/align_justify32.png
  65. BIN
      share/dark_resources/align_left32.png
  66. BIN
      share/dark_resources/align_right32.png
  67. BIN
      share/dark_resources/aperture16.png
  68. BIN
      share/dark_resources/aperture32.png
  69. BIN
      share/dark_resources/arc16.png
  70. BIN
      share/dark_resources/arc24.png
  71. BIN
      share/dark_resources/arc32.png
  72. BIN
      share/dark_resources/axis32.png
  73. BIN
      share/dark_resources/backup24.png
  74. BIN
      share/dark_resources/backup_export24.png
  75. BIN
      share/dark_resources/backup_import24.png
  76. BIN
      share/dark_resources/blocked16.png
  77. BIN
      share/dark_resources/blue32.png
  78. BIN
      share/dark_resources/bluelight12.png
  79. BIN
      share/dark_resources/bold32.png
  80. BIN
      share/dark_resources/bookmarks16.png
  81. BIN
      share/dark_resources/bookmarks32.png
  82. BIN
      share/dark_resources/brown32.png
  83. BIN
      share/dark_resources/buffer16-2.png
  84. BIN
      share/dark_resources/buffer16.png
  85. BIN
      share/dark_resources/buffer20.png
  86. BIN
      share/dark_resources/buffer24.png
  87. BIN
      share/dark_resources/bug16.png
  88. BIN
      share/dark_resources/bug32.png
  89. BIN
      share/dark_resources/calculator16.png
  90. BIN
      share/dark_resources/calculator24.png
  91. BIN
      share/dark_resources/calibrate_16.png
  92. BIN
      share/dark_resources/calibrate_32.png
  93. BIN
      share/dark_resources/cancel_edit16.png
  94. BIN
      share/dark_resources/cancel_edit32.png
  95. BIN
      share/dark_resources/circle32.png
  96. BIN
      share/dark_resources/clear_plot16.png
  97. BIN
      share/dark_resources/clear_plot32.png
  98. BIN
      share/dark_resources/close_edit_file16.png
  99. BIN
      share/dark_resources/close_edit_file32.png
  100. BIN
      share/dark_resources/cnc16.png

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 327 - 550
FlatCAMApp.py


+ 101 - 78
FlatCAMCommon.py

@@ -505,6 +505,94 @@ class ToolsDB(QtWidgets.QWidget):
         self.table_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
         table_hlay.addWidget(self.table_widget)
 
+        # set the number of columns and the headers tool tips
+        self.configure_table()
+
+        # pal = QtGui.QPalette()
+        # pal.setColor(QtGui.QPalette.Background, Qt.white)
+
+        # New Bookmark
+        new_vlay = QtWidgets.QVBoxLayout()
+        layout.addLayout(new_vlay)
+
+        # new_tool_lbl = QtWidgets.QLabel('<b>%s</b>' % _("New Tool"))
+        # new_vlay.addWidget(new_tool_lbl, alignment=QtCore.Qt.AlignBottom)
+
+        self.buttons_frame = QtWidgets.QFrame()
+        self.buttons_frame.setContentsMargins(0, 0, 0, 0)
+        layout.addWidget(self.buttons_frame)
+        self.buttons_box = QtWidgets.QHBoxLayout()
+        self.buttons_box.setContentsMargins(0, 0, 0, 0)
+        self.buttons_frame.setLayout(self.buttons_box)
+        self.buttons_frame.show()
+
+        add_entry_btn = FCButton(_("Add Geometry Tool in DB"))
+        add_entry_btn.setToolTip(
+            _("Add a new tool in the Tools Database.\n"
+              "It will be used in the Geometry UI.\n"
+              "You can edit it after it is added.")
+        )
+        self.buttons_box.addWidget(add_entry_btn)
+
+        # add_fct_entry_btn = FCButton(_("Add Paint/NCC Tool in DB"))
+        # add_fct_entry_btn.setToolTip(
+        #     _("Add a new tool in the Tools Database.\n"
+        #       "It will be used in the Paint/NCC Tools UI.\n"
+        #       "You can edit it after it is added.")
+        # )
+        # self.buttons_box.addWidget(add_fct_entry_btn)
+
+        remove_entry_btn = FCButton(_("Delete Tool from DB"))
+        remove_entry_btn.setToolTip(
+            _("Remove a selection of tools in the Tools Database.")
+        )
+        self.buttons_box.addWidget(remove_entry_btn)
+
+        export_db_btn = FCButton(_("Export DB"))
+        export_db_btn.setToolTip(
+            _("Save the Tools Database to a custom text file.")
+        )
+        self.buttons_box.addWidget(export_db_btn)
+
+        import_db_btn = FCButton(_("Import DB"))
+        import_db_btn.setToolTip(
+            _("Load the Tools Database information's from a custom text file.")
+        )
+        self.buttons_box.addWidget(import_db_btn)
+
+        self.add_tool_from_db = FCButton(_("Add Tool from Tools DB"))
+        self.add_tool_from_db.setToolTip(
+            _("Add a new tool in the Tools Table of the\n"
+              "active Geometry object after selecting a tool\n"
+              "in the Tools Database.")
+        )
+        self.add_tool_from_db.hide()
+
+        self.cancel_tool_from_db = FCButton(_("Cancel"))
+        self.cancel_tool_from_db.hide()
+
+        hlay = QtWidgets.QHBoxLayout()
+        layout.addLayout(hlay)
+        hlay.addWidget(self.add_tool_from_db)
+        hlay.addWidget(self.cancel_tool_from_db)
+        hlay.addStretch()
+
+        # ##############################################################################
+        # ######################## SIGNALS #############################################
+        # ##############################################################################
+
+        add_entry_btn.clicked.connect(self.on_tool_add)
+        remove_entry_btn.clicked.connect(self.on_tool_delete)
+        export_db_btn.clicked.connect(self.on_export_tools_db_file)
+        import_db_btn.clicked.connect(self.on_import_tools_db_file)
+        # closebtn.clicked.connect(self.accept)
+
+        self.add_tool_from_db.clicked.connect(self.on_tool_requested_from_app)
+        self.cancel_tool_from_db.clicked.connect(self.on_cancel_tool)
+
+        self.setup_db_ui()
+
+    def configure_table(self):
         self.table_widget.setColumnCount(27)
         # self.table_widget.setColumnWidth(0, 20)
         self.table_widget.setHorizontalHeaderLabels(
@@ -648,83 +736,8 @@ class ToolsDB(QtWidgets.QWidget):
             _("End Z.\n"
               "A position on Z plane to move immediately after job stop."))
 
-        # pal = QtGui.QPalette()
-        # pal.setColor(QtGui.QPalette.Background, Qt.white)
-
-        # New Bookmark
-        new_vlay = QtWidgets.QVBoxLayout()
-        layout.addLayout(new_vlay)
-
-        # new_tool_lbl = QtWidgets.QLabel('<b>%s</b>' % _("New Tool"))
-        # new_vlay.addWidget(new_tool_lbl, alignment=QtCore.Qt.AlignBottom)
-
-        self.buttons_frame = QtWidgets.QFrame()
-        self.buttons_frame.setContentsMargins(0, 0, 0, 0)
-        layout.addWidget(self.buttons_frame)
-        self.buttons_box = QtWidgets.QHBoxLayout()
-        self.buttons_box.setContentsMargins(0, 0, 0, 0)
-        self.buttons_frame.setLayout(self.buttons_box)
-        self.buttons_frame.show()
-
-        add_entry_btn = FCButton(_("Add Tool to Tools DB"))
-        add_entry_btn.setToolTip(
-            _("Add a new tool in the Tools Database.\n"
-              "You can edit it after it is added.")
-        )
-        remove_entry_btn = FCButton(_("Remove Tool from Tools DB"))
-        remove_entry_btn.setToolTip(
-            _("Remove a selection of tools in the Tools Database.")
-        )
-        export_db_btn = FCButton(_("Export Tool DB"))
-        export_db_btn.setToolTip(
-            _("Save the Tools Database to a custom text file.")
-        )
-        import_db_btn = FCButton(_("Import Tool DB"))
-        import_db_btn.setToolTip(
-            _("Load the Tools Database information's from a custom text file.")
-        )
-        # button_hlay.addStretch()
-        self.buttons_box.addWidget(add_entry_btn)
-        self.buttons_box.addWidget(remove_entry_btn)
-
-        self.buttons_box.addWidget(export_db_btn)
-        self.buttons_box.addWidget(import_db_btn)
-        # self.buttons_box.addWidget(closebtn)
-
-        self.add_tool_from_db = FCButton(_("Add Tool from Tools DB"))
-        self.add_tool_from_db.setToolTip(
-            _("Add a new tool in the Tools Table of the\n"
-              "active Geometry object after selecting a tool\n"
-              "in the Tools Database.")
-        )
-        self.add_tool_from_db.hide()
-
-        self.cancel_tool_from_db = FCButton(_("Cancel"))
-        self.cancel_tool_from_db.hide()
-
-        hlay = QtWidgets.QHBoxLayout()
-        layout.addLayout(hlay)
-        hlay.addWidget(self.add_tool_from_db)
-        hlay.addWidget(self.cancel_tool_from_db)
-        hlay.addStretch()
-
-        # ##############################################################################
-        # ######################## SIGNALS #############################################
-        # ##############################################################################
-
-        add_entry_btn.clicked.connect(self.on_tool_add)
-        remove_entry_btn.clicked.connect(self.on_tool_delete)
-        export_db_btn.clicked.connect(self.on_export_tools_db_file)
-        import_db_btn.clicked.connect(self.on_import_tools_db_file)
-        # closebtn.clicked.connect(self.accept)
-
-        self.add_tool_from_db.clicked.connect(self.on_tool_requested_from_app)
-        self.cancel_tool_from_db.clicked.connect(self.on_cancel_tool)
-
-        self.setup_db_ui()
-
     def setup_db_ui(self):
-        filename = self.app.data_path + '/tools_db.FlatConfig'
+        filename = self.app.data_path + '/tools_db.FlatDB'
 
         # load the database tools from the file
         try:
@@ -1007,7 +1020,17 @@ class ToolsDB(QtWidgets.QWidget):
 
         dict_elem = dict()
         dict_elem['name'] = 'new_tool'
-        dict_elem['tooldia'] = self.app.defaults["geometry_cnctooldia"]
+        if type(self.app.defaults["geometry_cnctooldia"]) == float:
+            dict_elem['tooldia'] = self.app.defaults["geometry_cnctooldia"]
+        else:
+            try:
+                tools_string = self.app.defaults["geometry_cnctooldia"].split(",")
+                tools_diameters = [eval(a) for a in tools_string if a != '']
+                dict_elem['tooldia'] = tools_diameters[0] if tools_diameters else 0.0
+            except Exception as e:
+                self.app.log.debug("ToolDB.on_tool_add() --> %s" % str(e))
+                return
+
         dict_elem['offset'] = 'Path'
         dict_elem['offset_value'] = 0.0
         dict_elem['type'] = 'Rough'
@@ -1151,7 +1174,7 @@ class ToolsDB(QtWidgets.QWidget):
     def on_save_tools_db(self, silent=False):
         self.app.log.debug("ToolsDB.on_save_button() --> Saving Tools Database to file.")
 
-        filename = self.app.data_path + "/tools_db.FlatConfig"
+        filename = self.app.data_path + "/tools_db.FlatDB"
 
         # Preferences save, update the color of the Tools DB Tab text
         for idx in range(self.app.ui.plot_tab_area.count()):

+ 32 - 16
FlatCAMObj.py

@@ -659,8 +659,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
 
         self.units_found = self.app.defaults['units']
 
-        self.fill_color = self.app.defaults['global_plot_fill']
-        self.outline_color = self.app.defaults['global_plot_line']
+        self.fill_color = self.app.defaults['gerber_plot_fill']
+        self.outline_color = self.app.defaults['gerber_plot_line']
 
         # Attributes to be included in serialization
         # Always append to it because it carries contents
@@ -738,6 +738,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
 
             self.ui.tool_type_label.hide()
             self.ui.tool_type_radio.hide()
+
+            # override the Preferences Value; in Basic mode the Tool Type is always Circular ('C1')
+            self.ui.tool_type_radio.set_value('circular')
+
             self.ui.tipdialabel.hide()
             self.ui.tipdia_spinner.hide()
             self.ui.tipanglelabel.hide()
@@ -1436,7 +1440,10 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                 def iso_init(geo_obj, app_obj):
                     # Propagate options
                     geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
-                    geo_obj.tool_type = self.ui.tool_type_radio.get_value().upper()
+                    if self.ui.tool_type_radio.get_value() == 'v':
+                        geo_obj.tool_type = 'V'
+                    else:
+                        geo_obj.tool_type = 'C1'
 
                     # if milling type is climb then the move is counter-clockwise around features
                     mill_t = 1 if milling_type == 'cl' else 0
@@ -1783,7 +1790,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         if 'color' in kwargs:
             color = kwargs['color']
         else:
-            color = self.app.defaults['global_plot_fill']
+            color = self.app.defaults['gerber_plot_fill']
 
         if 'marked_aperture' not in kwargs:
             return
@@ -3529,7 +3536,9 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             # Plot Excellon (All polygons?)
             if self.options["solid"]:
                 for geo in self.solid_geometry:
-                    self.add_shape(shape=geo, color='#750000BF', face_color='#C40000BF',
+                    self.add_shape(shape=geo,
+                                   color=self.app.defaults["excellon_plot_line"],
+                                   face_color=self.app.defaults["excellon_plot_fill"],
                                    visible=visible,
                                    layer=2)
             else:
@@ -3588,7 +3597,15 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         })
 
         if "cnctooldia" not in self.options:
-            self.options["cnctooldia"] = self.app.defaults["geometry_cnctooldia"]
+            if type(self.app.defaults["geometry_cnctooldia"]) == float:
+                self.options["cnctooldia"] = self.app.defaults["geometry_cnctooldia"]
+            else:
+                try:
+                    tools_string = self.app.defaults["geometry_cnctooldia"].split(",")
+                    tools_diameters = [eval(a) for a in tools_string if a != '']
+                    self.options["cnctooldia"] = tools_diameters[0] if tools_diameters else 0.0
+                except Exception as e:
+                    log.debug("FlatCAMObj.FlatCAMGeometry.init() --> %s" % str(e))
 
         self.options["startz"] = self.app.defaults["geometry_startz"]
 
@@ -4059,7 +4076,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
 
         # I use lambda's because the connected functions have parameters that could be used in certain scenarios
         self.ui.addtool_btn.clicked.connect(lambda: self.on_tool_add())
-        self.ui.addtool_entry.returnPressed.connect(self.on_tool_add)
 
         self.ui.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
         self.ui.deltool_btn.clicked.connect(lambda: self.on_tool_delete())
@@ -4112,11 +4128,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         except (TypeError, AttributeError):
             pass
 
-        try:
-            self.ui.addtool_entry.returnPressed.disconnect()
-        except (TypeError, AttributeError):
-            pass
-
         try:
             self.ui.copytool_btn.clicked.disconnect()
         except (TypeError, AttributeError):
@@ -5778,12 +5789,15 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
 
         return factor
 
-    def plot_element(self, element, color='#FF0000FF', visible=None):
+    def plot_element(self, element, color=None, visible=None):
+
+        if color is None:
+            color = '#FF0000FF'
 
         visible = visible if visible else self.options['plot']
         try:
             for sub_el in element:
-                self.plot_element(sub_el)
+                self.plot_element(sub_el, color=color)
 
         except TypeError:  # Element is not iterable...
             # if self.app.is_legacy is False:
@@ -5810,12 +5824,14 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             if self.multigeo is True:  # geo multi tool usage
                 for tooluid_key in self.tools:
                     solid_geometry = self.tools[tooluid_key]['solid_geometry']
-                    self.plot_element(solid_geometry, visible=visible)
+                    self.plot_element(solid_geometry, visible=visible,
+                                      color=self.app.defaults["geometry_plot_line"])
             else:
                 # plot solid geometry that may be an direct attribute of the geometry object
                 # for SingleGeo
                 if self.solid_geometry:
-                    self.plot_element(self.solid_geometry, visible=visible)
+                    self.plot_element(self.solid_geometry, visible=visible,
+                                      color=self.app.defaults["geometry_plot_line"])
 
             # self.plot_element(self.solid_geometry, visible=self.options['plot'])
 

+ 40 - 1
README.md

@@ -9,19 +9,58 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+27.12.2019
+
+- updated the POT file and the translation files for German, Spanish and French languages
+
+26.12.2019
+
+- modified the ToolDB class and changed some strings
+- Preferences classes now have access to the App attributes through app.setup_obj_classes() method
+- moved app.setup_obj_classes() upper in the App.__init__()
+- added a new Preferences setting allowing to modify the mouse cursor color
+- remade the GUI in Preferences -> General grouping the settings in a more clear way
+- made available the Jump To function in Excellon Editor
+- added a clean_up() method in all the Editor Tools that need it, to be run when aborting using the ESC key
+- fixed an error in the Gerber parser; it did not took into consideration the aperture size declared before the beginning of a Gerber region. Detected for Gerber files generated by KiCAD 5.x
+- in Panelize Tool made sure that for Gerber objects if one of the apertures is without geometry then it is ignored
+- further modifications in Preferences -> General GUI
+- further modifications in Preferences -> General GUI - extended the changes
+- in Legacy(2D) graphic engine made to work the mouse color change
+- theme changing is no longer auto-reboot upon change; it require now to press a button
+- cleaned the Preferences classes and added the signals and signal slots in those classes, removing them from the main app class
+- each FlatCAM object found in Preferences has it's own set of controls for changing the colors
+- added a set of gray icons to be used when the theme is complete dark (for now it is useful only for MacOS with dark theme because at the moment the app is not styled to dark UI except the plot area)
+
+25.12.2019
+
+- fixed an issue in old default file detection and in saving the factory defaults file
+- in Preferences window removed the Import/Export Preferences buttons because they are redundant with the entries in the File -> Menu -> Backup. and added a button to Restore Defaults
+- when in Basic mode the Tool type of the tool in the Geometry UI Tool Table after isolating a Gerber object is automatically selected as 'C1'
+- let the multiprocessing Pool have as many processes as needed
+- added a new Preferences setting allowing a custom mouse line width (to make it thicker or thinner)
+- changed the extension of the Tool Database file to FlatDB for easy recognition (in the future double clicking such a file might import the new tools in the FC database)
+
+24.12.2019
+
+- edited some icons so they don't contain white background
+- fixed an incorrect usage of object in the app.select_objects() method
+- fixed a typo in ToolDB.on_tool_add()
+
 23.12.2019
 
 - some fixes in the Legacy(2D) graphic mode regarding the possibility of changing the color of the Gerber objects
 - added a method to darken the outline color for Gerber objects when they have the color set
 - when Printing as PDF Gerber objects now the rendered color is the print color
 - speed up the plotting in OpenGL(3D) graphic mode
-- spped up the color setting for Gerber object when using the OpenGL(3D) graphic mode
+- speed up the color setting for Gerber object when using the OpenGL(3D) graphic mode
 - setting color for Gerber objects work on a selection of Gerber objects
 - ~~when the selection is changed in the Project Tree the selection shape on canvas is deleted~~
 - if an object is selected on Project Tree and it does not have the selection shape drawn, first click on canvas over it will draw the selection shape 
 - in Tool Transform added a new feature named 'Buffer'. For Geometry and Gerber objects will create (and replace) a geometry at a distance from the original geometry and for Excellon will adjust the Tool diameters
 - solved issue #355 - when the tool diameter field in the Edit → Preferences → Geometry → Geometry General → Tools → Tool dia is only one the app failed to read it
 - solved issue #356 - in Tools DB can not be added more than one tool if a translation is active 
+- some changes related to the fact that the geometry default tool diameter value can be comma separated string of tool diameters
 
 22.12.2019
 

+ 19 - 5
camlib.py

@@ -3466,11 +3466,20 @@ class CNCjob(Geometry):
         flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
         log.debug("%d paths" % len(flat_geometry))
 
+        if type(self.app.defaults["geometry_cnctooldia"]) == float:
+            default_dia = self.app.defaults["geometry_cnctooldia"]
+        else:
+            try:
+                tools_string = self.defaults["geometry_cnctooldia"].split(",")
+                tools_diameters = [eval(a) for a in tools_string if a != '']
+                default_dia = tools_diameters[0] if tools_diameters else 0.0
+            except Exception as e:
+                self.app.log.debug("camlib.CNCJob.generate_from_geometry_2() --> %s" % str(e))
+
         try:
-            self.tooldia = float(tooldia) if tooldia else self.app.defaults["geometry_cnctooldia"]
+            self.tooldia = float(tooldia) if tooldia else default_dia
         except ValueError:
-            self.tooldia = [float(el) for el in tooldia.split(',') if el != ''] if tooldia is not None else \
-                self.app.defaults["geometry_cnctooldia"]
+            self.tooldia = [float(el) for el in tooldia.split(',') if el != ''] if tooldia is not None else default_dia
 
         self.z_cut = float(z_cut) if z_cut is not None else self.app.defaults["geometry_cutz"]
         self.z_move = float(z_move) if z_move is not None else self.app.defaults["geometry_travelz"]
@@ -4243,8 +4252,7 @@ class CNCjob(Geometry):
     #     return fig
 
     def plot2(self, tooldia=None, dpi=75, margin=0.1, gcode_parsed=None,
-              color={"T": ["#F0E24D4C", "#B5AB3A4C"], "C": ["#5E6CFFFF", "#4650BDFF"]},
-              alpha={"T": 0.3, "C": 1.0}, tool_tolerance=0.0005, obj=None, visible=False, kind='all'):
+              color=None, alpha={"T": 0.3, "C": 1.0}, tool_tolerance=0.0005, obj=None, visible=False, kind='all'):
         """
         Plots the G-code job onto the given axes.
 
@@ -4261,6 +4269,12 @@ class CNCjob(Geometry):
         """
         # units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
 
+        if color is None:
+            color = {
+                "T": [self.app.defaults["cncjob_travel_fill"], self.app.defaults["cncjob_travel_line"]],
+                "C": [self.app.defaults["cncjob_plot_fill"], self.app.defaults["cncjob_plot_line"]]
+            }
+
         gcode_parsed = gcode_parsed if gcode_parsed else self.gcode_parsed
         path_num = 0
 

+ 110 - 25
flatcamEditors/FlatCAMExcEditor.py

@@ -56,8 +56,7 @@ class FCDrillAdd(FCShapeTool):
             item = self.draw_app.tools_table_exc.item((self.draw_app.last_tool_selected - 1), 1)
             self.draw_app.tools_table_exc.setCurrentItem(item)
         except KeyError:
-            self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' %
-                                          _("To add a drill first select a tool"))
+            self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("To add a drill first select a tool"))
             self.draw_app.select_tool("drill_select")
             return
 
@@ -75,6 +74,8 @@ class FCDrillAdd(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click to place ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -119,8 +120,18 @@ class FCDrillAdd(FCShapeTool):
         self.geometry = DrawToolShape(self.util_shape(self.points))
         self.draw_app.in_action = False
         self.complete = True
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Drill added."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Drill added."))
+        self.draw_app.app.jump_signal.disconnect()
+
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCDrillArray(FCShapeTool):
@@ -181,6 +192,8 @@ class FCDrillArray(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click on target location ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -292,7 +305,7 @@ class FCDrillArray(FCShapeTool):
 
         try:
             QtGui.QGuiApplication.restoreOverrideCursor()
-        except Exception as e:
+        except Exception:
             pass
 
         # add the point to drills if the diameter is a key in the dict, if not, create it add the drill location
@@ -322,6 +335,7 @@ class FCDrillArray(FCShapeTool):
             if (self.drill_angle * self.drill_array_size) > 360:
                 self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' %
                                               _("Too many drills for the selected spacing angle."))
+                self.draw_app.app.jump_signal.disconnect()
                 return
 
             radius = distance(self.destination, self.origin)
@@ -338,11 +352,21 @@ class FCDrillArray(FCShapeTool):
                 geo = self.util_shape((x, y))
                 self.geometry.append(DrawToolShape(geo))
         self.complete = True
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Drill Array added."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Drill Array added."))
         self.draw_app.in_action = False
         self.draw_app.array_frame.hide()
-        return
+
+        self.draw_app.app.jump_signal.disconnect()
+
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCSlot(FCShapeTool):
@@ -391,6 +415,8 @@ class FCSlot(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click on target location ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -531,9 +557,19 @@ class FCSlot(FCShapeTool):
 
         self.draw_app.in_action = False
         self.complete = True
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Adding Slot completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Slot completed."))
         self.draw_app.slot_frame.hide()
+        self.draw_app.app.jump_signal.disconnect()
+
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCSlotArray(FCShapeTool):
@@ -600,6 +636,8 @@ class FCSlotArray(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click on target location ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -821,6 +859,7 @@ class FCSlotArray(FCShapeTool):
             if (self.slot_angle * self.slot_array_size) > 360:
                 self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' %
                                               _("Too many Slots for the selected spacing angle."))
+                self.draw_app.app.jump_signal.disconnect()
                 return
 
             radius = distance(self.destination, self.origin)
@@ -842,18 +881,22 @@ class FCSlotArray(FCShapeTool):
 
                 self.geometry.append(DrawToolShape(geo))
         self.complete = True
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Slot Array added."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Slot Array added."))
         self.draw_app.in_action = False
         self.draw_app.slot_frame.hide()
         self.draw_app.slot_array_frame.hide()
-        return
+        self.draw_app.app.jump_signal.disconnect()
 
     def clean_up(self):
-        self.draw_app.selected = []
-        self.draw_app.apertures_table.clearSelection()
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
         self.draw_app.plot_all()
 
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCDrillResize(FCShapeTool):
     def __init__(self, draw_app):
@@ -1084,6 +1127,16 @@ class FCDrillResize(FCShapeTool):
         # MS: always return to the Select Tool
         self.draw_app.select_tool("drill_select")
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCDrillMove(FCShapeTool):
     def __init__(self, draw_app):
@@ -1112,6 +1165,8 @@ class FCDrillMove(FCShapeTool):
             dia_on_row = self.draw_app.tools_table_exc.item(row, 1).text()
             self.selected_dia_list.append(float(dia_on_row))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -1156,8 +1211,8 @@ class FCDrillMove(FCShapeTool):
             sel_shapes_to_be_deleted = []
 
         self.draw_app.build_ui()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Drill(s) Move completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Drill(s) Move completed."))
+        self.draw_app.app.jump_signal.disconnect()
 
     def selection_bbox(self):
         geo_list = []
@@ -1212,6 +1267,16 @@ class FCDrillMove(FCShapeTool):
                 ss_el = None
             return DrawToolUtilityShape(ss_el)
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCDrillCopy(FCDrillMove):
     def __init__(self, draw_app):
@@ -1254,8 +1319,18 @@ class FCDrillCopy(FCDrillMove):
             sel_shapes_to_be_deleted = []
 
         self.draw_app.build_ui()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Drill(s) copied."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Drill(s) copied."))
+        self.draw_app.app.jump_signal.disconnect()
+
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.tools_table_exc.clearSelection()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCDrillSelect(DrawTool):
@@ -2919,6 +2994,11 @@ class FlatCAMExcEditor(QtCore.QObject):
         except (TypeError, AttributeError):
             pass
 
+        try:
+            self.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
     def clear(self):
         self.active_tool = None
         # self.shape_buffer = []
@@ -3690,6 +3770,7 @@ class FlatCAMExcEditor(QtCore.QObject):
 
             # Update cursor
             self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         self.snap_x = x
@@ -3709,12 +3790,7 @@ class FlatCAMExcEditor(QtCore.QObject):
                                                "%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (dx, dy))
 
         # ## Utility geometry (animated)
-        geo = self.active_tool.utility_geometry(data=(x, y))
-
-        if isinstance(geo, DrawToolShape) and geo.geo is not None:
-            # Remove any previous utility shape
-            self.tool_shape.clear(update=True)
-            self.draw_utility_geometry(geo=geo)
+        self.update_utility_geometry(data=(x, y))
 
         # ## Selection area on canvas section # ##
         if event_is_dragging == 1 and event.button == 1:
@@ -3739,8 +3815,17 @@ class FlatCAMExcEditor(QtCore.QObject):
 
         # Update cursor
         self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
+                                     edge_width=self.app.defaults["global_cursor_width"],
                                      size=self.app.defaults["global_cursor_size"])
 
+    def update_utility_geometry(self, data):
+        # ### Utility geometry (animated) ###
+        geo = self.active_tool.utility_geometry(data=data)
+        if isinstance(geo, DrawToolShape) and geo.geo is not None:
+            # Remove any previous utility shape
+            self.tool_shape.clear(update=True)
+            self.draw_utility_geometry(geo=geo)
+
     def on_canvas_key_release(self, event):
         self.key = None
 

+ 116 - 6
flatcamEditors/FlatCAMGeoEditor.py

@@ -1883,6 +1883,7 @@ class DrawTool(object):
         # Jump to coords
         if key == QtCore.Qt.Key_J or key == 'J':
             self.draw_app.app.on_jump_to()
+        return
 
     def utility_geometry(self, data=None):
         return None
@@ -1988,6 +1989,15 @@ class FCCircle(FCShapeTool):
 
         self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Circle completed."))
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCArc(FCShapeTool):
     def __init__(self, draw_app):
@@ -2213,6 +2223,15 @@ class FCArc(FCShapeTool):
 
         self.draw_app.app.inform.emit('[success] %s' % _("Done. Arc completed."))
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCRectangle(FCShapeTool):
     """
@@ -2271,6 +2290,15 @@ class FCRectangle(FCShapeTool):
         self.draw_app.app.jump_signal.disconnect()
         self.draw_app.app.inform.emit('[success] %s' % _("Done. Rectangle completed."))
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCPolygon(FCShapeTool):
     """
@@ -2345,6 +2373,15 @@ class FCPolygon(FCShapeTool):
                 self.draw_app.draw_utility_geometry(geo=geo)
                 return _("Backtracked one point ...")
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCPath(FCPolygon):
     """
@@ -2401,6 +2438,15 @@ class FCPath(FCPolygon):
                 self.draw_app.draw_utility_geometry(geo=geo)
                 return _("Backtracked one point ...")
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCSelect(DrawTool):
     def __init__(self, draw_app):
@@ -2533,6 +2579,15 @@ class FCExplode(FCShapeTool):
         self.draw_app.on_shape_complete()
         self.draw_app.app.inform.emit('[success] %s...' % _("Done. Polygons exploded into lines."))
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCMove(FCShapeTool):
     def __init__(self, draw_app):
@@ -2555,8 +2610,10 @@ class FCMove(FCShapeTool):
         if len(self.draw_app.get_selected()) == 0:
             self.draw_app.app.inform.emit('[WARNING_NOTCL] %s...' %
                                           _("MOVE: No shape selected. Select a shape to move"))
+            return
         else:
             self.draw_app.app.inform.emit(_(" MOVE: Click on reference point ..."))
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
 
     def set_origin(self, origin):
         self.draw_app.app.inform.emit(_(" Click on destination point ..."))
@@ -2593,8 +2650,8 @@ class FCMove(FCShapeTool):
             # Delete old
             self.draw_app.delete_selected()
             self.complete = True
-            self.draw_app.app.inform.emit('[success] %s' %
-                                          _("Done. Geometry(s) Move completed."))
+            self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Move completed."))
+            self.draw_app.app.jump_signal.disconnect()
 
     def selection_bbox(self):
         geo_list = []
@@ -2701,6 +2758,15 @@ class FCMove(FCShapeTool):
             log.error("[ERROR] Something went bad. %s" % str(e))
             raise
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCCopy(FCMove):
     def __init__(self, draw_app):
@@ -2715,6 +2781,16 @@ class FCCopy(FCMove):
                          for geom in self.draw_app.get_selected()]
         self.complete = True
         self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Copy completed."))
+        self.draw_app.app.jump_signal.disconnect()
+
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCText(FCShapeTool):
@@ -2732,11 +2808,12 @@ class FCText(FCShapeTool):
 
         self.app = draw_app.app
 
-        self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
+        self.draw_app.app.inform.emit(_("Click on 1st point ..."))
         self.origin = (0, 0)
 
         self.text_gui = TextInputTool(self.app)
         self.text_gui.run()
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
 
     def click(self, point):
         # Create new geometry
@@ -2754,9 +2831,11 @@ class FCText(FCShapeTool):
                 self.text_gui.text_path = []
                 self.text_gui.hide_tool()
                 self.draw_app.select_tool('select')
+                self.draw_app.app.jump_signal.disconnect()
                 return
         else:
             self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("No text to add."))
+            self.draw_app.app.jump_signal.disconnect()
             return
 
         self.text_gui.text_path = []
@@ -2780,6 +2859,15 @@ class FCText(FCShapeTool):
         except Exception:
             return
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCBuffer(FCShapeTool):
     def __init__(self, draw_app):
@@ -2909,6 +2997,16 @@ class FCBuffer(FCShapeTool):
         self.draw_app.select_tool("select")
         self.buff_tool.hide_tool()
 
+    def clean_up(self):
+        self.draw_app.selected = list()
+        self.draw_app.plot_all()
+
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
+
 
 class FCEraser(FCShapeTool):
     def __init__(self, draw_app):
@@ -2931,6 +3029,7 @@ class FCEraser(FCShapeTool):
 
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
 
     def set_origin(self, origin):
         self.origin = origin
@@ -2982,8 +3081,8 @@ class FCEraser(FCShapeTool):
 
         self.draw_app.delete_utility_geometry()
         self.draw_app.plot_all()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Eraser tool action completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Eraser tool action completed."))
+        self.draw_app.app.jump_signal.disconnect()
 
     def utility_geometry(self, data=None):
         """
@@ -3013,9 +3112,14 @@ class FCEraser(FCShapeTool):
         return DrawToolUtilityShape(geo_list)
 
     def clean_up(self):
-        self.draw_app.selected = []
+        self.draw_app.selected = list()
         self.draw_app.plot_all()
 
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
 
 class FCPaint(FCShapeTool):
     def __init__(self, draw_app):
@@ -3557,6 +3661,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
         except (TypeError, AttributeError):
             pass
 
+        try:
+            self.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
     def add_shape(self, shape):
         """
         Adds a shape to the shape storage.
@@ -3831,6 +3940,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
 
             # Update cursor
             self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         self.snap_x = x

+ 56 - 9
flatcamEditors/FlatCAMGrbEditor.py

@@ -240,6 +240,8 @@ class FCPad(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click to place ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -378,13 +380,17 @@ class FCPad(FCShapeTool):
 
         self.draw_app.in_action = False
         self.complete = True
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Adding Pad completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Pad completed."))
+        self.draw_app.app.jump_signal.disconnect()
 
     def clean_up(self):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCPadArray(FCShapeTool):
@@ -464,6 +470,8 @@ class FCPadArray(FCShapeTool):
 
         self.draw_app.app.inform.emit(_("Click on target location ..."))
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
@@ -726,12 +734,16 @@ class FCPadArray(FCShapeTool):
                                       _("Done. Pad Array added."))
         self.draw_app.in_action = False
         self.draw_app.array_frame.hide()
-        return
+        self.draw_app.app.jump_signal.disconnect()
 
     def clean_up(self):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCPoligonize(FCShapeTool):
@@ -1077,6 +1089,10 @@ class FCRegion(FCShapeTool):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
     def on_key(self, key):
         # Jump to coords
@@ -1190,6 +1206,10 @@ class FCTrack(FCRegion):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
     def click(self, point):
         self.draw_app.in_action = True
@@ -1472,6 +1492,10 @@ class FCDisc(FCShapeTool):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCSemiDisc(FCShapeTool):
@@ -1737,6 +1761,10 @@ class FCSemiDisc(FCShapeTool):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
 
 class FCScale(FCShapeTool):
@@ -1921,6 +1949,8 @@ class FCApertureMove(FCShapeTool):
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         self.sel_limit = self.draw_app.app.defaults["gerber_editor_sel_limit"]
         self.selection_shape = self.selection_bbox()
 
@@ -2021,14 +2051,19 @@ class FCApertureMove(FCShapeTool):
 
         self.draw_app.plot_all()
         self.draw_app.build_ui()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Apertures Move completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Apertures Move completed."))
+        self.draw_app.app.jump_signal.disconnect()
 
     def clean_up(self):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
 
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
     def utility_geometry(self, data=None):
         """
         Temporary geometry on screen while using this tool.
@@ -2098,8 +2133,8 @@ class FCApertureCopy(FCApertureMove):
             sel_shapes_to_be_deleted = []
 
         self.draw_app.build_ui()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Apertures copied."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Apertures copied."))
+        self.draw_app.app.jump_signal.disconnect()
 
 
 class FCEraser(FCShapeTool):
@@ -2130,6 +2165,8 @@ class FCEraser(FCShapeTool):
         # Switch notebook to Selected page
         self.draw_app.app.ui.notebook.setCurrentWidget(self.draw_app.app.ui.selected_tab)
 
+        self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
+
         self.sel_limit = self.draw_app.app.defaults["gerber_editor_sel_limit"]
 
     def set_origin(self, origin):
@@ -2206,13 +2243,17 @@ class FCEraser(FCShapeTool):
 
         self.draw_app.delete_utility_geometry()
         self.draw_app.plot_all()
-        self.draw_app.app.inform.emit('[success] %s' %
-                                      _("Done. Eraser tool action completed."))
+        self.draw_app.app.inform.emit('[success] %s' % _("Done. Eraser tool action completed."))
+        self.draw_app.app.jump_signal.disconnect()
 
     def clean_up(self):
         self.draw_app.selected = []
         self.draw_app.apertures_table.clearSelection()
         self.draw_app.plot_all()
+        try:
+            self.draw_app.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
 
     def utility_geometry(self, data=None):
         """
@@ -3760,6 +3801,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
         except (TypeError, AttributeError):
             pass
 
+        try:
+            self.app.jump_signal.disconnect()
+        except (TypeError, AttributeError):
+            pass
+
     def clear(self):
         self.active_tool = None
         self.selected = []
@@ -4543,6 +4589,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
 
             # Update cursor
             self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         self.snap_x = x

+ 144 - 146
flatcamGUI/FlatCAMGUI.py

@@ -1211,23 +1211,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.pref_tab_bottom_layout_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
         self.pref_tab_bottom_layout.addLayout(self.pref_tab_bottom_layout_1)
 
-        self.pref_import_button = QtWidgets.QPushButton()
-        self.pref_import_button.setText(_("Import Preferences"))
-        self.pref_import_button.setMinimumWidth(130)
-        self.pref_import_button.setToolTip(
-            _("Import a full set of FlatCAM settings from a file\n"
-              "previously saved on HDD.\n\n"
-              "FlatCAM automatically save a 'factory_defaults' file\n"
-              "on the first start. Do not delete that file."))
-        self.pref_tab_bottom_layout_1.addWidget(self.pref_import_button)
-
-        self.pref_export_button = QtWidgets.QPushButton()
-        self.pref_export_button.setText(_("Export Preferences"))
-        self.pref_export_button.setMinimumWidth(130)
-        self.pref_export_button.setToolTip(
-           _("Export a full set of FlatCAM settings in a file\n"
-             "that is saved on HDD."))
-        self.pref_tab_bottom_layout_1.addWidget(self.pref_export_button)
+        self.pref_defaults_button = QtWidgets.QPushButton()
+        self.pref_defaults_button.setText(_("Restore Defaults"))
+        self.pref_defaults_button.setMinimumWidth(130)
+        self.pref_defaults_button.setToolTip(
+            _("Restore the entire set of default values\n"
+              "to the initial values loaded after first launch."))
+        self.pref_tab_bottom_layout_1.addWidget(self.pref_defaults_button)
 
         self.pref_open_button = QtWidgets.QPushButton()
         self.pref_open_button.setText(_("Open Pref Folder"))
@@ -1236,6 +1226,17 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
             _("Open the folder where FlatCAM save the preferences files."))
         self.pref_tab_bottom_layout_1.addWidget(self.pref_open_button)
 
+        # Clear Settings
+        self.clear_btn = FCButton('%s' % _('Clear GUI Settings'))
+        self.clear_btn.setMinimumWidth(130)
+
+        self.clear_btn.setToolTip(
+            _("Clear the GUI settings for FlatCAM,\n"
+              "such as: layout, gui state, style, hdpi support etc.")
+        )
+
+        self.pref_tab_bottom_layout_1.addWidget(self.clear_btn)
+
         self.pref_tab_bottom_layout_2 = QtWidgets.QHBoxLayout()
         self.pref_tab_bottom_layout_2.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
         self.pref_tab_bottom_layout.addLayout(self.pref_tab_bottom_layout_2)
@@ -2332,7 +2333,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         :param event: QT event to filter
         :return:
         """
-        if self.general_defaults_form.general_gui_set_group.toggle_tooltips_cb.get_value() is False:
+        if self.general_defaults_form.general_app_set_group.toggle_tooltips_cb.get_value() is False:
             if event.type() == QtCore.QEvent.ToolTip:
                 return True
             else:
@@ -3161,15 +3162,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                 if key == QtCore.Qt.Key_Escape or key == 'Escape':
                     # TODO: ...?
                     # self.on_tool_select("select")
-                    self.app.inform.emit('[WARNING_NOTCL] %s' %
-                                         _("Cancelled."))
+                    self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
 
                     self.app.geo_editor.delete_utility_geometry()
 
-                    # deselect any shape that might be selected
-                    self.app.geo_editor.selected = []
+                    self.app.geo_editor.active_tool.clean_up()
 
-                    self.app.geo_editor.replot()
                     self.app.geo_editor.select_tool('select')
 
                     # hide the notebook
@@ -3207,6 +3205,25 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                 if key == QtCore.Qt.Key_3 or key == '3':
                     self.app.on_select_tab('tool')
 
+                # Grid Snap
+                if key == QtCore.Qt.Key_G or key == 'G':
+                    self.app.ui.grid_snap_btn.trigger()
+
+                    # make sure that the cursor shape is enabled/disabled, too
+                    if self.app.geo_editor.options['grid_snap'] is True:
+                        self.app.app_cursor.enabled = True
+                    else:
+                        self.app.app_cursor.enabled = False
+
+                # Corner Snap
+                if key == QtCore.Qt.Key_K or key == 'K':
+                    self.app.geo_editor.on_corner_snap()
+
+                if key == QtCore.Qt.Key_V or key == 'V':
+                    self.app.on_zoom_fit(None)
+
+                # we do this so we can reuse the following keys while inside a Tool
+                # the above keys are general enough so were left outside
                 if self.app.geo_editor.active_tool is not None and self.geo_select_btn.isChecked() is False:
                     response = self.app.geo_editor.active_tool.on_key(key=key)
                     if response is not None:
@@ -3240,16 +3257,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                             messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
                             messagebox.exec_()
 
-                    # Grid Snap
-                    if key == QtCore.Qt.Key_G or key == 'G':
-                        self.app.ui.grid_snap_btn.trigger()
-
-                        # make sure that the cursor shape is enabled/disabled, too
-                        if self.app.geo_editor.options['grid_snap'] is True:
-                            self.app.app_cursor.enabled = True
-                        else:
-                            self.app.app_cursor.enabled = False
-
                     # Paint
                     if key == QtCore.Qt.Key_I or key == 'I':
                         self.app.geo_editor.select_tool('paint')
@@ -3258,10 +3265,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                     if key == QtCore.Qt.Key_J or key == 'J':
                         self.app.on_jump_to()
 
-                    # Corner Snap
-                    if key == QtCore.Qt.Key_K or key == 'K':
-                        self.app.geo_editor.on_corner_snap()
-
                     # Move
                     if key == QtCore.Qt.Key_M or key == 'M':
                         self.app.geo_editor.on_move_click()
@@ -3319,9 +3322,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                             messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
                             messagebox.exec_()
 
-                    if key == QtCore.Qt.Key_V or key == 'V':
-                        self.app.on_zoom_fit(None)
-
                     # Flip on X axis
                     if key == QtCore.Qt.Key_X or key == 'X':
                         self.app.geo_editor.transform_tool.on_flipx()
@@ -3351,7 +3351,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                 if key == QtCore.Qt.Key_M or key == 'M':
                     self.app.distance_tool.run()
                     return
-
             elif modifiers == QtCore.Qt.ShiftModifier:
                 # Run Distance Minimum Tool
                 if key == QtCore.Qt.Key_M or key == 'M':
@@ -3579,7 +3578,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                 if key == QtCore.Qt.Key_M or key == 'M':
                     self.app.distance_tool.run()
                     return
-
             elif modifiers == QtCore.Qt.ShiftModifier:
                 # Run Distance Minimum Tool
                 if key == QtCore.Qt.Key_M or key == 'M':
@@ -3590,15 +3588,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
             elif modifiers == QtCore.Qt.NoModifier:
                 # Abort the current action
                 if key == QtCore.Qt.Key_Escape or key == 'Escape':
-                    # TODO: ...?
-                    # self.on_tool_select("select")
                     self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
 
                     self.app.exc_editor.delete_utility_geometry()
 
-                    self.app.exc_editor.replot()
-                    # self.select_btn.setChecked(True)
-                    # self.on_tool_select('select')
+                    self.app.exc_editor.active_tool.clean_up()
+
                     self.app.exc_editor.select_tool('drill_select')
                     return
 
@@ -3655,44 +3650,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                     self.app.on_select_tab('tool')
                     return
 
-                # Add Array of Drill Hole Tool
-                if key == QtCore.Qt.Key_A or key == 'A':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    self.app.inform.emit("Click on target point.")
-                    self.app.ui.add_drill_array_btn.setChecked(True)
-
-                    self.app.exc_editor.x = self.app.mouse[0]
-                    self.app.exc_editor.y = self.app.mouse[1]
-
-                    self.app.exc_editor.select_tool('drill_array')
-                    return
-
-                # Copy
-                if key == QtCore.Qt.Key_C or key == 'C':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    if self.app.exc_editor.selected:
-                        self.app.inform.emit(_("Click on target point."))
-                        self.app.ui.copy_drill_btn.setChecked(True)
-                        self.app.exc_editor.on_tool_select('drill_copy')
-                        self.app.exc_editor.active_tool.set_origin(
-                            (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
-                    else:
-                        self.app.inform.emit('[WARNING_NOTCL] %s' %
-                                             _("Cancelled. Nothing selected to copy."))
-                    return
-
-                # Add Drill Hole Tool
-                if key == QtCore.Qt.Key_D or key == 'D':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    self.app.inform.emit(_("Click on target point."))
-                    self.app.ui.add_drill_btn.setChecked(True)
-
-                    self.app.exc_editor.x = self.app.mouse[0]
-                    self.app.exc_editor.y = self.app.mouse[1]
-
-                    self.app.exc_editor.select_tool('drill_add')
-                    return
-
                 # Grid Snap
                 if key == QtCore.Qt.Key_G or key == 'G':
                     self.app.exc_editor.launched_from_shortcuts = True
@@ -3704,69 +3661,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                     self.app.ui.grid_snap_btn.trigger()
                     return
 
-                # Jump to coords
-                if key == QtCore.Qt.Key_J or key == 'J':
-                    self.app.on_jump_to()
-
                 # Corner Snap
                 if key == QtCore.Qt.Key_K or key == 'K':
                     self.app.exc_editor.launched_from_shortcuts = True
                     self.app.ui.corner_snap_btn.trigger()
                     return
 
-                # Move
-                if key == QtCore.Qt.Key_M or key == 'M':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    if self.app.exc_editor.selected:
-                        self.app.inform.emit(_("Click on target point."))
-                        self.app.ui.move_drill_btn.setChecked(True)
-                        self.app.exc_editor.on_tool_select('drill_move')
-                        self.app.exc_editor.active_tool.set_origin(
-                            (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
-                    else:
-                        self.app.inform.emit('[WARNING_NOTCL] %s' %
-                                             _("Cancelled. Nothing selected to move."))
-                    return
-
-                # Add Array of Slote Hole Tool
-                if key == QtCore.Qt.Key_Q or key == 'Q':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    self.app.inform.emit("Click on target point.")
-                    self.app.ui.add_slot_array_btn.setChecked(True)
-
-                    self.app.exc_editor.x = self.app.mouse[0]
-                    self.app.exc_editor.y = self.app.mouse[1]
-
-                    self.app.exc_editor.select_tool('slot_array')
-                    return
-
-                # Resize Tool
-                if key == QtCore.Qt.Key_R or key == 'R':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    self.app.exc_editor.select_tool('drill_resize')
-                    return
-
-                # Add Tool
-                if key == QtCore.Qt.Key_T or key == 'T':
-                    self.app.exc_editor.launched_from_shortcuts = True
-                    # ## Current application units in Upper Case
-                    self.units = self.general_defaults_form.general_app_group.units_radio.get_value().upper()
-                    tool_add_popup = FCInputDialog(title=_("New Tool ..."),
-                                                   text='%s:' % _('Enter a Tool Diameter'),
-                                                   min=0.0000, max=99.9999, decimals=4)
-                    tool_add_popup.setWindowIcon(QtGui.QIcon(self.app.resource_location + '/letter_t_32.png'))
-
-                    val, ok = tool_add_popup.get_value()
-                    if ok:
-                        self.app.exc_editor.on_tool_add(tooldia=val)
-                        formated_val = '%.*f' % (self.decimals, float(val))
-                        self.app.inform.emit(
-                            '[success] %s: %s %s' % (_("Added new tool with dia"), formated_val, str(self.units))
-                        )
-                    else:
-                        self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding Tool cancelled ..."))
-                    return
-
                 # Zoom Fit
                 if key == QtCore.Qt.Key_V or key == 'V':
                     self.app.exc_editor.launched_from_shortcuts = True
@@ -3787,15 +3687,113 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
                 # Propagate to tool
                 response = None
-                if self.app.exc_editor.active_tool is not None:
-                    response = self.app.exc_editor.active_tool.on_key(key=key)
-                if response is not None:
-                    self.app.inform.emit(response)
 
                 # Show Shortcut list
                 if key == QtCore.Qt.Key_F3 or key == 'F3':
                     self.app.on_shortcut_list()
                     return
+
+                # we do this so we can reuse the following keys while inside a Tool
+                # the above keys are general enough so were left outside
+                if self.app.exc_editor.active_tool is not None and self.select_drill_btn.isChecked() is False:
+                    response = self.app.exc_editor.active_tool.on_key(key=key)
+                    if response is not None:
+                        self.app.inform.emit(response)
+                else:
+                    # Add Array of Drill Hole Tool
+                    if key == QtCore.Qt.Key_A or key == 'A':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        self.app.inform.emit("Click on target point.")
+                        self.app.ui.add_drill_array_btn.setChecked(True)
+
+                        self.app.exc_editor.x = self.app.mouse[0]
+                        self.app.exc_editor.y = self.app.mouse[1]
+
+                        self.app.exc_editor.select_tool('drill_array')
+                        return
+
+                    # Copy
+                    if key == QtCore.Qt.Key_C or key == 'C':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        if self.app.exc_editor.selected:
+                            self.app.inform.emit(_("Click on target point."))
+                            self.app.ui.copy_drill_btn.setChecked(True)
+                            self.app.exc_editor.on_tool_select('drill_copy')
+                            self.app.exc_editor.active_tool.set_origin(
+                                (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
+                        else:
+                            self.app.inform.emit('[WARNING_NOTCL] %s' %
+                                                 _("Cancelled. Nothing selected to copy."))
+                        return
+
+                    # Add Drill Hole Tool
+                    if key == QtCore.Qt.Key_D or key == 'D':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        self.app.inform.emit(_("Click on target point."))
+                        self.app.ui.add_drill_btn.setChecked(True)
+
+                        self.app.exc_editor.x = self.app.mouse[0]
+                        self.app.exc_editor.y = self.app.mouse[1]
+
+                        self.app.exc_editor.select_tool('drill_add')
+                        return
+
+                    # Jump to coords
+                    if key == QtCore.Qt.Key_J or key == 'J':
+                        self.app.on_jump_to()
+
+                    # Move
+                    if key == QtCore.Qt.Key_M or key == 'M':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        if self.app.exc_editor.selected:
+                            self.app.inform.emit(_("Click on target point."))
+                            self.app.ui.move_drill_btn.setChecked(True)
+                            self.app.exc_editor.on_tool_select('drill_move')
+                            self.app.exc_editor.active_tool.set_origin(
+                                (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
+                        else:
+                            self.app.inform.emit('[WARNING_NOTCL] %s' %
+                                                 _("Cancelled. Nothing selected to move."))
+                        return
+
+                    # Add Array of Slots Hole Tool
+                    if key == QtCore.Qt.Key_Q or key == 'Q':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        self.app.inform.emit("Click on target point.")
+                        self.app.ui.add_slot_array_btn.setChecked(True)
+
+                        self.app.exc_editor.x = self.app.mouse[0]
+                        self.app.exc_editor.y = self.app.mouse[1]
+
+                        self.app.exc_editor.select_tool('slot_array')
+                        return
+
+                    # Resize Tool
+                    if key == QtCore.Qt.Key_R or key == 'R':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        self.app.exc_editor.select_tool('drill_resize')
+                        return
+
+                    # Add Tool
+                    if key == QtCore.Qt.Key_T or key == 'T':
+                        self.app.exc_editor.launched_from_shortcuts = True
+                        # ## Current application units in Upper Case
+                        self.units = self.general_defaults_form.general_app_group.units_radio.get_value().upper()
+                        tool_add_popup = FCInputDialog(title=_("New Tool ..."),
+                                                       text='%s:' % _('Enter a Tool Diameter'),
+                                                       min=0.0000, max=99.9999, decimals=4)
+                        tool_add_popup.setWindowIcon(QtGui.QIcon(self.app.resource_location + '/letter_t_32.png'))
+
+                        val, ok = tool_add_popup.get_value()
+                        if ok:
+                            self.app.exc_editor.on_tool_add(tooldia=val)
+                            formated_val = '%.*f' % (self.decimals, float(val))
+                            self.app.inform.emit(
+                                '[success] %s: %s %s' % (_("Added new tool with dia"), formated_val, str(self.units))
+                            )
+                        else:
+                            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Adding Tool cancelled ..."))
+                        return
         elif self.app.call_source == 'measurement':
             if modifiers == QtCore.Qt.ControlModifier:
                 pass

+ 1 - 0
flatcamGUI/PlotCanvas.py

@@ -310,6 +310,7 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
             # Update cursor
             self.fcapp.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
                                            symbol='++', edge_color=self.fcapp.cursor_color_3D,
+                                           edge_width=self.fcapp.defaults["global_cursor_width"],
                                            size=self.fcapp.defaults["global_cursor_size"])
 
     def new_text_group(self, collection=None):

+ 32 - 14
flatcamGUI/PlotCanvasLegacy.py

@@ -375,16 +375,19 @@ class PlotCanvasLegacy(QtCore.QObject):
         pass
         # log.debug("Cache updated the screen!")
 
-    def new_cursor(self, axes=None, big=None):
+    def new_cursor(self, axes=None, big=None, color=None):
         # if axes is None:
         #     c = MplCursor(axes=self.axes, color='black', linewidth=1)
         # else:
         #     c = MplCursor(axes=axes, color='black', linewidth=1)
 
-        if self.app.defaults['global_theme'] == 'white':
-            color = '#000000'
+        if color:
+            color = color
         else:
-            color = '#FFFFFF'
+            if self.app.defaults['global_theme'] == 'white':
+                color = '#000000'
+            else:
+                color = '#FFFFFF'
 
         if big is True:
             self.big_cursor = True
@@ -398,20 +401,25 @@ class PlotCanvasLegacy(QtCore.QObject):
 
         return c
 
-    def draw_cursor(self, x_pos, y_pos):
+    def draw_cursor(self, x_pos, y_pos, color=None):
         """
         Draw a cursor at the mouse grid snapped position
 
         :param x_pos: mouse x position
         :param y_pos: mouse y position
+        :param color: custom color of the mouse
         :return:
         """
+
         # there is no point in drawing mouse cursor when panning as it jumps in a confusing way
         if self.app.app_cursor.enabled is True and self.panning is False:
-            if self.app.defaults['global_theme'] == 'white':
-                color = '#000000'
+            if color:
+                color = color
             else:
-                color = '#FFFFFF'
+                if self.app.defaults['global_theme'] == 'white':
+                    color = '#000000'
+                else:
+                    color = '#FFFFFF'
 
             if self.big_cursor is False:
                 try:
@@ -421,10 +429,11 @@ class PlotCanvasLegacy(QtCore.QObject):
                     # The size of the cursor is multiplied by 1.65 because that value made the cursor similar with the
                     # one in the OpenGL(3D) graphic engine
                     pointer_size = int(float(self.app.defaults["global_cursor_size"] ) * 1.65)
-                    elements = self.axes.plot(x, y, '+', color=color, ms=pointer_size, mew=1, animated=True)
+                    elements = self.axes.plot(x, y, '+', color=color, ms=pointer_size,
+                                              mew=self.app.defaults["global_cursor_width"], animated=True)
                     for el in elements:
                         self.axes.draw_artist(el)
-                except Exception as e:
+                except Exception:
                     # this happen at app initialization since self.app.geo_editor does not exist yet
                     # I could reshuffle the object instantiating order but what's the point?
                     # I could crash something else and that's pythonic, too
@@ -439,7 +448,10 @@ class PlotCanvasLegacy(QtCore.QObject):
     def clear_cursor(self, state):
 
         if state is True:
-            self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1])
+            if self.app.defaults["global_cursor_color_enabled"] is True:
+                self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1], color=self.app.cursor_color_3D)
+            else:
+                self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1])
         else:
             if self.big_cursor is True:
                 self.ch_line.remove()
@@ -784,7 +796,10 @@ class PlotCanvasLegacy(QtCore.QObject):
             self.panning = False
 
             # And update the cursor
-            self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1])
+            if self.app.defaults["global_cursor_color_enabled"] is True:
+                self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1], color=self.app.cursor_color_3D)
+            else:
+                self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1])
 
     def on_mouse_move(self, event):
         """
@@ -818,8 +833,10 @@ class PlotCanvasLegacy(QtCore.QObject):
             # #### Temporary place-holder for cached update #####
             self.update_screen_request.emit([0, 0, 0, 0, 0])
 
-        self.draw_cursor(x_pos=x, y_pos=y)
-
+        if self.app.defaults["global_cursor_color_enabled"] is True:
+            self.draw_cursor(x_pos=x, y_pos=y, color=self.app.cursor_color_3D)
+        else:
+            self.draw_cursor(x_pos=x, y_pos=y)
         # self.canvas.blit(self.axes.bbox)
 
     def translate_coords(self, position):
@@ -891,6 +908,7 @@ class FakeCursor(QtCore.QObject):
 
     def set_data(self, pos, **kwargs):
         """Internal event handler to draw the cursor when the mouse moves."""
+        return
 
 
 class ShapeCollectionLegacy:

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 600 - 325
flatcamGUI/PreferencesUI.py


+ 2 - 2
flatcamGUI/VisPyPatches.py

@@ -50,7 +50,7 @@ def apply_patches():
         try:
             self._update_child_widget_dim()
         except Exception as e:
-            print(e)
+            print("VisPyPatches.apply_patches._update_clipper() -> %s" % str(e))
 
     Grid._prepare_draw = _prepare_draw
     Grid._update_clipper = _update_clipper
@@ -72,7 +72,7 @@ def apply_patches():
 
         if GL:
             GL.glDisable(GL.GL_LINE_SMOOTH)
-            GL.glLineWidth(1.0)
+            GL.glLineWidth(2.0)
 
         if self._changed['pos']:
             self.pos_buf.set_data(self._pos)

+ 90 - 67
flatcamParsers/ParseGerber.py

@@ -437,18 +437,20 @@ class Gerber(Geometry):
                 gline = gline.strip(' \r\n')
                 # log.debug("Line=%3s %s" % (line_num, gline))
 
-                # ###################
-                # Ignored lines #####
-                # Comments      #####
-                # ###################
+                # ###############################################################
+                # ################   Ignored lines   ############################
+                # ################     Comments      ############################
+                # ###############################################################
                 match = self.comm_re.search(gline)
                 if match:
                     continue
 
-                # Polarity change ###### ##
-                # Example: %LPD*% or %LPC*%
-                # If polarity changes, creates geometry from current
-                # buffer, then adds or subtracts accordingly.
+                # ###############################################################
+                # ################  Polarity change #############################
+                # ########   Example: %LPD*% or %LPC*%        ###################
+                # ########   If polarity changes, creates geometry from current #
+                # ########    buffer, then adds or subtracts accordingly.       #
+                # ###############################################################
                 match = self.lpol_re.search(gline)
                 if match:
                     new_polarity = match.group(1)
@@ -491,11 +493,9 @@ class Gerber(Geometry):
                     # TODO: Remove when bug fixed
                     if len(poly_buffer) > 0:
                         if current_polarity == 'D':
-                            # self.follow_geometry = self.follow_geometry.union(cascaded_union(follow_buffer))
                             self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
 
                         else:
-                            # self.follow_geometry = self.follow_geometry.difference(cascaded_union(follow_buffer))
                             self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
 
                         # follow_buffer = []
@@ -504,11 +504,11 @@ class Gerber(Geometry):
                     current_polarity = new_polarity
                     continue
 
-                # ############################################################# ##
-                # Number format ############################################### ##
-                # Example: %FSLAX24Y24*%
-                # ############################################################# ##
-                # TODO: This is ignoring most of the format. Implement the rest.
+                # ################################################################
+                # #####################  Number format ###########################
+                # #####################  Example: %FSLAX24Y24*%  #################
+                # ################################################################
+
                 match = self.fmt_re.search(gline)
                 if match:
                     absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
@@ -524,8 +524,10 @@ class Gerber(Geometry):
                     log.debug("Gerber format found. Coordinates type = %s (Absolute or Relative)" % absolute)
                     continue
 
-                # ## Mode (IN/MM)
-                # Example: %MOIN*%
+                # ################################################################
+                # ######################## Mode (IN/MM)    #######################
+                # #####################    Example: %MOIN*%  #####################
+                # ################################################################
                 match = self.mode_re.search(gline)
                 if match:
                     self.units = match.group(1)
@@ -535,9 +537,9 @@ class Gerber(Geometry):
                     self.conversion_done = True
                     continue
 
-                # ############################################################# ##
-                # Combined Number format and Mode --- Allegro does this ####### ##
-                # ############################################################# ##
+                # ################################################################
+                # Combined Number format and Mode --- Allegro does this ##########
+                # ################################################################
                 match = self.fmt_re_alt.search(gline)
                 if match:
                     absolute = {'A': 'Absolute', 'I': 'Relative'}[match.group(2)]
@@ -558,9 +560,9 @@ class Gerber(Geometry):
                     self.conversion_done = True
                     continue
 
-                # ############################################################# ##
-                # Search for OrCAD way for having Number format
-                # ############################################################# ##
+                # ################################################################
+                # ####     Search for OrCAD way for having Number format  ########
+                # ################################################################
                 match = self.fmt_re_orcad.search(gline)
                 if match:
                     if match.group(1) is not None:
@@ -587,9 +589,9 @@ class Gerber(Geometry):
                         self.conversion_done = True
                         continue
 
-                # ############################################################# ##
-                # Units (G70/1) OBSOLETE
-                # ############################################################# ##
+                # ################################################################
+                # ############     Units (G70/1) OBSOLETE   ######################
+                # ################################################################
                 match = self.units_re.search(gline)
                 if match:
                     obs_gerber_units = {'0': 'IN', '1': 'MM'}[match.group(1)]
@@ -599,21 +601,21 @@ class Gerber(Geometry):
                     self.conversion_done = True
                     continue
 
-                # ############################################################# ##
-                # Absolute/relative coordinates G90/1 OBSOLETE ######## ##
-                # ##################################################### ##
+                # ################################################################
+                # #####   Absolute/relative coordinates G90/1 OBSOLETE ###########
+                # ################################################################
                 match = self.absrel_re.search(gline)
                 if match:
                     absolute = {'0': "Absolute", '1': "Relative"}[match.group(1)]
                     log.warning("Gerber obsolete coordinates type found = %s (Absolute or Relative) " % absolute)
                     continue
 
-                # ############################################################# ##
-                # Aperture Macros ##################################### ##
+                # ################################################################
+                # Aperture Macros ################################################
                 # Having this at the beginning will slow things down
                 # but macros can have complicated statements than could
                 # be caught by other patterns.
-                # ############################################################# ##
+                # ################################################################
                 if current_macro is None:  # No macro started yet
                     match = self.am1_re.search(gline)
                     # Start macro if match, else not an AM, carry on.
@@ -640,18 +642,20 @@ class Gerber(Geometry):
                         self.aperture_macros[current_macro].append(gline)
                     continue
 
-                # ## Aperture definitions %ADD...
+                # ################################################################
+                # ##############   Aperture definitions %ADD...  #################
+                # ################################################################
                 match = self.ad_re.search(gline)
                 if match:
                     # log.info("Found aperture definition. Line %d: %s" % (line_num, gline))
                     self.aperture_parse(match.group(1), match.group(2), match.group(3))
                     continue
 
-                # ############################################################# ##
-                # Operation code alone ###################### ##
-                # Operation code alone, usually just D03 (Flash)
+                # ################################################################
+                # ################  Operation code alone #########################
+                # ###########   Operation code alone, usually just D03 (Flash) ###
                 # self.opcode_re = re.compile(r'^D0?([123])\*$')
-                # ############################################################# ##
+                # ################################################################
                 match = self.opcode_re.search(gline)
                 if match:
                     current_operation_code = int(match.group(1))
@@ -690,10 +694,10 @@ class Gerber(Geometry):
 
                     continue
 
-                # ############################################################# ##
-                # Tool/aperture change
-                # Example: D12*
-                # ############################################################# ##
+                # ################################################################
+                # ################  Tool/aperture change  ########################
+                # ################  Example: D12*         ########################
+                # ################################################################
                 match = self.tool_re.search(gline)
                 if match:
                     current_aperture = match.group(1)
@@ -740,12 +744,11 @@ class Gerber(Geometry):
                             self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
 
                             path = [path[-1]]
-
                     continue
 
-                # ############################################################# ##
-                # G36* - Begin region
-                # ############################################################# ##
+                # ################################################################
+                # ################  G36* - Begin region   ########################
+                # ################################################################
                 if self.regionon_re.search(gline):
                     if len(path) > 1:
                         # Take care of what is left in the path
@@ -780,9 +783,9 @@ class Gerber(Geometry):
                     making_region = True
                     continue
 
-                # ############################################################# ##
-                # G37* - End region
-                # ############################################################# ##
+                # ################################################################
+                # ################  G37* - End region     ########################
+                # ################################################################
                 if self.regionoff_re.search(gline):
                     making_region = False
 
@@ -830,20 +833,27 @@ class Gerber(Geometry):
 
                     # --- Buffered ---
                     geo_dict = dict()
-                    region_f = Polygon(path).exterior
+                    if current_aperture in self.apertures:
+                        buff_value = float(self.apertures[current_aperture]['size']) / 2.0
+                        # region_geo = Polygon(path).buffer(buff_value, int(self.steps_per_circle))
+                        region_geo = Polygon(path)  # Sprint Layout Gerbers with ground fill are crashed with above
+                    else:
+                        region_geo = Polygon(path)
+
+                    region_f = region_geo.exterior
                     if not region_f.is_empty:
                         follow_buffer.append(region_f)
                         geo_dict['follow'] = region_f
 
-                    region_s = Polygon(path)
+                    region_s = region_geo
                     if not region_s.is_valid:
-                        region_s = region_s.buffer(0, int(self.steps_per_circle / 4))
-
+                        region_s = region_s.buffer(0, int(self.steps_per_circle))
                     if not region_s.is_empty:
                         if self.app.defaults['gerber_simplification']:
                             poly_buffer.append(region_s.simplify(s_tol))
                         else:
                             poly_buffer.append(region_s)
+
                         if self.is_lpc is True:
                             geo_dict['clear'] = region_s
                         else:
@@ -855,18 +865,22 @@ class Gerber(Geometry):
                     path = [[current_x, current_y]]  # Start new path
                     continue
 
-                # ## G01/2/3* - Interpolation mode change
-                # Can occur along with coordinates and operation code but
-                # sometimes by itself (handled here).
-                # Example: G01*
+                # ################################################################
+                # ################  G01/2/3* - Interpolation mode change #########
+                # ####  Can occur along with coordinates and operation code but ##
+                # ####  sometimes by itself (handled here).  #####################
+                # ####  Example: G01*                        #####################
+                # ################################################################
                 match = self.interp_re.search(gline)
                 if match:
                     current_interpolation_mode = int(match.group(1))
                     continue
 
-                # ## G01 - Linear interpolation plus flashes
-                # Operation code (D0x) missing is deprecated... oh well I will support it.
+                # ################################################################
+                # ######### G01 - Linear interpolation plus flashes  #############
+                # ######### Operation code (D0x) missing is deprecated   #########
                 # REGEX: r'^(?:G0?(1))?(?:X(-?\d+))?(?:Y(-?\d+))?(?:D0([123]))?\*$'
+                # ################################################################
                 match = self.lin_re.search(gline)
                 if match:
                     # Dxx alone?
@@ -1147,7 +1161,9 @@ class Gerber(Geometry):
                     # log.debug("Line_number=%3s X=%s Y=%s (%s)" % (line_num, linear_x, linear_y, gline))
                     continue
 
-                # ## G74/75* - Single or multiple quadrant arcs
+                # ################################################################
+                # ######### G74/75* - Single or multiple quadrant arcs  ##########
+                # ################################################################
                 match = self.quad_re.search(gline)
                 if match:
                     if match.group(1) == '4':
@@ -1156,9 +1172,12 @@ class Gerber(Geometry):
                         quadrant_mode = 'MULTI'
                     continue
 
-                # ## G02/3 - Circular interpolation
-                # 2-clockwise, 3-counterclockwise
-                # Ex. format: G03 X0 Y50 I-50 J0 where the X, Y coords are the coords of the End Point
+                # ################################################################
+                # ######### G02/3 - Circular interpolation   #####################
+                # ######### 2-clockwise, 3-counterclockwise  #####################
+                # ######### Ex. format: G03 X0 Y50 I-50 J0 where the     #########
+                # ######### X, Y coords are the coords of the End Point  #########
+                # ################################################################
                 match = self.circ_re.search(gline)
                 if match:
                     arcdir = [None, None, "cw", "ccw"]
@@ -1339,12 +1358,16 @@ class Gerber(Geometry):
                         else:
                             log.warning("Invalid arc in line %d." % line_num)
 
-                # ## EOF
+                # ################################################################
+                # ######### EOF - END OF FILE ####################################
+                # ################################################################
                 match = self.eof_re.search(gline)
                 if match:
                     continue
 
-                # ## Line did not match any pattern. Warn user.
+                # ################################################################
+                # ######### Line did not match any pattern. Warn user.  ##########
+                # ################################################################
                 log.warning("Line ignored (%d): %s" % (line_num, gline))
 
             if len(path) > 1:
@@ -1433,16 +1456,16 @@ class Gerber(Geometry):
 
                     self.solid_geometry = final_poly
 
-                # FIX for issue #347 - Sprint Layout generate strange Gerber files when the copper pour is enabled
+                # FIX for issue #347 - Sprint Layout generate Gerber files when the copper pour is enabled
                 # it use a filled bounding box polygon to which add clear polygons (negative) to isolate the copper
                 # features
                 if self.app.defaults['gerber_extra_buffering']:
                     candidate_geo = list()
                     try:
                         for p in self.solid_geometry:
-                            candidate_geo.append(p.buffer(0.0000001))
+                            candidate_geo.append(p.buffer(-0.0000001))
                     except TypeError:
-                        candidate_geo.append(self.solid_geometry.buffer(0.0000001))
+                        candidate_geo.append(self.solid_geometry.buffer(-0.0000001))
                     self.solid_geometry = candidate_geo
 
                 # try:

+ 1 - 0
flatcamTools/ToolCopperThieving.py

@@ -902,6 +902,7 @@ class ToolCopperThieving(FlatCAMTool):
 
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
                                          symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         # update the positions on status bar

+ 1 - 0
flatcamTools/ToolDistance.py

@@ -396,6 +396,7 @@ class Distance(FlatCAMTool):
                 # Update cursor
                 self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
                                              symbol='++', edge_color=self.app.cursor_color_3D,
+                                             edge_width=self.app.defaults["global_cursor_width"],
                                              size=self.app.defaults["global_cursor_size"])
             else:
                 pos = (pos_canvas[0], pos_canvas[1])

+ 2 - 1
flatcamTools/ToolNonCopperClear.py

@@ -698,11 +698,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
             "paintcontour": self.app.defaults["tools_paintcontour"],
             "paintoverlap": self.app.defaults["tools_paintoverlap"],
 
-            "nccoverlap": self.app.defaults["tools_nccoverlap"],
             "nccmargin": self.app.defaults["tools_nccmargin"],
             "nccmethod": self.app.defaults["tools_nccmethod"],
             "nccconnect": self.app.defaults["tools_nccconnect"],
             "ncccontour": self.app.defaults["tools_ncccontour"],
+            "nccoverlap": self.app.defaults["tools_nccoverlap"],
             "nccrest": self.app.defaults["tools_nccrest"]
         })
 
@@ -1349,6 +1349,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
 
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
                                          symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         # update the positions on status bar

+ 1 - 0
flatcamTools/ToolPaint.py

@@ -1290,6 +1290,7 @@ class ToolPaint(FlatCAMTool, Gerber):
 
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
                                          symbol='++', edge_color=self.app.cursor_color_3D,
+                                         edge_width=self.app.defaults["global_cursor_width"],
                                          size=self.app.defaults["global_cursor_size"])
 
         # update the positions on status bar

+ 41 - 46
flatcamTools/ToolPanelize.py

@@ -608,22 +608,22 @@ class Panelize(FlatCAMTool):
                         if panel_obj.multigeo is True:
                             for tool in panel_obj.tools:
                                 try:
-                                    for pol in panel_obj.tools[tool]['solid_geometry']:
-                                        geo_len += 1
+                                    geo_len += len(panel_obj.tools[tool]['solid_geometry'])
                                 except TypeError:
-                                    geo_len = 1
+                                    geo_len += 1
                         else:
                             try:
-                                for pol in panel_obj.solid_geometry:
-                                    geo_len += 1
+                                geo_len = len(panel_obj.solid_geometry)
                             except TypeError:
                                 geo_len = 1
                     elif isinstance(panel_obj, FlatCAMGerber):
                         for ap in panel_obj.apertures:
-                            for elem in panel_obj.apertures[ap]['geometry']:
-                                geo_len += 1
+                            if 'geometry' in panel_obj.apertures[ap]:
+                                try:
+                                    geo_len += len(panel_obj.apertures[ap]['geometry'])
+                                except TypeError:
+                                    geo_len += 1
 
-                    self.app.progress.emit(0)
                     element = 0
                     for row in range(rows):
                         currentx = 0.0
@@ -724,49 +724,48 @@ class Panelize(FlatCAMTool):
                                     if self.app.abort_flag:
                                         # graceful abort requested by the user
                                         raise FlatCAMApp.GracefulException
+                                    if 'geometry' in panel_obj.apertures[apid]:
+                                        try:
+                                            # calculate the number of polygons
+                                            geo_len = len(panel_obj.apertures[apid]['geometry'])
+                                        except TypeError:
+                                            geo_len = 1
+                                        pol_nr = 0
+                                        for el in panel_obj.apertures[apid]['geometry']:
+                                            if self.app.abort_flag:
+                                                # graceful abort requested by the user
+                                                raise FlatCAMApp.GracefulException
 
-                                    try:
-                                        # calculate the number of polygons
-                                        geo_len = len(panel_obj.apertures[apid]['geometry'])
-                                    except TypeError:
-                                        geo_len = 1
-                                    pol_nr = 0
-                                    for el in panel_obj.apertures[apid]['geometry']:
-                                        if self.app.abort_flag:
-                                            # graceful abort requested by the user
-                                            raise FlatCAMApp.GracefulException
-
-                                        new_el = dict()
-                                        if 'solid' in el:
-                                            geo_aper = translate_recursion(el['solid'])
-                                            new_el['solid'] = geo_aper
+                                            new_el = dict()
+                                            if 'solid' in el:
+                                                geo_aper = translate_recursion(el['solid'])
+                                                new_el['solid'] = geo_aper
 
-                                        if 'clear' in el:
-                                            geo_aper = translate_recursion(el['clear'])
-                                            new_el['clear'] = geo_aper
+                                            if 'clear' in el:
+                                                geo_aper = translate_recursion(el['clear'])
+                                                new_el['clear'] = geo_aper
 
-                                        if 'follow' in el:
-                                            geo_aper = translate_recursion(el['follow'])
-                                            new_el['follow'] = geo_aper
+                                            if 'follow' in el:
+                                                geo_aper = translate_recursion(el['follow'])
+                                                new_el['follow'] = geo_aper
 
-                                        obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
+                                            obj_fin.apertures[apid]['geometry'].append(deepcopy(new_el))
 
-                                        pol_nr += 1
-                                        disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
+                                            pol_nr += 1
+                                            disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
 
-                                        if old_disp_number < disp_number <= 100:
-                                            self.app.proc_container.update_view_text(' %s: %d %d%%' %
-                                                                                     (_("Copy"),
-                                                                                      int(element),
-                                                                                      disp_number))
-                                            old_disp_number = disp_number
+                                            if old_disp_number < disp_number <= 100:
+                                                self.app.proc_container.update_view_text(' %s: %d %d%%' %
+                                                                                         (_("Copy"),
+                                                                                          int(element),
+                                                                                          disp_number))
+                                                old_disp_number = disp_number
 
                             currentx += lenghtx
                         currenty += lenghty
 
                     if panel_type == 'gerber':
-                        self.app.inform.emit('%s' %
-                                             _("Generating panel ... Adding the Gerber code."))
+                        self.app.inform.emit('%s' % _("Generating panel ... Adding the Gerber code."))
                         obj_fin.source_file = self.app.export_gerber(obj_name=self.outname, filename=None,
                                                                      local_use=obj_fin, use_thread=False)
 
@@ -777,15 +776,11 @@ class Panelize(FlatCAMTool):
                     # app_obj.log.debug("Finished creating a cascaded union for the panel.")
                     self.app.proc_container.update_view_text('')
 
-                self.app.inform.emit('%s: %d' %
-                                     (_("Generating panel... Spawning copies"), (int(rows * columns))))
+                self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
                 if isinstance(panel_obj, FlatCAMExcellon):
-                    self.app.progress.emit(50)
                     self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
                 else:
-                    self.app.progress.emit(50)
-                    self.app.new_object(panel_type, self.outname, job_init_geometry,
-                                        plot=True, autoselected=True)
+                    self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)
 
         if self.constrain_flag is False:
             self.app.inform.emit('[success] %s' % _("Panel done..."))

BIN
locale/de/LC_MESSAGES/strings.mo


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


BIN
locale/en/LC_MESSAGES/strings.mo


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


BIN
locale/es/LC_MESSAGES/strings.mo


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


BIN
locale/fr/LC_MESSAGES/strings.mo


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


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


BIN
share/clear_plot32.png


BIN
share/copy32.png


BIN
share/cutpath16.png


BIN
share/cutpath24.png


BIN
share/cutpath32.png


BIN
share/dark_resources/about32.png


BIN
share/dark_resources/active.gif


BIN
share/dark_resources/active_2.gif


BIN
share/dark_resources/active_2_static.png


BIN
share/dark_resources/active_3.gif


BIN
share/dark_resources/active_3_static.png


BIN
share/dark_resources/active_4.gif


BIN
share/dark_resources/active_4_static.png


BIN
share/dark_resources/active_static.png


BIN
share/dark_resources/addarray16.png


BIN
share/dark_resources/addarray20.png


BIN
share/dark_resources/addarray32.png


BIN
share/dark_resources/aero.png


BIN
share/dark_resources/aero_arc.png


BIN
share/dark_resources/aero_array.png


BIN
share/dark_resources/aero_buffer.png


BIN
share/dark_resources/aero_circle.png


BIN
share/dark_resources/aero_circle_geo.png


BIN
share/dark_resources/aero_disc.png


BIN
share/dark_resources/aero_drill.png


BIN
share/dark_resources/aero_drill_array.png


BIN
share/dark_resources/aero_path1.png


BIN
share/dark_resources/aero_path2.png


BIN
share/dark_resources/aero_path3.png


BIN
share/dark_resources/aero_path4.png


BIN
share/dark_resources/aero_path5.png


BIN
share/dark_resources/aero_semidisc.png


BIN
share/dark_resources/aero_slot.png


BIN
share/dark_resources/aero_text.png


BIN
share/dark_resources/align_center32.png


BIN
share/dark_resources/align_justify32.png


BIN
share/dark_resources/align_left32.png


BIN
share/dark_resources/align_right32.png


BIN
share/dark_resources/aperture16.png


BIN
share/dark_resources/aperture32.png


BIN
share/dark_resources/arc16.png


BIN
share/dark_resources/arc24.png


BIN
share/dark_resources/arc32.png


BIN
share/dark_resources/axis32.png


BIN
share/dark_resources/backup24.png


BIN
share/dark_resources/backup_export24.png


BIN
share/dark_resources/backup_import24.png


BIN
share/dark_resources/blocked16.png


BIN
share/dark_resources/blue32.png


BIN
share/dark_resources/bluelight12.png


BIN
share/dark_resources/bold32.png


BIN
share/dark_resources/bookmarks16.png


BIN
share/dark_resources/bookmarks32.png


BIN
share/dark_resources/brown32.png


BIN
share/dark_resources/buffer16-2.png


BIN
share/dark_resources/buffer16.png


BIN
share/dark_resources/buffer20.png


BIN
share/dark_resources/buffer24.png


BIN
share/dark_resources/bug16.png


BIN
share/dark_resources/bug32.png


BIN
share/dark_resources/calculator16.png


BIN
share/dark_resources/calculator24.png


BIN
share/dark_resources/calibrate_16.png


BIN
share/dark_resources/calibrate_32.png


BIN
share/dark_resources/cancel_edit16.png


BIN
share/dark_resources/cancel_edit32.png


BIN
share/dark_resources/circle32.png


BIN
share/dark_resources/clear_plot16.png


BIN
share/dark_resources/clear_plot32.png


BIN
share/dark_resources/close_edit_file16.png


BIN
share/dark_resources/close_edit_file32.png


BIN
share/dark_resources/cnc16.png


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