mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix(colors): pyqtgraph styling updated on the app level
This commit is contained in:
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user