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

- added a dark theme to FlatCAM (only for canvas). The selection is done in Edit -> Preferences -> General -> GUI Settings

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

+ 28 - 3
FlatCAMApp.py

@@ -424,6 +424,17 @@ class App(QtCore.QObject):
 
 
         self.ui = FlatCAMGUI(self.version, self.beta, self)
         self.ui = FlatCAMGUI(self.version, self.beta, self)
 
 
+        settings = QtCore.QSettings("Open Source", "FlatCAM")
+        if settings.contains("theme"):
+            theme = settings.value('theme', type=str)
+        else:
+            theme = 'white'
+
+        if theme == 'white':
+            self.cursor_color_3D = 'black'
+        else:
+            self.cursor_color_3D = 'gray'
+
         self.ui.geom_update[int, int, int, int, int].connect(self.save_geometry)
         self.ui.geom_update[int, int, int, int, int].connect(self.save_geometry)
         self.ui.final_save.connect(self.final_save)
         self.ui.final_save.connect(self.final_save)
 
 
@@ -484,6 +495,7 @@ class App(QtCore.QObject):
             "global_activity_icon": self.ui.general_defaults_form.general_gui_group.activity_combo,
             "global_activity_icon": self.ui.general_defaults_form.general_gui_group.activity_combo,
 
 
             # General GUI Settings
             # General GUI Settings
+            "global_theme": self.ui.general_defaults_form.general_gui_set_group.theme_radio,
             "global_layout": self.ui.general_defaults_form.general_gui_set_group.layout_combo,
             "global_layout": self.ui.general_defaults_form.general_gui_set_group.layout_combo,
             "global_hover": self.ui.general_defaults_form.general_gui_set_group.hover_cb,
             "global_hover": self.ui.general_defaults_form.general_gui_set_group.hover_cb,
             "global_selection_shape": self.ui.general_defaults_form.general_gui_set_group.selection_cb,
             "global_selection_shape": self.ui.general_defaults_form.general_gui_set_group.selection_cb,
@@ -918,6 +930,7 @@ class App(QtCore.QObject):
             "global_zdownrate": None,
             "global_zdownrate": None,
 
 
             # General GUI Settings
             # General GUI Settings
+            "global_theme": 'white',
             "global_hover": False,
             "global_hover": False,
             "global_selection_shape": True,
             "global_selection_shape": True,
             "global_layout": "compact",
             "global_layout": "compact",
@@ -1996,6 +2009,7 @@ class App(QtCore.QObject):
         # ############ GUI SETTINGS SIGNALS ###############
         # ############ GUI SETTINGS SIGNALS ###############
         # #################################################
         # #################################################
 
 
+        self.ui.general_defaults_form.general_gui_set_group.theme_radio.activated_custom.connect(self.on_theme_change)
         self.ui.general_defaults_form.general_gui_set_group.cursor_radio.activated_custom.connect(self.on_cursor_type)
         self.ui.general_defaults_form.general_gui_set_group.cursor_radio.activated_custom.connect(self.on_cursor_type)
 
 
         # ########## CNC Job related signals #############
         # ########## CNC Job related signals #############
@@ -2824,6 +2838,15 @@ class App(QtCore.QObject):
                                 name)
                                 name)
                                )
                                )
 
 
+    def on_theme_change(self, val):
+        settings = QSettings("Open Source", "FlatCAM")
+        settings.setValue('theme', val)
+
+        # This will write the setting to the platform specific storage.
+        del settings
+
+        self.on_app_restart()
+
     def on_app_restart(self):
     def on_app_restart(self):
 
 
         # make sure that the Sys Tray icon is hidden before restart otherwise it will
         # make sure that the Sys Tray icon is hidden before restart otherwise it will
@@ -2831,7 +2854,7 @@ class App(QtCore.QObject):
         try:
         try:
             self.trayIcon.hide()
             self.trayIcon.hide()
         except Exception as e:
         except Exception as e:
-            log.debug("App.on_app_restart() --> %s" % str(e))
+           pass
 
 
         fcTranslate.restart_program(app=self)
         fcTranslate.restart_program(app=self)
 
 
@@ -6958,7 +6981,8 @@ class App(QtCore.QObject):
         if self.grid_status() == True:
         if self.grid_status() == True:
             # Update cursor
             # Update cursor
             self.app_cursor.set_data(np.asarray([(location[0], location[1])]),
             self.app_cursor.set_data(np.asarray([(location[0], location[1])]),
-                                     symbol='++', edge_color='black', size=self.defaults["global_cursor_size"])
+                                     symbol='++', edge_color=self.cursor_color_3D,
+                                     size=self.defaults["global_cursor_size"])
 
 
         # Set the position label
         # Set the position label
         self.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "
         self.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "
