diff --git a/.gitignore b/.gitignore
index f957e1b3..30a8ae85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ build/
.DS_Store
.AppleDouble
.LSOverride
+.vscode
diff --git a/Bookmark.py b/Bookmark.py
index 796c1105..a3b6629d 100644
--- a/Bookmark.py
+++ b/Bookmark.py
@@ -75,7 +75,7 @@ class BookmarkManager(QtWidgets.QWidget):
new_vlay = QtWidgets.QVBoxLayout()
layout.addLayout(new_vlay)
- new_title_lbl = FCLabel('%s' % _("New Bookmark"))
+ new_title_lbl = FCLabel('%s' % _("New Bookmark"), bold=True)
new_vlay.addWidget(new_title_lbl)
grid0 = GLay(v_spacing=5, h_spacing=3)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0b2b544..5e53c371 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,23 @@ CHANGELOG for FlatCAM Evo beta
=================================================
+20.04.2022
+
+- in Solderpaste Plugin fixed the GCode generation; make sure that if no object is selected then the first Gerber object is autoselected
+- in Solderpaste Plugin fixed the CNCJob plotting
+- in Solderpaste Plugin added a new parameter 'Margin' which allows reducing how much solderpaste is added and therefore adding a space between the solderpaste and the pad boundary
+- all CNCJob objects generated by the Solderpaste plugin now have the GCode saved as source_code which can be saved also from the CNCJob object context menu, and edited
+- updated some custom widgets in the GUI elements such that the scrolling in the Preferences can be done without blocking on some of the widgets
+- remade how the Preferences Tab is constructed such that now is made on demand for each section (tab) therefore making it faster to load (once a section is loaded - by clicking its tab - it will not be reloaded in the current session)
+- a fix for the latest change in the Preferences Tab
+- some changes in the Geometry Editor UI's and in some cases, fixes for the right-click close action
+
+19.04.2022
+
+- fixed and prettified the 'Light' theme
+- some more fixes for the 'Light' theme
+- made sure that the 'default' theme gets the 'stronger' colors
+
18.04.2022
- in Geometry Editor, in Copy Tool added the 2D copy-as-array feature therefore finishing this editor plugin upgrade
@@ -14,6 +31,8 @@ CHANGELOG for FlatCAM Evo beta
- replaced all the FCLabel widgets that have color HTML with the new FCLabel widget that uses parameters for 'color' and weight
- minor changes
- added a way to allow patching FCLabel widget colors for certain cases without having to pass them each instance
+- some changes in the theme selection, added that the default situation is where no theme is applied
+- some string changes
17.04.2022
@@ -7472,4 +7491,3 @@ Previously added features by Dennis
- Groups in Project view.
- Pan view by dragging in visualizer window with pressed MMB.
- OpenGL-based visualizer.
-
diff --git a/appDatabase.py b/appDatabase.py
index 8f21063a..0d487586 100644
--- a/appDatabase.py
+++ b/appDatabase.py
@@ -226,7 +226,7 @@ class ToolsDB2UI:
self.grid_tool.addWidget(self.dia_entry, 1, 1)
# Tool Tolerance
- self.tol_label = FCLabel("%s:" % _("Diameter Tolerance"))
+ self.tol_label = FCLabel('%s:' % _("Diameter Tolerance"), bold=True)
self.tol_label.setToolTip(
_("Tool tolerance. This tool will be used if the desired tool diameter\n"
"is within the tolerance specified here.")
@@ -262,7 +262,7 @@ class ToolsDB2UI:
self.grid_tool.addWidget(self.tol_max_entry, 6, 1)
# Tool Object Type
- self.tool_op_label = FCLabel('%s:' % _('Target'))
+ self.tool_op_label = FCLabel('%s:' % _('Target'), bold=True)
self.tool_op_label.setToolTip(
_("The kind of Application Tool where this tool is to be used."))
diff --git a/appEditors/AppExcEditor.py b/appEditors/AppExcEditor.py
index 5d701f71..91bf4cf9 100644
--- a/appEditors/AppExcEditor.py
+++ b/appEditors/AppExcEditor.py
@@ -4054,7 +4054,7 @@ class AppExcEditorUI:
self.name_box.addWidget(self.name_entry)
# Tools Drills Table Title
- self.tools_table_label = FCLabel("%s" % _('Tools Table'))
+ self.tools_table_label = FCLabel('%s' % _('Tools Table'), bold=True)
self.tools_table_label.setToolTip(
_("Tools in this Excellon object\n"
"when are used for drilling.")
@@ -4091,7 +4091,7 @@ class AppExcEditorUI:
self.ui_vertical_lay.addWidget(separator_line)
# Add a new Tool
- self.addtool_label = FCLabel('%s' % _('Add/Delete Tool'))
+ self.addtool_label = FCLabel('%s' % _('Add/Delete Tool'), bold=True)
self.addtool_label.setToolTip(
_("Add/Delete a tool to the tool list\n"
"for this Excellon object.")
@@ -4157,7 +4157,7 @@ class AppExcEditorUI:
self.resize_grid.setContentsMargins(0, 0, 0, 0)
self.resize_frame.setLayout(self.resize_grid)
- self.drillresize_label = FCLabel('%s' % _("Resize Tool"))
+ self.drillresize_label = FCLabel('%s' % _("Resize Tool"), bold=True)
self.drillresize_label.setToolTip(
_("Resize a drill or a selection of drills.")
)
@@ -4212,7 +4212,7 @@ class AppExcEditorUI:
self.array_frame.setLayout(self.array_grid)
# Type of Drill Array
- self.drill_array_label = FCLabel('%s' % _("Add Drill Array"))
+ self.drill_array_label = FCLabel('%s' % _("Add Drill Array"), bold=True)
self.drill_array_label.setToolTip(
_("Add an array of drills (linear or circular array)")
)
@@ -4352,7 +4352,7 @@ class AppExcEditorUI:
self.slot_frame.setLayout(self.slot_grid)
# Slot Tile Label
- self.slot_label = FCLabel('%s' % _("Slot Parameters"))
+ self.slot_label = FCLabel('%s' % _("Slot Parameters"), bold=True)
self.slot_label.setToolTip(
_("Parameters for adding a slot (hole with oval shape)\n"
"either single or as an part of an array.")
@@ -4424,7 +4424,7 @@ class AppExcEditorUI:
self.slot_array_frame.setLayout(self.slot_array_grid)
# Slot Array Title
- self.slot_array_label = FCLabel('%s' % _("Slot Array Parameters"))
+ self.slot_array_label = FCLabel('%s' % _("Slot Array Parameters"), bold=True)
self.slot_array_label.setToolTip(
_("Parameters for the array of slots (linear or circular array)")
)
diff --git a/appEditors/AppGeoEditor.py b/appEditors/AppGeoEditor.py
index 8183c40d..cc6839f4 100644
--- a/appEditors/AppGeoEditor.py
+++ b/appEditors/AppGeoEditor.py
@@ -3003,6 +3003,9 @@ class FCPaint(FCShapeTool):
self.origin = (0, 0)
self.draw_app.paint_tool.run()
+ def clean_up(self):
+ pass
+
class FCTransform(FCShapeTool):
def __init__(self, draw_app):
@@ -3016,6 +3019,9 @@ class FCTransform(FCShapeTool):
self.origin = (0, 0)
self.draw_app.transform_tool.run()
+ def clean_up(self):
+ pass
+
# ###############################################
# ################ Main Application #############
@@ -3096,7 +3102,7 @@ class AppGeoEditor(QtCore.QObject):
self.tools_box.addLayout(self.grid_d)
# Tool diameter
- tooldia_lbl = FCLabel('%s:' % _("Tool dia"))
+ tooldia_lbl = FCLabel('%s' % _("Tool dia"), bold=True)
tooldia_lbl.setToolTip(
_("Edited tool diameter.")
)
@@ -3108,7 +3114,7 @@ class AppGeoEditor(QtCore.QObject):
self.grid_d.addWidget(tooldia_lbl, 0, 0)
self.grid_d.addWidget(self.tooldia_entry, 0, 1)
# Tree Widget Title
- tw_label = FCLabel('%s:' % _("Geometry Table"))
+ tw_label = FCLabel('%s' % _("Geometry Table"), bold=True)
tw_label.setToolTip(
_("The list of geometry elements inside the edited object.")
)
@@ -3148,35 +3154,35 @@ class AppGeoEditor(QtCore.QObject):
grid0.addWidget(separator_line, 2, 0, 1, 3)
# Parameters Title
- param_title = FCLabel('%s:' % _("Parameters"))
+ param_title = FCLabel('%s' % _("Parameters"), bold=True)
param_title.setToolTip(
_("Geometry parameters.")
)
grid0.addWidget(param_title, 4, 0, 1, 3)
# Is Valid
- is_valid_lbl = FCLabel('%s:' % _("Is Valid"))
+ is_valid_lbl = FCLabel('%s' % _("Is Valid"), bold=True)
self.is_valid_entry = FCLabel('None')
grid0.addWidget(is_valid_lbl, 10, 0)
grid0.addWidget(self.is_valid_entry, 10, 1, 1, 2)
# Is Empty
- is_empty_lbl = FCLabel('%s:' % _("Is Empty"))
+ is_empty_lbl = FCLabel('%s' % _("Is Empty"), bold=True)
self.is_empty_entry = FCLabel('None')
grid0.addWidget(is_empty_lbl, 12, 0)
grid0.addWidget(self.is_empty_entry, 12, 1, 1, 2)
# Is Ring
- is_ring_lbl = FCLabel('%s:' % _("Is Ring"))
+ is_ring_lbl = FCLabel('%s' % _("Is Ring"), bold=True)
self.is_ring_entry = FCLabel('None')
grid0.addWidget(is_ring_lbl, 14, 0)
grid0.addWidget(self.is_ring_entry, 14, 1, 1, 2)
# Is CCW
- is_ccw_lbl = FCLabel('%s:' % _("Is CCW"))
+ is_ccw_lbl = FCLabel('%s' % _("Is CCW"), bold=True)
self.is_ccw_entry = FCLabel('None')
self.change_orientation_btn = FCButton(_("Change"))
self.change_orientation_btn.setIcon(QtGui.QIcon(self.app.resource_location + '/orientation32.png'))
@@ -3189,14 +3195,14 @@ class AppGeoEditor(QtCore.QObject):
grid0.addWidget(self.change_orientation_btn, 16, 2)
# Is Simple
- is_simple_lbl = FCLabel('%s:' % _("Is Simple"))
+ is_simple_lbl = FCLabel('%s' % _("Is Simple"), bold=True)
self.is_simple_entry = FCLabel('None')
grid0.addWidget(is_simple_lbl, 18, 0)
grid0.addWidget(self.is_simple_entry, 18, 1, 1, 2)
# Length
- len_lbl = FCLabel('%s:' % _("Length"))
+ len_lbl = FCLabel('%s' % _("Length"), bold=True)
len_lbl.setToolTip(
_("The length of the geometry element.")
)
@@ -3207,7 +3213,7 @@ class AppGeoEditor(QtCore.QObject):
grid0.addWidget(self.geo_len_entry, 20, 1, 1, 2)
# Coordinates
- coords_lbl = FCLabel('%s:' % _("Coordinates"))
+ coords_lbl = FCLabel('%s' % _("Coordinates"), bold=True)
coords_lbl.setToolTip(
_("The coordinates of the selected geometry element.")
)
@@ -3220,7 +3226,7 @@ class AppGeoEditor(QtCore.QObject):
grid0.addWidget(self.geo_coords_entry, 24, 0, 1, 3)
# Vertex Points Number
- vertex_lbl = FCLabel('%s:' % _("Vertex Points"))
+ vertex_lbl = FCLabel('%s' % _("Vertex Points"), bold=True)
vertex_lbl.setToolTip(
_("The number of vertex points in the selected geometry element.")
)
diff --git a/appEditors/AppGerberEditor.py b/appEditors/AppGerberEditor.py
index 6613ecc5..90a9cd9e 100644
--- a/appEditors/AppGerberEditor.py
+++ b/appEditors/AppGerberEditor.py
@@ -6174,7 +6174,7 @@ class AppGerberEditorUI:
# #############################################################################################################
# #################################### Gerber Apertures Table #################################################
# #############################################################################################################
- self.apertures_table_label = FCLabel('%s:' % _('Apertures'))
+ self.apertures_table_label = FCLabel('%s:' % _('Apertures'), bold=True)
self.apertures_table_label.setToolTip(
_("Apertures Table for the Gerber Object.")
)
@@ -6225,7 +6225,7 @@ class AppGerberEditorUI:
self.apertures_box.addLayout(grid1)
# Title
- apadd_del_lbl = FCLabel('%s:' % _('Add/Delete Aperture'))
+ apadd_del_lbl = FCLabel('%s:' % _('Add/Delete Aperture'), bold=True)
apadd_del_lbl.setToolTip(
_("Add/Delete an aperture in the aperture table")
)
@@ -6334,7 +6334,7 @@ class AppGerberEditorUI:
self.shape_grid.addWidget(separator_line, 2, 0, 1, 3)
# Parameters Title
- param_title = FCLabel('%s' % _("Parameters"))
+ param_title = FCLabel('%s' % _("Parameters"), bold=True)
param_title.setToolTip(
_("Geometry parameters.")
)
@@ -6343,7 +6343,7 @@ class AppGerberEditorUI:
p_grid = GLay(v_spacing=5, h_spacing=3, c_stretch=[0, 0, 0, 1, 0])
# Is Valid
- valid_lbl = FCLabel('%s:' % _("Valid"))
+ valid_lbl = FCLabel('%s' % _("Valid"), bold=True)
valid_lbl.setToolTip(
_("Show if the selected polygon is valid.")
)
@@ -6352,7 +6352,7 @@ class AppGerberEditorUI:
p_grid.addWidget(self.is_valid_entry, 0, 1)
# Area
- area_lbl = FCLabel('%s:' % _("Area"))
+ area_lbl = FCLabel('%s' % _("Area"), bold=True)
area_lbl.setToolTip(
_("Show the area of the selected polygon.")
)
@@ -6397,7 +6397,7 @@ class AppGerberEditorUI:
self.shape_grid.addWidget(separator_line, 12, 0, 1, 3)
# Simplification Title
- simplif_lbl = FCLabel('%s:' % _("Simplification"))
+ simplif_lbl = FCLabel('%s' % _("Simplification"), bold=True)
simplif_lbl.setToolTip(
_("Simplify a geometry by reducing its vertex points number.")
)
@@ -6445,7 +6445,7 @@ class AppGerberEditorUI:
self.buffer_tool_frame.hide()
# Title
- buf_title_lbl = FCLabel('%s:' % _('Buffer Aperture'))
+ buf_title_lbl = FCLabel('%s:' % _('Buffer Aperture'), bold=True)
buf_title_lbl.setToolTip(
_("Buffer a aperture in the aperture list")
)
@@ -6503,7 +6503,7 @@ class AppGerberEditorUI:
self.scale_tool_frame.hide()
# Title
- scale_title_lbl = FCLabel('%s:' % _('Scale Aperture'))
+ scale_title_lbl = FCLabel('%s:' % _('Scale Aperture'), bold=True)
scale_title_lbl.setToolTip(
_("Scale a aperture in the aperture list")
)
@@ -6552,7 +6552,7 @@ class AppGerberEditorUI:
self.ma_tools_box.addWidget(separator_line)
# Title
- ma_title_lbl = FCLabel('%s:' % _('Mark polygons'))
+ ma_title_lbl = FCLabel('%s:' % _('Mark polygons'), bold=True)
ma_title_lbl.setToolTip(
_("Mark the polygon areas.")
)
@@ -6632,7 +6632,7 @@ class AppGerberEditorUI:
self.array_box.addLayout(array_grid)
# Title
- self.padarray_label = FCLabel('%s' % _("Add Pad Array"))
+ self.padarray_label = FCLabel('%s' % _("Add Pad Array"), bold=True)
self.padarray_label.setToolTip(
_("Add an array of pads (linear or circular array)")
)
diff --git a/appEditors/geo_plugins/GeoCirclePlugin.py b/appEditors/geo_plugins/GeoCirclePlugin.py
index 397b2451..bf45b5aa 100644
--- a/appEditors/geo_plugins/GeoCirclePlugin.py
+++ b/appEditors/geo_plugins/GeoCirclePlugin.py
@@ -187,48 +187,70 @@ class CircleEditorUI:
self.circle_tool_box.addLayout(grid0)
# Position
- self.pos_lbl = FCLabel('%s' % _("Position"))
+ self.pos_lbl = FCLabel('%s' % _("Position"), color='red', bold=True)
grid0.addWidget(self.pos_lbl, 0, 0, 1, 3)
+ # #############################################################################################################
+ # Position Frame
+ # #############################################################################################################
+ pos_frame = FCFrame()
+ grid0.addWidget(pos_frame, 2, 0, 1, 2)
+
+ pos_grid = GLay(v_spacing=5, h_spacing=3)
+ pos_frame.setLayout(pos_grid)
+
# X Pos
self.x_lbl = FCLabel('%s:' % _("X"))
self.x_entry = FCDoubleSpinner()
self.x_entry.set_precision(self.decimals)
self.x_entry.set_range(-10000.0000, 10000.0000)
- grid0.addWidget(self.x_lbl, 2, 0)
- grid0.addWidget(self.x_entry, 2, 1, 1, 2)
+ pos_grid.addWidget(self.x_lbl, 0, 0)
+ pos_grid.addWidget(self.x_entry, 0, 1, 1, 2)
# Y Pos
self.y_lbl = FCLabel('%s:' % _("Y"))
self.y_entry = FCDoubleSpinner()
self.y_entry.set_precision(self.decimals)
self.y_entry.set_range(-10000.0000, 10000.0000)
- grid0.addWidget(self.y_lbl, 4, 0)
- grid0.addWidget(self.y_entry, 4, 1, 1, 2)
+ pos_grid.addWidget(self.y_lbl, 2, 0)
+ pos_grid.addWidget(self.y_entry, 2, 1, 1, 2)
+
+ # Radius
+ self.radius_lbl = FCLabel('%s' % _("Radius"), bold=True, color='blue')
+ grid0.addWidget(self.radius_lbl, 4, 0)
+
+ # #############################################################################################################
+ # Radius Frame
+ # #############################################################################################################
+ rad_frame = FCFrame()
+ grid0.addWidget(rad_frame, 6, 0, 1, 2)
+
+ rad_grid = GLay(v_spacing=5, h_spacing=3)
+ rad_frame.setLayout(rad_grid)
# Radius X
- self.radius_x_lbl = FCLabel('%s X:' % _("Radius"))
+ self.radius_x_lbl = FCLabel('%s:' % "X")
self.radius_x_entry = FCDoubleSpinner()
self.radius_x_entry.set_precision(self.decimals)
self.radius_x_entry.set_range(0.0000, 10000.0000)
- grid0.addWidget(self.radius_x_lbl, 6, 0)
- grid0.addWidget(self.radius_x_entry, 6, 1)
+ rad_grid.addWidget(self.radius_x_lbl, 0, 0)
+ rad_grid.addWidget(self.radius_x_entry, 0, 1)
# Radius Y
- self.radius_y_lbl = FCLabel('%s Y:' % _("Radius"))
+ self.radius_y_lbl = FCLabel('%s:' % "Y")
self.radius_y_entry = FCDoubleSpinner()
self.radius_y_entry.set_precision(self.decimals)
self.radius_y_entry.set_range(0.0000, 10000.0000)
- grid0.addWidget(self.radius_y_lbl, 7, 0)
- grid0.addWidget(self.radius_y_entry, 7, 1)
+ rad_grid.addWidget(self.radius_y_lbl, 1, 0)
+ rad_grid.addWidget(self.radius_y_entry, 1, 1)
# Angle
self.angle_lbl = FCLabel('%s:' % _("Angle"))
self.angle_entry = FCDoubleSpinner()
self.angle_entry.set_precision(self.decimals)
self.angle_entry.set_range(0.0000, 360.0000)
- grid0.addWidget(self.angle_lbl, 8, 0)
- grid0.addWidget(self.angle_entry, 8, 1)
+ rad_grid.addWidget(self.angle_lbl, 2, 0)
+ rad_grid.addWidget(self.angle_entry, 2, 1)
# Radius link
self.radius_link_btn = QtWidgets.QToolButton()
@@ -236,17 +258,19 @@ class CircleEditorUI:
self.radius_link_btn.setSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding,
QtWidgets.QSizePolicy.Policy.Expanding)
self.radius_link_btn.setCheckable(True)
- grid0.addWidget(self.radius_link_btn, 6, 2, 3, 1)
+ rad_grid.addWidget(self.radius_link_btn, 0, 2, 3, 1)
# Buttons
self.add_button = FCButton(_("Add"))
self.add_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
grid0.addWidget(self.add_button, 18, 0, 1, 3)
+ GLay.set_common_column_size([grid0, pos_grid, rad_grid], 0)
+
self.layout.addStretch(1)
# Note
- self.note_lbl = FCLabel('%s' % _("Note"))
+ self.note_lbl = FCLabel('%s' % _("Note"), bold=True)
self.layout.addWidget(self.note_lbl)
self.note_description_lbl = FCLabel('%s' % _("Shift + click to select a shape for modification."))
self.layout.addWidget(self.note_description_lbl)
@@ -256,14 +280,14 @@ class CircleEditorUI:
def on_link_checked(self, checked):
if checked:
- self.radius_x_lbl.set_value('%s:' % _("Radius"))
+ self.radius_x_lbl.set_value('%s:' % _("Value"))
self.radius_y_lbl.setDisabled(True)
self.radius_y_entry.setDisabled(True)
self.radius_y_entry.set_value(self.radius_x_entry.get_value())
self.angle_lbl.setDisabled(True)
self.angle_entry.setDisabled(True)
else:
- self.radius_x_lbl.set_value('%s X:' % _("Radius"))
+ self.radius_x_lbl.set_value('%s:' % "X")
self.radius_y_lbl.setDisabled(False)
self.radius_y_entry.setDisabled(False)
self.angle_lbl.setDisabled(False)
diff --git a/appEditors/geo_plugins/GeoCopyPlugin.py b/appEditors/geo_plugins/GeoCopyPlugin.py
index fb71cd2f..3f7aa75b 100644
--- a/appEditors/geo_plugins/GeoCopyPlugin.py
+++ b/appEditors/geo_plugins/GeoCopyPlugin.py
@@ -164,7 +164,7 @@ class CopyEditorUI:
grid0.addWidget(separator_line, 4, 0, 1, 2)
# Type of Array
- self.mode_label = FCLabel('%s:' % _("Mode"))
+ self.mode_label = FCLabel('%s:' % _("Mode"), bold=True)
self.mode_label.setToolTip(
_("Single copy or special (array of copies)")
)
@@ -461,15 +461,11 @@ class CopyEditorUI:
minval,
self.decimals,
maxval), False)
- else:
- self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
def confirmation_message_int(self, accepted, minval, maxval):
if accepted is False:
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
(_("Edited value is out of range"), minval, maxval), False)
- else:
- self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
def on_copy_mode(self, val):
if val == 'n':
@@ -496,7 +492,7 @@ class CopyEditorUI:
self.rows.valueChanged.connect(self.on_rows_cols_value_changed)
self.columns.valueChanged.connect(self.on_rows_cols_value_changed)
- self.app.inform.emit(_("Click to place ..."))
+ self.app.inform.emit(_("Click on reference location ..."))
else:
if val == 'linear':
self.array_circular_frame.hide()
@@ -505,7 +501,7 @@ class CopyEditorUI:
self.spacing_frame.hide()
self.offset_frame.hide()
- self.app.inform.emit(_("Click to place ..."))
+ self.app.inform.emit(_("Click on reference location ..."))
else: # 'circular'
self.array_circular_frame.show()
self.array_linear_frame.hide()
diff --git a/appEditors/geo_plugins/GeoRectanglePlugin.py b/appEditors/geo_plugins/GeoRectanglePlugin.py
index 9acc15d6..6815767d 100644
--- a/appEditors/geo_plugins/GeoRectanglePlugin.py
+++ b/appEditors/geo_plugins/GeoRectanglePlugin.py
@@ -219,8 +219,20 @@ class RectangleEditorUI:
grid0 = GLay(v_spacing=5, h_spacing=3)
self.rect_tool_box.addLayout(grid0)
+ # Position
+ self.pos_lbl = FCLabel('%s' % _("Position"), bold=True, color='red')
+ grid0.addWidget(self.pos_lbl, 0, 0, 1, 2)
+ # #############################################################################################################
+ # Position Frame
+ # #############################################################################################################
+ pos_frame = FCFrame()
+ grid0.addWidget(pos_frame, 2, 0, 1, 2)
+
+ pos_grid = GLay(v_spacing=5, h_spacing=3)
+ pos_frame.setLayout(pos_grid)
+
# Anchor
- self.anchor_lbl = FCLabel('%s:' % _("Anchor"))
+ self.anchor_lbl = FCLabel('%s:' % _("Anchor"), bold=False)
choices = [
{"label": _("T Left"), "value": "tl"},
{"label": _("T Right"), "value": "tr"},
@@ -229,31 +241,38 @@ class RectangleEditorUI:
{"label": _("Center"), "value": "c"}
]
self.anchor_radio = RadioSetCross(choices, compact=True)
- grid0.addWidget(self.anchor_lbl, 0, 0)
- grid0.addWidget(self.anchor_radio, 0, 1)
-
- # Position
- self.pos_lbl = FCLabel('%s' % _("Position"))
- grid0.addWidget(self.pos_lbl, 2, 0, 1, 2)
+ pos_grid.addWidget(self.anchor_lbl, 0, 0)
+ pos_grid.addWidget(self.anchor_radio, 0, 1)
# X Pos
self.x_lbl = FCLabel('%s:' % _("X"))
self.x_entry = FCDoubleSpinner()
self.x_entry.set_precision(self.decimals)
self.x_entry.set_range(-10000.0000, 10000.0000)
- grid0.addWidget(self.x_lbl, 4, 0)
- grid0.addWidget(self.x_entry, 4, 1)
+ pos_grid.addWidget(self.x_lbl, 2, 0)
+ pos_grid.addWidget(self.x_entry, 2, 1)
# Y Pos
self.y_lbl = FCLabel('%s:' % _("Y"))
self.y_entry = FCDoubleSpinner()
self.y_entry.set_precision(self.decimals)
self.y_entry.set_range(-10000.0000, 10000.0000)
- grid0.addWidget(self.y_lbl, 6, 0)
- grid0.addWidget(self.y_entry, 6, 1)
+ pos_grid.addWidget(self.y_lbl, 4, 0)
+ pos_grid.addWidget(self.y_entry, 4, 1)
+
+ self.corner_lbl = FCLabel('%s' % _("Corner"), bold=True, color='green')
+ grid0.addWidget(self.corner_lbl, 4, 0, 1, 2)
+ # #############################################################################################################
+ # Corner Frame
+ # #############################################################################################################
+ cor_frame = FCFrame()
+ grid0.addWidget(cor_frame, 6, 0, 1, 2)
+
+ cor_grid = GLay(v_spacing=5, h_spacing=3)
+ cor_frame.setLayout(cor_grid)
# Corner Type
- self.corner_lbl = FCLabel('%s:' % _("Corner"))
+ self.corner_lbl = FCLabel('%s:' % _("Type"))
self.corner_lbl.setToolTip(
_("There are 3 types of corners:\n"
" - 'Round': the corners are rounded\n"
@@ -265,42 +284,51 @@ class RectangleEditorUI:
{'label': _('Square'), 'value': 's'},
{'label': _('Beveled'), 'value': 'b'},
], orientation='vertical', compact=True)
- grid0.addWidget(self.corner_lbl, 8, 0)
- grid0.addWidget(self.corner_radio, 8, 1)
+ cor_grid.addWidget(self.corner_lbl, 0, 0)
+ cor_grid.addWidget(self.corner_radio, 0, 1)
# Radius
self.radius_lbl = FCLabel('%s:' % _("Radius"))
self.radius_entry = FCDoubleSpinner()
self.radius_entry.set_precision(self.decimals)
self.radius_entry.set_range(0.0000, 10000.0000)
- grid0.addWidget(self.radius_lbl, 10, 0)
- grid0.addWidget(self.radius_entry, 10, 1)
+ cor_grid.addWidget(self.radius_lbl, 2, 0)
+ cor_grid.addWidget(self.radius_entry, 2, 1)
# Size
- self.size_lbl = FCLabel('%s' % _("Size"))
- grid0.addWidget(self.size_lbl, 12, 0, 1, 2)
+ self.size_lbl = FCLabel('%s' % _("Size"), bold=True, color='indigo')
+ grid0.addWidget(self.size_lbl, 8, 0, 1, 2)
+ # #############################################################################################################
+ # Size Frame
+ # #############################################################################################################
+ size_frame = FCFrame()
+ grid0.addWidget(size_frame, 10, 0, 1, 2)
+
+ size_grid = GLay(v_spacing=5, h_spacing=3)
+ size_frame.setLayout(size_grid)
# Length
self.length_lbl = FCLabel('%s:' % _("Length"))
self.length_entry = NumericalEvalEntry()
- grid0.addWidget(self.length_lbl, 14, 0)
- grid0.addWidget(self.length_entry, 14, 1)
+ size_grid.addWidget(self.length_lbl, 0, 0)
+ size_grid.addWidget(self.length_entry, 0, 1)
# Width
self.width_lbl = FCLabel('%s:' % _("Width"))
self.width_entry = NumericalEvalEntry()
- grid0.addWidget(self.width_lbl, 16, 0)
- grid0.addWidget(self.width_entry, 16, 1)
+ size_grid.addWidget(self.width_lbl, 2, 0)
+ size_grid.addWidget(self.width_entry, 2, 1)
# Buttons
self.add_button = FCButton(_("Add"))
self.add_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
grid0.addWidget(self.add_button, 18, 0, 1, 2)
+ GLay.set_common_column_size([grid0, pos_grid, cor_grid, size_grid], 0)
self.layout.addStretch(1)
# Note
- self.note_lbl = FCLabel('%s' % _("Note"))
+ self.note_lbl = FCLabel('%s' % _("Note"), bold=True)
self.layout.addWidget(self.note_lbl)
self.note_description_lbl = FCLabel('%s' % _("Shift + click to select a shape for modification."))
self.layout.addWidget(self.note_description_lbl)
diff --git a/appEditors/geo_plugins/GeoSimplificationPlugin.py b/appEditors/geo_plugins/GeoSimplificationPlugin.py
index d350813e..cc89b1e1 100644
--- a/appEditors/geo_plugins/GeoSimplificationPlugin.py
+++ b/appEditors/geo_plugins/GeoSimplificationPlugin.py
@@ -196,43 +196,52 @@ class SimplificationEditorUI:
self.simp_tools_box.addLayout(grid0)
# Coordinates
- coords_lbl = FCLabel('%s:' % _("Coordinates"))
+ coords_lbl = FCLabel('%s' % _("Coordinates"), bold=True, color='red')
coords_lbl.setToolTip(
_("The coordinates of the selected geometry element.")
)
- grid0.addWidget(coords_lbl, 22, 0, 1, 3)
+ grid0.addWidget(coords_lbl, 0, 0, 1, 2)
+
+ # #############################################################################################################
+ # Coordinates Frame
+ # #############################################################################################################
+ coors_frame = FCFrame()
+ grid0.addWidget(coors_frame, 2, 0, 1, 2)
+
+ coords_grid = GLay(v_spacing=5, h_spacing=3)
+ coors_frame.setLayout(coords_grid)
self.geo_coords_entry = FCTextEdit()
self.geo_coords_entry.setPlaceholderText(
_("The coordinates of the selected geometry element.")
)
- grid0.addWidget(self.geo_coords_entry, 24, 0, 1, 3)
+ coords_grid.addWidget(self.geo_coords_entry, 0, 0, 1, 2)
# Vertex Points Number
- vertex_lbl = FCLabel('%s:' % _("Vertex Points"))
+ vertex_lbl = FCLabel('%s:' % _("Vertex Points"), bold=False)
vertex_lbl.setToolTip(
_("The number of vertex points in the selected geometry element.")
)
self.geo_vertex_entry = FCEntry(decimals=self.decimals)
self.geo_vertex_entry.setReadOnly(True)
- grid0.addWidget(vertex_lbl, 26, 0)
- grid0.addWidget(self.geo_vertex_entry, 26, 1, 1, 2)
-
- separator_line = QtWidgets.QFrame()
- separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
- separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
- grid0.addWidget(separator_line, 28, 0, 1, 3)
+ coords_grid.addWidget(vertex_lbl, 2, 0)
+ coords_grid.addWidget(self.geo_vertex_entry, 2, 1)
# Simplification Title
- simplif_lbl = FCLabel('%s:' % _("Simplification"))
- simplif_lbl.setToolTip(
- _("Simplify a geometry by reducing its vertex points number.")
- )
- grid0.addWidget(simplif_lbl, 30, 0, 1, 3)
+ par_lbl = FCLabel('%s' % _("Parameters"), bold=True, color='blue')
+ grid0.addWidget(par_lbl, 4, 0, 1, 2)
+ # #############################################################################################################
+ # Parameters Frame
+ # #############################################################################################################
+ par_frame = FCFrame()
+ grid0.addWidget(par_frame, 6, 0, 1, 2)
+
+ par_grid = GLay(v_spacing=5, h_spacing=3)
+ par_frame.setLayout(par_grid)
# Simplification Tolerance
- simplification_tol_lbl = FCLabel('%s:' % _("Tolerance"))
+ simplification_tol_lbl = FCLabel('%s' % _("Tolerance"), bold=True)
simplification_tol_lbl.setToolTip(
_("All points in the simplified object will be\n"
"within the tolerance distance of the original geometry.")
@@ -242,8 +251,8 @@ class SimplificationEditorUI:
self.geo_tol_entry.setSingleStep(10 ** -self.decimals)
self.geo_tol_entry.set_range(0.0000, 10000.0000)
- grid0.addWidget(simplification_tol_lbl, 32, 0)
- grid0.addWidget(self.geo_tol_entry, 32, 1, 1, 2)
+ par_grid.addWidget(simplification_tol_lbl, 0, 0)
+ par_grid.addWidget(self.geo_tol_entry, 0, 1)
# Simplification button
self.simplification_btn = FCButton(_("Simplify"))
@@ -258,6 +267,7 @@ class SimplificationEditorUI:
}
""")
- grid0.addWidget(self.simplification_btn, 34, 0, 1, 3)
+ self.layout.addWidget(self.simplification_btn)
+ GLay.set_common_column_size([grid0, coords_grid, par_grid], 0)
self.layout.addStretch(1)
diff --git a/appGUI/GUIElements.py b/appGUI/GUIElements.py
index c7b01204..bf07c8e3 100644
--- a/appGUI/GUIElements.py
+++ b/appGUI/GUIElements.py
@@ -1045,12 +1045,25 @@ class FCColorEntry(QtWidgets.QFrame):
return value[7:9]
+class FCSlider(QtWidgets.QSlider):
+
+ def __int__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
+
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
+
+
class FCSliderWithSpinner(QtWidgets.QFrame):
def __init__(self, min=0, max=100, step=1, **kwargs):
super().__init__(**kwargs)
- self.slider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal)
+ self.slider = FCSlider(QtCore.Qt.Orientation.Horizontal)
self.slider.setMinimum(min)
self.slider.setMaximum(max)
self.slider.setSingleStep(step)
@@ -1075,7 +1088,7 @@ class FCSliderWithSpinner(QtWidgets.QFrame):
self.spinner.valueChanged.connect(self._on_spinner)
self.valueChanged = self.spinner.valueChanged
- self.slider.installEventFilter(self)
+ # self.slider.installEventFilter(self)
def get_value(self) -> int:
return self.spinner.get_value()
@@ -1091,11 +1104,11 @@ class FCSliderWithSpinner(QtWidgets.QFrame):
slider_value = self.slider.value()
self.spinner.set_value(slider_value)
- def eventFilter(self, object, event):
- if event.type() == QtCore.QEvent.Type.Wheel:
- if not self.slider.hasFocus():
- return True
- return False
+ # def eventFilter(self, object, event):
+ # if event.type() == QtCore.QEvent.Type.Wheel:
+ # if not self.slider.hasFocus():
+ # return True
+ # return False
class FCSpinner(QtWidgets.QSpinBox):
@@ -1127,6 +1140,7 @@ class FCSpinner(QtWidgets.QSpinBox):
self.prev_readyToEdit = True
self.menu = None
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
if policy:
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Ignored,
QtWidgets.QSizePolicy.Policy.Preferred)
@@ -1151,10 +1165,17 @@ class FCSpinner(QtWidgets.QSpinBox):
else:
super().keyPressEvent(event)
- def wheelEvent(self, *args, **kwargs):
- # should work only there is a focus in the lineedit of the SpinBox
- if self.readyToEdit is False:
- super().wheelEvent(*args, **kwargs)
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
+ # def wheelEvent(self, *args, **kwargs):
+ # # should work only there is a focus in the lineedit of the SpinBox
+ # if self.readyToEdit is False:
+ # super().wheelEvent(*args, **kwargs)
+ # return
+ # self.clearFocus()
def on_edit_finished(self):
self.clearFocus()
@@ -1326,173 +1347,6 @@ class FCSpinner(QtWidgets.QSpinBox):
# return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
-class FCDoubleSlider(QtWidgets.QSlider):
- # frome here: https://stackoverflow.com/questions/42820380/use-float-for-qslider
-
- # create our our signal that we can connect to if necessary
- doubleValueChanged = pyqtSignal(float)
-
- def __init__(self, decimals=3, orientation='horizontal', *args, **kargs):
- if orientation == 'horizontal':
- super(FCDoubleSlider, self).__init__(QtCore.Qt.Orientation.Horizontal, *args, **kargs)
- else:
- super(FCDoubleSlider, self).__init__(QtCore.Qt.Orientation.Vertical, *args, **kargs)
-
- self._multi = 10 ** decimals
-
- self.valueChanged.connect(self.emitDoubleValueChanged)
-
- def emitDoubleValueChanged(self):
- value = float(super(FCDoubleSlider, self).value()) / self._multi
- self.doubleValueChanged.emit(value)
-
- def value(self):
- return float(super(FCDoubleSlider, self).value()) / self._multi
-
- def get_value(self):
- return self.value()
-
- def setMinimum(self, value):
- return super(FCDoubleSlider, self).setMinimum(int(value * self._multi))
-
- def setMaximum(self, value):
- return super(FCDoubleSlider, self).setMaximum(int(value * self._multi))
-
- def setSingleStep(self, value):
- return super(FCDoubleSlider, self).setSingleStep(int(value * self._multi))
-
- def singleStep(self):
- return float(super(FCDoubleSlider, self).singleStep()) / self._multi
-
- def set_value(self, value):
- super(FCDoubleSlider, self).setValue(int(value * self._multi))
-
- def set_precision(self, decimals):
- self._multi = 10 ** decimals
-
- def set_range(self, min, max):
- self.blockSignals(True)
- self.setRange(int(min * self._multi), int(max * self._multi))
- self.blockSignals(False)
-
-
-class FCSliderWithDoubleSpinner(QtWidgets.QFrame):
-
- def __init__(self, min=0, max=10000.0000, step=1, precision=4, orientation='horizontal', **kwargs):
- super().__init__(**kwargs)
-
- self.slider = FCDoubleSlider(orientation=orientation)
- self.slider.setMinimum(min)
- self.slider.setMaximum(max)
- self.slider.setSingleStep(step)
- self.slider.set_range(min, max)
-
- self.spinner = FCDoubleSpinner()
- self.spinner.set_range(min, max)
- self.spinner.set_precision(precision)
-
- self.spinner.set_step(step)
- self.spinner.setMinimumWidth(70)
-
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred,
- QtWidgets.QSizePolicy.Policy.Preferred)
- self.spinner.setSizePolicy(sizePolicy)
-
- self.layout = QtWidgets.QHBoxLayout()
- self.layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
- self.layout.setContentsMargins(0, 0, 0, 0)
- self.layout.addWidget(self.slider)
- self.layout.addWidget(self.spinner)
- self.setLayout(self.layout)
-
- self.slider.doubleValueChanged.connect(self._on_slider)
- self.spinner.valueChanged.connect(self._on_spinner)
-
- self.valueChanged = self.spinner.valueChanged
-
- def set_precision(self, prec):
- self.spinner.set_precision(prec)
-
- def setSingleStep(self, step):
- self.spinner.set_step(step)
-
- def set_range(self, min, max):
- self.spinner.set_range(min, max)
- self.slider.set_range(min, max)
-
- def set_minimum(self, min):
- self.slider.setMinimum(min)
- self.spinner.setMinimum(min)
-
- def set_maximum(self, max):
- self.slider.setMaximum(max)
- self.spinner.setMaximum(max)
-
- def get_value(self) -> float:
- return self.spinner.get_value()
-
- def set_value(self, value: float):
- self.spinner.set_value(value)
-
- def _on_spinner(self):
- spinner_value = self.spinner.value()
- self.slider.set_value(spinner_value)
-
- def _on_slider(self):
- slider_value = self.slider.value()
- self.spinner.set_value(slider_value)
-
-
-class FCButtonWithDoubleSpinner(QtWidgets.QFrame):
-
- def __init__(self, min=0, max=100, step=1, decimals=4, button_text='', button_icon=None, callback=None, **kwargs):
- super().__init__(**kwargs)
-
- self.button = QtWidgets.QToolButton()
- if button_text != '':
- self.button.setText(button_text)
- if button_icon:
- self.button.setIcon(button_icon)
-
- self.spinner = FCDoubleSpinner()
- self.spinner.set_range(min, max)
- self.spinner.set_step(step)
- self.spinner.set_precision(decimals)
- self.spinner.setMinimumWidth(70)
-
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding,
- QtWidgets.QSizePolicy.Policy.Preferred)
- self.spinner.setSizePolicy(sizePolicy)
-
- self.layout = QtWidgets.QHBoxLayout()
- self.layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
- self.layout.setContentsMargins(0, 0, 0, 0)
- self.layout.addWidget(self.spinner)
- self.layout.addWidget(self.button)
- self.setLayout(self.layout)
-
- self.valueChanged = self.spinner.valueChanged
-
- self._callback = callback
- self.button.clicked.connect(self._callback)
-
- def get_value(self) -> float:
- return self.spinner.get_value()
-
- def set_value(self, value: float):
- self.spinner.set_value(value)
-
- def set_callback(self, callback):
- self._callback = callback
-
- def set_text(self, txt: str):
- if txt:
- self.button.setText(txt)
-
- def set_icon(self, icon: QtGui.QIcon):
- self.button.setIcon(icon)
-
-
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
returnPressed = QtCore.pyqtSignal()
confirmation_signal = QtCore.pyqtSignal(bool, float, float)
@@ -1507,6 +1361,7 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
:param policy: by default the widget will not compact as much as possible on horizontal
"""
super(FCDoubleSpinner, self).__init__(parent)
+ self.cursor_pos = None
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
@@ -1536,6 +1391,7 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
self.prev_readyToEdit = True
self.menu = None
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
if policy:
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Ignored,
QtWidgets.QSizePolicy.Policy.Preferred)
@@ -1565,10 +1421,15 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
else:
super().keyPressEvent(event)
- def wheelEvent(self, *args, **kwargs):
- # should work only there is a focus in the lineedit of the SpinBox
- if self.readyToEdit is False:
- super().wheelEvent(*args, **kwargs)
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
+ # def wheelEvent(self, *args, **kwargs):
+ # # should work only there is a focus in the lineedit of the SpinBox
+ # if self.readyToEdit is False:
+ # super().wheelEvent(*args, **kwargs)
def focusOutEvent(self, e):
# don't focus out if the user requests an popup menu
@@ -1747,6 +1608,189 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
# return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
+class FCSliderWithDoubleSpinner(QtWidgets.QFrame):
+
+ def __init__(self, min=0, max=10000.0000, step=1, precision=4, orientation='horizontal', **kwargs):
+ super().__init__(**kwargs)
+
+ self.slider = FCDoubleSlider(orientation=orientation)
+ self.slider.setMinimum(min)
+ self.slider.setMaximum(max)
+ self.slider.setSingleStep(step)
+ self.slider.set_range(min, max)
+
+ self.spinner = FCDoubleSpinner()
+ self.spinner.set_range(min, max)
+ self.spinner.set_precision(precision)
+
+ self.spinner.set_step(step)
+ self.spinner.setMinimumWidth(70)
+
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred,
+ QtWidgets.QSizePolicy.Policy.Preferred)
+ self.spinner.setSizePolicy(sizePolicy)
+
+ self.layout = QtWidgets.QHBoxLayout()
+ self.layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
+ self.layout.setContentsMargins(0, 0, 0, 0)
+ self.layout.addWidget(self.slider)
+ self.layout.addWidget(self.spinner)
+ self.setLayout(self.layout)
+
+ self.slider.doubleValueChanged.connect(self._on_slider)
+ self.spinner.valueChanged.connect(self._on_spinner)
+
+ self.valueChanged = self.spinner.valueChanged
+
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
+
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
+
+ def set_precision(self, prec):
+ self.spinner.set_precision(prec)
+
+ def setSingleStep(self, step):
+ self.spinner.set_step(step)
+
+ def set_range(self, min, max):
+ self.spinner.set_range(min, max)
+ self.slider.set_range(min, max)
+
+ def set_minimum(self, min):
+ self.slider.setMinimum(min)
+ self.spinner.setMinimum(min)
+
+ def set_maximum(self, max):
+ self.slider.setMaximum(max)
+ self.spinner.setMaximum(max)
+
+ def get_value(self) -> float:
+ return self.spinner.get_value()
+
+ def set_value(self, value: float):
+ self.spinner.set_value(value)
+
+ def _on_spinner(self):
+ spinner_value = self.spinner.value()
+ self.slider.set_value(spinner_value)
+
+ def _on_slider(self):
+ slider_value = self.slider.value()
+ self.spinner.set_value(slider_value)
+
+
+class FCDoubleSlider(QtWidgets.QSlider):
+ # frome here: https://stackoverflow.com/questions/42820380/use-float-for-qslider
+
+ # create our own signal that we can connect to if necessary
+ doubleValueChanged = pyqtSignal(float)
+
+ def __init__(self, decimals=3, orientation='horizontal', *args, **kargs):
+ if orientation == 'horizontal':
+ super(FCDoubleSlider, self).__init__(QtCore.Qt.Orientation.Horizontal, *args, **kargs)
+ else:
+ super(FCDoubleSlider, self).__init__(QtCore.Qt.Orientation.Vertical, *args, **kargs)
+
+ self._multi = 10 ** decimals
+
+ self.valueChanged.connect(self.emitDoubleValueChanged)
+
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
+
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
+
+ def emitDoubleValueChanged(self):
+ value = float(super(FCDoubleSlider, self).value()) / self._multi
+ self.doubleValueChanged.emit(value)
+
+ def value(self):
+ return float(super(FCDoubleSlider, self).value()) / self._multi
+
+ def get_value(self):
+ return self.value()
+
+ def setMinimum(self, value):
+ return super(FCDoubleSlider, self).setMinimum(int(value * self._multi))
+
+ def setMaximum(self, value):
+ return super(FCDoubleSlider, self).setMaximum(int(value * self._multi))
+
+ def setSingleStep(self, value):
+ return super(FCDoubleSlider, self).setSingleStep(int(value * self._multi))
+
+ def singleStep(self):
+ return float(super(FCDoubleSlider, self).singleStep()) / self._multi
+
+ def set_value(self, value):
+ super(FCDoubleSlider, self).setValue(int(value * self._multi))
+
+ def set_precision(self, decimals):
+ self._multi = 10 ** decimals
+
+ def set_range(self, min, max):
+ self.blockSignals(True)
+ self.setRange(int(min * self._multi), int(max * self._multi))
+ self.blockSignals(False)
+
+
+class FCButtonWithDoubleSpinner(QtWidgets.QFrame):
+
+ def __init__(self, min=0, max=100, step=1, decimals=4, button_text='', button_icon=None, callback=None, **kwargs):
+ super().__init__(**kwargs)
+
+ self.button = QtWidgets.QToolButton()
+ if button_text != '':
+ self.button.setText(button_text)
+ if button_icon:
+ self.button.setIcon(button_icon)
+
+ self.spinner = FCDoubleSpinner()
+ self.spinner.set_range(min, max)
+ self.spinner.set_step(step)
+ self.spinner.set_precision(decimals)
+ self.spinner.setMinimumWidth(70)
+
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding,
+ QtWidgets.QSizePolicy.Policy.Preferred)
+ self.spinner.setSizePolicy(sizePolicy)
+
+ self.layout = QtWidgets.QHBoxLayout()
+ self.layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
+ self.layout.setContentsMargins(0, 0, 0, 0)
+ self.layout.addWidget(self.spinner)
+ self.layout.addWidget(self.button)
+ self.setLayout(self.layout)
+
+ self.valueChanged = self.spinner.valueChanged
+
+ self._callback = callback
+ self.button.clicked.connect(self._callback)
+
+ def get_value(self) -> float:
+ return self.spinner.get_value()
+
+ def set_value(self, value: float):
+ self.spinner.set_value(value)
+
+ def set_callback(self, callback):
+ self._callback = callback
+
+ def set_text(self, txt: str):
+ if txt:
+ self.button.setText(txt)
+
+ def set_icon(self, icon: QtGui.QIcon):
+ self.button.setIcon(icon)
+
+
class FCCheckBox(QtWidgets.QCheckBox):
def __init__(self, label='', parent=None):
super(FCCheckBox, self).__init__(str(label), parent)
@@ -2491,6 +2535,7 @@ class FCComboBox(QtWidgets.QComboBox):
self._set_last = False
self._obj_type = None
+ self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
if policy is True:
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Ignored,
QtWidgets.QSizePolicy.Policy.Preferred)
@@ -2508,8 +2553,11 @@ class FCComboBox(QtWidgets.QComboBox):
return True
return False
- def wheelEvent(self, *args, **kwargs):
- pass
+ def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
+ if self.hasFocus():
+ super().wheelEvent(event)
+ else:
+ event.ignore()
def get_value(self):
return str(self.currentText())
diff --git a/appGUI/MainGUI.py b/appGUI/MainGUI.py
index 56bd706b..8aa2d52f 100644
--- a/appGUI/MainGUI.py
+++ b/appGUI/MainGUI.py
@@ -41,6 +41,8 @@ import gettext
import appTranslation as fcTranslate
import builtins
+import darkdetect
+
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
@@ -52,8 +54,40 @@ class MainGUI(QtWidgets.QMainWindow):
final_save = QtCore.pyqtSignal(name='saveBeforeExit')
# screenChanged = QtCore.pyqtSignal(QtGui.QScreen, QtGui.QScreen)
+ # Mapping of colors used for text on Light theme to
+ # similar colors safe for use on Dark theme
+ # 'input_color': (light_color, dark_color),
+ theme_safe_colors = {
+ "blue": "#1F80FF",
+ "brown": "#CC9966",
+ "darkgreen": "#008015",
+ "darkorange": "darkorange",
+ "green": "#00CC22",
+ "indigo": "#9457EB",
+ "magenta": "magenta",
+ "orange": "orange",
+ "purple": "#B284BE",
+ "red": "salmon",
+ "teal": "teal",
+ "tomato": "tomato",
+ }
+
def theme_safe_color(self, color):
- return color
+ """
+ Some colors do not work well with light or dark backgrounds making them unreadable in the wrong
+ theme. For an approved color value this will return a similar color better suited for the current theme.
+
+ :param color: color to be replaced
+ :return: similar color better suited for dark or light theme
+ """
+
+ if color in self.theme_safe_colors:
+ if self.app.options['global_theme'] in ['default', 'light']:
+ return color
+ else:
+ return self.theme_safe_colors[color]
+ else:
+ return color
# https://www.w3.org/TR/SVG11/types.html#ColorKeywords
def __init__(self, app):
@@ -140,12 +174,12 @@ class MainGUI(QtWidgets.QMainWindow):
# Open Gerber ...
self.menufileopengerber = QtGui.QAction(QtGui.QIcon(self.app.resource_location + '/flatcam_icon24.png'),
- '%s...\t%s' % (_('Open Gerber'), _('Ctrl+G')), self)
+ '%s...\t%s' % (_('Open Gerber'), _('Ctrl+G')), self)
self.menufile_open.addAction(self.menufileopengerber)
# Open Excellon ...
self.menufileopenexcellon = QtGui.QAction(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'),
- '%s...\t%s' % (_('Open Excellon'), _('Ctrl+E')), self)
+ '%s...\t%s' % (_('Open Excellon'), _('Ctrl+E')), self)
self.menufile_open.addAction(self.menufileopenexcellon)
# Open G-Code ...
@@ -177,7 +211,7 @@ class MainGUI(QtWidgets.QMainWindow):
# Save Project As ...
self.menufilesaveprojectas = QtGui.QAction(QtGui.QIcon(self.app.resource_location + '/floppy16.png'),
- '%s...\t%s' % (_('Save Project As'), _('Ctrl+Shift+S')), self)
+ '%s...\t%s' % (_('Save Project As'), _('Ctrl+Shift+S')), self)
self.menufile_save.addAction(self.menufilesaveprojectas)
# Save Project Copy ...
@@ -196,9 +230,9 @@ class MainGUI(QtWidgets.QMainWindow):
self.menufile_scripting.setToolTipsVisible(True)
self.menufilenewscript = QtGui.QAction(QtGui.QIcon(self.app.resource_location + '/script_new16.png'),
- '%s...\t%s' % (_('New Script'), ''), self)
+ '%s...\t%s' % (_('New Script'), ''), self)
self.menufileopenscript = QtGui.QAction(QtGui.QIcon(self.app.resource_location + '/open_script32.png'),
- '%s...\t%s' % (_('Open Script'), ''), self)
+ '%s...\t%s' % (_('Open Script'), ''), self)
self.menufileopenscriptexample = QtGui.QAction(
QtGui.QIcon(self.app.resource_location + '/open_script32.png'),
'%s...\t%s' % (_('Open Example'), ''), self)
@@ -715,7 +749,7 @@ class MainGUI(QtWidgets.QMainWindow):
'%s\t%s' % (_("Copy Geom"), _('C')))
self.geo_delete_menuitem = self.geo_editor_menu.addAction(
QtGui.QIcon(self.app.resource_location + '/deleteshape16.png'),
- '%s\t%s' % (_("Delete Shape"), _('DEL'))
+ '%s\t%s' % (_("Delete"), _('DEL'))
)
self.geo_editor_menu.addSeparator()
self.geo_move_menuitem = self.geo_editor_menu.addAction(
@@ -1263,7 +1297,7 @@ class MainGUI(QtWidgets.QMainWindow):
QtGui.QIcon(self.app.resource_location + '/copy32.png'), _("Copy Shape(s)"))
self.geo_delete_btn = self.geo_edit_toolbar.addAction(
- QtGui.QIcon(self.app.resource_location + '/trash32.png'), _("Delete Shape"))
+ QtGui.QIcon(self.app.resource_location + '/trash32.png'), _("Delete"))
self.geo_transform_btn = self.geo_edit_toolbar.addAction(
QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transformations"))
self.geo_edit_toolbar.addSeparator()
@@ -2034,7 +2068,7 @@ class MainGUI(QtWidgets.QMainWindow):
self.lock_action.triggered[bool].connect(self.lock_toolbar)
self.pref_open_button.clicked.connect(self.on_preferences_open_folder)
- self.clear_btn.clicked.connect(self.on_gui_clear)
+ self.clear_btn.clicked.connect(lambda: self.on_gui_clear())
self.wplace_label.clicked.connect(self.app.on_workspace_toggle)
self.fcinfo.clicked.connect(self.toggle_shell_ui)
@@ -2353,19 +2387,17 @@ class MainGUI(QtWidgets.QMainWindow):
subprocess.Popen(['xdg-open', self.app.data_path])
self.app.inform.emit('[success] %s' % _("FlatCAM Preferences Folder opened."))
- def on_gui_clear(self, signal=None, forced_clear=False):
+ def on_gui_clear(self, forced_clear=False):
"""
Will clear the settings that are stored in QSettings.
"""
self.app.log.debug("Clearing the settings in QSettings. GUI settings cleared.")
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
- theme_settings.setValue('theme', 'white')
+ theme_settings.setValue('theme', 'light')
del theme_settings
- resource_loc = self.app.resource_location
-
response = None
bt_yes = None
if forced_clear is False:
@@ -2633,7 +2665,7 @@ class MainGUI(QtWidgets.QMainWindow):
self.geo_copy_btn = self.geo_edit_toolbar.addAction(
QtGui.QIcon(self.app.resource_location + '/copy32.png'), _("Copy Objects"))
self.geo_delete_btn = self.geo_edit_toolbar.addAction(
- QtGui.QIcon(self.app.resource_location + '/trash32.png'), _("Delete Shape"))
+ QtGui.QIcon(self.app.resource_location + '/trash32.png'), _("Delete"))
self.geo_transform_btn = self.geo_edit_toolbar.addAction(
QtGui.QIcon(self.app.resource_location + '/transform.png'), _("Transformations"))
@@ -3496,27 +3528,27 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.geo_editor.select_tool('select')
return
else:
- if self.app.geo_editor.active_tool.name == 'path' and \
- self.app.geo_editor.active_tool.path_tool.length != 0.0:
+ if self.app.geo_editor.active_tool.name == 'path' \
+ and self.app.geo_editor.active_tool.path_tool.length != 0.0:
pass
- elif self.app.geo_editor.active_tool.name == 'polygon' and \
- self.app.geo_editor.active_tool.polygon_tool.length != 0.0:
+ elif self.app.geo_editor.active_tool.name == 'polygon' \
+ and self.app.geo_editor.active_tool.polygon_tool.length != 0.0:
pass
- elif self.app.geo_editor.active_tool.name == 'circle' and \
- self.app.geo_editor.active_tool.circle_tool.x != 0.0 and \
- self.app.geo_editor.active_tool.circle_tool.y != 0.0:
+ elif self.app.geo_editor.active_tool.name == 'circle' \
+ and self.app.geo_editor.active_tool.circle_tool.x != 0.0 \
+ and self.app.geo_editor.active_tool.circle_tool.y != 0.0:
pass
- elif self.app.geo_editor.active_tool.name == 'rectangle' and \
- self.app.geo_editor.active_tool.rect_tool.length != 0.0 and \
- self.app.geo_editor.active_tool.rect_tool.width != 0.0:
+ elif self.app.geo_editor.active_tool.name == 'rectangle' \
+ and self.app.geo_editor.active_tool.rect_tool.length != 0.0 \
+ and self.app.geo_editor.active_tool.rect_tool.width != 0.0:
pass
- elif self.app.geo_editor.active_tool.name == 'move' and \
- self.app.geo_editor.active_tool.move_tool.length != 0.0 and \
- self.app.geo_editor.active_tool.move_tool.width != 0.0:
+ elif self.app.geo_editor.active_tool.name == 'move' \
+ and self.app.geo_editor.active_tool.move_tool.length != 0.0 \
+ and self.app.geo_editor.active_tool.move_tool.width != 0.0:
pass
- elif self.app.geo_editor.active_tool.name == 'copy' and \
- self.app.geo_editor.active_tool.copy_tool.length != 0.0 and \
- self.app.geo_editor.active_tool.copy_tool.width != 0.0:
+ elif self.app.geo_editor.active_tool.name == 'copy' \
+ and self.app.geo_editor.active_tool.copy_tool.length != 0.0 \
+ and self.app.geo_editor.active_tool.copy_tool.width != 0.0:
pass
else:
self.app.geo_editor.active_tool.click(
@@ -3862,8 +3894,9 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.inform.emit(_("Click on target point."))
self.app.ui.aperture_copy_btn.setChecked(True)
self.app.grb_editor.on_tool_select('copy')
- self.app.grb_editor.active_tool.set_origin(
- (self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
+ if self.app.grb_editor.active_tool is not None:
+ self.app.grb_editor.active_tool.set_origin(
+ (self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Nothing selected."))
return
@@ -3908,8 +3941,9 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.inform.emit(_("Click on target point."))
self.app.ui.aperture_move_btn.setChecked(True)
self.app.grb_editor.on_tool_select('move')
- self.app.grb_editor.active_tool.set_origin(
- (self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
+ if self.app.grb_editor.active_tool is not None:
+ self.app.grb_editor.active_tool.set_origin(
+ (self.app.grb_editor.snap_x, self.app.grb_editor.snap_y))
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Nothing selected."))
return
@@ -4120,8 +4154,9 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.inform.emit(_("Click on target point."))
self.app.ui.copy_drill_btn.setChecked(True)
self.app.exc_editor.on_tool_select('drill_copy')
- self.app.exc_editor.active_tool.set_origin(
- (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
+ if self.app.exc_editor.active_tool is not None:
+ self.app.exc_editor.active_tool.set_origin(
+ (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Nothing selected."))
return
@@ -4149,8 +4184,9 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.inform.emit(_("Click on target location ..."))
self.app.ui.move_drill_btn.setChecked(True)
self.app.exc_editor.on_tool_select('drill_move')
- self.app.exc_editor.active_tool.set_origin(
- (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
+ if self.app.exc_editor.active_tool is not None:
+ self.app.exc_editor.active_tool.set_origin(
+ (self.app.exc_editor.snap_x, self.app.exc_editor.snap_y))
else:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. Nothing selected."))
return
@@ -5211,7 +5247,7 @@ class ShortcutsTab(QtWidgets.QWidget):
_('Space'), _("Rotate Geometry"),
_('ENTER'), _("Finish drawing for certain tools"),
_('Esc'), _("Abort and return to Select"),
- _('Del'), _("Delete Shape")
+ _('Del'), _("Delete")
)
# EXCELLON EDITOR SHORTCUT LIST
diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py
index 143cac9c..a7b757eb 100644
--- a/appGUI/ObjectUI.py
+++ b/appGUI/ObjectUI.py
@@ -40,12 +40,12 @@ class ObjectUI(QtWidgets.QWidget):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
@@ -197,7 +197,7 @@ class GerberObjectUI(ObjectUI):
plot_grid.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
gen_frame.setLayout(plot_grid)
- self.plot_options_label = FCLabel("%s:" % _("Plot Options"))
+ self.plot_options_label = FCLabel('%s:' % _("Plot Options"), bold=True)
plot_grid.addWidget(self.plot_options_label, 0, 0)
@@ -219,7 +219,7 @@ class GerberObjectUI(ObjectUI):
self.name_hlay = QtWidgets.QHBoxLayout()
plot_grid.addLayout(self.name_hlay, 1, 0, 1, 3)
- name_label = FCLabel("%s:" % _("Name"))
+ name_label = FCLabel('%s:' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.name_hlay.addWidget(name_label)
@@ -482,7 +482,7 @@ class GerberObjectUI(ObjectUI):
# Non-Copper Regions Frame
# #############################################################################################################
# ## Non-copper regions
- self.noncopper_label = FCLabel("%s" % _("Non-copper regions"))
+ self.noncopper_label = FCLabel('%s' % _("Non-copper regions"), bold=True)
self.noncopper_label.setToolTip(
_("Create polygons covering the\n"
"areas without copper on the PCB.\n"
@@ -530,7 +530,7 @@ class GerberObjectUI(ObjectUI):
# Bounding Box Frame
# #############################################################################################################
# ## Bounding box
- self.boundingbox_label = FCLabel('%s' % _('Bounding Box'))
+ self.boundingbox_label = FCLabel('%s' % _('Bounding Box'), bold=True)
self.boundingbox_label.setToolTip(
_("Create a geometry surrounding the Gerber object.\n"
"Square shape.")
@@ -589,12 +589,12 @@ class ExcellonObjectUI(ObjectUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
ObjectUI.__init__(self, title=_('Excellon Object'),
icon_file=self.resource_loc + '/drill32.png',
@@ -617,7 +617,7 @@ class ExcellonObjectUI(ObjectUI):
gen_frame.setLayout(plot_grid)
# Plot options
- self.plot_options_label = FCLabel("%s: " % _("Plot Options"))
+ self.plot_options_label = FCLabel('%s: ' % _("Plot Options"), bold=True)
# Solid CB
self.solid_cb = FCCheckBox(label=_('Solid'))
@@ -638,7 +638,7 @@ class ExcellonObjectUI(ObjectUI):
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
- name_label = FCLabel("%s: " % _("Name"))
+ name_label = FCLabel('%s: ' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.name_hlay.addWidget(name_label)
@@ -844,7 +844,7 @@ class ExcellonObjectUI(ObjectUI):
# #############################################################################################################
# Milling Drill Holes Frame
# #############################################################################################################
- self.mill_hole_label = FCLabel('%s' % _('Milling Geometry'))
+ self.mill_hole_label = FCLabel('%s' % _('Milling Geometry'), bold=True)
self.mill_hole_label.setToolTip(
_("Create Geometry for milling holes.\n"
"Select from the Tools Table above the hole dias to be\n"
@@ -926,12 +926,12 @@ class GeometryObjectUI(ObjectUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
super(GeometryObjectUI, self).__init__(
title=_('Geometry Object'),
@@ -953,7 +953,7 @@ class GeometryObjectUI(ObjectUI):
plot_grid.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter)
gen_frame.setLayout(plot_grid)
- self.plot_options_label = FCLabel("%s:" % _("Plot Options"))
+ self.plot_options_label = FCLabel('%s:' % _("Plot Options"), bold=True)
self.plot_options_label.setMinimumWidth(90)
plot_grid.addWidget(self.plot_options_label, 0, 0)
@@ -970,7 +970,7 @@ class GeometryObjectUI(ObjectUI):
self.name_hlay = QtWidgets.QHBoxLayout()
plot_grid.addLayout(self.name_hlay, 2, 0, 1, 3)
- name_label = FCLabel("%s:" % _("Name"))
+ name_label = FCLabel('%s:' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.name_hlay.addWidget(name_label)
@@ -1033,7 +1033,7 @@ class GeometryObjectUI(ObjectUI):
self.tt_frame.setLayout(tt_grid)
# ### Tools ####
- self.tools_table_label = FCLabel('%s:' % _('Tools Table'))
+ self.tools_table_label = FCLabel('%s:' % _('Tools Table'), bold=True)
self.tools_table_label.setToolTip(
_("Tools in this Geometry object used for cutting.\n"
"The 'Offset' entry will set an offset for the cut.\n"
@@ -1182,7 +1182,7 @@ class GeometryObjectUI(ObjectUI):
# Simplification Frame
# #############################################################################################################
# Simplification Title
- simplif_lbl = FCLabel('%s:' % _("Simplification"))
+ simplif_lbl = FCLabel('%s' % _("Simplification"), bold=True)
simplif_lbl.setToolTip(
_("Simplify a geometry by reducing its vertex points number.")
)
@@ -1267,12 +1267,12 @@ class CNCObjectUI(ObjectUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
ObjectUI.__init__(self, title=_('CNC Job Object'),
icon_file=self.resource_loc + '/cnc32.png', parent=parent,
@@ -1296,7 +1296,7 @@ class CNCObjectUI(ObjectUI):
gen_frame.setLayout(grid0)
# Plot Options
- self.cncplot_method_label = FCLabel("%s: " % _("Plot Options"))
+ self.cncplot_method_label = FCLabel('%s: ' % _("Plot Options"), bold=True)
self.cncplot_method_label.setToolTip(
_(
"This selects the kind of geometries on the canvas to plot.\n"
@@ -1319,7 +1319,7 @@ class CNCObjectUI(ObjectUI):
grid0.addLayout(self.name_hlay, 2, 0, 1, 3)
# ## Object name
- name_label = FCLabel("%s: " % _("Name"))
+ name_label = FCLabel('%s: ' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
@@ -1387,7 +1387,7 @@ class CNCObjectUI(ObjectUI):
grid_par.addWidget(self.estimated_frame, 4, 0, 1, 3)
# Travelled Distance
- self.t_distance_label = FCLabel("%s:" % _("Travelled distance"))
+ self.t_distance_label = FCLabel('%s:' % _("Travelled distance"), bold=True)
self.t_distance_label.setToolTip(
_("This is the total travelled distance on X-Y plane.\n"
"In current units.")
@@ -1400,7 +1400,7 @@ class CNCObjectUI(ObjectUI):
estimated_grid.addWidget(self.units_label, 0, 2)
# Estimated Time
- self.t_time_label = FCLabel("%s:" % _("Estimated time"))
+ self.t_time_label = FCLabel('%s:' % _("Estimated time"), bold=True)
self.t_time_label.setToolTip(
_("This is the estimated time to do the routing/drilling,\n"
"without the time spent in ToolChange events.")
@@ -1456,7 +1456,7 @@ class CNCObjectUI(ObjectUI):
grid1.addLayout(hlay, 0, 0, 1, 2)
# CNC Tools Table for plot
- self.cnc_tools_table_label = FCLabel('%s' % _('CNC Tools Table'))
+ self.cnc_tools_table_label = FCLabel('%s' % _('CNC Tools Table'), bold=True)
self.cnc_tools_table_label.setToolTip(
_(
"Tools in this CNCJob object used for cutting.\n"
@@ -1585,12 +1585,12 @@ class ScriptObjectUI(ObjectUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
ObjectUI.__init__(self, title=_('Script Object'),
icon_file=self.resource_loc + '/script_new24.png',
@@ -1602,7 +1602,7 @@ class ScriptObjectUI(ObjectUI):
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
- name_label = FCLabel("%s:" % _("Name"))
+ name_label = FCLabel('%s:' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.name_hlay.addWidget(name_label)
@@ -1652,12 +1652,12 @@ class DocumentObjectUI(ObjectUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
- self.resource_loc = 'assets/resources'
+ self.resource_loc = 'assets/resources/dark_resources'
ObjectUI.__init__(self, title=_('Document Object'),
icon_file=self.resource_loc + '/notes16_1.png',
@@ -1669,7 +1669,7 @@ class DocumentObjectUI(ObjectUI):
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
- name_label = FCLabel("%s:" % _("Name"))
+ name_label = FCLabel('%s:' % _("Name"), bold=True)
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
self.name_hlay.addWidget(name_label)
diff --git a/appGUI/PlotCanvas.py b/appGUI/PlotCanvas.py
index 2253ce71..0d40cf9f 100644
--- a/appGUI/PlotCanvas.py
+++ b/appGUI/PlotCanvas.py
@@ -54,9 +54,14 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
- if theme == 'white':
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
self.line_color = (0.3, 0.0, 0.0, 1.0)
# self.rect_hud_color = Color('#0000FF10')
self.rect_hud_color = Color('#80808040')
@@ -384,9 +389,14 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
- if theme == 'white':
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
color = 'dimgray'
else:
color = '#dededeff'
@@ -712,7 +722,7 @@ class CursorBig(QtCore.QObject):
# if 'edge_color' in kwargs:
# color = kwargs['edge_color']
# else:
- # if self.app.options['global_theme'] == 'white':
+ # if self.app.options['global_theme'] == 'light':
# color = '#000000FF'
# else:
# color = '#FFFFFFFF'
diff --git a/appGUI/PlotCanvas3d.py b/appGUI/PlotCanvas3d.py
index 98051ece..748b459c 100644
--- a/appGUI/PlotCanvas3d.py
+++ b/appGUI/PlotCanvas3d.py
@@ -66,14 +66,19 @@ class PlotCanvas3d(QtCore.QObject, scene.SceneCanvas):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
+
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
if settings.contains("axis_font_size"):
a_fsize = settings.value('axis_font_size', type=int)
else:
a_fsize = 8
- if theme == 'white':
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
theme_color = Color('#FFFFFF')
tick_color = Color('#000000')
back_color = str(QPalette().color(QPalette.ColorRole.Window).name())
@@ -131,7 +136,7 @@ class PlotCanvas3d(QtCore.QObject, scene.SceneCanvas):
# self.xaxis.link_view(self.view)
# self.yaxis.link_view(self.view)
- # if theme == 'white':
+ # if theme == 'light':
# self.grid = scene.GridLines(parent=self.view.scene, color='dimgray')
# else:
# self.grid = scene.GridLines(parent=self.view.scene, color='#dededeff')
diff --git a/appGUI/PlotCanvasLegacy.py b/appGUI/PlotCanvasLegacy.py
index 2b5609e8..17590476 100644
--- a/appGUI/PlotCanvasLegacy.py
+++ b/appGUI/PlotCanvasLegacy.py
@@ -82,7 +82,18 @@ class CanvasCache(QtCore.QObject):
self.axes.set_xticks([])
self.axes.set_yticks([])
- if self.app.options['global_theme'] == 'white':
+ settings = QtCore.QSettings("Open Source", "FlatCAM")
+ if settings.contains("theme"):
+ theme = settings.value('theme', type=str)
+ else:
+ theme = 'default'
+
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
self.axes.set_facecolor('#FFFFFF')
else:
self.axes.set_facecolor('#000000')
@@ -154,7 +165,7 @@ class PlotCanvasLegacy(QtCore.QObject):
self.app = app
- if self.app.options['global_theme'] == 'white':
+ if self.app.options['global_theme'] in ['default', 'light']:
theme_color = '#FFFFFF'
tick_color = '#000000'
self.rect_hud_color = '#0000FF10'
@@ -446,7 +457,7 @@ class PlotCanvasLegacy(QtCore.QObject):
super().__init__()
self.p = plotcanvas
- units = self.p.app.app_units
+ # units = self.p.app.app_units
# self._text = 'Dx: %s [%s]\nDy: %s [%s]\n\nX: %s [%s]\nY: %s [%s]' % \
# ('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units)
self.on_update_text_hud()
@@ -639,7 +650,7 @@ class PlotCanvasLegacy(QtCore.QObject):
if self.app.options["global_cursor_color_enabled"]:
color = self.app.options["global_cursor_color"]
else:
- if self.app.options['global_theme'] == 'white':
+ if self.app.options['global_theme'] == 'light':
color = '#000000'
else:
color = '#FFFFFF'
@@ -694,7 +705,7 @@ class PlotCanvasLegacy(QtCore.QObject):
if color:
color = color
else:
- if self.app.options['global_theme'] == 'white':
+ if self.app.options['global_theme'] == 'light':
color = '#000000'
else:
color = '#FFFFFF'
@@ -737,7 +748,7 @@ class PlotCanvasLegacy(QtCore.QObject):
self.canvas.blit(self.axes.bbox)
def clear_cursor(self, state):
- if self.app.options['global_theme'] == 'white':
+ if self.app.options['global_theme'] == 'light':
color = '#000000'
else:
color = '#FFFFFF'
diff --git a/appGUI/VisPyCanvas.py b/appGUI/VisPyCanvas.py
index 597980d3..35d86aa4 100644
--- a/appGUI/VisPyCanvas.py
+++ b/appGUI/VisPyCanvas.py
@@ -39,9 +39,14 @@ class VisPyCanvas(scene.SceneCanvas):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
- if theme == 'white':
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
theme_color = Color('#FFFFFF')
tick_color = Color('#000000')
back_color = str(QPalette().color(QPalette.ColorRole.Window).name())
@@ -97,10 +102,15 @@ class VisPyCanvas(scene.SceneCanvas):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
+
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
self.view = view
- if theme == 'white':
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
self.grid = scene.GridLines(parent=self.view.scene, color='dimgray')
else:
self.grid = scene.GridLines(parent=self.view.scene, color='#dededeff')
diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py
index a5acde02..0e295799 100644
--- a/appGUI/preferences/PreferencesUIManager.py
+++ b/appGUI/preferences/PreferencesUIManager.py
@@ -28,6 +28,16 @@ class PreferencesUIManager(QtCore.QObject):
"""
super(PreferencesUIManager, self).__init__()
+ self.general_displayed = False
+ self.gerber_displayed = False
+ self.excellon_displayed = False
+ self.geometry_displayed = False
+ self.cnc_displayed = False
+ self.engrave_displayed = False
+ self.plugins_displayed = False
+ self.plugins2_displayed = False
+ self.util_displayed = False
+
self.defaults = defaults
self.data_path = data_path
self.ui = ui
@@ -73,8 +83,8 @@ class PreferencesUIManager(QtCore.QObject):
"global_tpdf_rmargin": self.ui.general_pref_form.general_app_group.rmargin_entry,
# General GUI Preferences
- "global_theme": self.ui.general_pref_form.general_gui_group.theme_radio,
- "global_gray_icons": self.ui.general_pref_form.general_gui_group.gray_icons_cb,
+ "global_appearance": self.ui.general_pref_form.general_gui_group.appearance_radio,
+ "global_dark_canvas": self.ui.general_pref_form.general_gui_group.dark_canvas_cb,
"global_layout": self.ui.general_pref_form.general_gui_group.layout_combo,
"global_hover_shape": self.ui.general_pref_form.general_gui_group.hover_cb,
"global_selection_shape": self.ui.general_pref_form.general_gui_group.selection_cb,
@@ -575,6 +585,7 @@ class PreferencesUIManager(QtCore.QObject):
# SolderPaste Dispensing Tool
"tools_solderpaste_tools": self.ui.plugin_pref_form.tools_solderpaste_group.nozzle_tool_dia_entry,
"tools_solderpaste_new": self.ui.plugin_pref_form.tools_solderpaste_group.addtool_entry,
+ "tools_solderpaste_margin": self.ui.plugin_pref_form.tools_solderpaste_group.margin_entry,
"tools_solderpaste_z_start": self.ui.plugin_pref_form.tools_solderpaste_group.z_start_entry,
"tools_solderpaste_z_dispense": self.ui.plugin_pref_form.tools_solderpaste_group.z_dispense_entry,
"tools_solderpaste_z_stop": self.ui.plugin_pref_form.tools_solderpaste_group.z_stop_entry,
@@ -798,6 +809,25 @@ class PreferencesUIManager(QtCore.QObject):
:return: None
"""
+ self.init_preferences_gui()
+
+ self.pref_connect()
+
+ # Initialize the color box's color in Preferences -> Global -> Colors
+ self.__init_color_pickers()
+
+ # log.debug("Finished Preferences GUI form initialization.")
+
+ def init_preferences_gui(self):
+ self.general_displayed = False
+ self.gerber_displayed = False
+ self.excellon_displayed = False
+ self.geometry_displayed = False
+ self.cnc_displayed = False
+ self.engrave_displayed = False
+ self.plugins_displayed = False
+ self.plugins2_displayed = False
+ self.util_displayed = False
gen_form = self.ui.general_pref_form
try:
@@ -807,72 +837,10 @@ class PreferencesUIManager(QtCore.QObject):
self.ui.general_scroll_area.setWidget(gen_form)
gen_form.show()
- ger_form = self.ui.gerber_pref_form
- try:
- self.ui.gerber_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.gerber_scroll_area.setWidget(ger_form)
- ger_form.show()
+ def pref_connect(self):
+ self.pref_disconnect()
- exc_form = self.ui.excellon_pref_form
- try:
- self.ui.excellon_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.excellon_scroll_area.setWidget(exc_form)
- exc_form.show()
-
- geo_form = self.ui.geo_pref_form
- try:
- self.ui.geometry_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.geometry_scroll_area.setWidget(geo_form)
- geo_form.show()
-
- cnc_form = self.ui.cncjob_pref_form
- try:
- self.ui.cncjob_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.cncjob_scroll_area.setWidget(cnc_form)
- cnc_form.show()
-
- plugins_engraving_form = self.ui.plugin_eng_pref_form
- try:
- self.ui.plugins_engraving_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.plugins_engraving_scroll_area.setWidget(plugins_engraving_form)
- plugins_engraving_form.show()
-
- plugins_form = self.ui.plugin_pref_form
- try:
- self.ui.tools_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.tools_scroll_area.setWidget(plugins_form)
- plugins_form.show()
-
- plugins2_form = self.ui.plugin2_pref_form
- try:
- self.ui.tools2_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.tools2_scroll_area.setWidget(plugins2_form)
- plugins2_form.show()
-
- fa_form = self.ui.util_pref_form
- try:
- self.ui.fa_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
- self.ui.fa_scroll_area.setWidget(fa_form)
- fa_form.show()
-
- # Initialize the color box's color in Preferences -> Global -> Colors
- self.__init_color_pickers()
+ self.ui.pref_tab_area.tabBarClicked.connect(self.on_tab_clicked)
# Button handlers
self.ui.pref_save_button.clicked.connect(lambda: self.on_save_button(save_to_file=True))
@@ -880,9 +848,12 @@ class PreferencesUIManager(QtCore.QObject):
self.ui.pref_close_button.clicked.connect(self.on_pref_close_button)
self.ui.pref_defaults_button.clicked.connect(self.on_restore_defaults_preferences)
- # log.debug("Finished Preferences GUI form initialization.")
+ def pref_disconnect(self):
+ try:
+ self.ui.pref_tab_area.tabBarClicked.disconnect()
+ except Exception:
+ pass
- def clear_preferences_gui(self):
# Disconnect Button handlers
try:
self.ui.pref_save_button.clicked.disconnect()
@@ -904,50 +875,143 @@ class PreferencesUIManager(QtCore.QObject):
except Exception:
pass
- try:
- self.ui.general_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ def clear_preferences_gui(self):
+ self.pref_disconnect()
+ # try:
+ # self.ui.general_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.gerber_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.excellon_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.geometry_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.cncjob_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.plugins_engraving_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.tools_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.tools2_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
+ #
+ # try:
+ # self.ui.fa_scroll_area.takeWidget()
+ # except Exception:
+ # self.ui.app.log.debug("Nothing to remove")
- try:
- self.ui.gerber_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ def on_tab_clicked(self, idx):
+ if idx == 0 and self.general_displayed is False:
+ self.general_displayed = True
+ gen_form = self.ui.general_pref_form
+ try:
+ self.ui.general_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.general_scroll_area.setWidget(gen_form)
+ gen_form.show()
- try:
- self.ui.excellon_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 1 and self.gerber_displayed is False:
+ self.gerber_displayed = True
+ ger_form = self.ui.gerber_pref_form
+ try:
+ self.ui.gerber_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.gerber_scroll_area.setWidget(ger_form)
+ ger_form.show()
- try:
- self.ui.geometry_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 2 and self.excellon_displayed is False:
+ self.excellon_displayed = True
+ exc_form = self.ui.excellon_pref_form
+ try:
+ self.ui.excellon_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.excellon_scroll_area.setWidget(exc_form)
+ exc_form.show()
- try:
- self.ui.cncjob_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 3 and self.geometry_displayed is False:
+ self.geometry_displayed = True
+ geo_form = self.ui.geo_pref_form
+ try:
+ self.ui.geometry_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.geometry_scroll_area.setWidget(geo_form)
+ geo_form.show()
- try:
- self.ui.plugins_engraving_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 4 and self.cnc_displayed is False:
+ self.cnc_displayed = True
+ cnc_form = self.ui.cncjob_pref_form
+ try:
+ self.ui.cncjob_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.cncjob_scroll_area.setWidget(cnc_form)
+ cnc_form.show()
- try:
- self.ui.tools_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 5 and self.engrave_displayed is False:
+ self.engrave_displayed = True
+ plugins_engraving_form = self.ui.plugin_eng_pref_form
+ try:
+ self.ui.plugins_engraving_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.plugins_engraving_scroll_area.setWidget(plugins_engraving_form)
+ plugins_engraving_form.show()
- try:
- self.ui.tools2_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 6 and self.plugins_displayed is False:
+ self.plugins_displayed = True
+ plugins_form = self.ui.plugin_pref_form
+ try:
+ self.ui.tools_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.tools_scroll_area.setWidget(plugins_form)
+ plugins_form.show()
- try:
- self.ui.fa_scroll_area.takeWidget()
- except Exception:
- self.ui.app.log.debug("Nothing to remove")
+ if idx == 7 and self.plugins2_displayed is False:
+ self.plugins2_displayed = True
+ plugins2_form = self.ui.plugin2_pref_form
+ try:
+ self.ui.tools2_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.tools2_scroll_area.setWidget(plugins2_form)
+ plugins2_form.show()
+
+ if idx == 8 and self.util_displayed is False:
+ self.util_displayed = True
+ fa_form = self.ui.util_pref_form
+ try:
+ self.ui.fa_scroll_area.takeWidget()
+ except Exception:
+ self.ui.app.log.debug("Nothing to remove")
+ self.ui.fa_scroll_area.setWidget(fa_form)
+ fa_form.show()
def __init_color_pickers(self):
# Init Gerber Plot Colors
@@ -1064,20 +1128,26 @@ class PreferencesUIManager(QtCore.QObject):
# make sure we update the self.current_defaults dict used to undo changes to self.defaults
self.defaults.current_defaults.update(self.defaults)
- # deal with theme change
- theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
- if theme_settings.contains("theme"):
- theme = theme_settings.value('theme', type=str)
+ # deal with appearance change
+ appearance_settings = QtCore.QSettings("Open Source", "FlatCAM")
+ if appearance_settings.contains("appearance"):
+ appearance = appearance_settings.value('appearance', type=str)
else:
- theme = 'white'
+ appearance = None
+
+ if appearance_settings.contains("dark_canvas"):
+ dark_canvas = appearance_settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = None
should_restart = False
- theme_new_val = self.ui.general_pref_form.general_gui_group.theme_radio.get_value()
+ appearance_new_val = self.ui.general_pref_form.general_gui_group.appearance_radio.get_value()
+ dark_canvas_new_val = self.ui.general_pref_form.general_gui_group.dark_canvas_cb.get_value()
ge = self.defaults["global_graphic_engine"]
ge_val = self.ui.general_pref_form.general_app_group.ge_radio.get_value()
- if theme_new_val != theme or ge != ge_val:
+ if appearance_new_val != appearance or ge != ge_val or dark_canvas_new_val != dark_canvas:
msgbox = FCMessageBox(parent=self.ui)
title = _("Application will restart")
txt = _("Are you sure you want to continue?")
@@ -1094,17 +1164,24 @@ class PreferencesUIManager(QtCore.QObject):
msgbox.exec()
response = msgbox.clickedButton()
- if theme_new_val != theme:
+ if appearance_new_val != appearance:
if response == bt_yes:
- theme_settings.setValue('theme', theme_new_val)
-
- # This will write the setting to the platform specific storage.
- del theme_settings
-
+ appearance_settings.setValue('appearance', appearance_new_val)
should_restart = True
else:
- self.ui.general_pref_form.general_gui_group.theme_radio.set_value(theme)
- else:
+ self.ui.general_pref_form.general_gui_group.appearance_radio.set_value(appearance)
+
+ if dark_canvas_new_val != dark_canvas:
+ if response == bt_yes:
+ appearance_settings.setValue('dark_canvas', dark_canvas_new_val)
+ should_restart = True
+ else:
+ self.ui.general_pref_form.general_gui_group.dark_canvas_cb.set_value(dark_canvas)
+
+ # This will write the setting to the platform specific storage.
+ del appearance_settings
+
+ if ge != ge_val:
if response == bt_yes:
self.defaults["global_graphic_engine"] = ge_val
should_restart = True
diff --git a/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py b/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py
index 3c0f5fdb..c62b2296 100644
--- a/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py
+++ b/appGUI/preferences/excellon/ExcellonOptPrefGroupUI.py
@@ -38,7 +38,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
param_frame.setLayout(param_grid)
# ### Milling Holes ## ##
- self.mill_hole_label = FCLabel('%s' % _('Mill Holes'))
+ self.mill_hole_label = FCLabel('%s' % _('Mill Holes'), bold=True)
self.mill_hole_label.setToolTip(
_("Create Geometry for milling holes.")
)
diff --git a/appGUI/preferences/general/GeneralAPPSetGroupUI.py b/appGUI/preferences/general/GeneralAPPSetGroupUI.py
index 44fd77c4..b7d92edf 100644
--- a/appGUI/preferences/general/GeneralAPPSetGroupUI.py
+++ b/appGUI/preferences/general/GeneralAPPSetGroupUI.py
@@ -26,9 +26,9 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
self.resource_loc = 'assets/resources'
else:
self.resource_loc = 'assets/resources'
@@ -496,9 +496,14 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
- if theme == 'white':
+ if theme_settings.contains("dark_canvas"):
+ dark_canvas = theme_settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
self.app.cursor_color_3D = 'black'
else:
self.app.cursor_color_3D = 'gray'
@@ -509,4 +514,4 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
def on_axis_color_entry(self):
self.app.options['global_axis_color'] = self.axis_color_entry.get_value()
- self.app.plotcanvas.apply_axis_color()
\ No newline at end of file
+ self.app.plotcanvas.apply_axis_color()
diff --git a/appGUI/preferences/general/GeneralAppPrefGroupUI.py b/appGUI/preferences/general/GeneralAppPrefGroupUI.py
index ef32a068..a5346b49 100644
--- a/appGUI/preferences/general/GeneralAppPrefGroupUI.py
+++ b/appGUI/preferences/general/GeneralAppPrefGroupUI.py
@@ -89,7 +89,7 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
grid1_frame.setLayout(grid1)
# Graphic Engine for FlatCAM
- self.ge_label = FCLabel('%s:' % _('Graphic Engine'))
+ self.ge_label = FCLabel('%s:' % _('Graphic Engine'), bold=True)
self.ge_label.setToolTip(_("Choose what graphic engine to use in FlatCAM.\n"
"Legacy(2D) -> reduced functionality, slow performance but enhanced compatibility.\n"
"OpenGL(3D) -> full functionality, high performance\n"
diff --git a/appGUI/preferences/general/GeneralAppSettingsGroupUI.py b/appGUI/preferences/general/GeneralAppSettingsGroupUI.py
index 0bea646b..60bbc5fa 100644
--- a/appGUI/preferences/general/GeneralAppSettingsGroupUI.py
+++ b/appGUI/preferences/general/GeneralAppSettingsGroupUI.py
@@ -292,9 +292,14 @@ class GeneralAppSettingsGroupUI(OptionsGroupUI2):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
- if theme == 'white':
+ if theme_settings.contains("dark_canvas"):
+ dark_canvas = theme_settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
+
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
self.app.cursor_color_3D = 'black'
else:
self.app.cursor_color_3D = 'gray'
diff --git a/appGUI/preferences/general/GeneralGUIPrefGroupUI.py b/appGUI/preferences/general/GeneralGUIPrefGroupUI.py
index 9d1ba15a..e846d1e0 100644
--- a/appGUI/preferences/general/GeneralGUIPrefGroupUI.py
+++ b/appGUI/preferences/general/GeneralGUIPrefGroupUI.py
@@ -35,28 +35,36 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
par_frame.setLayout(grid0)
# Theme selection
- self.theme_label = FCLabel('%s:' % _('Theme'))
- self.theme_label.setToolTip(
+ self.appearance_label = FCLabel('%s' % _('Theme'), bold=True)
+ self.appearance_label.setToolTip(
_("Select a theme for the application.\n"
"It will theme the plot area.")
)
- self.theme_radio = RadioSet([
- {"label": _("Light"), "value": "white"},
- {"label": _("Dark"), "value": "black"}
+ self.appearance_radio = RadioSet([
+ {"label": _("Default"), "value": "default"},
+ {"label": _("Auto"), "value": "auto"},
+ {"label": _("Light"), "value": "light"},
+ {"label": _("Dark"), "value": "dark"}
], compact=True)
-
- grid0.addWidget(self.theme_label, 0, 0)
- grid0.addWidget(self.theme_radio, 0, 1)
-
- # Enable Gray Icons
- self.gray_icons_cb = FCCheckBox('%s' % _('Use Gray Icons'))
- self.gray_icons_cb.setToolTip(
- _("Check this box to use a set of icons with\n"
- "a lighter (gray) color. To be used when a\n"
- "full dark theme is applied.")
+ self.appearance_radio.setToolTip(
+ _("The theme can be:\n"
+ "Default: Default theme\n"
+ "Auto: Matches mode from OS\n"
+ "Light: Light mode\n"
+ "Dark: Dark mode")
)
- grid0.addWidget(self.gray_icons_cb, 2, 0, 1, 3)
+
+ # Dark Canvas
+ self.dark_canvas_cb = FCCheckBox('%s' % _('Dark Canvas'))
+ self.dark_canvas_cb.setToolTip(
+ _("Check this box to force the use of dark canvas\n"
+ "even if a dark theme is not selected.")
+ )
+
+ grid0.addWidget(self.appearance_label, 0, 0, 1, 2)
+ grid0.addWidget(self.appearance_radio, 1, 0, 1, 3)
+ grid0.addWidget(self.dark_canvas_cb, 2, 0, 1, 3)
# self.theme_button = FCButton(_("Apply Theme"))
# self.theme_button.setToolTip(
@@ -156,7 +164,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
color_frame.setLayout(grid1)
# Plot Selection (left - right) Color
- self.sel_lr_label = FCLabel('%s' % _('Left-Right Selection Color'))
+ self.sel_lr_label = FCLabel('%s' % _('Left-Right Selection Color'), bold=True)
grid1.addWidget(self.sel_lr_label, 0, 0, 1, 2)
self.sl_color_label = FCLabel('%s:' % _('Outline'))
@@ -196,7 +204,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
grid1.addWidget(separator_line, 8, 0, 1, 2)
# Plot Selection (left - right) Color
- self.sel_rl_label = FCLabel('%s' % _('Right-Left Selection Color'))
+ self.sel_rl_label = FCLabel('%s' % _('Right-Left Selection Color'), bold=True)
grid1.addWidget(self.sel_rl_label, 10, 0, 1, 2)
# Plot Selection (right - left) Line Color
@@ -241,7 +249,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
# ----------------------- Editor Color -----------------------------
# ------------------------------------------------------------------
- self.editor_color_label = FCLabel('%s' % _('Editor Color'))
+ self.editor_color_label = FCLabel('%s' % _('Editor Color'), bold=True)
grid1.addWidget(self.editor_color_label, 20, 0, 1, 2)
# Editor Draw Color
@@ -273,7 +281,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
# ----------------------- Project Settings -----------------------------
# ------------------------------------------------------------------
# Light Theme
- self.proj_settings_l_label = FCLabel('%s - %s' % (_('Project Items Color'), _("Light")))
+ self.proj_settings_l_label = FCLabel('%s' % _("Light"), bold=True)
grid1.addWidget(self.proj_settings_l_label, 28, 0, 1, 2)
# Project Tab items color
@@ -299,8 +307,13 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.proj_color_dis_l_label, 32, 0)
grid1.addWidget(self.proj_color_dis_light_entry, 32, 1)
+ separator_line = QtWidgets.QFrame()
+ separator_line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
+ separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ grid1.addWidget(separator_line, 33, 0, 1, 2)
+
# Dark Theme
- self.proj_settings_d_label = FCLabel('%s - %s' % (_('Project Items Color'), _("Dark")))
+ self.proj_settings_d_label = FCLabel('%s' % _("Dark"), bold=True)
grid1.addWidget(self.proj_settings_d_label, 34, 0, 1, 2)
# Project Tab items color
diff --git a/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py b/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py
index 4c85b0ea..c274284d 100644
--- a/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py
+++ b/appGUI/preferences/tools/Tools2CThievingPrefGroupUI.py
@@ -142,7 +142,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI):
# #############################################################################################################
# DOTS Grid Parameters Frame
# #############################################################################################################
- self.dots_label = FCLabel('%s:' % _("Dots Grid Parameters"))
+ self.dots_label = FCLabel('%s' % _("Dots Grid Parameters"), bold=True)
self.layout.addWidget(self.dots_label)
dots_frame = FCFrame()
@@ -181,7 +181,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI):
# #############################################################################################################
# Squares Grid Parameters Frame
# #############################################################################################################
- self.squares_label = FCLabel('%s:' % _("Squares Grid Parameters"))
+ self.squares_label = FCLabel('%s' % _("Squares Grid Parameters"), bold=True)
self.layout.addWidget(self.squares_label)
square_frame = FCFrame()
@@ -220,7 +220,7 @@ class Tools2CThievingPrefGroupUI(OptionsGroupUI):
# #############################################################################################################
# Lines Grid Parameters Frame
# #############################################################################################################
- self.lines_label = FCLabel('%s:' % _("Lines Grid Parameters"))
+ self.lines_label = FCLabel('%s' % _("Lines Grid Parameters"), bold=True)
self.layout.addWidget(self.lines_label)
line_frame = FCFrame()
diff --git a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py
index 187a8158..ef75ae59 100644
--- a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py
@@ -44,11 +44,6 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
_("A value greater than 1 will compact the film\n"
"while a value less than 1 will jolt it.")
)
- self.film_scale_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_scale_cb, 2, 0, 1, 2)
# SCALE FRAME
@@ -109,11 +104,6 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
_("Positive values will skew to the right\n"
"while negative values will skew to the left.")
)
- self.film_skew_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_skew_cb, 8, 0, 1, 2)
# SKEW FRAME
@@ -171,11 +161,6 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
self.film_mirror_cb.setToolTip(
_("Mirror the film geometry on the selected axis or on both.")
)
- self.film_mirror_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_mirror_cb, 12, 0, 1, 2)
self.film_mirror_axis = RadioSet([{'label': _('X'), 'value': 'x'},
diff --git a/appGUI/preferences/tools/ToolsISOPrefGroupUI.py b/appGUI/preferences/tools/ToolsISOPrefGroupUI.py
index c0fdd5a4..0a041e38 100644
--- a/appGUI/preferences/tools/ToolsISOPrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsISOPrefGroupUI.py
@@ -39,7 +39,7 @@ class ToolsISOPrefGroupUI(OptionsGroupUI):
par_frame.setLayout(par_grid)
# Tool Dias
- isotdlabel = FCLabel('%s:' % _('Tools Dia'))
+ isotdlabel = FCLabel('%s:' % _('Tools Dia'), color='green', bold=True)
isotdlabel.setToolTip(
_("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
diff --git a/appGUI/preferences/tools/ToolsMillPrefGroupUI.py b/appGUI/preferences/tools/ToolsMillPrefGroupUI.py
index 65cd74ea..00793fb0 100644
--- a/appGUI/preferences/tools/ToolsMillPrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsMillPrefGroupUI.py
@@ -38,7 +38,7 @@ class ToolsMillPrefGroupUI(OptionsGroupUI):
param_frame.setLayout(param_grid)
# Tooldia
- tdlabel = FCLabel('%s:' % _('Tools Dia'))
+ tdlabel = FCLabel('%s:' % _('Tools Dia'), color='green', bold=True)
tdlabel.setToolTip(
_("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
diff --git a/appGUI/preferences/tools/ToolsNCCPrefGroupUI.py b/appGUI/preferences/tools/ToolsNCCPrefGroupUI.py
index b2dddf3f..c547ebb5 100644
--- a/appGUI/preferences/tools/ToolsNCCPrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsNCCPrefGroupUI.py
@@ -40,7 +40,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
par_frame.setLayout(par_grid)
# Tools Diameters
- ncctdlabel = FCLabel('%s:' % _('Tools Dia'))
+ ncctdlabel = FCLabel('%s:' % _('Tools Dia'), color='green', bold=True)
ncctdlabel.setToolTip(
_("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
diff --git a/appGUI/preferences/tools/ToolsPaintPrefGroupUI.py b/appGUI/preferences/tools/ToolsPaintPrefGroupUI.py
index 85cbfc0a..789de600 100644
--- a/appGUI/preferences/tools/ToolsPaintPrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsPaintPrefGroupUI.py
@@ -42,7 +42,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
par_frame.setLayout(param_grid)
# Tool dia
- ptdlabel = FCLabel('%s:' % _('Tools Dia'))
+ ptdlabel = FCLabel('%s:' % _('Tools Dia'), color='green', bold=True)
ptdlabel.setToolTip(
_("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
diff --git a/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py b/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py
index 0349b352..218c71d9 100644
--- a/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py
+++ b/appGUI/preferences/tools/ToolsSolderpastePrefGroupUI.py
@@ -39,7 +39,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
param_frame.setLayout(param_grid)
# Nozzle Tool Diameters
- nozzletdlabel = FCLabel('%s:' % _('Tools Dia'))
+ nozzletdlabel = FCLabel('%s:' % _('Tools Dia'), color='green', bold=True)
nozzletdlabel.setToolTip(
_("Diameters of the tools, separated by comma.\n"
"The value of the diameter has to use the dot decimals separator.\n"
@@ -51,7 +51,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
param_grid.addWidget(self.nozzle_tool_dia_entry, 0, 1)
# New Nozzle Tool Dia
- self.addtool_entry_lbl = FCLabel('%s:' % _('New Nozzle Dia'))
+ self.addtool_entry_lbl = FCLabel('%s:' % _('New Nozzle Dia'), bold=True)
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool to add in the Tool Table")
)
@@ -60,8 +60,23 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.addtool_entry.set_range(0.0000001, 10000.0000)
self.addtool_entry.setSingleStep(0.1)
- param_grid.addWidget(self.addtool_entry_lbl, 1, 0)
- param_grid.addWidget(self.addtool_entry, 1, 1)
+ param_grid.addWidget(self.addtool_entry_lbl, 2, 0)
+ param_grid.addWidget(self.addtool_entry, 2, 1)
+
+ # Margin
+ self.margin_label = FCLabel('%s:' % _("Margin"))
+ self.margin_label.setToolTip('%s %s' % (
+ _("Offset from the boundary."),
+ _("Fraction of tool diameter.")
+ )
+ )
+ self.margin_entry = FCDoubleSpinner(suffix='%')
+ self.margin_entry.set_range(-100.0000, 100.0000)
+ self.margin_entry.set_precision(self.decimals)
+ self.margin_entry.setSingleStep(0.1)
+
+ param_grid.addWidget(self.margin_label, 4, 0)
+ param_grid.addWidget(self.margin_entry, 4, 1)
# Z dispense start
self.z_start_entry = FCDoubleSpinner()
@@ -73,8 +88,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.z_start_label.setToolTip(
_("The height (Z) when solder paste dispensing starts.")
)
- param_grid.addWidget(self.z_start_label, 2, 0)
- param_grid.addWidget(self.z_start_entry, 2, 1)
+ param_grid.addWidget(self.z_start_label, 6, 0)
+ param_grid.addWidget(self.z_start_entry, 6, 1)
# Z dispense
self.z_dispense_entry = FCDoubleSpinner()
@@ -86,8 +101,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.z_dispense_label.setToolTip(
_("The height (Z) when doing solder paste dispensing.")
)
- param_grid.addWidget(self.z_dispense_label, 3, 0)
- param_grid.addWidget(self.z_dispense_entry, 3, 1)
+ param_grid.addWidget(self.z_dispense_label, 8, 0)
+ param_grid.addWidget(self.z_dispense_entry, 8, 1)
# Z dispense stop
self.z_stop_entry = FCDoubleSpinner()
@@ -99,8 +114,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.z_stop_label.setToolTip(
_("The height (Z) when solder paste dispensing stops.")
)
- param_grid.addWidget(self.z_stop_label, 4, 0)
- param_grid.addWidget(self.z_stop_entry, 4, 1)
+ param_grid.addWidget(self.z_stop_label, 10, 0)
+ param_grid.addWidget(self.z_stop_entry, 101, 1)
# Z travel
self.z_travel_entry = FCDoubleSpinner()
@@ -113,8 +128,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("The height (Z) for travel between pads\n"
"(without dispensing solder paste).")
)
- param_grid.addWidget(self.z_travel_label, 5, 0)
- param_grid.addWidget(self.z_travel_entry, 5, 1)
+ param_grid.addWidget(self.z_travel_label, 12, 0)
+ param_grid.addWidget(self.z_travel_entry, 12, 1)
# Z toolchange location
self.z_toolchange_entry = FCDoubleSpinner()
@@ -126,8 +141,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.z_toolchange_label.setToolTip(
_("The height (Z) for tool (nozzle) change.")
)
- param_grid.addWidget(self.z_toolchange_label, 6, 0)
- param_grid.addWidget(self.z_toolchange_entry, 6, 1)
+ param_grid.addWidget(self.z_toolchange_label, 14, 0)
+ param_grid.addWidget(self.z_toolchange_entry, 14, 1)
# X,Y Toolchange location
self.xy_toolchange_entry = NumericalEvalTupleEntry(border_color='#0069A9')
@@ -136,8 +151,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("The X,Y location for tool (nozzle) change.\n"
"The format is (x, y) where x and y are real numbers.")
)
- param_grid.addWidget(self.xy_toolchange_label, 7, 0)
- param_grid.addWidget(self.xy_toolchange_entry, 7, 1)
+ param_grid.addWidget(self.xy_toolchange_label, 16, 0)
+ param_grid.addWidget(self.xy_toolchange_entry, 16, 1)
# Feedrate X-Y
self.frxy_entry = FCDoubleSpinner()
@@ -149,8 +164,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.frxy_label.setToolTip(
_("Feedrate (speed) while moving on the X-Y plane.")
)
- param_grid.addWidget(self.frxy_label, 8, 0)
- param_grid.addWidget(self.frxy_entry, 8, 1)
+ param_grid.addWidget(self.frxy_label, 18, 0)
+ param_grid.addWidget(self.frxy_entry, 18, 1)
# Feedrate Z
self.frz_entry = FCDoubleSpinner()
@@ -163,8 +178,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("Feedrate (speed) while moving vertically\n"
"(on Z plane).")
)
- param_grid.addWidget(self.frz_label, 9, 0)
- param_grid.addWidget(self.frz_entry, 9, 1)
+ param_grid.addWidget(self.frz_label, 20, 0)
+ param_grid.addWidget(self.frz_entry, 20, 1)
# Feedrate Z Dispense
self.frz_dispense_entry = FCDoubleSpinner()
@@ -177,8 +192,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("Feedrate (speed) while moving up vertically\n"
"to Dispense position (on Z plane).")
)
- param_grid.addWidget(self.frz_dispense_label, 10, 0)
- param_grid.addWidget(self.frz_dispense_entry, 10, 1)
+ param_grid.addWidget(self.frz_dispense_label, 22, 0)
+ param_grid.addWidget(self.frz_dispense_entry, 22, 1)
# Spindle Speed Forward
self.speedfwd_entry = FCSpinner()
@@ -190,25 +205,25 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("The dispenser speed while pushing solder paste\n"
"through the dispenser nozzle.")
)
- param_grid.addWidget(self.speedfwd_label, 11, 0)
- param_grid.addWidget(self.speedfwd_entry, 11, 1)
+ param_grid.addWidget(self.speedfwd_label, 24, 0)
+ param_grid.addWidget(self.speedfwd_entry, 24, 1)
# Dwell Forward
self.dwellfwd_entry = FCDoubleSpinner()
self.dwellfwd_entry.set_precision(self.decimals)
- self.dwellfwd_entry.set_range(0.0000001, 10000.0000)
+ self.dwellfwd_entry.set_range(0.0000, 10000.0000)
self.dwellfwd_entry.setSingleStep(0.1)
self.dwellfwd_label = FCLabel('%s:' % _("Dwell FWD"))
self.dwellfwd_label.setToolTip(
_("Pause after solder dispensing.")
)
- param_grid.addWidget(self.dwellfwd_label, 12, 0)
- param_grid.addWidget(self.dwellfwd_entry, 12, 1)
+ param_grid.addWidget(self.dwellfwd_label, 26, 0)
+ param_grid.addWidget(self.dwellfwd_entry, 26, 1)
# Spindle Speed Reverse
self.speedrev_entry = FCSpinner()
- self.speedrev_entry.set_range(0, 999999)
+ self.speedrev_entry.set_range(0, 1000000)
self.speedrev_entry.set_step(1000)
self.speedrev_label = FCLabel('%s:' % _("Spindle Speed REV"))
@@ -216,13 +231,13 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("The dispenser speed while retracting solder paste\n"
"through the dispenser nozzle.")
)
- param_grid.addWidget(self.speedrev_label, 13, 0)
- param_grid.addWidget(self.speedrev_entry, 13, 1)
+ param_grid.addWidget(self.speedrev_label, 28, 0)
+ param_grid.addWidget(self.speedrev_entry, 28, 1)
# Dwell Reverse
self.dwellrev_entry = FCDoubleSpinner()
self.dwellrev_entry.set_precision(self.decimals)
- self.dwellrev_entry.set_range(0.0000001, 10000.0000)
+ self.dwellrev_entry.set_range(0.0000, 10000.0000)
self.dwellrev_entry.setSingleStep(0.1)
self.dwellrev_label = FCLabel('%s:' % _("Dwell REV"))
@@ -230,8 +245,8 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
_("Pause after solder paste dispenser retracted,\n"
"to allow pressure equilibrium.")
)
- param_grid.addWidget(self.dwellrev_label, 14, 0)
- param_grid.addWidget(self.dwellrev_entry, 14, 1)
+ param_grid.addWidget(self.dwellrev_label, 30, 0)
+ param_grid.addWidget(self.dwellrev_entry, 30, 1)
# Preprocessors
pp_label = FCLabel('%s:' % _('Preprocessor'))
@@ -246,7 +261,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
for it in range(self.pp_combo.count()):
self.pp_combo.setItemData(it, self.pp_combo.itemText(it), QtCore.Qt.ItemDataRole.ToolTipRole)
- param_grid.addWidget(pp_label, 15, 0)
- param_grid.addWidget(self.pp_combo, 15, 1)
+ param_grid.addWidget(pp_label, 32, 0)
+ param_grid.addWidget(self.pp_combo, 32, 1)
self.layout.addStretch()
diff --git a/appGUI/preferences/utilities/AutoCompletePrefGroupUI.py b/appGUI/preferences/utilities/AutoCompletePrefGroupUI.py
index ee8f2e88..93139239 100644
--- a/appGUI/preferences/utilities/AutoCompletePrefGroupUI.py
+++ b/appGUI/preferences/utilities/AutoCompletePrefGroupUI.py
@@ -33,7 +33,7 @@ class AutoCompletePrefGroupUI(OptionsGroupUI):
hlay0.addWidget(self.del_all_btn)
# ## Gerber associations
- self.grb_list_label = FCLabel("%s:" % _("Keywords list"))
+ self.grb_list_label = FCLabel('%s:' % _("Keywords list"), bold=True)
self.grb_list_label.setToolTip(
_("List of keywords used by\n"
"the autocompleter in FlatCAM.\n"
diff --git a/appGUI/preferences/utilities/FAExcPrefGroupUI.py b/appGUI/preferences/utilities/FAExcPrefGroupUI.py
index 8e3c1c8e..68a6a5f7 100644
--- a/appGUI/preferences/utilities/FAExcPrefGroupUI.py
+++ b/appGUI/preferences/utilities/FAExcPrefGroupUI.py
@@ -43,7 +43,7 @@ class FAExcPrefGroupUI(OptionsGroupUI):
self.vertical_lay.addLayout(hlay0)
# # ## Excellon associations
- list_label = FCLabel("%s:" % _("Extensions list"))
+ list_label = FCLabel('%s:' % _("Extensions list"), bold=True)
list_label.setToolTip(
_("List of file extensions to be\n"
"associated with FlatCAM.")
diff --git a/appGUI/preferences/utilities/FAGcoPrefGroupUI.py b/appGUI/preferences/utilities/FAGcoPrefGroupUI.py
index 84697c77..9df84f31 100644
--- a/appGUI/preferences/utilities/FAGcoPrefGroupUI.py
+++ b/appGUI/preferences/utilities/FAGcoPrefGroupUI.py
@@ -34,7 +34,7 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
hlay0.addWidget(self.del_all_btn)
# ## G-Code associations
- self.gco_list_label = FCLabel("%s:" % _("Extensions list"))
+ self.gco_list_label = FCLabel('%s:' % _("Extensions list"), bold=True)
self.gco_list_label.setToolTip(
_("List of file extensions to be\n"
"associated with FlatCAM.")
diff --git a/appGUI/preferences/utilities/FAGrbPrefGroupUI.py b/appGUI/preferences/utilities/FAGrbPrefGroupUI.py
index fe1dbf53..dcec8eca 100644
--- a/appGUI/preferences/utilities/FAGrbPrefGroupUI.py
+++ b/appGUI/preferences/utilities/FAGrbPrefGroupUI.py
@@ -33,7 +33,7 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
hlay0.addWidget(self.del_all_btn)
# ## Gerber associations
- self.grb_list_label = FCLabel("%s:" % _("Extensions list"))
+ self.grb_list_label = FCLabel('%s:' % _("Extensions list"), bold=True)
self.grb_list_label.setToolTip(
_("List of file extensions to be\n"
"associated with FlatCAM.")
diff --git a/appGUI/themes/__init__.py b/appGUI/themes/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/appGUI/style_sheet.py b/appGUI/themes/dark_style_sheet.py
similarity index 100%
rename from appGUI/style_sheet.py
rename to appGUI/themes/dark_style_sheet.py
diff --git a/appGUI/themes/light_style_sheet.py b/appGUI/themes/light_style_sheet.py
new file mode 100644
index 00000000..b0e87a96
--- /dev/null
+++ b/appGUI/themes/light_style_sheet.py
@@ -0,0 +1,1079 @@
+L_STYLE_SHEET = """
+* {
+ padding: 0px;
+ margin: 0px;
+ border: none;
+ border-style: none;
+ border-image: unset;
+ outline: none;
+}
+QToolBar * {
+ margin: 0px;
+ padding: 0px;
+}
+QWidget {
+ background: #f8f9fa;
+ color: #4d5157;
+ selection-background-color: #0081db;
+ selection-color: #f8f9fa;
+}
+QWidget:disabled {
+ color: #babdc2;
+ selection-background-color: #dadce0;
+ selection-color: #babdc2;
+}
+QWidget {
+ backward-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ forward-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ leftarrow-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+ rightarrow-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+ dialog-ok-icon: url(${path}/themes/light/svg/check__icon-foreground.svg);
+ dialog-cancel-icon: url(${path}/themes/light/svg/close__icon-foreground.svg);
+ dialog-yes-icon: url(${path}/themes/light/svg/check_circle__icon-foreground.svg);
+ dialog-no-icon: url(${path}/themes/light/svg/cancel__icon-foreground.svg);
+ dialog-apply-icon: url(${path}/themes/light/svg/check__icon-foreground.svg);
+ dialog-reset-icon: url(${path}/themes/light/svg/restart_alt__icon-foreground.svg);
+ dialog-save-icon: url(${path}/themes/light/svg/save__icon-foreground.svg);
+ dialog-discard-icon: url(${path}/themes/light/svg/delete__icon-foreground.svg);
+ dialog-close-icon: url(${path}/themes/light/svg/close__icon-foreground.svg);
+ dialog-open-icon: url(${path}/themes/light/svg/folder_open__icon-foreground.svg);
+ dialog-help-icon: url(${path}/themes/light/svg/help__icon-foreground.svg);
+ filedialog-parent-directory-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground.svg);
+ filedialog-new-directory-icon: url(${path}/themes/light/svg/create_new_folder__icon-foreground.svg);
+ titlebar-close-icon: url(${path}/themes/light/svg/close__icon-foreground.svg);
+ titlebar-normal-icon: url(${path}/themes/light/svg/flip_to_front__icon-foreground.svg);
+}
+QCommandLinkButton {
+ qproperty-icon: url(${path}/themes/light/svg/east__highlight.svg);
+}
+QMainWindow::separator {
+ width: 2px;
+ height: 4px;
+ background: #dadce0;
+}
+QMainWindow::separator:hover,
+QMainWindow::separator:pressed {
+ background: #0081db;
+}
+QToolTip {
+ background: #ffffff;
+ color: #4d5157;
+ border: 1px solid #dadce0;
+}
+QSizeGrip {
+ width: 0;
+ height: 0;
+ image: none;
+}
+QStatusBar {
+ background: #dfe1e5;
+}
+QStatusBar::item {
+ border: none;
+}
+QStatusBar QWidget {
+ background: transparent;
+ padding: 0px;
+ border-radius: $radius{0px};
+}
+QStatusBar > .QSizeGrip {
+ padding: 0;
+}
+QStatusBar QWidget:hover {
+ background: #d1d4da;
+}
+QStatusBar QWidget:pressed {
+ background: #c3c7ce;
+}
+QStatusBar QWidget:disabled {
+ background: #edeef0;
+}
+QStatusBar QWidget:checked {
+ background: #c3c7ce;
+}
+QCheckBox,
+QRadioButton {
+ border-top: 2px solid transparent;
+ border-bottom: 2px solid transparent;
+}
+QCheckBox:!window,
+QRadioButton:!window {
+ background: transparent;
+}
+QCheckBox:hover,
+QRadioButton:hover {
+ border-bottom: 2px solid #0081db;
+}
+QGroupBox {
+ font-weight: bold;
+ border: 1px solid #dadce0;
+ margin-top: 8px;
+ padding: 2px 1px 1px 1px;
+ border-radius: $radius{4px};
+}
+QGroupBox::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ left: 7px;
+ margin: 0 2px 0 3px;
+}
+QGroupBox:flat {
+ border-color: transparent;
+}
+QMenuBar {
+ background: #f8f9fa;
+ padding: 2px;
+ border-bottom: 1px solid #dadce0;
+}
+QMenuBar::item {
+ background: transparent;
+ padding: 4px;
+}
+QMenuBar::item:selected {
+ padding: 4px;
+ background: #dadce0;
+ border-radius: $radius{4px};
+}
+QMenuBar::item:pressed {
+ padding: 4px;
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+QToolBar {
+ background: #f8f9fa;
+ padding: 0px;
+ font-weight: bold;
+ spacing: 1px;
+ margin: 0px;
+}
+QToolBar::handle:horizontal {
+ width: 10px;
+ image: url(${path}/themes/light/svg/drag_indicator_horizontal__icon-foreground.svg);
+}
+QToolBar::handle:vertical {
+ height: 20px;
+ image: url(${path}/themes/light/svg/drag_indicator_horizontal__icon-foreground__rotate-90.svg);
+}
+QToolBar::separator {
+ background: #dadce0;
+}
+QToolBar::separator:horizontal {
+ width: 2px;
+ margin: 0 6px;
+}
+QToolBar::separator:vertical {
+ height: 2px;
+ margin: 6px 0;
+}
+QToolBar > QToolButton {
+ background: transparent;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QToolBar > QToolButton:hover,
+QToolBar > QToolButton::menu-button:hover {
+ background: #d7d7d7;
+}
+QToolBar > QToolButton:pressed,
+QToolBar > QToolButton::menu-button:pressed {
+ background: #c4c4c4;
+}
+QToolBar > QToolButton:checked {
+ background: #c4c4c4;
+}
+QToolBar > QToolButton#qt_toolbar_ext_button {
+ image: url(${path}/themes/light/svg/double_arrow__icon-foreground.svg);
+ $env_patch{"os": "Windows", "value": "padding: 0; qproperty-icon: unset"};
+}
+QToolBar > QToolButton#qt_toolbar_ext_button:disabled {
+ image: url(${path}/themes/light/svg/double_arrow__icon-foreground-disabled.svg);
+}
+QToolBar > QWidget {
+ background: transparent;
+}
+QMenu {
+ background: #ffffff;
+ padding: 8px 0;
+ border: 1px solid #dadce0;
+}
+QMenu::separator {
+ margin: 4px 0;
+ height: 1px;
+ background: #dadce0;
+}
+QMenu::item {
+ padding: 4px 28px;
+}
+QMenu::item:selected {
+ background: #dadce0;
+}
+QMenu::icon {
+ padding-left: 10px;
+ width: 14px;
+ height: 14px;
+}
+QMenu::right-arrow {
+ margin: 2px;
+ padding-left: 12px;
+ height: 20px;
+ width: 20px;
+ image: url(${path}/themes/light/svg/chevron_right__icon-foreground.svg);
+}
+QMenu::right-arrow:disabled {
+ image: url(${path}/themes/light/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QScrollBar {
+ background: #edeff2;
+ $env_patch{"os": "Darwin", "value": "background: transparent"};
+ border-radius: $radius{4px};
+}
+QScrollBar:horizontal {
+ height: 14px;
+ $env_patch{"os": "Darwin", "value": "height: 7px;"};
+}
+QScrollBar:vertical {
+ width: 14px;
+ $env_patch{"os": "Darwin", "value": "width: 7px;"};
+}
+QScrollBar::handle {
+ background: rgba(155.000, 155.000, 157.000, 0.737);
+ border-radius: $radius{3px};
+}
+QScrollBar::handle:hover {
+ background: rgba(117.000, 117.000, 119.000, 0.827);
+}
+QScrollBar::handle:pressed {
+ background: rgba(96.000, 96.000, 98.000, 0.933);
+}
+QScrollBar::handle:disabled {
+ background-color: #d6dbe2;
+}
+QScrollBar::handle:horizontal {
+ min-width: 8px;
+ margin: 4px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:horizontal:hover {
+ margin: 2px 14px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical {
+ min-height: 8px;
+ margin: 14px 4px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::handle:vertical:hover {
+ margin: 14px 2px;
+ $env_patch{"os": "Darwin", "value": "margin: 0;"};
+}
+QScrollBar::sub-page, QScrollBar::add-page {
+ background: transparent;
+}
+QScrollBar::sub-line,
+QScrollBar::add-line {
+ background: transparent;
+ width: 14px;
+ height: 14px;
+ margin: 2px;
+ subcontrol-origin: margin;
+ $env_patch{"os": "Darwin", "value": "width: 0; height: 0; margin: 0"};
+}
+QScrollBar::sub-line:vertical {
+ subcontrol-position: top;
+}
+QScrollBar::add-line:vertical {
+ subcontrol-position: bottom;
+}
+QScrollBar::sub-line:horizontal {
+ subcontrol-position: left;
+}
+QScrollBar::add-line:horizontal {
+ subcontrol-position: right;
+}
+QScrollBar::up-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle.svg);
+}
+QScrollBar::right-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle__rotate-90.svg);
+}
+QScrollBar::down-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle__rotate-180.svg);
+}
+QScrollBar::left-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle__rotate-270.svg);
+}
+QScrollBar::up-arrow:hover {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle-pressed.svg);
+}
+QScrollBar::right-arrow:hover {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-90.svg);
+}
+QScrollBar::down-arrow:hover {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-180.svg);
+}
+QScrollBar::left-arrow:hover {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-handle-pressed__rotate-270.svg);
+}
+QScrollBar::up-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-disabled.svg);
+}
+QScrollBar::right-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-disabled__rotate-90.svg);
+}
+QScrollBar::down-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-disabled__rotate-180.svg);
+}
+QScrollBar::left-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__scrollbar-disabled__rotate-270.svg);
+}
+QProgressBar {
+ border: 1px solid #dadce0;
+ text-align: center;
+ color: #4d5157;
+ border-radius: $radius{4px};
+}
+QProgressBar::chunk {
+ background: #0081db;
+ border-radius: $radius{3px};
+}
+QProgressBar::chunk:disabled {
+ background: #dadce0;
+}
+QPushButton {
+ color: #0081db;
+ border: 1px solid #dadce0;
+ padding: 4px 8px;
+ border-radius: $radius{4px};
+}
+QPushButton:!window {
+ background: transparent;
+}
+QPushButton:flat,
+QPushButton:default {
+ border: none;
+ padding: 5px 9px;
+}
+QPushButton:default {
+ color: #f8f9fa;
+ background: #0081db;
+}
+QPushButton:hover,
+QPushButton:flat:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QPushButton:pressed,
+QPushButton:flat:pressed,
+QPushButton:checked:pressed,
+QPushButton:flat:checked:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QPushButton:checked,
+QPushButton:flat:checked {
+ background: rgba(181.000, 202.000, 244.000, 0.733);
+}
+QPushButton:default:hover {
+ background: #3781ea;
+}
+QPushButton:default:pressed {
+ background: #6ca1f0;
+}
+QPushButton:default:disabled {
+ background: #dadce0;
+}
+QDialogButtonBox QPushButton {
+ min-width: 65px;
+}
+QToolButton {
+ background: transparent;
+ padding: 5px;
+ spacing: 2px;
+ border-radius: $radius{2px};
+}
+QToolButton:hover,
+QToolButton::menu-button:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QToolButton:pressed,
+QToolButton:checked:pressed,
+QToolButton::menu-button:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QToolButton:selected,
+QToolButton:checked {
+ background: rgba(181.000, 202.000, 244.000, 0.733);
+}
+QToolButton::checked:disabled {
+ background: #dadce0;
+}
+QToolButton::menu-indicator {
+ height: 18px;
+ width: 18px;
+ top: 6px;
+ left: 3px;
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-indicator:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton::menu-arrow {
+ image: unset;
+}
+QToolButton::menu-button {
+ subcontrol-origin: margin;
+ border: none;
+ width: 17px;
+ border-top-right-radius: $radius{4px};
+ border-bottom-right-radius: $radius{4px};
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QToolButton::menu-button:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QToolButton[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "popupMode=MenuButtonPopup"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "popupMode=\\\"1\\\""}
+$env_patch{"version": ">=6.0.0", "value": "popupMode=MenuButtonPopup"}
+] {
+ padding-right: 1px;
+ margin-right: 18px;
+ border-top-right-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QComboBox {
+ border: 1px solid #dadce0;
+ min-height: 1.5em;
+ padding: 0 4px;
+ background: rgba(255.000, 255.000, 255.000, 0.000);
+ border-radius: $radius{4px};
+}
+QComboBox:focus,
+QComboBox:open {
+ border: 1px solid #0081db;
+}
+QComboBox::drop-down {
+ border: none;
+ padding-right: 4px;
+}
+QComboBox::down-arrow {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QComboBox::down-arrow:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QComboBox::item:selected {
+ border: none;
+ background: #4ca6e5;
+ color: #4d5157;
+}
+QComboBox QAbstractItemView {
+ background: #ffffff;
+ margin: 0;
+ border: 1px solid #dadce0;
+ selection-background-color: #4ca6e5;
+ selection-color: #4d5157;
+ padding: 2px;
+}
+QComboBox QAbstractItemView[
+$env_patch{"version": "<6.0.0", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: #dadce0;
+}
+QSlider {
+ padding: 2px 0;
+}
+QSlider::groove {
+ border-radius: $radius{2px};
+}
+QSlider::groove:horizontal {
+ height: 4px;
+}
+QSlider::groove:vertical {
+ width: 4px;
+}
+QSlider::sub-page, QSlider::handle {
+ background: #0081db;
+}
+QSlider::sub-page:disabled,
+QSlider::add-page:disabled,
+QSlider::handle:disabled {
+ background: #dadce0;
+}
+QSlider::add-page {
+ background: #abc6f6;
+}
+QSlider::handle:hover {
+ background: #3781ea;
+}
+QSlider::handle:pressed {
+ background: #6ca1f0;
+}
+QSlider::handle:horizontal {
+ width: 16px;
+ height: 8px;
+ margin: -6px 0;
+ border-radius: 8px;
+}
+QSlider::handle:vertical {
+ width: 8px;
+ height: 16px;
+ margin: 0 -6px;
+ border-radius: 8px;
+}
+QTabWidget::pane {
+ border: 1px solid #dadce0;
+ border-radius: $radius{4px};
+}
+QTabBar {
+ qproperty-drawBase: 0;
+}
+QTabBar::close-button:selected {
+ image: url(${path}/themes/light/svg/close__icon-foreground.svg);
+}
+QTabBar::close-button:!selected {
+ image: url(${path}/themes/light/svg/close__tabbar-button-inselected.svg)
+}
+QTabBar::close-button:disabled {
+ image: url(${path}/themes/light/svg/close__icon-foreground-disabled.svg);
+}
+QTabBar::close-button:hover {
+ background: #93b2ef;
+ border-radius: $radius{4px};
+}
+QTabBar::close-button:hover:!selected {
+ background: #aec5f4;
+}
+QTabBar::tab {
+ padding: 3px;
+}
+QTabBar::tab:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QTabBar::tab:selected {
+ color: #0081db;
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QTabBar::tab:selected:disabled {
+ background: #dadce0;
+ color: #babdc2;
+}
+QTabBar::tab:top {
+ border-bottom: 2px solid #dadce0;
+ margin-left: 4px;
+ border-top-left-radius: $radius{2px};
+ border-top-right-radius: $radius{2px};
+}
+QTabBar::tab:top:selected {
+ border-bottom: 2px solid #0081db;
+}
+QTabBar::tab:top:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:top:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:bottom {
+ border-top: 2px solid #dadce0;
+ margin-left: 4px;
+ border-bottom-left-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:bottom:selected {
+ border-top: 2px solid #0081db;
+}
+QTabBar::tab:bottom:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:bottom:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:left {
+ border-right: 2px solid #dadce0;
+ margin-top: 4px;
+ border-top-left-radius: $radius{2px};
+ border-bottom-left-radius: $radius{2px};
+}
+QTabBar::tab:left:selected {
+ border-right: 2px solid #0081db;
+}
+QTabBar::tab:left:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:left:selected:disabled {
+ border-color: #dadce0;
+}
+QTabBar::tab:right {
+ border-left: 2px solid #dadce0;
+ margin-top: 4px;
+ border-top-right-radius: $radius{2px};
+ border-bottom-right-radius: $radius{2px};
+}
+QTabBar::tab:right:selected {
+ border-left: 2px solid #0081db;
+}
+QTabBar::tab:right:hover {
+ border-color: #0081db;
+}
+QTabBar::tab:right:selected:disabled {
+ border-color: #dadce0;
+}
+QDockWidget {
+ border: 1px solid #dadce0;
+ border-radius: $radius{4px};
+}
+QDockWidget::title {
+ padding: 3px;
+ spacing: 4px;
+ background: #edeef0;
+}
+QDockWidget::close-button,
+QDockWidget::float-button {
+ border-radius: $radius{2px};
+}
+QDockWidget::close-button:hover,
+QDockWidget::float-button:hover {
+ background: rgba(181.000, 202.000, 244.000, 0.333);
+}
+QDockWidget::close-button:pressed,
+QDockWidget::float-button:pressed {
+ background: rgba(181.000, 202.000, 244.000, 0.933);
+}
+QFrame {
+ border: 1px solid #dadce0;
+ padding: 1px;
+ border-radius: $radius{4px};
+}
+.QFrame {
+ padding: 0;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border-color: transparent;
+ padding: 0;
+}
+.QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=NoFrame"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"0\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=NoFrame"}
+] {
+ border: none;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=Panel"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"2\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=Panel"}
+] {
+ border-color: #ffffff;
+ background: #ffffff;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=HLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"4\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=HLine"}
+] {
+ max-height: 2px;
+ border: none;
+ background: #dadce0;
+}
+QFrame[
+$env_patch{"version": "<6.0.0", "qt": "PySide2", "value": "frameShape=VLine"}
+$env_patch{"version": "<6.0.0", "qt": "PyQt5", "value": "frameShape=\\\"5\\\""}
+$env_patch{"version": ">=6.0.0", "value": "frameShape=VLine"}
+] {
+ max-width: 2px;
+ border: none;
+ background: #dadce0;
+}
+QLCDNumber {
+ color: #4d5157;
+ min-width: 2em;
+ margin: 2px;
+}
+QLabel:!window,
+QLCDNumber:!window {
+ background-color: transparent;
+}
+QToolBox:selected {
+ border: 2px solid #0081db;
+}
+QToolBox::tab {
+ background: #edeef0;
+ border-bottom: 2px solid #dadce0;
+ border-top-left-radius: $radius{4px};
+ border-top-right-radius: $radius{4px};
+}
+QToolBox::tab:selected {
+ border-bottom: 2px solid #0081db;
+}
+QToolBox::tab:selected:disabled {
+ border-bottom: 2px solid #dadce0;
+}
+
+QAbstractScrollArea {
+ selection-background-color: #4ca6e5;
+ selection-color: #4d5157;
+ margin: 0px;
+ padding: 0px, 0px, 0px, 0px;
+}
+QAbstractScrollArea:disabled {
+ selection-background-color: #0081db;
+}
+QAbstractScrollArea::corner {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget {
+ background: transparent;
+}
+QAbstractScrollArea > .QWidget > .QWidget {
+ background: transparent;
+}
+QTextEdit, QPlainTextEdit {
+ background: #ffffff;
+}
+QTextEdit:focus,
+QTextEdit:selected,
+QPlainTextEdit:focus,
+QPlainTextEdit:selected {
+ border: 1px solid #0081db;
+ selection-background-color: #a2d8ff;
+}
+QTextEdit:!focus,
+QPlainTextEdit:!focus {
+ $env_patch{"version": ">=5.15.0", "value": "selection-background-color: #e4e6f2"};
+}
+QTextEdit:!active,
+QPlainTextEdit:!active {
+ $env_patch{"version": "<5.15.0", "value": "selection-background-color: #e4e6f2"};
+}
+QAbstractItemView {
+ alternate-background-color: #e9ecef;
+}
+QAbstractItemView::item {
+ $env_patch{"version": ">=6.0.0", "value": "border-color: transparent"};
+}
+QAbstractItemView:selected:!active,
+QAbstractItemView:selected:!focus,
+QAbstractItemView::item:selected:!active,
+QTreeView::branch:selected:!active {
+ background: #e4e6f2;
+}
+QAbstractItemView::item:selected,
+QTreeView::branch:selected {
+ background: #4ca6e5;
+ color: #4d5157;
+}
+QAbstractItemView::item:!selected:hover,
+QTreeView::branch:!selected:hover {
+ background: #d3d3d3;
+}
+QAbstractItemView::item:selected:disabled {
+ color: #babdc2;
+}
+QAbstractItemView QLineEdit,
+QAbstractItemView QAbstractSpinBox,
+QAbstractItemView QComboBox,
+QAbstractItemView QAbstractButton {
+ padding: 0;
+ margin: 0px;
+}
+QTreeView::branch {
+ border-image: url(${path}/themes/light/svg/vertical_line__guides-stroke-inactive.svg) 0;
+}
+QTreeView::branch:active {
+ border-image: url(${path}/themes/light/svg/vertical_line__icon-foreground.svg) 0;
+}
+QTreeView::branch:disabled {
+ border-image: url(${path}/themes/light/svg/vertical_line__icon-foreground-disabled.svg) 0;
+}
+QTreeView::branch:has-siblings:adjoins-item,
+QTreeView::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: unset;
+}
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/themes/light/svg/chevron_right__icon-foreground.svg);
+}
+QTreeView::branch:has-children:!has-siblings:closed:disabled,
+QTreeView::branch:closed:has-children:has-siblings:disabled {
+ image: url(${path}/themes/light/svg/chevron_right__icon-foreground-disabled.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings {
+ border-image: unset;
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QTreeView::branch:open:has-children:!has-siblings:disabled,
+QTreeView::branch:open:has-children:has-siblings:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QTableView {
+ gridline-color: #58595c;
+ background: #ffffff;
+}
+QTableView QTableCornerButton::section {
+ margin: 0 1px 1px 0;
+ background: #dadce0;
+ border-top-left-radius: $radius{2px};
+}
+QTableView QTableCornerButton::section:pressed {
+ background: #4ca6e5;
+}
+QTableView > QHeaderView{
+ background: #ffffff;
+}
+QHeaderView {
+ padding: 0;
+ margin: 0;
+ border: none;
+ border-radius: $radius{0};
+}
+QHeaderView::section {
+ background: #dadce0;
+ text-align: left;
+ padding: 0 0px;
+ border: none;
+}
+QHeaderView::section:horizontal:on,
+QHeaderView::section:vertical:on {
+ border-color: #0081db;
+}
+QHeaderView::section:horizontal:on:disabled,
+QHeaderView::section:vertical:on:disabled {
+ color: #dadce0;
+ border-color: #dadce0;
+}
+QHeaderView::section:horizontal {
+ border-top: 2px solid transparent;
+ margin-right: 1px;
+}
+QHeaderView::section:vertical {
+ border-left: 2px solid transparent;
+ margin-bottom: 1px;
+}
+QHeaderView::section:last,
+QHeaderView::section:only-one {
+ margin: 0;
+}
+QHeaderView::down-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground__rotate-180.svg);
+}
+QHeaderView::down-arrow:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled__rotate-180.svg);
+}
+QHeaderView::up-arrow {
+ margin: -2px -6px -6px -6px;
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground.svg);
+}
+QHeaderView::up-arrow:disabled {
+ image: url(${path}/themes/light/svg/expand_less__icon-foreground-disabled.svg);
+}
+QCalendarWidget {
+ border: none;
+}
+QCalendarWidget > .QWidget {
+ background: #ffffff;
+ border-bottom: 1px solid #dadce0;
+ border-radius: $radius{4px};
+ border-bottom-left-radius: $radius{0};
+ border-bottom-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QWidget {
+ padding: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox {
+ margin-left: 1px;
+}
+QCalendarWidget > .QWidget > QSpinBox::up-button,
+QCalendarWidget > .QWidget > QSpinBox::down-button {
+ margin: 1px 3px 1px 1px;
+}
+QCalendarWidget .QWidget > QToolButton {
+ border-radius: $radius{4px};
+}
+QCalendarWidget > .QWidget > QToolButton::menu-indicator {
+ height: 14px;
+ width: 14px;
+ top: 5px;
+ left: 3px;
+}
+QCalendarWidget > QTableView {
+ margin: 0;
+ border: none;
+ border-radius: $radius{4px};
+ border-top-left-radius: $radius{0};
+ border-top-right-radius: $radius{0};
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_prevmonth {
+ qproperty-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-270.svg);
+}
+QCalendarWidget > .QWidget > QToolButton#qt_calendar_nextmonth {
+ qproperty-icon: url(${path}/themes/light/svg/arrow_upward__icon-foreground__rotate-90.svg);
+}
+QLineEdit,
+QAbstractSpinBox {
+ border: 1px solid #dadce0;
+ padding: 3px 4px;
+ min-height: 1em;
+ background: rgba(255.000, 255.000, 255.000, 0.000);
+ border-radius: $radius{4px};
+}
+QLineEdit:focus,
+QAbstractSpinBox:focus {
+ border: 1px solid #0081db;
+}
+QAbstractSpinBox::up-button,
+QAbstractSpinBox::down-button {
+ subcontrol-origin: border;
+ width: 12px;
+ height: 4px;
+ padding: 3px;
+ border-radius: $radius{4px};
+}
+QAbstractSpinBox::up-button:hover,
+QAbstractSpinBox::down-button:hover {
+ background: #e2eafb;
+}
+QAbstractSpinBox::up-button {
+ subcontrol-position: top right;
+ margin: 3px 3px 1px 1px;
+}
+QAbstractSpinBox::up-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__icon-foreground.svg);
+}
+QAbstractSpinBox::up-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__icon-foreground-disabled.svg);
+}
+QAbstractSpinBox::down-button {
+ subcontrol-position: bottom right;
+ margin: 1px 3px 3px 1px;
+}
+QAbstractSpinBox::down-arrow {
+ image: url(${path}/themes/light/svg/arrow_drop_up__icon-foreground__rotate-180.svg);
+}
+QAbstractSpinBox::down-arrow:disabled {
+ image: url(${path}/themes/light/svg/arrow_drop_up__icon-foreground-disabled__rotate-180.svg);
+}
+QDateTimeEdit::drop-down {
+ padding-right: 4px;
+ width: 16px;
+ image: url(${path}/themes/light/svg/calendar_today__icon-foreground.svg);
+}
+QDateTimeEdit::drop-down:disabled {
+ image: url(${path}/themes/light/svg/calendar_today__icon-foreground-disabled.svg);
+}
+QDateTimeEdit::down-arrow[calendarPopup=true] {
+ image: none;
+}
+QDateTimeEdit QCalendarWidget QAbstractItemView {
+ padding: -1px;
+ border: none;
+}
+QFileDialog > QFrame QAbstractItemView {
+ border: none;
+}
+QFileDialog > QFrame > QFrame QFrame QFrame {
+ border: none;
+ padding: 0;
+}
+QFontDialog QListView {
+ min-height: 60px;
+}
+QFontDialog QScrollBar:vertical {
+ margin: 0;
+}
+QComboBox::indicator:checked,
+QMenu::indicator:checked {
+ width: 18px;
+ image: url(${path}/themes/light/svg/check__icon-foreground.svg);
+}
+QMenu::indicator {
+ width: 18px;
+ background: #c4c7cc;
+ margin-left: 3px;
+ border-radius: $radius{4px};
+}
+QCheckBox,
+QRadioButton {
+ spacing: 8px;
+}
+QGroupBox::title,
+QAbstractItemView::item {
+ spacing: 6px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator,
+QRadioButton::indicator {
+ height: 18px;
+ width: 18px;
+}
+QCheckBox::indicator,
+QGroupBox::indicator,
+QAbstractItemView::indicator {
+ image: url(${path}/themes/light/svg/check_box_outline_blank__icon-foreground.svg);
+}
+QCheckBox::indicator:unchecked:disabled,
+QGroupBox::indicator:unchecked:disabled,
+QAbstractItemView::indicator:unchecked:disabled {
+ image: url(${path}/themes/light/svg/check_box_outline_blank__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:checked,
+QGroupBox::indicator:checked,
+QAbstractItemView::indicator:checked {
+ image: url(${path}/themes/light/svg/check_box__highlight.svg);
+}
+QCheckBox::indicator:checked:disabled,
+QGroupBox::indicator:checked:disabled,
+QAbstractItemView::indicator:checked:disabled {
+ image: url(${path}/themes/light/svg/check_box__icon-foreground-disabled.svg);
+}
+QCheckBox::indicator:indeterminate,
+QAbstractItemView::indicator:indeterminate {
+ image: url(${path}/themes/light/svg/indeterminate_check_box__highlight.svg);
+}
+QCheckBox::indicator:indeterminate:disabled,
+QAbstractItemView::indicator:indeterminate:disabled {
+ image: url(${path}/themes/light/svg/indeterminate_check_box__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:unchecked {
+ image: url(${path}/themes/light/svg/radio_button_unchecked__icon-foreground.svg);
+}
+QRadioButton::indicator:unchecked:disabled {
+ image: url(${path}/themes/light/svg/radio_button_unchecked__icon-foreground-disabled.svg);
+}
+QRadioButton::indicator:checked {
+ image: url(${path}/themes/light/svg/radio_button_checked__highlight.svg);
+}
+QRadioButton::indicator:checked:disabled {
+ image: url(${path}/themes/light/svg/radio_button_checked__icon-foreground-disabled.svg);
+}
+QComboBox QAbstractItemView,
+QStatusBar > QMenu,
+QDateTimeEdit QCalendarWidget QAbstractItemView,
+QDateTimeEdit QCalendarWidget .QWidget {
+ margin: 0;
+ border-radius: $radius{0};
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{4px}"};
+}
+QMenu,
+QStatusBar > QMenu {
+ $env_patch{"version": "<6.0.0", "os": "Darwin", "value": "border-radius: $radius{8px}"};
+}
+PlotWidget {
+ padding: 0;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::up-button,
+ParameterTree > .QWidget > .QWidget > .QWidget > QAbstractSpinBox::down-button {
+ margin: 2px 3px 1px 1px;
+ padding: 2px;
+}
+ParameterTree > .QWidget > .QWidget > .QWidget > QComboBox{
+ min-height: 1.2em;
+}
+
+"""
\ No newline at end of file
diff --git a/appMain.py b/appMain.py
index 37e74ba8..61ff699c 100644
--- a/appMain.py
+++ b/appMain.py
@@ -42,13 +42,14 @@ import tkinter as tk
import qdarktheme
import qdarktheme.themes.dark.stylesheet as qdarksheet
+import qdarktheme.themes.light.stylesheet as qlightsheet
# ####################################################################################################################
# ################################### Imports part of FlatCAM #############################################
# ####################################################################################################################
# Various
-from appGUI import style_sheet
+from appGUI.themes import dark_style_sheet, light_style_sheet
from appCommon.Common import LoudDict
from appCommon.Common import color_variant
@@ -108,6 +109,8 @@ import gettext
import appTranslation as fcTranslate
import builtins
+import darkdetect
+
if sys.platform == 'win32':
import winreg
@@ -610,6 +613,22 @@ class App(QtCore.QObject):
# self.preferencesUiManager.show_preferences_gui()
+ # Set global_theme based on appearance
+ if self.options["global_appearance"] == 'auto':
+ if darkdetect.isDark():
+ theme = 'dark'
+ else:
+ theme = 'light'
+ else:
+ if self.options["global_appearance"] == 'default':
+ theme = 'default'
+ elif self.options["global_appearance"] == 'dark':
+ theme = 'dark'
+ else:
+ theme = 'light'
+
+ self.options["global_theme"] = theme
+
self.app_units = self.options["units"]
self.default_units = self.defaults["units"]
@@ -618,16 +637,15 @@ class App(QtCore.QObject):
else:
self.decimals = int(self.options['decimals_inch'])
- if self.options["global_gray_icons"] is False:
+ if self.options["global_theme"] == 'default':
self.resource_location = 'assets/resources'
+ elif self.options["global_theme"] == 'light':
+ self.resource_location = 'assets/resources'
+ qlightsheet.STYLE_SHEET = light_style_sheet.L_STYLE_SHEET
+ self.qapp.setStyleSheet(qdarktheme.load_stylesheet('light'))
else:
self.resource_location = 'assets/resources/dark_resources'
-
- # #############################################################################################################
- # ######################################### DARK THEME ########################################################
- # #############################################################################################################
- if self.options["global_gray_icons"] is True:
- qdarksheet.STYLE_SHEET = style_sheet.D_STYLE_SHEET # patching so I can do my own changes to the theme
+ qdarksheet.STYLE_SHEET = dark_style_sheet.D_STYLE_SHEET
self.qapp.setStyleSheet(qdarktheme.load_stylesheet())
# ###########################################################################################################
@@ -1021,20 +1039,19 @@ class App(QtCore.QObject):
self.FC_dark_blue = '#0000ffbf'
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
- if theme_settings.contains("theme"):
- theme = theme_settings.value('theme', type=str)
- else:
- theme = 'white'
+ theme_settings.setValue("appearance", self.options["global_appearance"])
+ theme_settings.setValue("theme", self.options["global_theme"])
+ theme_settings.setValue("dark_canvas", self.options["global_dark_canvas"])
if self.options["global_cursor_color_enabled"]:
self.cursor_color_3D = self.options["global_cursor_color"]
else:
- if theme == 'white':
+ if (theme == 'light' or theme == 'default') and not self.options["global_dark_canvas"]:
self.cursor_color_3D = 'black'
else:
self.cursor_color_3D = 'gray'
- # update the options dict with the setting in QSetting
+ # update the 'options' dict with the setting in QSetting
self.options['global_theme'] = theme
# ########################
@@ -8624,7 +8641,7 @@ class App(QtCore.QObject):
root = d_properties_tw.invisibleRootItem()
font = QtGui.QFont()
font.setBold(True)
- p_color = QtGui.QColor("#000000") if self.options['global_gray_icons'] is False else QtGui.QColor("#FFFFFF")
+ p_color = QtGui.QColor("#000000") if self.options['global_theme'] == 'light' else QtGui.QColor("#FFFFFF")
# main Items categories
general_cat = d_properties_tw.addParent(root, _('General'), expanded=True, color=p_color, font=font)
@@ -9430,6 +9447,7 @@ class App(QtCore.QObject):
return float('%.*f' % (dec_nr, float(val)))
+
class ArgsThread(QtCore.QObject):
open_signal = pyqtSignal(list)
start = pyqtSignal()
diff --git a/appObjects/AppObjectTemplate.py b/appObjects/AppObjectTemplate.py
index 192bb636..1e22e465 100644
--- a/appObjects/AppObjectTemplate.py
+++ b/appObjects/AppObjectTemplate.py
@@ -536,7 +536,7 @@ class FlatCAMObj(QtCore.QObject):
font = QtGui.QFont()
font.setBold(True)
- p_color = QtGui.QColor("#000000") if self.app.options['global_gray_icons'] is False \
+ p_color = QtGui.QColor("#000000") if self.app.options['global_theme'] == 'light' \
else QtGui.QColor("#FFFFFF")
# main Items categories
diff --git a/appObjects/CNCJobObject.py b/appObjects/CNCJobObject.py
index 8cf9abb8..e795c3ef 100644
--- a/appObjects/CNCJobObject.py
+++ b/appObjects/CNCJobObject.py
@@ -1001,15 +1001,15 @@ class CNCJobObject(FlatCAMObj, CNCjob):
if postamble == '':
postamble = self.app.options["cncjob_append"]
- try:
- if self.special_group:
- self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' %
- (_("This CNCJob object can't be processed because it is a"),
- str(self.special_group),
- _("CNCJob object")))
- return 'fail'
- except AttributeError:
- pass
+ # try:
+ # if self.special_group:
+ # self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' %
+ # (_("This CNCJob object can't be processed because it is a"),
+ # str(self.special_group),
+ # _("CNCJob object")))
+ # return 'fail'
+ # except AttributeError:
+ # pass
# if this dict is not empty then the object is a Geometry object
if self.obj_options['type'].lower() == 'geometry':
@@ -1357,7 +1357,8 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.plot2(tooldia=dia_plot, obj=self, visible=visible, gcode_parsed=gcode_parsed,
kind=kind)
self.shapes.redraw()
- except (ObjectDeleted, AttributeError):
+ except (ObjectDeleted, AttributeError) as err:
+ self.app.log.debug("CNCJobObject.plot() --> %s" % str(err))
self.shapes.clear(update=True)
if self.app.use_3d_engine:
self.annotation.clear(update=True)
diff --git a/appObjects/ObjectCollection.py b/appObjects/ObjectCollection.py
index d8fa9660..742aefab 100644
--- a/appObjects/ObjectCollection.py
+++ b/appObjects/ObjectCollection.py
@@ -508,7 +508,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
theme = theme_settings.value('theme', type=str)
- if theme in ['black', 'dark']:
+ if theme == 'dark':
color = QColor(self.app.options['global_proj_item_color_dark'][:-2])
color_disabled = QColor(self.app.options['global_proj_item_dis_color_dark'][:-2])
else:
diff --git a/appPlugins/ToolAlignObjects.py b/appPlugins/ToolAlignObjects.py
index c8f1bfdb..d8e95ace 100644
--- a/appPlugins/ToolAlignObjects.py
+++ b/appPlugins/ToolAlignObjects.py
@@ -503,7 +503,7 @@ class AlignUI:
par_frame.setLayout(grid2)
# Alignment Type
- self.a_type_lbl = FCLabel('%s:' % _("Alignment Type"))
+ self.a_type_lbl = FCLabel('%s:' % _("Alignment Type"), bold=True)
self.a_type_lbl.setToolTip(
_("The type of alignment can be:\n"
"- Single Point -> it require a single point of sync, the action will be a translation\n"
diff --git a/appPlugins/ToolCalibration.py b/appPlugins/ToolCalibration.py
index a265562d..a897b58d 100644
--- a/appPlugins/ToolCalibration.py
+++ b/appPlugins/ToolCalibration.py
@@ -767,7 +767,7 @@ class CalibrationUI:
grid_lay = GLay(v_spacing=5, h_spacing=3, c_stretch=[0, 1, 0])
self.layout.addLayout(grid_lay)
- self.gcode_title_label = FCLabel('%s:' % _('Parameters'))
+ self.gcode_title_label = FCLabel('%s:' % _('Parameters'), bold=True)
self.gcode_title_label.setToolTip(
_("Parameters used when creating the GCode in this tool.")
)
@@ -873,7 +873,7 @@ class CalibrationUI:
grid_lay.addWidget(FCLabel(''), 9, 0, 1, 3)
- step_1 = FCLabel('%s' % _("STEP 1: Acquire Calibration Points"))
+ step_1 = FCLabel('%s' % _("STEP 1: Acquire Calibration Points"), bold=True)
step_1.setToolTip(
_("Pick four points by clicking on canvas.\n"
"Those four points should be in the four\n"
@@ -881,7 +881,7 @@ class CalibrationUI:
)
grid_lay.addWidget(step_1, 10, 0, 1, 3)
- self.cal_source_lbl = FCLabel("%s:" % _("Source Type"))
+ self.cal_source_lbl = FCLabel('%s:' % _("Source Type"), bold=True)
self.cal_source_lbl.setToolTip(_("The source of calibration points.\n"
"It can be:\n"
"- Object -> click a hole geo for Excellon or a pad for Gerber\n"
@@ -918,7 +918,7 @@ class CalibrationUI:
grid_lay.addWidget(self.object_label, 13, 0, 1, 3)
grid_lay.addWidget(self.object_combo, 14, 0, 1, 3)
- self.points_table_label = FCLabel('%s' % _('Calibration Points'))
+ self.points_table_label = FCLabel('%s' % _('Calibration Points'), bold=True)
self.points_table_label.setToolTip(
_("Contain the expected calibration points and the\n"
"ones measured.")
@@ -1090,7 +1090,7 @@ class CalibrationUI:
grid_lay.addWidget(FCLabel(''), 19, 0)
# STEP 2 #
- step_2 = FCLabel('%s' % _("STEP 2: Verification GCode"))
+ step_2 = FCLabel('%s' % _("STEP 2: Verification GCode"), bold=True)
step_2.setToolTip(
_("Generate GCode file to locate and align the PCB by using\n"
"the four points acquired above.\n"
@@ -1129,7 +1129,7 @@ class CalibrationUI:
grid_lay.addWidget(FCLabel(''), 23, 0, 1, 3)
# STEP 3 #
- step_3 = FCLabel('%s' % _("STEP 3: Adjustments"))
+ step_3 = FCLabel('%s' % _("STEP 3: Adjustments"), bold=True)
step_3.setToolTip(
_("Calculate Scale and Skew factors based on the differences (delta)\n"
"found when checking the PCB pattern. The differences must be filled\n"
@@ -1160,7 +1160,7 @@ class CalibrationUI:
grid_lay.addWidget(FCLabel(''), 27, 0, 1, 3)
# STEP 4 #
- step_4 = FCLabel('%s' % _("STEP 4: Adjusted GCode"))
+ step_4 = FCLabel('%s' % _("STEP 4: Adjusted GCode"), bold=True)
step_4.setToolTip(
_("Generate verification GCode file adjusted with\n"
"the factors above.")
@@ -1241,7 +1241,7 @@ class CalibrationUI:
""")
grid_lay.addWidget(self.skew_button, 34, 0, 1, 3)
- # final_factors_lbl = FCLabel('%s' % _("Final Factors"))
+ # final_factors_lbl = FCLabel('%s' % _("Final Factors"), bold=True)
# final_factors_lbl.setToolTip(
# _("Generate verification GCode file adjusted with\n"
# "the factors above.")
@@ -1323,7 +1323,7 @@ class CalibrationUI:
grid_lay.addWidget(FCLabel(''), 44, 0, 1, 3)
# STEP 5 #
- step_5 = FCLabel('%s' % _("STEP 5: Calibrate FlatCAM Objects"))
+ step_5 = FCLabel('%s' % _("STEP 5: Calibrate FlatCAM Objects"), bold=True)
step_5.setToolTip(
_("Adjust the FlatCAM objects\n"
"with the factors determined and verified above.")
diff --git a/appPlugins/ToolCopperThieving.py b/appPlugins/ToolCopperThieving.py
index debcf626..9d03c758 100644
--- a/appPlugins/ToolCopperThieving.py
+++ b/appPlugins/ToolCopperThieving.py
@@ -1449,7 +1449,7 @@ class ThievingUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
dots_grid.addWidget(separator_line, 0, 0, 1, 2)
- self.dots_label = FCLabel('%s:' % _("Dots Grid Parameters"))
+ self.dots_label = FCLabel('%s' % _("Dots Grid Parameters"), bold=True)
dots_grid.addWidget(self.dots_label, 2, 0, 1, 2)
# Dot diameter #
@@ -1495,7 +1495,7 @@ class ThievingUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
squares_grid.addWidget(separator_line, 0, 0, 1, 2)
- self.squares_label = FCLabel('%s:' % _("Squares Grid Parameters"))
+ self.squares_label = FCLabel('%s' % _("Squares Grid Parameters"), bold=True)
squares_grid.addWidget(self.squares_label, 2, 0, 1, 2)
# Square Size #
@@ -1541,7 +1541,7 @@ class ThievingUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
lines_grid.addWidget(separator_line, 0, 0, 1, 2)
- self.lines_label = FCLabel('%s:' % _("Lines Grid Parameters"))
+ self.lines_label = FCLabel('%s' % _("Lines Grid Parameters"), bold=True)
lines_grid.addWidget(self.lines_label, 2, 0, 1, 2)
# Line Size #
diff --git a/appPlugins/ToolDblSided.py b/appPlugins/ToolDblSided.py
index a4149570..8643adb6 100644
--- a/appPlugins/ToolDblSided.py
+++ b/appPlugins/ToolDblSided.py
@@ -884,7 +884,7 @@ class DsidedUI:
grid_mirror.addWidget(separator_line, 3, 0, 1, 3)
# ## Reference
- self.axloc_label = FCLabel('%s:' % _("Reference"))
+ self.axloc_label = FCLabel('%s' % _("Reference"), bold=True)
self.axloc_label.setToolTip(
_("The coordinates used as reference for the mirror operation.\n"
"Can be:\n"
@@ -980,7 +980,7 @@ class DsidedUI:
grid_snap_ref.setContentsMargins(0, 0, 0, 0)
self.sr_frame.setLayout(grid_snap_ref)
- self.exc_hole_lbl = FCLabel('%s:' % _("Excellon"))
+ self.exc_hole_lbl = FCLabel('%s' % _("Excellon"), bold=True)
self.exc_hole_lbl.setToolTip(
_("Object that holds holes that can be picked as reference for mirroring.")
)
diff --git a/appPlugins/ToolDistance.py b/appPlugins/ToolDistance.py
index 316ac0ea..a7f4ec28 100644
--- a/appPlugins/ToolDistance.py
+++ b/appPlugins/ToolDistance.py
@@ -764,15 +764,20 @@ class Distance(AppTool):
if settings.contains("theme"):
theme = settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'default'
+
+ if settings.contains("dark_canvas"):
+ dark_canvas = settings.value('dark_canvas', type=bool)
+ else:
+ dark_canvas = False
if self.app.use_3d_engine:
- if theme == 'white':
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
color = '#000000FF'
else:
color = '#FFFFFFFF'
else:
- if theme == 'white':
+ if (theme == 'default' or theme == 'light') and not dark_canvas:
color = '#000000'
else:
color = '#FFFFFF'
@@ -958,7 +963,7 @@ class DistanceUI:
res_grid.addWidget(separator_line, 8, 0, 1, 3)
# Distance
- self.total_distance_label = FCLabel("%s:" % _('DISTANCE'))
+ self.total_distance_label = FCLabel('%s:' % _('DISTANCE'), bold=True)
self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
self.total_distance_entry = FCEntry()
diff --git a/appPlugins/ToolExtract.py b/appPlugins/ToolExtract.py
index 9585784c..b8e6cbf4 100644
--- a/appPlugins/ToolExtract.py
+++ b/appPlugins/ToolExtract.py
@@ -1186,7 +1186,7 @@ class ExtractUI:
self.ring_box.addLayout(ring_grid)
# Annular Ring value
- self.ring_label = FCLabel('%s' % _("Fixed Annular Ring"))
+ self.ring_label = FCLabel('%s' % _("Fixed Annular Ring"), bold=True)
self.ring_label.setToolTip(
_("The size of annular ring.\n"
"The copper sliver between the hole exterior\n"
@@ -1271,7 +1271,7 @@ class ExtractUI:
self.fix_frame.setLayout(fixed_grid)
# Fixed Diameter
- self.fixed_label = FCLabel('%s' % _("Fixed Diameter"))
+ self.fixed_label = FCLabel('%s' % _("Fixed Diameter"), bold=True)
fixed_grid.addWidget(self.fixed_label, 2, 0, 1, 2)
# Diameter value
@@ -1299,7 +1299,7 @@ class ExtractUI:
self.prop_frame.setLayout(prop_grid)
# Proportional Diameter
- self.prop_label = FCLabel('%s' % _("Proportional Diameter"))
+ self.prop_label = FCLabel('%s' % _("Proportional Diameter"), bold=True)
prop_grid.addWidget(self.prop_label, 0, 0, 1, 2)
# Diameter value
diff --git a/appPlugins/ToolFilm.py b/appPlugins/ToolFilm.py
index fba56017..8efffa3f 100644
--- a/appPlugins/ToolFilm.py
+++ b/appPlugins/ToolFilm.py
@@ -1351,11 +1351,6 @@ class FilmUI:
_("A value greater than 1 will compact the film\n"
"while a value less than 1 will jolt it.")
)
- self.film_scale_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_scale_cb, 2, 0, 1, 2)
# Scale Type
@@ -1426,11 +1421,6 @@ class FilmUI:
_("Positive values will skew to the right\n"
"while negative values will skew to the left.")
)
- self.film_skew_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_skew_cb, 14, 0, 1, 2)
# Skew Type
@@ -1501,11 +1491,6 @@ class FilmUI:
self.film_mirror_cb.setToolTip(
_("Mirror the film geometry on the selected axis or on both.")
)
- self.film_mirror_cb.setStyleSheet(
- """
- QCheckBox {font-weight: bold; color: black}
- """
- )
adj_grid.addWidget(self.film_mirror_cb, 26, 0, 1, 2)
self.film_mirror_axis = RadioSet([{'label': _('X'), 'value': 'x'},
diff --git a/appPlugins/ToolImage.py b/appPlugins/ToolImage.py
index 233b353b..18791c24 100644
--- a/appPlugins/ToolImage.py
+++ b/appPlugins/ToolImage.py
@@ -346,7 +346,7 @@ class ImageUI:
# Type of image interpretation
self.image_type = RadioSet([{'label': 'B/W', 'value': 'black'},
{'label': 'Color', 'value': 'color'}])
- self.image_type_label = FCLabel("%s:" % _('Image type'))
+ self.image_type_label = FCLabel('%s:' % _('Image type'), bold=True)
self.image_type_label.setToolTip(
_("Choose a method for the image interpretation.\n"
"B/W means a black & white image. Color means a colored image.")
diff --git a/appPlugins/ToolIsolation.py b/appPlugins/ToolIsolation.py
index 8dbc70c5..acdc7e0e 100644
--- a/appPlugins/ToolIsolation.py
+++ b/appPlugins/ToolIsolation.py
@@ -3470,7 +3470,7 @@ class IsoUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
new_tool_grid.addWidget(separator_line, 0, 0, 1, 3)
- self.tool_sel_label = FCLabel('%s' % _('Add from DB'))
+ self.tool_sel_label = FCLabel('%s' % _('Add from DB'), bold=True)
new_tool_grid.addWidget(self.tool_sel_label, 2, 0, 1, 3)
# ### Tool Diameter ####
diff --git a/appPlugins/ToolLevelling.py b/appPlugins/ToolLevelling.py
index f99f5a3d..c8393041 100644
--- a/appPlugins/ToolLevelling.py
+++ b/appPlugins/ToolLevelling.py
@@ -1794,7 +1794,7 @@ class LevelUI:
grid0 = GLay(v_spacing=5, h_spacing=3)
self.al_box.addLayout(grid0)
- self.al_title = FCLabel('%s' % _("Probe Points Table"))
+ self.al_title = FCLabel('%s' % _("Probe Points Table"), bold=True)
self.al_title.setToolTip(_("Generate GCode that will obtain the height map"))
self.show_al_table = FCCheckBox(_("Show"))
@@ -1894,7 +1894,7 @@ class LevelUI:
param_grid.addWidget(separator_line, 6, 0, 1, 2)
# AUTOLEVELL MODE
- al_mode_lbl = FCLabel('%s:' % _("Mode"))
+ al_mode_lbl = FCLabel('%s' % _("Mode"), bold=True)
al_mode_lbl.setToolTip(_("Choose a mode for height map generation.\n"
"- Manual: will pick a selection of probe points by clicking on canvas\n"
"- Grid: will automatically generate a grid of probe points"))
diff --git a/appPlugins/ToolMilling.py b/appPlugins/ToolMilling.py
index 39ae0437..23f29e7a 100644
--- a/appPlugins/ToolMilling.py
+++ b/appPlugins/ToolMilling.py
@@ -4184,7 +4184,7 @@ class MillingUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
new_tool_grid.addWidget(separator_line, 0, 0, 1, 2)
- self.tool_sel_label = FCLabel('%s' % _("Add from DB"))
+ self.tool_sel_label = FCLabel('%s' % _("Add from DB"), bold=True)
new_tool_grid.addWidget(self.tool_sel_label, 2, 0, 1, 2)
self.addtool_entry_lbl = FCLabel('%s:' % _('Tool Dia'))
diff --git a/appPlugins/ToolNCC.py b/appPlugins/ToolNCC.py
index 982bba2d..66f44520 100644
--- a/appPlugins/ToolNCC.py
+++ b/appPlugins/ToolNCC.py
@@ -4193,7 +4193,7 @@ class NccUI:
# #############################################################
# ############### Tool selection ##############################
# #############################################################
- self.tool_sel_label = FCLabel('%s' % _('Add from DB'))
+ self.tool_sel_label = FCLabel('%s' % _('Add from DB'), bold=True)
new_tool_grid.addWidget(self.tool_sel_label, 2, 0, 1, 3)
# ### Tool Diameter ####
diff --git a/appPlugins/ToolObjectDistance.py b/appPlugins/ToolObjectDistance.py
index 3679a534..88d17eb4 100644
--- a/appPlugins/ToolObjectDistance.py
+++ b/appPlugins/ToolObjectDistance.py
@@ -570,7 +570,7 @@ class ObjectDistanceUI:
res_grid.addWidget(separator_line, 6, 0, 1, 3)
# Total Distance
- self.total_distance_label = FCLabel("%s:" % _('DISTANCE'))
+ self.total_distance_label = FCLabel('%s:' % _('DISTANCE'), bold=True)
self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
self.total_distance_entry = FCEntry()
@@ -584,7 +584,7 @@ class ObjectDistanceUI:
res_grid.addWidget(FCLabel("%s" % self.units), 8, 2)
# Half Point
- self.half_point_label = FCLabel("%s:" % _('Half Point'))
+ self.half_point_label = FCLabel('%s:' % _('Half Point'), bold=True)
self.half_point_label.setToolTip(_("This is the middle point of the point to point Euclidean distance."))
self.half_point_entry = FCEntry()
diff --git a/appPlugins/ToolOptimal.py b/appPlugins/ToolOptimal.py
index 830dea85..60d29a5d 100644
--- a/appPlugins/ToolOptimal.py
+++ b/appPlugins/ToolOptimal.py
@@ -494,7 +494,7 @@ class OptimalUI:
self.gerber_object_combo.is_last = True
self.gerber_object_combo.obj_type = "Gerber"
- self.gerber_object_label = FCLabel("%s:" % _("GERBER"))
+ self.gerber_object_label = FCLabel('%s:' % _("GERBER"), bold=True)
self.gerber_object_label.setToolTip(
"Gerber object for which to find the minimum distance between copper features."
)
diff --git a/appPlugins/ToolPaint.py b/appPlugins/ToolPaint.py
index 620e9d2a..03690b15 100644
--- a/appPlugins/ToolPaint.py
+++ b/appPlugins/ToolPaint.py
@@ -3041,7 +3041,7 @@ class PaintUI:
"L = laser"))
# Tool Order
- self.order_label = FCLabel('%s:' % _('Tool order'))
+ self.order_label = FCLabel('%s:' % _('Tool order'), bold=True)
self.order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
"'Default' --> means that the used order is the one in the tool table\n"
"'Forward' --> means that the tools will be ordered from small to big\n"
@@ -3071,7 +3071,7 @@ class PaintUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
new_tool_grid.addWidget(separator_line, 0, 0, 1, 2)
- self.tool_sel_label = FCLabel('%s' % _('Add from DB'))
+ self.tool_sel_label = FCLabel('%s' % _('Add from DB'), bold=True)
new_tool_grid.addWidget(self.tool_sel_label, 2, 0, 1, 2)
# ### Tool Diameter ####
diff --git a/appPlugins/ToolPanelize.py b/appPlugins/ToolPanelize.py
index 6bb55144..158de065 100644
--- a/appPlugins/ToolPanelize.py
+++ b/appPlugins/ToolPanelize.py
@@ -1344,7 +1344,7 @@ class PanelizeUI:
# Type of resulting Panel object
self.panel_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'gerber'},
{'label': _('Geo'), 'value': 'geometry'}])
- self.panel_type_label = FCLabel("%s:" % _("Panel Type"))
+ self.panel_type_label = FCLabel('%s:' % _("Panel Type"), bold=True)
self.panel_type_label.setToolTip(
_("Choose the type of object for the panel object:\n"
"- Gerber\n"
diff --git a/appPlugins/ToolPcbWizard.py b/appPlugins/ToolPcbWizard.py
index d23cd9f1..0c2cab65 100644
--- a/appPlugins/ToolPcbWizard.py
+++ b/appPlugins/ToolPcbWizard.py
@@ -484,7 +484,7 @@ class WizardUI:
# Units type
self.units_radio = RadioSet([{'label': _('Inch'), 'value': 'INCH'},
{'label': _('mm'), 'value': 'METRIC'}])
- self.units_label = FCLabel("%s:" % _('Units'))
+ self.units_label = FCLabel('%s:' % _('Units'), bold=True)
self.units_label.setToolTip(
_("The type of units that the coordinates and tool\n"
"diameters are using. Can be INCH or MM.")
diff --git a/appPlugins/ToolPunchGerber.py b/appPlugins/ToolPunchGerber.py
index 325bb021..1d04a24f 100644
--- a/appPlugins/ToolPunchGerber.py
+++ b/appPlugins/ToolPunchGerber.py
@@ -2173,7 +2173,7 @@ class PunchUI:
separator_line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
grid1.addWidget(separator_line, 2, 0, 1, 2)
- self.exc_label = FCLabel('%s' % _("Excellon"))
+ self.exc_label = FCLabel('%s' % _("Excellon"), bold=True)
self.exc_label.setToolTip(
_("Remove the geometry of Excellon from the Gerber to create the holes in pads.")
)
@@ -2188,7 +2188,7 @@ class PunchUI:
grid1.addWidget(self.exc_combo, 6, 0, 1, 2)
# Fixed Dia
- self.fixed_label = FCLabel('%s' % _("Fixed Diameter"))
+ self.fixed_label = FCLabel('%s' % _("Fixed Diameter"), bold=True)
grid1.addWidget(self.fixed_label, 8, 0, 1, 2)
# Diameter value
@@ -2216,7 +2216,7 @@ class PunchUI:
self.ring_frame.setLayout(self.ring_box)
# Annular Ring value
- self.ring_label = FCLabel('%s' % _("Fixed Annular Ring"))
+ self.ring_label = FCLabel('%s' % _("Fixed Annular Ring"), bold=True)
self.ring_label.setToolTip(
_("The size of annular ring.\n"
"The copper sliver between the hole exterior\n"
@@ -2295,7 +2295,7 @@ class PunchUI:
# #############################################################################################################
# Proportional value
- self.prop_label = FCLabel('%s' % _("Proportional Diameter"))
+ self.prop_label = FCLabel('%s' % _("Proportional Diameter"), bold=True)
grid1.addWidget(self.prop_label, 14, 0, 1, 2)
# Diameter value
diff --git a/appPlugins/ToolReport.py b/appPlugins/ToolReport.py
index c8193269..1e93783e 100644
--- a/appPlugins/ToolReport.py
+++ b/appPlugins/ToolReport.py
@@ -158,7 +158,7 @@ class ObjectReport(AppTool):
font = QtGui.QFont()
font.setBold(True)
- p_color = QtGui.QColor("#000000") if self.app.options['global_gray_icons'] is False \
+ p_color = QtGui.QColor("#000000") if self.app.options['global_theme'] == 'light' \
else QtGui.QColor("#FFFFFF")
# main Items categories
diff --git a/appPlugins/ToolSolderPaste.py b/appPlugins/ToolSolderPaste.py
index d95de190..1a7efd3e 100644
--- a/appPlugins/ToolSolderPaste.py
+++ b/appPlugins/ToolSolderPaste.py
@@ -154,6 +154,7 @@ class SolderPaste(AppTool):
"tools_solderpaste_z_dispense": self.ui.z_dispense_entry,
"tools_solderpaste_z_stop": self.ui.z_stop_entry,
"tools_solderpaste_z_travel": self.ui.z_travel_entry,
+ "tools_solderpaste_margin": self.ui.margin_entry,
"tools_solderpaste_z_toolchange": self.ui.z_toolchange_entry,
"tools_solderpaste_xy_toolchange": self.ui.xy_toolchange_entry,
"tools_solderpaste_frxy": self.ui.frxy_entry,
@@ -217,6 +218,12 @@ class SolderPaste(AppTool):
if obj and obj.kind == 'gerber':
obj_name = obj.obj_options['name']
self.ui.obj_combo.set_value(obj_name)
+ else:
+ # select first Gerber object found
+ for o in self.app.collection.get_list():
+ if o.kind == 'gerber':
+ obj_name = o.obj_options['name']
+ self.ui.obj_combo.set_value(obj_name)
def build_ui(self):
"""
@@ -451,6 +458,8 @@ class SolderPaste(AppTool):
current_row = self.ui.tools_table.currentRow()
uid = tooluid if tooluid else int(self.ui.tools_table.item(current_row, 2).text())
+ if uid < 0:
+ return
for key in self.form_fields:
self.tooltable_tools[uid]['data'].update({
key: self.form_fields[key].get_value()
@@ -718,6 +727,10 @@ class SolderPaste(AppTool):
:param use_thread: use thread, True or False
:return: a Geometry type object
"""
+
+ # this is a percentage of the tool diameter
+ tool_margin = self.ui.margin_entry.get_value()
+
proc = self.app.proc_container.new('%s...' % _("Working"))
obj = work_object
@@ -795,7 +808,7 @@ class SolderPaste(AppTool):
tooluid = 1
for tool in sorted_tools:
- offset = tool / 2
+ offset = ((tool_margin * tool) * 0.01) + (tool / 2)
for uid, vl in self.tooltable_tools.items():
if float('%.*f' % (self.decimals, float(vl['tooldia']))) == tool:
tooluid = int(uid)
@@ -817,7 +830,7 @@ class SolderPaste(AppTool):
# so we do a hack: get first the exterior in a form of LinearRings and then convert back to Polygon
# because intersection does not work on LinearRings
for g in work_geo:
- # for whatever reason intersection on LinearRings does not work so we convert back to Polygons
+ # for whatever reason intersection on LinearRings does not work, so we convert back to Polygons
poly = Polygon(g)
x_min, y_min, x_max, y_max = poly.bounds
@@ -1002,13 +1015,13 @@ class SolderPaste(AppTool):
app_obj.log.debug("GeometryObject.mtool_gen_cncjob() --> generate_from_geometry2() failed")
return 'fail'
else:
- tool_cnc_dict['gcode'] = StringIO(res)
+ tool_cnc_dict['gcode'] = res
total_gcode += res
# ## PARSE GCODE # ##
tool_cnc_dict['gcode_parsed'] = new_obj.gcode_parse(tool_data=tool_cnc_dict['data'])
- # TODO this serve for bounding box creation only; should be optimized
+ # TODO this serve for bounding box creation only; should be optimized. Using recursive bounds()?
tool_cnc_dict['solid_geometry'] = unary_union([geo['geom'] for geo in tool_cnc_dict['gcode_parsed']])
# tell gcode_parse from which point to start drawing the lines depending on what kind of
@@ -1019,6 +1032,9 @@ class SolderPaste(AppTool):
})
tool_cnc_dict.clear()
+ used_tools = list(obj.tools.keys())
+ new_obj.used_tools = used_tools
+
new_obj.source_file = StringIO(total_gcode)
if use_thread:
@@ -1268,7 +1284,7 @@ class SolderUI:
_("Tool Diameter. Its value\n"
"is the width of the solder paste dispensed."))
- self.addtool_entry_lbl = FCLabel('%s:' % _('New Tool'))
+ self.addtool_entry_lbl = FCLabel('%s:' % _('New Tool'), bold=True)
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool to add in the Tool Table")
)
@@ -1330,6 +1346,21 @@ class SolderUI:
param_grid.addWidget(self.z_travel_label, 0, 0)
param_grid.addWidget(self.z_travel_entry, 0, 1)
+ # MARGIN
+ self.margin_label = FCLabel('%s:' % _("Margin"))
+ self.margin_label.setToolTip('%s %s' % (
+ _("Offset from the boundary."),
+ _("Fraction of tool diameter.")
+ )
+ )
+ self.margin_entry = FCDoubleSpinner(suffix='%')
+ self.margin_entry.set_range(-100.0000, 100.0000)
+ self.margin_entry.set_precision(self.decimals)
+ self.margin_entry.setSingleStep(0.1)
+
+ param_grid.addWidget(self.margin_label, 2, 0)
+ param_grid.addWidget(self.margin_entry, 2, 1)
+
# #############################################################################################################
# Dispense Frame
# #############################################################################################################
diff --git a/appPlugins/ToolSub.py b/appPlugins/ToolSub.py
index a6b42da3..f16de017 100644
--- a/appPlugins/ToolSub.py
+++ b/appPlugins/ToolSub.py
@@ -901,7 +901,7 @@ class SubUI:
geo_grid = GLay(v_spacing=5, h_spacing=3)
geo_frame.setLayout(geo_grid)
- self.geo_title = FCLabel("%s" % _("GEOMETRY"))
+ self.geo_title = FCLabel('%s' % _("GEOMETRY"), bold=True)
self.tools_box.addWidget(self.geo_title)
# Target Geometry Object
diff --git a/appTranslation.py b/appTranslation.py
index 470ccaba..ed0964e9 100644
--- a/appTranslation.py
+++ b/appTranslation.py
@@ -93,12 +93,12 @@ def on_language_apply_click(app, restart=False):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
resource_loc = 'assets/resources'
else:
- resource_loc = 'assets/resources'
+ resource_loc = 'assets/resources/dark_resources'
# do nothing if trying to apply the language that is the current language (already applied).
settings = QSettings("Open Source", "FlatCAM")
@@ -190,12 +190,12 @@ def restart_program(app, ask=None):
if theme_settings.contains("theme"):
theme = theme_settings.value('theme', type=str)
else:
- theme = 'white'
+ theme = 'light'
- if theme == 'white':
+ if theme == 'light':
resource_loc = 'assets/resources'
else:
- resource_loc = 'assets/resources'
+ resource_loc = 'assets/resources/dark_resources'
# try to quit the Socket opened by ArgsThread class
try:
diff --git a/camlib.py b/camlib.py
index 7ed420c6..c0307edd 100644
--- a/camlib.py
+++ b/camlib.py
@@ -7193,7 +7193,7 @@ class CNCjob(Geometry):
return
try:
- if self.app.options['global_theme'] == 'white':
+ if self.app.options['global_theme'] == 'light':
obj.annotation.set(text=text, pos=pos, visible=obj.obj_options['plot'],
font_size=self.app.options["cncjob_annotation_fontsize"],
color=self.app.options["cncjob_annotation_fontcolor"])
diff --git a/defaults.py b/defaults.py
index 1bf2634e..8dc78ab6 100644
--- a/defaults.py
+++ b/defaults.py
@@ -112,8 +112,9 @@ class AppDefaults:
"global_tpdf_rmargin": 20.0,
# General GUI Preferences
- "global_theme": 'white',
- "global_gray_icons": False,
+ "global_appearance": 'default',
+ "global_dark_canvas": False,
+ "global_theme": 'default',
"global_layout": "compact",
"global_hover_shape": False,
@@ -129,8 +130,8 @@ class AppDefaults:
# Project Items colors
"global_proj_item_color_light": '#000000FF',
"global_proj_item_dis_color_light": '#b7b7cbFF',
- "global_proj_item_color_dark": '#4385C8FF',
- "global_proj_item_dis_color_dark": '#61616CFF',
+ "global_proj_item_color_dark": '#F2F2F2FF',
+ "global_proj_item_dis_color_dark": '#a6a6a6ff',
"global_project_autohide": True,
@@ -649,6 +650,7 @@ class AppDefaults:
# SolderPaste Tool
"tools_solderpaste_tools": "1.0, 0.3",
"tools_solderpaste_new": 0.3,
+ "tools_solderpaste_margin": 0.0,
"tools_solderpaste_z_start": 0.05,
"tools_solderpaste_z_dispense": 0.1,
"tools_solderpaste_z_stop": 0.05,
diff --git a/requirements.txt b/requirements.txt
index 37809140..be98b3e6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -43,4 +43,7 @@ vispy>=0.9.0
pyqtdarktheme
gdal
-rasterio
\ No newline at end of file
+rasterio
+
+# To detect OS dark mode
+darkdetect