bec-widgets 1.25.1__py3-none-any.whl → 2.0.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.
Files changed (196) hide show
  1. .gitlab-ci.yml +3 -5
  2. CHANGELOG.md +639 -0
  3. PKG-INFO +3 -3
  4. bec_widgets/__init__.py +4 -0
  5. bec_widgets/applications/bw_launch.py +23 -0
  6. bec_widgets/applications/launch_window.py +430 -0
  7. bec_widgets/assets/app_icons/auto_update.png +0 -0
  8. bec_widgets/assets/app_icons/ui_loader_tile.png +0 -0
  9. bec_widgets/cli/__init__.py +0 -1
  10. bec_widgets/cli/client.py +1779 -2064
  11. bec_widgets/cli/client_utils.py +346 -174
  12. bec_widgets/cli/generate_cli.py +143 -37
  13. bec_widgets/cli/rpc/rpc_base.py +152 -21
  14. bec_widgets/cli/rpc/rpc_register.py +113 -6
  15. bec_widgets/cli/rpc/rpc_widget_handler.py +13 -11
  16. bec_widgets/cli/server.py +125 -239
  17. bec_widgets/examples/jupyter_console/jupyter_console_window.py +97 -145
  18. bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py +1 -1
  19. bec_widgets/utils/bec_connector.py +190 -21
  20. bec_widgets/utils/bec_designer.py +7 -0
  21. bec_widgets/utils/bec_dispatcher.py +71 -4
  22. bec_widgets/utils/bec_plugin_helper.py +89 -0
  23. bec_widgets/utils/bec_signal_proxy.py +1 -1
  24. bec_widgets/utils/bec_widget.py +26 -10
  25. bec_widgets/utils/colors.py +1 -1
  26. bec_widgets/{qt_utils → utils}/compact_popup.py +2 -0
  27. bec_widgets/utils/container_utils.py +37 -12
  28. bec_widgets/utils/crosshair.py +25 -8
  29. bec_widgets/utils/entry_validator.py +3 -1
  30. bec_widgets/{qt_utils → utils}/error_popups.py +18 -0
  31. bec_widgets/{qt_utils → utils}/expandable_frame.py +2 -2
  32. bec_widgets/utils/forms_from_types/forms.py +182 -0
  33. bec_widgets/{widgets/editors/scan_metadata/_metadata_widgets.py → utils/forms_from_types/items.py} +41 -30
  34. bec_widgets/utils/generate_designer_plugin.py +40 -36
  35. bec_widgets/utils/linear_region_selector.py +2 -0
  36. bec_widgets/utils/name_utils.py +16 -0
  37. bec_widgets/{qt_utils → utils}/palette_viewer.py +2 -2
  38. bec_widgets/utils/plot_indicator_items.py +2 -5
  39. bec_widgets/utils/plugin_utils.py +47 -1
  40. bec_widgets/{qt_utils → utils}/round_frame.py +14 -14
  41. bec_widgets/utils/rpc_server.py +277 -0
  42. bec_widgets/utils/serialization.py +44 -0
  43. bec_widgets/{qt_utils → utils}/settings_dialog.py +26 -1
  44. bec_widgets/{qt_utils → utils}/side_panel.py +17 -10
  45. bec_widgets/{qt_utils → utils}/toolbar.py +69 -25
  46. bec_widgets/utils/ui_loader.py +8 -8
  47. bec_widgets/utils/widget_io.py +166 -25
  48. bec_widgets/widgets/containers/auto_update/auto_updates.py +364 -0
  49. bec_widgets/widgets/containers/dock/dock.py +157 -49
  50. bec_widgets/widgets/containers/dock/dock_area.py +188 -138
  51. bec_widgets/widgets/containers/layout_manager/layout_manager.py +2 -1
  52. bec_widgets/widgets/containers/main_window/addons/web_links.py +15 -0
  53. bec_widgets/widgets/containers/main_window/main_window.py +189 -41
  54. bec_widgets/widgets/control/buttons/button_abort/button_abort.py +3 -4
  55. bec_widgets/widgets/control/buttons/button_reset/button_reset.py +3 -4
  56. bec_widgets/widgets/control/buttons/button_resume/button_resume.py +3 -3
  57. bec_widgets/widgets/control/buttons/stop_button/stop_button.py +18 -7
  58. bec_widgets/widgets/control/device_control/position_indicator/position_indicator.py +22 -3
  59. bec_widgets/widgets/control/device_control/positioner_box/_base/positioner_box_base.py +31 -13
  60. bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +3 -1
  61. bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.ui +27 -4
  62. bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py +5 -2
  63. bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.ui +97 -31
  64. bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.ui +11 -4
  65. bec_widgets/widgets/control/device_control/positioner_group/positioner_group.py +2 -3
  66. bec_widgets/widgets/control/device_input/base_classes/device_input_base.py +29 -4
  67. bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +1 -0
  68. bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +2 -2
  69. bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py +2 -2
  70. bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py +1 -2
  71. bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py +1 -2
  72. bec_widgets/widgets/control/scan_control/scan_control.py +7 -5
  73. bec_widgets/widgets/control/scan_control/scan_group_box.py +28 -5
  74. bec_widgets/widgets/dap/dap_combo_box/dap_combo_box.py +1 -2
  75. bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py +3 -4
  76. bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_vertical.ui +14 -8
  77. bec_widgets/widgets/editors/console/console.py +1 -1
  78. bec_widgets/widgets/editors/{scan_metadata/additional_metadata_table.py → dict_backed_table.py} +29 -6
  79. bec_widgets/widgets/editors/scan_metadata/__init__.py +0 -7
  80. bec_widgets/widgets/editors/scan_metadata/_util.py +1 -1
  81. bec_widgets/widgets/{plots/motor_map/register_bec_motor_map_widget.py → editors/scan_metadata/register_scan_metadata.py} +2 -4
  82. bec_widgets/widgets/editors/scan_metadata/scan_metadata.py +42 -136
  83. bec_widgets/widgets/editors/scan_metadata/scan_metadata.pyproject +1 -0
  84. bec_widgets/widgets/{plots/multi_waveform/bec_multi_waveform_widget_plugin.py → editors/scan_metadata/scan_metadata_plugin.py} +9 -9
  85. bec_widgets/widgets/editors/text_box/text_box.py +2 -3
  86. bec_widgets/widgets/editors/website/website.py +2 -2
  87. bec_widgets/widgets/games/minesweeper.py +3 -2
  88. bec_widgets/widgets/plots/image/image.py +960 -0
  89. bec_widgets/widgets/plots/image/image.pyproject +1 -0
  90. bec_widgets/widgets/plots/image/image_item.py +279 -0
  91. bec_widgets/widgets/plots/{motor_map/bec_motor_map_widget_plugin.py → image/image_plugin.py} +11 -13
  92. bec_widgets/widgets/{containers/figure/plots → plots}/image/image_processor.py +31 -64
  93. bec_widgets/widgets/plots/image/{register_bec_image_widget.py → register_image.py} +2 -2
  94. bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +59 -0
  95. bec_widgets/widgets/plots/image/toolbar_bundles/processing.py +79 -0
  96. bec_widgets/widgets/plots/motor_map/motor_map.py +832 -0
  97. bec_widgets/widgets/plots/motor_map/motor_map.pyproject +1 -0
  98. bec_widgets/widgets/plots/motor_map/motor_map_plugin.py +54 -0
  99. bec_widgets/widgets/plots/{multi_waveform/register_bec_multi_waveform_widget.py → motor_map/register_motor_map.py} +2 -4
  100. bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py +129 -0
  101. bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.ui +120 -0
  102. bec_widgets/widgets/plots/motor_map/toolbar_bundles/motor_selection.py +70 -0
  103. bec_widgets/widgets/plots/multi_waveform/multi_waveform.py +508 -0
  104. bec_widgets/widgets/plots/multi_waveform/multi_waveform.pyproject +1 -0
  105. bec_widgets/widgets/plots/multi_waveform/multi_waveform_plugin.py +54 -0
  106. bec_widgets/widgets/plots/multi_waveform/register_multi_waveform.py +15 -0
  107. bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py +144 -0
  108. bec_widgets/widgets/plots/multi_waveform/settings/multi_waveform_controls.ui +164 -0
  109. bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/monitor_selection.py +65 -0
  110. bec_widgets/widgets/{plots_next_gen → plots}/plot_base.py +321 -40
  111. bec_widgets/widgets/plots/{waveform/register_bec_waveform_widget.py → scatter_waveform/register_scatter_waveform.py} +3 -3
  112. bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +197 -0
  113. bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +553 -0
  114. bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.pyproject +1 -0
  115. bec_widgets/widgets/plots/{image/bec_image_widget_plugin.py → scatter_waveform/scatter_waveform_plugin.py} +9 -13
  116. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +138 -0
  117. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui +195 -0
  118. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui +204 -0
  119. bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings.py +8 -8
  120. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/mouse_interactions.py +4 -18
  121. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/plot_export.py +14 -3
  122. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/roi_bundle.py +6 -1
  123. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/save_state.py +2 -2
  124. bec_widgets/widgets/{containers/figure/plots/waveform/waveform_curve.py → plots/waveform/curve.py} +119 -49
  125. bec_widgets/widgets/plots/waveform/register_waveform.py +15 -0
  126. bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py +125 -0
  127. bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +576 -0
  128. bec_widgets/widgets/plots/waveform/utils/__init__.py +0 -0
  129. bec_widgets/widgets/plots/waveform/utils/roi_manager.py +84 -0
  130. bec_widgets/widgets/plots/waveform/waveform.py +1794 -0
  131. bec_widgets/widgets/plots/waveform/waveform.pyproject +1 -0
  132. bec_widgets/widgets/plots/waveform/{bec_waveform_widget_plugin.py → waveform_plugin.py} +9 -13
  133. bec_widgets/widgets/progress/bec_progressbar/bec_progressbar.py +1 -2
  134. bec_widgets/widgets/progress/ring_progress_bar/ring.py +11 -10
  135. bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py +24 -14
  136. bec_widgets/widgets/services/bec_queue/bec_queue.py +13 -11
  137. bec_widgets/widgets/services/bec_status_box/bec_status_box.py +3 -4
  138. bec_widgets/widgets/services/device_browser/device_browser.py +5 -2
  139. bec_widgets/widgets/services/device_browser/device_item/device_item.py +1 -1
  140. bec_widgets/widgets/utility/logpanel/logpanel.py +36 -17
  141. bec_widgets/widgets/utility/spinbox/decimal_spinbox.py +3 -3
  142. bec_widgets/widgets/utility/visual/color_button/color_button.py +1 -1
  143. bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +4 -6
  144. bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py +4 -8
  145. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/METADATA +3 -3
  146. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/RECORD +168 -153
  147. pyproject.toml +3 -3
  148. bec_widgets/applications/alignment/alignment_1d/alignment_1d.py +0 -198
  149. bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +0 -615
  150. bec_widgets/applications/bec_app.py +0 -84
  151. bec_widgets/cli/auto_updates.py +0 -168
  152. bec_widgets/widgets/containers/figure/__init__.py +0 -1
  153. bec_widgets/widgets/containers/figure/figure.py +0 -796
  154. bec_widgets/widgets/containers/figure/plots/axis_settings.py +0 -91
  155. bec_widgets/widgets/containers/figure/plots/axis_settings.ui +0 -256
  156. bec_widgets/widgets/containers/figure/plots/image/image.py +0 -772
  157. bec_widgets/widgets/containers/figure/plots/image/image_item.py +0 -337
  158. bec_widgets/widgets/containers/figure/plots/motor_map/motor_map.py +0 -525
  159. bec_widgets/widgets/containers/figure/plots/multi_waveform/multi_waveform.py +0 -340
  160. bec_widgets/widgets/containers/figure/plots/plot_base.py +0 -505
  161. bec_widgets/widgets/containers/figure/plots/waveform/waveform.py +0 -1563
  162. bec_widgets/widgets/plots/image/bec_image_widget.pyproject +0 -1
  163. bec_widgets/widgets/plots/image/image_widget.py +0 -515
  164. bec_widgets/widgets/plots/motor_map/bec_motor_map_widget.pyproject +0 -1
  165. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.py +0 -56
  166. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.ui +0 -108
  167. bec_widgets/widgets/plots/motor_map/motor_map_widget.py +0 -234
  168. bec_widgets/widgets/plots/multi_waveform/bec_multi_waveform_widget.pyproject +0 -1
  169. bec_widgets/widgets/plots/multi_waveform/multi_waveform_controls.ui +0 -99
  170. bec_widgets/widgets/plots/multi_waveform/multi_waveform_widget.py +0 -536
  171. bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject +0 -1
  172. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py +0 -336
  173. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui +0 -372
  174. bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py +0 -25
  175. bec_widgets/widgets/plots/waveform/waveform_widget.py +0 -751
  176. /bec_widgets/{qt_utils → utils}/collapsible_panel_manager.py +0 -0
  177. /bec_widgets/{applications/alignment → utils/forms_from_types}/__init__.py +0 -0
  178. /bec_widgets/{qt_utils → utils}/redis_message_waiter.py +0 -0
  179. /bec_widgets/{applications/alignment/alignment_1d → widgets/containers/auto_update}/__init__.py +0 -0
  180. /bec_widgets/{qt_utils → widgets/containers/main_window/addons}/__init__.py +0 -0
  181. /bec_widgets/widgets/{containers/figure/plots → plots/image/toolbar_bundles}/__init__.py +0 -0
  182. /bec_widgets/widgets/{containers/figure/plots/image → plots/motor_map/settings}/__init__.py +0 -0
  183. /bec_widgets/widgets/{containers/figure/plots/motor_map → plots/motor_map/toolbar_bundles}/__init__.py +0 -0
  184. /bec_widgets/widgets/{containers/figure/plots/multi_waveform → plots/multi_waveform/settings}/__init__.py +0 -0
  185. /bec_widgets/widgets/{containers/figure/plots/waveform → plots/multi_waveform/toolbar_bundles}/__init__.py +0 -0
  186. /bec_widgets/widgets/plots/{motor_map/motor_map_dialog → scatter_waveform}/__init__.py +0 -0
  187. /bec_widgets/widgets/plots/{waveform/waveform_popups → scatter_waveform/settings}/__init__.py +0 -0
  188. /bec_widgets/widgets/plots/{waveform/waveform_popups/curve_dialog → setting_menus}/__init__.py +0 -0
  189. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_horizontal.ui +0 -0
  190. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_vertical.ui +0 -0
  191. /bec_widgets/widgets/plots/{waveform/waveform_popups/dap_summary_dialog → toolbar_bundles}/__init__.py +0 -0
  192. /bec_widgets/widgets/{plots_next_gen/setting_menus → plots/waveform/settings}/__init__.py +0 -0
  193. /bec_widgets/widgets/{plots_next_gen/toolbar_bundles → plots/waveform/settings/curve_settings}/__init__.py +0 -0
  194. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/WHEEL +0 -0
  195. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/entry_points.txt +0 -0
  196. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,25 +1,33 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Literal, Optional
