Преглед изворни кода

- added more key shortcuts into the application; they are now displayed in the GUI menu's
- reorganized the Edit -> Preferences -> Global
- redesigned the messagebox that is showed when quiting ot creating a New Project: now it has an option ('Cancel') to abort the process returning to the app

Marius Stanciu пре 7 година
родитељ
комит
c4a9c8bd77

+ 1 - 0
FlatCAM.py

@@ -6,6 +6,7 @@ from FlatCAMApp import App
 from multiprocessing import freeze_support
 import VisPyPatches
 
+
 if sys.platform == "win32":
     # cx_freeze 'module win32' workaround
     import OpenGL.platform.win32

+ 249 - 155
FlatCAMApp.py

@@ -104,6 +104,7 @@ class App(QtCore.QObject):
     manual_url = "http://flatcam.org/manual/index.html"
     video_url = "https://www.youtube.com/playlist?list=PLVvP2SYRpx-AQgNlfoxw93tXUXon7G94_"
 
+    should_we_quit = True
 
     ##################
     ##    Signals   ##
@@ -291,25 +292,25 @@ class App(QtCore.QObject):
         # when adding entries here read the comments in the  method found bellow named:
         # def new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
         self.defaults_form_fields = {
-            "units": self.general_defaults_form.general_group.units_radio,
-            "global_shell_at_startup": self.general_defaults_form.general_group.shell_startup_cb,
-            "global_version_check": self.general_defaults_form.general_group.version_check_cb,
-            "global_send_stats": self.general_defaults_form.general_group.send_stats_cb,
-            "global_gridx": self.general_defaults_form.general_group.gridx_entry,
-            "global_gridy": self.general_defaults_form.general_group.gridy_entry,
-            "global_plot_fill": self.general_defaults_form.general_group.pf_color_entry,
-            "global_plot_line": self.general_defaults_form.general_group.pl_color_entry,
-            "global_sel_fill": self.general_defaults_form.general_group.sf_color_entry,
-            "global_sel_line": self.general_defaults_form.general_group.sl_color_entry,
-            "global_alt_sel_fill": self.general_defaults_form.general_group.alt_sf_color_entry,
-            "global_alt_sel_line": self.general_defaults_form.general_group.alt_sl_color_entry,
-            "global_draw_color": self.general_defaults_form.general_group.draw_color_entry,
-            "global_sel_draw_color": self.general_defaults_form.general_group.sel_draw_color_entry,
-            "global_pan_button": self.general_defaults_form.general_group.pan_button_radio,
-            "global_mselect_key": self.general_defaults_form.general_group.mselect_radio,
-            # "global_pan_with_space_key": self.general_defaults_form.general_group.pan_with_space_cb,
-            "global_workspace": self.general_defaults_form.general_group.workspace_cb,
-            "global_workspaceT": self.general_defaults_form.general_group.wk_cb,
+            "units": self.general_defaults_form.general_app_group.units_radio,
+            "global_shell_at_startup": self.general_defaults_form.general_app_group.shell_startup_cb,
+            "global_version_check": self.general_defaults_form.general_app_group.version_check_cb,
+            "global_send_stats": self.general_defaults_form.general_app_group.send_stats_cb,
+            "global_gridx": self.general_defaults_form.general_gui_group.gridx_entry,
+            "global_gridy": self.general_defaults_form.general_gui_group.gridy_entry,
+            "global_plot_fill": self.general_defaults_form.general_gui_group.pf_color_entry,
+            "global_plot_line": self.general_defaults_form.general_gui_group.pl_color_entry,
+            "global_sel_fill": self.general_defaults_form.general_gui_group.sf_color_entry,
+            "global_sel_line": self.general_defaults_form.general_gui_group.sl_color_entry,
+            "global_alt_sel_fill": self.general_defaults_form.general_gui_group.alt_sf_color_entry,
+            "global_alt_sel_line": self.general_defaults_form.general_gui_group.alt_sl_color_entry,
+            "global_draw_color": self.general_defaults_form.general_gui_group.draw_color_entry,
+            "global_sel_draw_color": self.general_defaults_form.general_gui_group.sel_draw_color_entry,
+            "global_pan_button": self.general_defaults_form.general_app_group.pan_button_radio,
+            "global_mselect_key": self.general_defaults_form.general_app_group.mselect_radio,
+            # "global_pan_with_space_key": self.general_defaults_form.general_gui_group.pan_with_space_cb,
+            "global_workspace": self.general_defaults_form.general_gui_group.workspace_cb,
+            "global_workspaceT": self.general_defaults_form.general_gui_group.wk_cb,
 
             "gerber_plot": self.gerber_defaults_form.gerber_group.plot_cb,
             "gerber_solid": self.gerber_defaults_form.gerber_group.solid_cb,
@@ -582,9 +583,9 @@ class App(QtCore.QObject):
         self.cncjob_options_form = CNCJobPreferencesUI()
 
         self.options_form_fields = {
-            "units": self.general_options_form.general_group.units_radio,
-            "global_gridx": self.general_options_form.general_group.gridx_entry,
-            "global_gridy": self.general_options_form.general_group.gridy_entry,
+            "units": self.general_options_form.general_app_group.units_radio,
+            "global_gridx": self.general_options_form.general_gui_group.gridx_entry,
+            "global_gridy": self.general_options_form.general_gui_group.gridy_entry,
             "gerber_plot": self.gerber_options_form.gerber_group.plot_cb,
             "gerber_solid": self.gerber_options_form.gerber_group.solid_cb,
             "gerber_multicolored": self.gerber_options_form.gerber_group.multicolored_cb,
@@ -758,51 +759,51 @@ class App(QtCore.QObject):
 
         ### Initialize the color box's color in Preferences -> Global -> Color
         # Init Plot Colors
-        self.general_defaults_form.general_group.pf_color_entry.set_value(self.defaults['global_plot_fill'])
-        self.general_defaults_form.general_group.pf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pf_color_entry.set_value(self.defaults['global_plot_fill'])
+        self.general_defaults_form.general_gui_group.pf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_plot_fill'])[:7])
-        self.general_defaults_form.general_group.pf_color_alpha_spinner.set_value(
+        self.general_defaults_form.general_gui_group.pf_color_alpha_spinner.set_value(
             int(self.defaults['global_plot_fill'][7:9], 16))
-        self.general_defaults_form.general_group.pf_color_alpha_slider.setValue(
+        self.general_defaults_form.general_gui_group.pf_color_alpha_slider.setValue(
             int(self.defaults['global_plot_fill'][7:9], 16))
 
-        self.general_defaults_form.general_group.pl_color_entry.set_value(self.defaults['global_plot_line'])
-        self.general_defaults_form.general_group.pl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pl_color_entry.set_value(self.defaults['global_plot_line'])
+        self.general_defaults_form.general_gui_group.pl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_plot_line'])[:7])
 
         # Init Left-Right Selection colors
-        self.general_defaults_form.general_group.sf_color_entry.set_value(self.defaults['global_sel_fill'])
-        self.general_defaults_form.general_group.sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sf_color_entry.set_value(self.defaults['global_sel_fill'])
+        self.general_defaults_form.general_gui_group.sf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_fill'])[:7])
-        self.general_defaults_form.general_group.sf_color_alpha_spinner.set_value(
+        self.general_defaults_form.general_gui_group.sf_color_alpha_spinner.set_value(
             int(self.defaults['global_sel_fill'][7:9], 16))
-        self.general_defaults_form.general_group.sf_color_alpha_slider.setValue(
+        self.general_defaults_form.general_gui_group.sf_color_alpha_slider.setValue(
             int(self.defaults['global_sel_fill'][7:9], 16))
 
-        self.general_defaults_form.general_group.sl_color_entry.set_value(self.defaults['global_sel_line'])
-        self.general_defaults_form.general_group.sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sl_color_entry.set_value(self.defaults['global_sel_line'])
+        self.general_defaults_form.general_gui_group.sl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_line'])[:7])
 
         # Init Right-Left Selection colors
-        self.general_defaults_form.general_group.alt_sf_color_entry.set_value(self.defaults['global_alt_sel_fill'])
-        self.general_defaults_form.general_group.alt_sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sf_color_entry.set_value(self.defaults['global_alt_sel_fill'])
+        self.general_defaults_form.general_gui_group.alt_sf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_alt_sel_fill'])[:7])
-        self.general_defaults_form.general_group.alt_sf_color_alpha_spinner.set_value(
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.set_value(
             int(self.defaults['global_sel_fill'][7:9], 16))
-        self.general_defaults_form.general_group.alt_sf_color_alpha_slider.setValue(
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.setValue(
             int(self.defaults['global_sel_fill'][7:9], 16))
 
-        self.general_defaults_form.general_group.alt_sl_color_entry.set_value(self.defaults['global_alt_sel_line'])
-        self.general_defaults_form.general_group.alt_sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sl_color_entry.set_value(self.defaults['global_alt_sel_line'])
+        self.general_defaults_form.general_gui_group.alt_sl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_alt_sel_line'])[:7])
 
         # Init Draw color and Selection Draw Color
-        self.general_defaults_form.general_group.draw_color_entry.set_value(self.defaults['global_draw_color'])
-        self.general_defaults_form.general_group.draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.draw_color_entry.set_value(self.defaults['global_draw_color'])
+        self.general_defaults_form.general_gui_group.draw_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_draw_color'])[:7])
 
-        self.general_defaults_form.general_group.sel_draw_color_entry.set_value(self.defaults['global_sel_draw_color'])
-        self.general_defaults_form.general_group.sel_draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sel_draw_color_entry.set_value(self.defaults['global_sel_draw_color'])
+        self.general_defaults_form.general_gui_group.sel_draw_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_draw_color'])[:7])
         #### End of Data ####
 
@@ -917,6 +918,7 @@ class App(QtCore.QObject):
         self.ui.menueditorigin.triggered.connect(self.on_set_origin)
         self.ui.menueditjump.triggered.connect(self.on_jump_to)
 
+        self.ui.menuedittoggleunits.triggered.connect(self.on_toggle_units_click)
         self.ui.menueditselectall.triggered.connect(self.on_selectall)
         self.ui.menueditpreferences.triggered.connect(self.on_preferences)
 
@@ -942,6 +944,7 @@ class App(QtCore.QObject):
         self.ui.menuview_zoom_fit.triggered.connect(self.on_zoom_fit)
         self.ui.menuview_zoom_in.triggered.connect(lambda: self.plotcanvas.zoom(1 / 1.5))
         self.ui.menuview_zoom_out.triggered.connect(lambda: self.plotcanvas.zoom(1.5))
+        self.ui.menuview_toggle_grid.triggered.connect(self.on_toggle_grid)
         self.ui.menuview_toggle_axis.triggered.connect(self.on_toggle_axis)
         self.ui.menuview_toggle_workspace.triggered.connect(self.on_workspace_menu)
 
@@ -995,6 +998,7 @@ class App(QtCore.QObject):
         self.ui.draw_line.triggered.connect(self.geo_editor.draw_tool_path)
         self.ui.draw_rect.triggered.connect(self.geo_editor.draw_tool_rectangle)
         self.ui.draw_cut.triggered.connect(self.geo_editor.cutpath)
+        self.ui.draw_move.triggered.connect(self.geo_editor.on_move)
         self.ui.drill.triggered.connect(self.exc_editor.exc_add_drill)
         self.ui.drill_array.triggered.connect(self.exc_editor.exc_add_drill_array)
         self.ui.drill_copy.triggered.connect(self.exc_editor.exc_copy_drills)
@@ -1019,39 +1023,48 @@ class App(QtCore.QObject):
         self.ui.pref_export_button.clicked.connect(self.on_export_preferences)
         self.ui.pref_open_button.clicked.connect(self.on_preferences_open_folder)
 
-        self.general_options_form.general_group.units_radio.group_toggle_fn = self.on_toggle_units
+        ###############################
+        ### GUI PREFERENCES SIGNALS ###
+        ###############################
+        self.general_options_form.general_app_group.units_radio.group_toggle_fn = self.on_toggle_units
+        self.general_defaults_form.general_app_group.language_apply_btn.clicked.connect(self.on_language_apply)
+
+        ###############################
+        ### GUI PREFERENCES SIGNALS ###
+        ###############################
+
         # Setting plot colors signals
-        self.general_defaults_form.general_group.pf_color_entry.editingFinished.connect(self.on_pf_color_entry)
-        self.general_defaults_form.general_group.pf_color_button.clicked.connect(self.on_pf_color_button)
-        self.general_defaults_form.general_group.pf_color_alpha_spinner.valueChanged.connect(self.on_pf_color_spinner)
-        self.general_defaults_form.general_group.pf_color_alpha_slider.valueChanged.connect(self.on_pf_color_slider)
-        self.general_defaults_form.general_group.pl_color_entry.editingFinished.connect(self.on_pl_color_entry)
-        self.general_defaults_form.general_group.pl_color_button.clicked.connect(self.on_pl_color_button)
+        self.general_defaults_form.general_gui_group.pf_color_entry.editingFinished.connect(self.on_pf_color_entry)
+        self.general_defaults_form.general_gui_group.pf_color_button.clicked.connect(self.on_pf_color_button)
+        self.general_defaults_form.general_gui_group.pf_color_alpha_spinner.valueChanged.connect(self.on_pf_color_spinner)
+        self.general_defaults_form.general_gui_group.pf_color_alpha_slider.valueChanged.connect(self.on_pf_color_slider)
+        self.general_defaults_form.general_gui_group.pl_color_entry.editingFinished.connect(self.on_pl_color_entry)
+        self.general_defaults_form.general_gui_group.pl_color_button.clicked.connect(self.on_pl_color_button)
         # Setting selection (left - right) colors signals
-        self.general_defaults_form.general_group.sf_color_entry.editingFinished.connect(self.on_sf_color_entry)
-        self.general_defaults_form.general_group.sf_color_button.clicked.connect(self.on_sf_color_button)
-        self.general_defaults_form.general_group.sf_color_alpha_spinner.valueChanged.connect(self.on_sf_color_spinner)
-        self.general_defaults_form.general_group.sf_color_alpha_slider.valueChanged.connect(self.on_sf_color_slider)
-        self.general_defaults_form.general_group.sl_color_entry.editingFinished.connect(self.on_sl_color_entry)
-        self.general_defaults_form.general_group.sl_color_button.clicked.connect(self.on_sl_color_button)
+        self.general_defaults_form.general_gui_group.sf_color_entry.editingFinished.connect(self.on_sf_color_entry)
+        self.general_defaults_form.general_gui_group.sf_color_button.clicked.connect(self.on_sf_color_button)
+        self.general_defaults_form.general_gui_group.sf_color_alpha_spinner.valueChanged.connect(self.on_sf_color_spinner)
+        self.general_defaults_form.general_gui_group.sf_color_alpha_slider.valueChanged.connect(self.on_sf_color_slider)
+        self.general_defaults_form.general_gui_group.sl_color_entry.editingFinished.connect(self.on_sl_color_entry)
+        self.general_defaults_form.general_gui_group.sl_color_button.clicked.connect(self.on_sl_color_button)
         # Setting selection (right - left) colors signals
-        self.general_defaults_form.general_group.alt_sf_color_entry.editingFinished.connect(self.on_alt_sf_color_entry)
-        self.general_defaults_form.general_group.alt_sf_color_button.clicked.connect(self.on_alt_sf_color_button)
-        self.general_defaults_form.general_group.alt_sf_color_alpha_spinner.valueChanged.connect(
+        self.general_defaults_form.general_gui_group.alt_sf_color_entry.editingFinished.connect(self.on_alt_sf_color_entry)
+        self.general_defaults_form.general_gui_group.alt_sf_color_button.clicked.connect(self.on_alt_sf_color_button)
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.valueChanged.connect(
             self.on_alt_sf_color_spinner)
-        self.general_defaults_form.general_group.alt_sf_color_alpha_slider.valueChanged.connect(
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.valueChanged.connect(
             self.on_alt_sf_color_slider)
-        self.general_defaults_form.general_group.alt_sl_color_entry.editingFinished.connect(self.on_alt_sl_color_entry)
-        self.general_defaults_form.general_group.alt_sl_color_button.clicked.connect(self.on_alt_sl_color_button)
+        self.general_defaults_form.general_gui_group.alt_sl_color_entry.editingFinished.connect(self.on_alt_sl_color_entry)
+        self.general_defaults_form.general_gui_group.alt_sl_color_button.clicked.connect(self.on_alt_sl_color_button)
         # Setting Editor Draw colors signals
-        self.general_defaults_form.general_group.draw_color_entry.editingFinished.connect(self.on_draw_color_entry)
-        self.general_defaults_form.general_group.draw_color_button.clicked.connect(self.on_draw_color_button)
+        self.general_defaults_form.general_gui_group.draw_color_entry.editingFinished.connect(self.on_draw_color_entry)
+        self.general_defaults_form.general_gui_group.draw_color_button.clicked.connect(self.on_draw_color_button)
 
-        self.general_defaults_form.general_group.sel_draw_color_entry.editingFinished.connect(self.on_sel_draw_color_entry)
-        self.general_defaults_form.general_group.sel_draw_color_button.clicked.connect(self.on_sel_draw_color_button)
+        self.general_defaults_form.general_gui_group.sel_draw_color_entry.editingFinished.connect(self.on_sel_draw_color_entry)
+        self.general_defaults_form.general_gui_group.sel_draw_color_button.clicked.connect(self.on_sel_draw_color_button)
 
-        self.general_defaults_form.general_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified)
-        self.general_defaults_form.general_group.workspace_cb.stateChanged.connect(self.on_workspace)
+        self.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified)
+        self.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace)
 
 
         # Modify G-CODE Plot Area TAB
@@ -1067,7 +1080,7 @@ class App(QtCore.QObject):
         self.collection.view.activated.connect(self.on_row_activated)
 
         # Monitor the checkbox from the Application Defaults Tab and show the TCL shell or not depending on it's value
-        self.general_defaults_form.general_group.shell_startup_cb.clicked.connect(self.on_toggle_shell)
+        self.general_defaults_form.general_app_group.shell_startup_cb.clicked.connect(self.on_toggle_shell)
 
         # Load the defaults values into the Excellon Format and Excellon Zeros fields
         self.excellon_defaults_form.excellon_group.excellon_defaults_button.clicked.connect(
@@ -1173,7 +1186,7 @@ class App(QtCore.QObject):
         # Separate thread (Not worker)
         # Check for updates on startup but only if the user consent and the app is not in Beta version
         if (self.beta is False or self.beta is None) and \
-                self.general_defaults_form.general_group.version_check_cb.get_value() is True:
+                self.general_defaults_form.general_gui_group.version_check_cb.get_value() is True:
             App.log.info("Checking for updates in backgroud (this is version %s)." % str(self.version))
 
             self.thr2 = QtCore.QThread()
@@ -2214,13 +2227,16 @@ class App(QtCore.QObject):
                            "Do you want to Save the project?")
             msgbox.setWindowTitle("Save changes")
             msgbox.setWindowIcon(QtGui.QIcon('share/save_as.png'))
-            msgbox.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Ok)
-            msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
+            msgbox.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No |
+                                      QtWidgets.QMessageBox.Cancel)
+            msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
 
             response = msgbox.exec_()
 
-            if response == QtWidgets.QMessageBox.Ok:
+            if response == QtWidgets.QMessageBox.Yes:
                 self.on_file_saveprojectas(thread=False)
+            elif response == QtWidgets.QMessageBox.Cancel:
+                return
             self.save_defaults()
         else:
             self.save_defaults()
@@ -2350,14 +2366,17 @@ class App(QtCore.QObject):
                            "Do you want to Save the project?")
             msgbox.setWindowTitle("Save changes")
             msgbox.setWindowIcon(QtGui.QIcon('share/save_as.png'))
-            msgbox.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Ok)
-            msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
+            msgbox.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No |
+                                      QtWidgets.QMessageBox.Cancel)
+            msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
 
             response = msgbox.exec_()
 
-            if response == QtWidgets.QMessageBox.Ok:
+            if response == QtWidgets.QMessageBox.Yes:
                 self.on_file_saveprojectas(thread=False)
-
+            elif response == QtWidgets.QMessageBox.Cancel:
+                self.should_we_quit = False
+                return
         self.save_defaults()
         log.debug("Application defaults saved ... Exit event.")
 
@@ -2508,7 +2527,7 @@ class App(QtCore.QObject):
             return
 
         # If option is the same, then ignore
-        if self.general_options_form.general_group.units_radio.get_value().upper() == self.options["units"].upper():
+        if self.general_options_form.general_app_group.units_radio.get_value().upper() == self.options["units"].upper():
             self.log.debug("on_toggle_units(): Same as options, so ignoring.")
             return
 
@@ -2542,7 +2561,7 @@ class App(QtCore.QObject):
 
         # The scaling factor depending on choice of units.
         factor = 1/25.4
-        if self.general_options_form.general_group.units_radio.get_value().upper() == 'MM':
+        if self.general_options_form.general_app_group.units_radio.get_value().upper() == 'MM':
             factor = 25.4
 
 
@@ -2570,7 +2589,7 @@ class App(QtCore.QObject):
             self.ui.grid_gap_y_entry.set_value(float(self.ui.grid_gap_y_entry.get_value()) * factor)
 
             for obj in self.collection.get_list():
-                units = self.general_options_form.general_group.units_radio.get_value().upper()
+                units = self.general_options_form.general_app_group.units_radio.get_value().upper()
                 obj.convert_units(units)
 
                 # make that the properties stored in the object are also updated
@@ -2587,10 +2606,10 @@ class App(QtCore.QObject):
         else:
             # Undo toggling
             self.toggle_units_ignore = True
-            if self.general_options_form.general_group.units_radio.get_value().upper() == 'MM':
-                self.general_options_form.general_group.units_radio.set_value('IN')
+            if self.general_options_form.general_app_group.units_radio.get_value().upper() == 'MM':
+                self.general_options_form.general_app_group.units_radio.set_value('IN')
             else:
-                self.general_options_form.general_group.units_radio.set_value('MM')
+                self.general_options_form.general_app_group.units_radio.set_value('MM')
             self.toggle_units_ignore = False
 
         self.options_read_form()
@@ -2598,6 +2617,18 @@ class App(QtCore.QObject):
         #self.ui.units_label.setText("[" + self.options["units"] + "]")
         self.set_screen_units(self.options["units"])
 
+    def on_toggle_units_click(self):
+        if self.options["units"] == 'MM':
+            self.general_options_form.general_app_group.units_radio.set_value("IN")
+        else:
+            self.general_options_form.general_app_group.units_radio.set_value("MM")
+        self.on_toggle_units()
+
+    def on_language_apply(self):
+        # TODO: apply the language
+        # app restart section
+        pass
+
     def on_toggle_axis(self):
         if self.toggle_axis is False:
             self.plotcanvas.v_line.set_data(color=(0.70, 0.3, 0.3, 1.0))
@@ -2611,6 +2642,9 @@ class App(QtCore.QObject):
             self.plotcanvas.redraw()
             self.toggle_axis = False
 
+    def on_toggle_grid(self):
+        self.ui.grid_snap_btn.trigger()
+
     def on_options_combo_change(self, sel):
         """
         Called when the combo box to choose between application defaults and
@@ -2702,9 +2736,9 @@ class App(QtCore.QObject):
 
     # Setting plot colors handlers
     def on_pf_color_entry(self):
-        self.defaults['global_plot_fill'] = self.general_defaults_form.general_group.pf_color_entry.get_value()[:7] + \
+        self.defaults['global_plot_fill'] = self.general_defaults_form.general_gui_group.pf_color_entry.get_value()[:7] + \
                                             self.defaults['global_plot_fill'][7:9]
-        self.general_defaults_form.general_group.pf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_plot_fill'])[:7])
 
     def on_pf_color_button(self):
@@ -2716,29 +2750,29 @@ class App(QtCore.QObject):
         if plot_fill_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.pf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pf_color_button.setStyleSheet(
             "background-color:%s" % str(plot_fill_color.name()))
 
         new_val = str(plot_fill_color.name()) + str(self.defaults['global_plot_fill'][7:9])
-        self.general_defaults_form.general_group.pf_color_entry.set_value(new_val)
+        self.general_defaults_form.general_gui_group.pf_color_entry.set_value(new_val)
         self.defaults['global_plot_fill'] = new_val
 
     def on_pf_color_spinner(self):
-        spinner_value = self.general_defaults_form.general_group.pf_color_alpha_spinner.value()
-        self.general_defaults_form.general_group.pf_color_alpha_slider.setValue(spinner_value)
+        spinner_value = self.general_defaults_form.general_gui_group.pf_color_alpha_spinner.value()
+        self.general_defaults_form.general_gui_group.pf_color_alpha_slider.setValue(spinner_value)
         self.defaults['global_plot_fill'] = self.defaults['global_plot_fill'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
         self.defaults['global_plot_line'] = self.defaults['global_plot_line'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
 
     def on_pf_color_slider(self):
-        slider_value = self.general_defaults_form.general_group.pf_color_alpha_slider.value()
-        self.general_defaults_form.general_group.pf_color_alpha_spinner.setValue(slider_value)
+        slider_value = self.general_defaults_form.general_gui_group.pf_color_alpha_slider.value()
+        self.general_defaults_form.general_gui_group.pf_color_alpha_spinner.setValue(slider_value)
 
     def on_pl_color_entry(self):
-        self.defaults['global_plot_line'] = self.general_defaults_form.general_group.pl_color_entry.get_value()[:7] + \
+        self.defaults['global_plot_line'] = self.general_defaults_form.general_gui_group.pl_color_entry.get_value()[:7] + \
                                             self.defaults['global_plot_line'][7:9]
-        self.general_defaults_form.general_group.pl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_plot_line'])[:7])
 
     def on_pl_color_button(self):
@@ -2751,18 +2785,18 @@ class App(QtCore.QObject):
         if plot_line_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.pl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.pl_color_button.setStyleSheet(
             "background-color:%s" % str(plot_line_color.name()))
 
         new_val_line = str(plot_line_color.name()) + str(self.defaults['global_plot_line'][7:9])
-        self.general_defaults_form.general_group.pl_color_entry.set_value(new_val_line)
+        self.general_defaults_form.general_gui_group.pl_color_entry.set_value(new_val_line)
         self.defaults['global_plot_line'] = new_val_line
 
     # Setting selection colors (left - right) handlers
     def on_sf_color_entry(self):
-        self.defaults['global_sel_fill'] = self.general_defaults_form.general_group.sf_color_entry.get_value()[:7] + \
+        self.defaults['global_sel_fill'] = self.general_defaults_form.general_gui_group.sf_color_entry.get_value()[:7] + \
                                             self.defaults['global_sel_fill'][7:9]
-        self.general_defaults_form.general_group.sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_fill'])[:7])
 
     def on_sf_color_button(self):
@@ -2774,29 +2808,29 @@ class App(QtCore.QObject):
         if plot_fill_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sf_color_button.setStyleSheet(
             "background-color:%s" % str(plot_fill_color.name()))
 
         new_val = str(plot_fill_color.name()) + str(self.defaults['global_sel_fill'][7:9])
-        self.general_defaults_form.general_group.sf_color_entry.set_value(new_val)
+        self.general_defaults_form.general_gui_group.sf_color_entry.set_value(new_val)
         self.defaults['global_sel_fill'] = new_val
 
     def on_sf_color_spinner(self):
-        spinner_value = self.general_defaults_form.general_group.sf_color_alpha_spinner.value()
-        self.general_defaults_form.general_group.sf_color_alpha_slider.setValue(spinner_value)
+        spinner_value = self.general_defaults_form.general_gui_group.sf_color_alpha_spinner.value()
+        self.general_defaults_form.general_gui_group.sf_color_alpha_slider.setValue(spinner_value)
         self.defaults['global_sel_fill'] = self.defaults['global_sel_fill'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
         self.defaults['global_sel_line'] = self.defaults['global_sel_line'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
 
     def on_sf_color_slider(self):
-        slider_value = self.general_defaults_form.general_group.sf_color_alpha_slider.value()
-        self.general_defaults_form.general_group.sf_color_alpha_spinner.setValue(slider_value)
+        slider_value = self.general_defaults_form.general_gui_group.sf_color_alpha_slider.value()
+        self.general_defaults_form.general_gui_group.sf_color_alpha_spinner.setValue(slider_value)
 
     def on_sl_color_entry(self):
-        self.defaults['global_sel_line'] = self.general_defaults_form.general_group.sl_color_entry.get_value()[:7] + \
+        self.defaults['global_sel_line'] = self.general_defaults_form.general_gui_group.sl_color_entry.get_value()[:7] + \
                                             self.defaults['global_sel_line'][7:9]
-        self.general_defaults_form.general_group.sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_line'])[:7])
 
     def on_sl_color_button(self):
@@ -2808,18 +2842,18 @@ class App(QtCore.QObject):
         if plot_line_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sl_color_button.setStyleSheet(
             "background-color:%s" % str(plot_line_color.name()))
 
         new_val_line = str(plot_line_color.name()) + str(self.defaults['global_sel_line'][7:9])
-        self.general_defaults_form.general_group.sl_color_entry.set_value(new_val_line)
+        self.general_defaults_form.general_gui_group.sl_color_entry.set_value(new_val_line)
         self.defaults['global_sel_line'] = new_val_line
 
     # Setting selection colors (right - left) handlers
     def on_alt_sf_color_entry(self):
-        self.defaults['global_alt_sel_fill'] = self.general_defaults_form.general_group \
+        self.defaults['global_alt_sel_fill'] = self.general_defaults_form.general_gui_group \
                                    .alt_sf_color_entry.get_value()[:7] + self.defaults['global_alt_sel_fill'][7:9]
-        self.general_defaults_form.general_group.alt_sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sf_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_alt_sel_fill'])[:7])
 
     def on_alt_sf_color_button(self):
@@ -2831,29 +2865,29 @@ class App(QtCore.QObject):
         if plot_fill_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.alt_sf_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sf_color_button.setStyleSheet(
             "background-color:%s" % str(plot_fill_color.name()))
 
         new_val = str(plot_fill_color.name()) + str(self.defaults['global_alt_sel_fill'][7:9])
-        self.general_defaults_form.general_group.alt_sf_color_entry.set_value(new_val)
+        self.general_defaults_form.general_gui_group.alt_sf_color_entry.set_value(new_val)
         self.defaults['global_alt_sel_fill'] = new_val
 
     def on_alt_sf_color_spinner(self):
-        spinner_value = self.general_defaults_form.general_group.alt_sf_color_alpha_spinner.value()
-        self.general_defaults_form.general_group.alt_sf_color_alpha_slider.setValue(spinner_value)
+        spinner_value = self.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.value()
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.setValue(spinner_value)
         self.defaults['global_alt_sel_fill'] = self.defaults['global_alt_sel_fill'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
         self.defaults['global_alt_sel_line'] = self.defaults['global_alt_sel_line'][:7] + \
                                             (hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
 
     def on_alt_sf_color_slider(self):
-        slider_value = self.general_defaults_form.general_group.alt_sf_color_alpha_slider.value()
-        self.general_defaults_form.general_group.alt_sf_color_alpha_spinner.setValue(slider_value)
+        slider_value = self.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.value()
+        self.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.setValue(slider_value)
 
     def on_alt_sl_color_entry(self):
-        self.defaults['global_alt_sel_line'] = self.general_defaults_form.general_group \
+        self.defaults['global_alt_sel_line'] = self.general_defaults_form.general_gui_group \
                                    .alt_sl_color_entry.get_value()[:7] + self.defaults['global_alt_sel_line'][7:9]
-        self.general_defaults_form.general_group.alt_sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sl_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_alt_sel_line'])[:7])
 
     def on_alt_sl_color_button(self):
@@ -2865,18 +2899,18 @@ class App(QtCore.QObject):
         if plot_line_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.alt_sl_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.alt_sl_color_button.setStyleSheet(
             "background-color:%s" % str(plot_line_color.name()))
 
         new_val_line = str(plot_line_color.name()) + str(self.defaults['global_alt_sel_line'][7:9])
-        self.general_defaults_form.general_group.alt_sl_color_entry.set_value(new_val_line)
+        self.general_defaults_form.general_gui_group.alt_sl_color_entry.set_value(new_val_line)
         self.defaults['global_alt_sel_line'] = new_val_line
 
     # Setting Editor colors
     def on_draw_color_entry(self):
-        self.defaults['global_draw_color'] = self.general_defaults_form.general_group \
+        self.defaults['global_draw_color'] = self.general_defaults_form.general_gui_group \
                                                    .draw_color_entry.get_value()
-        self.general_defaults_form.general_group.draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.draw_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_draw_color']))
 
     def on_draw_color_button(self):
@@ -2888,17 +2922,17 @@ class App(QtCore.QObject):
         if draw_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.draw_color_button.setStyleSheet(
             "background-color:%s" % str(draw_color.name()))
 
         new_val = str(draw_color.name())
-        self.general_defaults_form.general_group.draw_color_entry.set_value(new_val)
+        self.general_defaults_form.general_gui_group.draw_color_entry.set_value(new_val)
         self.defaults['global_draw_color'] = new_val
 
     def on_sel_draw_color_entry(self):
-        self.defaults['global_sel_draw_color'] = self.general_defaults_form.general_group \
+        self.defaults['global_sel_draw_color'] = self.general_defaults_form.general_gui_group \
                                                    .sel_draw_color_entry.get_value()
-        self.general_defaults_form.general_group.sel_draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sel_draw_color_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['global_sel_draw_color']))
 
     def on_sel_draw_color_button(self):
@@ -2910,11 +2944,11 @@ class App(QtCore.QObject):
         if sel_draw_color.isValid() is False:
             return
 
-        self.general_defaults_form.general_group.sel_draw_color_button.setStyleSheet(
+        self.general_defaults_form.general_gui_group.sel_draw_color_button.setStyleSheet(
             "background-color:%s" % str(sel_draw_color.name()))
 
         new_val_sel = str(sel_draw_color.name())
-        self.general_defaults_form.general_group.sel_draw_color_entry.set_value(new_val_sel)
+        self.general_defaults_form.general_gui_group.sel_draw_color_entry.set_value(new_val_sel)
         self.defaults['global_sel_draw_color'] = new_val_sel
 
     def on_workspace_modified(self):
@@ -2922,7 +2956,7 @@ class App(QtCore.QObject):
         self.plotcanvas.draw_workspace()
 
     def on_workspace(self):
-        if self.general_defaults_form.general_group.workspace_cb.isChecked():
+        if self.general_defaults_form.general_gui_group.workspace_cb.isChecked():
             self.plotcanvas.restore_workspace()
         else:
             self.plotcanvas.delete_workspace()
@@ -2930,10 +2964,10 @@ class App(QtCore.QObject):
         self.save_defaults(silent=True)
 
     def on_workspace_menu(self):
-        if self.general_defaults_form.general_group.workspace_cb.isChecked():
-            self.general_defaults_form.general_group.workspace_cb.setChecked(False)
+        if self.general_defaults_form.general_gui_group.workspace_cb.isChecked():
+            self.general_defaults_form.general_gui_group.workspace_cb.setChecked(False)
         else:
-            self.general_defaults_form.general_group.workspace_cb.setChecked(True)
+            self.general_defaults_form.general_gui_group.workspace_cb.setChecked(True)
         self.on_workspace()
 
     def on_save_button(self):
@@ -3573,6 +3607,9 @@ class App(QtCore.QObject):
             if event.key == 'G':
                 self.on_fileopengerber()
 
+            if event.key == 'N':
+                self.on_file_new_click()
+
             if event.key == 'M':
                 self.measurement_tool.run()
 
@@ -3585,14 +3622,44 @@ class App(QtCore.QObject):
             return
         elif self.key_modifiers == QtCore.Qt.AltModifier:
             # place holder for further shortcut key
-            return
+            if event.key == 'C':
+                self.calculator_tool.run()
+
+            if event.key == 'D':
+                self.dblsidedtool.run()
+
+            if event.key == 'L':
+                self.film_tool.run()
+
+            if event.key == 'N':
+                self.ncclear_tool.run()
+
+            if event.key == 'P':
+                self.paint_tool.run()
+
+            if event.key == 'R':
+                self.transform_tool.run()
+
+            if event.key == 'U':
+                self.cutout_tool.run()
+
+            if event.key == 'Z':
+                self.panelize_tool.run()
+
         elif self.key_modifiers == QtCore.Qt.ShiftModifier:
             # place holder for further shortcut key
 
+            if event.key == 'C':
+                self.on_copy_name()
+
             # Toggle axis
             if event.key == 'G':
                 self.on_toggle_axis()
 
+            # Open Preferences Window
+            if event.key == 'P':
+                self.on_preferences()
+
             # Rotate Object by 90 degree CCW
             if event.key == 'R':
                 self.on_rotate(silent=True, preset=-90)
@@ -3601,6 +3668,14 @@ class App(QtCore.QObject):
             if event.key == 'W':
                 self.on_workspace_menu()
 
+            # Skew on X axis
+            if event.key == 'X':
+                self.on_skewx()
+
+            # Skew on Y axis
+            if event.key == 'Y':
+                self.on_skewy()
+
             return
         else:
             if event.key == self.defaults['fit_key']:  # 1
@@ -3624,9 +3699,6 @@ class App(QtCore.QObject):
                     self.collection.get_active().ui.plot_cb.toggle()
                     self.delete_selection_shape()
 
-            if event.key == 'C':
-                self.on_copy_name()
-
             if event.key == 'E':
                 self.object2editor()
 
@@ -3643,12 +3715,14 @@ class App(QtCore.QObject):
             if event.key == 'N':
                 self.on_new_geometry()
 
+            if event.key == 'O':
+                self.on_set_origin()
+
+            if event.key == 'P':
+                self.properties_tool.run()
+
             if event.key == 'Q':
-                if self.options["units"] == 'MM':
-                    self.general_options_form.general_group.units_radio.set_value("IN")
-                else:
-                    self.general_options_form.general_group.units_radio.set_value("MM")
-                self.on_toggle_units()
+                self.on_toggle_units_click()
 
             if event.key == 'R':
                 self.on_rotate(silent=True, preset=90)
@@ -3656,9 +3730,6 @@ class App(QtCore.QObject):
             if event.key == 'S':
                 self.on_toggle_shell()
 
-            if event.key == 'T':
-                self.transform_tool.run()
-
             if event.key == 'V':
                 self.on_zoom_fit(None)
 
@@ -3695,7 +3766,6 @@ class App(QtCore.QObject):
 <b>2:</b>       Zoom Out<br>
 <b>3:</b>       Zoom In<br>
 <b>A:</b>       Draw an Arc (when in Edit Mode)<br>
-<b>C:</b>       Copy Obj_Name<br>
 <b>C:</b>       Copy Geo Item (when in Edit Mode)<br>
 <b>E:</b>       Edit Object (if selected)<br>
 <b>G:</b>       Grid On/Off<br>
@@ -3704,13 +3774,14 @@ class App(QtCore.QObject):
 <b>M:</b>       Move Geo Item (when in Edit Mode)<br>
 <b>N:</b>       New Geometry<br>
 <b>N:</b>       Draw a Polygon (when in Edit Mode)<br>
+<b>O:</b>       Set Origin<br>
 <b>O:</b>       Draw a Circle (when in Edit Mode)<br>
 <b>Q:</b>       Change Units<br>
+<b>P:</b>       Open Properties Tool<br>
 <b>P:</b>       Draw a Path (when in Edit Mode)<br>
 <b>R:</b>       Rotate by 90 degree CW<br>
 <b>R:</b>       Draw Rectangle (when in Edit Mode)<br>
 <b>S:</b>       Shell Toggle<br>
-<b>T:</b>       Transformation<br>
 <b>V:</b>       View Fit<br>
 <b>X:</b>       Flip on X_axis<br>
 <b>Y:</b>       Flip on Y_axis<br>
@@ -3720,14 +3791,28 @@ class App(QtCore.QObject):
 <b>CTRL+C:</b>   Copy Obj<br>
 <b>CTRL+E:</b>   Open Excellon File<br>
 <b>CTRL+G:</b>   Open Gerber File<br>
+<b>CTRL+N:</b>   New Project<br>
 <b>CTRL+M:</b>   Measurement Tool<br>
 <b>CTRL+O:</b>   Open Project<br>
 <b>CTRL+S:</b>   Save Project As<br>
 <b>CTRL+S:</b>   Save Object and Exit Editor (when in Edit Mode)<br>
 <br>
+<b>SHIFT+C:</b>  Copy Obj_Name<br>
 <b>SHIFT+G:</b>  Toggle the axis<br>
+<b>SHIFT+P:</b>  Open Preferences Window<br>
 <b>SHIFT+R:</b>  Rotate by 90 degree CCW<br>
 <b>SHIFT+W:</b>  Toggle the workspace<br>
+<b>SHIFT+X:</b>  Skew on X axis<br>
+<b>SHIFT+Y:</b>  Skew on Y axis<br>
+<br>
+<b>ALT+C:</b>    Calculators Tool<br>
+<b>ALT+D:</b>    2-Sided PCB Tool<br>
+<b>ALT+L:</b>    Film PCB Tool<br>
+<b>ALT+N:</b>    Non-Copper Clearing Tool<br>
+<b>ALT+P:</b>    Paint Area Tool<br>
+<b>ALT+R:</b>    Transformation Tool<br>
+<b>ALT+U:</b>    Cutout PCB Tool<br>
+<b>ALT+Z:</b>    Panelize PCB Tool<br>
 <b>Del:</b>      Delete Obj'''
 
         helpbox = QtWidgets.QMessageBox()
@@ -3740,7 +3825,13 @@ class App(QtCore.QObject):
 
     def on_copy_name(self):
         obj = self.collection.get_active()
-        name = obj.options["name"]
+        try:
+            name = obj.options["name"]
+        except AttributeError:
+            log.debug("on_copy_name() --> No object selected to copy it's name")
+            self.inform.emit("[warning_notcl]No object selected to copy it's name")
+            return
+
         self.clipboard.setText(name)
         self.inform.emit("Name copied on clipboard ...")
 
@@ -4093,13 +4184,16 @@ class App(QtCore.QObject):
                            "Do you want to Save the project?")
             msgbox.setWindowTitle("Save changes")
             msgbox.setWindowIcon(QtGui.QIcon('share/save_as.png'))
-            msgbox.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Ok)
+            msgbox.setStandardButtons(QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.Yes |
+                                      QtWidgets.QMessageBox.No)
             msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
 
             response = msgbox.exec_()
 
-            if response == QtWidgets.QMessageBox.Ok:
+            if response == QtWidgets.QMessageBox.Yes:
                 self.on_file_saveprojectas()
+            elif response == QtWidgets.QMessageBox.Cancel:
+                return
             self.on_file_new()
         else:
             self.on_file_new()
@@ -4963,7 +5057,7 @@ class App(QtCore.QObject):
             return "Could not retrieve object: %s" % obj_name
 
         # updated units
-        units = self.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.general_options_form.general_app_group.units_radio.get_value().upper()
         if units == 'IN' or units == 'INCH':
             units = 'INCH'
 
@@ -5056,7 +5150,7 @@ class App(QtCore.QObject):
             return "Could not retrieve object: %s" % obj_name
 
         # updated units
-        units = self.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.general_options_form.general_app_group.units_radio.get_value().upper()
         if units == 'IN' or units == 'INCH':
             units = 'INCH'
         elif units == 'MM' or units == 'METIRC':
@@ -5109,7 +5203,7 @@ class App(QtCore.QObject):
                              "Only Geometry and Gerber are supported")
             return
 
-        units = self.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.general_options_form.general_app_group.units_radio.get_value().upper()
 
         def obj_init(geo_obj, app_obj):
             geo_obj.import_svg(filename, obj_type, units=units)
@@ -5150,7 +5244,7 @@ class App(QtCore.QObject):
                              "Only Geometry and Gerber are supported")
             return
 
-        units = self.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.general_options_form.general_app_group.units_radio.get_value().upper()
 
         def obj_init(geo_obj, app_obj):
             geo_obj.import_dxf(filename, obj_type, units=units)
@@ -5197,7 +5291,7 @@ class App(QtCore.QObject):
 
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
-            units = self.general_options_form.general_group.units_radio.get_value()
+            units = self.general_options_form.general_app_group.units_radio.get_value()
 
             self.new_object(obj_type, name, obj_init)
             self.progress.emit(20)
@@ -5886,7 +5980,7 @@ class App(QtCore.QObject):
 
         self.log.debug("version_check()")
 
-        if self.general_defaults_form.general_group.send_stats_cb.get_value() is True:
+        if self.general_defaults_form.general_gui_group.send_stats_cb.get_value() is True:
             full_url = App.version_url + \
                        "?s=" + str(self.defaults['global_serial']) + \
                        "&v=" + str(self.version) + \

+ 21 - 9
FlatCAMEditor.py

@@ -291,7 +291,7 @@ class TextInputTool(FlatCAMTool):
                     font_name=self.font_name,
                     font_size=font_to_geo_size,
                     font_type=font_to_geo_type,
-                    units=self.app.general_options_form.general_group.units_radio.get_value().upper())
+                    units=self.app.general_options_form.general_app_group.units_radio.get_value().upper())
 
     def font_family(self, font):
         self.text_input_entry.selectAll()
@@ -1143,6 +1143,7 @@ class FCMove(FCShapeTool):
         self.start_msg = "Click on reference point."
 
     def set_origin(self, origin):
+        self.draw_app.app.inform.emit("Click on destination point.")
         self.origin = origin
 
     def click(self, point):
@@ -1901,6 +1902,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
         self.app.ui.geo_cutpath_btn.triggered.connect(self.cutpath)
         self.app.ui.geo_delete_btn.triggered.connect(self.on_delete_btn)
 
+        self.app.ui.geo_move_menuitem.triggered.connect(self.on_move)
+        self.app.ui.geo_cornersnap_menuitem.triggered.connect(self.on_corner_snap)
+
         ## Toolbar events and properties
         self.tools = {
             "select": {"button": self.app.ui.geo_select_btn,
@@ -2596,14 +2600,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
 
         # Corner Snap
         if event.key.name == 'K':
-            self.app.ui.corner_snap_btn.trigger()
+            self.on_corner_snap()
 
         # Move
         if event.key.name == 'M':
-            self.app.ui.geo_move_btn.setChecked(True)
-            self.on_tool_select('move')
-            self.active_tool.set_origin(self.snap(self.x, self.y))
-            self.app.inform.emit("Click on target point.")
+            self.on_move_click()
 
         # Polygon Tool
         if event.key.name == 'N':
@@ -2718,6 +2719,17 @@ class FlatCAMGeoEditor(QtCore.QObject):
         if shape in self.selected:
             self.selected.remove(shape)  # TODO: Check performance
 
+    def on_move(self):
+        self.app.ui.geo_move_btn.setChecked(True)
+        self.on_tool_select('move')
+
+    def on_move_click(self):
+        self.on_move()
+        self.active_tool.set_origin(self.snap(self.x, self.y))
+
+    def on_corner_snap(self):
+        self.app.ui.corner_snap_btn.trigger()
+
     def get_selected(self):
         """
         Returns list of shapes that are selected in the editor.
@@ -3638,7 +3650,7 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.move_timer.setSingleShot(True)
 
         ## Current application units in Upper Case
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         self.key = None  # Currently pressed key
         self.modifiers = None
@@ -3712,7 +3724,7 @@ class FlatCAMExcEditor(QtCore.QObject):
 
     def set_ui(self):
         # updated units
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         self.olddia_newdia.clear()
         self.tool2tooldia.clear()
@@ -3752,7 +3764,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             pass
 
         # updated units
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         # make a new name for the new Excellon object (the one with edited content)
         self.edited_obj_name = self.exc_obj.options['name']

+ 201 - 129
FlatCAMGUI.py

@@ -36,22 +36,24 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menufile = self.menu.addMenu('&File')
 
         # New
-        self.menufilenew = QtWidgets.QAction(QtGui.QIcon('share/file16.png'), '&New Project', self)
+        self.menufilenew = QtWidgets.QAction(QtGui.QIcon('share/file16.png'), '&New Project ...\tCTRL+N', self)
         self.menufile.addAction(self.menufilenew)
 
         self.menufile_open = self.menufile.addMenu(QtGui.QIcon('share/folder32_bis.png'), 'Open')
         # Open gerber ...
-        self.menufileopengerber = QtWidgets.QAction(QtGui.QIcon('share/flatcam_icon24.png'), 'Open &Gerber ...', self)
+        self.menufileopengerber = QtWidgets.QAction(QtGui.QIcon('share/flatcam_icon24.png'),
+                                                    'Open &Gerber ...\tCTRL+G', self)
         self.menufile_open.addAction(self.menufileopengerber)
 
         # Open gerber with follow...
         self.menufileopengerber_follow = QtWidgets.QAction(QtGui.QIcon('share/flatcam_icon24.png'),
-                                                       'Open &Gerber (w/ Follow)', self)
+                                                       'Open &Gerber (w/ Follow) ...', self)
         self.menufile_open.addAction(self.menufileopengerber_follow)
         self.menufile_open.addSeparator()
 
         # Open Excellon ...
-        self.menufileopenexcellon = QtWidgets.QAction(QtGui.QIcon('share/open_excellon32.png'), 'Open &Excellon ...',
+        self.menufileopenexcellon = QtWidgets.QAction(QtGui.QIcon('share/open_excellon32.png'),
+                                                      'Open &Excellon ...\tCTRL+E',
                                                   self)
         self.menufile_open.addAction(self.menufileopenexcellon)
 
@@ -70,7 +72,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menufile.addSeparator()
 
         # Run Scripts
-        self.menufilerunscript = QtWidgets.QAction(QtGui.QIcon('share/script16.png'), 'Run Script', self)
+        self.menufilerunscript = QtWidgets.QAction(QtGui.QIcon('share/script16.png'), 'Run Script ...', self)
         self.menufile.addAction(self.menufilerunscript)
 
         # Separator
@@ -79,18 +81,18 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # Import ...
         self.menufileimport = self.menufile.addMenu(QtGui.QIcon('share/import.png'), 'Import')
         self.menufileimportsvg = QtWidgets.QAction(QtGui.QIcon('share/svg16.png'),
-                                               '&SVG as Geometry Object', self)
+                                               '&SVG as Geometry Object ...', self)
         self.menufileimport.addAction(self.menufileimportsvg)
         self.menufileimportsvg_as_gerber = QtWidgets.QAction(QtGui.QIcon('share/svg16.png'),
-                                                         '&SVG as Gerber Object', self)
+                                                         '&SVG as Gerber Object ...', self)
         self.menufileimport.addAction(self.menufileimportsvg_as_gerber)
         self.menufileimport.addSeparator()
 
         self.menufileimportdxf = QtWidgets.QAction(QtGui.QIcon('share/dxf16.png'),
-                                               '&DXF as Geometry Object', self)
+                                               '&DXF as Geometry Object ...', self)
         self.menufileimport.addAction(self.menufileimportdxf)
         self.menufileimportdxf_as_gerber = QtWidgets.QAction(QtGui.QIcon('share/dxf16.png'),
-                                                         '&DXF as Gerber Object', self)
+                                                         '&DXF as Gerber Object ...', self)
         self.menufileimport.addAction(self.menufileimportdxf_as_gerber)
         self.menufileimport.addSeparator()
 
