0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

fix(colors): pyqtgraph styling updated on the app level

This commit is contained in:
2025-02-12 21:45:09 +01:00
committed by wyzula_j
parent 97c0ed53df
commit ae18279685
5 changed files with 125 additions and 18 deletions

View File

@ -66,7 +66,7 @@ class BECWidget(BECConnector):
if hasattr(qapp, "theme_signal"): if hasattr(qapp, "theme_signal"):
qapp.theme_signal.theme_updated.connect(self._update_theme) qapp.theme_signal.theme_updated.connect(self._update_theme)
def _update_theme(self, theme: str): def _update_theme(self, theme: str | None = None):
"""Update the theme.""" """Update the theme."""
if theme is None: if theme is None:
qapp = QApplication.instance() qapp = QApplication.instance()

View File

@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
import itertools
import re import re
from typing import TYPE_CHECKING, Literal from typing import TYPE_CHECKING, Literal
@ -71,15 +70,64 @@ def apply_theme(theme: Literal["dark", "light"]):
Apply the theme to all pyqtgraph widgets. Do not use this function directly. Use set_theme instead. Apply the theme to all pyqtgraph widgets. Do not use this function directly. Use set_theme instead.
""" """
app = QApplication.instance() app = QApplication.instance()
# go through all pyqtgraph widgets and set background graphic_layouts = [
children = itertools.chain.from_iterable( child
top.findChildren(pg.GraphicsLayoutWidget) for top in app.topLevelWidgets() for top in app.topLevelWidgets()
) for child in top.findChildren(pg.GraphicsLayoutWidget)
pg.setConfigOptions( ]
foreground="d" if theme == "dark" else "k", background="k" if theme == "dark" else "w"
) plot_items = [
for pg_widget in children: item
pg_widget.setBackground("k" if theme == "dark" else "w") for gl in graphic_layouts
for item in gl.ci.items.keys() # ci is internal pg.GraphicsLayout that hosts all items
if isinstance(item, pg.PlotItem)
]
histograms = [
item
for gl in graphic_layouts
for item in gl.ci.items.keys() # ci is internal pg.GraphicsLayout that hosts all items
if isinstance(item, pg.HistogramLUTItem)
]
# Update background color based on the theme
if theme == "light":
background_color = "#e9ecef" # Subtle contrast for light mode
foreground_color = "#141414"
label_color = "#000000"
axis_color = "#666666"
else:
background_color = "#141414" # Dark mode
foreground_color = "#e9ecef"
label_color = "#FFFFFF"
axis_color = "#CCCCCC"
# update GraphicsLayoutWidget
pg.setConfigOptions(foreground=foreground_color, background=background_color)
for pg_widget in graphic_layouts:
pg_widget.setBackground(background_color)
# update PlotItems
for plot_item in plot_items:
for axis in ["left", "right", "top", "bottom"]:
plot_item.getAxis(axis).setPen(pg.mkPen(color=axis_color))
plot_item.getAxis(axis).setTextPen(pg.mkPen(color=label_color))
# Change title color
plot_item.titleLabel.setText(plot_item.titleLabel.text, color=label_color)
# Change legend color
if hasattr(plot_item, "legend") and plot_item.legend is not None:
plot_item.legend.setLabelTextColor(label_color)
# if legend is in plot item and theme is changed, has to be like that because of pg opt logic
for sample, label in plot_item.legend.items:
label_text = label.text
label.setText(label_text, color=label_color)
# update HistogramLUTItem
for histogram in histograms:
histogram.axis.setPen(pg.mkPen(color=axis_color))
histogram.axis.setTextPen(pg.mkPen(color=label_color))
# now define stylesheet according to theme and apply it # now define stylesheet according to theme and apply it
style = bec_qthemes.load_stylesheet(theme) style = bec_qthemes.load_stylesheet(theme)

View File

