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

- 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)
- 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

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

+ 38 - 18
FlatCAMApp.py

@@ -338,13 +338,13 @@ class App(QtCore.QObject):
             os.makedirs(self.preprocessorpaths)
             App.log.debug('Created preprocessors folder: ' + self.preprocessorpaths)
 
-        # create tools_db.FlatConfig file if there is none
+        # create tools_db.FlatDB file if there is none
         try:
-            f = open(self.data_path + '/tools_db.FlatConfig')
+            f = open(self.data_path + '/tools_db.FlatDB')
             f.close()
         except IOError:
-            App.log.debug('Creating empty tool_db.FlatConfig')
-            f = open(self.data_path + '/tools_db.FlatConfig', 'w')
+            App.log.debug('Creating empty tool_db.FlatDB')
+            f = open(self.data_path + '/tools_db.FlatDB', 'w')
             json.dump({}, f)
             f.close()
 
@@ -513,6 +513,8 @@ class App(QtCore.QObject):
             "global_cursor_type": "small",
             "global_cursor_size": 20,
             "global_cursor_width": 2,
+            "global_cursor_color": '#000000',
+            "global_cursor_color_enabled": False,
 
             # Gerber General
             "gerber_plot": True,
@@ -990,10 +992,14 @@ class App(QtCore.QObject):
         self.current_defaults = dict()
         self.current_defaults.update(self.defaults)
 
-        # #############################################################################
-        # ##################### CREATE MULTIPROCESSING POOL ###########################
-        # #############################################################################
+        # ##########################################################################
+        # ##################### SETUP OBJECT CLASSES ###############################
+        # ##########################################################################
+        self.setup_obj_classes()
 
+        # ##########################################################################
+        # ##################### CREATE MULTIPROCESSING POOL ########################
+        # ##########################################################################
         self.pool = Pool()
 
         # ##########################################################################
@@ -1049,10 +1055,13 @@ class App(QtCore.QObject):
         else:
             theme = 'white'
 
-        if theme == 'white':
-            self.cursor_color_3D = 'black'
+        if self.defaults["global_cursor_color_enabled"]:
+            self.cursor_color_3D = self.defaults["global_cursor_color"]
         else:
-            self.cursor_color_3D = 'gray'
+            if theme == 'white':
+                self.cursor_color_3D = 'black'
+            else:
+                self.cursor_color_3D = 'gray'
 
         self.ui.geom_update[int, int, int, int, int].connect(self.save_geometry)
         self.ui.final_save.connect(self.final_save)
@@ -1084,8 +1093,6 @@ class App(QtCore.QObject):
 
             "global_version_check": self.ui.general_defaults_form.general_app_group.version_check_cb,
             "global_send_stats": self.ui.general_defaults_form.general_app_group.send_stats_cb,
-            "global_pan_button": self.ui.general_defaults_form.general_app_group.pan_button_radio,
-            "global_mselect_key": self.ui.general_defaults_form.general_app_group.mselect_radio,
 
             "global_worker_number": self.ui.general_defaults_form.general_app_group.worker_number_sb,
             "global_tolerance": self.ui.general_defaults_form.general_app_group.tol_entry,
@@ -1122,7 +1129,7 @@ class App(QtCore.QObject):
 
             "global_proj_item_color": self.ui.general_defaults_form.general_gui_group.proj_color_entry,
             "global_proj_item_dis_color": self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry,
-            "global_activity_icon": self.ui.general_defaults_form.general_gui_group.activity_combo,
+            "global_project_autohide": self.ui.general_defaults_form.general_gui_group.project_autohide_cb,
 
             # General GUI Settings
             "global_theme": self.ui.general_defaults_form.general_gui_set_group.theme_radio,
@@ -1132,12 +1139,17 @@ class App(QtCore.QObject):
             "global_systray_icon": self.ui.general_defaults_form.general_gui_set_group.systray_cb,
             "global_shell_at_startup": self.ui.general_defaults_form.general_gui_set_group.shell_startup_cb,
             "global_project_at_startup": self.ui.general_defaults_form.general_gui_set_group.project_startup_cb,
-            "global_project_autohide": self.ui.general_defaults_form.general_gui_set_group.project_autohide_cb,
-            "global_toggle_tooltips": self.ui.general_defaults_form.general_gui_set_group.toggle_tooltips_cb,
-            "global_delete_confirmation": self.ui.general_defaults_form.general_gui_set_group.delete_conf_cb,
             "global_cursor_type": self.ui.general_defaults_form.general_gui_set_group.cursor_radio,
             "global_cursor_size": self.ui.general_defaults_form.general_gui_set_group.cursor_size_entry,
             "global_cursor_width": self.ui.general_defaults_form.general_gui_set_group.cursor_width_entry,
+            "global_cursor_color_enabled": self.ui.general_defaults_form.general_gui_set_group.mouse_cursor_color_cb,
+            "global_cursor_color": self.ui.general_defaults_form.general_gui_set_group.mouse_cursor_entry,
+            "global_pan_button": self.ui.general_defaults_form.general_gui_set_group.pan_button_radio,
+            "global_mselect_key": self.ui.general_defaults_form.general_gui_set_group.mselect_radio,
+            "global_delete_confirmation": self.ui.general_defaults_form.general_gui_set_group.delete_conf_cb,
+
+            "global_toggle_tooltips": self.ui.general_defaults_form.general_gui_set_group.toggle_tooltips_cb,
+            "global_activity_icon": self.ui.general_defaults_form.general_gui_set_group.activity_combo,
 
             # Gerber General
             "gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
@@ -2212,7 +2224,6 @@ class App(QtCore.QObject):
             self.ui.splitter.setSizes([0, 1])
 
         # Sets up FlatCAMObj, FCProcess and FCProcessContainer.