@@ -128,11 +130,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
         self.menufile_save = self.menufile.addMenu(QtGui.QIcon('share/save_as.png'), 'Save')
         # Save Project
-        self.menufilesaveproject = QtWidgets.QAction(QtGui.QIcon('share/floppy16.png'), '&Save Project', self)
+        self.menufilesaveproject = QtWidgets.QAction(QtGui.QIcon('share/floppy16.png'), '&Save Project ...', self)
         self.menufile_save.addAction(self.menufilesaveproject)
 
         # Save Project As ...
-        self.menufilesaveprojectas = QtWidgets.QAction(QtGui.QIcon('share/save_as.png'), 'Save Project &As ...', self)
+        self.menufilesaveprojectas = QtWidgets.QAction(QtGui.QIcon('share/save_as.png'),
+                                                       'Save Project &As ...\tCTRL+S', self)
         self.menufile_save.addAction(self.menufilesaveprojectas)
 
         # Save Project Copy ...
@@ -151,12 +154,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
         ### Edit ###
         self.menuedit = self.menu.addMenu('&Edit')
-        self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), '&New Geometry')
-        self.menueditnewexc = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Excellon')
+        self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), '&New Geometry\tN')
+        self.menueditnewexc = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Excellon\tX')
         # Separator
         self.menuedit.addSeparator()
