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
@@ -6,8 +6,8 @@
6
6
  <rect>
7
7
  <x>0</x>
8
8
  <y>0</y>
9
- <width>326</width>
10
- <height>323</height>
9
+ <width>402</width>
10
+ <height>394</height>
11
11
  </rect>
12
12
  </property>
13
13
  <property name="windowTitle">
@@ -23,7 +23,7 @@
23
23
  <property name="title">
24
24
  <string>No positioner selected</string>
25
25
  </property>
26
- <layout class="QGridLayout" name="gridLayout_6" rowstretch="0,0,0,0,0,0">
26
+ <layout class="QGridLayout" name="gridLayout_6" rowstretch="0,0,0,0,0,0,0">
27
27
  <property name="topMargin">
28
28
  <number>0</number>
29
29
  </property>
@@ -40,15 +40,38 @@
40
40
  </widget>
41
41
  </item>
42
42
  <item>
43
- <widget class="QLabel" name="readback_ver">
44
- <property name="text">
45
- <string>Position</string>
43
+ <spacer name="horizontalSpacer_18">
44
+ <property name="orientation">
45
+ <enum>Qt::Orientation::Horizontal</enum>
46
46
  </property>
47
- <property name="alignment">
48
- <set>Qt::AlignmentFlag::AlignCenter</set>
47
+ <property name="sizeHint" stdset="0">
48
+ <size>
49
+ <width>40</width>
50
+ <height>20</height>
51
+ </size>
52
+ </property>
53
+ </spacer>
54
+ </item>
55
+ <item>
56
+ <widget class="QLabel" name="units_ver">
57
+ <property name="text">
58
+ <string/>
49
59
  </property>
50
60
  </widget>
51
61
  </item>
62
+ <item>
63
+ <spacer name="horizontalSpacer_19">
64
+ <property name="orientation">
65
+ <enum>Qt::Orientation::Horizontal</enum>
66
+ </property>
67
+ <property name="sizeHint" stdset="0">
68
+ <size>
69
+ <width>40</width>
70
+ <height>20</height>
71
+ </size>
72
+ </property>
73
+ </spacer>
74
+ </item>
52
75
  <item>
53
76
  <widget class="SpinnerWidget" name="spinner_widget_ver">
54
77
  <property name="minimumSize">
@@ -67,20 +90,7 @@
67
90
  </item>
68
91
  </layout>
69
92
  </item>
70
- <item row="2" column="0">
71
- <widget class="QLineEdit" name="setpoint_ver">
72
- <property name="enabled">
73
- <bool>false</bool>
74
- </property>
75
- <property name="focusPolicy">
76
- <enum>Qt::FocusPolicy::StrongFocus</enum>
77
- </property>
78
- <property name="alignment">
79
- <set>Qt::AlignmentFlag::AlignCenter</set>
80
- </property>
81
- </widget>
82
- </item>
83
- <item row="5" column="0">
93
+ <item row="6" column="0">
84
94
  <layout class="QHBoxLayout" name="horizontalLayout_6">
85
95
  <item>
86
96
  <widget class="QDoubleSpinBox" name="step_size_ver">
@@ -94,6 +104,29 @@
94
104
  </item>
95
105
  </layout>
96
106
  </item>
107
+ <item row="3" column="0">
108
+ <widget class="QLineEdit" name="setpoint_ver">
109
+ <property name="enabled">
110
+ <bool>false</bool>
111
+ </property>
112
+ <property name="focusPolicy">
113
+ <enum>Qt::FocusPolicy::StrongFocus</enum>
114
+ </property>
115
+ <property name="alignment">
116
+ <set>Qt::AlignmentFlag::AlignCenter</set>
117
+ </property>
118
+ </widget>
119
+ </item>
120
+ <item row="2" column="0">
121
+ <widget class="QLabel" name="readback_ver">
122
+ <property name="text">
123
+ <string>Position</string>
124
+ </property>
125
+ <property name="alignment">
126
+ <set>Qt::AlignmentFlag::AlignCenter</set>
127
+ </property>
128
+ </widget>
129
+ </item>
97
130
  </layout>