-        self.setup_obj_classes()
         self.setup_component_editor()
 
         # #####################################################################################
@@ -6326,12 +6337,20 @@ class App(QtCore.QObject):
             "background-color:%s;"
             "border-color: dimgray" % str(self.defaults['global_proj_item_color'])[:7])
 
+        # Init Project Disabled Items color
         self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry.set_value(
             self.defaults['global_proj_item_dis_color'])
         self.ui.general_defaults_form.general_gui_group.proj_color_dis_button.setStyleSheet(
             "background-color:%s;"
             "border-color: dimgray" % str(self.defaults['global_proj_item_dis_color'])[:7])
 
+        # Init Project Disabled Items color
+        self.ui.general_defaults_form.general_gui_set_group.mouse_cursor_entry.set_value(
+            self.defaults['global_cursor_color'])
+        self.ui.general_defaults_form.general_gui_set_group.mouse_cursor_button.setStyleSheet(
+            "background-color:%s;"
+            "border-color: dimgray" % str(self.defaults['global_cursor_color'])[:7])
+
         # Init the Annotation CNC Job color
         self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.set_value(
             self.defaults['cncjob_annotation_fontcolor'])
@@ -6766,7 +6785,7 @@ class App(QtCore.QObject):
             "background-color:%s" % str(proj_color.name()))
 
         new_val_sel = str(proj_color.name())
-        self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry.set_value(new_val_sel)
+        self.ui.general_defaults_form.general_gui_set_group.proj_color_dis_entry.set_value(new_val_sel)
         self.defaults['global_proj_item_dis_color'] = new_val_sel
 
     def on_annotation_fontcolor_entry(self):
@@ -12155,6 +12174,7 @@ class App(QtCore.QObject):
         CNCjob.app = self
         FCProcess.app = self
         FCProcessContainer.app = self