-        self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Object')
-        self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), '&Update Object')
+        self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Object\tE')
+        self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), '&Update Object\tCTRL+S')
         # Separator
         self.menuedit.addSeparator()
         self.menuedit_convert = self.menuedit.addMenu(QtGui.QIcon('share/convert24.png'), 'Conversion')
@@ -185,29 +188,31 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
             "Will convert a Geometry object from multi_geometry type\n"
             "to a single_geometry type.")
         self.menuedit_convert.setToolTipsVisible(True)
-        # Separator
-        self.menuedit.addSeparator()
-        self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), '&Delete')
 
         # Separator
         self.menuedit.addSeparator()
-        self.menueditcopyobject = self.menuedit.addAction(QtGui.QIcon('share/copy.png'), '&Copy Object')
+        self.menueditcopyobject = self.menuedit.addAction(QtGui.QIcon('share/copy.png'), '&Copy Object\tCTRL+C')
         self.menueditcopyobjectasgeom = self.menuedit.addAction(QtGui.QIcon('share/copy_geo.png'),
                                                                 'Copy as &Geom')
+        # Separator
+        self.menuedit.addSeparator()
+        self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), '&Delete\tDEL')
 
         # Separator
         self.menuedit.addSeparator()
-        self.menueditorigin = self.menuedit.addAction(QtGui.QIcon('share/origin.png'), 'Se&t Origin')
-        self.menueditjump = self.menuedit.addAction(QtGui.QIcon('share/jump_to16.png'), 'Jump to Location')
+        self.menueditorigin = self.menuedit.addAction(QtGui.QIcon('share/origin.png'), 'Se&t Origin\tO')
+        self.menueditjump = self.menuedit.addAction(QtGui.QIcon('share/jump_to16.png'), 'Jump to Location\tJ')
 
         # Separator
         self.menuedit.addSeparator()