98
131
  </widget>
99
132
  </item>
@@ -132,15 +165,38 @@
132
165
  </widget>
133
166
  </item>
134
167
  <item>
135
- <widget class="QLabel" name="readback_hor">
136
- <property name="text">
137
- <string>Position</string>
168
+ <spacer name="horizontalSpacer_9">
169
+ <property name="orientation">
170
+ <enum>Qt::Orientation::Horizontal</enum>
138
171
  </property>
139
- <property name="alignment">
140
- <set>Qt::AlignmentFlag::AlignCenter</set>
172
+ <property name="sizeHint" stdset="0">
173
+ <size>
174
+ <width>40</width>
175
+ <height>20</height>
176
+ </size>
177
+ </property>
178
+ </spacer>
179
+ </item>
180
+ <item>
181
+ <widget class="QLabel" name="units_hor">
182
+ <property name="text">
183
+ <string/>
141
184
  </property>
142
185
  </widget>
143
186
  </item>
187
+ <item>
188
+ <spacer name="horizontalSpacer_13">
189
+ <property name="orientation">
190
+ <enum>Qt::Orientation::Horizontal</enum>
191
+ </property>
192
+ <property name="sizeHint" stdset="0">
193
+ <size>
194
+ <width>40</width>
195
+ <height>20</height>
196
+ </size>
197
+ </property>
198
+ </spacer>
199
+ </item>
144
200
  <item>
145
201
  <widget class="SpinnerWidget" name="spinner_widget_hor">
146
202
  <property name="minimumSize">
@@ -173,6 +229,16 @@
173
229
  </item>
174
230
  </layout>
175
231
  </item>
232
+ <item row="2" column="0">
233
+ <widget class="QLabel" name="readback_hor">
234
+ <property name="text">
235
+ <string>Position</string>
236
+ </property>
237
+ <property name="alignment">
238
+ <set>Qt::AlignmentFlag::AlignCenter</set>
239
+ </property>
240
+ </widget>
241
+ </item>
176
242
  </layout>
177
243
  </widget>
178
244
  </item>
@@ -526,14 +592,14 @@
526
592
  </widget>
527
593
  <customwidgets>
528
594
  <customwidget>
529
- <class>StopButton</class>
595
+ <class>PositionIndicator</class>
530
596
  <extends>QWidget</extends>
531
- <header>stop_button</header>
597
+ <header>position_indicator</header>
532
598
  </customwidget>
533
599
  <customwidget>
534
- <class>PositionIndicator</class>
600
+ <class>StopButton</class>
535
601
  <extends>QWidget</extends>
536
- <header>position_indicator</header>
602
+ <header>stop_button</header>
537
603
  </customwidget>
538
604
  <customwidget>
539
605
  <class>SpinnerWidget</class>
@@ -116,6 +116,13 @@
116
116
  </property>
117
117
  </widget>
118
118
  </item>
119
+ <item>
120
+ <widget class="QLabel" name="units">
121
+ <property name="text">
122
+ <string>TextLabel</string>
123
+ </property>
124
+ </widget>
125
+ </item>
119
126
  </layout>
120
127
  </item>
121
128
  <item>
@@ -219,14 +226,14 @@
219
226
  </widget>
220
227
  <customwidgets>
221
228
  <customwidget>
222
- <class>SpinnerWidget</class>
229
+ <class>PositionIndicator</class>
223
230
  <extends>QWidget</extends>
224
- <header>spinner_widget</header>
231
+ <header>position_indicator</header>
225
232
  </customwidget>
226
233
  <customwidget>
227
- <class>PositionIndicator</class>
234
+ <class>SpinnerWidget</class>
228
235
  <extends>QWidget</extends>
229
- <header>position_indicator</header>
236
+ <header>spinner_widget</header>
230
237
  </customwidget>
231
238
  </customwidgets>
232
239
  <resources/>
@@ -7,8 +7,8 @@ from bec_lib.logger import bec_logger
7
7
  from qtpy.QtCore import QSize, Signal