3
+ from typing import TYPE_CHECKING, Any, Literal, Optional, cast
4
4
 
5
+ from bec_lib.logger import bec_logger
5
6
  from pydantic import Field
6
7
  from pyqtgraph.dockarea import Dock, DockLabel
7
8
  from qtpy import QtCore, QtGui
8
9
 
10
+ from bec_widgets.cli.client_utils import IGNORE_WIDGETS
9
11
  from bec_widgets.cli.rpc.rpc_widget_handler import widget_handler
10
12
  from bec_widgets.utils import ConnectionConfig, GridLayoutManager
11
13
  from bec_widgets.utils.bec_widget import BECWidget
14
+ from bec_widgets.utils.container_utils import WidgetContainerUtils
15
+ from bec_widgets.utils.error_popups import SafeSlot
12
16
 
13
- if TYPE_CHECKING:
17
+ logger = bec_logger.logger
18
+
19
+ if TYPE_CHECKING: # pragma: no cover
14
20
  from qtpy.QtWidgets import QWidget
15
21
 
22
+ from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
23
+
16
24
 
17
25
  class DockConfig(ConnectionConfig):
18
26
  widgets: dict[str, Any] = Field({}, description="The widgets in the dock.")
19
27
  position: Literal["bottom", "top", "left", "right", "above", "below"] = Field(
20
28
  "bottom", description="The position of the dock."
21
29
  )