+        self.menuedittoggleunits= self.menuedit.addAction(QtGui.QIcon('share/toggle_units16.png'),
+                                                         'Toggle Units\tQ')
         self.menueditselectall = self.menuedit.addAction(QtGui.QIcon('share/select_all.png'),
-                                                         '&Select All')
+                                                         '&Select All\tCTRL+A')
 
         # Separator
         self.menuedit.addSeparator()
-        self.menueditpreferences = self.menuedit.addAction(QtGui.QIcon('share/pref.png'), '&Preferences')
+        self.menueditpreferences = self.menuedit.addAction(QtGui.QIcon('share/pref.png'), '&Preferences\tSHIFT+P')
 
         ### Options ###
         self.menuoptions = self.menu.addMenu('&Options')
@@ -225,21 +230,21 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # self.menuoptions_transform = self.menuoptions.addMenu(QtGui.QIcon('share/transform.png'),
         #                                                       '&Transform Object')
         self.menuoptions_transform_rotate = self.menuoptions.addAction(QtGui.QIcon('share/rotate.png'),
-                                                                                 "&Rotate Selection")
+                                                                                 "&Rotate Selection\tSHIFT+(R)")
         # Separator
         self.menuoptions.addSeparator()
 
         self.menuoptions_transform_skewx = self.menuoptions.addAction(QtGui.QIcon('share/skewX.png'),
-                                                                                "&Skew on X axis")
+                                                                                "&Skew on X axis\tSHIFT+X")
         self.menuoptions_transform_skewy = self.menuoptions.addAction(QtGui.QIcon('share/skewY.png'),
-                                                                                "S&kew on Y axis")
+                                                                                "S&kew on Y axis\tSHIFT+Y")
 
         # Separator
         self.menuoptions.addSeparator()
         self.menuoptions_transform_flipx = self.menuoptions.addAction(QtGui.QIcon('share/flipx.png'),
-                                                                                "Flip on &X axis")
+                                                                                "Flip on &X axis\tX")
         self.menuoptions_transform_flipy = self.menuoptions.addAction(QtGui.QIcon('share/flipy.png'),
-                                                                                "Flip on &Y axis")
+                                                                                "Flip on &Y axis\tY")
         # Separator
         self.menuoptions.addSeparator()
 