@@ -7936,7 +7960,8 @@ class App(QtCore.QObject):
 
 
                     # Update cursor
                     # Update cursor
                     self.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
                     self.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
-                                             symbol='++', edge_color='black', size=self.defaults["global_cursor_size"])
+                                             symbol='++', edge_color=self.cursor_color_3D,
+                                             size=self.defaults["global_cursor_size"])
                 else:
                 else:
                     pos = (pos_canvas[0], pos_canvas[1])
                     pos = (pos_canvas[0], pos_canvas[1])
 
 

+ 1 - 0
README.md

@@ -13,6 +13,7 @@ CAD program, and create G-Code for Isolation routing.
 
 
 - fixed an conflict in a signal usage that was triggered by Tool SolderPaste when a new project was created
 - fixed an conflict in a signal usage that was triggered by Tool SolderPaste when a new project was created
 - updated Optimal Tool to display both points coordinates that made a distance (and the minimum) not only the middle point (which is still the place where the jump happen)
 - updated Optimal Tool to display both points coordinates that made a distance (and the minimum) not only the middle point (which is still the place where the jump happen)
+- added a dark theme to FlatCAM (only for canvas). The selection is done in Edit -> Preferences -> General -> GUI Settings
 
 
 6.10.2019
 6.10.2019
 
 

+ 2 - 2
flatcamEditors/FlatCAMExcEditor.py

@@ -3657,7 +3657,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             x, y = self.app.geo_editor.snap(x, y)
             x, y = self.app.geo_editor.snap(x, y)
 
 
             # Update cursor
             # Update cursor
-            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
                                          size=self.app.defaults["global_cursor_size"])
                                          size=self.app.defaults["global_cursor_size"])
 
 
         self.snap_x = x
         self.snap_x = x
@@ -3706,7 +3706,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             self.app.selection_type = None
             self.app.selection_type = None
 
 
         # Update cursor
         # Update cursor
-        self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+        self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
                                      size=self.app.defaults["global_cursor_size"])
                                      size=self.app.defaults["global_cursor_size"])
 
 
     def on_canvas_key_release(self, event):
     def on_canvas_key_release(self, event):

+ 1 - 1
flatcamEditors/FlatCAMGeoEditor.py

@@ -3823,7 +3823,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
             x, y = self.snap(x, y)
             x, y = self.snap(x, y)
 
 
             # Update cursor
             # Update cursor
-            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
                                          size=self.app.defaults["global_cursor_size"])
                                          size=self.app.defaults["global_cursor_size"])
 
 
         self.snap_x = x
         self.snap_x = x

+ 1 - 1
flatcamEditors/FlatCAMGrbEditor.py

@@ -4446,7 +4446,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
             x, y = self.app.geo_editor.snap(x, y)
             x, y = self.app.geo_editor.snap(x, y)
 
 
             # Update cursor
             # Update cursor
-            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+            self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color=self.app.cursor_color_3D,
                                          size=self.app.defaults["global_cursor_size"])
                                          size=self.app.defaults["global_cursor_size"])
 
 
         self.snap_x = x
         self.snap_x = x

+ 16 - 3
flatcamGUI/PlotCanvas.py

@@ -9,7 +9,7 @@
 from PyQt5 import QtCore
 from PyQt5 import QtCore
 
 
 import logging
 import logging
-from flatcamGUI.VisPyCanvas import VisPyCanvas, time
+from flatcamGUI.VisPyCanvas import VisPyCanvas, time, Color
 from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
 from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
 from vispy.scene.visuals import InfiniteLine, Line
 from vispy.scene.visuals import InfiniteLine, Line
 import numpy as np
 import numpy as np
@@ -44,6 +44,17 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         # Parent container
         # Parent container
         self.container = container
         self.container = container
 
 
+        settings = QtCore.QSettings("Open Source", "FlatCAM")
+        if settings.contains("theme"):
+            theme = settings.value('theme', type=str)
+        else:
+            theme = 'white'
+
+        if theme == 'white':
+            self.line_color = (0.3, 0.0, 0.0, 1.0)
+        else:
+            self.line_color = (0.4, 0.4, 0.4, 1.0)
+
         # workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
         # workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
         # which might decrease performance
         # which might decrease performance
         self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
         self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