22
- parent_dock_area: Optional[str] = Field(
30
+ parent_dock_area: Optional[str] | None = Field(
23
31
  None, description="The GUI ID of parent dock area of the dock."
24
32
  )
25
33
 
@@ -103,16 +111,17 @@ class BECDock(BECWidget, Dock):
103
111
  ICON_NAME = "widgets"
104
112
  USER_ACCESS = [
105
113
  "_config_dict",
106
- "_rpc_id",
107
- "widget_list",
114
+ "element_list",
115
+ "elements",
116
+ "new",
117
+ "show",
118
+ "hide",
108
119
  "show_title_bar",
109
- "hide_title_bar",
110
- "get_widgets_positions",
111
120
  "set_title",
112
- "add_widget",
113
- "list_eligible_widgets",
114
- "move_widget",
115
- "remove_widget",
121
+ "hide_title_bar",
122
+ "available_widgets",
123
+ "delete",
124
+ "delete_all",
116
125
  "remove",
117
126
  "attach",
118
127
  "detach",
@@ -121,29 +130,38 @@ class BECDock(BECWidget, Dock):
121
130
  def __init__(
122
131
  self,
123
132
  parent: QWidget | None = None,
124
- parent_dock_area: QWidget | None = None,
133
+ parent_dock_area: BECDockArea | None = None,
125
134
  config: DockConfig | None = None,
126
135
  name: str | None = None,
136
+ object_name: str | None = None,
127
137
  client=None,
128
138
  gui_id: str | None = None,
129
139
  closable: bool = True,
130
140
  **kwargs,
131
141
  ) -> None:
142
+
132
143
  if config is None:
133
144
  config = DockConfig(
134
- widget_class=self.__class__.__name__, parent_dock_area=parent_dock_area.gui_id
145
+ widget_class=self.__class__.__name__,
146
+ parent_dock_area=parent_dock_area.gui_id if parent_dock_area else None,
135
147
  )
136
148
  else:
137
149
  if isinstance(config, dict):
138
150
  config = DockConfig(**config)
139
151
  self.config = config
140
- super().__init__(client=client, config=config, gui_id=gui_id)
141
152
  label = CustomDockLabel(text=name, closable=closable)
142
- Dock.__init__(self, name=name, label=label, **kwargs)
143
- # Dock.__init__(self, name=name, **kwargs)
153
+ super().__init__(
154
+ parent=parent_dock_area,
155
+ name=name,
156
+ object_name=object_name,
157
+ client=client,
158
+ gui_id=gui_id,
159
+ config=config,
160
+ label=label,
161
+ **kwargs,
162
+ )
144
163
 
145
164
  self.parent_dock_area = parent_dock_area
146
-
147
165
  # Layout Manager
148
166
  self.layout_manager = GridLayoutManager(self.layout)
149
167
 
@@ -173,7 +191,18 @@ class BECDock(BECWidget, Dock):
173
191
  super().float()
174
192
 
175
193
  @property
176
- def widget_list(self) -> list[BECWidget]:
194
+ def elements(self) -> dict[str, BECWidget]:
195
+ """
196
+ Get the widgets in the dock.
197
+
198
+ Returns:
199
+ widgets(dict): The widgets in the dock.
200
+ """
201
+ # pylint: disable=protected-access
202
+ return dict((widget.object_name, widget) for widget in self.element_list)
203
+
204
+ @property
205
+ def element_list(self) -> list[BECWidget]:
177
206
  """
178
207
  Get the widgets in the dock.
179
208
 
@@ -182,10 +211,6 @@ class BECDock(BECWidget, Dock):
182
211
  """
183
212
  return self.widgets
184
213
 
185
- @widget_list.setter
186
- def widget_list(self, value: list[BECWidget]):
187
- self.widgets = value
188
-
189
214
  def hide_title_bar(self):
190
215
  """
191
216
  Hide the title bar of the dock.
@@ -194,6 +219,20 @@ class BECDock(BECWidget, Dock):
194
219
  self.label.hide()
195
220
  self.labelHidden = True
196
221
 
222
+ def show(self):
223
+ """
224
+ Show the dock.
225
+ """
226
+ super().show()
227
+ self.show_title_bar()
228
+
229
+ def hide(self):
230
+ """
231
+ Hide the dock.
232
+ """
233
+ self.hide_title_bar()
234
+ super().hide()
235
+
197
236
  def show_title_bar(self):
198
237
  """
199
238
  Hide the title bar of the dock.
@@ -211,7 +250,6 @@ class BECDock(BECWidget, Dock):
211
250
  """
212
251
  self.orig_area.docks[title] = self.orig_area.docks.pop(self.name())
213
252
  self.setTitle(title)
214
- self._name = title
215
253
 
216
254
  def get_widgets_positions(self) -> dict:
217
255
  """
@@ -222,7 +260,7 @@ class BECDock(BECWidget, Dock):
222
260
  """
223
261
  return self.layout_manager.get_widgets_positions()
224
262
 
225
- def list_eligible_widgets(
263
+ def available_widgets(
226
264
  self,
227
265
  ) -> list: # TODO can be moved to some util mixin like container class for rpc widgets
228
266
  """
@@ -233,42 +271,69 @@ class BECDock(BECWidget, Dock):
233
271
  """
234
272
  return list(widget_handler.widget_classes.keys())
235
273
 
236
- def add_widget(
274
+ def _get_list_of_widget_name_of_parent_dock_area(self) -> list[str]:
275
+ if (docks := self.parent_dock_area.panel_list) is None:
276
+ return []
277
+ widgets = []
278
+ for dock in docks:
279
+ widgets.extend(dock.elements.keys())
280
+ return widgets
281
+
282
+ @SafeSlot(popup_error=True)
283
+ def new(
237
284
  self,
238
285
  widget: BECWidget | str,
239
- row=None,
240
- col=0,
241
- rowspan=1,
242
- colspan=1,
286
+ name: str | None = None,
287
+ row: int | None = None,
288
+ col: int = 0,
289
+ rowspan: int = 1,
290
+ colspan: int = 1,
243
291
  shift: Literal["down", "up", "left", "right"] = "down",
244
292
  ) -> BECWidget:
245
293
  """
246
294
  Add a widget to the dock.
247
295
 
248
296
  Args:
249
- widget(QWidget): The widget to add.
297
+ widget(QWidget): The widget to add. It can not be BECDock or BECDockArea.
298
+ name(str): The name of the widget.
250
299
  row(int): The row to add the widget to. If None, the widget will be added to the next available row.
251
300
  col(int): The column to add the widget to.
252
301
  rowspan(int): The number of rows the widget should span.
253
302
  colspan(int): The number of columns the widget should span.
254
303
  shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied.
255
304
  """
305
+ if name is not None:
306
+ if not WidgetContainerUtils.has_name_valid_chars(name):
307
+ raise ValueError(
308
+ f"Name {name} contains invalid characters. "
309
+ f"Only alphanumeric characters and underscores are allowed."
310
+ )
311
+
256
312
  if row is None:
257
313
  row = self.layout.rowCount()
258
314
 
259
315
  if self.layout_manager.is_position_occupied(row, col):
260
316
  self.layout_manager.shift_widgets(shift, start_row=row)
261
317
 
318
+ # Check that Widget is not BECDock or BECDockArea
319
+ widget_class_name = widget if isinstance(widget, str) else widget.__class__.__name__
320
+ if widget_class_name in IGNORE_WIDGETS:
321
+ raise ValueError(f"Widget {widget} can not be added to dock.")
322
+
262
323
  if isinstance(widget, str):
263
- widget = widget_handler.create_widget(widget)
324
+ widget = cast(
325
+ BECWidget,
326
+ widget_handler.create_widget(
327
+ widget_type=widget, object_name=name, parent_dock=self, parent=self
328
+ ),
329
+ )
264
330
  else:
265
- widget = widget
331
+ widget.object_name = name
266
332
 
267
333
  self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
268
-
269
334
  if hasattr(widget, "config"):
270
- self.config.widgets[widget.gui_id] = widget.config
271
-
335
+ widget.config.gui_id = widget.gui_id
336
+ self.config.widgets[widget.object_name] = widget.config
272
337
  return widget
273
338
 
274
339
  def move_widget(self, widget: QWidget, new_row: int, new_col: int):
@@ -294,36 +359,68 @@ class BECDock(BECWidget, Dock):
294
359
  """
295
360
  self.float()
296
361
 
297
- def remove_widget(self, widget_rpc_id: str):
362
+ def remove(self):
363
+ """
364
+ Remove the dock from the parent dock area.
365
+ """
366
+ self.parent_dock_area.delete(self.object_name)
367
+
368
+ def delete(self, widget_name: str) -> None:
298
369
  """
299
370
  Remove a widget from the dock.
300
371
 
301
372
  Args:
302
- widget_rpc_id(str): The ID of the widget to remove.
373
+ widget_name(str): Delete the widget with the given name.
303
374
  """
304
- widget = self.rpc_register.get_rpc_by_id(widget_rpc_id)
375
+ # pylint: disable=protected-access
376
+ widgets = [widget for widget in self.widgets if widget.object_name == widget_name]
377
+ if len(widgets) == 0:
378
+ logger.warning(
379
+ f"Widget with name {widget_name} not found in dock {self.name()}. "
380
+ f"Checking if gui_id was passed as widget_name."
381
+ )
382
+ # Try to find the widget in the RPC register, maybe the gui_id was passed as widget_name
383
+ widget = self.rpc_register.get_rpc_by_id(widget_name)
384
+ if widget is None:
385
+ logger.warning(
386
+ f"Widget not found for name or gui_id: {widget_name} in dock {self.name()}"
387
+ )
388
+ return
389
+ else:
390
+ widget = widgets[0]
305
391
  self.layout.removeWidget(widget)
306
- self.config.widgets.pop(widget_rpc_id, None)
392
+ self.config.widgets.pop(widget.object_name, None)
393
+ if widget in self.widgets:
394
+ self.widgets.remove(widget)
307
395
  widget.close()
308
396
 
309
- def remove(self):
397
+ def delete_all(self):
310
398
  """
311
- Remove the dock from the parent dock area.
399
+ Remove all widgets from the dock.
312
400
  """
313
- # self.cleanup()
314
- self.parent_dock_area.remove_dock(self.name())
401
+ for widget in self.widgets:
402
+ self.delete(widget.object_name)
315
403
 
316
404
  def cleanup(self):
317
405
  """
318
406
  Clean up the dock, including all its widgets.
319
407
  """
320
- for widget in self.widgets:
321
- if hasattr(widget, "cleanup"):
322
- widget.cleanup()
408
+ # # FIXME Cleanup might be called twice
409
+ try:
410
+ logger.info(f"Cleaning up dock {self.name()}")
411
+ self.label.close()
412
+ self.label.deleteLater()
413
+ except Exception as e:
414
+ logger.error(f"Error while closing dock label: {e}")
415
+
416
+ # Remove the dock from the parent dock area
417
+ if self.parent_dock_area:
418
+ self.parent_dock_area.dock_area.docks.pop(self.name(), None)
419
+ self.parent_dock_area.config.docks.pop(self.name(), None)
420
+ self.delete_all()
323
421
  self.widgets.clear()
324
- self.label.close()
325
- self.label.deleteLater()
326
422
  super().cleanup()
423
+ self.deleteLater()
327
424
 
328
425
  def close(self):
329
426
  """
@@ -332,4 +429,15 @@ class BECDock(BECWidget, Dock):
332
429
  """
333
430
  self.cleanup()
334
431
  super().close()
335
- self.parent_dock_area.dock_area.docks.pop(self.name(), None)
432
+
433
+
434
+ if __name__ == "__main__": # pragma: no cover
435
+ import sys
436
+
437
+ from qtpy.QtWidgets import QApplication
438
+
439
+ app = QApplication([])
440
+ dock = BECDock(name="dock")
441
+ dock.show()
442
+ app.exec_()
443
+ sys.exit(app.exec_())