@@ -252,14 +257,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
                                                             'Disable non-selected')
         # Separator
         self.menuview.addSeparator()
-        self.menuview_zoom_fit = self.menuview.addAction(QtGui.QIcon('share/zoom_fit32.png'), "&Zoom Fit")
-        self.menuview_zoom_in = self.menuview.addAction(QtGui.QIcon('share/zoom_in32.png'), "&Zoom In")
-        self.menuview_zoom_out = self.menuview.addAction(QtGui.QIcon('share/zoom_out32.png'), "&Zoom Out")
+        self.menuview_zoom_fit = self.menuview.addAction(QtGui.QIcon('share/zoom_fit32.png'), "&Zoom Fit\t1")
+        self.menuview_zoom_in = self.menuview.addAction(QtGui.QIcon('share/zoom_in32.png'), "&Zoom In\t2")
+        self.menuview_zoom_out = self.menuview.addAction(QtGui.QIcon('share/zoom_out32.png'), "&Zoom Out\t3")
 
         self.menuview.addSeparator()
-        self.menuview_toggle_axis = self.menuview.addAction(QtGui.QIcon('share/axis32.png'), "&Toggle Axis")
+        self.menuview_toggle_grid = self.menuview.addAction(QtGui.QIcon('share/grid32.png'), "&Toggle Grid\tG")
+        self.menuview_toggle_axis = self.menuview.addAction(QtGui.QIcon('share/axis32.png'), "&Toggle Axis\tSHIFT+G")
         self.menuview_toggle_workspace = self.menuview.addAction(QtGui.QIcon('share/workspace24.png'),
-                                                                 "Toggle Workspace")
+                                                                 "Toggle Workspace\tSHIFT+W")
 
 
         ### FlatCAM Editor menu ###