@@ -68,7 +79,6 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         self.draw_workspace()
         self.draw_workspace()
 
 
         self.line_parent = None
         self.line_parent = None
-        self.line_color = (0.3, 0.0, 0.0, 1.0)
         self.cursor_v_line = InfiniteLine(pos=None, color=self.line_color, vertical=True,
         self.cursor_v_line = InfiniteLine(pos=None, color=self.line_color, vertical=True,
                                           parent=self.line_parent)
                                           parent=self.line_parent)
 
 
@@ -328,7 +338,10 @@ class CursorBig(QtCore.QObject):
         if 'edge_color' in kwargs:
         if 'edge_color' in kwargs:
             color = kwargs['edge_color']
             color = kwargs['edge_color']
         else:
         else:
-            color = (0.0, 0.0, 0.0, 1.0)
+            if self.app.defaults['global_theme'] == 'white':
+                color = '#000000FF'
+            else:
+                color = '#FFFFFFFF'
 
 
         position = [pos[0][0], pos[0][1]]
         position = [pos[0][0], pos[0][1]]
         self.mouse_position_updated.emit(position)
         self.mouse_position_updated.emit(position)

+ 41 - 9
flatcamGUI/PlotCanvasLegacy.py

@@ -77,6 +77,11 @@ class CanvasCache(QtCore.QObject):
         self.axes.set_xticks([])
         self.axes.set_xticks([])
         self.axes.set_yticks([])
         self.axes.set_yticks([])
 
 
+        if self.app.defaults['global_theme'] == 'white':
+            self.axes.set_facecolor('#FFFFFF')
+        else:
+            self.axes.set_facecolor('#000000')
+
         self.canvas = FigureCanvas(self.figure)
         self.canvas = FigureCanvas(self.figure)
 
 
         self.cache = None
         self.cache = None
@@ -140,6 +145,13 @@ class PlotCanvasLegacy(QtCore.QObject):
 
 
         self.app = app
         self.app = app
 
 
+        if self.app.defaults['global_theme'] == 'white':
+            theme_color = '#FFFFFF'
+            tick_color = '#000000'
+        else:
+            theme_color = '#000000'
+            tick_color = '#FFFFFF'
+
         # Options
         # Options
         self.x_margin = 15  # pixels
         self.x_margin = 15  # pixels
         self.y_margin = 25  # Pixels
         self.y_margin = 25  # Pixels
@@ -149,16 +161,26 @@ class PlotCanvasLegacy(QtCore.QObject):
 
 
         # Plots go onto a single matplotlib.figure
         # Plots go onto a single matplotlib.figure
         self.figure = Figure(dpi=50)  # TODO: dpi needed?
         self.figure = Figure(dpi=50)  # TODO: dpi needed?
-        self.figure.patch.set_visible(False)
+        self.figure.patch.set_visible(True)
+        self.figure.set_facecolor(theme_color)
 
 
         # These axes show the ticks and grid. No plotting done here.
         # These axes show the ticks and grid. No plotting done here.
         # New axes must have a label, otherwise mpl returns an existing one.
         # New axes must have a label, otherwise mpl returns an existing one.
         self.axes = self.figure.add_axes([0.05, 0.05, 0.9, 0.9], label="base", alpha=0.0)
         self.axes = self.figure.add_axes([0.05, 0.05, 0.9, 0.9], label="base", alpha=0.0)
         self.axes.set_aspect(1)
         self.axes.set_aspect(1)
-        self.axes.grid(True)
+        self.axes.grid(True, color='gray')
         self.axes.axhline(color=(0.70, 0.3, 0.3), linewidth=2)
         self.axes.axhline(color=(0.70, 0.3, 0.3), linewidth=2)
         self.axes.axvline(color=(0.70, 0.3, 0.3), linewidth=2)
         self.axes.axvline(color=(0.70, 0.3, 0.3), linewidth=2)
 
 
+        self.axes.tick_params(axis='x', color=tick_color, labelcolor=tick_color)
+        self.axes.tick_params(axis='y', color=tick_color, labelcolor=tick_color)
+        self.axes.spines['bottom'].set_color(tick_color)
+        self.axes.spines['top'].set_color(tick_color)
+        self.axes.spines['right'].set_color(tick_color)
+        self.axes.spines['left'].set_color(tick_color)
+
+        self.axes.set_facecolor(theme_color)
+
         self.ch_line = None
         self.ch_line = None
         self.cv_line = None
         self.cv_line = None
 
 
