bec-widgets 0.51.0__py3-none-any.whl → 0.52.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bec_widgets/cli/__init__.py +1 -1
- bec_widgets/cli/bec_widgets_icon.png +0 -0
- bec_widgets/cli/client.py +328 -5
- bec_widgets/cli/client_utils.py +17 -5
- bec_widgets/cli/generate_cli.py +7 -3
- bec_widgets/cli/rpc_register.py +4 -0
- bec_widgets/cli/rpc_wigdet_handler.py +27 -0
- bec_widgets/cli/server.py +34 -9
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +54 -2
- bec_widgets/examples/jupyter_console/jupyter_console_window.ui +26 -2
- bec_widgets/examples/jupyter_console/terminal_icon.png +0 -0
- bec_widgets/utils/__init__.py +1 -0
- bec_widgets/utils/bec_connector.py +18 -3
- bec_widgets/utils/bec_table.py +1 -0
- bec_widgets/utils/container_utils.py +3 -0
- bec_widgets/utils/crosshair.py +1 -0
- bec_widgets/utils/entry_validator.py +2 -0
- bec_widgets/utils/layout_manager.py +121 -0
- bec_widgets/utils/widget_io.py +5 -0
- bec_widgets/utils/yaml_dialog.py +2 -0
- bec_widgets/validation/monitor_config_validator.py +2 -1
- bec_widgets/widgets/__init__.py +1 -0
- bec_widgets/widgets/dock/__init__.py +2 -0
- bec_widgets/widgets/dock/dock.py +269 -0
- bec_widgets/widgets/dock/dock_area.py +225 -0
- bec_widgets/widgets/figure/figure.py +45 -16
- bec_widgets/widgets/plots/__init__.py +1 -1
- bec_widgets/widgets/plots/image.py +46 -9
- bec_widgets/widgets/plots/motor_map.py +17 -3
- bec_widgets/widgets/plots/plot_base.py +14 -3
- bec_widgets/widgets/plots/waveform.py +37 -10
- bec_widgets/widgets/scan_control/scan_control.py +10 -2
- bec_widgets/widgets/toolbar/toolbar.py +1 -0
- {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.1.dist-info}/METADATA +1 -1
- {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.1.dist-info}/RECORD +46 -40
- tests/end-2-end/conftest.py +19 -4
- tests/end-2-end/test_bec_dock_rpc_e2e.py +145 -0
- tests/end-2-end/test_bec_figure_rpc_e2e.py +17 -17
- tests/end-2-end/test_rpc_register_e2e.py +3 -3
- tests/unit_tests/test_bec_dock.py +114 -0
- tests/unit_tests/test_bec_figure.py +20 -22
- tests/unit_tests/test_generate_cli_client.py +1 -1
- tests/unit_tests/test_waveform1d.py +1 -1
- bec_widgets/simulations/__init__.py +0 -0
- bec_widgets/utils/ctrl_c.py +0 -39
- {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.1.dist-info}/LICENSE +0 -0
- {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.1.dist-info}/WHEEL +0 -0
- {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.1.dist-info}/top_level.txt +0 -0
bec_widgets/utils/widget_io.py
CHANGED
@@ -114,6 +114,7 @@ class WidgetIO:
|
|
114
114
|
def get_value(widget, ignore_errors=False):
|
115
115
|
"""
|
116
116
|
Retrieve value from the widget instance.
|
117
|
+
|
117
118
|
Args:
|
118
119
|
widget: Widget instance.
|
119
120
|
ignore_errors(bool, optional): Whether to ignore if no handler is found.
|
@@ -129,6 +130,7 @@ class WidgetIO:
|
|
129
130
|
def set_value(widget, value, ignore_errors=False):
|
130
131
|
"""
|
131
132
|
Set a value on the widget instance.
|
133
|
+
|
132
134
|
Args:
|
133
135
|
widget: Widget instance.
|
134
136
|
value: Value to set.
|
@@ -155,6 +157,7 @@ class WidgetHierarchy:
|
|
155
157
|
) -> None:
|
156
158
|
"""
|
157
159
|
Print the widget hierarchy to the console.
|
160
|
+
|
158
161
|
Args:
|
159
162
|
widget: Widget to print the hierarchy of
|
160
163
|
indent(int, optional): Level of indentation.
|
@@ -196,6 +199,7 @@ class WidgetHierarchy:
|
|
196
199
|
) -> dict:
|
197
200
|
"""
|
198
201
|
Export the widget hierarchy to a dictionary.
|
202
|
+
|
199
203
|
Args:
|
200
204
|
widget: Widget to print the hierarchy of.
|
201
205
|
config(dict,optional): Dictionary to export the hierarchy to.
|
@@ -245,6 +249,7 @@ class WidgetHierarchy:
|
|
245
249
|
def import_config_from_dict(widget, config: dict, set_values: bool = False) -> None:
|
246
250
|
"""
|
247
251
|
Import the widget hierarchy from a dictionary.
|
252
|
+
|
248
253
|
Args:
|
249
254
|
widget: Widget to import the hierarchy to.
|
250
255
|
config:
|
bec_widgets/utils/yaml_dialog.py
CHANGED
@@ -9,6 +9,7 @@ from qtpy.QtWidgets import QFileDialog
|
|
9
9
|
def load_yaml(instance) -> Union[dict, None]:
|
10
10
|
"""
|
11
11
|
Load YAML file from disk.
|
12
|
+
|
12
13
|
Args:
|
13
14
|
instance: Instance of the calling widget.
|
14
15
|
|
@@ -40,6 +41,7 @@ def load_yaml(instance) -> Union[dict, None]:
|
|
40
41
|
def save_yaml(instance, config: dict) -> None:
|
41
42
|
"""
|
42
43
|
Save YAML file to disk.
|
44
|
+
|
43
45
|
Args:
|
44
46
|
instance: Instance of the calling widget.
|
45
47
|
config: Configuration data to be saved.
|
@@ -8,7 +8,7 @@ class Signal(BaseModel):
|
|
8
8
|
"""
|
9
9
|
Represents a signal in a plot configuration.
|
10
10
|
|
11
|
-
|
11
|
+
Args:
|
12
12
|
name (str): The name of the signal.
|
13
13
|
entry (Optional[str]): The entry point of the signal, optional.
|
14
14
|
"""
|
@@ -21,6 +21,7 @@ class Signal(BaseModel):
|
|
21
21
|
def validate_fields(cls, values):
|
22
22
|
"""Validate the fields of the model.
|
23
23
|
First validate the 'name' field, then validate the 'entry' field.
|
24
|
+
|
24
25
|
Args:
|
25
26
|
values (dict): The values to be validated."""
|
26
27
|
devices = MonitorConfigValidator.devices
|
bec_widgets/widgets/__init__.py
CHANGED
@@ -0,0 +1,269 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING, Literal, Optional
|
4
|
+
|
5
|
+
from pydantic import Field
|
6
|
+
from pyqtgraph.dockarea import Dock
|
7
|
+
|
8
|
+
from bec_widgets.cli.rpc_wigdet_handler import RPCWidgetHandler
|
9
|
+
from bec_widgets.utils import BECConnector, ConnectionConfig, GridLayoutManager
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from qtpy.QtWidgets import QWidget
|
13
|
+
|
14
|
+
from bec_widgets.widgets import BECDockArea
|
15
|
+
|
16
|
+
|
17
|
+
class DockConfig(ConnectionConfig):
|
18
|
+
widgets: dict[str, ConnectionConfig] = Field({}, description="The widgets in the dock.")
|
19
|
+
position: Literal["bottom", "top", "left", "right", "above", "below"] = Field(
|
20
|
+
"bottom", description="The position of the dock."
|
21
|
+
)
|
22
|
+
parent_dock_area: Optional[str] = Field(
|
23
|
+
None, description="The GUI ID of parent dock area of the dock."
|
24
|
+
)
|
25
|
+
|
26
|
+
|
27
|
+
class BECDock(BECConnector, Dock):
|
28
|
+
USER_ACCESS = [
|
29
|
+
"rpc_id",
|
30
|
+
"widget_list",
|
31
|
+
"show_title_bar",
|
32
|
+
"hide_title_bar",
|
33
|
+
"get_widgets_positions",
|
34
|
+
"set_title",
|
35
|
+
"add_widget_bec",
|
36
|
+
"list_eligible_widgets",
|
37
|
+
"move_widget",
|
38
|
+
"remove_widget",
|
39
|
+
"remove",
|
40
|
+
"attach",
|
41
|
+
"detach",
|
42
|
+
]
|
43
|
+
|
44
|
+
def __init__(
|
45
|
+
self,
|
46
|
+
parent: QWidget | None = None,
|
47
|
+
parent_dock_area: BECDockArea | None = None,
|
48
|
+
config: DockConfig | None = None,
|
49
|
+
name: str | None = None,
|
50
|
+
client=None,
|
51
|
+
gui_id: str | None = None,
|
52
|
+
**kwargs,
|
53
|
+
) -> None:
|
54
|
+
if config is None:
|
55
|
+
config = DockConfig(
|
56
|
+
widget_class=self.__class__.__name__, parent_dock_area=parent_dock_area.gui_id
|
57
|
+
)
|
58
|
+
else:
|
59
|
+
if isinstance(config, dict):
|
60
|
+
config = DockConfig(**config)
|
61
|
+
self.config = config
|
62
|
+
super().__init__(client=client, config=config, gui_id=gui_id)
|
63
|
+
Dock.__init__(self, name=name, **kwargs)
|
64
|
+
|
65
|
+
self.parent_dock_area = parent_dock_area
|
66
|
+
|
67
|
+
# Layout Manager
|
68
|
+
self.layout_manager = GridLayoutManager(self.layout)
|
69
|
+
|
70
|
+
def dropEvent(self, event):
|
71
|
+
source = event.source()
|
72
|
+
old_area = source.area
|
73
|
+
self.setOrientation("horizontal", force=True)
|
74
|
+
super().dropEvent(event)
|
75
|
+
if old_area in self.parent_dock_area.tempAreas and old_area != self.parent_dock_area:
|
76
|
+
self.parent_dock_area.removeTempArea(old_area)
|
77
|
+
|
78
|
+
def float(self):
|
79
|
+
"""
|
80
|
+
Float the dock.
|
81
|
+
Overwrites the default pyqtgraph dock float.
|
82
|
+
"""
|
83
|
+
|
84
|
+
# need to check if the dock is temporary and if it is the only dock in the area
|
85
|
+
# fixes bug in pyqtgraph detaching
|
86
|
+
if self.area.temporary == True and len(self.area.docks) <= 1:
|
87
|
+
return
|
88
|
+
elif self.area.temporary == True and len(self.area.docks) > 1:
|
89
|
+
self.area.docks.pop(self.name(), None)
|
90
|
+
super().float()
|
91
|
+
else:
|
92
|
+
super().float()
|
93
|
+
|
94
|
+
@property
|
95
|
+
def widget_list(self) -> list:
|
96
|
+
"""
|
97
|
+
Get the widgets in the dock.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
widgets(list): The widgets in the dock.
|
101
|
+
"""
|
102
|
+
return self.widgets
|
103
|
+
|
104
|
+
@widget_list.setter
|
105
|
+
def widget_list(self, value: list):
|
106
|
+
self.widgets = value
|
107
|
+
|
108
|
+
def hide_title_bar(self):
|
109
|
+
"""
|
110
|
+
Hide the title bar of the dock.
|
111
|
+
"""
|
112
|
+
# self.hideTitleBar() #TODO pyqtgraph looks bugged ATM, doing my implementation
|
113
|
+
self.label.hide()
|
114
|
+
self.labelHidden = True
|
115
|
+
|
116
|
+
def show_title_bar(self):
|
117
|
+
"""
|
118
|
+
Hide the title bar of the dock.
|
119
|
+
"""
|
120
|
+
# self.showTitleBar() #TODO pyqtgraph looks bugged ATM, doing my implementation
|
121
|
+
self.label.show()
|
122
|
+
self.labelHidden = False
|
123
|
+
|
124
|
+
def set_title(self, title: str):
|
125
|
+
"""
|
126
|
+
Set the title of the dock.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
title(str): The title of the dock.
|
130
|
+
"""
|
131
|
+
self.parent_dock_area.docks[title] = self.parent_dock_area.docks.pop(self.name())
|
132
|
+
self.setTitle(title)
|
133
|
+
|
134
|
+
def get_widgets_positions(self) -> dict:
|
135
|
+
"""
|
136
|
+
Get the positions of the widgets in the dock.
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
dict: The positions of the widgets in the dock as dict -> {(row, col, rowspan, colspan):widget}
|
140
|
+
"""
|
141
|
+
return self.layout_manager.get_widgets_positions()
|
142
|
+
|
143
|
+
def list_eligible_widgets(
|
144
|
+
self,
|
145
|
+
) -> list: # TODO can be moved to some util mixin like container class for rpc widgets
|
146
|
+
"""
|
147
|
+
List all widgets that can be added to the dock.
|
148
|
+
|
149
|
+
Returns:
|
150
|
+
list: The list of eligible widgets.
|
151
|
+
"""
|
152
|
+
return list(RPCWidgetHandler.widget_classes.keys())
|
153
|
+
|
154
|
+
def add_widget_bec(
|
155
|
+
self,
|
156
|
+
widget_type: str,
|
157
|
+
row=None,
|
158
|
+
col=0,
|
159
|
+
rowspan=1,
|
160
|
+
colspan=1,
|
161
|
+
shift: Literal["down", "up", "left", "right"] = "down",
|
162
|
+
):
|
163
|
+
"""
|
164
|
+
Add a widget to the dock.
|
165
|
+
|
166
|
+
Args:
|
167
|
+
widget_type(str): The widget to add. Only BEC RPC widgets from RPCWidgetHandler are allowed.
|
168
|
+
row(int): The row to add the widget to. If None, the widget will be added to the next available row.
|
169
|
+
col(int): The column to add the widget to.
|
170
|
+
rowspan(int): The number of rows the widget should span.
|
171
|
+
colspan(int): The number of columns the widget should span.
|
172
|
+
shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied.
|
173
|
+
"""
|
174
|
+
if row is None:
|
175
|
+
row = self.layout.rowCount()
|
176
|
+
|
177
|
+
if self.layout_manager.is_position_occupied(row, col):
|
178
|
+
self.layout_manager.shift_widgets(shift, start_row=row)
|
179
|
+
|
180
|
+
widget = RPCWidgetHandler.create_widget(widget_type)
|
181
|
+
self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
|
182
|
+
|
183
|
+
return widget
|
184
|
+
|
185
|
+
def add_widget(
|
186
|
+
self,
|
187
|
+
widget: QWidget,
|
188
|
+
row=None,
|
189
|
+
col=0,
|
190
|
+
rowspan=1,
|
191
|
+
colspan=1,
|
192
|
+
shift: Literal["down", "up", "left", "right"] = "down",
|
193
|
+
):
|
194
|
+
"""
|
195
|
+
Add a widget to the dock.
|
196
|
+
|
197
|
+
Args:
|
198
|
+
widget(QWidget): The widget to add.
|
199
|
+
row(int): The row to add the widget to. If None, the widget will be added to the next available row.
|
200
|
+
col(int): The column to add the widget to.
|
201
|
+
rowspan(int): The number of rows the widget should span.
|
202
|
+
colspan(int): The number of columns the widget should span.
|
203
|
+
shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied.
|
204
|
+
"""
|
205
|
+
if row is None:
|
206
|
+
row = self.layout.rowCount()
|
207
|
+
|
208
|
+
if self.layout_manager.is_position_occupied(row, col):
|
209
|
+
self.layout_manager.shift_widgets(shift, start_row=row)
|
210
|
+
|
211
|
+
self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
|
212
|
+
|
213
|
+
def move_widget(self, widget: QWidget, new_row: int, new_col: int):
|
214
|
+
"""
|
215
|
+
Move a widget to a new position in the layout.
|
216
|
+
|
217
|
+
Args:
|
218
|
+
widget(QWidget): The widget to move.
|
219
|
+
new_row(int): The new row to move the widget to.
|
220
|
+
new_col(int): The new column to move the widget to.
|
221
|
+
"""
|
222
|
+
self.layout_manager.move_widget(widget, new_row, new_col)
|
223
|
+
|
224
|
+
def attach(self):
|
225
|
+
"""
|
226
|
+
Attach the dock to the parent dock area.
|
227
|
+
"""
|
228
|
+
self.parent_dock_area.removeTempArea(self.area)
|
229
|
+
|
230
|
+
def detach(self):
|
231
|
+
"""
|
232
|
+
Detach the dock from the parent dock area.
|
233
|
+
"""
|
234
|
+
self.float()
|
235
|
+
|
236
|
+
def remove_widget(self, widget_rpc_id: str):
|
237
|
+
"""
|
238
|
+
Remove a widget from the dock.
|
239
|
+
|
240
|
+
Args:
|
241
|
+
widget_rpc_id(str): The ID of the widget to remove.
|
242
|
+
"""
|
243
|
+
widget = self.rpc_register.get_rpc_by_id(widget_rpc_id)
|
244
|
+
self.layout.removeWidget(widget)
|
245
|
+
widget.close()
|
246
|
+
|
247
|
+
def remove(self):
|
248
|
+
"""
|
249
|
+
Remove the dock from the parent dock area.
|
250
|
+
"""
|
251
|
+
# self.cleanup()
|
252
|
+
self.parent_dock_area.remove_dock(self.name())
|
253
|
+
|
254
|
+
def cleanup(self):
|
255
|
+
"""
|
256
|
+
Clean up the dock, including all its widgets.
|
257
|
+
"""
|
258
|
+
for widget in self.widgets:
|
259
|
+
if hasattr(widget, "cleanup"):
|
260
|
+
widget.cleanup()
|
261
|
+
super().cleanup()
|
262
|
+
|
263
|
+
def close(self):
|
264
|
+
"""
|
265
|
+
Close the dock area and cleanup.
|
266
|
+
Has to be implemented to overwrite pyqtgraph event accept in Container close.
|
267
|
+
"""
|
268
|
+
self.cleanup()
|
269
|
+
super().close()
|
@@ -0,0 +1,225 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Literal, Optional
|
4
|
+
from weakref import WeakValueDictionary
|
5
|
+
|
6
|
+
from pydantic import Field
|
7
|
+
from pyqtgraph.dockarea.DockArea import DockArea
|
8
|
+
from qtpy.QtCore import Qt
|
9
|
+
from qtpy.QtGui import QPainter, QPaintEvent
|
10
|
+
from qtpy.QtWidgets import QWidget
|
11
|
+
|
12
|
+
from bec_widgets.utils import BECConnector, ConnectionConfig, WidgetContainerUtils
|
13
|
+
|
14
|
+
from .dock import BECDock, DockConfig
|
15
|
+
|
16
|
+
|
17
|
+
class DockAreaConfig(ConnectionConfig):
|
18
|
+
docks: dict[str, DockConfig] = Field({}, description="The docks in the dock area.")
|
19
|
+
|
20
|
+
|
21
|
+
class BECDockArea(BECConnector, DockArea):
|
22
|
+
USER_ACCESS = [
|
23
|
+
"panels",
|
24
|
+
"save_state",
|
25
|
+
"remove_dock",
|
26
|
+
"restore_state",
|
27
|
+
"add_dock",
|
28
|
+
"clear_all",
|
29
|
+
"detach_dock",
|
30
|
+
"attach_all",
|
31
|
+
"get_all_rpc",
|
32
|
+
]
|
33
|
+
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
parent: QWidget | None = None,
|
37
|
+
config: DockAreaConfig | None = None,
|
38
|
+
client=None,
|
39
|
+
gui_id: str = None,
|
40
|
+
) -> None:
|
41
|
+
if config is None:
|
42
|
+
config = DockAreaConfig(widget_class=self.__class__.__name__)
|
43
|
+
else:
|
44
|
+
if isinstance(config, dict):
|
45
|
+
config = DockAreaConfig(**config)
|
46
|
+
self.config = config
|
47
|
+
super().__init__(client=client, config=config, gui_id=gui_id)
|
48
|
+
DockArea.__init__(self, parent=parent)
|
49
|
+
|
50
|
+
self._instructions_visible = True
|
51
|
+
|
52
|
+
def paintEvent(self, event: QPaintEvent):
|
53
|
+
super().paintEvent(event)
|
54
|
+
if self._instructions_visible:
|
55
|
+
painter = QPainter(self)
|
56
|
+
painter.drawText(self.rect(), Qt.AlignCenter, "Add docks using 'add_dock' method")
|
57
|
+
|
58
|
+
@property
|
59
|
+
def panels(self) -> dict:
|
60
|
+
"""
|
61
|
+
Get the docks in the dock area.
|
62
|
+
Returns:
|
63
|
+
dock_dict(dict): The docks in the dock area.
|
64
|
+
"""
|
65
|
+
return dict(self.docks)
|
66
|
+
|
67
|
+
@panels.setter
|
68
|
+
def panels(self, value: dict):
|
69
|
+
|
70
|
+
self.docks = WeakValueDictionary(value)
|
71
|
+
|
72
|
+
def restore_state(
|
73
|
+
self,
|
74
|
+
state: dict = None,
|
75
|
+
missing: Literal["ignore", "error"] = "ignore",
|
76
|
+
extra="bottom",
|
77
|
+
):
|
78
|
+
"""
|
79
|
+
Restore the state of the dock area. If no state is provided, the last state is restored.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
state(dict): The state to restore.
|
83
|
+
missing(Literal['ignore','error']): What to do if a dock is missing.
|
84
|
+
extra(str): Extra docks that are in the dockarea but that are not mentioned in state will be added to the bottom of the dockarea, unless otherwise specified by the extra argument.
|
85
|
+
"""
|
86
|
+
if state is None:
|
87
|
+
state = self._last_state
|
88
|
+
self.restoreState(state, missing=missing, extra=extra)
|
89
|
+
|
90
|
+
def save_state(self) -> dict:
|
91
|
+
"""
|
92
|
+
Save the state of the dock area.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
dict: The state of the dock area.
|
96
|
+
"""
|
97
|
+
self._last_state = self.saveState()
|
98
|
+
return self._last_state
|
99
|
+
|
100
|
+
def remove_dock(self, name: str):
|
101
|
+
"""
|
102
|
+
Remove a dock by name and ensure it is properly closed and cleaned up.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
name(str): The name of the dock to remove.
|
106
|
+
"""
|
107
|
+
dock = self.docks.pop(name, None)
|
108
|
+
if dock:
|
109
|
+
dock.close()
|
110
|
+
if len(self.docks) <= 1:
|
111
|
+
for dock in self.docks.values():
|
112
|
+
dock.hide_title_bar()
|
113
|
+
|
114
|
+
else:
|
115
|
+
raise ValueError(f"Dock with name {name} does not exist.")
|
116
|
+
|
117
|
+
def add_dock(
|
118
|
+
self,
|
119
|
+
name: str = None,
|
120
|
+
position: Literal["bottom", "top", "left", "right", "above", "below"] = None,
|
121
|
+
relative_to: BECDock | None = None,
|
122
|
+
closable: bool = False,
|
123
|
+
prefix: str = "dock",
|
124
|
+
widget: str | QWidget | None = None,
|
125
|
+
row: int = None,
|
126
|
+
col: int = 0,
|
127
|
+
rowspan: int = 1,
|
128
|
+
colspan: int = 1,
|
129
|
+
) -> BECDock:
|
130
|
+
"""
|
131
|
+
Add a dock to the dock area. Dock has QGridLayout as layout manager by default.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
name(str): The name of the dock to be displayed and for further references. Has to be unique.
|
135
|
+
position(Literal["bottom", "top", "left", "right", "above", "below"]): The position of the dock.
|
136
|
+
relative_to(BECDock): The dock to which the new dock should be added relative to.
|
137
|
+
closable(bool): Whether the dock is closable.
|
138
|
+
prefix(str): The prefix for the dock name if no name is provided.
|
139
|
+
widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed.
|
140
|
+
row(int): The row of the added widget.
|
141
|
+
col(int): The column of the added widget.
|
142
|
+
rowspan(int): The rowspan of the added widget.
|
143
|
+
colspan(int): The colspan of the added widget.
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
BECDock: The created dock.
|
147
|
+
"""
|
148
|
+
if name is None:
|
149
|
+
name = WidgetContainerUtils.generate_unique_widget_id(
|
150
|
+
container=self.docks, prefix=prefix
|
151
|
+
)
|
152
|
+
|
153
|
+
if name in set(self.docks.keys()):
|
154
|
+
raise ValueError(f"Dock with name {name} already exists.")
|
155
|
+
|
156
|
+
if position is None:
|
157
|
+
position = "bottom"
|
158
|
+
|
159
|
+
dock = BECDock(name=name, parent_dock_area=self, closable=closable)
|
160
|
+
dock.config.position = position
|
161
|
+
self.config.docks[name] = dock.config
|
162
|
+
|
163
|
+
self.addDock(dock=dock, position=position, relativeTo=relative_to)
|
164
|
+
|
165
|
+
if len(self.docks) <= 1:
|
166
|
+
dock.hide_title_bar()
|
167
|
+
elif len(self.docks) > 1:
|
168
|
+
for dock in self.docks.values():
|
169
|
+
dock.show_title_bar()
|
170
|
+
|
171
|
+
if widget is not None and isinstance(widget, str):
|
172
|
+
dock.add_widget_bec(
|
173
|
+
widget_type=widget, row=row, col=col, rowspan=rowspan, colspan=colspan
|
174
|
+
)
|
175
|
+
elif widget is not None and isinstance(widget, QWidget):
|
176
|
+
dock.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
|
177
|
+
if self._instructions_visible:
|
178
|
+
self._instructions_visible = False
|
179
|
+
self.update()
|
180
|
+
return dock
|
181
|
+
|
182
|
+
def detach_dock(self, dock_name: str) -> BECDock:
|
183
|
+
"""
|
184
|
+
Undock a dock from the dock area.
|
185
|
+
|
186
|
+
Args:
|
187
|
+
dock_name(str): The dock to undock.
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
BECDock: The undocked dock.
|
191
|
+
"""
|
192
|
+
dock = self.docks[dock_name]
|
193
|
+
self.floatDock(dock)
|
194
|
+
return dock
|
195
|
+
|
196
|
+
def attach_all(self):
|
197
|
+
"""
|
198
|
+
Return all floating docks to the dock area.
|
199
|
+
"""
|
200
|
+
while self.tempAreas:
|
201
|
+
for temp_area in self.tempAreas:
|
202
|
+
self.removeTempArea(temp_area)
|
203
|
+
|
204
|
+
def clear_all(self):
|
205
|
+
"""
|
206
|
+
Close all docks and remove all temp areas.
|
207
|
+
"""
|
208
|
+
self.attach_all()
|
209
|
+
for dock in dict(self.docks).values():
|
210
|
+
dock.remove()
|
211
|
+
|
212
|
+
def cleanup(self):
|
213
|
+
"""
|
214
|
+
Cleanup the dock area.
|
215
|
+
"""
|
216
|
+
self.clear_all()
|
217
|
+
super().cleanup()
|
218
|
+
|
219
|
+
def close(self):
|
220
|
+
"""
|
221
|
+
Close the dock area and cleanup.
|
222
|
+
Has to be implemented to overwrite pyqtgraph event accept in Container close.
|
223
|
+
"""
|
224
|
+
self.cleanup()
|
225
|
+
super().close()
|