8
8
  from qtpy.QtWidgets import QGridLayout, QGroupBox, QVBoxLayout, QWidget
9
9
 
10
- from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
11
10
  from bec_widgets.utils.bec_widget import BECWidget
11
+ from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
12
12
  from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox
13
13
 
14
14
  logger = bec_logger.logger
@@ -69,8 +69,7 @@ class PositionerGroup(BECWidget, QWidget):
69
69
  Args:
70
70
  parent: The parent widget.
71
71
  """
72
- super().__init__(**kwargs)
73
- QWidget.__init__(self, parent)
72
+ super().__init__(parent=parent, **kwargs)
74
73
 
75
74
  self.get_bec_shortcuts()
76
75
 
@@ -5,6 +5,7 @@ import enum
5
5
  from bec_lib.device import ComputedSignal, Device, Positioner, ReadoutPriority
6
6
  from bec_lib.device import Signal as BECSignal
7
7
  from bec_lib.logger import bec_logger
8
+ from pydantic import field_validator
8
9
  from qtpy.QtCore import Property, Signal, Slot
9
10
 
10
11
  from bec_widgets.utils import ConnectionConfig
@@ -25,13 +26,35 @@ class BECDeviceFilter(enum.Enum):
25
26
 
26
27
 
27
28
  class DeviceInputConfig(ConnectionConfig):
28
- device_filter: list[BECDeviceFilter] = []
29
- readout_filter: list[ReadoutPriority] = []
29
+ device_filter: list[str] = []
30
+ readout_filter: list[str] = []
30
31
  devices: list[str] = []
31
32
  default: str | None = None
32
33
  arg_name: str | None = None
33
34
  apply_filter: bool = True
34
35
 
36
+ @field_validator("device_filter")
37
+ @classmethod
38
+ def check_device_filter(cls, v, values):
39
+ valid_device_filters = [entry.value for entry in BECDeviceFilter]
40
+ for filt in v:
41
+ if filt not in valid_device_filters:
42
+ raise ValueError(
43
+ f"Device filter {filt} is not a valid device filter {valid_device_filters}."
44
+ )
45
+ return v
46
+
47
+ @field_validator("readout_filter")
48
+ @classmethod
49
+ def check_readout_filter(cls, v, values):
50
+ valid_device_filters = [entry.value for entry in ReadoutPriority]
51
+ for filt in v:
52
+ if filt not in valid_device_filters:
53
+ raise ValueError(
54
+ f"Device filter {filt} is not a valid device filter {valid_device_filters}."
55
+ )
56
+ return v
57
+
35
58
 
36
59
  class DeviceInputBase(BECWidget):
37
60
  """
@@ -59,7 +82,7 @@ class DeviceInputBase(BECWidget):
59
82
  ReadoutPriority.ON_REQUEST: "readout_on_request",
60
83
  }
61
84
 
62
- def __init__(self, client=None, config=None, gui_id: str | None = None, **kwargs):
85
+ def __init__(self, parent=None, client=None, config=None, gui_id: str | None = None, **kwargs):
63
86
 
64
87
  if config is None:
65
88
  config = DeviceInputConfig(widget_class=self.__class__.__name__)
@@ -67,7 +90,9 @@ class DeviceInputBase(BECWidget):
67
90
  if isinstance(config, dict):
68
91
  config = DeviceInputConfig(**config)
69
92
  self.config = config
70
- super().__init__(client=client, config=config, gui_id=gui_id, theme_update=True, **kwargs)
93
+ super().__init__(
94
+ parent=parent, client=client, config=config, gui_id=gui_id, theme_update=True, **kwargs
95
+ )
71
96
  self.get_bec_shortcuts()
72
97
  self._device_filter = []
73
98
  self._readout_filter = []
@@ -29,6 +29,7 @@ class DeviceSignalInputBase(BECWidget):
29
29
  signal object based on the current text of the widget.