@@ -264,10 +286,15 @@ class PlotCanvasLegacy(QtCore.QObject):
         # else:
         # else:
         #     c = MplCursor(axes=axes, color='black', linewidth=1)
         #     c = MplCursor(axes=axes, color='black', linewidth=1)
 
 
-        if  big is True:
+        if self.app.defaults['global_theme'] == 'white':
+            color = '#000000'
+        else:
+            color = '#FFFFFF'
+
+        if big is True:
             self.big_cursor = True
             self.big_cursor = True
-            self.ch_line = self.axes.axhline(color=(0.0, 0.0, 0.0), linewidth=1)
-            self.cv_line = self.axes.axvline(color=(0.0, 0.0, 0.0), linewidth=1)
+            self.ch_line = self.axes.axhline(color=color, linewidth=1)
+            self.cv_line = self.axes.axvline(color=color, linewidth=1)
         else:
         else:
             self.big_cursor = False
             self.big_cursor = False
 
 
@@ -286,6 +313,11 @@ class PlotCanvasLegacy(QtCore.QObject):
         """
         """
         # there is no point in drawing mouse cursor when panning as it jumps in a confusing way
         # there is no point in drawing mouse cursor when panning as it jumps in a confusing way
         if self.app.app_cursor.enabled is True and self.panning is False:
         if self.app.app_cursor.enabled is True and self.panning is False:
+            if self.app.defaults['global_theme'] == 'white':
+                color = '#000000'
+            else:
+                color = '#FFFFFF'
+
             if self.big_cursor is False:
             if self.big_cursor is False:
                 try:
                 try:
                     x, y = self.app.geo_editor.snap(x_pos, y_pos)
                     x, y = self.app.geo_editor.snap(x_pos, y_pos)
@@ -294,13 +326,13 @@ class PlotCanvasLegacy(QtCore.QObject):
                     # The size of the cursor is multiplied by 1.65 because that value made the cursor similar with the
                     # The size of the cursor is multiplied by 1.65 because that value made the cursor similar with the
                     # one in the OpenGL(3D) graphic engine
                     # one in the OpenGL(3D) graphic engine
                     pointer_size = int(float(self.app.defaults["global_cursor_size"] ) * 1.65)
                     pointer_size = int(float(self.app.defaults["global_cursor_size"] ) * 1.65)
-                    elements = self.axes.plot(x, y, 'k+', ms=pointer_size, mew=1, animated=True)
+                    elements = self.axes.plot(x, y, '+', color=color, ms=pointer_size, mew=1, animated=True)
                     for el in elements:
                     for el in elements:
                         self.axes.draw_artist(el)
                         self.axes.draw_artist(el)
                 except Exception as e:
                 except Exception as e:
                     # this happen at app initialization since self.app.geo_editor does not exist yet
                     # this happen at app initialization since self.app.geo_editor does not exist yet
-                    # I could reshuffle the object instantiating order but what's the point? I could crash something else
-                    # and that's pythonic, too
+                    # I could reshuffle the object instantiating order but what's the point?
+                    # I could crash something else and that's pythonic, too
                     pass
                     pass
             else:
             else:
                 self.ch_line.set_ydata(y_pos)
                 self.ch_line.set_ydata(y_pos)
@@ -476,7 +508,7 @@ class PlotCanvasLegacy(QtCore.QObject):
 
 
         # Adjust axes
         # Adjust axes
         for ax in self.figure.get_axes():
         for ax in self.figure.get_axes():
-            ax.set_xlim((x - half_width , x + half_width))
+            ax.set_xlim((x - half_width, x + half_width))
             ax.set_ylim((y - half_height, y + half_height))
             ax.set_ylim((y - half_height, y + half_height))
 
 
         # Re-draw
         # Re-draw

+ 77 - 30
flatcamGUI/PreferencesUI.py

@@ -557,6 +557,27 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         # Create a form layout for the Application general settings
         # Create a form layout for the Application general settings
         self.form_box = QtWidgets.QFormLayout()
         self.form_box = QtWidgets.QFormLayout()
 
 
