Skip to content

Commit fa95aa1

Browse files
committed
fix(positioner_box): remove CompactPopupWidget inheritance
1 parent e7ef8a3 commit fa95aa1

9 files changed

Lines changed: 137 additions & 55 deletions

File tree

bec_widgets/widgets/control/device_control/positioner_box/_base/__init__.py

Lines changed: 0 additions & 3 deletions
This file was deleted.

bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from bec_widgets.utils import UILoader
1515
from bec_widgets.utils.colors import apply_theme, get_accent_colors
1616
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
17-
from bec_widgets.widgets.control.device_control.positioner_box._base import PositionerBoxBase
18-
from bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base import (
17+
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
1918
DeviceUpdateUIComponents,
19+
PositionerBoxBase,
2020
)
2121

2222
logger = bec_logger.logger
@@ -63,10 +63,10 @@ def init_ui(self):
6363

6464
self.ui = UILoader(self).loader(os.path.join(self.current_path, self.ui_file))
6565

66-
self.addWidget(self.ui)
67-
self.layout.setSpacing(0)
68-
self.layout.setContentsMargins(0, 0, 0, 0)
69-
self.layout.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter)
66+
self.main_layout.addWidget(self.ui)
67+
self.main_layout.setSpacing(0)
68+
self.main_layout.setContentsMargins(0, 0, 0, 0)
69+
self.main_layout.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter)
7070
ui_min_size = self.ui.minimumSize()
7171
ui_min_hint = self.ui.minimumSizeHint()
7272
self.setMinimumSize(
@@ -115,8 +115,6 @@ def device(self, value: str):
115115
return
116116
old_device = self._device
117117
self._device = value
118-
if not self.label:
119-
self.label = value
120118
self.device_changed.emit(old_device, value)
121119

122120
@SafeProperty(bool)

bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
from bec_widgets.utils import UILoader
1616
from bec_widgets.utils.colors import apply_theme
1717
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
18-
from bec_widgets.widgets.control.device_control.positioner_box._base import PositionerBoxBase
19-
from bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base import (
18+
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
2019
DeviceUpdateUIComponents,
20+
PositionerBoxBase,
2121
)
2222

2323
logger = bec_logger.logger
@@ -96,9 +96,9 @@ def init_ui(self):
9696

9797
def connect_ui(self):
9898
"""Connect the UI components to signals, data, or routines"""
99-
self.addWidget(self.ui)
100-
self.layout.setSpacing(0)
101-
self.layout.setContentsMargins(0, 0, 0, 0)
99+
self.main_layout.addWidget(self.ui)
100+
self.main_layout.setSpacing(0)
101+
self.main_layout.setContentsMargins(0, 0, 0, 0)
102102

103103
def _init_ui(val: QDoubleValidator, device_id: DeviceId):
104104
ui = self._device_ui_components_hv(device_id)
@@ -200,7 +200,6 @@ def device_hor(self, value: str):
200200
return
201201
old_device = self._device_hor
202202
self._device_hor = value
203-
self.label = f"{self._device_hor}, {self._device_ver}"
204203
self.device_changed_hor.emit(old_device, value)
205204
self._init_device(self.device_hor, self.position_update_hor.emit, self.update_limits_hor)
206205

@@ -220,7 +219,6 @@ def device_ver(self, value: str):
220219
return
221220
old_device = self._device_ver
222221
self._device_ver = value
223-
self.label = f"{self._device_hor}, {self._device_ver}"
224222
self.device_changed_ver.emit(old_device, value)
225223
self._init_device(self.device_ver, self.position_update_ver.emit, self.update_limits_ver)
226224

bec_widgets/widgets/control/device_control/positioner_box/_base/positioner_box_base.py renamed to bec_widgets/widgets/control/device_control/positioner_box/positioner_box_base.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
QLineEdit,
1515
QPushButton,
1616
QVBoxLayout,
17+
QWidget,
1718
)
1819