@ -1,9 +1,15 @@
import pyqtgraph as pg
import pytest import pytest
from pydantic import ValidationError from pydantic import ValidationError
from qtpy.QtGui import QColor from qtpy.QtGui import QColor
from qtpy.QtWidgets import QVBoxLayout, QWidget
from bec_widgets.utils import Colors from bec_widgets.utils import Colors, ConnectionConfig
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.colors import apply_theme
from bec_widgets.widgets.containers.figure.plots.waveform.waveform_curve import CurveConfig from bec_widgets.widgets.containers.figure.plots.waveform.waveform_curve import CurveConfig
from tests.unit_tests.client_mocks import mocked_client
from tests.unit_tests.conftest import create_widget
def test_color_validation_CSS(): def test_color_validation_CSS():
@ -110,3 +116,55 @@ def test_golder_angle_colors(num):
assert all(color.isValid() for color in colors_qcolor) assert all(color.isValid() for color in colors_qcolor)
assert all(color.startswith("#") for color in colors_hex) assert all(color.startswith("#") for color in colors_hex)
##################################################
# Testing of the ExamplePlotWidget theme change
##################################################
class ExamplePlotWidget(BECWidget, QWidget):
def __init__(
self,
parent: QWidget | None = None,
config: ConnectionConfig | None = None,
client=None,
gui_id: str | None = None,
) -> None:
if config is None:
config = ConnectionConfig(widget_class=self.__class__.__name__)
super().__init__(client=client, gui_id=gui_id, config=config)
QWidget.__init__(self, parent=parent)
self.layout = QVBoxLayout(self)
self.glw = pg.GraphicsLayoutWidget()
self.pi = pg.PlotItem()
self.layout.addWidget(self.glw)
self.glw.addItem(self.pi)
self.pi.plot([1, 2, 3, 4, 5], pen="r")
def test_apply_theme(qtbot, mocked_client):
widget = create_widget(qtbot, ExamplePlotWidget, client=mocked_client)
apply_theme("dark")
# Get the default state of dark theme
dark_bg = widget.glw.backgroundBrush().color().name()
dark_axis_color = widget.pi.getAxis("left").pen().color().name()
dark_label_color = widget.pi.getAxis("left").textPen().color().name()
assert dark_bg == "#141414"
assert dark_axis_color == "#cccccc"
assert dark_label_color == "#ffffff"
apply_theme("light")
# Get the default state of light theme
light_bg = widget.glw.backgroundBrush().color().name()
light_axis_color = widget.pi.getAxis("left").pen().color().name()
light_label_color = widget.pi.getAxis("left").textPen().color().name()
assert light_bg == "#e9ecef"
assert light_axis_color == "#666666"
assert light_label_color == "#000000"

View File

@ -271,7 +271,8 @@ def test_multi_waveform_widget_theme_update(qtbot, multi_waveform_widget):
palette = get_theme_palette() palette = get_theme_palette()
waveform_color_dark = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color_dark = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = multi_waveform_widget.fig.backgroundBrush().color() bg_color = multi_waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("black")
assert bg_color == QColor(20, 20, 20)
assert waveform_color_dark == palette.text().color() assert waveform_color_dark == palette.text().color()
# Set the theme to light # Set the theme to light
@ -279,7 +280,7 @@ def test_multi_waveform_widget_theme_update(qtbot, multi_waveform_widget):
palette = get_theme_palette() palette = get_theme_palette()
waveform_color_light = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color_light = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = multi_waveform_widget.fig.backgroundBrush().color() bg_color = multi_waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("white") assert bg_color == QColor(233, 236, 239)
assert waveform_color_light == palette.text().color() assert waveform_color_light == palette.text().color()
assert waveform_color_dark != waveform_color_light assert waveform_color_dark != waveform_color_light
@ -291,5 +292,5 @@ def test_multi_waveform_widget_theme_update(qtbot, multi_waveform_widget):
waveform_color = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color = multi_waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = multi_waveform_widget.fig.backgroundBrush().color() bg_color = multi_waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("black") assert bg_color == QColor(20, 20, 20)
assert waveform_color == waveform_color_dark assert waveform_color == waveform_color_dark

View File

@ -484,7 +484,7 @@ def test_waveform_widget_theme_update(qtbot, waveform_widget):
palette = get_theme_palette() palette = get_theme_palette()
waveform_color_dark = waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color_dark = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = waveform_widget.fig.backgroundBrush().color() bg_color = waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("black") assert bg_color == QColor(20, 20, 20)
assert waveform_color_dark == palette.text().color() assert waveform_color_dark == palette.text().color()
# Set the theme to light; equivalent to clicking the light mode button # Set the theme to light; equivalent to clicking the light mode button
@ -493,7 +493,7 @@ def test_waveform_widget_theme_update(qtbot, waveform_widget):
palette = get_theme_palette() palette = get_theme_palette()
waveform_color_light = waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color_light = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = waveform_widget.fig.backgroundBrush().color() bg_color = waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("white") assert bg_color == QColor(233, 236, 239)
assert waveform_color_light == palette.text().color() assert waveform_color_light == palette.text().color()
assert waveform_color_dark != waveform_color_light assert waveform_color_dark != waveform_color_light
@ -509,7 +509,7 @@ def test_waveform_widget_theme_update(qtbot, waveform_widget):
# we compare the waveform color to the dark theme color # we compare the waveform color to the dark theme color
waveform_color = waveform_widget.waveform.plot_item.getAxis("left").pen().color() waveform_color = waveform_widget.waveform.plot_item.getAxis("left").pen().color()
bg_color = waveform_widget.fig.backgroundBrush().color() bg_color = waveform_widget.fig.backgroundBrush().color()
assert bg_color == QColor("black") assert bg_color == QColor(20, 20, 20)
assert waveform_color == waveform_color_dark assert waveform_color == waveform_color_dark