+        grid0 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid0)
+        grid0.setColumnStretch(0, 0)
+        grid0.setColumnStretch(1, 1)
+
+        grid0.addWidget(QtWidgets.QLabel(''), 0, 0)
+
+        # Theme selection
+        self.theme_label = QtWidgets.QLabel('%s:' % _('Theme'))
+        self.theme_label.setToolTip(
+            _("Select a theme for FlatCAM.\n"
+              "The application will restart after change.")
+        )
+        self.theme_radio = RadioSet([
+            {"label": _("White"), "value": "white"},
+            {"label": _("Dark"), "value": "black"}
+        ], orientation='horizontal', stretch=False)
+
+        grid0.addWidget(self.theme_label, 1, 0)
+        grid0.addWidget(self.theme_radio, 1, 1)
+
         # Layout selection
         # Layout selection
         self.layout_label = QtWidgets.QLabel('%s:' % _('Layout'))
         self.layout_label = QtWidgets.QLabel('%s:' % _('Layout'))
         self.layout_label.setToolTip(
         self.layout_label.setToolTip(
@@ -568,6 +589,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.layout_combo.addItem("standard")
         self.layout_combo.addItem("standard")
         self.layout_combo.addItem("compact")
         self.layout_combo.addItem("compact")
 
 
+        grid0.addWidget(self.layout_label, 2, 0)
+        grid0.addWidget(self.layout_combo, 2, 1)
+
         # Set the current index for layout_combo
         # Set the current index for layout_combo
         settings = QSettings("Open Source", "FlatCAM")
         settings = QSettings("Open Source", "FlatCAM")
         if settings.contains("layout"):
         if settings.contains("layout"):
@@ -588,6 +612,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.style_combo.setCurrentIndex(index)
         self.style_combo.setCurrentIndex(index)
         self.style_combo.activated[str].connect(self.handle_style)
         self.style_combo.activated[str].connect(self.handle_style)
 
 
+        grid0.addWidget(self.style_label, 3, 0)
+        grid0.addWidget(self.style_combo, 3, 1)
+
         # Enable High DPI Support
         # Enable High DPI Support
         self.hdpi_label = QtWidgets.QLabel('%s:' % _('HDPI Support'))
         self.hdpi_label = QtWidgets.QLabel('%s:' % _('HDPI Support'))
         self.hdpi_label.setToolTip(
         self.hdpi_label.setToolTip(
@@ -603,6 +630,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
             self.hdpi_cb.set_value(False)
             self.hdpi_cb.set_value(False)
         self.hdpi_cb.stateChanged.connect(self.handle_hdpi)
         self.hdpi_cb.stateChanged.connect(self.handle_hdpi)
 
 
+        grid0.addWidget(self.hdpi_label, 4, 0)
+        grid0.addWidget(self.hdpi_cb, 4, 1)
+
         # Clear Settings
         # Clear Settings
         self.clear_label = QtWidgets.QLabel('%s:' % _('Clear GUI Settings'))
         self.clear_label = QtWidgets.QLabel('%s:' % _('Clear GUI Settings'))
         self.clear_label.setToolTip(
         self.clear_label.setToolTip(
@@ -612,6 +642,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.clear_btn = FCButton(_("Clear"))
         self.clear_btn = FCButton(_("Clear"))
         self.clear_btn.clicked.connect(self.handle_clear)
         self.clear_btn.clicked.connect(self.handle_clear)
 
 
+        grid0.addWidget(self.clear_label, 5, 0)
+        grid0.addWidget(self.clear_btn, 5, 1)
+
         # Enable Hover box
         # Enable Hover box
         self.hover_label = QtWidgets.QLabel('%s:' % _('Hover Shape'))
         self.hover_label = QtWidgets.QLabel('%s:' % _('Hover Shape'))
         self.hover_label.setToolTip(
         self.hover_label.setToolTip(
@@ -621,6 +654,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         )
         )
         self.hover_cb = FCCheckBox()
         self.hover_cb = FCCheckBox()
 
 
+        grid0.addWidget(self.hover_label, 6, 0)
+        grid0.addWidget(self.hover_cb, 6, 1)
+
         # Enable Selection box
         # Enable Selection box
         self.selection_label = QtWidgets.QLabel('%s:' % _('Sel. Shape'))
         self.selection_label = QtWidgets.QLabel('%s:' % _('Sel. Shape'))
         self.selection_label.setToolTip(
         self.selection_label.setToolTip(
@@ -631,6 +667,11 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         )
         )
         self.selection_cb = FCCheckBox()
         self.selection_cb = FCCheckBox()
 
 
+        grid0.addWidget(self.selection_label, 7, 0)
+        grid0.addWidget(self.selection_cb, 7, 1)
+
+        grid0.addWidget(QtWidgets.QLabel(''), 8, 0)
+
         # Notebook Font Size
         # Notebook Font Size
         self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('NB Font Size'))
         self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('NB Font Size'))
         self.notebook_font_size_label.setToolTip(
         self.notebook_font_size_label.setToolTip(
@@ -649,6 +690,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.notebook_font_size_spinner.set_value(12)
             self.notebook_font_size_spinner.set_value(12)
 
 
+        grid0.addWidget(self.notebook_font_size_label, 9, 0)
+        grid0.addWidget(self.notebook_font_size_spinner, 9, 1)
+
         # Axis Font Size
         # Axis Font Size
         self.axis_font_size_label = QtWidgets.QLabel('%s:' % _('Axis Font Size'))
         self.axis_font_size_label = QtWidgets.QLabel('%s:' % _('Axis Font Size'))
         self.axis_font_size_label.setToolTip(
         self.axis_font_size_label.setToolTip(
@@ -665,6 +709,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.axis_font_size_spinner.set_value(8)
             self.axis_font_size_spinner.set_value(8)
 
 
+        grid0.addWidget(self.axis_font_size_label, 10, 0)
+        grid0.addWidget(self.axis_font_size_spinner, 10, 1)
+
         # TextBox Font Size
         # TextBox Font Size
         self.textbox_font_size_label = QtWidgets.QLabel('%s:' % _('Textbox Font Size'))
         self.textbox_font_size_label = QtWidgets.QLabel('%s:' % _('Textbox Font Size'))
         self.textbox_font_size_label.setToolTip(
         self.textbox_font_size_label.setToolTip(
@@ -682,8 +729,11 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.textbox_font_size_spinner.set_value(10)
             self.textbox_font_size_spinner.set_value(10)
 
 
+        grid0.addWidget(self.textbox_font_size_label, 11, 0)
+        grid0.addWidget(self.textbox_font_size_spinner, 11, 1)
+
         # Just to add empty rows
         # Just to add empty rows
-        self.spacelabel = QtWidgets.QLabel('')
+        grid0.addWidget(QtWidgets.QLabel(''), 12, 0)
 
 
         # Splash Screen
         # Splash Screen
         self.splash_label = QtWidgets.QLabel('%s:' % _('Splash Screen'))
         self.splash_label = QtWidgets.QLabel('%s:' % _('Splash Screen'))
@@ -697,6 +747,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.splash_cb.set_value(False)
             self.splash_cb.set_value(False)
 
 
+        grid0.addWidget(self.splash_label, 13, 0)
+        grid0.addWidget(self.splash_cb, 13, 1)
+
         # Sys Tray Icon
         # Sys Tray Icon
         self.systray_label = QtWidgets.QLabel('%s:' % _('Sys Tray Icon'))
         self.systray_label = QtWidgets.QLabel('%s:' % _('Sys Tray Icon'))
         self.systray_label.setToolTip(
         self.systray_label.setToolTip(
@@ -704,6 +757,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         )
         )
         self.systray_cb = FCCheckBox()
         self.systray_cb = FCCheckBox()
 
 
+        grid0.addWidget(self.systray_label, 14, 0)
+        grid0.addWidget(self.systray_cb, 14, 1)
+
         # Shell StartUp CB
         # Shell StartUp CB
         self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
         self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
         self.shell_startup_label.setToolTip(
         self.shell_startup_label.setToolTip(
@@ -716,6 +772,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "start automatically at startup.")
               "start automatically at startup.")
         )
         )
 
 
+        grid0.addWidget(self.shell_startup_label, 15, 0)
+        grid0.addWidget(self.shell_startup_cb, 15, 1)
+
         # Project at StartUp CB
         # Project at StartUp CB
         self.project_startup_label = QtWidgets.QLabel('%s:' % _('Project at StartUp'))
         self.project_startup_label = QtWidgets.QLabel('%s:' % _('Project at StartUp'))
         self.project_startup_label.setToolTip(
         self.project_startup_label.setToolTip(
@@ -728,6 +787,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "to be shown automatically at startup.")
               "to be shown automatically at startup.")
         )
         )
 
 
+        grid0.addWidget(self.project_startup_label, 16, 0)
+        grid0.addWidget(self.project_startup_cb, 16, 1)
+
         # Project autohide CB
         # Project autohide CB
         self.project_autohide_label = QtWidgets.QLabel('%s:' % _('Project AutoHide'))
         self.project_autohide_label = QtWidgets.QLabel('%s:' % _('Project AutoHide'))
         self.project_autohide_label.setToolTip(
         self.project_autohide_label.setToolTip(
@@ -742,6 +804,11 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "to show whenever a new object is created.")
               "to show whenever a new object is created.")
         )
         )
 
 
+        grid0.addWidget(self.project_autohide_label, 17, 0)
+        grid0.addWidget(self.project_autohide_cb, 17, 1)
+
+        grid0.addWidget(QtWidgets.QLabel(''), 18, 0)
+
         # Enable/Disable ToolTips globally
         # Enable/Disable ToolTips globally
         self.toggle_tooltips_label = QtWidgets.QLabel('<b>%s:</b>' % _('Enable ToolTips'))
         self.toggle_tooltips_label = QtWidgets.QLabel('<b>%s:</b>' % _('Enable ToolTips'))
         self.toggle_tooltips_label.setToolTip(
         self.toggle_tooltips_label.setToolTip(
@@ -754,6 +821,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "when hovering with mouse over items throughout the App.")
               "when hovering with mouse over items throughout the App.")
         )
         )
 
 
+        grid0.addWidget(self.toggle_tooltips_label, 19, 0)
+        grid0.addWidget(self.toggle_tooltips_cb, 19, 1)
+
         # Mouse Cursor Shape
         # Mouse Cursor Shape
         self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor'))
         self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor'))
         self.cursor_lbl.setToolTip(
         self.cursor_lbl.setToolTip(
@@ -767,6 +837,9 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
             {"label": _("Big"), "value": "big"}
             {"label": _("Big"), "value": "big"}
         ], orientation='horizontal', stretch=False)
         ], orientation='horizontal', stretch=False)
 
 