1920
from bec_widgets.utils.bec_widget import BECWidget
20-
from bec_widgets.utils.compact_popup import CompactPopupWidget
2121
from bec_widgets.widgets.control.device_control.position_indicator.position_indicator import (
2222
PositionIndicator,
2323
)
@@ -43,7 +43,7 @@ class DeviceUpdateUIComponents(TypedDict):
4343
units: QLabel
4444

4545

46-
class PositionerBoxBase(BECWidget, CompactPopupWidget):
46+
class PositionerBoxBase(BECWidget, QWidget):
4747
"""Contains some core logic for positioner box widgets"""
4848

4949
current_path = ""
@@ -57,7 +57,10 @@ def __init__(self, parent=None, **kwargs):
5757
parent: The parent widget.
5858
device (Positioner): The device to control.
5959
"""
60-
super().__init__(parent=parent, layout=QVBoxLayout, **kwargs)
60+
super().__init__(parent=parent, **kwargs)
61+
self.main_layout = QVBoxLayout(self)
62+
self.main_layout.setContentsMargins(0, 0, 0, 0)
63+
self.main_layout.setSpacing(0)
6164
self._dialog = None
6265
self.get_bec_shortcuts()
6366

@@ -173,11 +176,9 @@ def _on_device_readback(
173176
if is_moving:
174177
spinner.start()
175178
spinner.setToolTip("Device is moving")
176-
self.set_global_state("warning")
177179
else:
178180
spinner.stop()
179181
spinner.setToolTip("Device is idle")
180-
self.set_global_state("success")
181182
else:
182183
spinner.setVisible(False)
183184

@@ -196,9 +197,8 @@ def _on_device_readback(
196197
pos = (readback_val - limits[0]) / (limits[1] - limits[0])
197198
position_indicator.set_value(pos)
198199

199-
def _update_limits_ui(
200-
self, limits: tuple[float, float], position_indicator, setpoint_validator
201-
):
200+
@staticmethod
201+
def _update_limits_ui(limits: tuple[float, float], position_indicator, setpoint_validator):
202202
if limits is not None and limits[0] != limits[1]:
203203
position_indicator.setToolTip(f"Min: {limits[0]}, Max: {limits[1]}")
204204
setpoint_validator.setRange(limits[0], limits[1])
@@ -223,8 +223,9 @@ def _swap_readback_signal_connection(self, slot, old_device, new_device):
223223
self.bec_dispatcher.disconnect_slot(slot, MessageEndpoints.device_readback(old_device))
224224
self.bec_dispatcher.connect_slot(slot, MessageEndpoints.device_readback(new_device))
225225

226-
def _toggle_enable_buttons(self, ui: DeviceUpdateUIComponents, enable: bool) -> None:
227-
"""Toogle enable/disable on available buttons
226+
@staticmethod
227+
def _toggle_enable_buttons(ui: DeviceUpdateUIComponents, enable: bool) -> None:
228+
"""Toggle enable/disable on available buttons
228229
229230
Args:
230231
enable (bool): Enable buttons

bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22

33
from bec_lib.device import Positioner
4+
from qtpy.QtCore import Qt
5+
from qtpy.QtWidgets import QSizePolicy
46

57
from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox
68

@@ -22,7 +24,82 @@ def __init__(self, parent=None, device: Positioner | str | None = None, *args, *
2224
device (Positioner): The device to control.
2325
"""
2426
self.current_path = os.path.dirname(__file__)
27+
self._indicator_switch_width = 0
28+
self._horizontal_indicator_width = 0
29+
self._vertical_indicator_width = 15
30+
self._indicator_thickness = 10
31+
self._indicator_is_horizontal = False
32+
self._line_height = self.dimensions[0]
2533
super().__init__(parent=parent, device=device, *args, **kwargs)
34+
self._configure_line_layout()
35+
self._update_indicator_orientation()
36+
37+
def _configure_line_layout(self):
38+
device_box = self.ui.device_box
39+
indicator = self.ui.position_indicator
40+
41+
self.main_layout.setAlignment(Qt.AlignmentFlag(0))
42+
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
43+
self.ui.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
44+
device_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
45+
46+
self._line_height = max(
47+
self.dimensions[0],
48+
self.ui.minimumSizeHint().height(),
49+
self.ui.sizeHint().height(),
50+
device_box.minimumSizeHint().height(),
51+
device_box.sizeHint().height(),
52+
)
53+
device_box.setFixedHeight(self._line_height)
54+
device_box.setMinimumWidth(self.dimensions[1])
55+
device_box.setMaximumWidth(16777215)
56+
self.setFixedHeight(self._line_height)
57+
self.setMinimumWidth(self.dimensions[1])
58+
59+
self.ui.verticalLayout.setContentsMargins(0, 0, 0, 0)
60+
self.ui.verticalLayout.setSpacing(0)
61+
self.ui.readback.setMaximumWidth(16777215)
62+
self.ui.setpoint.setMaximumWidth(16777215)
63+
self.ui.step_size.setMaximumWidth(16777215)
64+
65+
indicator_hint = indicator.minimumSizeHint()
66+
step_hint = self.ui.step_size.sizeHint()
67+
self._indicator_thickness = max(indicator_hint.height(), 10)
68+
self._vertical_indicator_width = max(indicator.minimumWidth(), 15)
69+
self._horizontal_indicator_width = max(90, step_hint.width())
70+
base_width = max(device_box.minimumSizeHint().width(), self.dimensions[1])
71+
self._indicator_switch_width = (
72+
base_width - self._vertical_indicator_width + self._horizontal_indicator_width
73+
)
74+
75+
def resizeEvent(self, event):
76+
super().resizeEvent(event)
77+
self._update_indicator_orientation()
78+
79+
def _update_indicator_orientation(self):
80+
if not hasattr(self, "ui"):
81+
return
82+
83+
indicator = self.ui.position_indicator
84+
available_width = self.ui.device_box.width() or self.width() or self.dimensions[1]
85+
should_use_horizontal = available_width >= self._indicator_switch_width
86+
if should_use_horizontal == self._indicator_is_horizontal:
87+
return
88+
89+
self._indicator_is_horizontal = should_use_horizontal
90+
indicator.vertical = not should_use_horizontal
91+
92+
if should_use_horizontal:
93+
indicator.setMinimumSize(self._horizontal_indicator_width, self._indicator_thickness)
94+
indicator.setMaximumHeight(self._indicator_thickness)
95+
indicator.setMaximumWidth(16777215)
96+
indicator.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Fixed)
97+
else:
98+
indicator.setMinimumSize(self._vertical_indicator_width, self._indicator_thickness)
99+
indicator.setMaximumSize(self._vertical_indicator_width, 16777215)
100+
indicator.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
101+
102+
indicator.updateGeometry()
26103