30
30
  """
31
31
 
32
+ RPC = False
32
33
  _filter_handler = {
33
34
  Kind.hinted: "include_hinted_signals",
34
35
  Kind.normal: "include_normal_signals",
@@ -47,8 +47,7 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
47
47
  arg_name: str | None = None,
48
48
  **kwargs,
49
49
  ):
50
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
51
- QComboBox.__init__(self, parent=parent)
50
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
52
51
  if arg_name is not None:
53
52
  self.config.arg_name = arg_name
54
53
  self.arg_name = arg_name
@@ -104,6 +103,7 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
104
103
  """Cleanup the widget."""
105
104
  if self._callback_id is not None:
106
105
  self.bec_dispatcher.client.callbacks.remove(self._callback_id)
106
+ super().cleanup()
107
107
 
108
108
  def get_current_device(self) -> object:
109
109
  """
@@ -53,8 +53,7 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
53
53
  self._callback_id = None
54
54
  self._is_valid_input = False
55
55
  self._accent_colors = get_accent_colors()
56
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
57
- QLineEdit.__init__(self, parent=parent)
56
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
58
57
  self.completer = QCompleter(self)
59
58
  self.setCompleter(self.completer)
60
59
 
@@ -111,6 +110,7 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
111
110
  """Cleanup the widget."""
112
111
  if self._callback_id is not None:
113
112
  self.bec_dispatcher.client.callbacks.remove(self._callback_id)
113
+ super().cleanup()
114
114
 
115
115
  def get_current_device(self) -> object:
