wip
This commit is contained in:
@@ -41,15 +41,19 @@ from qtpy.QtWidgets import (
|
||||
QDialogButtonBox,
|
||||
QDoubleSpinBox,
|
||||
QFormLayout,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QMessageBox,
|
||||
QPushButton,
|
||||
QTabWidget,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from ..scan_control_xas.scan_control_xas import ScanControlXAS
|
||||
from .qt_widgets import MyButton
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -204,10 +208,119 @@ class ScheduleItemDialog(QDialog):
|
||||
)
|
||||
)
|
||||
self.custom_edit = QLineEdit()
|
||||
# TODO Change to a different placeholder text
|
||||
self.custom_edit.setPlaceholderText("scans.xas_simple_scan(12000, 14000, 2, 10)")
|
||||
layout.addWidget(self.custom_edit)
|
||||
|
||||
ic_form = self._create_ionization_chamber_form()
|
||||
if ic_form is not None:
|
||||
layout.addWidget(ic_form)
|
||||
|
||||
reffoil_form = self._create_reffoil_form()
|
||||
if reffoil_form is not None:
|
||||
layout.addWidget(reffoil_form)
|
||||
|
||||
layout.addStretch(1)
|
||||
self.tabs.addTab(tab, "Custom")
|
||||
self.tabs.addTab(tab, "Other")
|
||||
|
||||
def _create_ionization_chamber_form(self):
|
||||
if all(key in self._dev for key in ("ic0", "ic1", "ic2")):
|
||||
ic_group = QGroupBox("Ionization chamber filling")
|
||||
layout = QVBoxLayout(ic_group)
|
||||
form = QFormLayout()
|
||||
layout.addLayout(form)
|
||||
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.FieldsStayAtSizeHint)
|
||||
self.ic_selector = QComboBox()
|
||||
self.ic_selector.addItems(["IC0", "IC1", "IC2"])
|
||||
gases = ["He", "N2", "Ar", "Kr"]
|
||||
self.gas1 = QComboBox()
|
||||
self.gas2 = QComboBox()
|
||||
self.gas1.addItems(gases)
|
||||
self.gas2.addItems(gases)
|
||||
self.conc1 = QDoubleSpinBox()
|
||||
self.conc2 = QDoubleSpinBox()
|
||||
for conc in [self.conc1, self.conc2]:
|
||||
conc.setDecimals(0)
|
||||
conc.setSuffix(" %")
|
||||
conc.setMinimum(0)
|
||||
conc.setMaximum(100)
|
||||
conc.setSingleStep(1)
|
||||
self.pressure = QDoubleSpinBox()
|
||||
self.pressure.setDecimals(3)
|
||||
self.pressure.setSuffix(" bar abs")
|
||||
self.pressure.setMinimum(1)
|
||||
self.pressure.setMaximum(3)
|
||||
self.pressure.setSingleStep(0.1)
|
||||
|
||||
form.addRow("Ionization chamber", self.ic_selector)
|
||||
form.addRow("Gas 1", self.gas1)
|
||||
form.addRow("Concentration 1", self.conc1)
|
||||
form.addRow("Gas 2", self.gas2)
|
||||
form.addRow("Concentration 2", self.conc2)
|
||||
form.addRow("Pressure", self.pressure)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
generate_cmd = MyButton("Generate command", "default")
|
||||
button_layout.addWidget(generate_cmd)
|
||||
button_layout.addStretch(1)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
self.conc1.valueChanged.connect(self._equalize_ic_conc)
|
||||
self.conc2.valueChanged.connect(self._equalize_ic_conc)
|
||||
generate_cmd.clicked.connect(self._generate_ic_command)
|
||||
|
||||
return ic_group
|
||||
return None
|
||||
|
||||
def _equalize_ic_conc(self, new_val):
|
||||
if self.conc1.value() == new_val: # conc1 was changed
|
||||
self.conc2.setValue(100 - new_val)
|
||||
else:
|
||||
self.conc1.setValue(100 - new_val)
|
||||
|
||||
def _generate_ic_command(self):
|
||||
match self.ic_selector.currentText():
|
||||
case "IC0":
|
||||
ic = "ic0"
|
||||
case "IC1":
|
||||
ic = "ic1"
|
||||
case "IC2":
|
||||
ic = "ic2"
|
||||
cmd = (
|
||||
f"dev.{ic}.fill("
|
||||
+ f"gas1='{self.gas1.currentText()}', conc1={self.conc1.value()}, "
|
||||
+ f"gas2='{self.gas2.currentText()}', conc2={self.conc2.value()}, "
|
||||
+ f"pressure={self.pressure.value()}, wait=True)"
|
||||
)
|
||||
self.custom_edit.setText(cmd)
|
||||
|
||||
def _create_reffoil_form(self):
|
||||
if "reffoilchanger" in self._dev:
|
||||
reffoil_group = QGroupBox("Reference foil changer")
|
||||
layout = QVBoxLayout(reffoil_group)
|
||||
form = QFormLayout()
|
||||
layout.addLayout(form)
|
||||
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.FieldsStayAtSizeHint)
|
||||
self.reffoil_selector = QComboBox()
|
||||
available_foils = self._dev.reffoilchanger.get_all_foils()
|
||||
self.reffoil_selector.addItems(available_foils)
|
||||
|
||||
form.addRow("Reference foil", self.reffoil_selector)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
generate_cmd = MyButton("Generate command", "default")
|
||||
button_layout.addWidget(generate_cmd)
|
||||
button_layout.addStretch(1)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
generate_cmd.clicked.connect(self._generate_reffoil_command)
|
||||
|
||||
return reffoil_group
|
||||
return None
|
||||
|
||||
def _generate_reffoil_command(self):
|
||||
cmd = f"dev.reffoilchanger.insert(ref='{self.reffoil_selector.currentText()}', wait=True)"
|
||||
self.custom_edit.setText(cmd)
|
||||
|
||||
def _collect_custom_result(self) -> dict:
|
||||
text = self.custom_edit.text().strip()
|
||||
|
||||
@@ -129,7 +129,7 @@ def notify_item_finished(
|
||||
text = text + f"\nScan number: {scan_number}"
|
||||
text = text + f"\n\nCommand: {command}"
|
||||
if error:
|
||||
text += f"\n{error.strip().splitlines()[-1]}"
|
||||
text += f"\n\n{error.strip().splitlines()[-1]}"
|
||||
|
||||
try:
|
||||
send_notification(client, settings, text)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
from bec_widgets.utils.colors import get_accent_colors
|
||||
from qtpy.QtCore import Qt, Signal
|
||||
|
||||
# pylint: disable=E0611
|
||||
from qtpy.QtGui import QKeySequence
|
||||
from qtpy.QtWidgets import QListWidget, QPushButton
|
||||
|
||||
|
||||
class MyListWidget(QListWidget):
|
||||
deletePressed = Signal()
|
||||
emptySpaceClicked = Signal()
|
||||
copyPressed = Signal()
|
||||
pastePressed = Signal()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == Qt.Key_Delete and self.currentItem() is not None:
|
||||
self.deletePressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
if event.matches(QKeySequence.StandardKey.Copy) and self.currentItem() is not None:
|
||||
self.copyPressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
if event.matches(QKeySequence.StandardKey.Paste):
|
||||
self.pastePressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
super().keyPressEvent(event)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.LeftButton and self.itemAt(event.position().toPoint()) is None:
|
||||
self.clearSelection()
|
||||
self.setCurrentRow(-1)
|
||||
self.emptySpaceClicked.emit()
|
||||
return
|
||||
|
||||
super().mousePressEvent(event)
|
||||
|
||||
|
||||
class MyButton(QPushButton):
|
||||
def __init__(self, text="", color="default", parent=None):
|
||||
self.color = color
|
||||
super().__init__(text, parent)
|
||||
self.apply_theme()
|
||||
|
||||
def apply_theme(self):
|
||||
if self.isEnabled():
|
||||
colors = get_accent_colors()
|
||||
color = getattr(colors, self.color).name()
|
||||
self.setStyleSheet(f"QPushButton {{ background-color: {color}; color: white; }}")
|
||||
else:
|
||||
self.setStyleSheet(
|
||||
"QPushButton {{background-color: rgb(120, 120, 120); color: white;}}"
|
||||
)
|
||||
|
||||
def setEnabled(self, enable: bool = True):
|
||||
super().setEnabled(enable)
|
||||
self.apply_theme()
|
||||
@@ -22,13 +22,11 @@ from bec_lib.messages import VariableMessage
|
||||
from bec_qthemes import material_icon
|
||||
from bec_widgets.utils.bec_connector import ConnectionConfig
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.colors import get_accent_colors
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
from pydantic import ValidationError
|
||||
|
||||
# pylint: disable=E0611
|
||||
from qtpy.QtCore import Qt, QTimer, Signal
|
||||
from qtpy.QtGui import QKeySequence
|
||||
from qtpy.QtWidgets import (
|
||||
QApplication,
|
||||
QDialog,
|
||||
@@ -37,11 +35,9 @@ from qtpy.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QListWidget,
|
||||
QListWidgetItem,
|
||||
QMessageBox,
|
||||
QPlainTextEdit,
|
||||
QPushButton,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
@@ -58,6 +54,7 @@ from .notifications import (
|
||||
notify_item_finished,
|
||||
notify_schedule_state,
|
||||
)
|
||||
from .qt_widgets import MyButton, MyListWidget
|
||||
from .schedule_item import Schedule, ScheduleItem
|
||||
from .schedule_logic import index_of, pick_next_runnable, protected_prefix_length
|
||||
|
||||
@@ -97,60 +94,6 @@ class ScheduleWidgetConfig(ConnectionConfig):
|
||||
schedule_name: str = "default_schedule"
|
||||
|
||||
|
||||
class MyListWidget(QListWidget):
|
||||
deletePressed = Signal()
|
||||
emptySpaceClicked = Signal()
|
||||
copyPressed = Signal()
|
||||
pastePressed = Signal()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == Qt.Key_Delete and self.currentItem() is not None:
|
||||
self.deletePressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
if event.matches(QKeySequence.StandardKey.Copy) and self.currentItem() is not None:
|
||||
self.copyPressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
if event.matches(QKeySequence.StandardKey.Paste):
|
||||
self.pastePressed.emit()
|
||||
event.accept()
|
||||
return
|
||||
|
||||
super().keyPressEvent(event)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.LeftButton and self.itemAt(event.position().toPoint()) is None:
|
||||
self.clearSelection()
|
||||
self.setCurrentRow(-1)
|
||||
self.emptySpaceClicked.emit()
|
||||
return
|
||||
|
||||
super().mousePressEvent(event)
|
||||
|
||||
|
||||
class MyButton(QPushButton):
|
||||
def __init__(self, text="", color="default", parent=None):
|
||||
self.color = color
|
||||
super().__init__(text, parent)
|
||||
|
||||
def apply_theme(self):
|
||||
if self.isEnabled():
|
||||
colors = get_accent_colors()
|
||||
color = getattr(colors, self.color).name()
|
||||
self.setStyleSheet(f"QPushButton {{ background-color: {color}; color: white; }}")
|
||||
else:
|
||||
self.setStyleSheet(
|
||||
"QPushButton {{background-color: rgb(120, 120, 120); color: white;}}"
|
||||
)
|
||||
|
||||
def setEnabled(self, enable: bool = True):
|
||||
super().setEnabled(enable)
|
||||
self.apply_theme()
|
||||
|
||||
|
||||
class Scheduler(BECWidget, QWidget):
|
||||
"""Schedule, persist and execute a sequence of BEC scan/device commands."""
|
||||
|
||||
@@ -1192,7 +1135,7 @@ class Scheduler(BECWidget, QWidget):
|
||||
|
||||
def _run_all(self, repeat_aborted_item):
|
||||
notify_schedule_state(
|
||||
self.client, self.schedule.notifications, self.schedule_name, "started"
|
||||
self.client, self.schedule.notifications, self.schedule.schedule_name, "started"
|
||||
)
|
||||
namespace = {"scans": self.scans, "dev": self.dev}
|
||||
while not self._abort_requested and not self._closing.is_set():
|
||||
@@ -1207,15 +1150,18 @@ class Scheduler(BECWidget, QWidget):
|
||||
self._execute_item(next_item, namespace)
|
||||
if self._abort_requested:
|
||||
notify_schedule_state(
|
||||
self.client, self.schedule.notifications, self.schedule_name, "aborted"
|
||||
self.client, self.schedule.notifications, self.schedule.schedule_name, "aborted"
|
||||
)
|
||||
elif self._closing.is_set():
|
||||
notify_schedule_state(
|
||||
self.client, self.schedule.notifications, self.schedule_name, "widget_closed"
|
||||
self.client,
|
||||
self.schedule.notifications,
|
||||
self.schedule.schedule_name,
|
||||
"widget_closed",
|
||||
)
|
||||
else:
|
||||
notify_schedule_state(
|
||||
self.client, self.schedule.notifications, self.schedule_name, "finished"
|
||||
self.client, self.schedule.notifications, self.schedule.schedule_name, "finished"
|
||||
)
|
||||
with self._lock:
|
||||
logger.info("in _run_all, set is_running to false")
|
||||
@@ -1252,7 +1198,9 @@ class Scheduler(BECWidget, QWidget):
|
||||
item.request_id = getattr(request, "requestID", None)
|
||||
self._persist_locked()
|
||||
|
||||
report.wait()
|
||||
# RPC commands may not return a status, thus have no wait()
|
||||
if item.kind != "custom":
|
||||
report.wait()
|
||||
|
||||
if self._closing.is_set():
|
||||
# The widget was closed mid-item; exit without changing status in Redis.
|
||||
|
||||
Reference in New Issue
Block a user