+        OptionsGroupUI.app = self
 
     def version_check(self):
         """

+ 90 - 77
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:
@@ -1161,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()):

+ 11 - 0
README.md

@@ -9,6 +9,16 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+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
+
 25.12.2019
 
 - fixed an issue in old default file detection and in saving the factory defaults file
@@ -16,6 +26,7 @@ CAD program, and create G-Code for Isolation routing.
 - 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
 

+ 108 - 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 = []
@@ -3710,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:
@@ -3743,6 +3818,14 @@ class FlatCAMExcEditor(QtCore.QObject):
                                      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
 

+ 115 - 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.

+ 55 - 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 = []

+ 125 - 128
flatcamGUI/FlatCAMGUI.py

@@ -3151,15 +3151,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
@@ -3197,6 +3194,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:
@@ -3230,16 +3246,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')
@@ -3248,10 +3254,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()
@@ -3309,9 +3311,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()
@@ -3341,7 +3340,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':
@@ -3569,7 +3567,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':
@@ -3580,15 +3577,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
 
@@ -3645,44 +3639,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
@@ -3694,69 +3650,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
@@ -3777,15 +3676,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

+ 372 - 211
flatcamGUI/PreferencesUI.py

@@ -26,6 +26,8 @@ else:
 
 
 class OptionsGroupUI(QtWidgets.QGroupBox):
+    app = None
+
     def __init__(self, title, parent=None):
         # QtGui.QGroupBox.__init__(self, title, parent=parent)
         super(OptionsGroupUI, self).__init__()
@@ -322,11 +324,17 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("GUI Preferences")))
         self.decimals = decimals
         
-        # Create a form layout for the Application general settings
-        self.form_box = QtWidgets.QFormLayout()
+        # Create a grid layout for the Application general settings
+        grid0 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid0)
+        grid0.setColumnStretch(0, 0)
+        grid0.setColumnStretch(1, 1)
+
+        self.grid_label = QtWidgets.QLabel('<b>%s</b>' % _('Grid Settings'))
+        grid0.addWidget(self.grid_label, 0, 0, 1, 2)
 
         # Grid X Entry
-        self.gridx_label = QtWidgets.QLabel('%s:' % _('Grid X value'))
+        self.gridx_label = QtWidgets.QLabel('%s:' % _('X value'))
         self.gridx_label.setToolTip(
            _("This is the Grid snap value on X axis.")
         )
@@ -334,8 +342,11 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.gridx_entry.set_precision(self.decimals)
         self.gridx_entry.setSingleStep(0.1)
 
+        grid0.addWidget(self.gridx_label, 1, 0)
+        grid0.addWidget(self.gridx_entry, 1, 1)
+
         # Grid Y Entry
-        self.gridy_label = QtWidgets.QLabel('%s:' % _('Grid Y value'))
+        self.gridy_label = QtWidgets.QLabel('%s:' % _('Y value'))
         self.gridy_label.setToolTip(
             _("This is the Grid snap value on Y axis.")
         )
@@ -343,6 +354,9 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.gridy_entry.set_precision(self.decimals)
         self.gridy_entry.setSingleStep(0.1)
 
+        grid0.addWidget(self.gridy_label, 2, 0)
+        grid0.addWidget(self.gridy_entry, 2, 1)
+
         # Snap Max Entry
         self.snap_max_label = QtWidgets.QLabel('%s:' % _('Snap Max'))
         self.snap_max_label.setToolTip(_("Max. magnet distance"))
@@ -350,20 +364,36 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.snap_max_dist_entry.set_precision(self.decimals)
         self.snap_max_dist_entry.setSingleStep(0.1)
 
+        grid0.addWidget(self.snap_max_label, 3, 0)
+        grid0.addWidget(self.snap_max_dist_entry, 3, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 4, 0, 1, 2)
+
         # Workspace
-        self.workspace_lbl = QtWidgets.QLabel('%s:' % _('Workspace'))
-        self.workspace_lbl.setToolTip(
+        self.workspace_label = QtWidgets.QLabel('<b>%s</b>' % _('Workspace Settings'))
+        grid0.addWidget(self.workspace_label, 5, 0, 1, 2)
+
+        self.workspace_cb = FCCheckBox('%s' % _('Active'))
+        self.workspace_cb.setToolTip(
            _("Draw a delimiting rectangle on canvas.\n"
              "The purpose is to illustrate the limits for our work.")
         )
-        self.workspace_type_lbl = QtWidgets.QLabel('%s:' % _('Wk. size'))
+
+        grid0.addWidget(self.workspace_cb, 6, 0, 1, 2)
+
+        self.workspace_type_lbl = QtWidgets.QLabel('%s:' % _('Size'))
         self.workspace_type_lbl.setToolTip(
            _("Select the type of rectangle to be used on canvas,\n"
              "as valid workspace.")
         )
-        self.workspace_cb = FCCheckBox()
         self.wk_cb = FCComboBox()
 
+        grid0.addWidget(self.workspace_type_lbl, 7, 0)
+        grid0.addWidget(self.wk_cb, 7, 1)
+
         self.pagesize = dict()
         self.pagesize.update(
             {
@@ -420,13 +450,9 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         page_size_list = list(self.pagesize.keys())
 
         self.wk_cb.addItems(page_size_list)
-        # self.wk_cb.addItem('A4P')
-        # self.wk_cb.addItem('A4L')
-        # self.wk_cb.addItem('A3P')
-        # self.wk_cb.addItem('A3L')
 
         # Page orientation
-        self.wk_orientation_label = QtWidgets.QLabel('%s:' % _("Wk. Orientation"))
+        self.wk_orientation_label = QtWidgets.QLabel('%s:' % _("Orientation"))
         self.wk_orientation_label.setToolTip(_("Can be:\n"
                                                "- Portrait\n"
                                                "- Landscape"))
@@ -443,12 +469,40 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
                                             self.wk_orientation_radio
                                         ])
 
+        grid0.addWidget(self.wk_orientation_label, 8, 0)
+        grid0.addWidget(self.wk_orientation_radio, 8, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 9, 0, 1, 2)
+
+        self.gerber_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Gerber Object Color'))
+        grid0.addWidget(self.gerber_color_label, 10, 0, 1, 2)
+
+        # Plot Line Color
+        self.pl_color_label = QtWidgets.QLabel('%s:' % _('Outline'))
+        self.pl_color_label.setToolTip(
+           _("Set the line color for plotted objects.")
+        )
+        self.pl_color_entry = FCEntry()
+        self.pl_color_button = QtWidgets.QPushButton()
+        self.pl_color_button.setFixedSize(15, 15)
+
+        self.form_box_child_2 = QtWidgets.QHBoxLayout()
+        self.form_box_child_2.addWidget(self.pl_color_entry)
+        self.form_box_child_2.addWidget(self.pl_color_button)
+        self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        grid0.addWidget(self.pl_color_label, 11, 0)
+        grid0.addLayout(self.form_box_child_2, 11, 1)
+
         # Plot Fill Color
-        self.pf_color_label = QtWidgets.QLabel('%s:' % _('Plot Fill'))
+        self.pf_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
         self.pf_color_label.setToolTip(
-           _("Set the fill color for plotted objects.\n"
-             "First 6 digits are the color and the last 2\n"
-             "digits are for alpha (transparency) level.")
+            _("Set the fill color for plotted objects.\n"
+              "First 6 digits are the color and the last 2\n"
+              "digits are for alpha (transparency) level.")
         )
         self.pf_color_entry = FCEntry()
         self.pf_color_button = QtWidgets.QPushButton()
@@ -459,8 +513,11 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.form_box_child_1.addWidget(self.pf_color_button)
         self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
+        grid0.addWidget(self.pf_color_label, 12, 0)
+        grid0.addLayout(self.form_box_child_1, 12, 1)
+
         # Plot Fill Transparency Level
-        self.pf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha Level'))
+        self.pf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
         self.pf_alpha_label.setToolTip(
            _("Set the fill transparency for plotted objects.")
         )
@@ -473,26 +530,39 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.pf_color_alpha_spinner.setMinimumWidth(70)
         self.pf_color_alpha_spinner.set_range(0, 255)
 
-        self.form_box_child_2 = QtWidgets.QHBoxLayout()
-        self.form_box_child_2.addWidget(self.pf_color_alpha_slider)
-        self.form_box_child_2.addWidget(self.pf_color_alpha_spinner)
+        self.form_box_child_3 = QtWidgets.QHBoxLayout()
+        self.form_box_child_3.addWidget(self.pf_color_alpha_slider)
+        self.form_box_child_3.addWidget(self.pf_color_alpha_spinner)
 
-        # Plot Line Color
-        self.pl_color_label = QtWidgets.QLabel('%s:' % _('Plot Line'))
-        self.pl_color_label.setToolTip(
-           _("Set the line color for plotted objects.")
+        grid0.addWidget(self.pf_alpha_label, 13, 0)
+        grid0.addLayout(self.form_box_child_3, 13, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 14, 0, 1, 2)
+
+        # Plot Selection (left - right) Color
+        self.sel_lr_label = QtWidgets.QLabel('<b>%s</b>' % _('Object Left-Right Selection Color'))
+        grid0.addWidget(self.sel_lr_label, 15, 0, 1, 2)
+
+        self.sl_color_label = QtWidgets.QLabel('%s:' % _('Outline'))
+        self.sl_color_label.setToolTip(
+            _("Set the line color for the 'left to right' selection box.")
         )
-        self.pl_color_entry = FCEntry()
-        self.pl_color_button = QtWidgets.QPushButton()
-        self.pl_color_button.setFixedSize(15, 15)
+        self.sl_color_entry = FCEntry()
+        self.sl_color_button = QtWidgets.QPushButton()
+        self.sl_color_button.setFixedSize(15, 15)
 
-        self.form_box_child_3 = QtWidgets.QHBoxLayout()
-        self.form_box_child_3.addWidget(self.pl_color_entry)
-        self.form_box_child_3.addWidget(self.pl_color_button)
-        self.form_box_child_3.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        self.form_box_child_4 = QtWidgets.QHBoxLayout()
+        self.form_box_child_4.addWidget(self.sl_color_entry)
+        self.form_box_child_4.addWidget(self.sl_color_button)
+        self.form_box_child_4.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
-        # Plot Selection (left - right) Fill Color
-        self.sf_color_label = QtWidgets.QLabel('%s:' % _('Sel. Fill'))
+        grid0.addWidget(self.sl_color_label, 16, 0)
+        grid0.addLayout(self.form_box_child_4, 16, 1)
+
+        self.sf_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
         self.sf_color_label.setToolTip(
             _("Set the fill color for the selection box\n"
               "in case that the selection is done from left to right.\n"
@@ -503,13 +573,16 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.sf_color_button = QtWidgets.QPushButton()
         self.sf_color_button.setFixedSize(15, 15)
 
-        self.form_box_child_4 = QtWidgets.QHBoxLayout()
-        self.form_box_child_4.addWidget(self.sf_color_entry)
-        self.form_box_child_4.addWidget(self.sf_color_button)
-        self.form_box_child_4.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        self.form_box_child_5 = QtWidgets.QHBoxLayout()
+        self.form_box_child_5.addWidget(self.sf_color_entry)
+        self.form_box_child_5.addWidget(self.sf_color_button)
+        self.form_box_child_5.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        grid0.addWidget(self.sf_color_label, 17, 0)
+        grid0.addLayout(self.form_box_child_5, 17, 1)
 
         # Plot Selection (left - right) Fill Transparency Level
-        self.sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha Level'))
+        self.sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
         self.sf_alpha_label.setToolTip(
             _("Set the fill transparency for the 'left to right' selection box.")
         )
@@ -522,26 +595,41 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.sf_color_alpha_spinner.setMinimumWidth(70)
         self.sf_color_alpha_spinner.set_range(0, 255)
 
-        self.form_box_child_5 = QtWidgets.QHBoxLayout()
-        self.form_box_child_5.addWidget(self.sf_color_alpha_slider)
-        self.form_box_child_5.addWidget(self.sf_color_alpha_spinner)
+        self.form_box_child_6 = QtWidgets.QHBoxLayout()
+        self.form_box_child_6.addWidget(self.sf_color_alpha_slider)
+        self.form_box_child_6.addWidget(self.sf_color_alpha_spinner)
 
-        # Plot Selection (left - right) Line Color
-        self.sl_color_label = QtWidgets.QLabel('%s:' % _('Sel. Line'))
-        self.sl_color_label.setToolTip(
-            _("Set the line color for the 'left to right' selection box.")
+        grid0.addWidget(self.sf_alpha_label, 18, 0)
+        grid0.addLayout(self.form_box_child_6, 18, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 19, 0, 1, 2)
+
+        # Plot Selection (left - right) Color
+        self.sel_rl_label = QtWidgets.QLabel('<b>%s</b>' % _('Object Right-Left Selection Color'))
+        grid0.addWidget(self.sel_rl_label, 20, 0, 1, 2)
+
+        # Plot Selection (right - left) Line Color
+        self.alt_sl_color_label = QtWidgets.QLabel('%s:' % _('Outline'))
+        self.alt_sl_color_label.setToolTip(
+            _("Set the line color for the 'right to left' selection box.")
         )
-        self.sl_color_entry = FCEntry()
-        self.sl_color_button = QtWidgets.QPushButton()
-        self.sl_color_button.setFixedSize(15, 15)
+        self.alt_sl_color_entry = FCEntry()
+        self.alt_sl_color_button = QtWidgets.QPushButton()
+        self.alt_sl_color_button.setFixedSize(15, 15)
 
-        self.form_box_child_6 = QtWidgets.QHBoxLayout()
-        self.form_box_child_6.addWidget(self.sl_color_entry)
-        self.form_box_child_6.addWidget(self.sl_color_button)
-        self.form_box_child_6.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        self.form_box_child_7 = QtWidgets.QHBoxLayout()
+        self.form_box_child_7.addWidget(self.alt_sl_color_entry)
+        self.form_box_child_7.addWidget(self.alt_sl_color_button)
+        self.form_box_child_7.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        grid0.addWidget(self.alt_sl_color_label, 21, 0)
+        grid0.addLayout(self.form_box_child_7, 21, 1)
 
         # Plot Selection (right - left) Fill Color
-        self.alt_sf_color_label = QtWidgets.QLabel('%s:' % _('Sel2. Fill'))
+        self.alt_sf_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
         self.alt_sf_color_label.setToolTip(
             _("Set the fill color for the selection box\n"
               "in case that the selection is done from right to left.\n"
@@ -552,13 +640,16 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.alt_sf_color_button = QtWidgets.QPushButton()
         self.alt_sf_color_button.setFixedSize(15, 15)
 
-        self.form_box_child_7 = QtWidgets.QHBoxLayout()
-        self.form_box_child_7.addWidget(self.alt_sf_color_entry)
-        self.form_box_child_7.addWidget(self.alt_sf_color_button)
-        self.form_box_child_7.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        self.form_box_child_8 = QtWidgets.QHBoxLayout()
+        self.form_box_child_8.addWidget(self.alt_sf_color_entry)
+        self.form_box_child_8.addWidget(self.alt_sf_color_button)
+        self.form_box_child_8.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        grid0.addWidget(self.alt_sf_color_label, 22, 0)
+        grid0.addLayout(self.form_box_child_8, 22, 1)
 
         # Plot Selection (right - left) Fill Transparency Level
-        self.alt_sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha Level'))
+        self.alt_sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
         self.alt_sf_alpha_label.setToolTip(
             _("Set the fill transparency for selection 'right to left' box.")
         )
@@ -571,26 +662,27 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.alt_sf_color_alpha_spinner.setMinimumWidth(70)
         self.alt_sf_color_alpha_spinner.set_range(0, 255)
 
-        self.form_box_child_8 = QtWidgets.QHBoxLayout()
-        self.form_box_child_8.addWidget(self.alt_sf_color_alpha_slider)
-        self.form_box_child_8.addWidget(self.alt_sf_color_alpha_spinner)
+        self.form_box_child_9 = QtWidgets.QHBoxLayout()
+        self.form_box_child_9.addWidget(self.alt_sf_color_alpha_slider)
+        self.form_box_child_9.addWidget(self.alt_sf_color_alpha_spinner)
 
-        # Plot Selection (right - left) Line Color
-        self.alt_sl_color_label = QtWidgets.QLabel('%s:' % _('Sel2. Line'))
-        self.alt_sl_color_label.setToolTip(
-            _("Set the line color for the 'right to left' selection box.")
-        )
-        self.alt_sl_color_entry = FCEntry()
-        self.alt_sl_color_button = QtWidgets.QPushButton()
-        self.alt_sl_color_button.setFixedSize(15, 15)
+        grid0.addWidget(self.alt_sf_alpha_label, 23, 0)
+        grid0.addLayout(self.form_box_child_9, 23, 1)
 
-        self.form_box_child_9 = QtWidgets.QHBoxLayout()
-        self.form_box_child_9.addWidget(self.alt_sl_color_entry)
-        self.form_box_child_9.addWidget(self.alt_sl_color_button)
-        self.form_box_child_9.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 24, 0, 1, 2)
+
+        # ------------------------------------------------------------------
+        # ----------------------- Editor Color -----------------------------
+        # ------------------------------------------------------------------
+
+        self.editor_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Editor Color'))
+        grid0.addWidget(self.editor_color_label, 25, 0, 1, 2)
 
         # Editor Draw Color
-        self.draw_color_label = QtWidgets.QLabel('%s:' % _('Editor Draw'))
+        self.draw_color_label = QtWidgets.QLabel('%s:' % _('Drawing'))
         self.alt_sf_color_label.setToolTip(
             _("Set the color for the shape.")
         )
@@ -603,8 +695,11 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.form_box_child_10.addWidget(self.draw_color_button)
         self.form_box_child_10.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
+        grid0.addWidget(self.draw_color_label, 26, 0)
+        grid0.addLayout(self.form_box_child_10, 26, 1)
+
         # Editor Draw Selection Color
-        self.sel_draw_color_label = QtWidgets.QLabel('%s:' % _('Editor Draw Sel.'))
+        self.sel_draw_color_label = QtWidgets.QLabel('%s:' % _('Selection'))
         self.sel_draw_color_label.setToolTip(
             _("Set the color of the shape when selected.")
         )
@@ -617,8 +712,23 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.form_box_child_11.addWidget(self.sel_draw_color_button)
         self.form_box_child_11.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
+        grid0.addWidget(self.sel_draw_color_label, 27, 0)
+        grid0.addLayout(self.form_box_child_11, 27, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 28, 0, 1, 2)
+
+        # ------------------------------------------------------------------
+        # ----------------------- Project Settings -----------------------------
+        # ------------------------------------------------------------------
+
+        self.proj_settings_label = QtWidgets.QLabel('<b>%s</b>' % _('Project Items Color'))
+        grid0.addWidget(self.proj_settings_label, 29, 0, 1, 2)
+
         # Project Tab items color
-        self.proj_color_label = QtWidgets.QLabel('%s:' % _('Project Items'))
+        self.proj_color_label = QtWidgets.QLabel('%s:' % _('Enabled'))
         self.proj_color_label.setToolTip(
             _("Set the color of the items in Project Tab Tree.")
         )
@@ -631,7 +741,10 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.form_box_child_12.addWidget(self.proj_color_button)
         self.form_box_child_12.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
-        self.proj_color_dis_label = QtWidgets.QLabel('%s:' % _('Proj. Dis. Items'))
+        grid0.addWidget(self.proj_color_label, 30, 0)
+        grid0.addLayout(self.form_box_child_12, 30, 1)
+
+        self.proj_color_dis_label = QtWidgets.QLabel('%s:' % _('Disabled'))
         self.proj_color_dis_label.setToolTip(
             _("Set the color of the items in Project Tab Tree,\n"
               "for the case when the items are disabled.")
@@ -645,51 +758,23 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
         self.form_box_child_13.addWidget(self.proj_color_dis_button)
         self.form_box_child_13.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
-        # Activity monitor icon
-        self.activity_label = QtWidgets.QLabel('%s:' % _("Activity Icon"))
-        self.activity_label.setToolTip(
-            _("Select the GIF that show activity when FlatCAM is active.")
-        )
-        self.activity_combo = FCComboBox()
-        self.activity_combo.addItems(['Ball black', 'Ball green', 'Arrow green', 'Eclipse green'])
-
-        # Just to add empty rows
-        self.spacelabel = QtWidgets.QLabel('')
-
-        # Add (label - input field) pair to the QFormLayout
-        self.form_box.addRow(self.spacelabel, self.spacelabel)
-
-        self.form_box.addRow(self.gridx_label, self.gridx_entry)
-        self.form_box.addRow(self.gridy_label, self.gridy_entry)
-        self.form_box.addRow(self.snap_max_label, self.snap_max_dist_entry)
-
-        self.form_box.addRow(self.workspace_lbl, self.workspace_cb)
-        self.form_box.addRow(self.workspace_type_lbl, self.wk_cb)
-        self.form_box.addRow(self.wk_orientation_label, self.wk_orientation_radio)
+        grid0.addWidget(self.proj_color_dis_label, 31, 0)
+        grid0.addLayout(self.form_box_child_13, 31, 1)
 
-        self.form_box.addRow(self.spacelabel, self.spacelabel)
-        self.form_box.addRow(self.pf_color_label, self.form_box_child_1)
-        self.form_box.addRow(self.pf_alpha_label, self.form_box_child_2)
-        self.form_box.addRow(self.pl_color_label, self.form_box_child_3)
-        self.form_box.addRow(self.sf_color_label, self.form_box_child_4)
-        self.form_box.addRow(self.sf_alpha_label, self.form_box_child_5)
-        self.form_box.addRow(self.sl_color_label, self.form_box_child_6)
-        self.form_box.addRow(self.alt_sf_color_label, self.form_box_child_7)
-        self.form_box.addRow(self.alt_sf_alpha_label, self.form_box_child_8)
-        self.form_box.addRow(self.alt_sl_color_label, self.form_box_child_9)
-        self.form_box.addRow(self.draw_color_label, self.form_box_child_10)
-        self.form_box.addRow(self.sel_draw_color_label, self.form_box_child_11)
-        self.form_box.addRow(QtWidgets.QLabel(""))
-        self.form_box.addRow(self.proj_color_label, self.form_box_child_12)
-        self.form_box.addRow(self.proj_color_dis_label, self.form_box_child_13)
+        # Project autohide CB
+        self.project_autohide_cb = FCCheckBox(label='Project AutoHide')
+        self.project_autohide_cb.setToolTip(
+            _("Check this box if you want the project/selected/tool tab area to\n"
+              "hide automatically when there are no objects loaded and\n"
+              "to show whenever a new object is created.")
+        )
 
-        self.form_box.addRow(self.activity_label, self.activity_combo)
+        grid0.addWidget(self.project_autohide_cb, 32, 0, 1, 2)
 
-        self.form_box.addRow(self.spacelabel, self.spacelabel)
+        # Just to add empty rows
+        grid0.addWidget(QtWidgets.QLabel(''), 33, 0, 1, 2)
 
-        # Add the QFormLayout that holds the Application general defaults
-        # to the main layout of this TAB
-        self.layout.addLayout(self.form_box)
+        self.layout.addStretch()
 
 
 class GeneralGUISetGroupUI(OptionsGroupUI):
@@ -710,9 +795,7 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
             self.resource_loc = 'share'
 
-        # Create a form layout for the Application general settings
-        self.form_box = QtWidgets.QFormLayout()
-
+        # Create a grid layout for the Application general settings
         grid0 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid0)
         grid0.setColumnStretch(0, 0)
@@ -891,12 +974,23 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         # Just to add empty rows
         grid0.addWidget(QtWidgets.QLabel(''), 12, 0)
 
+        # -----------------------------------------------------------
+        # ----------- APPLICATION STARTUP SETTINGS ------------------
+        # -----------------------------------------------------------
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 13, 0, 1, 2)
+
+        self.startup_label = QtWidgets.QLabel('<b>%s</b>' % _('Startup Settings'))
+        grid0.addWidget(self.startup_label, 14, 0, 1, 2)
+
         # Splash Screen
-        self.splash_label = QtWidgets.QLabel('%s:' % _('Splash Screen'))
-        self.splash_label.setToolTip(
+        self.splash_cb = FCCheckBox('%s' % _('Splash Screen'))
+        self.splash_cb.setToolTip(
             _("Enable display of the splash screen at application startup.")
         )
-        self.splash_cb = FCCheckBox()
 
         settings = QSettings("Open Source", "FlatCAM")
         if settings.value("splash_screen"):
@@ -904,85 +998,46 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
             self.splash_cb.set_value(False)
 
-        grid0.addWidget(self.splash_label, 13, 0)
-        grid0.addWidget(self.splash_cb, 13, 1)
+        grid0.addWidget(self.splash_cb, 15, 0, 1, 2)
 
         # Sys Tray Icon
-        self.systray_label = QtWidgets.QLabel('%s:' % _('Sys Tray Icon'))
-        self.systray_label.setToolTip(
+        self.systray_cb = FCCheckBox('%s' % _('Sys Tray Icon'))
+        self.systray_cb.setToolTip(
             _("Enable display of FlatCAM icon in Sys Tray.")
         )
-        self.systray_cb = FCCheckBox()
-
-        grid0.addWidget(self.systray_label, 14, 0)
-        grid0.addWidget(self.systray_cb, 14, 1)
+        grid0.addWidget(self.systray_cb, 16, 0, 1, 2)
 
         # Shell StartUp CB
-        self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
-        self.shell_startup_label.setToolTip(
-            _("Check this box if you want the shell to\n"
-              "start automatically at startup.")
-        )
-        self.shell_startup_cb = FCCheckBox(label='')
+        self.shell_startup_cb = FCCheckBox(label='%s' % _('Show Shell'))
         self.shell_startup_cb.setToolTip(
             _("Check this box if you want the shell to\n"
               "start automatically at startup.")
         )
 
-        grid0.addWidget(self.shell_startup_label, 15, 0)
-        grid0.addWidget(self.shell_startup_cb, 15, 1)
+        grid0.addWidget(self.shell_startup_cb, 17, 0, 1, 2)
 
         # Project at StartUp CB
-        self.project_startup_label = QtWidgets.QLabel('%s:' % _('Project at StartUp'))
-        self.project_startup_label.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "to be shown automatically at startup.")
-        )
-        self.project_startup_cb = FCCheckBox(label='')
+        self.project_startup_cb = FCCheckBox(label='%s' % _('Show Project'))
         self.project_startup_cb.setToolTip(
             _("Check this box if you want the project/selected/tool tab area to\n"
               "to be shown automatically at startup.")
         )
+        grid0.addWidget(self.project_startup_cb, 18, 0, 1, 2)
 
-        grid0.addWidget(self.project_startup_label, 16, 0)
-        grid0.addWidget(self.project_startup_cb, 16, 1)
+        # -----------------------------------------------------------
+        # -------------- MOUSE SETTINGS -----------------------------
+        # -----------------------------------------------------------
 
-        # Project autohide CB
-        self.project_autohide_label = QtWidgets.QLabel('%s:' % _('Project AutoHide'))
-        self.project_autohide_label.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "hide automatically when there are no objects loaded and\n"
-              "to show whenever a new object is created.")
-        )
-        self.project_autohide_cb = FCCheckBox(label='')
-        self.project_autohide_cb.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "hide automatically when there are no objects loaded and\n"
-              "to show whenever a new object is created.")
-        )
-
-        grid0.addWidget(self.project_autohide_label, 17, 0)
-        grid0.addWidget(self.project_autohide_cb, 17, 1)
-
-        grid0.addWidget(QtWidgets.QLabel(''), 18, 0)
-
-        # Enable/Disable ToolTips globally
-        self.toggle_tooltips_label = QtWidgets.QLabel('<b>%s:</b>' % _('Enable ToolTips'))
-        self.toggle_tooltips_label.setToolTip(
-            _("Check this box if you want to have toolTips displayed\n"
-              "when hovering with mouse over items throughout the App.")
-        )
-        self.toggle_tooltips_cb = FCCheckBox(label='')
-        self.toggle_tooltips_cb.setToolTip(
-            _("Check this box if you want to have toolTips displayed\n"
-              "when hovering with mouse over items throughout the App.")
-        )
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 20, 0, 1, 2)
 
-        grid0.addWidget(self.toggle_tooltips_label, 19, 0)
-        grid0.addWidget(self.toggle_tooltips_cb, 19, 1)
+        self.mouse_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Mouse Settings'))
+        grid0.addWidget(self.mouse_lbl, 21, 0, 1, 2)
 
         # Mouse Cursor Shape
-        self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor'))
+        self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Cursor Shape'))
         self.cursor_lbl.setToolTip(
            _("Choose a mouse cursor shape.\n"
              "- Small -> with a customizable size.\n"
@@ -994,10 +1049,11 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
             {"label": _("Big"), "value": "big"}
         ], orientation='horizontal', stretch=False)
 
-        grid0.addWidget(self.cursor_lbl, 20, 0)
-        grid0.addWidget(self.cursor_radio, 20, 1)
+        grid0.addWidget(self.cursor_lbl, 22, 0)
+        grid0.addWidget(self.cursor_radio, 22, 1)
 
-        self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor Size'))
+        # Mouse Cursor Size
+        self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Cursor Size'))
         self.cursor_size_lbl.setToolTip(
            _("Set the size of the mouse cursor, in pixels.")
         )
@@ -1006,10 +1062,11 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.cursor_size_entry.set_range(10, 70)
         self.cursor_size_entry.setWrapping(True)
 
-        grid0.addWidget(self.cursor_size_lbl, 21, 0)
-        grid0.addWidget(self.cursor_size_entry, 21, 1)
+        grid0.addWidget(self.cursor_size_lbl, 23, 0)
+        grid0.addWidget(self.cursor_size_entry, 23, 1)
 
-        self.cursor_width_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor Width'))
+        # Cursor Width
+        self.cursor_width_lbl = QtWidgets.QLabel('%s:' % _('Cursor Width'))
         self.cursor_width_lbl.setToolTip(
            _("Set the line width of the mouse cursor, in pixels.")
         )
@@ -1018,8 +1075,69 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.cursor_width_entry.set_range(1, 10)
         self.cursor_width_entry.setWrapping(True)
 
-        grid0.addWidget(self.cursor_width_lbl, 22, 0)
-        grid0.addWidget(self.cursor_width_entry, 22, 1)
+        grid0.addWidget(self.cursor_width_lbl, 24, 0)
+        grid0.addWidget(self.cursor_width_entry, 24, 1)
+
+        # Cursor Color Enable
+        self.mouse_cursor_color_cb = FCCheckBox(label='%s' % _('Cursor Color'))
+        self.mouse_cursor_color_cb.setToolTip(
+            _("Check this box to color mouse cursor.")
+        )
+        grid0.addWidget(self.mouse_cursor_color_cb, 25, 0, 1, 2)
+
+        # Cursor Color
+        self.mouse_color_label = QtWidgets.QLabel('%s:' % _('Cursor Color'))
+        self.mouse_color_label.setToolTip(
+            _("Set the color of the mouse cursor.")
+        )
+        self.mouse_cursor_entry = FCEntry()
+        self.mouse_cursor_button = QtWidgets.QPushButton()
+        self.mouse_cursor_button.setFixedSize(15, 15)
+
+        self.form_box_child_1 = QtWidgets.QHBoxLayout()
+        self.form_box_child_1.addWidget(self.mouse_cursor_entry)
+        self.form_box_child_1.addWidget(self.mouse_cursor_button)
+        self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        grid0.addWidget(self.mouse_color_label, 26, 0)
+        grid0.addLayout(self.form_box_child_1, 26, 1)
+
+        self.mois = OptionalInputSection(
+            self.mouse_cursor_color_cb,
+            [
+                self.mouse_color_label,
+                self.mouse_cursor_entry,
+                self.mouse_cursor_button
+            ]
+        )
+        # Select mouse pan button
+        self.panbuttonlabel = QtWidgets.QLabel('%s:' % _('Pan Button'))
+        self.panbuttonlabel.setToolTip(
+            _("Select the mouse button to use for panning:\n"
+              "- MMB --> Middle Mouse Button\n"
+              "- RMB --> Right Mouse Button")
+        )
+        self.pan_button_radio = RadioSet([{'label': _('MMB'), 'value': '3'},
+                                          {'label': _('RMB'), 'value': '2'}])
+
+        grid0.addWidget(self.panbuttonlabel, 27, 0)
+        grid0.addWidget(self.pan_button_radio, 27, 1)
+
+        # Multiple Selection Modifier Key
+        self.mselectlabel = QtWidgets.QLabel('%s:' % _('Multiple Selection'))
+        self.mselectlabel.setToolTip(
+            _("Select the key used for multiple selection.")
+        )
+        self.mselect_radio = RadioSet([{'label': _('CTRL'), 'value': 'Control'},
+                                       {'label': _('SHIFT'), 'value': 'Shift'}])
+
+        grid0.addWidget(self.mselectlabel, 28, 0)
+        grid0.addWidget(self.mselect_radio, 28, 1)
+
+        separator_line = QtWidgets.QFrame()
+        separator_line.setFrameShape(QtWidgets.QFrame.HLine)
+        separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        grid0.addWidget(separator_line, 29, 0, 1, 2)
 
         # Delete confirmation
         self.delete_conf_cb = FCCheckBox(_('Delete object confirmation'))
@@ -1028,10 +1146,73 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "whenever the Delete object(s) event is triggered, either by\n"
               "menu shortcut or key shortcut.")
         )
-        grid0.addWidget(self.delete_conf_cb, 23, 0, 1, 2)
+        grid0.addWidget(self.delete_conf_cb, 30, 0, 1, 2)
+
+        # Enable/Disable ToolTips globally
+        self.toggle_tooltips_cb = FCCheckBox(label='Enable ToolTips')
+        self.toggle_tooltips_cb.setToolTip(
+            _("Check this box if you want to have toolTips displayed\n"
+              "when hovering with mouse over items throughout the App.")
+        )
+
+        grid0.addWidget(self.toggle_tooltips_cb, 31, 0, 1, 2)
+
+        # Activity monitor icon
+        self.activity_label = QtWidgets.QLabel('%s:' % _("Activity Icon"))
+        self.activity_label.setToolTip(
+            _("Select the GIF that show activity when FlatCAM is active.")
+        )
+        self.activity_combo = FCComboBox()
+        self.activity_combo.addItems(['Ball black', 'Ball green', 'Arrow green', 'Eclipse green'])
+
+        grid0.addWidget(self.activity_label, 32, 0)
+        grid0.addWidget(self.activity_combo, 32, 1)
 
         self.layout.addStretch()
 
+        self.mouse_cursor_color_cb.stateChanged.connect(self.on_mouse_cursor_color_enable)
+
+        self.mouse_cursor_entry.editingFinished.connect(self.on_mouse_cursor_entry)
+        self.mouse_cursor_button.clicked.connect(self.on_mouse_cursor_button)
+
+    def on_mouse_cursor_color_enable(self, val):
+        if val:
+            self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
+        else:
+            theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
+            if theme_settings.contains("theme"):
+                theme = theme_settings.value('theme', type=str)
+            else:
+                theme = 'white'
+
+            if theme == 'white':
+                self.app.cursor_color_3D = 'black'
+            else:
+                self.app.cursor_color_3D = 'gray'
+
+    def on_mouse_cursor_entry(self):
+        self.app.defaults['global_cursor_color'] = self.mouse_cursor_entry.get_value()
+        self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_cursor_color']))
+
+        self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
+
+    def on_mouse_cursor_button(self):
+        current_color = QtGui.QColor(self.app.defaults['global_cursor_color'])
+
+        c_dialog = QtWidgets.QColorDialog()
+        proj_color = c_dialog.getColor(initial=current_color)
+
+        if proj_color.isValid() is False:
+            return
+
+        self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(proj_color.name()))
+
+        new_val_sel = str(proj_color.name())
+        self.mouse_cursor_entry.set_value(new_val_sel)
+        self.app.defaults['global_cursor_color'] = new_val_sel
+
+        self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
+
     def handle_style(self, style):
         # set current style
         settings = QSettings("Open Source", "FlatCAM")
@@ -1213,26 +1394,6 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
 
         self.ois_version_check = OptionalInputSection(self.version_check_cb, [self.send_stats_cb])
 
-        # Select mouse pan button
-        self.panbuttonlabel = QtWidgets.QLabel('<b>%s:</b>' % _('Pan Button'))
-        self.panbuttonlabel.setToolTip(_("Select the mouse button to use for panning:\n"
-                                         "- MMB --> Middle Mouse Button\n"
-                                         "- RMB --> Right Mouse Button"))
-        self.pan_button_radio = RadioSet([{'label': _('MMB'), 'value': '3'},
-                                          {'label': _('RMB'), 'value': '2'}])
-
-        grid0.addWidget(self.panbuttonlabel, 12, 0)
-        grid0.addWidget(self.pan_button_radio, 12, 1)
-
-        # Multiple Selection Modifier Key
-        self.mselectlabel = QtWidgets.QLabel('<b>%s:</b>' % _('Multiple Sel'))
-        self.mselectlabel.setToolTip(_("Select the key used for multiple selection."))
-        self.mselect_radio = RadioSet([{'label': _('CTRL'), 'value': 'Control'},
-                                       {'label': _('SHIFT'), 'value': 'Shift'}])
-
-        grid0.addWidget(self.mselectlabel, 13, 0)
-        grid0.addWidget(self.mselect_radio, 13, 1)
-
         # Worker Numbers
         self.worker_number_label = QtWidgets.QLabel('%s:' % _('Workers number'))
         self.worker_number_label.setToolTip(

+ 1 - 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"]
         })