mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
refactor(color_button_native): color button with OS native dialog separated from the curve tree
This commit is contained in:
@ -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.dap.dap_combo_box.dap_combo_box import DapComboBox
|
||||||
from bec_widgets.widgets.plots.waveform.curve import CurveConfig, DeviceSignal
|
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
|
from bec_widgets.widgets.utility.visual.colormap_widget.colormap_widget import BECColorMapWidget
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
@ -40,49 +43,6 @@ if TYPE_CHECKING: # pragma: no cover
|
|||||||
logger = bec_logger.logger
|
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):
|
class CurveRow(QTreeWidgetItem):
|
||||||
DELETE_BUTTON_COLOR = "#CC181E"
|
DELETE_BUTTON_COLOR = "#CC181E"
|
||||||
"""A unified row that can represent either a device or a DAP curve.
|
"""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):
|
def _init_style_controls(self):
|
||||||
"""Create columns 3..6: color button, style combo, width spin, symbol spin."""
|
"""Create columns 3..6: color button, style combo, width spin, symbol spin."""
|
||||||
# Color in col 3
|
# 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.color_button.clicked.connect(lambda: self._select_color(self.color_button))
|
||||||
self.tree.setItemWidget(self, 3, 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.deleteLater()
|
||||||
self.dap_combo = None
|
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
|
# Remove the item from the tree widget
|
||||||
index = self.tree.indexOfTopLevelItem(self)
|
index = self.tree.indexOfTopLevelItem(self)
|
||||||
if index != -1:
|
if index != -1:
|
||||||
@ -337,8 +302,8 @@ class CurveRow(QTreeWidgetItem):
|
|||||||
self.config.label = f"{parent_conf.label}-{new_dap}"
|
self.config.label = f"{parent_conf.label}-{new_dap}"
|
||||||
|
|
||||||
# Common style fields
|
# Common style fields
|
||||||
self.config.color = self.color_button.color()
|
self.config.color = self.color_button.color
|
||||||
self.config.symbol_color = self.color_button.color()
|
self.config.symbol_color = self.color_button.color
|
||||||
self.config.pen_style = self.style_combo.currentText()
|
self.config.pen_style = self.style_combo.currentText()
|
||||||
self.config.pen_width = self.width_spin.value()
|
self.config.pen_width = self.width_spin.value()
|
||||||
self.config.symbol_size = self.symbol_spin.value()
|
self.config.symbol_size = self.symbol_spin.value()
|
||||||
|
@ -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)
|
@ -0,0 +1 @@
|
|||||||
|
{'files': ['color_button_native.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 = """
|
||||||
|
<ui language='c++'>
|
||||||
|
<widget class='ColorButtonNative' name='color_button_native'>
|
||||||
|
</widget>
|
||||||
|
</ui>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
@ -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()
|
Reference in New Issue
Block a user