+        grid0.addWidget(self.cursor_lbl, 20, 0)
+        grid0.addWidget(self.cursor_radio, 20, 1)
+
         self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor Size'))
         self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor Size'))
         self.cursor_size_lbl.setToolTip(
         self.cursor_size_lbl.setToolTip(
            _("Set the size of the mouse cursor, in pixels.")
            _("Set the size of the mouse cursor, in pixels.")
@@ -776,34 +849,8 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.cursor_size_entry.set_range(10, 70)
         self.cursor_size_entry.set_range(10, 70)
         self.cursor_size_entry.setWrapping(True)
         self.cursor_size_entry.setWrapping(True)
 
 
-
-        # Add (label - input field) pair to the QFormLayout
-        self.form_box.addRow(self.spacelabel, self.spacelabel)
-
-        self.form_box.addRow(self.layout_label, self.layout_combo)
-        self.form_box.addRow(self.style_label, self.style_combo)
-        self.form_box.addRow(self.hdpi_label, self.hdpi_cb)
-        self.form_box.addRow(self.clear_label, self.clear_btn)
-        self.form_box.addRow(self.hover_label, self.hover_cb)
-        self.form_box.addRow(self.selection_label, self.selection_cb)
-        self.form_box.addRow(QtWidgets.QLabel(''))
-        self.form_box.addRow(self.notebook_font_size_label, self.notebook_font_size_spinner)
-        self.form_box.addRow(self.axis_font_size_label, self.axis_font_size_spinner)
-        self.form_box.addRow(self.textbox_font_size_label, self.textbox_font_size_spinner)
-        self.form_box.addRow(QtWidgets.QLabel(''))
-        self.form_box.addRow(self.splash_label, self.splash_cb)
-        self.form_box.addRow(self.systray_label, self.systray_cb)
-        self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
-        self.form_box.addRow(self.project_startup_label, self.project_startup_cb)
-        self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
-        self.form_box.addRow(QtWidgets.QLabel(''))
-        self.form_box.addRow(self.toggle_tooltips_label, self.toggle_tooltips_cb)
-        self.form_box.addRow(self.cursor_lbl, self.cursor_radio)
-        self.form_box.addRow(self.cursor_size_lbl, self.cursor_size_entry)
-
-        # Add the QFormLayout that holds the Application general defaults
-        # to the main layout of this TAB
-        self.layout.addLayout(self.form_box)
+        grid0.addWidget(self.cursor_size_lbl, 21, 0)
+        grid0.addWidget(self.cursor_size_entry, 21, 1)
 
 
         # Delete confirmation
         # Delete confirmation
         self.delete_conf_cb = FCCheckBox(_('Delete object confirmation'))
         self.delete_conf_cb = FCCheckBox(_('Delete object confirmation'))
@@ -812,7 +859,7 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
               "whenever the Delete object(s) event is triggered, either by\n"
               "whenever the Delete object(s) event is triggered, either by\n"
               "menu shortcut or key shortcut.")
               "menu shortcut or key shortcut.")
         )
         )
