@@ -15,6 +15,7 @@ logger = bec_logger.logger
|
||||
_Widgets = {
|
||||
"DataViewer": "DataViewer",
|
||||
"DigitalTwin": "DigitalTwin",
|
||||
"ScanControlAdvanced": "ScanControlAdvanced",
|
||||
}
|
||||
|
||||
|
||||
@@ -64,3 +65,26 @@ class DigitalTwin(RPCBase):
|
||||
"""
|
||||
Detach the widget from its parent dock widget (if widget is in the dock), making it a floating widget.
|
||||
"""
|
||||
|
||||
|
||||
class ScanControlAdvanced(RPCBase):
|
||||
_IMPORT_MODULE = "debye_bec.bec_widgets.widgets.scan_control_advanced.scan_control_advanced"
|
||||
|
||||
@rpc_call
|
||||
def attach(self):
|
||||
"""
|
||||
None
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def detach(self):
|
||||
"""
|
||||
Detach the widget from its parent dock widget (if widget is in the dock), making it a floating widget.
|
||||
"""
|
||||
|
||||
@rpc_timeout(None)
|
||||
@rpc_call
|
||||
def screenshot(self, file_name: "str | None" = None):
|
||||
"""
|
||||
Take a screenshot of the dock area and save it to a file.
|
||||
"""
|
||||
|
||||
@@ -7,6 +7,14 @@ from __future__ import annotations
|
||||
designer_plugins = {
|
||||
"DataViewer": ("debye_bec.bec_widgets.widgets.data_viewer.data_viewer", "DataViewer"),
|
||||
"DigitalTwin": ("debye_bec.bec_widgets.widgets.digital_twin.digital_twin", "DigitalTwin"),
|
||||
"ScanControlAdvanced": (
|
||||
"debye_bec.bec_widgets.widgets.scan_control_advanced.scan_control_advanced",
|
||||
"ScanControlAdvanced",
|
||||
),
|
||||
}
|
||||
|
||||
widget_icons = {"DataViewer": "find_in_page", "DigitalTwin": "lightbulb"}
|
||||
widget_icons = {
|
||||
"DataViewer": "find_in_page",
|
||||
"DigitalTwin": "lightbulb",
|
||||
"ScanControlAdvanced": "tune",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from .scan_control_advanced_plugin import ScanControlAdvancedPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(ScanControlAdvancedPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
@@ -0,0 +1,103 @@
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_lib import bec_logger
|
||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
||||
from bec_widgets.utils.colors import apply_theme
|
||||
from bec_widgets.widgets.control.scan_control.scan_control import ScanControl
|
||||
from qtpy.QtCore import Qt, Signal
|
||||
|
||||
# pylint: disable=E0611
|
||||
from qtpy.QtWidgets import QApplication, QDoubleSpinBox, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
SHOW_MOTION_PROFILE = [
|
||||
"xas_simple_scan",
|
||||
"xas_simple_scan_with_xrd",
|
||||
"xas_advanced_scan",
|
||||
"xas_advanced_scan_with_xrd",
|
||||
]
|
||||
|
||||
|
||||
class ScanControlAdvanced(ScanControl):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.motion_profile_widget = MotionProfileWidget(self)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.show_motion_profile(self._selected_scan)
|
||||
|
||||
def _add_metadata_form(self):
|
||||
self.layout.addWidget(self.motion_profile_widget)
|
||||
super()._add_metadata_form()
|
||||
self.connect_scan_parameter_signals()
|
||||
|
||||
def on_scan_selection_changed(self, scan_name: str):
|
||||
super().on_scan_selection_changed(scan_name)
|
||||
self.show_motion_profile(scan_name)
|
||||
if scan_name in SHOW_MOTION_PROFILE:
|
||||
self.connect_scan_parameter_signals()
|
||||
self.scan_parameter_changed()
|
||||
|
||||
def show_motion_profile(self, scan_name):
|
||||
if scan_name in SHOW_MOTION_PROFILE:
|
||||
self.motion_profile_widget.setVisible(True)
|
||||
else:
|
||||
self.motion_profile_widget.setVisible(False)
|
||||
|
||||
def connect_scan_parameter_signals(self):
|
||||
for box in self.kwarg_boxes:
|
||||
for widget in box.findChildren(QWidget):
|
||||
try:
|
||||
if hasattr(widget, "valueChanged"):
|
||||
widget.valueChanged.connect(
|
||||
self.scan_parameter_changed, Qt.ConnectionType.UniqueConnection
|
||||
)
|
||||
elif hasattr(widget, "textChanged"):
|
||||
widget.textChanged.connect(
|
||||
self.scan_parameter_changed, Qt.ConnectionType.UniqueConnection
|
||||
)
|
||||
except TypeError:
|
||||
# Raised if a connection would not be unique anymore, i.e. if
|
||||
# connect_scan_parameter_signals is called more than once with
|
||||
# the same kwarg_boxes
|
||||
pass
|
||||
|
||||
def scan_parameter_changed(self, *_):
|
||||
params = self.get_scan_parameters()[1]
|
||||
logger.info(f"Scan parameters: {params}")
|
||||
self.motion_profile_widget.update_plot(params)
|
||||
|
||||
|
||||
PLOT_RESOLUTION = 100
|
||||
|
||||
|
||||
class MotionProfileWidget(QWidget):
|
||||
|
||||
parameters_changed = Signal(dict)
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__()
|
||||
self.parent = parent
|
||||
layout = QVBoxLayout(self)
|
||||
self.plot = pg.PlotWidget()
|
||||
self.plot.enableAutoRange()
|
||||
layout.addWidget(self.plot)
|
||||
|
||||
def update_plot(self, scan_parameters):
|
||||
x = np.linspace(scan_parameters["start"], scan_parameters["stop"], PLOT_RESOLUTION)
|
||||
x_sin = np.linspace(0, np.pi, PLOT_RESOLUTION)
|
||||
y = 1 * np.sin(x_sin)
|
||||
|
||||
self.plot.clear()
|
||||
self.plot.plot(x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
apply_theme("light")
|
||||
dispatcher = BECDispatcher(gui_id="scan_control_advanced")
|
||||
win = ScanControlAdvanced()
|
||||
win.show()
|
||||
sys.exit(app.exec_())
|
||||
@@ -0,0 +1 @@
|
||||
{'files': ['scan_control_advanced.py']}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtWidgets import QWidget
|
||||
|
||||
from .scan_control_advanced import ScanControlAdvanced
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='ScanControlAdvanced' name='scan_control_advanced'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class ScanControlAdvancedPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
if parent is None:
|
||||
return QWidget()
|
||||
t = ScanControlAdvanced(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return ""
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(ScanControlAdvanced.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "scan_control_advanced"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "ScanControlAdvanced"
|
||||
|
||||
def toolTip(self):
|
||||
return "ScanControlAdvanced"
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
Reference in New Issue
Block a user