mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 11:11:49 +02:00
fix(color_button_native): popup logic to choose color moved to ColorButtonNative
This commit is contained in:
@ -22,6 +22,7 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from bec_widgets import SafeSlot
|
||||||
from bec_widgets.utils import ConnectionConfig, EntryValidator
|
from bec_widgets.utils import ConnectionConfig, EntryValidator
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import Colors
|
from bec_widgets.utils.colors import Colors
|
||||||
@ -154,7 +155,7 @@ class CurveRow(QTreeWidgetItem):
|
|||||||
"""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 = ColorButtonNative(color=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.color_changed.connect(self._on_color_changed)
|
||||||
self.tree.setItemWidget(self, 3, self.color_button)
|
self.tree.setItemWidget(self, 3, self.color_button)
|
||||||
|
|
||||||
# Style in col 4
|
# Style in col 4
|
||||||
@ -177,20 +178,16 @@ class CurveRow(QTreeWidgetItem):
|
|||||||
self.symbol_spin.setValue(self.config.symbol_size)
|
self.symbol_spin.setValue(self.config.symbol_size)
|
||||||
self.tree.setItemWidget(self, 6, self.symbol_spin)
|
self.tree.setItemWidget(self, 6, self.symbol_spin)
|
||||||
|
|
||||||
def _select_color(self, button):
|
@SafeSlot(str, verify_sender=True)
|
||||||
|
def _on_color_changed(self, new_color: str):
|
||||||
"""
|
"""
|
||||||
Selects a new color using a color dialog and applies it to the specified button. Updates
|
Update configuration when the color button emits a change.
|
||||||
related configuration properties based on the chosen color.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
button: The button widget whose color is being modified.
|
new_color (str): The new color in hex format.
|
||||||
"""
|
"""
|
||||||
current_color = QColor(button.color())
|
self.config.color = new_color
|
||||||
chosen_color = QColorDialog.getColor(current_color, self.tree, "Select Curve Color")
|
self.config.symbol_color = new_color
|
||||||
if chosen_color.isValid():
|
|
||||||
button.set_color(chosen_color)
|
|
||||||
self.config.color = chosen_color.name()
|
|
||||||
self.config.symbol_color = chosen_color.name()
|
|
||||||
|
|
||||||
def add_dap_row(self):
|
def add_dap_row(self):
|
||||||
"""Create a new DAP row as a child. Only valid if source='device'."""
|
"""Create a new DAP row as a child. Only valid if source='device'."""
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from qtpy.QtCore import Signal
|
||||||
from qtpy.QtGui import QColor
|
from qtpy.QtGui import QColor
|
||||||
from qtpy.QtWidgets import QPushButton
|
from qtpy.QtWidgets import QColorDialog, QPushButton
|
||||||
|
|
||||||
from bec_widgets import BECWidget, SafeProperty, SafeSlot
|
from bec_widgets import BECWidget, SafeProperty, SafeSlot
|
||||||
|
|
||||||
@ -12,6 +15,8 @@ class ColorButtonNative(BECWidget, QPushButton):
|
|||||||
to guarantee good readability.
|
to guarantee good readability.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
color_changed = Signal(str)
|
||||||
|
|
||||||
RPC = False
|
RPC = False
|
||||||
PLUGIN = True
|
PLUGIN = True
|
||||||
ICON_NAME = "colors"
|
ICON_NAME = "colors"
|
||||||
@ -25,9 +30,10 @@ class ColorButtonNative(BECWidget, QPushButton):
|
|||||||
"""
|
"""
|
||||||
super().__init__(parent=parent, **kwargs)
|
super().__init__(parent=parent, **kwargs)
|
||||||
self.set_color(color)
|
self.set_color(color)
|
||||||
|
self.clicked.connect(self._open_color_dialog)
|
||||||
|
|
||||||
@SafeSlot()
|
@SafeSlot()
|
||||||
def set_color(self, color):
|
def set_color(self, color: str | QColor):
|
||||||
"""Set the button's color and update its appearance.
|
"""Set the button's color and update its appearance.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -38,6 +44,7 @@ class ColorButtonNative(BECWidget, QPushButton):
|
|||||||
else:
|
else:
|
||||||
self._color = color
|
self._color = color
|
||||||
self._update_appearance()
|
self._update_appearance()
|
||||||
|
self.color_changed.emit(self._color)
|
||||||
|
|
||||||
@SafeProperty("QColor")
|
@SafeProperty("QColor")
|
||||||
def color(self):
|
def color(self):
|
||||||
@ -56,3 +63,11 @@ class ColorButtonNative(BECWidget, QPushButton):
|
|||||||
text_color = "#000000" if brightness > 0.5 else "#FFFFFF"
|
text_color = "#000000" if brightness > 0.5 else "#FFFFFF"
|
||||||
self.setStyleSheet(f"background-color: {self._color}; color: {text_color};")
|
self.setStyleSheet(f"background-color: {self._color}; color: {text_color};")
|
||||||
self.setText(self._color)
|
self.setText(self._color)
|
||||||
|
|
||||||
|
@SafeSlot()
|
||||||
|
def _open_color_dialog(self):
|
||||||
|
"""Open a QColorDialog and apply the selected color."""
|
||||||
|
current_color = QColor(self._color)
|
||||||
|
chosen_color = QColorDialog.getColor(current_color, self, "Select Curve Color")
|
||||||
|
if chosen_color.isValid():
|
||||||
|
self.set_color(chosen_color)
|
||||||
|
87
tests/unit_tests/test_color_button_native.py
Normal file
87
tests/unit_tests/test_color_button_native.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from qtpy.QtCore import Qt
|
||||||
|
from qtpy.QtGui import QColor
|
||||||
|
from qtpy.QtWidgets import QColorDialog
|
||||||
|
|
||||||
|
from bec_widgets.widgets.utility.visual.color_button_native.color_button_native import (
|
||||||
|
ColorButtonNative,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_button_native(qtbot):
|
||||||
|
cb = create_widget(qtbot, ColorButtonNative)
|
||||||
|
|
||||||
|
# Check if the instance is created successfully
|
||||||
|
assert cb is not None
|
||||||
|
|
||||||
|
# Check if the button has a default color
|
||||||
|
assert cb.color is not None
|
||||||
|
|
||||||
|
# Check if the button can change color
|
||||||
|
new_color = QColor(255, 0, 0) # Red
|
||||||
|
cb.set_color(new_color)
|
||||||
|
assert cb.color == new_color.name()
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_dialog_applies_chosen_color(qtbot, monkeypatch):
|
||||||
|
"""Clicking the button should open the dialog and apply the selected color."""
|
||||||
|
cb = create_widget(qtbot, ColorButtonNative)
|
||||||
|
chosen_color = QColor(0, 255, 0) # Green
|
||||||
|
|
||||||
|
# Force QColorDialog.getColor to return our chosen color
|
||||||
|
monkeypatch.setattr(QColorDialog, "getColor", lambda *args, **kwargs: chosen_color)
|
||||||
|
|
||||||
|
# Expect the color_changed signal during the click
|
||||||
|
with qtbot.waitSignal(cb.color_changed, timeout=1000):
|
||||||
|
qtbot.mouseClick(cb, Qt.LeftButton)
|
||||||
|
|
||||||
|
assert cb.color == chosen_color.name()
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_dialog_cancel_keeps_color(qtbot, monkeypatch):
|
||||||
|
"""If the dialog returns an invalid color, the button color should stay the same."""
|
||||||
|
cb = create_widget(qtbot, ColorButtonNative)
|
||||||
|
original_color = cb.color
|
||||||
|
|
||||||
|
# Simulate cancel: return an invalid QColor
|
||||||
|
monkeypatch.setattr(QColorDialog, "getColor", lambda *args, **kwargs: QColor())
|
||||||
|
|
||||||
|
qtbot.mouseClick(cb, Qt.LeftButton)
|
||||||
|
|
||||||
|
# No signal emitted, color unchanged
|
||||||
|
assert cb.color == original_color
|
||||||
|
|
||||||
|
|
||||||
|
# Additional tests for color property getter/setter
|
||||||
|
def test_color_property_getter_setter_hex(qtbot):
|
||||||
|
"""Verify the color property works correctly with hex strings."""
|
||||||
|
cb = create_widget(qtbot, ColorButtonNative)
|
||||||
|
|
||||||
|
# Confirm default value is a valid hex string
|
||||||
|
default_color = cb.color
|
||||||
|
assert (
|
||||||
|
isinstance(default_color, str) and default_color.startswith("#") and len(default_color) == 7
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use property setter with a new hex color
|
||||||
|
new_color_hex = "#123456"
|
||||||
|
with qtbot.waitSignal(cb.color_changed, timeout=1000):
|
||||||
|
cb.color = new_color_hex
|
||||||
|
|
||||||
|
# Getter should reflect the new value
|
||||||
|
assert cb.color == new_color_hex
|
||||||
|
# Button text should update as well
|
||||||
|
assert cb.text() == new_color_hex
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_property_setter_qcolor(qtbot):
|
||||||
|
"""Verify the color property accepts QColor and emits the signal."""
|
||||||
|
cb = create_widget(qtbot, ColorButtonNative)
|
||||||
|
q_color = QColor(200, 100, 50)
|
||||||
|
|
||||||
|
with qtbot.waitSignal(cb.color_changed, timeout=1000):
|
||||||
|
cb.color = q_color
|
||||||
|
|
||||||
|
assert cb.color == q_color.name()
|
||||||
|
assert cb.text() == q_color.name()
|
Reference in New Issue
Block a user