bec-widgets 1.25.0__py3-none-any.whl → 2.0.0__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 (197) hide show
  1. .gitlab-ci.yml +11 -6
  2. CHANGELOG.md +650 -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 +186 -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 +37 -18
  60. bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +28 -4
  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/spinner/spinner.py +2 -2
  143. bec_widgets/widgets/utility/visual/color_button/color_button.py +1 -1
  144. bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +4 -6
  145. bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py +4 -8
  146. {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/METADATA +3 -3
  147. {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/RECORD +169 -154
  148. pyproject.toml +3 -3
  149. bec_widgets/applications/alignment/alignment_1d/alignment_1d.py +0 -198
  150. bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +0 -615
  151. bec_widgets/applications/bec_app.py +0 -84
  152. bec_widgets/cli/auto_updates.py +0 -168
  153. bec_widgets/widgets/containers/figure/__init__.py +0 -1
  154. bec_widgets/widgets/containers/figure/figure.py +0 -796
  155. bec_widgets/widgets/containers/figure/plots/axis_settings.py +0 -91
  156. bec_widgets/widgets/containers/figure/plots/axis_settings.ui +0 -256
  157. bec_widgets/widgets/containers/figure/plots/image/image.py +0 -772
  158. bec_widgets/widgets/containers/figure/plots/image/image_item.py +0 -337
  159. bec_widgets/widgets/containers/figure/plots/motor_map/motor_map.py +0 -525
  160. bec_widgets/widgets/containers/figure/plots/multi_waveform/multi_waveform.py +0 -340
  161. bec_widgets/widgets/containers/figure/plots/plot_base.py +0 -505
  162. bec_widgets/widgets/containers/figure/plots/waveform/waveform.py +0 -1563
  163. bec_widgets/widgets/plots/image/bec_image_widget.pyproject +0 -1
  164. bec_widgets/widgets/plots/image/image_widget.py +0 -515
  165. bec_widgets/widgets/plots/motor_map/bec_motor_map_widget.pyproject +0 -1
  166. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.py +0 -56
  167. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.ui +0 -108
  168. bec_widgets/widgets/plots/motor_map/motor_map_widget.py +0 -234
  169. bec_widgets/widgets/plots/multi_waveform/bec_multi_waveform_widget.pyproject +0 -1
  170. bec_widgets/widgets/plots/multi_waveform/multi_waveform_controls.ui +0 -99
  171. bec_widgets/widgets/plots/multi_waveform/multi_waveform_widget.py +0 -536
  172. bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject +0 -1
  173. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py +0 -336
  174. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui +0 -372
  175. bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py +0 -25
  176. bec_widgets/widgets/plots/waveform/waveform_widget.py +0 -751
  177. /bec_widgets/{qt_utils → utils}/collapsible_panel_manager.py +0 -0
  178. /bec_widgets/{applications/alignment → utils/forms_from_types}/__init__.py +0 -0
  179. /bec_widgets/{qt_utils → utils}/redis_message_waiter.py +0 -0
  180. /bec_widgets/{applications/alignment/alignment_1d → widgets/containers/auto_update}/__init__.py +0 -0
  181. /bec_widgets/{qt_utils → widgets/containers/main_window/addons}/__init__.py +0 -0
  182. /bec_widgets/widgets/{containers/figure/plots → plots/image/toolbar_bundles}/__init__.py +0 -0
  183. /bec_widgets/widgets/{containers/figure/plots/image → plots/motor_map/settings}/__init__.py +0 -0
  184. /bec_widgets/widgets/{containers/figure/plots/motor_map → plots/motor_map/toolbar_bundles}/__init__.py +0 -0
  185. /bec_widgets/widgets/{containers/figure/plots/multi_waveform → plots/multi_waveform/settings}/__init__.py +0 -0
  186. /bec_widgets/widgets/{containers/figure/plots/waveform → plots/multi_waveform/toolbar_bundles}/__init__.py +0 -0
  187. /bec_widgets/widgets/plots/{motor_map/motor_map_dialog → scatter_waveform}/__init__.py +0 -0
  188. /bec_widgets/widgets/plots/{waveform/waveform_popups → scatter_waveform/settings}/__init__.py +0 -0
  189. /bec_widgets/widgets/plots/{waveform/waveform_popups/curve_dialog → setting_menus}/__init__.py +0 -0
  190. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_horizontal.ui +0 -0
  191. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_vertical.ui +0 -0
  192. /bec_widgets/widgets/plots/{waveform/waveform_popups/dap_summary_dialog → toolbar_bundles}/__init__.py +0 -0
  193. /bec_widgets/widgets/{plots_next_gen/setting_menus → plots/waveform/settings}/__init__.py +0 -0
  194. /bec_widgets/widgets/{plots_next_gen/toolbar_bundles → plots/waveform/settings/curve_settings}/__init__.py +0 -0
  195. {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/WHEEL +0 -0
  196. {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/entry_points.txt +0 -0
  197. {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1 @@
1
+ {'files': ['waveform.py']}
@@ -1,43 +1,39 @@
1
1
  # Copyright (C) 2022 The Qt Company Ltd.
2
2
  # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
- import os
4
3
 
5
4
  from qtpy.QtDesigner import QDesignerCustomWidgetInterface
6
5
 
7
- import bec_widgets
8
6
  from bec_widgets.utils.bec_designer import designer_material_icon
9
- from bec_widgets.widgets.plots.waveform.waveform_widget import BECWaveformWidget
7
+ from bec_widgets.widgets.plots.waveform.waveform import Waveform
10
8
 
11
9
  DOM_XML = """
12
10
  <ui language='c++'>
13
- <widget class='BECWaveformWidget' name='bec_waveform_widget'>
11
+ <widget class='Waveform' name='waveform'>
14
12
  </widget>
15
13
  </ui>
16
14
  """
17
15
 
18
- MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
16
 
20
-
21
- class BECWaveformWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
17
+ class WaveformPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
22
18
  def __init__(self):
23
19
  super().__init__()
24
20
  self._form_editor = None
25
21
 
26
22
  def createWidget(self, parent):
27
- t = BECWaveformWidget(parent)
23
+ t = Waveform(parent)
28
24
  return t
29
25
 
30
26
  def domXml(self):
31
27
  return DOM_XML
32
28
 
33
29
  def group(self):
34
- return "BEC Plots"
30
+ return "Plot Widgets"
35
31
 
36
32
  def icon(self):
37
- return designer_material_icon(BECWaveformWidget.ICON_NAME)
33
+ return designer_material_icon(Waveform.ICON_NAME)
38
34
 
39
35
  def includeFile(self):
40
- return "bec_waveform_widget"
36
+ return "waveform"
41
37
 
42
38
  def initialize(self, form_editor):
43
39
  self._form_editor = form_editor
@@ -49,10 +45,10 @@ class BECWaveformWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cov
49
45
  return self._form_editor is not None
50
46
 
51
47
  def name(self):
52
- return "BECWaveformWidget"
48
+ return "Waveform"
53
49
 
54
50
  def toolTip(self):
55
- return "BECWaveformWidget"
51
+ return "Waveform"
56
52
 
57
53
  def whatsThis(self):
58
54
  return self.toolTip()
@@ -25,8 +25,7 @@ class BECProgressBar(BECWidget, QWidget):
25
25
  ICON_NAME = "page_control"
26
26
 
27
27
  def __init__(self, parent=None, client=None, config=None, gui_id=None, **kwargs):
28
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
29
- QWidget.__init__(self, parent=parent)
28
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
30
29
 
31
30
  accent_colors = get_accent_colors()
32
31
 
@@ -6,6 +6,7 @@ from bec_lib.endpoints import EndpointInfo, MessageEndpoints
6
6
  from pydantic import BaseModel, Field, field_validator
7
7
  from pydantic_core import PydanticCustomError
8
8
  from qtpy import QtGui
9
+ from qtpy.QtCore import QObject
9
10
 
10
11
  from bec_widgets.utils import BECConnector, ConnectionConfig
11
12
 
@@ -77,7 +78,7 @@ class RingConfig(ProgressbarConfig):
77
78
  )
78
79
 
79
80
 
80
- class Ring(BECConnector):
81
+ class Ring(BECConnector, QObject):
81
82
  USER_ACCESS = [
82
83
  "_get_all_rpc",
83
84
  "_rpc_id",
@@ -95,7 +96,6 @@ class Ring(BECConnector):
95
96
  def __init__(
96
97
  self,
97
98
  parent=None,
98
- parent_progress_widget=None,
99
99
  config: RingConfig | dict | None = None,
100
100
  client=None,
101
101
  gui_id: Optional[str] = None,
@@ -108,9 +108,10 @@ class Ring(BECConnector):
108
108
  if isinstance(config, dict):
109
109
  config = RingConfig(**config)
110
110
  self.config = config
111
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
111
+ super().__init__(parent=parent, client=client, config=config, gui_id=gui_id, **kwargs)
112
+
113
+ self.parent_progress_widget = parent
112
114
 
113
- self.parent_progress_widget = parent_progress_widget
114
115
  self.color = None
115
116
  self.background_color = None
116
117
  self.start_position = None
@@ -227,9 +228,9 @@ class Ring(BECConnector):
227
228
  self.config.connections.slot = None
228
229
  self.config.connections.endpoint = None
229
230
  elif mode == "scan":
230
- self.set_connections("on_scan_progress", "scans/scan_progress")
231
+ self.set_connections("on_scan_progress", MessageEndpoints.scan_progress())
231
232
  elif mode == "device":
232
- self.set_connections("on_device_readback", f"internal/devices/readback/{device}")
233
+ self.set_connections("on_device_readback", MessageEndpoints.device_readback(device))
233
234
 
234
235
  self.parent_progress_widget.enable_auto_updates(False)
235
236
 
@@ -243,12 +244,12 @@ class Ring(BECConnector):
243
244
  """
244
245
  if self.config.connections.endpoint == endpoint and self.config.connections.slot == slot:
245
246
  return
246
- else:
247
+ if self.config.connections.slot is not None:
247
248
  self.bec_dispatcher.disconnect_slot(
248
- self.config.connections.slot, self.config.connections.endpoint
249
+ getattr(self, self.config.connections.slot), self.config.connections.endpoint
249
250
  )
250
- self.config.connections = ProgressbarConnections(slot=slot, endpoint=endpoint)
251
- self.bec_dispatcher.connect_slot(getattr(self, slot), endpoint)
251
+ self.config.connections = ProgressbarConnections(slot=slot, endpoint=endpoint)
252
+ self.bec_dispatcher.connect_slot(getattr(self, slot), endpoint)
252
253
 
253
254
  def reset_connection(self):
254
255
  """
@@ -20,7 +20,7 @@ logger = bec_logger.logger
20
20
 
21
21
  class RingProgressBarConfig(ConnectionConfig):
22
22
  color_map: Optional[str] = Field(
23
- "magma", description="Color scheme for the progress bars.", validate_default=True
23
+ "plasma", description="Color scheme for the progress bars.", validate_default=True
24
24
  )
25
25
  min_number_of_bars: int | None = Field(
26
26
  1, description="Minimum number of progress bars to display."
@@ -71,6 +71,10 @@ class RingProgressBarConfig(ConnectionConfig):
71
71
 
72
72
 
73
73
  class RingProgressBar(BECWidget, QWidget):
74
+ """
75
+ Show the progress of devices, scans or custom values in the form of ring progress bars.
76
+ """
77
+
74
78
  PLUGIN = True
75
79
  ICON_NAME = "track_changes"
76
80
  USER_ACCESS = [
@@ -110,8 +114,7 @@ class RingProgressBar(BECWidget, QWidget):
110
114
  if isinstance(config, dict):
111
115
  config = RingProgressBarConfig(**config, widget_class=self.__class__.__name__)
112
116
  self.config = config
113
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
114
- QWidget.__init__(self, parent=parent)
117
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
115
118
 
116
119
  self.get_bec_shortcuts()
117
120
  self.entry_validator = EntryValidator(self.dev)
@@ -120,7 +123,7 @@ class RingProgressBar(BECWidget, QWidget):
120
123
 
121
124
  # For updating bar behaviour
122
125
  self._auto_updates = True
123
- self._rings = None
126
+ self._rings = []
124
127
 
125
128
  if num_bars is not None:
126
129
  self.config.num_bars = max(
@@ -131,11 +134,12 @@ class RingProgressBar(BECWidget, QWidget):
131
134
  self.enable_auto_updates(self.config.auto_updates)
132
135
 
133
136
  @property
134
- def rings(self):
137
+ def rings(self) -> list[Ring]:
138
+ """Returns a list of all rings in the progress bar."""
135
139
  return self._rings
136
140
 
137
141
  @rings.setter
138
- def rings(self, value):
142
+ def rings(self, value: list[Ring]):
139
143
  self._rings = value
140
144
 
141
145
  def update_config(self, config: RingProgressBarConfig | dict):
@@ -166,15 +170,15 @@ class RingProgressBar(BECWidget, QWidget):
166
170
  )
167
171
  for i in range(self.config.num_bars)
168
172
  ]
169
- self._rings = [
170
- Ring(parent_progress_widget=self, config=config) for config in self.config.rings
171
- ]
173
+ self._rings = [Ring(parent=self, config=config) for config in self.config.rings]
172
174
 
173
175
  if self.config.color_map:
174
176
  self.set_colors_from_map(self.config.color_map)
175
177
 
176
178
  min_size = self._calculate_minimum_size()
177
179
  self.setMinimumSize(min_size)
180
+ # Set outer ring to listen to scan progress
181
+ self.rings[0].set_update(mode="scan")
178
182
  self.update()
179
183
 
180
184
  def add_ring(self, **kwargs) -> Ring:
@@ -196,7 +200,7 @@ class RingProgressBar(BECWidget, QWidget):
196
200
  directions=-1,
197
201
  **kwargs,
198
202
  )
199
- ring = Ring(parent_progress_widget=self, config=ring_config)
203
+ ring = Ring(parent=self, config=ring_config)
200
204
  self.config.num_bars += 1
201
205
  self._rings.append(ring)
202
206
  self.config.rings.append(ring.config)
@@ -215,6 +219,10 @@ class RingProgressBar(BECWidget, QWidget):
215
219
  index(int): Index of the progress bar to remove.
216
220
  """
217
221
  ring = self._find_ring_by_index(index)
222
+ self._cleanup_ring(ring)
223
+ self.update()
224
+
225
+ def _cleanup_ring(self, ring: Ring) -> None:
218
226
  ring.reset_connection()
219
227
  self._rings.remove(ring)
220
228
  self.config.rings.remove(ring.config)
@@ -222,8 +230,10 @@ class RingProgressBar(BECWidget, QWidget):
222
230
  self._reindex_rings()
223
231
  if self.config.color_map:
224
232
  self.set_colors_from_map(self.config.color_map)
225
- del ring
226
- self.update()
233
+ # Remove ring from rpc, afterwards call close event.
234
+ ring.rpc_register.remove_rpc(ring)
235
+ ring.deleteLater()
236
+ # del ring
227
237
 
228
238
  def _reindex_rings(self):
229
239
  """
@@ -289,7 +299,7 @@ class RingProgressBar(BECWidget, QWidget):
289
299
  widget_class="Ring", index=i, start_positions=90 * 16, directions=-1
290
300
  )
291
301
  self.config.rings.append(new_ring_config)
292
- new_ring = Ring(parent_progress_widget=self, config=new_ring_config)
302
+ new_ring = Ring(parent=self, config=new_ring_config)
293
303
  self._rings.append(new_ring)
294
304
 
295
305
  elif num_bars < current_num_bars:
@@ -639,6 +649,6 @@ class RingProgressBar(BECWidget, QWidget):
639
649
  self.on_scan_queue_status, MessageEndpoints.scan_queue_status()
640
650
  )
641
651
  for ring in self._rings:
642
- ring.reset_connection()
652
+ self._cleanup_ring(ring)
643
653
  self._rings.clear()
644
654
  super().cleanup()
@@ -6,10 +6,10 @@ from qtpy.QtCore import Property, Qt, Signal, Slot
6
6
  from qtpy.QtGui import QColor
7
7
  from qtpy.QtWidgets import QHeaderView, QLabel, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget
8
8
 
9
- from bec_widgets.qt_utils.compact_popup import CompactPopupWidget
10
- from bec_widgets.qt_utils.toolbar import ModularToolBar, SeparatorAction, WidgetAction
11
9
  from bec_widgets.utils.bec_connector import ConnectionConfig
12
10
  from bec_widgets.utils.bec_widget import BECWidget
11
+ from bec_widgets.utils.compact_popup import CompactPopupWidget
12
+ from bec_widgets.utils.toolbar import ModularToolBar, SeparatorAction, WidgetAction
13
13
  from bec_widgets.widgets.control.buttons.button_abort.button_abort import AbortButton
14
14
  from bec_widgets.widgets.control.buttons.button_reset.button_reset import ResetButton
15
15
  from bec_widgets.widgets.control.buttons.button_resume.button_resume import ResumeButton
@@ -44,8 +44,9 @@ class BECQueue(BECWidget, CompactPopupWidget):
44
44
  refresh_upon_start: bool = True,
45
45
  **kwargs,
46
46
  ):
47
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
48
- CompactPopupWidget.__init__(self, parent=parent, layout=QVBoxLayout)
47
+ super().__init__(
48
+ parent=parent, layout=QVBoxLayout, client=client, gui_id=gui_id, config=config, **kwargs
49
+ )
49
50
  self.layout.setSpacing(0)
50
51
  self.layout.setContentsMargins(0, 0, 0, 0)
51
52
 
@@ -56,6 +57,7 @@ class BECQueue(BECWidget, CompactPopupWidget):
56
57
  # self.layout.addWidget(self.table)
57
58
  self.table.setColumnCount(4)
58
59
  self.table.setHorizontalHeaderLabels(["Scan Number", "Type", "Status", "Cancel"])
60
+
59
61
  header = self.table.horizontalHeader()
60
62
  header.setSectionResizeMode(QHeaderView.Stretch)
61
63
 
@@ -72,15 +74,16 @@ class BECQueue(BECWidget, CompactPopupWidget):
72
74
  """
73
75
  Set the toolbar.
74
76
  """
75
- widget_label = QLabel("Live Queue")
77
+ widget_label = QLabel(text="Live Queue", parent=self)
76
78
  widget_label.setStyleSheet("font-weight: bold;")
77
79
  self.toolbar = ModularToolBar(
80
+ parent=self,
78
81
  actions={
79
82
  "widget_label": WidgetAction(widget=widget_label),
80
83
  "separator_1": SeparatorAction(),
81
- "resume": WidgetAction(widget=ResumeButton(toolbar=False)),
82
- "stop": WidgetAction(widget=StopButton(toolbar=False)),
83
- "reset": WidgetAction(widget=ResetButton(toolbar=False)),
84
+ "resume": WidgetAction(widget=ResumeButton(parent=self, toolbar=False)),
85
+ "stop": WidgetAction(widget=StopButton(parent=self, toolbar=False)),
86
+ "reset": WidgetAction(widget=ResetButton(parent=self, toolbar=False)),
84
87
  },
85
88
  target_widget=self,
86
89
  )
@@ -222,7 +225,7 @@ class BECQueue(BECWidget, CompactPopupWidget):
222
225
  Returns:
223
226
  AbortButton: The abort button.
224
227
  """
225
- abort_button = AbortButton(scan_id=scan_id)
228
+ abort_button = AbortButton(parent=self, scan_id=scan_id)
226
229
 
227
230
  abort_button.button.setText("")
228
231
  abort_button.button.setIcon(
@@ -230,7 +233,6 @@ class BECQueue(BECWidget, CompactPopupWidget):
230
233
  )
231
234
  abort_button.button.setStyleSheet("background-color: rgba(0,0,0,0) ")
232
235
  abort_button.button.setFlat(True)
233
-
234
236
  return abort_button
235
237
 
236
238
  def delete_selected_row(self):
@@ -238,7 +240,7 @@ class BECQueue(BECWidget, CompactPopupWidget):
238
240
  button = self.sender()
239
241
  row = self.table.indexAt(button.pos()).row()
240
242
  self.table.removeRow(row)
241
-
243
+ button.close()
242
244
  button.deleteLater()
243
245
 
244
246
  def reset_content(self):
@@ -12,11 +12,11 @@ from bec_lib.utils.import_utils import lazy_import_from
12
12
  from qtpy.QtCore import QObject, QTimer, Signal, Slot
13
13
  from qtpy.QtWidgets import QHBoxLayout, QTreeWidget, QTreeWidgetItem
14
14
 
15
- from bec_widgets.qt_utils.compact_popup import CompactPopupWidget
16
15
  from bec_widgets.utils.bec_widget import BECWidget
16
+ from bec_widgets.utils.compact_popup import CompactPopupWidget
17
17
  from bec_widgets.widgets.services.bec_status_box.status_item import StatusItem
18
18
 
19
- if TYPE_CHECKING:
19
+ if TYPE_CHECKING: # pragma: no cover
20
20
  from bec_lib.client import BECClient
21
21
 
22
22
  # TODO : Put normal imports back when Pydantic gets faster
@@ -89,8 +89,7 @@ class BECStatusBox(BECWidget, CompactPopupWidget):
89
89
  gui_id: str = None,
90
90
  **kwargs,
91
91
  ):
92
- super().__init__(client=client, gui_id=gui_id, **kwargs)
93
- CompactPopupWidget.__init__(self, parent=parent, layout=QHBoxLayout)
92
+ super().__init__(parent=parent, layout=QHBoxLayout, client=client, gui_id=gui_id, **kwargs)
94
93
 
95
94
  self.box_name = box_name
96
95
  self.status_container = defaultdict(lambda: {"info": None, "item": None, "widget": None})
@@ -13,6 +13,10 @@ from bec_widgets.widgets.services.device_browser.device_item import DeviceItem
13
13
 
14
14
 
15
15
  class DeviceBrowser(BECWidget, QWidget):
16
+ """
17
+ DeviceBrowser is a widget that displays all available devices in the current BEC session.
18
+ """
19
+
16
20
  device_update: Signal = Signal()
17
21
  PLUGIN = True
18
22
  ICON_NAME = "lists"
@@ -25,8 +29,7 @@ class DeviceBrowser(BECWidget, QWidget):
25
29
  gui_id: Optional[str] = None,
26
30
  **kwargs,
27
31
  ) -> None:
28
- super().__init__(client=client, config=config, gui_id=gui_id, **kwargs)
29
- QWidget.__init__(self, parent)
32
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
30
33
 
31
34
  self.get_bec_shortcuts()
32
35
  self.ui = None
@@ -7,7 +7,7 @@ from qtpy.QtCore import QMimeData, Qt
7
7
  from qtpy.QtGui import QDrag
8
8
  from qtpy.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget
9
9
 
10
- if TYPE_CHECKING:
10
+ if TYPE_CHECKING: # pragma: no cover
11
11
  from qtpy.QtGui import QMouseEvent
12
12
 
13
13
  logger = bec_logger.logger
@@ -1,4 +1,4 @@
1
- """ Module for a LogPanel widget to display BEC log messages """
1
+ """Module for a LogPanel widget to display BEC log messages"""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -15,7 +15,8 @@ from bec_lib.connector import ConnectorBase
15
15
  from bec_lib.endpoints import MessageEndpoints
16
16
  from bec_lib.logger import LogLevel, bec_logger
17
17
  from bec_lib.messages import LogMessage, StatusMessage
18
- from qtpy.QtCore import QDateTime, Qt, Signal # type: ignore
18
+ from PySide6.QtCore import QObject
19
+ from qtpy.QtCore import QDateTime, Qt, Signal
19
20
  from qtpy.QtGui import QFont
20
21
  from qtpy.QtWidgets import (
21
22
  QApplication,
@@ -34,8 +35,8 @@ from qtpy.QtWidgets import (
34
35
  QWidget,
35
36
  )
36
37
 
37
- from bec_widgets.qt_utils.error_popups import SafeSlot
38
38
  from bec_widgets.utils.colors import get_theme_palette, set_theme
39
+ from bec_widgets.utils.error_popups import SafeSlot
39
40
  from bec_widgets.widgets.editors.text_box.text_box import TextBox
40
41
  from bec_widgets.widgets.services.bec_status_box.bec_status_box import BECServiceStatusMixin
41
42
  from bec_widgets.widgets.utility.logpanel._util import (
@@ -51,8 +52,8 @@ from bec_widgets.widgets.utility.logpanel._util import (
51
52
  simple_color_format,
52
53
  )
53
54
 
54
- if TYPE_CHECKING:
55
- from PySide6.QtCore import SignalInstance
55
+ if TYPE_CHECKING: # pragma: no cover
56
+ from qtpy.QtCore import SignalInstance
56
57
 
57
58
  logger = bec_logger.logger
58
59
 
@@ -68,20 +69,22 @@ DEFAULT_LOG_COLORS = {
68
69
  }
69
70
 
70
71
 
71
- class BecLogsQueue:
72
+ class BecLogsQueue(QObject):
72
73
  """Manages getting logs from BEC Redis and formatting them for display"""
73
74
 
75
+ new_message = Signal()
76
+
74
77
  def __init__(
75
78
  self,
79
+ parent: QObject | None,
76
80
  conn: ConnectorBase,
77
- new_message_signal: SignalInstance,
78
81
  maxlen: int = 1000,
79
82
  line_formatter: LineFormatter = noop_format,
80
83
  ) -> None:
84
+ super().__init__(parent=parent)
81
85
  self._timestamp_start: QDateTime | None = None
82
86
  self._timestamp_end: QDateTime | None = None
83
87
  self._conn = conn
84
- self._new_message_signal: SignalInstance | None = new_message_signal
85
88
  self._max_length = maxlen
86
89
  self._data: deque[LogMessage] = deque([], self._max_length)
87
90
  self._display_queue: deque[str] = deque([], self._max_length)
@@ -91,9 +94,9 @@ class BecLogsQueue:
91
94
  self._set_formatter_and_update_filter(line_formatter)
92
95
  self._conn.register([MessageEndpoints.log()], None, self._process_incoming_log_msg)
93
96
 
94
- def disconnect(self):
97
+ def unsub_from_redis(self):
98
+ """Stop listening to the Redis log stream"""
95
99
  self._conn.unregister([MessageEndpoints.log()], None, self._process_incoming_log_msg)
96
- self._new_message_signal.disconnect()
97
100
 
98
101
  def _process_incoming_log_msg(self, msg: dict):
99
102
  try:
@@ -101,10 +104,9 @@ class BecLogsQueue:
101
104
  self._data.append(_msg)
102
105
  if self.filter is None or self.filter(_msg):
103
106
  self._display_queue.append(self._line_formatter(_msg))
104
- if self._new_message_signal:
105
- self._new_message_signal.emit()
106
- except Exception:
107
- logger.warning("Error in LogPanel incoming message callback!")
107
+ self.new_message.emit()
108
+ except Exception as e:
109
+ logger.warning(f"Error in LogPanel incoming message callback: {e}")
108
110
 
109
111
  def _set_formatter_and_update_filter(self, line_formatter: LineFormatter = noop_format):
110
112
  self._line_formatter: LineFormatter = line_formatter
@@ -144,6 +146,7 @@ class BecLogsQueue:
144
146
 
145
147
  @property
146
148
  def filter(self) -> LineFilter:
149
+ """A function which filters a log message based on all applied criteria"""
147
150
  thresh = LogLevel[self._log_level].value if self._log_level is not None else 0
148
151
  return self._combine_filters(
149
152
  partial(level_filter, thresh=thresh),
@@ -153,6 +156,7 @@ class BecLogsQueue:
153
156
  )
154
157
 
155
158
  def update_level_filter(self, level: str):
159
+ """Change the log-level of the level filter"""
156
160
  if level not in [l.name for l in LogLevel]:
157
161
  logger.error(f"Logging level {level} unrecognized for filter!")
158
162
  return
@@ -160,34 +164,42 @@ class BecLogsQueue:
160
164
  self._set_formatter_and_update_filter(self._line_formatter)
161
165
 
162
166
  def update_search_filter(self, search_query: Pattern | str | None = None):
167
+ """Change the string or regex to filter against"""
163
168
  self._search_query = search_query
164
169
  self._set_formatter_and_update_filter(self._line_formatter)
165
170
 
166
171
  def update_time_filter(self, start: QDateTime | None, end: QDateTime | None):
172
+ """Change the start and/or end times to filter against"""
167
173
  self._timestamp_start = start
168
174
  self._timestamp_end = end
169
175
  self._set_formatter_and_update_filter(self._line_formatter)
170
176
 
171
177
  def update_service_filter(self, services: set[str]):
178
+ """Change the selected services to display"""
172
179
  self._selected_services = services
173
180
  self._set_formatter_and_update_filter(self._line_formatter)
174
181
 
175
182
  def update_line_formatter(self, line_formatter: LineFormatter):
183
+ """Update the formatter"""
176
184
  self._set_formatter_and_update_filter(line_formatter)
177
185
 
178
186
  def display_all(self) -> str:
187
+ """Return formatted output for all log messages"""
179
188
  return "\n".join(self._queue_formatter(self._data.copy()))
180
189
 
181
190
  def format_new(self):
191
+ """Return formatted output for the display queue"""
182
192
  res = "\n".join(self._display_queue)
183
193
  self._display_queue = deque([], self._max_length)
184
194
  return res
185
195
 
186
196
  def clear_logs(self):
197
+ """Clear the cache and display queue"""
187
198
  self._data = deque([])
188
199
  self._display_queue = deque([])
189
200
 
190
201
  def fetch_history(self):
202
+ """Fetch all available messages from Redis"""
191
203
  self._data = deque(
192
204
  item["data"]
193
205
  for item in self._conn.xread(
@@ -196,14 +208,16 @@ class BecLogsQueue:
196
208
  )
197
209
 
198
210
  def unique_service_names_from_history(self) -> set[str]:
211
+ """Go through the log history to determine active service names"""
199
212
  return set(msg.log_msg["service_name"] for msg in self._data)
200
213
 
201
214
 
202
215
  class LogPanelToolbar(QWidget):
203
216
 
204
- services_selected: pyqtBoundSignal = Signal(set)
217
+ services_selected: SignalInstance = Signal(set)
205
218
 
206
219
  def __init__(self, parent: QWidget | None = None) -> None:
220
+ """A toolbar for the logpanel, mainly used for managing the states of filters"""
207
221
  super().__init__(parent)
208
222
 
209
223
  # in unix time
@@ -337,6 +351,7 @@ class LogPanelToolbar(QWidget):
337
351
  def service_list_update(
338
352
  self, services_info: dict[str, StatusMessage], services_from_history: set[str], *_, **__
339
353
  ):
354
+ """Change the list of services which can be selected"""
340
355
  self._unique_service_names = set([s.split("/")[0] for s in services_info.keys()])
341
356
  self._unique_service_names |= services_from_history
342
357
  if self._services_selected is None:
@@ -396,10 +411,11 @@ class LogPanel(TextBox):
396
411
  self._update_colors()
397
412
  self._service_status = service_status or BECServiceStatusMixin(self, client=self.client) # type: ignore
398
413
  self._log_manager = BecLogsQueue(
414
+ parent,
399
415
  self.client.connector, # type: ignore
400
- new_message_signal=self._new_messages,
401
416
  line_formatter=partial(simple_color_format, colors=self._colors),
402
417
  )
418
+ self._log_manager.new_message.connect(self._new_messages)
403
419
 
404
420
  self.toolbar = LogPanelToolbar(parent=parent)
405
421
  self.toolbar_area = QScrollArea()
@@ -513,7 +529,10 @@ class LogPanel(TextBox):
513
529
 
514
530
  def cleanup(self):
515
531
  self._service_status.cleanup()
516
- self._log_manager.disconnect()
532
+ self._log_manager.unsub_from_redis()
533
+ self._log_manager.new_message.disconnect(self._new_messages)
534
+ self._new_messages.disconnect(self._on_append)
535
+ super().cleanup()
517
536
 
518
537
 
519
538
  if __name__ == "__main__": # pragma: no cover
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import sys
2
4
 
3
5
  from bec_qthemes import material_icon
@@ -30,10 +32,8 @@ class BECSpinBox(BECWidget, QDoubleSpinBox):
30
32
  ) -> None:
31
33
  if config is None:
32
34
  config = ConnectionConfig(widget_class=self.__class__.__name__)
33
- super().__init__(client=client, gui_id=gui_id, config=config, **kwargs)
34
- QDoubleSpinBox.__init__(self, parent=parent)
35
+ super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
35
36
 
36
- self.setObjectName("BECSpinBox")
37
37
  # Make the widget as compact as possible horizontally.
38
38
  self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
39
39
  self.setAlignment(Qt.AlignHCenter)
@@ -23,8 +23,8 @@ class SpinnerWidget(QWidget):
23
23
  self.timer = QTimer(self)
24
24
  self.timer.timeout.connect(self.rotate)
25
25
  self.time = 0
26
- self.duration = 50
27
- self.speed = 50
26
+ self.duration = 40
27
+ self.speed = 40
28
28
  self._started = False
29
29
 
30
30
  def start(self):
@@ -6,7 +6,7 @@ import pyqtgraph as pg
6
6
  from qtpy.QtCore import Qt, Signal
7
7
  from qtpy.QtWidgets import QHBoxLayout, QWidget
8
8
 
9
- from bec_widgets.qt_utils.error_popups import SafeSlot
9
+ from bec_widgets.utils.error_popups import SafeSlot
10
10
 
11
11
 
12
12
  class ColorButton(QWidget):
@@ -9,18 +9,16 @@ from bec_widgets.utils.bec_widget import BECWidget
9
9
  class BECColorMapWidget(BECWidget, QWidget):
10
10
  colormap_changed_signal = Signal(str)
11
11
  ICON_NAME = "palette"
12
- USER_ACCESS = ["colormap"]
13
12
  PLUGIN = True
13
+ RPC = False
14
14
 
15
- def __init__(self, parent=None, cmap: str = "magma", **kwargs):
16
- super().__init__(**kwargs)
17
- QWidget.__init__(self, parent=parent)
18
-
15
+ def __init__(self, parent=None, cmap: str = "plasma", **kwargs):
16
+ super().__init__(parent=parent, **kwargs)
19
17
  # Create the ColorMapButton
20
18
  self.button = ColorMapButton()
21
19
 
22
20
  # Set the size policy and minimum width
23
- size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
21
+ size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
24
22
  self.button.setSizePolicy(size_policy)
25
23
  self.button.setMinimumWidth(100)
26
24
  self.button.setMinimumHeight(30)