116
116
  """
@@ -40,8 +40,7 @@ class SignalComboBox(DeviceSignalInputBase, QComboBox):
40
40
  arg_name: str | None = None,
41
41
  **kwargs,
42
42
  ):
43
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
44
- QComboBox.__init__(self, parent=parent)
43
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
45
44
  if arg_name is not None:
46
45
  self.config.arg_name = arg_name
47
46
  self.arg_name = arg_name
@@ -42,8 +42,7 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
42
42
  **kwargs,
43
43
  ):
44
44
  self._is_valid_input = False
45
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
46
- QLineEdit.__init__(self, parent=parent)
45
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
47
46
  self._accent_colors = get_accent_colors()
48
47
  self.completer = QCompleter(self)
49
48
  self.setCompleter(self.completer)
@@ -18,10 +18,10 @@ from qtpy.QtWidgets import (
18
18
  QWidget,
19
19
  )
20
20
 
21
- from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
22
21
  from bec_widgets.utils import ConnectionConfig
23
22
  from bec_widgets.utils.bec_widget import BECWidget
24
23
  from bec_widgets.utils.colors import get_accent_colors
24
+ from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
25
25
  from bec_widgets.widgets.control.buttons.stop_button.stop_button import StopButton
26
26
  from bec_widgets.widgets.control.scan_control.scan_group_box import ScanGroupBox
27
27
  from bec_widgets.widgets.editors.scan_metadata.scan_metadata import ScanMetadata
@@ -41,6 +41,10 @@ class ScanControlConfig(ConnectionConfig):
41
41
 
42
42
 
43
43
  class ScanControl(BECWidget, QWidget):
44
+ """
45
+ Widget to submit new scans to the queue.
46
+ """
47
+
44
48
  PLUGIN = True
45
49
  ICON_NAME = "tune"
46
50
  ARG_BOX_POSITION: int = 2
@@ -60,13 +64,11 @@ class ScanControl(BECWidget, QWidget):
60
64
  default_scan: str | None = None,
61
65
  **kwargs,
62
66
  ):
63
-
64
67
  if config is None:
65
68
  config = ScanControlConfig(
66
69
  widget_class=self.__class__.__name__, allowed_scans=allowed_scans
67
70
  )
68
- super().__init__(client=client, gui_id=gui_id, config=config, **kwargs)
69
- QWidget.__init__(self, parent=parent)
71
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
70
72
 
71
73
  self._hide_add_remove_buttons = False
72
74
 
@@ -163,7 +165,7 @@ class ScanControl(BECWidget, QWidget):
163
165
  self.layout.addStretch()
164
166
 
165
167
  def _add_metadata_form(self):
166
- self._metadata_form = ScanMetadata()
168
+ self._metadata_form = ScanMetadata(parent=self)
167
169
  self.layout.addWidget(self._metadata_form)
168
170
  self._metadata_form.update_with_new_scan(self.comboBox_scan_selection.currentText())
169
171
  self.scan_selected.connect(self._metadata_form.update_with_new_scan)
@@ -234,7 +234,7 @@ class ScanGroupBox(QGroupBox):
234
234
  continue
235
235
  if default == "_empty":
236
236
  default = None
237
- widget = widget_class(arg_name=arg_name, default=default)
237
+ widget = widget_class(parent=self.parent(), arg_name=arg_name, default=default)
238
238
  if isinstance(widget, DeviceLineEdit):
239
239
  widget.set_device_filter(BECDeviceFilter.DEVICE)
240
240
  self.selected_devices[widget] = ""
@@ -274,12 +274,24 @@ class ScanGroupBox(QGroupBox):
274
274
  for widget in self.widgets[-len(self.inputs) :]:
275
275
  if isinstance(widget, DeviceLineEdit):
276
276
  self.selected_devices[widget] = ""
277
+ widget.close()
277
278
  widget.deleteLater()
278
279
  self.widgets = self.widgets[: -len(self.inputs)]
279
280
 
280
281
  selected_devices_str = " ".join(self.selected_devices.values())
281
282
  self.device_selected.emit(selected_devices_str.strip())
282
283
 
284
+ def remove_all_widget_bundles(self):
285
+ """Remove every widget bundle from the scan control layout."""
286
+ for widget in list(self.widgets):
287
+ if isinstance(widget, DeviceLineEdit):
288
+ self.selected_devices.pop(widget, None)
289
+ widget.close()
290
+ widget.deleteLater()
291
+ self.layout.removeWidget(widget)
292
+ self.widgets.clear()
293
+ self.device_selected.emit("")
294
+
283
295
  @Property(bool)
284
296
  def hide_add_remove_buttons(self):
285
297
  return self._hide_add_remove_buttons
@@ -348,10 +360,21 @@ class ScanGroupBox(QGroupBox):
348
360
  self._set_kwarg_parameters(parameters)
349
361
 
350
362
  def _set_arg_parameters(self, parameters: list):
351
- while len(parameters) != len(self.widgets):
352
- self.add_widget_bundle()
353
- for i, parameter in enumerate(parameters):
354
- WidgetIO.set_value(self.widgets[i], parameter)
363
+ self.remove_all_widget_bundles()
364
+ if not parameters:
365
+ return
366
+
367
+ inputs_per_bundle = len(self.inputs)
368
+ if inputs_per_bundle == 0:
369
+ return
370
+
371
+ bundles_needed = -(-len(parameters) // inputs_per_bundle)
372
+
373
+ for row in range(1, bundles_needed + 1):
374
+ self.add_input_widgets(self.inputs, row)
375
+
376
+ for i, value in enumerate(parameters):
377
+ WidgetIO.set_value(self.widgets[i], value)
355
378
 
356
379
  def _set_kwarg_parameters(self, parameters: dict):
357
380
  for widget in self.widgets:
@@ -44,8 +44,7 @@ class DapComboBox(BECWidget, QWidget):
44
44
  default_fit: str | None = None,
45
45
  **kwargs,
46
46
  ):
47
- super().__init__(client=client, gui_id=gui_id, **kwargs)
48
- QWidget.__init__(self, parent=parent)
47
+ super().__init__(parent=parent, client=client, gui_id=gui_id, **kwargs)
49
48
  self.layout = QVBoxLayout(self)
50
49
  self.fit_model_combobox = QComboBox(self)
51
50
  self.layout.addWidget(self.fit_model_combobox)
@@ -4,10 +4,10 @@ from bec_lib.logger import bec_logger
4
4
  from qtpy.QtCore import Signal
5
5
  from qtpy.QtWidgets import QPushButton, QTreeWidgetItem, QVBoxLayout, QWidget
6
6
 
7
- from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
8
7
  from bec_widgets.utils import UILoader
9
8
  from bec_widgets.utils.bec_widget import BECWidget
10
9
  from bec_widgets.utils.colors import get_accent_colors
10
+ from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
11
11
 
12
12
  logger = bec_logger.logger
13
13
 
@@ -17,6 +17,7 @@ class LMFitDialog(BECWidget, QWidget):
17
17
 
18
18
  PLUGIN = True
19
19
  ICON_NAME = "monitoring"
20
+ RPC = False
20
21
  # Signal to emit the currently selected fit curve_id
21
22
  selected_fit = Signal(str)
22
23
  # Signal to emit a move action in form of a tuple (param_name, value)
@@ -43,10 +44,8 @@ class LMFitDialog(BECWidget, QWidget):
43
44
  gui_id (str): GUI ID.
44
45
  ui_file (str): The UI file to be loaded.
45
46
  """