@@ -269,28 +275,46 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menu.addMenu(self.geo_editor_menu)
 
         # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share/pointer16.png'), "Select 'Esc'")
-        self.geo_add_circle_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/circle32.png'), 'Add Circle')
-        self.geo_add_arc_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/arc16.png'), 'Add Arc')
+        self.geo_add_circle_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/circle32.png'), 'Add Circle\tO'
+        )
+        self.geo_add_arc_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/arc16.png'), 'Add Arc\tA')
         self.geo_editor_menu.addSeparator()
-        self.geo_add_rectangle_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle')
-        self.geo_add_polygon_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon')
-        self.geo_add_path_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/path32.png'), 'Add Path')
+        self.geo_add_rectangle_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle\tR'
+        )
+        self.geo_add_polygon_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/polygon32.png'), 'Add Polygon\tN'
+        )
+        self.geo_add_path_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/path32.png'), 'Add Path\tP')
         self.geo_editor_menu.addSeparator()
-        self.geo_add_text_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/text32.png'), 'Add Text')
+        self.geo_add_text_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/text32.png'), 'Add Text\tT')
         self.geo_editor_menu.addSeparator()
         self.geo_union_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/union16.png'), 'Polygon Union')
         self.geo_intersection_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/intersection16.png'),
                                                          'Polygon Intersection')
-        self.geo_subtract_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/subtract16.png'), 'Polygon Subtraction')
+        self.geo_subtract_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/subtract16.png'), 'Polygon Subtraction'
+        )
         self.geo_editor_menu.addSeparator()
-        self.geo_cutpath_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/cutpath16.png'), 'Cut Path')
+        self.geo_cutpath_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/cutpath16.png'), 'Cut Path\tX')
         # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share/move16.png'), "Move Objects 'm'")
-        self.geo_copy_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/copy16.png'), "Copy Geom")
-        self.geo_delete_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/deleteshape16.png'), "Delete Shape")
+        self.geo_copy_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/copy16.png'), "Copy Geom\tC")
+        self.geo_delete_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/deleteshape16.png'), "Delete Shape\tDEL"
+        )
         self.geo_editor_menu.addSeparator()
-        self.geo_buffer_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/buffer16.png'), "Buffer Selection")
-        self.geo_paint_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/paint16.png'), "Paint Selection")
+        self.geo_move_menuitem = self.geo_editor_menu.addAction(QtGui.QIcon('share/move32.png'), "Move\tM")
+        self.geo_buffer_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/buffer16.png'), "Buffer Selection\tB"
+        )
+        self.geo_paint_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/paint16.png'), "Paint Selection\tI"
+        )
         self.geo_editor_menu.addSeparator()
+        self.geo_cornersnap_menuitem = self.geo_editor_menu.addAction(
+            QtGui.QIcon('share/corner32.png'), "Toggle Corner Snap\tK"
+        )
 
         # self.exc_editor_menu = QtWidgets.QMenu("Excellon Editor")
         # self.menu.addMenu(self.exc_editor_menu)
@@ -302,7 +326,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # self.menutool = self.menu.addMenu('&Tool')
         self.menutool = QtWidgets.QMenu('&Tool')
         self.menutoolaction = self.menu.addMenu(self.menutool)
-        self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), '&Command Line')
+        self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), '&Command Line\tS')
 
         ### Help ###
         self.menuhelp = self.menu.addMenu('&Help')
@@ -655,6 +679,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.draw_line = self.g_editor_cmenu.addAction(QtGui.QIcon('share/path32.png'), "Line")
         self.draw_rect = self.g_editor_cmenu.addAction(QtGui.QIcon('share/rectangle32.png'), "Rectangle")
         self.draw_cut = self.g_editor_cmenu.addAction(QtGui.QIcon('share/cutpath32.png'), "Cut")
+        self.g_editor_cmenu.addSeparator()
+        self.draw_move = self.g_editor_cmenu.addAction(QtGui.QIcon('share/move32.png'), "Move")
 
         self.e_editor_cmenu = self.popMenu.addMenu(QtGui.QIcon('share/drill32.png'), "Exc Editor")
         self.drill = self.e_editor_cmenu.addAction(QtGui.QIcon('share/drill32.png'), "Add Drill")
@@ -844,18 +870,29 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         # self.splitter.sizes()[0] is actually the size of the "notebook"
         self.geom_update.emit(grect.x(), grect.y(), grect.width(), grect.height(), self.splitter.sizes()[0])
         self.final_save.emit()
-        QtWidgets.qApp.quit()
+
+        if self.app.should_we_quit is True:
+            QtWidgets.qApp.quit()
+        else:
+            self.app.should_we_quit = True
+            event.ignore()
 
 
 class GeneralPreferencesUI(QtWidgets.QWidget):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent=parent)
-        self.layout = QtWidgets.QVBoxLayout()
+        self.layout = QtWidgets.QHBoxLayout()
         self.setLayout(self.layout)
 
-        self.general_group = GeneralPrefGroupUI()
-        self.general_group.setFixedWidth(260)
-        self.layout.addWidget(self.general_group)
+        self.general_app_group = GeneralAppPrefGroupUI()
+        self.general_app_group.setFixedWidth(260)
+
+        self.general_gui_group = GeneralGUIPrefGroupUI()
+        self.general_gui_group.setFixedWidth(260)
+
+        self.layout.addWidget(self.general_app_group)
+        self.layout.addWidget(self.general_gui_group)
+        self.layout.addStretch()
 
 
 class GerberPreferencesUI(QtWidgets.QWidget):
@@ -922,59 +959,15 @@ class OptionsGroupUI(QtWidgets.QGroupBox):
         self.setLayout(self.layout)
 
 
-class GeneralPrefGroupUI(OptionsGroupUI):
+class GeneralGUIPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
-        super(GeneralPrefGroupUI, self).__init__(self)
+        super(GeneralGUIPrefGroupUI, self).__init__(self)
 
-        self.setTitle(str("Global Preferences"))
+        self.setTitle(str("GUI Preferences"))
 
         # Create a form layout for the Application general settings
         self.form_box = QtWidgets.QFormLayout()
 
-        # Units for FlatCAM
-        self.unitslabel = QtWidgets.QLabel('<b>Units:</b>')
-        self.unitslabel.setToolTip("Those are units in which FlatCAM works.")
-        self.units_radio = RadioSet([{'label': 'IN', 'value': 'IN'},
-                                     {'label': 'MM', 'value': 'MM'}])
-
-        # Shell StartUp CB
-        self.shell_startup_label = QtWidgets.QLabel('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.setToolTip(
-            "Check this box if you want the shell to\n"
-            "start automatically at startup."
-        )
-
-        # Version Check CB
-        self.version_check_label = QtWidgets.QLabel('Version Check:')
-        self.version_check_label.setToolTip(
-            "Check this box if you want to check\n"
-            "for a new version automatically at startup."
-        )
-        self.version_check_cb = FCCheckBox(label='')
-        self.version_check_cb.setToolTip(
-            "Check this box if you want to check\n"
-            "for a new version automatically at startup."
-        )
-
-        # Send Stats CB
-        self.send_stats_label = QtWidgets.QLabel('Send Stats:')
-        self.send_stats_label.setToolTip(
-            "Check this box if you agree to send anonymous\n"
-            "stats automatically at startup, to help improve FlatCAM."
-        )
-        self.send_stats_cb= FCCheckBox(label='')
-        self.send_stats_cb.setToolTip(
-            "Check this box if you agree to send anonymous\n"
-            "stats automatically at startup, to help improve FlatCAM."
-        )
-
-        self.ois_version_check = OptionalInputSection(self.version_check_cb, [self.send_stats_cb])
-
         # Grid X Entry
         self.gridx_label = QtWidgets.QLabel('Grid X value:')
         self.gridx_label.setToolTip(
@@ -989,30 +982,6 @@ class GeneralPrefGroupUI(OptionsGroupUI):
         )
         self.gridy_entry = LengthEntry()
 
