mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
fix(plot_framework): all widgets, popups and side menus cleanups adjusted
This commit is contained in:
@ -14,10 +14,8 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
from bec_lib import messages
|
||||
from bec_lib.connector import MessageObject
|
||||
|
||||
from bec_widgets.cli.client_utils import BECGuiClient
|
||||
|
||||
|
||||
import bec_widgets.cli.client as client
|
||||
from bec_widgets.cli.client_utils import BECGuiClient
|
||||
else:
|
||||
client = lazy_import("bec_widgets.cli.client") # avoid circular import
|
||||
messages = lazy_import("bec_lib.messages")
|
||||
|
@ -77,13 +77,6 @@ class BECWidget(BECConnector):
|
||||
logger.debug(f"Subscribing to theme updates for {self.__class__.__name__}")
|
||||
self._connect_to_theme_change()
|
||||
|
||||
def _ensure_bec_app(self):
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from bec_widgets.utils.bec_qapp import BECApplication
|
||||
|
||||
app = BECApplication.from_qapplication()
|
||||
return app
|
||||
|
||||
def _connect_to_theme_change(self):
|
||||
"""Connect to the theme change signal."""
|
||||
qapp = QApplication.instance()
|
||||
@ -113,6 +106,7 @@ class BECWidget(BECConnector):
|
||||
"""Cleanup the widget."""
|
||||
with RPCRegister.delayed_broadcast():
|
||||
# All widgets need to call super().cleanup() in their cleanup method
|
||||
logger.info(f"Registry cleanup for widget {self.__class__.__name__}")
|
||||
self.rpc_register.remove_rpc(self)
|
||||
|
||||
def closeEvent(self, event):
|
||||
|
@ -1,7 +1,11 @@
|
||||
from bec_lib.logger import bec_logger
|
||||
from PySide6.QtGui import QCloseEvent
|
||||
from qtpy.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class SettingWidget(QWidget):
|
||||
"""
|
||||
@ -37,6 +41,15 @@ class SettingWidget(QWidget):
|
||||
"""
|
||||
pass
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Cleanup the settings widget.
|
||||
"""
|
||||
|
||||
def closeEvent(self, event: QCloseEvent) -> None:
|
||||
self.cleanup()
|
||||
return super().closeEvent(event)
|
||||
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
"""
|
||||
@ -99,8 +112,17 @@ class SettingsDialog(QDialog):
|
||||
Accept the changes made in the settings widget and close the dialog.
|
||||
"""
|
||||
self.widget.accept_changes()
|
||||
self.cleanup()
|
||||
super().accept()
|
||||
|
||||
@SafeSlot()
|
||||
def reject(self):
|
||||
"""
|
||||
Reject the changes made in the settings widget and close the dialog.
|
||||
"""
|
||||
self.cleanup()
|
||||
super().reject()
|
||||
|
||||
@SafeSlot()
|
||||
def apply_changes(self):
|
||||
"""
|
||||
@ -114,7 +136,10 @@ class SettingsDialog(QDialog):
|
||||
"""
|
||||
self.button_box.close()
|
||||
self.button_box.deleteLater()
|
||||
self.widget.close()
|
||||
self.widget.deleteLater()
|
||||
|
||||
def closeEvent(self, event):
|
||||
logger.info("Closing settings dialog")
|
||||
self.cleanup()
|
||||
super().closeEvent(event)
|
||||
|
@ -133,7 +133,7 @@ class Image(PlotBase):
|
||||
super().__init__(
|
||||
parent=parent, config=config, client=client, gui_id=gui_id, popups=popups, **kwargs
|
||||
)
|
||||
self._main_image.parent_image = self
|
||||
self._main_image = ImageItem(parent_image=self, parent_id=self.gui_id)
|
||||
|
||||
self.plot_item.addItem(self._main_image)
|
||||
self.scan_id = None
|
||||
@ -913,10 +913,14 @@ class Image(PlotBase):
|
||||
"""
|
||||
Disconnect the image update signals and clean up the image.
|
||||
"""
|
||||
# Main Image cleanup
|
||||
if self._main_image.config.monitor is not None:
|
||||
self.disconnect_monitor(self._main_image.config.monitor)
|
||||
self._main_image.config.monitor = None
|
||||
self.plot_item.removeItem(self._main_image)
|
||||
self._main_image = None
|
||||
|
||||
# Colorbar Cleanup
|
||||
if self._color_bar:
|
||||
if self.config.color_bar == "full":
|
||||
self.cleanup_histogram_lut_item(self._color_bar)
|
||||
@ -925,6 +929,10 @@ class Image(PlotBase):
|
||||
self._color_bar.deleteLater()
|
||||
self._color_bar = None
|
||||
|
||||
# Toolbar cleanup
|
||||
self.toolbar.widgets["monitor"].widget.close()
|
||||
self.toolbar.widgets["monitor"].widget.deleteLater()
|
||||
|
||||
super().cleanup()
|
||||
|
||||
|
||||
|
@ -28,7 +28,9 @@ class MonitorSelectionToolbarBundle(ToolbarBundle):
|
||||
|
||||
# 1) Device combo box
|
||||
self.device_combo_box = DeviceComboBox(
|
||||
device_filter=BECDeviceFilter.DEVICE, readout_priority_filter=[ReadoutPriority.ASYNC]
|
||||
parent=self.target_widget,
|
||||
device_filter=BECDeviceFilter.DEVICE,
|
||||
readout_priority_filter=[ReadoutPriority.ASYNC],
|
||||
)
|
||||
self.device_combo_box.addItem("", None)
|
||||
self.device_combo_box.setCurrentText("")
|
||||
|
@ -791,6 +791,10 @@ class MotorMap(PlotBase):
|
||||
data = {"x": self._buffer["x"], "y": self._buffer["y"]}
|
||||
return data
|
||||
|
||||
def cleanup(self):
|
||||
self.motor_selection_bundle.cleanup()
|
||||
super().cleanup()
|
||||
|
||||
|
||||
class DemoApp(QMainWindow): # pragma: no cover
|
||||
def __init__(self):
|
||||
|
@ -27,14 +27,18 @@ class MotorSelectionToolbarBundle(ToolbarBundle):
|
||||
self.target_widget = target_widget
|
||||
|
||||
# Motor X
|
||||
self.motor_x = DeviceComboBox(device_filter=[BECDeviceFilter.POSITIONER])
|
||||
self.motor_x = DeviceComboBox(
|
||||
parent=self.target_widget, device_filter=[BECDeviceFilter.POSITIONER]
|
||||
)
|
||||
self.motor_x.addItem("", None)
|
||||
self.motor_x.setCurrentText("")
|
||||
self.motor_x.setToolTip("Select Motor X")
|
||||
self.motor_x.setItemDelegate(NoCheckDelegate(self.motor_x))
|
||||
|
||||
# Motor X
|
||||
self.motor_y = DeviceComboBox(device_filter=[BECDeviceFilter.POSITIONER])
|
||||
self.motor_y = DeviceComboBox(
|
||||
parent=self.target_widget, device_filter=[BECDeviceFilter.POSITIONER]
|
||||
)
|
||||
self.motor_y.addItem("", None)
|
||||
self.motor_y.setCurrentText("")
|
||||
self.motor_y.setToolTip("Select Motor Y")
|
||||
@ -58,3 +62,9 @@ class MotorSelectionToolbarBundle(ToolbarBundle):
|
||||
or motor_y != self.target_widget.config.y_motor.name
|
||||
):
|
||||
self.target_widget.map(motor_x, motor_y)
|
||||
|
||||
def cleanup(self):
|
||||
self.motor_x.close()
|
||||
self.motor_x.deleteLater()
|
||||
self.motor_y.close()
|
||||
self.motor_y.deleteLater()
|
||||
|
@ -496,3 +496,9 @@ class MultiWaveform(PlotBase):
|
||||
self.monitor_selection_bundle.colormap_widget.blockSignals(True)
|
||||
self.monitor_selection_bundle.colormap_widget.colormap = self.config.color_palette
|
||||
self.monitor_selection_bundle.colormap_widget.blockSignals(False)
|
||||
|
||||
def cleanup(self):
|
||||
self._disconnect_monitor()
|
||||
self.clear_curves()
|
||||
self.monitor_selection_bundle.cleanup()
|
||||
super().cleanup()
|
||||
|
@ -58,3 +58,10 @@ class MultiWaveformSelectionToolbarBundle(ToolbarBundle):
|
||||
@SafeSlot(str)
|
||||
def change_colormap(self, colormap: str):
|
||||
self.target_widget.color_palette = colormap
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Cleanup the toolbar bundle.
|
||||
"""
|
||||
self.monitor.close()
|
||||
self.monitor.deleteLater()
|
||||
|
@ -69,7 +69,7 @@ class PlotBase(BECWidget, QWidget):
|
||||
config: ConnectionConfig | None = None,
|
||||
client=None,
|
||||
gui_id: str | None = None,
|
||||
popups: bool = False,
|
||||
popups: bool = True,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if config is None:
|
||||
@ -170,6 +170,9 @@ class PlotBase(BECWidget, QWidget):
|
||||
# hide some options by default
|
||||
self.toolbar.toggle_action_visibility("fps_monitor", False)
|
||||
|
||||
# Get default viewbox state
|
||||
self.mouse_bundle.get_viewbox_mode()
|
||||
|
||||
def add_side_menus(self):
|
||||
"""Adds multiple menus to the side panel."""
|
||||
# Setting Axis Widget
|
||||
|
@ -107,14 +107,15 @@ class ScatterWaveform(PlotBase):
|
||||
):
|
||||
if config is None:
|
||||
config = ScatterWaveformConfig(widget_class=self.__class__.__name__)
|
||||
# Specific GUI elements
|
||||
self.scatter_dialog = None
|
||||
self.scatter_curve_settings = None
|
||||
|
||||
super().__init__(
|
||||
parent=parent, config=config, client=client, gui_id=gui_id, popups=popups, **kwargs
|
||||
)
|
||||
self._main_curve = ScatterCurve(parent_item=self)
|
||||
|
||||
# Specific GUI elements
|
||||
self.scatter_dialog = None
|
||||
|
||||
# Scan Data
|
||||
self.old_scan_id = None
|
||||
self.scan_id = None
|
||||
@ -128,24 +129,26 @@ class ScatterWaveform(PlotBase):
|
||||
self.proxy_update_sync = pg.SignalProxy(
|
||||
self.sync_signal_update, rateLimit=25, slot=self.update_sync_curves
|
||||
)
|
||||
|
||||
self._init_scatter_curve_settings()
|
||||
self.update_with_scan_history(-1)
|
||||
|
||||
################################################################################
|
||||
# Widget Specific GUI interactions
|
||||
################################################################################
|
||||
|
||||
def _init_scatter_curve_settings(self):
|
||||
"""
|
||||
Initialize the scatter curve settings menu.
|
||||
"""
|
||||
|
||||
scatter_curve_settings = ScatterCurveSettings(parent=self, target_widget=self, popup=False)
|
||||
self.scatter_curve_settings = ScatterCurveSettings(
|
||||
parent=self, target_widget=self, popup=False
|
||||
)
|
||||
self.side_panel.add_menu(
|
||||
action_id="scatter_curve",
|
||||
icon_name="scatter_plot",
|
||||
tooltip="Show Scatter Curve Settings",
|
||||
widget=scatter_curve_settings,
|
||||
widget=self.scatter_curve_settings,
|
||||
title="Scatter Curve Settings",
|
||||
)
|
||||
|
||||
@ -461,17 +464,30 @@ class ScatterWaveform(PlotBase):
|
||||
logger.warning(f"Neither scan_id or scan_number was provided, fetching the latest scan")
|
||||
scan_index = -1
|
||||
|
||||
if scan_index is not None:
|
||||
if len(self.client.history) == 0:
|
||||
logger.info("No scans executed so far. Skipping scan history update.")
|
||||
return
|
||||
|
||||
self.scan_item = self.client.history[scan_index]
|
||||
metadata = self.scan_item.metadata
|
||||
self.scan_id = metadata["bec"]["scan_id"]
|
||||
else:
|
||||
if scan_index is None:
|
||||
self.scan_id = scan_id
|
||||
self.scan_item = self.client.history.get_by_scan_id(scan_id)
|
||||
self.sync_signal_update.emit()
|
||||
return
|
||||
|
||||
if scan_index == -1:
|
||||
scan_item = self.client.queue.scan_storage.current_scan
|
||||
if scan_item is not None:
|
||||
if scan_item.status_message is None:
|
||||
logger.warning(f"Scan item with {scan_item.scan_id} has no status message.")
|
||||
return
|
||||
self.scan_item = scan_item
|
||||
self.scan_id = scan_item.scan_id
|
||||
self.sync_signal_update.emit()
|
||||
return
|
||||
|
||||
if len(self.client.history) == 0:
|
||||
logger.info("No scans executed so far. Skipping scan history update.")
|
||||
return
|
||||
|
||||
self.scan_item = self.client.history[scan_index]
|
||||
metadata = self.scan_item.metadata
|
||||
self.scan_id = metadata["bec"]["scan_id"]
|
||||
|
||||
self.sync_signal_update.emit()
|
||||
|
||||
@ -487,6 +503,22 @@ class ScatterWaveform(PlotBase):
|
||||
self.crosshair.clear_markers()
|
||||
self._main_curve.clear()
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Cleanup the widget and disconnect all signals.
|
||||
"""
|
||||
if self.scatter_dialog is not None:
|
||||
self.scatter_dialog.close()
|
||||
self.scatter_dialog.deleteLater()
|
||||
if self.scatter_curve_settings is not None:
|
||||
self.scatter_curve_settings.cleanup()
|
||||
print("scatter_curve_settings celanup called")
|
||||
self.bec_dispatcher.disconnect_slot(self.on_scan_status, MessageEndpoints.scan_status())
|
||||
self.bec_dispatcher.disconnect_slot(self.on_scan_progress, MessageEndpoints.scan_progress())
|
||||
self.plot_item.removeItem(self._main_curve)
|
||||
self._main_curve = None
|
||||
super().cleanup()
|
||||
|
||||
|
||||
class DemoApp(QMainWindow): # pragma: no cover
|
||||
def __init__(self):
|
||||
|
@ -122,3 +122,17 @@ class ScatterCurveSettings(SettingWidget):
|
||||
color_map=color_map,
|
||||
validate_bec=validate_bec,
|
||||
)
|
||||
|
||||
def cleanup(self):
|
||||
self.ui.x_name.close()
|
||||
self.ui.x_name.deleteLater()
|
||||
self.ui.x_entry.close()
|
||||
self.ui.x_entry.deleteLater()
|
||||
self.ui.y_name.close()
|
||||
self.ui.y_name.deleteLater()
|
||||
self.ui.y_entry.close()
|
||||
self.ui.y_entry.deleteLater()
|
||||
self.ui.z_name.close()
|
||||
self.ui.z_name.deleteLater()
|
||||
self.ui.z_entry.close()
|
||||
self.ui.z_entry.deleteLater()
|
||||
|
@ -56,9 +56,6 @@ class MouseInteractionToolbarBundle(ToolbarBundle):
|
||||
rect.action.toggled.connect(self.enable_mouse_rectangle_mode)
|
||||
auto.action.triggered.connect(self.autorange_plot)
|
||||
|
||||
# Give some time to check the state
|
||||
QTimer.singleShot(10, self.get_viewbox_mode)
|
||||
|
||||
def get_viewbox_mode(self):
|
||||
"""
|
||||
Returns the current interaction mode of a PyQtGraph ViewBox and sets the corresponding action.
|
||||
|
@ -93,7 +93,8 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
self.config = config
|
||||
self.parent_item = parent_item
|
||||
self.parent_id = self.parent_item.gui_id
|
||||
super().__init__(name=name, config=config, gui_id=gui_id, **kwargs)
|
||||
object_name = name.replace("-", "_") if name else None
|
||||
super().__init__(name=name, object_name=object_name, config=config, gui_id=gui_id, **kwargs)
|
||||
|
||||
self.apply_config()
|
||||
self.dap_params = None
|
||||
|
@ -28,7 +28,6 @@ class CurveSetting(SettingWidget):
|
||||
def __init__(self, parent=None, target_widget: Waveform = None, *args, **kwargs):
|
||||
super().__init__(parent=parent, *args, **kwargs)
|
||||
self.setProperty("skip_settings", True)
|
||||
self.setObjectName("CurveSetting")
|
||||
self.target_widget = target_widget
|
||||
|
||||
self.layout = QVBoxLayout(self)
|
||||
@ -52,7 +51,7 @@ class CurveSetting(SettingWidget):
|
||||
self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
self.device_x_label = QLabel("Device")
|
||||
self.device_x = DeviceLineEdit()
|
||||
self.device_x = DeviceLineEdit(parent=self)
|
||||
|
||||
self.signal_x_label = QLabel("Signal")
|
||||
self.signal_x = QLineEdit()
|
||||
@ -117,3 +116,10 @@ class CurveSetting(SettingWidget):
|
||||
"""Refresh the curve tree and the x axis combo box in the case Waveform is modified from rpc."""
|
||||
self.curve_manager.refresh_from_waveform()
|
||||
self._get_x_mode_from_waveform()
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup the widget."""
|
||||
self.device_x.close()
|
||||
self.device_x.deleteLater()
|
||||
self.curve_manager.close()
|
||||
self.curve_manager.deleteLater()
|
||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_qthemes._icon.material_icons import material_icon
|
||||
from qtpy.QtGui import QColor
|
||||
from qtpy.QtWidgets import (
|
||||
@ -36,6 +37,9 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class ColorButton(QPushButton):
|
||||
"""A QPushButton subclass that displays a color.
|
||||
|
||||
@ -110,11 +114,16 @@ class CurveRow(QTreeWidgetItem):
|
||||
self.curve_tree = tree.parent() # The CurveTree widget
|
||||
self.curve_tree.all_items.append(self) # Track stable ordering
|
||||
|
||||
# BEC user input
|
||||
self.device_edit = None
|
||||
self.dap_combo = None
|
||||
|
||||
self.dev = device_manager
|
||||
self.entry_validator = EntryValidator(self.dev)
|
||||
|
||||
self.config = config or CurveConfig()
|
||||
self.source = self.config.source
|
||||
self.dap_rows = []
|
||||
|
||||
# Create column 0 (Actions)
|
||||
self._init_actions()
|
||||
@ -155,8 +164,8 @@ class CurveRow(QTreeWidgetItem):
|
||||
"""Create columns 1 and 2. For device rows, we have device/entry edits; for dap rows, label/model combo."""
|
||||
if self.source == "device":
|
||||
# Device row: columns 1..2 are device line edits
|
||||
self.device_edit = DeviceLineEdit()
|
||||
self.entry_edit = QLineEdit() # TODO in future will be signal line edit
|
||||
self.device_edit = DeviceLineEdit(parent=self.tree)
|
||||
self.entry_edit = QLineEdit(parent=self.tree) # TODO in future will be signal line edit
|
||||
if self.config.signal:
|
||||
self.device_edit.setText(self.config.signal.name or "")
|
||||
self.entry_edit.setText(self.config.signal.entry or "")
|
||||
@ -168,7 +177,7 @@ class CurveRow(QTreeWidgetItem):
|
||||
# DAP row: column1= "Model" label, column2= DapComboBox
|
||||
self.label_widget = QLabel("Model")
|
||||
self.tree.setItemWidget(self, 1, self.label_widget)
|
||||
self.dap_combo = DapComboBox()
|
||||
self.dap_combo = DapComboBox(parent=self.tree)
|
||||
self.dap_combo.populate_fit_model_combobox()
|
||||
# If config.signal has a dap
|
||||
if self.config.signal and self.config.signal.dap:
|
||||
@ -258,15 +267,31 @@ class CurveRow(QTreeWidgetItem):
|
||||
|
||||
def remove_self(self):
|
||||
"""Remove this row from the tree and from the parent's item list."""
|
||||
# If top-level:
|
||||
# Recursively remove all child rows first
|
||||
for i in reversed(range(self.childCount())):
|
||||
child = self.child(i)
|
||||
if isinstance(child, CurveRow):
|
||||
child.remove_self()
|
||||
|
||||
# Clean up the widget references if they still exist
|
||||
if getattr(self, "device_edit", None) is not None:
|
||||
self.device_edit.close()
|
||||
self.device_edit.deleteLater()
|
||||
self.device_edit = None
|
||||
|
||||
if getattr(self, "dap_combo", None) is not None:
|
||||
self.dap_combo.close()
|
||||
self.dap_combo.deleteLater()
|
||||
self.dap_combo = None
|
||||
|
||||
# Remove the item from the tree widget
|
||||
index = self.tree.indexOfTopLevelItem(self)
|
||||
if index != -1:
|
||||
self.tree.takeTopLevelItem(index)
|
||||
else:
|
||||
# If child item
|
||||
if self.parent_item:
|
||||
self.parent_item.removeChild(self)
|
||||
# Also remove from all_items
|
||||
elif self.parent_item:
|
||||
self.parent_item.removeChild(self)
|
||||
|
||||
# Finally, remove self from the registration list in the curve tree
|
||||
curve_tree = self.tree.parent()
|
||||
if self in curve_tree.all_items:
|
||||
curve_tree.all_items.remove(self)
|
||||
@ -320,6 +345,10 @@ class CurveRow(QTreeWidgetItem):
|
||||
|
||||
return self.config.model_dump()
|
||||
|
||||
def closeEvent(self, event) -> None:
|
||||
logger.info(f"CurveRow closeEvent: {self.config.label}")
|
||||
return super().closeEvent(event)
|
||||
|
||||
|
||||
class CurveTree(BECWidget, QWidget):
|
||||
"""A tree widget that manages device and DAP curves."""
|
||||
@ -535,3 +564,13 @@ class CurveTree(BECWidget, QWidget):
|
||||
for dap in dap_curves:
|
||||
if dap.config.parent_label == dev.config.label:
|
||||
CurveRow(self.tree, parent_item=dr, config=dap.config, device_manager=self.dev)
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup the widget."""
|
||||
all_items = list(self.all_items)
|
||||
for item in all_items:
|
||||
item.remove_self()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.cleanup()
|
||||
return super().closeEvent(event)
|
||||
|
@ -10,14 +10,7 @@ from bec_lib import bec_logger, messages
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from pydantic import Field, ValidationError, field_validator
|
||||
from qtpy.QtCore import QTimer, Signal
|
||||
from qtpy.QtWidgets import (
|
||||
QApplication,
|
||||
QDialog,
|
||||
QHBoxLayout,
|
||||
QMainWindow,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from qtpy.QtWidgets import QApplication, QDialog, QHBoxLayout, QMainWindow, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.utils import ConnectionConfig
|
||||
from bec_widgets.utils.bec_signal_proxy import BECSignalProxy
|
||||
@ -320,6 +313,8 @@ class Waveform(PlotBase):
|
||||
"""
|
||||
Slot for when the axis settings dialog is closed.
|
||||
"""
|
||||
self.curve_settings_dialog.close()
|
||||
self.curve_settings_dialog.deleteLater()
|
||||
self.curve_settings_dialog = None
|
||||
self.toolbar.widgets["curve"].action.setChecked(False)
|
||||
|
||||
@ -863,6 +858,9 @@ class Waveform(PlotBase):
|
||||
Clear all curves from the plot widget.
|
||||
"""
|
||||
curve_list = self.curves
|
||||
self._dap_curves = []
|
||||
self._sync_curves = []
|
||||
self._async_curves = []
|
||||
for curve in curve_list:
|
||||
self.remove_curve(curve.name())
|
||||
if self.crosshair is not None:
|
||||
@ -943,6 +941,7 @@ class Waveform(PlotBase):
|
||||
self.on_async_readback,
|
||||
MessageEndpoints.device_async_readback(self.scan_id, curve.name()),
|
||||
)
|
||||
curve.rpc_register.remove_rpc(curve)
|
||||
|
||||
# Remove itself from the DAP summary only for side panels
|
||||
if (
|
||||
@ -1330,7 +1329,9 @@ class Waveform(PlotBase):
|
||||
# find the device curve
|
||||
parent_curve = self._find_curve_by_label(parent_label)
|
||||
if parent_curve is None:
|
||||
logger.warning(f"No device curve found for DAP curve '{dap_curve.name()}'!")
|
||||
logger.warning(
|
||||
f"No device curve found for DAP curve '{dap_curve.name()}'!"
|
||||
) # TODO triggerd when DAP curve is removed from the curve dialog, why?
|
||||
continue
|
||||
|
||||
x_data, y_data = parent_curve.get_data()
|
||||
@ -1565,7 +1566,6 @@ class Waveform(PlotBase):
|
||||
found_sync = True
|
||||
else:
|
||||
logger.warning("Device {dev_name} not found in readout priority list.")
|
||||
|
||||
# Determine the mode of the scan
|
||||
if found_async and found_sync:
|
||||
mode = "mixed"
|
||||
@ -1599,18 +1599,31 @@ class Waveform(PlotBase):
|
||||
logger.warning(f"Neither scan_id or scan_number was provided, fetching the latest scan")
|
||||
scan_index = -1
|
||||
|
||||
if scan_index is not None:
|
||||
if len(self.client.history) == 0:
|
||||
logger.info("No scans executed so far. Skipping scan history update.")
|
||||
return
|
||||
|
||||
self.scan_item = self.client.history[scan_index]
|
||||
metadata = self.scan_item.metadata
|
||||
self.scan_id = metadata["bec"]["scan_id"]
|
||||
else:
|
||||
if scan_index is None:
|
||||
self.scan_id = scan_id
|
||||
self.scan_item = self.client.history.get_by_scan_id(scan_id)
|
||||
self._emit_signal_update()
|
||||
return
|
||||
|
||||
if scan_index == -1:
|
||||
scan_item = self.client.queue.scan_storage.current_scan
|
||||
if scan_item is not None:
|
||||
self.scan_item = scan_item
|
||||
self.scan_id = scan_item.scan_id
|
||||
self._emit_signal_update()
|
||||
return
|
||||
|
||||
if len(self.client.history) == 0:
|
||||
logger.info("No scans executed so far. Skipping scan history update.")
|
||||
return
|
||||
|
||||
self.scan_item = self.client.history[scan_index]
|
||||
metadata = self.scan_item.metadata
|
||||
self.scan_id = metadata["bec"]["scan_id"]
|
||||
|
||||
self._emit_signal_update()
|
||||
|
||||
def _emit_signal_update(self):
|
||||
self._categorise_device_curves()
|
||||
|
||||
self.setup_dap_for_scan()
|
||||
@ -1733,9 +1746,11 @@ class Waveform(PlotBase):
|
||||
self.clear_all()
|
||||
if self.curve_settings_dialog is not None:
|
||||
self.curve_settings_dialog.close()
|
||||
self.curve_settings_dialog.deleteLater()
|
||||
self.curve_settings_dialog = None
|
||||
if self.dap_summary_dialog is not None:
|
||||
self.dap_summary_dialog.close()
|
||||
self.dap_summary_dialog.deleteLater()
|
||||
self.dap_summary_dialog = None
|
||||
super().cleanup()
|
||||
|
||||
|
@ -29,8 +29,6 @@ def test_axis_settings_init(axis_settings_fixture):
|
||||
assert axis_settings.layout.count() == 1 # scroll area
|
||||
# Check the target
|
||||
assert axis_settings.target_widget == plot_base
|
||||
# Check the object name
|
||||
assert axis_settings.objectName() == "AxisSettings"
|
||||
|
||||
|
||||
def test_change_ui_updates_plot_base(axis_settings_fixture, qtbot):
|
||||
|
@ -33,8 +33,6 @@ def test_curve_setting_init(curve_setting_fixture):
|
||||
"""
|
||||
curve_setting, wf = curve_setting_fixture
|
||||
|
||||
# Basic checks
|
||||
assert curve_setting.objectName() == "CurveSetting"
|
||||
# The layout should be QVBoxLayout
|
||||
assert isinstance(curve_setting.layout, QVBoxLayout)
|
||||
|
||||
|
@ -134,12 +134,6 @@ def test_curve_access_pattern(qtbot, mocked_client):
|
||||
assert wf.get_curve(0) == c1
|
||||
assert wf.get_curve(1) == c2
|
||||
|
||||
# Check that the curve is accessible by label
|
||||
assert wf["bpm4i-bpm4i"] == c1
|
||||
assert wf["bpm3a-bpm3a"] == c2
|
||||
assert wf[0] == c1
|
||||
assert wf[1] == c2
|
||||
|
||||
assert wf.curves[0] == c1
|
||||
assert wf.curves[1] == c2
|
||||
|
||||
|
Reference in New Issue
Block a user