mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-07-24 12:12:59 +02:00
feat(ring_progress_bar): add set_progress_state for one-call ring + label updates
This commit is contained in:
@@ -5285,6 +5285,35 @@ class RingProgressBar(RPCBase):
|
||||
text(str): Text for the center label.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def set_progress_state(
|
||||
self,
|
||||
values: list[float | None] | dict[int, float | None] | None = None,
|
||||
center_label: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Update several rings and the center label in a single call.
|
||||
|
||||
Updating each ring value and the center label individually is one RPC
|
||||
round-trip per call; over a long-running scan that is a steady stream of
|
||||
round-trips, and each one also triggers a server-side registry
|
||||
broadcast. ``set_progress_state`` applies all of them within a single
|
||||
method call, i.e. one RPC round-trip and one broadcast.
|
||||
|
||||
Args:
|
||||
values: Ring values to apply. Either a list aligned to ring index,
|
||||
where ``None`` leaves that ring unchanged (e.g.
|
||||
``[12.0, None, 80.0]`` updates rings 0 and 2), or a
|
||||
``{index: value}`` mapping to update only specific rings.
|
||||
``None`` leaves all ring values unchanged.
|
||||
center_label: New center-label text, or ``None`` to leave the
|
||||
current text unchanged.
|
||||
**kwargs: Ignored. Absorbs RPC-layer pass-through keyword arguments
|
||||
(e.g. ``_rpc_wait_for_response``) so the call does not fail when
|
||||
extra control kwargs are supplied by the client.
|
||||
"""
|
||||
|
||||
|
||||
class SBBMonitor(RPCBase):
|
||||
"""A widget to display the SBB monitor website."""
|
||||
|
||||
@@ -393,6 +393,7 @@ class RingProgressBar(BECWidget, QWidget):
|
||||
"remove_ring",
|
||||
"set_gap",
|
||||
"set_center_label",
|
||||
"set_progress_state",
|
||||
]
|
||||
|
||||
def __init__(self, parent: QWidget | None = None, client=None, **kwargs):
|
||||
@@ -511,6 +512,44 @@ class RingProgressBar(BECWidget, QWidget):
|
||||
"""
|
||||
self.center_label = text
|
||||
|
||||
def set_progress_state(
|
||||
self,
|
||||
values: list[float | None] | dict[int, float | None] | None = None,
|
||||
center_label: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Update several rings and the center label in a single call.
|
||||
|
||||
Updating each ring value and the center label individually is one RPC
|
||||
round-trip per call; over a long-running scan that is a steady stream of
|
||||
round-trips, and each one also triggers a server-side registry
|
||||
broadcast. ``set_progress_state`` applies all of them within a single
|
||||
method call, i.e. one RPC round-trip and one broadcast.
|
||||
|
||||
Args:
|
||||
values: Ring values to apply. Either a list aligned to ring index,
|
||||
where ``None`` leaves that ring unchanged (e.g.
|
||||
``[12.0, None, 80.0]`` updates rings 0 and 2), or a
|
||||
``{index: value}`` mapping to update only specific rings.
|
||||
``None`` leaves all ring values unchanged.
|
||||
center_label: New center-label text, or ``None`` to leave the
|
||||
current text unchanged.
|
||||
**kwargs: Ignored. Absorbs RPC-layer pass-through keyword arguments
|
||||
(e.g. ``_rpc_wait_for_response``) so the call does not fail when
|
||||
extra control kwargs are supplied by the client.
|
||||
"""
|
||||
rings = self.rings
|
||||
if isinstance(values, dict):
|
||||
for index, value in values.items():
|
||||
if value is not None and 0 <= int(index) < len(rings):
|
||||
rings[int(index)].set_value(value)
|
||||
elif values is not None:
|
||||
for ring, value in zip(rings, values):
|
||||
if value is not None:
|
||||
ring.set_value(value)
|
||||
if center_label is not None:
|
||||
self.center_label = center_label
|
||||
|
||||
@property
|
||||
def rings(self) -> list[Ring]:
|
||||
return self.ring_progress_bar.rings
|
||||
|
||||
@@ -741,3 +741,62 @@ def test_leave_event_clears_hover_and_hides_tooltip(qtbot, container):
|
||||
assert ring._hovered is False
|
||||
assert container._last_hover_global_pos is None
|
||||
container._hover_tooltip.hide.assert_called()
|
||||
|
||||
|
||||
def _ensure_three_rings(ring_progress_bar):
|
||||
while len(ring_progress_bar.rings) < 3:
|
||||
ring_progress_bar.add_ring()
|
||||
rings = ring_progress_bar.rings
|
||||
for ring in rings:
|
||||
ring.set_value(1.0) # sentinel so "unchanged" assertions are meaningful
|
||||
return rings
|
||||
|
||||
|
||||
def test_set_progress_state_in_user_access():
|
||||
assert "set_progress_state" in RingProgressBar.USER_ACCESS
|
||||
|
||||
|
||||
def test_set_progress_state_list_updates_selected_rings_and_label(ring_progress_bar):
|
||||
rings = _ensure_three_rings(ring_progress_bar)
|
||||
ring_progress_bar.set_progress_state([12.0, None, 80.0], center_label="batched")
|
||||
assert rings[0].config.value == 12.0 # updated
|
||||
assert rings[1].config.value == 1.0 # None -> unchanged
|
||||
assert rings[2].config.value == 80.0 # updated
|
||||
assert ring_progress_bar.center_label == "batched"
|
||||
|
||||
|
||||
def test_set_progress_state_accepts_index_mapping(ring_progress_bar):
|
||||
rings = _ensure_three_rings(ring_progress_bar)
|
||||
ring_progress_bar.set_progress_state({0: 5.0, 2: 95.0})
|
||||
assert rings[0].config.value == 5.0
|
||||
assert rings[1].config.value == 1.0 # untouched index
|
||||
assert rings[2].config.value == 95.0
|
||||
|
||||
|
||||
def test_set_progress_state_label_only_leaves_rings_untouched(ring_progress_bar):
|
||||
rings = _ensure_three_rings(ring_progress_bar)
|
||||
ring_progress_bar.set_progress_state(center_label="only label")
|
||||
assert [r.config.value for r in rings] == [1.0, 1.0, 1.0]
|
||||
assert ring_progress_bar.center_label == "only label"
|
||||
|
||||
|
||||
def test_set_progress_state_ignores_rpc_passthrough_kwargs(ring_progress_bar):
|
||||
_ensure_three_rings(ring_progress_bar)
|
||||
# the client may pass control kwargs (e.g. _rpc_wait_for_response); must not raise
|
||||
ring_progress_bar.set_progress_state([3.0], center_label="kw", _rpc_wait_for_response=False)
|
||||
assert ring_progress_bar.rings[0].config.value == 3.0
|
||||
assert ring_progress_bar.center_label == "kw"
|
||||
|
||||
|
||||
def test_set_progress_state_no_rings_is_noop(ring_progress_bar):
|
||||
# a freshly created RingProgressBar has no rings; must not raise
|
||||
assert ring_progress_bar.rings == []
|
||||
ring_progress_bar.set_progress_state([1.0, 2.0], center_label="safe")
|
||||
assert ring_progress_bar.center_label == "safe"
|
||||
|
||||
|
||||
def test_set_progress_state_clamps_and_ignores_out_of_range_index(ring_progress_bar):
|
||||
rings = _ensure_three_rings(ring_progress_bar)
|
||||
# value above max clamps to 100; out-of-range index is ignored, not an error
|
||||
ring_progress_bar.set_progress_state({0: 150.0, 99: 42.0})
|
||||
assert rings[0].config.value == 100.0
|
||||
|
||||
Reference in New Issue
Block a user