-        self.layout.addWidget(self.delete_conf_cb)
+        grid0.addWidget(self.delete_conf_cb, 22, 0, 1, 2)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 

+ 27 - 11
flatcamGUI/VisPyCanvas.py

@@ -25,7 +25,25 @@ class VisPyCanvas(scene.SceneCanvas):
 
 
         self.unfreeze()
         self.unfreeze()
 
 
-        back_color = str(QPalette().color(QPalette.Window).name())
+        settings = QSettings("Open Source", "FlatCAM")
+        if settings.contains("axis_font_size"):
+            a_fsize = settings.value('axis_font_size', type=int)
+        else:
+            a_fsize = 8
+
+        if settings.contains("theme"):
+            theme = settings.value('theme', type=str)
+        else:
+            theme = 'white'
+
+        if theme == 'white':
+            theme_color = Color('#FFFFFF')
+            tick_color = Color('#000000')
+            back_color = str(QPalette().color(QPalette.Window).name())
+        else:
+            theme_color = Color('#000000')
+            tick_color = Color('gray')
+            back_color = Color('#000000')
 
 
         self.central_widget.bgcolor = back_color
         self.central_widget.bgcolor = back_color
         self.central_widget.border_color = back_color
         self.central_widget.border_color = back_color
@@ -36,18 +54,16 @@ class VisPyCanvas(scene.SceneCanvas):
         top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
         top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
         top_padding.height_max = 0
         top_padding.height_max = 0
 
 