27104

28105
if __name__ == "__main__": # pragma: no cover

bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.ui

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22
<ui version="4.0">
33
<class>Form</class>
44
<widget class="QWidget" name="Form">
5+
<property name="sizePolicy">
6+
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
7+
<horstretch>0</horstretch>
8+
<verstretch>0</verstretch>
9+
</sizepolicy>
10+
</property>
511
<property name="geometry">
612
<rect>
713
<x>0</x>
814
<y>0</y>
9-
<width>612</width>
10-
<height>91</height>
15+
<width>592</width>
16+
<height>76</height>
1117
</rect>
1218
</property>
1319
<property name="minimumSize">
@@ -26,8 +32,29 @@
2632
<string>Form</string>
2733
</property>
2834
<layout class="QVBoxLayout" name="verticalLayout">
35+
<property name="spacing">
36+
<number>0</number>
37+
</property>
38+
<property name="leftMargin">
39+
<number>0</number>
40+
</property>
41+
<property name="topMargin">
42+
<number>0</number>
43+
</property>
44+
<property name="rightMargin">
45+
<number>0</number>
46+
</property>
47+
<property name="bottomMargin">
48+
<number>0</number>
49+
</property>
2950
<item>
3051
<widget class="QGroupBox" name="device_box">
52+
<property name="sizePolicy">
53+
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
54+
<horstretch>0</horstretch>
55+
<verstretch>0</verstretch>
56+
</sizepolicy>
57+
</property>
3158
<property name="title">
3259
<string>Device Name</string>
3360
</property>
@@ -227,12 +254,12 @@
227254
<customwidgets>
228255
<customwidget>
229256
<class>PositionIndicator</class>
230-
<extends>QWidget</extends>
257+
<extends></extends>
231258
<header>position_indicator</header>
232259
</customwidget>
233260
<customwidget>
234261
<class>SpinnerWidget</class>
235-
<extends>QWidget</extends>
262+
<extends></extends>
236263
<header>spinner_widget</header>
237264
</customwidget>
238265
</customwidgets>