-        # Select mouse pan button
-        self.panbuttonlabel = QtWidgets.QLabel('<b>Pan Button:</b>')
-        self.panbuttonlabel.setToolTip("Select the mouse button to use for panning.")
-        self.pan_button_radio = RadioSet([{'label': 'Middle But.', 'value': '3'},
-                                     {'label': 'Right But.', 'value': '2'}])
-
-        # Multiple Selection Modifier Key
-        self.mselectlabel = QtWidgets.QLabel('<b>Multiple Sel:</b>')
-        self.mselectlabel.setToolTip("Select the key used for multiple selection.")
-        self.mselect_radio = RadioSet([{'label': 'CTRL', 'value': 'Control'},
-                                     {'label': 'SHIFT', 'value': 'Shift'}])
-
-        # # Mouse panning with "Space" key, CB
-        # self.pan_with_space_label = QtWidgets.QLabel('Pan w/ Space:')
-        # self.pan_with_space_label.setToolTip(
-        #     "Check this box if you want to pan when mouse is moved,\n"
-        #     "and key 'Space' is pressed."
-        # )
-        # self.pan_with_space_cb = FCCheckBox(label='')
-        # self.pan_with_space_cb.setToolTip(
-        #     "Check this box if you want to pan when mouse is moved,\n"
-        #     "and key 'Space' is pressed."
-        # )
-
         # Workspace
         self.workspace_lbl = QtWidgets.QLabel('Workspace:')
         self.workspace_lbl.setToolTip(
@@ -1214,17 +1183,12 @@ class GeneralPrefGroupUI(OptionsGroupUI):
         self.spacelabel = QtWidgets.QLabel('')
 
         # Add (label - input field) pair to the QFormLayout
-        self.form_box.addRow(self.unitslabel, self.units_radio)
+
         self.form_box.addRow(self.spacelabel, self.spacelabel)
-        self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
-        self.form_box.addRow(self.version_check_label, self.version_check_cb)
-        self.form_box.addRow(self.send_stats_label, self.send_stats_cb)
 
         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.panbuttonlabel, self.pan_button_radio)
-        self.form_box.addRow(self.mselectlabel, self.mselect_radio)
-        # self.form_box.addRow(self.pan_with_space_label, self.pan_with_space_cb)
+
         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.spacelabel, self.spacelabel)
@@ -1245,6 +1209,114 @@ class GeneralPrefGroupUI(OptionsGroupUI):
         self.layout.addLayout(self.form_box)
 
 
+class GeneralAppPrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+        super(GeneralAppPrefGroupUI, self).__init__(self)
+
+        self.setTitle(str("App Preferences"))
+
+        # Create a form layout for the Application general settings
+        self.form_box = QtWidgets.QFormLayout()
+
+        # Units for FlatCAM
+        self.unitslabel = QtWidgets.QLabel('<b>Units:</b>')
+        self.unitslabel.setToolTip("Those are units in which FlatCAM works.")
+        self.units_radio = RadioSet([{'label': 'IN', 'value': 'IN'},
+                                     {'label': 'MM', 'value': 'MM'}])
+
+        # Languages for FlatCAM
+        self.languagelabel = QtWidgets.QLabel('<b>Languages:</b>')
+        self.languagelabel.setToolTip("Set the language used for FlatCAM texts.")
+        self.language_cb = FCComboBox()
+        self.languagespace = QtWidgets.QLabel('')
+        self.language_apply_btn = FCButton("Apply Language")
+
+        # Shell StartUp CB
+        self.shell_startup_label = QtWidgets.QLabel('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.setToolTip(
+            "Check this box if you want the shell to\n"
+            "start automatically at startup."
+        )
+
+        # Version Check CB
+        self.version_check_label = QtWidgets.QLabel('Version Check:')
+        self.version_check_label.setToolTip(
+            "Check this box if you want to check\n"
+            "for a new version automatically at startup."
+        )
+        self.version_check_cb = FCCheckBox(label='')
+        self.version_check_cb.setToolTip(
+            "Check this box if you want to check\n"
+            "for a new version automatically at startup."
+        )
+
+        # Send Stats CB
+        self.send_stats_label = QtWidgets.QLabel('Send Stats:')
+        self.send_stats_label.setToolTip(
+            "Check this box if you agree to send anonymous\n"
+            "stats automatically at startup, to help improve FlatCAM."
+        )
+        self.send_stats_cb= FCCheckBox(label='')
+        self.send_stats_cb.setToolTip(
+            "Check this box if you agree to send anonymous\n"
+            "stats automatically at startup, to help improve FlatCAM."
+        )
+
+        self.ois_version_check = OptionalInputSection(self.version_check_cb, [self.send_stats_cb])
+
+        # Select mouse pan button
+        self.panbuttonlabel = QtWidgets.QLabel('<b>Pan Button:</b>')
+        self.panbuttonlabel.setToolTip("Select the mouse button to use for panning.")
+        self.pan_button_radio = RadioSet([{'label': 'Middle But.', 'value': '3'},
+                                     {'label': 'Right But.', 'value': '2'}])
+
+        # Multiple Selection Modifier Key
+        self.mselectlabel = QtWidgets.QLabel('<b>Multiple Sel:</b>')
+        self.mselectlabel.setToolTip("Select the key used for multiple selection.")
+        self.mselect_radio = RadioSet([{'label': 'CTRL', 'value': 'Control'},
+                                     {'label': 'SHIFT', 'value': 'Shift'}])
+
+        # # Mouse panning with "Space" key, CB
+        # self.pan_with_space_label = QtWidgets.QLabel('Pan w/ Space:')
+        # self.pan_with_space_label.setToolTip(
+        #     "Check this box if you want to pan when mouse is moved,\n"
+        #     "and key 'Space' is pressed."
+        # )
+        # self.pan_with_space_cb = FCCheckBox(label='')
+        # self.pan_with_space_cb.setToolTip(
+        #     "Check this box if you want to pan when mouse is moved,\n"
+        #     "and key 'Space' is pressed."
+        # )
+
+
+        # Just to add empty rows
+        self.spacelabel = QtWidgets.QLabel('')
+
+        # Add (label - input field) pair to the QFormLayout
+        self.form_box.addRow(self.unitslabel, self.units_radio)
+        self.form_box.addRow(self.languagelabel, self.language_cb)
+        self.form_box.addRow(self.languagespace, self.language_apply_btn)
+
+        self.form_box.addRow(self.spacelabel, self.spacelabel)
+        self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
+        self.form_box.addRow(self.version_check_label, self.version_check_cb)
+        self.form_box.addRow(self.send_stats_label, self.send_stats_cb)
+
+        self.form_box.addRow(self.panbuttonlabel, self.pan_button_radio)
+        self.form_box.addRow(self.mselectlabel, self.mselect_radio)
+        # self.form_box.addRow(self.pan_with_space_label, self.pan_with_space_cb)
+        self.form_box.addRow(self.spacelabel, self.spacelabel)
+
+        # Add the QFormLayout that holds the Application general defaults
+        # to the main layout of this TAB
+        self.layout.addLayout(self.form_box)
+
+
 class GerberPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
         # OptionsGroupUI.__init__(self, "Gerber Options", parent=parent)

+ 3 - 3
FlatCAMObj.py

@@ -1295,7 +1295,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         """
 
         excellon_code = ''
-        units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         # store here if the file has slots, return 1 if any slots, 0 if only drills
         has_slots = 0
@@ -1355,7 +1355,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         """
 
         excellon_code = ''
-        units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         # store here if the file has slots, return 1 if any slots, 0 if only drills
         has_slots = 0
@@ -2862,7 +2862,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.ui.geo_tools_table.setCurrentItem(self.ui.geo_tools_table.item(row, 0))
 
     def export_dxf(self):
-        units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
         dwg = None
         try:
             dwg = ezdxf.new('R2010')

+ 7 - 2
FlatCAMTool.py

@@ -33,7 +33,7 @@ class FlatCAMTool(QtWidgets.QWidget):
 
         self.menuAction = None
 
-    def install(self, icon=None, separator=None, **kwargs):
+    def install(self, icon=None, separator=None, shortcut=None, **kwargs):
         before = None
 
         # 'pos' is the menu where the Action has to be installed
@@ -54,8 +54,13 @@ class FlatCAMTool(QtWidgets.QWidget):
         # if provided, add an icon to this Action
         if icon is not None:
             self.menuAction.setIcon(icon)
+
         # set the text name of the Action, which will be displayed in the menu
-        self.menuAction.setText(self.toolName)
+        if shortcut is None:
+            self.menuAction.setText(self.toolName)
+        else:
+            self.menuAction.setText(self.toolName + '\t%s' % shortcut)
+
         # add a ToolTip to the new Action
         # self.menuAction.setToolTip(self.toolTip) # currently not available
 

+ 60 - 6
ObjectCollection.py

@@ -262,6 +262,9 @@ class ObjectCollection(QtCore.QAbstractItemModel):
             if key == QtCore.Qt.Key_G:
                 self.app.on_fileopengerber()
 
+            if key == QtCore.Qt.Key_N:
+                self.app.on_file_new_click()
+
             if key == QtCore.Qt.Key_M:
                 self.app.measurement_tool.run()
             if key == QtCore.Qt.Key_O:
@@ -272,6 +275,11 @@ class ObjectCollection(QtCore.QAbstractItemModel):
             return
         elif modifiers == QtCore.Qt.ShiftModifier:
 
+            # Copy Object Name
+            # Copy Object Name
+            if key == QtCore.Qt.Key_C:
+                self.app.on_copy_name()
+
             # Toggle axis
             if key == QtCore.Qt.Key_G:
                 if self.toggle_axis is False:
@@ -286,11 +294,51 @@ class ObjectCollection(QtCore.QAbstractItemModel):
                     self.appplotcanvas.redraw()
                     self.app.toggle_axis = False
 
+            # Open Preferences Window
+            if key == QtCore.Qt.Key_P:
+                self.app.on_preferences()
+                return
+
             # Rotate Object by 90 degree CCW
             if key == QtCore.Qt.Key_R:
                 self.app.on_rotate(silent=True, preset=-90)
                 return
 
+            # Toggle Workspace
+            if key == QtCore.Qt.Key_W:
+                self.app.on_workspace_menu()
+                return
+
+            # Skew on X axis
+            if key == QtCore.Qt.Key_X:
+                self.app.on_skewx()
+                return
+
+            # Skew on Y axis
+            if key == QtCore.Qt.Key_Y:
+                self.app.on_skewy()
+                return
+        elif modifiers == QtCore.Qt.AltModifier:
+            # 2-Sided PCB Tool
+            if key == QtCore.Qt.Key_D:
+                self.app.dblsidedtool.run()
+                return
+
+            # Non-Copper Clear Tool
+            if key == QtCore.Qt.Key_N:
+                self.app.ncclear_tool.run()
+                return
+
+            # Transformation Tool
+            if key == QtCore.Qt.Key_R:
+                self.app.measurement_tool.run()
+                return
+
+            # Cutout Tool
+            if key == QtCore.Qt.Key_U:
+                self.app.cutout_tool.run()
+                return
+
         else:
             # Zoom Fit
             if key == QtCore.Qt.Key_1:
@@ -316,10 +364,6 @@ class ObjectCollection(QtCore.QAbstractItemModel):
                     select.ui.plot_cb.toggle()
                 self.app.delete_selection_shape()
 
-            # Copy Object Name
-            if key == QtCore.Qt.Key_C:
-                self.app.on_copy_name()
-
             # Copy Object Name
             if key == QtCore.Qt.Key_E:
                 self.app.object2editor()
