diff --git a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py index 90e3f944..f5291673 100644 --- a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +++ b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py @@ -31,6 +31,9 @@ from bec_widgets.widgets.control.device_input.device_line_edit.device_line_edit ) from bec_widgets.widgets.dap.dap_combo_box.dap_combo_box import DapComboBox from bec_widgets.widgets.plots.waveform.curve import CurveConfig, DeviceSignal +from bec_widgets.widgets.utility.visual.color_button_native.color_button_native import ( + ColorButtonNative, +) from bec_widgets.widgets.utility.visual.colormap_widget.colormap_widget import BECColorMapWidget if TYPE_CHECKING: # pragma: no cover @@ -40,49 +43,6 @@ if TYPE_CHECKING: # pragma: no cover logger = bec_logger.logger -class ColorButton(QPushButton): - """A QPushButton subclass that displays a color. - - The background is set to the given color and the button text is the hex code. - The text color is chosen automatically (black if the background is light, white if dark) - to guarantee good readability. - """ - - def __init__(self, color="#000000", parent=None): - """Initialize the color button. - - Args: - color (str): The initial color in hex format (e.g., '#000000'). - parent: Optional QWidget parent. - """ - super().__init__(parent) - self.set_color(color) - - def set_color(self, color): - """Set the button's color and update its appearance. - - Args: - color (str or QColor): The new color to assign. - """ - if isinstance(color, QColor): - self._color = color.name() - else: - self._color = color - self._update_appearance() - - def color(self): - """Return the current color in hex.""" - return self._color - - def _update_appearance(self): - """Update the button style based on the background color's brightness.""" - c = QColor(self._color) - brightness = c.lightnessF() - text_color = "#000000" if brightness > 0.5 else "#FFFFFF" - self.setStyleSheet(f"background-color: {self._color}; color: {text_color};") - self.setText(self._color) - - class CurveRow(QTreeWidgetItem): DELETE_BUTTON_COLOR = "#CC181E" """A unified row that can represent either a device or a DAP curve. @@ -193,7 +153,7 @@ class CurveRow(QTreeWidgetItem): def _init_style_controls(self): """Create columns 3..6: color button, style combo, width spin, symbol spin.""" # Color in col 3 - self.color_button = ColorButton(self.config.color) + self.color_button = ColorButtonNative(color=self.config.color) self.color_button.clicked.connect(lambda: self._select_color(self.color_button)) self.tree.setItemWidget(self, 3, self.color_button) @@ -284,6 +244,11 @@ class CurveRow(QTreeWidgetItem): self.dap_combo.deleteLater() self.dap_combo = None + if getattr(self, "color_button", None) is not None: + self.color_button.close() + self.color_button.deleteLater() + self.color_button = None + # Remove the item from the tree widget index = self.tree.indexOfTopLevelItem(self) if index != -1: @@ -337,8 +302,8 @@ class CurveRow(QTreeWidgetItem): self.config.label = f"{parent_conf.label}-{new_dap}" # Common style fields - self.config.color = self.color_button.color() - self.config.symbol_color = self.color_button.color() + self.config.color = self.color_button.color + self.config.symbol_color = self.color_button.color self.config.pen_style = self.style_combo.currentText() self.config.pen_width = self.width_spin.value() self.config.symbol_size = self.symbol_spin.value() diff --git a/bec_widgets/widgets/utility/visual/color_button_native/__init__.py b/bec_widgets/widgets/utility/visual/color_button_native/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.py b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.py new file mode 100644 index 00000000..b79cf4ec --- /dev/null +++ b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.py @@ -0,0 +1,58 @@ +from qtpy.QtGui import QColor +from qtpy.QtWidgets import QPushButton + +from bec_widgets import BECWidget, SafeProperty, SafeSlot + + +class ColorButtonNative(BECWidget, QPushButton): + """A QPushButton subclass that displays a color. + + The background is set to the given color and the button text is the hex code. + The text color is chosen automatically (black if the background is light, white if dark) + to guarantee good readability. + """ + + RPC = False + PLUGIN = True + ICON_NAME = "colors" + + def __init__(self, parent=None, color="#000000", **kwargs): + """Initialize the color button. + + Args: + parent: Optional QWidget parent. + color (str): The initial color in hex format (e.g., '#000000'). + """ + super().__init__(parent=parent, **kwargs) + self.set_color(color) + + @SafeSlot() + def set_color(self, color): + """Set the button's color and update its appearance. + + Args: + color (str or QColor): The new color to assign. + """ + if isinstance(color, QColor): + self._color = color.name() + else: + self._color = color + self._update_appearance() + + @SafeProperty("QColor") + def color(self): + """Return the current color in hex.""" + return self._color + + @color.setter + def color(self, value): + """Set the button's color and update its appearance.""" + self.set_color(value) + + def _update_appearance(self): + """Update the button style based on the background color's brightness.""" + c = QColor(self._color) + brightness = c.lightnessF() + text_color = "#000000" if brightness > 0.5 else "#FFFFFF" + self.setStyleSheet(f"background-color: {self._color}; color: {text_color};") + self.setText(self._color) diff --git a/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.pyproject b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.pyproject new file mode 100644 index 00000000..7d36ffb6 --- /dev/null +++ b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native.pyproject @@ -0,0 +1 @@ +{'files': ['color_button_native.py']} \ No newline at end of file diff --git a/bec_widgets/widgets/utility/visual/color_button_native/color_button_native_plugin.py b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native_plugin.py new file mode 100644 index 00000000..d6290bd3 --- /dev/null +++ b/bec_widgets/widgets/utility/visual/color_button_native/color_button_native_plugin.py @@ -0,0 +1,56 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from qtpy.QtDesigner import QDesignerCustomWidgetInterface + +from bec_widgets.utils.bec_designer import designer_material_icon +from bec_widgets.widgets.utility.visual.color_button_native.color_button_native import ( + ColorButtonNative, +) + +DOM_XML = """ + + + + +""" + + +class ColorButtonNativePlugin(QDesignerCustomWidgetInterface): # pragma: no cover + def __init__(self): + super().__init__() + self._form_editor = None + + def createWidget(self, parent): + t = ColorButtonNative(parent) + return t + + def domXml(self): + return DOM_XML + + def group(self): + return "BEC Buttons" + + def icon(self): + return designer_material_icon(ColorButtonNative.ICON_NAME) + + def includeFile(self): + return "color_button_native" + + def initialize(self, form_editor): + self._form_editor = form_editor + + def isContainer(self): + return False + + def isInitialized(self): + return self._form_editor is not None + + def name(self): + return "ColorButtonNative" + + def toolTip(self): + return "A QPushButton subclass that displays a color." + + def whatsThis(self): + return self.toolTip() diff --git a/bec_widgets/widgets/utility/visual/color_button_native/register_color_button_native.py b/bec_widgets/widgets/utility/visual/color_button_native/register_color_button_native.py new file mode 100644 index 00000000..499318c6 --- /dev/null +++ b/bec_widgets/widgets/utility/visual/color_button_native/register_color_button_native.py @@ -0,0 +1,17 @@ +def main(): # pragma: no cover + from qtpy import PYSIDE6 + + if not PYSIDE6: + print("PYSIDE6 is not available in the environment. Cannot patch designer.") + return + from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection + + from bec_widgets.widgets.utility.visual.color_button_native.color_button_native_plugin import ( + ColorButtonNativePlugin, + ) + + QPyDesignerCustomWidgetCollection.addCustomWidget(ColorButtonNativePlugin()) + + +if __name__ == "__main__": # pragma: no cover + main()