bec_widgets/widgets/control/device_control/positioner_group/positioner_group.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,13 @@ def __init__(self, parent, dev_name):
2727
self.layout().setContentsMargins(0, 0, 0, 0)
2828
self.layout().setSpacing(0)
2929
self.widget = PositionerBox(self, dev_name)
30-
self.widget.compact_view = True
31-
self.widget.expand_popup = False
3230
self.layout().addWidget(self.widget)
3331
self.widget.position_update.connect(self._on_position_update)
34-
self.widget.expand.connect(self._on_expand)
3532
self.setTitle(self.device_name)
3633
self.widget.force_update_readback()
3734

38-
def _on_expand(self, expand):
39-
if expand:
40-
self.setTitle("")
41-
self.setFlat(True)
42-
else:
43-
self.setTitle(self.device_name)
44-
self.setFlat(False)
45-
4635
def _on_position_update(self, pos: float):
4736
self.position_update.emit(pos)
48-
precision = getattr(self.widget.dev[self.widget.device], "precision", 8)
49-
try:
50-
precision = int(precision)
51-
except (TypeError, ValueError):
52-
precision = int(8)
53-
self.widget.label = f"{pos:.{precision}f}"
5437

5538
def close(self):
5639
self.widget.close()

tests/unit_tests/test_positioner_box.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ def precision(self):
3636
def positioner_box(qtbot, mocked_client):
3737
"""Fixture for PositionerBox widget"""
3838
with mock.patch(
39-
"bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base.uuid.uuid4"
39+
"bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base.uuid.uuid4"
4040
) as mock_uuid:
4141
mock_uuid.return_value = "fake_uuid"
4242
with mock.patch(
43-
"bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base.PositionerBoxBase._check_device_is_valid",
43+
"bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base.PositionerBoxBase._check_device_is_valid",
4444
return_value=True,
4545
):
4646
db = create_widget(qtbot, PositionerBox, device="samx", client=mocked_client)
@@ -141,7 +141,7 @@ def test_positioner_control_line(qtbot, mocked_client):
141141
Inherits from PositionerBox, but the layout is changed. Check dimensions only
142142
"""
143143
with mock.patch(
144-
"bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base.uuid.uuid4"
144+
"bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base.uuid.uuid4"
145145
) as mock_uuid:
146146
mock_uuid.return_value = "fake_uuid"
147147
with mock.patch(
@@ -151,7 +151,8 @@ def test_positioner_control_line(qtbot, mocked_client):
151151
db = PositionerControlLine(device="samx", client=mocked_client)
152152
qtbot.addWidget(db)
153153

154-
assert db.ui.device_box.height() == 60
154+
assert db.ui.device_box.height() == db.height()
155+
assert db.ui.device_box.height() >= db.dimensions[0]
155156
assert db.ui.device_box.width() == 600
156157

157158

tests/unit_tests/test_positioner_box_2d.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
def positioner_box_2d(qtbot, mocked_client):
1313
"""Fixture for PositionerBox widget"""
1414
with mock.patch(
15-
"bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base.uuid.uuid4"
15+
"bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base.uuid.uuid4"
1616
) as mock_uuid:
1717
mock_uuid.return_value = "fake_uuid"
1818
with mock.patch(
19-
"bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base.PositionerBoxBase._check_device_is_valid",
19+
"bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base.PositionerBoxBase._check_device_is_valid",
2020
return_value=True,
2121
):
2222
db = create_widget(

0 commit comments

Comments
 (0)