-        settings = QSettings("Open Source", "FlatCAM")
-        if settings.contains("axis_font_size"):
-            a_fsize = settings.value('axis_font_size', type=int)
-        else:
-            a_fsize = 8
-
-        self.yaxis = scene.AxisWidget(orientation='left', axis_color='black', text_color='black', font_size=a_fsize)
+        self.yaxis = scene.AxisWidget(
+            orientation='left', axis_color=tick_color, text_color=tick_color, font_size=a_fsize
+        )
         self.yaxis.width_max = 55
         self.yaxis.width_max = 55
         self.grid_widget.add_widget(self.yaxis, row=1, col=0)
         self.grid_widget.add_widget(self.yaxis, row=1, col=0)
 
 
-        self.xaxis = scene.AxisWidget(orientation='bottom', axis_color='black', text_color='black', font_size=a_fsize,
-                                      anchors=['center', 'bottom'])
+        self.xaxis = scene.AxisWidget(
+            orientation='bottom', axis_color=tick_color, text_color=tick_color, font_size=a_fsize,
+            anchors=['center', 'bottom']
+        )
         self.xaxis.height_max = 30
         self.xaxis.height_max = 30
         self.grid_widget.add_widget(self.xaxis, row=2, col=1)
         self.grid_widget.add_widget(self.xaxis, row=2, col=1)
 
 
@@ -55,7 +71,7 @@ class VisPyCanvas(scene.SceneCanvas):
         # right_padding.width_max = 24
         # right_padding.width_max = 24
         right_padding.width_max = 0
         right_padding.width_max = 0
 
 
-        view = self.grid_widget.add_view(row=1, col=1, border_color='black', bgcolor='white')
+        view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color, bgcolor=theme_color)
         view.camera = Camera(aspect=1, rect=(-25, -25, 150, 150))
         view.camera = Camera(aspect=1, rect=(-25, -25, 150, 150))
 
 
         # Following function was removed from 'prepare_draw()' of 'Grid' class by patch,
         # Following function was removed from 'prepare_draw()' of 'Grid' class by patch,

+ 1 - 1
flatcamTools/ToolDistance.py

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

+ 2 - 1
flatcamTools/ToolNonCopperClear.py

@@ -1331,7 +1331,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
             curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
             curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
 
 
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
-                                         symbol='++', edge_color='black', size=self.app.defaults["global_cursor_size"])
+                                         symbol='++', edge_color=self.app.cursor_color_3D,
+                                         size=self.app.defaults["global_cursor_size"])
 
 
         # update the positions on status bar
         # update the positions on status bar
         self.app.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "
         self.app.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "

+ 2 - 1
flatcamTools/ToolPaint.py

@@ -1199,7 +1199,8 @@ class ToolPaint(FlatCAMTool, Gerber):
             curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
             curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
 
 
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
             self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
-                                         symbol='++', edge_color='black', size=self.app.defaults["global_cursor_size"])
+                                         symbol='++', edge_color=self.app.cursor_color_3D,
+                                         size=self.app.defaults["global_cursor_size"])
 
 
         # update the positions on status bar
         # update the positions on status bar
         self.app.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "
         self.app.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp;   "