@@ -340,12 +384,22 @@ class ObjectCollection(QtCore.QAbstractItemModel):
             if key == QtCore.Qt.Key_N:
                 self.app.on_new_geometry()
 
+            # Set Origin
+            if key == QtCore.Qt.Key_O:
+                self.app.on_set_origin()
+                return
+
+            # Set Origin
+            if key == QtCore.Qt.Key_P:
+                self.app.properties_tool.run()
+                return
+
             # Change Units
             if key == QtCore.Qt.Key_Q:
                 if self.app.options["units"] == 'MM':
-                    self.app.general_options_form.general_group.units_radio.set_value("IN")
+                    self.app.general_options_form.general_app_group.units_radio.set_value("IN")
                 else:
-                    self.app.general_options_form.general_group.units_radio.set_value("MM")
+                    self.app.general_options_form.general_app_group.units_radio.set_value("MM")
                 self.app.on_toggle_units()
 
             # Rotate Object by 90 degree CW

+ 2 - 2
PlotCanvas.py

@@ -65,7 +65,7 @@ class PlotCanvas(QtCore.QObject):
         self.draw_workspace()
 
         # if self.app.defaults['global_workspace'] is True:
-        #     if self.app.general_options_form.general_group.units_radio.get_value().upper() == 'MM':
+        #     if self.app.general_options_form.general_app_group.units_radio.get_value().upper() == 'MM':
         #         self.wkspace_t = Line(pos=)
 
         self.shape_collections = []
@@ -92,7 +92,7 @@ class PlotCanvas(QtCore.QObject):
         a3p_mm = np.array([(0, 0), (297, 0), (297, 420), (0, 420)])
         a3l_mm = np.array([(0, 0), (420, 0), (420, 297), (0, 297)])
 
-        if self.app.general_options_form.general_group.units_radio.get_value().upper() == 'MM':
+        if self.app.general_options_form.general_app_group.units_radio.get_value().upper() == 'MM':
             if self.app.defaults['global_workspaceT'] == 'A4P':
                 a = a4p_mm
             elif self.app.defaults['global_workspaceT'] == 'A4L':

+ 7 - 0
README.md

@@ -9,6 +9,13 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+27.01.2018
+
+- added more key shortcuts into the application; they are now displayed in the GUI menu's
+- reorganized the Edit -> Preferences -> Global
+- redesigned the messagebox that is showed when quiting ot creating a New Project: now it has an option ('Cancel') to abort the process returning to the app
+
+
 26.01.2019
 
 - fixed grbl_11 postprocessor in linear_code() function

+ 3 - 0
flatcamTools/ToolCalculators.py

@@ -141,6 +141,9 @@ class ToolCalculator(FlatCAMTool):
         FlatCAMTool.run(self)
         self.app.ui.notebook.setTabText(2, "Calc. Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+C', **kwargs)
+
     def on_calculate_tool_dia(self):
         # Calculation:
         # Manufacturer gives total angle of the the tip but we need only half of it

+ 4 - 1
flatcamTools/ToolCutout.py

@@ -9,7 +9,7 @@ from FlatCAMObj import FlatCAMGeometry, FlatCAMExcellon, FlatCAMGerber
 
 class ToolCutout(FlatCAMTool):
 
-    toolName = "Cutout PCB Tool"
+    toolName = "Cutout PCB"
 
     def __init__(self, app):
         FlatCAMTool.__init__(self, app)
@@ -188,6 +188,9 @@ class ToolCutout(FlatCAMTool):
         FlatCAMTool.run(self)
         self.app.ui.notebook.setTabText(2, "Cutout Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+U', **kwargs)
+
     def on_freeform_cutout(self):
 
         def subtract_rectangle(obj_, x0, y0, x1, y1):

+ 4 - 1
flatcamTools/ToolDblSided.py

@@ -8,7 +8,7 @@ from PyQt5 import QtCore
 
 class DblSidedTool(FlatCAMTool):
 
-    toolName = "Double-Sided PCB Tool"
+    toolName = "2-Sided PCB"
 
     def __init__(self, app):
         FlatCAMTool.__init__(self, app)
@@ -254,6 +254,9 @@ class DblSidedTool(FlatCAMTool):
         self.axis_location.set_value('point')
         self.drill_dia.set_value(1)
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+D', **kwargs)
+
     def on_combo_box_type(self):
         obj_type = self.box_combo_type.currentIndex()
         self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))

+ 4 - 1
flatcamTools/ToolFilm.py

@@ -6,7 +6,7 @@ from PyQt5 import QtGui, QtCore, QtWidgets
 
 class Film(FlatCAMTool):
 
-    toolName = "Film PCB Tool"
+    toolName = "Film PCB"
 
     def __init__(self, app):
         FlatCAMTool.__init__(self, app)
@@ -154,6 +154,9 @@ class Film(FlatCAMTool):
         FlatCAMTool.run(self)
         self.app.ui.notebook.setTabText(2, "Film Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+L', **kwargs)
+
     def on_film_creation(self):
         try:
             name = self.tf_object_combo.currentText()

+ 7 - 4
flatcamTools/ToolMeasurement.py

@@ -7,12 +7,12 @@ from math import sqrt
 
 class Measurement(FlatCAMTool):
 
-    toolName = "Measurement Tool"
+    toolName = "Measurement"
 
     def __init__(self, app):
         FlatCAMTool.__init__(self, app)
 
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().lower()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().lower()
 
         ## Title
         title_label = QtWidgets.QLabel("<font size=4><b>%s</b></font><br>" % self.toolName)
@@ -165,10 +165,13 @@ class Measurement(FlatCAMTool):
 
         # Switch notebook to tool page
         self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().lower()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().lower()
         self.show()
         self.app.ui.notebook.setTabText(2, "Meas. Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='CTRL+M', **kwargs)
+
     def on_key_release_meas(self, event):
         if event.key == 'escape':
             # abort the measurement action
@@ -217,7 +220,7 @@ class Measurement(FlatCAMTool):
         else:
             # ENABLE the Measuring TOOL
             self.active = True
-            self.units = self.app.general_options_form.general_group.units_radio.get_value().lower()
+            self.units = self.app.general_options_form.general_app_group.units_radio.get_value().lower()
 
             # we disconnect the mouse/key handlers from wherever the measurement tool was called
             if self.app.call_source == 'app':

+ 1 - 1
flatcamTools/ToolMove.py

@@ -31,7 +31,7 @@ class ToolMove(FlatCAMTool):
         self.sel_shapes = ShapeCollection(parent=self.app.plotcanvas.vispy_canvas.view.scene, layers=1)
 
     def install(self, icon=None, separator=None, **kwargs):
-        FlatCAMTool.install(self, icon, separator, **kwargs)
+        FlatCAMTool.install(self, icon, separator, shortcut='M', **kwargs)
 
     def run(self):
         if self.app.tool_tab_locked is True:

+ 4 - 4
flatcamTools/ToolNonCopperClear.py

@@ -7,7 +7,7 @@ import time
 
 class NonCopperClear(FlatCAMTool, Gerber):
 
-    toolName = "Non-Copper Clearing Tool"
+    toolName = "Non-Copper Clearing"
 
     def __init__(self, app):
         self.app = app
@@ -234,7 +234,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.generate_ncc_button.clicked.connect(self.on_ncc)
 
     def install(self, icon=None, separator=None, **kwargs):
-        FlatCAMTool.install(self, icon, separator, **kwargs)
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+N', **kwargs)
 
     def run(self):
         FlatCAMTool.run(self)
@@ -322,13 +322,13 @@ class NonCopperClear(FlatCAMTool, Gerber):
         self.obj_name = ""
         self.ncc_obj = None
         self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
     def build_ui(self):
         self.ui_disconnect()
 
         # updated units
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         if self.units == "IN":
             self.addtool_entry.set_value(0.039)

+ 4 - 4
flatcamTools/ToolPaint.py

@@ -5,7 +5,7 @@ from ObjectCollection import *
 
 class ToolPaint(FlatCAMTool, Gerber):
 
-    toolName = "Paint Area Tool"
+    toolName = "Paint Area"
 
     def __init__(self, app):
         self.app = app
@@ -290,7 +290,7 @@ class ToolPaint(FlatCAMTool, Gerber):
 
 
     def install(self, icon=None, separator=None, **kwargs):
-        FlatCAMTool.install(self, icon, separator, **kwargs)
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
 
     def run(self):
         FlatCAMTool.run(self)
@@ -327,7 +327,7 @@ class ToolPaint(FlatCAMTool, Gerber):
         self.paintoverlap_entry.set_value(self.default_data["paintoverlap"])
 
         # updated units
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         if self.units == "IN":
             self.addtool_entry.set_value(0.039)
@@ -390,7 +390,7 @@ class ToolPaint(FlatCAMTool, Gerber):
             pass
 
         # updated units
-        self.units = self.app.general_options_form.general_group.units_radio.get_value().upper()
+        self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
 
         sorted_tools = []
         for k, v in self.paint_tools.items():

+ 4 - 1
flatcamTools/ToolPanelize.py

@@ -6,7 +6,7 @@ import time
 
 class Panelize(FlatCAMTool):
 
-    toolName = "Panelize PCB Tool"
+    toolName = "Panelize PCB"
 
     def __init__(self, app):
         super(Panelize, self).__init__(self)
@@ -197,6 +197,9 @@ class Panelize(FlatCAMTool):
         FlatCAMTool.run(self)
         self.app.ui.notebook.setTabText(2, "Panel. Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+Z', **kwargs)
+
     def on_panelize(self):
         name = self.object_combo.currentText()
 

+ 6 - 3
flatcamTools/ToolProperties.py

@@ -53,6 +53,9 @@ class Properties(FlatCAMTool):
         FlatCAMTool.run(self)
         self.properties()
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='P', **kwargs)
+
     def properties(self):
         obj_list = self.app.collection.get_selected()
         if not obj_list:
@@ -86,10 +89,10 @@ class Properties(FlatCAMTool):
         width = abs(ymax - ymin)
 
         self.addChild(dims, ['Length:', '%.4f %s' % (
-            length, self.app.general_options_form.general_group.units_radio.get_value().lower())], True)
+            length, self.app.general_options_form.general_app_group.units_radio.get_value().lower())], True)
         self.addChild(dims, ['Width:', '%.4f %s' % (
-            width, self.app.general_options_form.general_group.units_radio.get_value().lower())], True)
-        if self.app.general_options_form.general_group.units_radio.get_value().lower() == 'mm':
+            width, self.app.general_options_form.general_app_group.units_radio.get_value().lower())], True)
+        if self.app.general_options_form.general_app_group.units_radio.get_value().lower() == 'mm':
             area = (length * width) / 100
             self.addChild(dims, ['Box Area:', '%.4f %s' % (area, 'cm2')], True)
         else:

+ 3 - 0
flatcamTools/ToolTransform.py

@@ -370,6 +370,9 @@ class ToolTransform(FlatCAMTool):
         FlatCAMTool.run(self)
         self.app.ui.notebook.setTabText(2, "Transform Tool")
 
+    def install(self, icon=None, separator=None, **kwargs):
+        FlatCAMTool.install(self, icon, separator, shortcut='ALT+R', **kwargs)
+
     def on_rotate(self):
         try:
             value = float(self.rotate_entry.get_value())

BIN
share/toggle_units16.png


BIN
share/toggle_units32.png