46
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
47
- QWidget.__init__(self, parent=parent)
47
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
48
48
  self.setProperty("skip_settings", True)
49
- self.setObjectName("LMFitDialog")
50
49
  self._ui_file = ui_file
51
50
  self.target_widget = target_widget
52
51
 
@@ -6,12 +6,12 @@
6
6
  <rect>
7
7
  <x>0</x>
8
8
  <y>0</y>
9
- <width>303</width>
10
- <height>457</height>
9
+ <width>337</width>
10
+ <height>552</height>
11
11
  </rect>
12
12
  </property>
13
13
  <property name="sizePolicy">
14
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
14
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
15
15
  <horstretch>0</horstretch>
16
16
  <verstretch>0</verstretch>
17
17
  </sizepolicy>
@@ -35,11 +35,17 @@
35
35
  <item>
36
36
  <widget class="QGroupBox" name="group_curve_selection">
37
37
  <property name="sizePolicy">
38
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
38
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
39
39
  <horstretch>0</horstretch>
40
40
  <verstretch>0</verstretch>
41
41
  </sizepolicy>
42
42
  </property>
43
+ <property name="minimumSize">
44
+ <size>
45
+ <width>0</width>
46
+ <height>100</height>
47
+ </size>
48
+ </property>
43
49
  <property name="title">
44
50
  <string>Select Curve</string>
45
51
  </property>
@@ -60,7 +66,7 @@
60
66
  <item>
61
67
  <widget class="QGroupBox" name="group_summary">
62
68
  <property name="sizePolicy">
63
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
69
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
64
70
  <horstretch>0</horstretch>
65
71
  <verstretch>0</verstretch>
66
72
  </sizepolicy>
@@ -68,7 +74,7 @@
68
74
  <property name="minimumSize">
69
75
  <size>
70
76
  <width>0</width>
71
- <height>0</height>
77
+ <height>200</height>
72
78
  </size>
73
79
  </property>
74
80
  <property name="title">
@@ -113,7 +119,7 @@
113
119
  <item>
114
120
  <widget class="QGroupBox" name="group_parameters">
115
121
  <property name="sizePolicy">
116
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
122
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
117
123
  <horstretch>0</horstretch>
118
124
  <verstretch>0</verstretch>
119
125
  </sizepolicy>
@@ -121,7 +127,7 @@
121
127
  <property name="minimumSize">
122
128
  <size>
123
129
  <width>0</width>
124
- <height>0</height>
130
+ <height>200</height>
125
131
  </size>
126
132
  </property>
127
133
  <property name="title">
@@ -25,7 +25,7 @@ from qtpy.QtCore import Signal as pyqtSignal
25
25
  from qtpy.QtGui import QClipboard, QColor, QPalette, QTextCursor
26
26
  from qtpy.QtWidgets import QApplication, QHBoxLayout, QScrollBar, QSizePolicy
27
27
 
28
- from bec_widgets.qt_utils.error_popups import SafeSlot as Slot
28
+ from bec_widgets.utils.error_popups import SafeSlot as Slot
29
29
 
30
30
  ansi_colors = {
31
31
  "black": "#000000",