mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix: compatibility adjustment to .ui loading and tests for PySide6
This commit is contained in:
@ -1,307 +0,0 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import h5py
|
|
||||||
import numpy as np
|
|
||||||
import pyqtgraph as pg
|
|
||||||
import zmq
|
|
||||||
from pyqtgraph.Qt import uic
|
|
||||||
from qtpy.QtCore import Signal as pyqtSignal
|
|
||||||
from qtpy.QtCore import Slot as pyqtSlot
|
|
||||||
from qtpy.QtGui import QKeySequence
|
|
||||||
from qtpy.QtWidgets import QDialog, QFileDialog, QFrame, QLabel, QShortcut, QVBoxLayout, QWidget
|
|
||||||
|
|
||||||
# from scipy.stats import multivariate_normal
|
|
||||||
|
|
||||||
|
|
||||||
class EigerPlot(QWidget):
|
|
||||||
update_signal = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
# pg.setConfigOptions(background="w", foreground="k", antialias=True)
|
|
||||||
|
|
||||||
current_path = os.path.dirname(__file__)
|
|
||||||
uic.loadUi(os.path.join(current_path, "eiger_plot.ui"), self)
|
|
||||||
|
|
||||||
# Set widow name
|
|
||||||
self.setWindowTitle("Eiger Plot")
|
|
||||||
|
|
||||||
self.hist_lims = None
|
|
||||||
self.mask = None
|
|
||||||
self.image = None
|
|
||||||
|
|
||||||
# UI
|
|
||||||
self.init_ui()
|
|
||||||
self.hook_signals()
|
|
||||||
self.key_bindings()
|
|
||||||
|
|
||||||
# ZMQ Consumer
|
|
||||||
self._zmq_consumer_exit_event = threading.Event()
|
|
||||||
self._zmq_consumer_thread = self.start_zmq_consumer()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
super().close()
|
|
||||||
self._zmq_consumer_exit_event.set()
|
|
||||||
self._zmq_consumer_thread.join()
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
# Create Plot and add ImageItem
|
|
||||||
self.plot_item = pg.PlotItem()
|
|
||||||
self.plot_item.setAspectLocked(True)
|
|
||||||
self.imageItem = pg.ImageItem()
|
|
||||||
self.plot_item.addItem(self.imageItem)
|
|
||||||
|
|
||||||
# Setting up histogram
|
|
||||||
self.hist = pg.HistogramLUTItem()
|
|
||||||
self.hist.setImageItem(self.imageItem)
|
|
||||||
self.hist.gradient.loadPreset("magma")
|
|
||||||
self.update_hist()
|
|
||||||
|
|
||||||
# Adding Items to Graphical Layout
|
|
||||||
self.glw.addItem(self.plot_item)
|
|
||||||
self.glw.addItem(self.hist)
|
|
||||||
|
|
||||||
def hook_signals(self):
|
|
||||||
# Buttons
|
|
||||||
# self.pushButton_test.clicked.connect(self.start_sim_stream)
|
|
||||||
self.pushButton_mask.clicked.connect(self.load_mask_dialog)
|
|
||||||
self.pushButton_delete_mask.clicked.connect(self.delete_mask)
|
|
||||||
self.pushButton_help.clicked.connect(self.show_help_dialog)
|
|
||||||
|
|
||||||
# SpinBoxes
|
|
||||||
self.doubleSpinBox_hist_min.valueChanged.connect(self.update_hist)
|
|
||||||
self.doubleSpinBox_hist_max.valueChanged.connect(self.update_hist)
|
|
||||||
|
|
||||||
# Signal/Slots
|
|
||||||
self.update_signal.connect(self.on_image_update)
|
|
||||||
|
|
||||||
def key_bindings(self):
|
|
||||||
# Key bindings for rotation
|
|
||||||
rotate_plus = QShortcut(QKeySequence("Ctrl+A"), self)
|
|
||||||
rotate_minus = QShortcut(QKeySequence("Ctrl+Z"), self)
|
|
||||||
self.comboBox_rotation.setToolTip("Increase rotation: Ctrl+A\nDecrease rotation: Ctrl+Z")
|
|
||||||
self.checkBox_transpose.setToolTip("Toggle transpose: Ctrl+T")
|
|
||||||
|
|
||||||
max_index = self.comboBox_rotation.count() - 1 # Maximum valid index
|
|
||||||
|
|
||||||
rotate_plus.activated.connect(
|
|
||||||
lambda: self.comboBox_rotation.setCurrentIndex(
|
|
||||||
min(self.comboBox_rotation.currentIndex() + 1, max_index)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
rotate_minus.activated.connect(
|
|
||||||
lambda: self.comboBox_rotation.setCurrentIndex(
|
|
||||||
max(self.comboBox_rotation.currentIndex() - 1, 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Key bindings for transpose
|
|
||||||
transpose = QShortcut(QKeySequence("Ctrl+T"), self)
|
|
||||||
transpose.activated.connect(self.checkBox_transpose.toggle)
|
|
||||||
|
|
||||||
FFT = QShortcut(QKeySequence("Ctrl+F"), self)
|
|
||||||
FFT.activated.connect(self.checkBox_FFT.toggle)
|
|
||||||
self.checkBox_FFT.setToolTip("Toggle FFT: Ctrl+F")
|
|
||||||
|
|
||||||
log = QShortcut(QKeySequence("Ctrl+L"), self)
|
|
||||||
log.activated.connect(self.checkBox_log.toggle)
|
|
||||||
self.checkBox_log.setToolTip("Toggle log: Ctrl+L")
|
|
||||||
|
|
||||||
mask = QShortcut(QKeySequence("Ctrl+M"), self)
|
|
||||||
mask.activated.connect(self.pushButton_mask.click)
|
|
||||||
self.pushButton_mask.setToolTip("Load mask: Ctrl+M")
|
|
||||||
|
|
||||||
delete_mask = QShortcut(QKeySequence("Ctrl+D"), self)
|
|
||||||
delete_mask.activated.connect(self.pushButton_delete_mask.click)
|
|
||||||
self.pushButton_delete_mask.setToolTip("Delete mask: Ctrl+D")
|
|
||||||
|
|
||||||
def update_hist(self):
|
|
||||||
self.hist_levels = [
|
|
||||||
self.doubleSpinBox_hist_min.value(),
|
|
||||||
self.doubleSpinBox_hist_max.value(),
|
|
||||||
]
|
|
||||||
self.hist.setLevels(min=self.hist_levels[0], max=self.hist_levels[1])
|
|
||||||
self.hist.setHistogramRange(
|
|
||||||
self.hist_levels[0] - 0.1 * self.hist_levels[0],
|
|
||||||
self.hist_levels[1] + 0.1 * self.hist_levels[1],
|
|
||||||
)
|
|
||||||
|
|
||||||
def load_mask_dialog(self):
|
|
||||||
options = QFileDialog.Options()
|
|
||||||
options |= QFileDialog.ReadOnly
|
|
||||||
file_name, _ = QFileDialog.getOpenFileName(
|
|
||||||
self, "Select Mask File", "", "H5 Files (*.h5);;All Files (*)", options=options
|
|
||||||
)
|
|
||||||
if file_name:
|
|
||||||
self.load_mask(file_name)
|
|
||||||
|
|
||||||
def load_mask(self, path):
|
|
||||||
try:
|
|
||||||
with h5py.File(path, "r") as f:
|
|
||||||
self.mask = f["data"][...]
|
|
||||||
if self.mask is not None:
|
|
||||||
# Set label to mask name without path
|
|
||||||
self.label_mask.setText(os.path.basename(path))
|
|
||||||
except KeyError as e:
|
|
||||||
# Update GUI with the error message
|
|
||||||
print(f"Error: {str(e)}")
|
|
||||||
|
|
||||||
def delete_mask(self):
|
|
||||||
self.mask = None
|
|
||||||
self.label_mask.setText("No Mask")
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def on_image_update(self):
|
|
||||||
# TODO first rotate then transpose
|
|
||||||
if self.mask is not None:
|
|
||||||
# self.image = np.ma.masked_array(self.image, mask=self.mask) #TODO test if np works
|
|
||||||
self.image = self.image * (1 - self.mask) + 1
|
|
||||||
|
|
||||||
if self.checkBox_FFT.isChecked():
|
|
||||||
self.image = np.abs(np.fft.fftshift(np.fft.fft2(self.image)))
|
|
||||||
|
|
||||||
if self.comboBox_rotation.currentIndex() > 0: # rotate
|
|
||||||
self.image = np.rot90(self.image, k=self.comboBox_rotation.currentIndex(), axes=(0, 1))
|
|
||||||
|
|
||||||
if self.checkBox_transpose.isChecked(): # transpose
|
|
||||||
self.image = np.transpose(self.image)
|
|
||||||
|
|
||||||
if self.checkBox_log.isChecked():
|
|
||||||
self.image = np.log10(self.image)
|
|
||||||
|
|
||||||
self.imageItem.setImage(self.image, autoLevels=False)
|
|
||||||
|
|
||||||
###############################
|
|
||||||
# ZMQ Consumer
|
|
||||||
###############################
|
|
||||||
|
|
||||||
def start_zmq_consumer(self):
|
|
||||||
consumer_thread = threading.Thread(
|
|
||||||
target=self.zmq_consumer, args=(self._zmq_consumer_exit_event,), daemon=True
|
|
||||||
)
|
|
||||||
consumer_thread.start()
|
|
||||||
return consumer_thread
|
|
||||||
|
|
||||||
def zmq_consumer(self, exit_event):
|
|
||||||
print("starting consumer")
|
|
||||||
live_stream_url = "tcp://129.129.95.38:20000"
|
|
||||||
receiver = zmq.Context().socket(zmq.SUB)
|
|
||||||
receiver.connect(live_stream_url)
|
|
||||||
receiver.setsockopt_string(zmq.SUBSCRIBE, "")
|
|
||||||
|
|
||||||
poller = zmq.Poller()
|
|
||||||
poller.register(receiver, zmq.POLLIN)
|
|
||||||
|
|
||||||
# code could be a bit simpler here, testing exit_event in
|
|
||||||
# 'while' condition, but like this it is easier for the
|
|
||||||
# 'test_zmq_consumer' test
|
|
||||||
while True:
|
|
||||||
if poller.poll(1000): # 1s timeout
|
|
||||||
raw_meta, raw_data = receiver.recv_multipart(zmq.NOBLOCK)
|
|
||||||
|
|
||||||
meta = json.loads(raw_meta.decode("utf-8"))
|
|
||||||
self.image = np.frombuffer(raw_data, dtype=meta["type"]).reshape(meta["shape"])
|
|
||||||
self.update_signal.emit()
|
|
||||||
if exit_event.is_set():
|
|
||||||
break
|
|
||||||
|
|
||||||
receiver.disconnect(live_stream_url)
|
|
||||||
|
|
||||||
###############################
|
|
||||||
# just simulations from here
|
|
||||||
###############################
|
|
||||||
|
|
||||||
def show_help_dialog(self):
|
|
||||||
dialog = QDialog(self)
|
|
||||||
dialog.setWindowTitle("Help")
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
|
|
||||||
# Key bindings section
|
|
||||||
layout.addWidget(QLabel("Keyboard Shortcuts:"))
|
|
||||||
|
|
||||||
key_bindings = [
|
|
||||||
("Ctrl+A", "Increase rotation"),
|
|
||||||
("Ctrl+Z", "Decrease rotation"),
|
|
||||||
("Ctrl+T", "Toggle transpose"),
|
|
||||||
("Ctrl+F", "Toggle FFT"),
|
|
||||||
("Ctrl+L", "Toggle log scale"),
|
|
||||||
("Ctrl+M", "Load mask"),
|
|
||||||
("Ctrl+D", "Delete mask"),
|
|
||||||
]
|
|
||||||
|
|
||||||
for keys, action in key_bindings:
|
|
||||||
layout.addWidget(QLabel(f"{keys} - {action}"))
|
|
||||||
|
|
||||||
# Separator
|
|
||||||
separator = QFrame()
|
|
||||||
separator.setFrameShape(QFrame.HLine)
|
|
||||||
separator.setFrameShadow(QFrame.Sunken)
|
|
||||||
layout.addWidget(separator)
|
|
||||||
|
|
||||||
# Histogram section
|
|
||||||
layout.addWidget(QLabel("Histogram:"))
|
|
||||||
layout.addWidget(
|
|
||||||
QLabel(
|
|
||||||
"Use the Double Spin Boxes to adjust the minimum and maximum values of the histogram."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Another Separator
|
|
||||||
another_separator = QFrame()
|
|
||||||
another_separator.setFrameShape(QFrame.HLine)
|
|
||||||
another_separator.setFrameShadow(QFrame.Sunken)
|
|
||||||
layout.addWidget(another_separator)
|
|
||||||
|
|
||||||
# Mask section
|
|
||||||
layout.addWidget(QLabel("Mask:"))
|
|
||||||
layout.addWidget(
|
|
||||||
QLabel(
|
|
||||||
"Use 'Load Mask' to load a mask from an H5 file. 'Delete Mask' removes the current mask."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
dialog.setLayout(layout)
|
|
||||||
dialog.exec()
|
|
||||||
|
|
||||||
###############################
|
|
||||||
# just simulations from here
|
|
||||||
###############################
|
|
||||||
# def start_sim_stream(self):
|
|
||||||
# sim_stream_thread = threading.Thread(target=self.sim_stream, daemon=True)
|
|
||||||
# sim_stream_thread.start()
|
|
||||||
#
|
|
||||||
# def sim_stream(self):
|
|
||||||
# for i in range(100):
|
|
||||||
# # Generate 100x100 image of random noise
|
|
||||||
# self.image = np.random.rand(100, 100) * 0.2
|
|
||||||
#
|
|
||||||
# # Define Gaussian parameters
|
|
||||||
# x, y = np.mgrid[0:50, 0:50]
|
|
||||||
# pos = np.dstack((x, y))
|
|
||||||
#
|
|
||||||
# # Center at (25, 25) longer along y-axis
|
|
||||||
# rv = multivariate_normal(mean=[25, 25], cov=[[25, 0], [0, 80]])
|
|
||||||
#
|
|
||||||
# # Generate Gaussian in the first quadrant
|
|
||||||
# gaussian_quadrant = rv.pdf(pos) * 40
|
|
||||||
#
|
|
||||||
# # Place Gaussian in the first quadrant
|
|
||||||
# self.image[0:50, 0:50] += gaussian_quadrant * 10
|
|
||||||
#
|
|
||||||
# self.update_signal.emit()
|
|
||||||
# time.sleep(0.1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from qtpy.QtWidgets import QApplication
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
plot = EigerPlot()
|
|
||||||
plot.show()
|
|
||||||
sys.exit(app.exec())
|
|
@ -1,207 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>Form</class>
|
|
||||||
<widget class="QWidget" name="Form">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>874</width>
|
|
||||||
<height>762</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Plot Control</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Histogram MIN</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_hist_min">
|
|
||||||
<property name="minimum">
|
|
||||||
<double>-100000.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>100000.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Histogram MAX</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_hist_max">
|
|
||||||
<property name="minimum">
|
|
||||||
<double>-100000.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>100000.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>2.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
|
||||||
<property name="title">
|
|
||||||
<string>Data Control</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="checkBox_FFT">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>FFT</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="checkBox_log">
|
|
||||||
<property name="text">
|
|
||||||
<string>log</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_mask">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load Mask</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_delete_mask">
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete Mask</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Orientation</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QComboBox" name="comboBox_rotation">
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>0</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>90</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>180</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>270</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Rotation</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="checkBox_transpose">
|
|
||||||
<property name="text">
|
|
||||||
<string>Transpose</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_4">
|
|
||||||
<property name="title">
|
|
||||||
<string>Help</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_mask">
|
|
||||||
<property name="text">
|
|
||||||
<string>No Mask</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_help">
|
|
||||||
<property name="text">
|
|
||||||
<string>Help</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="GraphicsLayoutWidget" name="glw"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>GraphicsLayoutWidget</class>
|
|
||||||
<extends>QGraphicsView</extends>
|
|
||||||
<header>pyqtgraph.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -2,7 +2,7 @@ import os
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtWidgets, uic
|
from pyqtgraph.Qt import QtWidgets
|
||||||
from qtconsole.inprocess import QtInProcessKernelManager
|
from qtconsole.inprocess import QtInProcessKernelManager
|
||||||
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
||||||
from qtpy.QtCore import QSize
|
from qtpy.QtCore import QSize
|
||||||
@ -10,7 +10,7 @@ from qtpy.QtGui import QIcon
|
|||||||
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.cli.rpc_register import RPCRegister
|
from bec_widgets.cli.rpc_register import RPCRegister
|
||||||
from bec_widgets.utils import BECDispatcher
|
from bec_widgets.utils import BECDispatcher, UILoader
|
||||||
from bec_widgets.widgets import BECFigure
|
from bec_widgets.widgets import BECFigure
|
||||||
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
||||||
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
||||||
@ -40,11 +40,11 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
uic.loadUi(os.path.join(current_path, "jupyter_console_window.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "jupyter_console_window.ui"), self)
|
||||||
|
|
||||||
self._init_ui()
|
self._init_ui()
|
||||||
|
|
||||||
self.splitter.setSizes([200, 100])
|
self.ui.splitter.setSizes([200, 100])
|
||||||
self.safe_close = False
|
self.safe_close = False
|
||||||
# self.figure.clean_signal.connect(self.confirm_close)
|
# self.figure.clean_signal.connect(self.confirm_close)
|
||||||
|
|
||||||
@ -75,11 +75,11 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
|
|
||||||
def _init_ui(self):
|
def _init_ui(self):
|
||||||
# Plotting window
|
# Plotting window
|
||||||
self.glw_1_layout = QVBoxLayout(self.glw) # Create a new QVBoxLayout
|
self.glw_1_layout = QVBoxLayout(self.ui.glw) # Create a new QVBoxLayout
|
||||||
self.figure = BECFigure(parent=self, gui_id="remote") # Create a new BECDeviceMonitor
|
self.figure = BECFigure(parent=self, gui_id="remote") # Create a new BECDeviceMonitor
|
||||||
self.glw_1_layout.addWidget(self.figure) # Add BECDeviceMonitor to the layout
|
self.glw_1_layout.addWidget(self.figure) # Add BECDeviceMonitor to the layout
|
||||||
|
|
||||||
self.dock_layout = QVBoxLayout(self.dock_placeholder)
|
self.dock_layout = QVBoxLayout(self.ui.dock_placeholder)
|
||||||
self.dock = BECDockArea(gui_id="remote")
|
self.dock = BECDockArea(gui_id="remote")
|
||||||
self.dock_layout.addWidget(self.dock)
|
self.dock_layout.addWidget(self.dock)
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
# init dock for testing
|
# init dock for testing
|
||||||
self._init_dock()
|
self._init_dock()
|
||||||
|
|
||||||
self.console_layout = QVBoxLayout(self.widget_console)
|
self.console_layout = QVBoxLayout(self.ui.widget_console)
|
||||||
self.console = JupyterConsoleWidget()
|
self.console = JupyterConsoleWidget()
|
||||||
self.console_layout.addWidget(self.console)
|
self.console_layout.addWidget(self.console)
|
||||||
self.console.set_default_style("linux")
|
self.console.set_default_style("linux")
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MainWindow</class>
|
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1433</width>
|
|
||||||
<height>689</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>MainWindow</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget">
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Plot Config 2</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" colspan="2">
|
|
||||||
<widget class="BECMonitor" name="plot_1"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="3">
|
|
||||||
<widget class="QPushButton" name="pushButton_setting_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Setting Plot 2</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2" colspan="2">
|
|
||||||
<widget class="BECMonitor" name="plot_2"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="4">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Plot Scan Types = True</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QPushButton" name="pushButton_setting_1">
|
|
||||||
<property name="text">
|
|
||||||
<string>Setting Plot 1</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Plot Config 1</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="5">
|
|
||||||
<widget class="QPushButton" name="pushButton_setting_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Setting Plot 3</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="4" colspan="2">
|
|
||||||
<widget class="BECMonitor" name="plot_3"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenuBar" name="menubar">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1433</width>
|
|
||||||
<height>37</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>BECMonitor</class>
|
|
||||||
<extends>QGraphicsView</extends>
|
|
||||||
<header location="global">bec_widgets.widgets.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,197 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from qtpy import uic
|
|
||||||
from qtpy.QtWidgets import QApplication, QMainWindow
|
|
||||||
|
|
||||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
|
||||||
from bec_widgets.widgets import BECMonitor
|
|
||||||
|
|
||||||
# some default configs for demonstration purposes
|
|
||||||
CONFIG_SIMPLE = {
|
|
||||||
"plot_settings": {
|
|
||||||
"background_color": "black",
|
|
||||||
"num_columns": 2,
|
|
||||||
"colormap": "plasma",
|
|
||||||
"scan_types": False,
|
|
||||||
},
|
|
||||||
"plot_data": [
|
|
||||||
{
|
|
||||||
"plot_name": "BPM4i plots vs samx",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "bpm4i",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx"}],
|
|
||||||
"y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
# {
|
|
||||||
# "type": "history",
|
|
||||||
# "signals": {
|
|
||||||
# "x": [{"name": "samx"}],
|
|
||||||
# "y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
|
||||||
# },
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "type": "dap",
|
|
||||||
# 'worker':'some_worker',
|
|
||||||
# "signals": {
|
|
||||||
# "x": [{"name": "samx"}],
|
|
||||||
# "y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
|
||||||
# },
|
|
||||||
# },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plot_name": "Gauss plots vs samx",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "Gauss",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx", "entry": "samx"}],
|
|
||||||
"y": [{"name": "gauss_bpm"}, {"name": "gauss_adc1"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCAN_MODE = {
|
|
||||||
"plot_settings": {
|
|
||||||
"background_color": "white",
|
|
||||||
"num_columns": 3,
|
|
||||||
"colormap": "plasma",
|
|
||||||
"scan_types": True,
|
|
||||||
},
|
|
||||||
"plot_data": {
|
|
||||||
"grid_scan": [
|
|
||||||
{
|
|
||||||
"plot_name": "Grid plot 1",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "BPM",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx", "entry": "samx"}],
|
|
||||||
"y": [{"name": "gauss_bpm"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plot_name": "Grid plot 2",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "BPM",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx", "entry": "samx"}],
|
|
||||||
"y": [{"name": "gauss_adc1"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plot_name": "Grid plot 3",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "BPM",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {"x": [{"name": "samy"}], "y": [{"name": "gauss_adc2"}]},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plot_name": "Grid plot 4",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "BPM",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samy", "entry": "samy"}],
|
|
||||||
"y": [{"name": "gauss_adc3"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"line_scan": [
|
|
||||||
{
|
|
||||||
"plot_name": "BPM plots vs samx",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "Gauss",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx", "entry": "samx"}],
|
|
||||||
"y": [{"name": "bpm4i"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plot_name": "Gauss plots vs samx",
|
|
||||||
"x_label": "Motor X",
|
|
||||||
"y_label": "Gauss",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "scan_segment",
|
|
||||||
"signals": {
|
|
||||||
"x": [{"name": "samx", "entry": "samx"}],
|
|
||||||
"y": [{"name": "gauss_bpm"}, {"name": "gauss_adc1"}],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ModularApp(QMainWindow):
|
|
||||||
def __init__(self, client=None, parent=None):
|
|
||||||
super(ModularApp, self).__init__(parent)
|
|
||||||
|
|
||||||
# Client and device manager from BEC
|
|
||||||
self.client = BECDispatcher().client if client is None else client
|
|
||||||
|
|
||||||
# Loading UI
|
|
||||||
current_path = os.path.dirname(__file__)
|
|
||||||
uic.loadUi(os.path.join(current_path, "modular.ui"), self)
|
|
||||||
|
|
||||||
self._init_plots()
|
|
||||||
|
|
||||||
def _init_plots(self):
|
|
||||||
"""Initialize plots and connect the buttons to the config dialogs"""
|
|
||||||
plots = [self.plot_1, self.plot_2, self.plot_3]
|
|
||||||
configs = [CONFIG_SIMPLE, CONFIG_SCAN_MODE, CONFIG_SCAN_MODE]
|
|
||||||
buttons = [self.pushButton_setting_1, self.pushButton_setting_2, self.pushButton_setting_3]
|
|
||||||
|
|
||||||
# hook plots, configs and buttons together
|
|
||||||
for plot, config, button in zip(plots, configs, buttons):
|
|
||||||
plot.on_config_update(config)
|
|
||||||
button.clicked.connect(plot.show_config_dialog)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# BECclient global variables
|
|
||||||
client = BECDispatcher().client
|
|
||||||
client.start()
|
|
||||||
|
|
||||||
app = QApplication([])
|
|
||||||
modularApp = ModularApp(client=client)
|
|
||||||
|
|
||||||
window = modularApp
|
|
||||||
window.show()
|
|
||||||
app.exec()
|
|
@ -151,7 +151,7 @@ class MotorControlPanel(QWidget):
|
|||||||
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
||||||
|
|
||||||
# Set the window to a fixed size based on its contents
|
# Set the window to a fixed size based on its contents
|
||||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
# self.layout().setSizeConstraint(layout.SetFixedSize)
|
||||||
|
|
||||||
|
|
||||||
class MotorControlPanelAbsolute(QWidget):
|
class MotorControlPanelAbsolute(QWidget):
|
||||||
@ -178,9 +178,6 @@ class MotorControlPanelAbsolute(QWidget):
|
|||||||
# Connecting signals and slots
|
# Connecting signals and slots
|
||||||
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
||||||
|
|
||||||
# Set the window to a fixed size based on its contents
|
|
||||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
|
||||||
|
|
||||||
|
|
||||||
class MotorControlPanelRelative(QWidget):
|
class MotorControlPanelRelative(QWidget):
|
||||||
def __init__(self, parent=None, client=None, config=None):
|
def __init__(self, parent=None, client=None, config=None):
|
||||||
@ -206,9 +203,6 @@ class MotorControlPanelRelative(QWidget):
|
|||||||
# Connecting signals and slots
|
# Connecting signals and slots
|
||||||
self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
|
self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
|
||||||
|
|
||||||
# Set the window to a fixed size based on its contents
|
|
||||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -29,10 +29,10 @@
|
|||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="GraphicsLayoutWidget" name="glw_plot"/>
|
<widget class="QWidget" name="glw_plot_placeholder" native="true"/>
|
||||||
<widget class="GraphicsLayoutWidget" name="glw_image"/>
|
<widget class="QWidget" name="glw_image_placeholder" native="true"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="">
|
<widget class="QWidget" name="layoutWidget">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,1,15">
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,1,15">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_generate">
|
<widget class="QPushButton" name="pushButton_generate">
|
||||||
@ -143,13 +143,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>GraphicsLayoutWidget</class>
|
|
||||||
<extends>QGraphicsView</extends>
|
|
||||||
<header>pyqtgraph.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -9,18 +9,17 @@ from bec_lib import messages
|
|||||||
from bec_lib.endpoints import MessageEndpoints
|
from bec_lib.endpoints import MessageEndpoints
|
||||||
from bec_lib.redis_connector import RedisConnector
|
from bec_lib.redis_connector import RedisConnector
|
||||||
from pyqtgraph import mkBrush, mkPen
|
from pyqtgraph import mkBrush, mkPen
|
||||||
from pyqtgraph.Qt import QtCore, QtWidgets, uic
|
from pyqtgraph.Qt import QtCore, QtWidgets
|
||||||
from pyqtgraph.Qt.QtCore import pyqtSignal
|
from qtpy.QtCore import Signal, Slot
|
||||||
from qtpy.QtCore import Slot as pyqtSlot
|
from qtpy.QtWidgets import QTableWidgetItem, QVBoxLayout
|
||||||
from qtpy.QtWidgets import QTableWidgetItem
|
|
||||||
|
|
||||||
from bec_widgets.utils import Colors, Crosshair
|
from bec_widgets.utils import Colors, Crosshair, UILoader
|
||||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
||||||
|
|
||||||
|
|
||||||
class StreamPlot(QtWidgets.QWidget):
|
class StreamPlot(QtWidgets.QWidget):
|
||||||
update_signal = pyqtSignal()
|
update_signal = Signal()
|
||||||
roi_signal = pyqtSignal(tuple)
|
roi_signal = Signal(tuple)
|
||||||
|
|
||||||
def __init__(self, name="", y_value_list=["gauss_bpm"], client=None, parent=None) -> None:
|
def __init__(self, name="", y_value_list=["gauss_bpm"], client=None, parent=None) -> None:
|
||||||
"""
|
"""
|
||||||
@ -39,7 +38,7 @@ class StreamPlot(QtWidgets.QWidget):
|
|||||||
pg.setConfigOption("background", "w")
|
pg.setConfigOption("background", "w")
|
||||||
pg.setConfigOption("foreground", "k")
|
pg.setConfigOption("foreground", "k")
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
uic.loadUi(os.path.join(current_path, "line_plot.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "line_plot.ui"), self)
|
||||||
|
|
||||||
self._idle_time = 100
|
self._idle_time = 100
|
||||||
self.connector = RedisConnector(["localhost:6379"])
|
self.connector = RedisConnector(["localhost:6379"])
|
||||||
@ -82,6 +81,9 @@ class StreamPlot(QtWidgets.QWidget):
|
|||||||
|
|
||||||
# LabelItem for ROI
|
# LabelItem for ROI
|
||||||
self.label_plot = pg.LabelItem(justify="center")
|
self.label_plot = pg.LabelItem(justify="center")
|
||||||
|
self.glw_plot_layout = QVBoxLayout(self.ui.glw_plot_placeholder)
|
||||||
|
self.glw_plot = pg.GraphicsLayoutWidget()
|
||||||
|
self.glw_plot_layout.addWidget(self.glw_plot)
|
||||||
self.glw_plot.addItem(self.label_plot)
|
self.glw_plot.addItem(self.label_plot)
|
||||||
self.label_plot.setText("ROI region")
|
self.label_plot.setText("ROI region")
|
||||||
|
|
||||||
@ -112,6 +114,9 @@ class StreamPlot(QtWidgets.QWidget):
|
|||||||
|
|
||||||
# Label for coordinates moved
|
# Label for coordinates moved
|
||||||
self.label_image_moved = pg.LabelItem(justify="center")
|
self.label_image_moved = pg.LabelItem(justify="center")
|
||||||
|
self.glw_image_layout = QVBoxLayout(self.ui.glw_image_placeholder)
|
||||||
|
self.glw_image = pg.GraphicsLayoutWidget()
|
||||||
|
self.glw_plot_layout.addWidget(self.glw_image)
|
||||||
self.glw_image.addItem(self.label_image_moved)
|
self.glw_image.addItem(self.label_image_moved)
|
||||||
self.label_image_moved.setText("Actual coordinates (X, Y)")
|
self.label_image_moved.setText("Actual coordinates (X, Y)")
|
||||||
|
|
||||||
@ -221,10 +226,10 @@ class StreamPlot(QtWidgets.QWidget):
|
|||||||
|
|
||||||
def init_table(self):
|
def init_table(self):
|
||||||
# Init number of rows in table according to n of devices
|
# Init number of rows in table according to n of devices
|
||||||
self.cursor_table.setRowCount(len(self.y_value_list))
|
self.ui.cursor_table.setRowCount(len(self.y_value_list))
|
||||||
# self.table.setHorizontalHeaderLabels(["(X, Y) - Moved", "(X, Y) - Clicked"]) #TODO can be dynamic
|
# self.table.setHorizontalHeaderLabels(["(X, Y) - Moved", "(X, Y) - Clicked"]) #TODO can be dynamic
|
||||||
self.cursor_table.setVerticalHeaderLabels(self.y_value_list)
|
self.ui.cursor_table.setVerticalHeaderLabels(self.y_value_list)
|
||||||
self.cursor_table.resizeColumnsToContents()
|
self.ui.cursor_table.resizeColumnsToContents()
|
||||||
|
|
||||||
def update_table(self, table_widget, x, y_values):
|
def update_table(self, table_widget, x, y_values):
|
||||||
for i, y in enumerate(y_values):
|
for i, y in enumerate(y_values):
|
||||||
@ -287,13 +292,13 @@ class StreamPlot(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.update_signal.emit()
|
self.update_signal.emit()
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@Slot(dict, dict)
|
||||||
def on_dap_update(self, data: dict, metadata: dict):
|
def on_dap_update(self, data: dict, metadata: dict):
|
||||||
flipped_data = self.flip_even_rows(data["data"]["z"])
|
flipped_data = self.flip_even_rows(data["data"]["z"])
|
||||||
|
|
||||||
self.img.setImage(flipped_data)
|
self.img.setImage(flipped_data)
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@Slot(dict, dict)
|
||||||
def new_proj(self, content: dict, _metadata: dict):
|
def new_proj(self, content: dict, _metadata: dict):
|
||||||
proj_nr = content["signals"]["proj_nr"]
|
proj_nr = content["signals"]["proj_nr"]
|
||||||
endpoint = f"px_stream/projection_{proj_nr}/metadata"
|
endpoint = f"px_stream/projection_{proj_nr}/metadata"
|
||||||
|
@ -8,13 +8,13 @@ from qtpy.QtCore import Signal as pyqtSignal
|
|||||||
|
|
||||||
class Crosshair(QObject):
|
class Crosshair(QObject):
|
||||||
# Signal for 1D plot
|
# Signal for 1D plot
|
||||||
coordinatesChanged1D = pyqtSignal(float, list)
|
coordinatesChanged1D = pyqtSignal(tuple)
|
||||||
coordinatesClicked1D = pyqtSignal(float, list)
|
coordinatesClicked1D = pyqtSignal(tuple)
|
||||||
# Signal for 2D plot
|
# Signal for 2D plot
|
||||||
coordinatesChanged2D = pyqtSignal(float, float)
|
coordinatesChanged2D = pyqtSignal(tuple)
|
||||||
coordinatesClicked2D = pyqtSignal(float, float)
|
coordinatesClicked2D = pyqtSignal(tuple)
|
||||||
|
|
||||||
def __init__(self, plot_item: pg.PlotItem, precision: int = None, parent=None):
|
def __init__(self, plot_item: pg.PlotItem, precision: int = 3, parent=None):
|
||||||
"""
|
"""
|
||||||
Crosshair for 1D and 2D plots.
|
Crosshair for 1D and 2D plots.
|
||||||
|
|
||||||
@ -174,10 +174,11 @@ class Crosshair(QObject):
|
|||||||
if isinstance(item, pg.PlotDataItem):
|
if isinstance(item, pg.PlotDataItem):
|
||||||
if x is None or all(v is None for v in y_values):
|
if x is None or all(v is None for v in y_values):
|
||||||
return
|
return
|
||||||
self.coordinatesChanged1D.emit(
|
coordinate_to_emit = (
|
||||||
round(x, self.precision),
|
round(x, self.precision),
|
||||||
[round(y_val, self.precision) for y_val in y_values],
|
[round(y_val, self.precision) for y_val in y_values],
|
||||||
)
|
)
|
||||||
|
self.coordinatesChanged1D.emit(coordinate_to_emit)
|
||||||
for i, y_val in enumerate(y_values):
|
for i, y_val in enumerate(y_values):
|
||||||
self.marker_moved_1d[i].setData(
|
self.marker_moved_1d[i].setData(
|
||||||
[x if not self.is_log_x else np.log10(x)],
|
[x if not self.is_log_x else np.log10(x)],
|
||||||
@ -186,7 +187,8 @@ class Crosshair(QObject):
|
|||||||
elif isinstance(item, pg.ImageItem):
|
elif isinstance(item, pg.ImageItem):
|
||||||
if x is None or y_values is None:
|
if x is None or y_values is None:
|
||||||
return
|
return
|
||||||
self.coordinatesChanged2D.emit(x, y_values)
|
coordinate_to_emit = (x, y_values)
|
||||||
|
self.coordinatesChanged2D.emit(coordinate_to_emit)
|
||||||
|
|
||||||
def mouse_clicked(self, event):
|
def mouse_clicked(self, event):
|
||||||
"""Handles the mouse clicked event, updating the crosshair position and emitting signals.
|
"""Handles the mouse clicked event, updating the crosshair position and emitting signals.
|
||||||
@ -209,10 +211,11 @@ class Crosshair(QObject):
|
|||||||
if isinstance(item, pg.PlotDataItem):
|
if isinstance(item, pg.PlotDataItem):
|
||||||
if x is None or all(v is None for v in y_values):
|
if x is None or all(v is None for v in y_values):
|
||||||
return
|
return
|
||||||
self.coordinatesClicked1D.emit(
|
coordinate_to_emit = (
|
||||||
round(x, self.precision),
|
round(x, self.precision),
|
||||||
[round(y_val, self.precision) for y_val in y_values],
|
[round(y_val, self.precision) for y_val in y_values],
|
||||||
)
|
)
|
||||||
|
self.coordinatesClicked1D.emit(coordinate_to_emit)
|
||||||
for i, y_val in enumerate(y_values):
|
for i, y_val in enumerate(y_values):
|
||||||
for marker in self.marker_clicked_1d[i]:
|
for marker in self.marker_clicked_1d[i]:
|
||||||
marker.setData(
|
marker.setData(
|
||||||
@ -222,7 +225,8 @@ class Crosshair(QObject):
|
|||||||
elif isinstance(item, pg.ImageItem):
|
elif isinstance(item, pg.ImageItem):
|
||||||
if x is None or y_values is None:
|
if x is None or y_values is None:
|
||||||
return
|
return
|
||||||
self.coordinatesClicked2D.emit(x, y_values)
|
coordinate_to_emit = (x, y_values)
|
||||||
|
self.coordinatesClicked2D.emit(coordinate_to_emit)
|
||||||
self.marker_2d.setPos([x, y_values])
|
self.marker_2d.setPos([x, y_values])
|
||||||
|
|
||||||
def check_log(self):
|
def check_log(self):
|
||||||
|
@ -16,6 +16,7 @@ from qtpy.QtWidgets import (
|
|||||||
QTableWidgetItem,
|
QTableWidgetItem,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from bec_widgets.utils import UILoader
|
||||||
from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
|
from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
|
||||||
|
|
||||||
|
|
||||||
@ -37,25 +38,25 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
def _load_ui(self):
|
def _load_ui(self):
|
||||||
"""Load the UI for the coordinate table."""
|
"""Load the UI for the coordinate table."""
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
uic.loadUi(os.path.join(current_path, "motor_table.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "motor_table.ui"), self)
|
||||||
|
|
||||||
def _init_ui(self):
|
def _init_ui(self):
|
||||||
"""Initialize the UI"""
|
"""Initialize the UI"""
|
||||||
# Setup table behaviour
|
# Setup table behaviour
|
||||||
self._setup_table()
|
self._setup_table()
|
||||||
self.table.setSelectionBehavior(QTableWidget.SelectRows)
|
self.ui.table.setSelectionBehavior(QTableWidget.SelectRows)
|
||||||
|
|
||||||
# for tag columns default tag
|
# for tag columns default tag
|
||||||
self.tag_counter = 1
|
self.tag_counter = 1
|
||||||
|
|
||||||
# Connect signals and slots
|
# Connect signals and slots
|
||||||
self.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
|
self.ui.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
|
||||||
self.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
|
self.ui.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
|
||||||
|
|
||||||
# Keyboard shortcuts for deleting a row
|
# Keyboard shortcuts for deleting a row
|
||||||
self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.table)
|
self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.ui.table)
|
||||||
self.delete_shortcut.activated.connect(self.delete_selected_row)
|
self.delete_shortcut.activated.connect(self.delete_selected_row)
|
||||||
self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.table)
|
self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.ui.table)
|
||||||
self.backspace_shortcut.activated.connect(self.delete_selected_row)
|
self.backspace_shortcut.activated.connect(self.delete_selected_row)
|
||||||
|
|
||||||
# Warning message for mode switch enable/disable
|
# Warning message for mode switch enable/disable
|
||||||
@ -83,13 +84,13 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
self.mode = self.config["motor_control"].get("mode", "Individual")
|
self.mode = self.config["motor_control"].get("mode", "Individual")
|
||||||
|
|
||||||
# Set combobox to default mode
|
# Set combobox to default mode
|
||||||
self.comboBox_mode.setCurrentText(self.mode)
|
self.ui.comboBox_mode.setCurrentText(self.mode)
|
||||||
|
|
||||||
self._init_ui()
|
self._init_ui()
|
||||||
|
|
||||||
def _setup_table(self):
|
def _setup_table(self):
|
||||||
"""Setup the table with appropriate headers and configurations."""
|
"""Setup the table with appropriate headers and configurations."""
|
||||||
mode = self.comboBox_mode.currentText()
|
mode = self.ui.comboBox_mode.currentText()
|
||||||
|
|
||||||
if mode == "Individual":
|
if mode == "Individual":
|
||||||
self._setup_individual_mode()
|
self._setup_individual_mode()
|
||||||
@ -101,14 +102,14 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
|
|
||||||
def _setup_individual_mode(self):
|
def _setup_individual_mode(self):
|
||||||
"""Setup the table for individual mode."""
|
"""Setup the table for individual mode."""
|
||||||
self.table.setColumnCount(5)
|
self.ui.table.setColumnCount(5)
|
||||||
self.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
|
self.ui.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
|
||||||
self.table.verticalHeader().setVisible(False)
|
self.ui.table.verticalHeader().setVisible(False)
|
||||||
|
|
||||||
def _setup_start_stop_mode(self):
|
def _setup_start_stop_mode(self):
|
||||||
"""Setup the table for start/stop mode."""
|
"""Setup the table for start/stop mode."""
|
||||||
self.table.setColumnCount(8)
|
self.ui.table.setColumnCount(8)
|
||||||
self.table.setHorizontalHeaderLabels(
|
self.ui.table.setHorizontalHeaderLabels(
|
||||||
[
|
[
|
||||||
"Show",
|
"Show",
|
||||||
"Move [start]",
|
"Move [start]",
|
||||||
@ -120,15 +121,15 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
"Y [end]",
|
"Y [end]",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
self.table.verticalHeader().setVisible(False)
|
self.ui.table.verticalHeader().setVisible(False)
|
||||||
# Set flag to track if the coordinate is stat or the end of the entry
|
# Set flag to track if the coordinate is stat or the end of the entry
|
||||||
self.is_next_entry_end = False
|
self.is_next_entry_end = False
|
||||||
|
|
||||||
def mode_switch(self):
|
def mode_switch(self):
|
||||||
"""Switch between individual and start/stop mode."""
|
"""Switch between individual and start/stop mode."""
|
||||||
last_selected_index = self.comboBox_mode.currentIndex()
|
last_selected_index = self.ui.comboBox_mode.currentIndex()
|
||||||
|
|
||||||
if self.table.rowCount() > 0 and self.warning_message is True:
|
if self.ui.table.rowCount() > 0 and self.warning_message is True:
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.setIcon(QMessageBox.Critical)
|
msgBox.setIcon(QMessageBox.Critical)
|
||||||
msgBox.setText(
|
msgBox.setText(
|
||||||
@ -138,9 +139,9 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
returnValue = msgBox.exec()
|
returnValue = msgBox.exec()
|
||||||
|
|
||||||
if returnValue is QMessageBox.Cancel:
|
if returnValue is QMessageBox.Cancel:
|
||||||
self.comboBox_mode.blockSignals(True) # Block signals
|
self.ui.comboBox_mode.blockSignals(True) # Block signals
|
||||||
self.comboBox_mode.setCurrentIndex(last_selected_index)
|
self.ui.comboBox_mode.setCurrentIndex(last_selected_index)
|
||||||
self.comboBox_mode.blockSignals(False) # Unblock signals
|
self.ui.comboBox_mode.blockSignals(False) # Unblock signals
|
||||||
return
|
return
|
||||||
|
|
||||||
# Wipe table
|
# Wipe table
|
||||||
@ -170,7 +171,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
y(float): Y coordinate.
|
y(float): Y coordinate.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
mode = self.comboBox_mode.currentText()
|
mode = self.ui.comboBox_mode.currentText()
|
||||||
if mode == "Individual":
|
if mode == "Individual":
|
||||||
checkbox_pos = 0
|
checkbox_pos = 0
|
||||||
button_pos = 1
|
button_pos = 1
|
||||||
@ -181,8 +182,8 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
color = "green"
|
color = "green"
|
||||||
|
|
||||||
# Add new row -> new entry
|
# Add new row -> new entry
|
||||||
row_count = self.table.rowCount()
|
row_count = self.ui.table.rowCount()
|
||||||
self.table.insertRow(row_count)
|
self.ui.table.insertRow(row_count)
|
||||||
|
|
||||||
# Add Widgets
|
# Add Widgets
|
||||||
self._add_widgets(
|
self._add_widgets(
|
||||||
@ -213,8 +214,8 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
color = "blue"
|
color = "blue"
|
||||||
|
|
||||||
# Add new row -> new entry
|
# Add new row -> new entry
|
||||||
row_count = self.table.rowCount()
|
row_count = self.ui.table.rowCount()
|
||||||
self.table.insertRow(row_count)
|
self.ui.table.insertRow(row_count)
|
||||||
|
|
||||||
# Add Widgets
|
# Add Widgets
|
||||||
self._add_widgets(
|
self._add_widgets(
|
||||||
@ -236,7 +237,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
|
|
||||||
elif self.is_next_entry_end is True: # It is the end position of the entry
|
elif self.is_next_entry_end is True: # It is the end position of the entry
|
||||||
print("End position")
|
print("End position")
|
||||||
row_count = self.table.rowCount() - 1 # Current row
|
row_count = self.ui.table.rowCount() - 1 # Current row
|
||||||
button_pos = 2
|
button_pos = 2
|
||||||
x_pos = 6
|
x_pos = 6
|
||||||
y_pos = 7
|
y_pos = 7
|
||||||
@ -294,7 +295,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
# Add widgets
|
# Add widgets
|
||||||
self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
|
self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
|
||||||
self._add_move_button(row, button_pos, x_pos, y_pos)
|
self._add_move_button(row, button_pos, x_pos, y_pos)
|
||||||
self.table.setItem(row, tag_pos, QTableWidgetItem(tag))
|
self.ui.table.setItem(row, tag_pos, QTableWidgetItem(tag))
|
||||||
self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
|
self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
|
||||||
self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
|
self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
|
||||||
|
|
||||||
@ -302,10 +303,10 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
||||||
|
|
||||||
# Connect item edit to emit coordinates
|
# Connect item edit to emit coordinates
|
||||||
self.table.itemChanged.connect(
|
self.ui.table.itemChanged.connect(
|
||||||
lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
|
lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
|
||||||
)
|
)
|
||||||
self.table.itemChanged.connect(
|
self.ui.table.itemChanged.connect(
|
||||||
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -321,7 +322,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
show_checkbox = QCheckBox()
|
show_checkbox = QCheckBox()
|
||||||
show_checkbox.setChecked(True)
|
show_checkbox.setChecked(True)
|
||||||
show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
|
show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
|
||||||
self.table.setCellWidget(row, checkBox_pos, show_checkbox)
|
self.ui.table.setCellWidget(row, checkBox_pos, show_checkbox)
|
||||||
|
|
||||||
def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
|
def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
|
||||||
"""
|
"""
|
||||||
@ -334,7 +335,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
"""
|
"""
|
||||||
move_button = QPushButton("Move")
|
move_button = QPushButton("Move")
|
||||||
move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
|
move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
|
||||||
self.table.setCellWidget(row, button_pos, move_button)
|
self.ui.table.setCellWidget(row, button_pos, move_button)
|
||||||
|
|
||||||
def _add_line_edit(
|
def _add_line_edit(
|
||||||
self,
|
self,
|
||||||
@ -367,7 +368,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
# Add line edit to the table
|
# Add line edit to the table
|
||||||
self.table.setCellWidget(row, line_pos, edit)
|
self.ui.table.setCellWidget(row, line_pos, edit)
|
||||||
edit.textChanged.connect(
|
edit.textChanged.connect(
|
||||||
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
||||||
)
|
)
|
||||||
@ -375,10 +376,10 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
def wipe_motor_map_coordinates(self):
|
def wipe_motor_map_coordinates(self):
|
||||||
"""Wipe the motor map coordinates."""
|
"""Wipe the motor map coordinates."""
|
||||||
try:
|
try:
|
||||||
self.table.itemChanged.disconnect() # Disconnect all previous connections
|
self.ui.table.itemChanged.disconnect() # Disconnect all previous connections
|
||||||
except TypeError:
|
except TypeError:
|
||||||
print("No previous connections to disconnect")
|
print("No previous connections to disconnect")
|
||||||
self.table.setRowCount(0)
|
self.ui.table.setRowCount(0)
|
||||||
reference_tags = ["Individual", "Start", "Stop"]
|
reference_tags = ["Individual", "Start", "Stop"]
|
||||||
for reference_tag in reference_tags:
|
for reference_tag in reference_tags:
|
||||||
self.plot_coordinates_signal.emit([], reference_tag, "green")
|
self.plot_coordinates_signal.emit([], reference_tag, "green")
|
||||||
@ -391,7 +392,7 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
y_pos(int): Y position of the coordinate.
|
y_pos(int): Y position of the coordinate.
|
||||||
"""
|
"""
|
||||||
button = self.sender()
|
button = self.sender()
|
||||||
row = self.table.indexAt(button.pos()).row()
|
row = self.ui.table.indexAt(button.pos()).row()
|
||||||
|
|
||||||
x = self.get_coordinate(row, x_pos)
|
x = self.get_coordinate(row, x_pos)
|
||||||
y = self.get_coordinate(row, y_pos)
|
y = self.get_coordinate(row, y_pos)
|
||||||
@ -410,8 +411,8 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
|
f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
|
||||||
)
|
)
|
||||||
coordinates = []
|
coordinates = []
|
||||||
for row in range(self.table.rowCount()):
|
for row in range(self.ui.table.rowCount()):
|
||||||
show = self.table.cellWidget(row, 0).isChecked()
|
show = self.ui.table.cellWidget(row, 0).isChecked()
|
||||||
x = self.get_coordinate(row, x_pos)
|
x = self.get_coordinate(row, x_pos)
|
||||||
y = self.get_coordinate(row, y_pos)
|
y = self.get_coordinate(row, y_pos)
|
||||||
|
|
||||||
@ -427,27 +428,27 @@ class MotorCoordinateTable(MotorControlWidget):
|
|||||||
Returns:
|
Returns:
|
||||||
float: Value of the coordinate.
|
float: Value of the coordinate.
|
||||||
"""
|
"""
|
||||||
edit = self.table.cellWidget(row, column)
|
edit = self.ui.table.cellWidget(row, column)
|
||||||
value = float(edit.text()) if edit and edit.text() != "" else None
|
value = float(edit.text()) if edit and edit.text() != "" else None
|
||||||
if value:
|
if value:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def delete_selected_row(self):
|
def delete_selected_row(self):
|
||||||
"""Delete the selected row from the table."""
|
"""Delete the selected row from the table."""
|
||||||
selected_rows = self.table.selectionModel().selectedRows()
|
selected_rows = self.ui.table.selectionModel().selectedRows()
|
||||||
for row in selected_rows:
|
for row in selected_rows:
|
||||||
self.table.removeRow(row.row())
|
self.ui.table.removeRow(row.row())
|
||||||
if self.comboBox_mode.currentText() == "Start/Stop":
|
if self.ui.comboBox_mode.currentText() == "Start/Stop":
|
||||||
self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
|
self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
|
||||||
self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
|
self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
|
||||||
self.is_next_entry_end = False
|
self.is_next_entry_end = False
|
||||||
elif self.comboBox_mode.currentText() == "Individual":
|
elif self.ui.comboBox_mode.currentText() == "Individual":
|
||||||
self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
|
self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
|
||||||
|
|
||||||
def resize_table_auto(self):
|
def resize_table_auto(self):
|
||||||
"""Resize the table to fit the contents."""
|
"""Resize the table to fit the contents."""
|
||||||
if self.checkBox_resize_auto.isChecked():
|
if self.ui.checkBox_resize_auto.isChecked():
|
||||||
self.table.resizeColumnsToContents()
|
self.ui.table.resizeColumnsToContents()
|
||||||
|
|
||||||
def move_motor(self, x: float, y: float) -> None:
|
def move_motor(self, x: float, y: float) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -3,8 +3,10 @@ import os
|
|||||||
from qtpy import uic
|
from qtpy import uic
|
||||||
from qtpy.QtCore import Signal as pyqtSignal
|
from qtpy.QtCore import Signal as pyqtSignal
|
||||||
from qtpy.QtCore import Slot as pyqtSlot
|
from qtpy.QtCore import Slot as pyqtSlot
|
||||||
|
from qtpy.QtWidgets import QWidget
|
||||||
|
|
||||||
from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
|
from bec_widgets.utils import UILoader
|
||||||
|
from bec_widgets.widgets.motor_control.motor_control import MotorControlErrors, MotorControlWidget
|
||||||
|
|
||||||
|
|
||||||
class MotorControlAbsolute(MotorControlWidget):
|
class MotorControlAbsolute(MotorControlWidget):
|
||||||
@ -23,26 +25,26 @@ class MotorControlAbsolute(MotorControlWidget):
|
|||||||
def _load_ui(self):
|
def _load_ui(self):
|
||||||
"""Load the UI from the .ui file."""
|
"""Load the UI from the .ui file."""
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
uic.loadUi(os.path.join(current_path, "movement_absolute.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "movement_absolute.ui"), self)
|
||||||
|
|
||||||
def _init_ui(self):
|
def _init_ui(self):
|
||||||
"""Initialize the UI."""
|
"""Initialize the UI."""
|
||||||
|
|
||||||
# Check if there are any motors connected
|
# Check if there are any motors connected
|
||||||
if self.motor_x is None or self.motor_y is None:
|
if self.motor_x is None or self.motor_y is None:
|
||||||
self.motorControl_absolute.setEnabled(False)
|
self.ui.motorControl_absolute.setEnabled(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Move to absolute coordinates
|
# Move to absolute coordinates
|
||||||
self.pushButton_go_absolute.clicked.connect(
|
self.ui.pushButton_go_absolute.clicked.connect(
|
||||||
lambda: self.move_motor_absolute(
|
lambda: self.move_motor_absolute(
|
||||||
self.spinBox_absolute_x.value(), self.spinBox_absolute_y.value()
|
self.ui.spinBox_absolute_x.value(), self.ui.spinBox_absolute_y.value()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.pushButton_set.clicked.connect(self.save_absolute_coordinates)
|
self.ui.pushButton_set.clicked.connect(self.save_absolute_coordinates)
|
||||||
self.pushButton_save.clicked.connect(self.save_current_coordinates)
|
self.ui.pushButton_save.clicked.connect(self.save_current_coordinates)
|
||||||
self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
||||||
|
|
||||||
# Enable/Disable GUI
|
# Enable/Disable GUI
|
||||||
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
||||||
@ -80,11 +82,11 @@ class MotorControlAbsolute(MotorControlWidget):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Disable or enable all controls within the motorControl_absolute group box
|
# Disable or enable all controls within the motorControl_absolute group box
|
||||||
for widget in self.motorControl_absolute.findChildren(QWidget):
|
for widget in self.ui.motorControl_absolute.findChildren(QWidget):
|
||||||
widget.setEnabled(enable)
|
widget.setEnabled(enable)
|
||||||
|
|
||||||
# Enable the pushButton_stop if the motor is moving
|
# Enable the pushButton_stop if the motor is moving
|
||||||
self.pushButton_stop.setEnabled(True)
|
self.ui.pushButton_stop.setEnabled(True)
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def change_motors(self, motor_x: str, motor_y: str):
|
def change_motors(self, motor_x: str, motor_y: str):
|
||||||
@ -109,8 +111,8 @@ class MotorControlAbsolute(MotorControlWidget):
|
|||||||
"""
|
"""
|
||||||
self.precision = precision
|
self.precision = precision
|
||||||
self.config["motor_control"]["precision"] = precision
|
self.config["motor_control"]["precision"] = precision
|
||||||
self.spinBox_absolute_x.setDecimals(precision)
|
self.ui.spinBox_absolute_x.setDecimals(precision)
|
||||||
self.spinBox_absolute_y.setDecimals(precision)
|
self.ui.spinBox_absolute_y.setDecimals(precision)
|
||||||
|
|
||||||
def move_motor_absolute(self, x: float, y: float) -> None:
|
def move_motor_absolute(self, x: float, y: float) -> None:
|
||||||
"""
|
"""
|
||||||
@ -122,32 +124,32 @@ class MotorControlAbsolute(MotorControlWidget):
|
|||||||
# self._enable_motor_controls(False)
|
# self._enable_motor_controls(False)
|
||||||
target_coordinates = (x, y)
|
target_coordinates = (x, y)
|
||||||
self.motor_thread.move_absolute(self.motor_x, self.motor_y, target_coordinates)
|
self.motor_thread.move_absolute(self.motor_x, self.motor_y, target_coordinates)
|
||||||
if self.checkBox_save_with_go.isChecked():
|
if self.ui.checkBox_save_with_go.isChecked():
|
||||||
self.save_absolute_coordinates()
|
self.save_absolute_coordinates()
|
||||||
|
|
||||||
def _init_keyboard_shortcuts(self):
|
def _init_keyboard_shortcuts(self):
|
||||||
"""Initialize the keyboard shortcuts."""
|
"""Initialize the keyboard shortcuts."""
|
||||||
# Go absolute button
|
# Go absolute button
|
||||||
self.pushButton_go_absolute.setShortcut("Ctrl+G")
|
self.ui.pushButton_go_absolute.setShortcut("Ctrl+G")
|
||||||
self.pushButton_go_absolute.setToolTip("Ctrl+G")
|
self.ui.pushButton_go_absolute.setToolTip("Ctrl+G")
|
||||||
|
|
||||||
# Set absolute coordinates
|
# Set absolute coordinates
|
||||||
self.pushButton_set.setShortcut("Ctrl+D")
|
self.ui.pushButton_set.setShortcut("Ctrl+D")
|
||||||
self.pushButton_set.setToolTip("Ctrl+D")
|
self.ui.pushButton_set.setToolTip("Ctrl+D")
|
||||||
|
|
||||||
# Save Current coordinates
|
# Save Current coordinates
|
||||||
self.pushButton_save.setShortcut("Ctrl+S")
|
self.ui.pushButton_save.setShortcut("Ctrl+S")
|
||||||
self.pushButton_save.setToolTip("Ctrl+S")
|
self.ui.pushButton_save.setToolTip("Ctrl+S")
|
||||||
|
|
||||||
# Stop Button
|
# Stop Button
|
||||||
self.pushButton_stop.setShortcut("Ctrl+X")
|
self.ui.pushButton_stop.setShortcut("Ctrl+X")
|
||||||
self.pushButton_stop.setToolTip("Ctrl+X")
|
self.ui.pushButton_stop.setToolTip("Ctrl+X")
|
||||||
|
|
||||||
def save_absolute_coordinates(self):
|
def save_absolute_coordinates(self):
|
||||||
"""Emit the setup coordinates from the spinboxes"""
|
"""Emit the setup coordinates from the spinboxes"""
|
||||||
|
|
||||||
x, y = round(self.spinBox_absolute_x.value(), self.precision), round(
|
x, y = round(self.ui.spinBox_absolute_x.value(), self.precision), round(
|
||||||
self.spinBox_absolute_y.value(), self.precision
|
self.ui.spinBox_absolute_y.value(), self.precision
|
||||||
)
|
)
|
||||||
self.coordinates_signal.emit((x, y))
|
self.coordinates_signal.emit((x, y))
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from qtpy.QtCore import Slot as pyqtSlot
|
|||||||
from qtpy.QtGui import QKeySequence
|
from qtpy.QtGui import QKeySequence
|
||||||
from qtpy.QtWidgets import QDoubleSpinBox, QShortcut, QWidget
|
from qtpy.QtWidgets import QDoubleSpinBox, QShortcut, QWidget
|
||||||
|
|
||||||
|
from bec_widgets.utils import UILoader
|
||||||
from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
|
from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
"""Load the UI from the .ui file."""
|
"""Load the UI from the .ui file."""
|
||||||
# Loading UI
|
# Loading UI
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
uic.loadUi(os.path.join(current_path, "movement_relative.ui"), self)
|
self.ui = UILoader().load_ui(os.path.join(current_path, "movement_relative.ui"), self)
|
||||||
|
|
||||||
def _init_ui(self):
|
def _init_ui(self):
|
||||||
"""Initialize the UI."""
|
"""Initialize the UI."""
|
||||||
@ -51,15 +52,15 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
|
|
||||||
# Update step precision
|
# Update step precision
|
||||||
self.precision = self.config["motor_control"]["precision"]
|
self.precision = self.config["motor_control"]["precision"]
|
||||||
self.spinBox_precision.setValue(self.precision)
|
self.ui.spinBox_precision.setValue(self.precision)
|
||||||
|
|
||||||
# Update step sizes
|
# Update step sizes
|
||||||
self.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
|
self.ui.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
|
||||||
self.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
|
self.ui.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
|
||||||
|
|
||||||
# Checkboxes for keyboard shortcuts and x/y step size link
|
# Checkboxes for keyboard shortcuts and x/y step size link
|
||||||
self.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
|
self.ui.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
|
||||||
self.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
|
self.ui.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
|
||||||
|
|
||||||
self._init_ui()
|
self._init_ui()
|
||||||
|
|
||||||
@ -67,30 +68,32 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
"""Initialize the motor control elements"""
|
"""Initialize the motor control elements"""
|
||||||
|
|
||||||
# Connect checkbox and spinBoxes
|
# Connect checkbox and spinBoxes
|
||||||
self.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
|
self.ui.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
|
||||||
self.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
|
self.ui.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
|
||||||
self.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
|
self.ui.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
|
||||||
|
|
||||||
self.toolButton_right.clicked.connect(
|
self.ui.toolButton_right.clicked.connect(
|
||||||
lambda: self.move_motor_relative(self.motor_x, "x", 1)
|
lambda: self.move_motor_relative(self.motor_x, "x", 1)
|
||||||
)
|
)
|
||||||
self.toolButton_left.clicked.connect(
|
self.ui.toolButton_left.clicked.connect(
|
||||||
lambda: self.move_motor_relative(self.motor_x, "x", -1)
|
lambda: self.move_motor_relative(self.motor_x, "x", -1)
|
||||||
)
|
)
|
||||||
self.toolButton_up.clicked.connect(lambda: self.move_motor_relative(self.motor_y, "y", 1))
|
self.ui.toolButton_up.clicked.connect(
|
||||||
self.toolButton_down.clicked.connect(
|
lambda: self.move_motor_relative(self.motor_y, "y", 1)
|
||||||
|
)
|
||||||
|
self.ui.toolButton_down.clicked.connect(
|
||||||
lambda: self.move_motor_relative(self.motor_y, "y", -1)
|
lambda: self.move_motor_relative(self.motor_y, "y", -1)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Switch between key shortcuts active
|
# Switch between key shortcuts active
|
||||||
self.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
|
self.ui.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
|
||||||
self._update_arrow_key_shortcuts()
|
self._update_arrow_key_shortcuts()
|
||||||
|
|
||||||
# Enable/Disable GUI
|
# Enable/Disable GUI
|
||||||
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
||||||
|
|
||||||
# Precision update
|
# Precision update
|
||||||
self.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
|
self.ui.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
|
||||||
|
|
||||||
# Error messages
|
# Error messages
|
||||||
self.motor_thread.motor_error.connect(
|
self.motor_thread.motor_error.connect(
|
||||||
@ -98,7 +101,7 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Stop Button
|
# Stop Button
|
||||||
self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
||||||
|
|
||||||
def _init_keyboard_shortcuts(self) -> None:
|
def _init_keyboard_shortcuts(self) -> None:
|
||||||
"""Initialize the keyboard shortcuts"""
|
"""Initialize the keyboard shortcuts"""
|
||||||
@ -107,42 +110,42 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
increase_x_shortcut = QShortcut(QKeySequence("Ctrl+A"), self)
|
increase_x_shortcut = QShortcut(QKeySequence("Ctrl+A"), self)
|
||||||
decrease_x_shortcut = QShortcut(QKeySequence("Ctrl+Z"), self)
|
decrease_x_shortcut = QShortcut(QKeySequence("Ctrl+Z"), self)
|
||||||
increase_x_shortcut.activated.connect(
|
increase_x_shortcut.activated.connect(
|
||||||
lambda: self._change_step_size(self.spinBox_step_x, 2)
|
lambda: self._change_step_size(self.ui.spinBox_step_x, 2)
|
||||||
)
|
)
|
||||||
decrease_x_shortcut.activated.connect(
|
decrease_x_shortcut.activated.connect(
|
||||||
lambda: self._change_step_size(self.spinBox_step_x, 0.5)
|
lambda: self._change_step_size(self.ui.spinBox_step_x, 0.5)
|
||||||
)
|
)
|
||||||
self.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
|
self.ui.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
|
||||||
|
|
||||||
# Increase/decrease step size for Y motor
|
# Increase/decrease step size for Y motor
|
||||||
increase_y_shortcut = QShortcut(QKeySequence("Alt+A"), self)
|
increase_y_shortcut = QShortcut(QKeySequence("Alt+A"), self)
|
||||||
decrease_y_shortcut = QShortcut(QKeySequence("Alt+Z"), self)
|
decrease_y_shortcut = QShortcut(QKeySequence("Alt+Z"), self)
|
||||||
increase_y_shortcut.activated.connect(
|
increase_y_shortcut.activated.connect(
|
||||||
lambda: self._change_step_size(self.spinBox_step_y, 2)
|
lambda: self._change_step_size(self.ui.spinBox_step_y, 2)
|
||||||
)
|
)
|
||||||
decrease_y_shortcut.activated.connect(
|
decrease_y_shortcut.activated.connect(
|
||||||
lambda: self._change_step_size(self.spinBox_step_y, 0.5)
|
lambda: self._change_step_size(self.ui.spinBox_step_y, 0.5)
|
||||||
)
|
)
|
||||||
self.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
|
self.ui.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
|
||||||
|
|
||||||
# Stop Button
|
# Stop Button
|
||||||
self.pushButton_stop.setShortcut("Ctrl+X")
|
self.ui.pushButton_stop.setShortcut("Ctrl+X")
|
||||||
self.pushButton_stop.setToolTip("Ctrl+X")
|
self.ui.pushButton_stop.setToolTip("Ctrl+X")
|
||||||
|
|
||||||
def _update_arrow_key_shortcuts(self) -> None:
|
def _update_arrow_key_shortcuts(self) -> None:
|
||||||
"""Update the arrow key shortcuts based on the checkbox state."""
|
"""Update the arrow key shortcuts based on the checkbox state."""
|
||||||
if self.checkBox_enableArrows.isChecked():
|
if self.ui.checkBox_enableArrows.isChecked():
|
||||||
# Set the arrow key shortcuts for motor movement
|
# Set the arrow key shortcuts for motor movement
|
||||||
self.toolButton_right.setShortcut(Qt.Key_Right)
|
self.ui.toolButton_right.setShortcut(Qt.Key_Right)
|
||||||
self.toolButton_left.setShortcut(Qt.Key_Left)
|
self.ui.toolButton_left.setShortcut(Qt.Key_Left)
|
||||||
self.toolButton_up.setShortcut(Qt.Key_Up)
|
self.ui.toolButton_up.setShortcut(Qt.Key_Up)
|
||||||
self.toolButton_down.setShortcut(Qt.Key_Down)
|
self.ui.toolButton_down.setShortcut(Qt.Key_Down)
|
||||||
else:
|
else:
|
||||||
# Clear the shortcuts
|
# Clear the shortcuts
|
||||||
self.toolButton_right.setShortcut("")
|
self.ui.toolButton_right.setShortcut("")
|
||||||
self.toolButton_left.setShortcut("")
|
self.ui.toolButton_left.setShortcut("")
|
||||||
self.toolButton_up.setShortcut("")
|
self.ui.toolButton_up.setShortcut("")
|
||||||
self.toolButton_down.setShortcut("")
|
self.ui.toolButton_down.setShortcut("")
|
||||||
|
|
||||||
def _update_precision(self, precision: int) -> None:
|
def _update_precision(self, precision: int) -> None:
|
||||||
"""
|
"""
|
||||||
@ -150,8 +153,8 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
Args:
|
Args:
|
||||||
precision(int): Precision of the coordinates.
|
precision(int): Precision of the coordinates.
|
||||||
"""
|
"""
|
||||||
self.spinBox_step_x.setDecimals(precision)
|
self.ui.spinBox_step_x.setDecimals(precision)
|
||||||
self.spinBox_step_y.setDecimals(precision)
|
self.ui.spinBox_step_y.setDecimals(precision)
|
||||||
self.precision_signal.emit(precision)
|
self.precision_signal.emit(precision)
|
||||||
|
|
||||||
def _change_step_size(self, spinBox: QDoubleSpinBox, factor: float) -> None:
|
def _change_step_size(self, spinBox: QDoubleSpinBox, factor: float) -> None:
|
||||||
@ -167,21 +170,21 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
|
|
||||||
def _sync_step_sizes(self):
|
def _sync_step_sizes(self):
|
||||||
"""Sync step sizes based on checkbox state."""
|
"""Sync step sizes based on checkbox state."""
|
||||||
if self.checkBox_same_xy.isChecked():
|
if self.ui.checkBox_same_xy.isChecked():
|
||||||
value = self.spinBox_step_x.value()
|
value = self.ui.spinBox_step_x.value()
|
||||||
self.spinBox_step_y.setValue(value)
|
self.ui.spinBox_step_y.setValue(value)
|
||||||
|
|
||||||
def _update_step_size_x(self):
|
def _update_step_size_x(self):
|
||||||
"""Update step size for x if checkbox is checked."""
|
"""Update step size for x if checkbox is checked."""
|
||||||
if self.checkBox_same_xy.isChecked():
|
if self.ui.checkBox_same_xy.isChecked():
|
||||||
value = self.spinBox_step_x.value()
|
value = self.ui.spinBox_step_x.value()
|
||||||
self.spinBox_step_y.setValue(value)
|
self.ui.spinBox_step_y.setValue(value)
|
||||||
|
|
||||||
def _update_step_size_y(self):
|
def _update_step_size_y(self):
|
||||||
"""Update step size for y if checkbox is checked."""
|
"""Update step size for y if checkbox is checked."""
|
||||||
if self.checkBox_same_xy.isChecked():
|
if self.ui.checkBox_same_xy.isChecked():
|
||||||
value = self.spinBox_step_y.value()
|
value = self.ui.spinBox_step_y.value()
|
||||||
self.spinBox_step_x.setValue(value)
|
self.ui.spinBox_step_x.setValue(value)
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def change_motors(self, motor_x: str, motor_y: str):
|
def change_motors(self, motor_x: str, motor_y: str):
|
||||||
@ -206,11 +209,11 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Disable or enable all controls within the motorControl_absolute group box
|
# Disable or enable all controls within the motorControl_absolute group box
|
||||||
for widget in self.motorControl.findChildren(QWidget):
|
for widget in self.ui.motorControl.findChildren(QWidget):
|
||||||
widget.setEnabled(disable)
|
widget.setEnabled(disable)
|
||||||
|
|
||||||
# Enable the pushButton_stop if the motor is moving
|
# Enable the pushButton_stop if the motor is moving
|
||||||
self.pushButton_stop.setEnabled(True)
|
self.ui.pushButton_stop.setEnabled(True)
|
||||||
|
|
||||||
def move_motor_relative(self, motor, axis: str, direction: int) -> None:
|
def move_motor_relative(self, motor, axis: str, direction: int) -> None:
|
||||||
"""
|
"""
|
||||||
@ -221,7 +224,7 @@ class MotorControlRelative(MotorControlWidget):
|
|||||||
direction(int): Direction to move. 1 for positive, -1 for negative.
|
direction(int): Direction to move. 1 for positive, -1 for negative.
|
||||||
"""
|
"""
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
step = direction * self.spinBox_step_x.value()
|
step = direction * self.ui.spinBox_step_x.value()
|
||||||
elif axis == "y":
|
elif axis == "y":
|
||||||
step = direction * self.spinBox_step_y.value()
|
step = direction * self.ui.spinBox_step_y.value()
|
||||||
self.motor_thread.move_relative(motor, step)
|
self.motor_thread.move_relative(motor, step)
|
||||||
|
@ -150,7 +150,7 @@ def test_spiral_bar(rpc_server_dock):
|
|||||||
dock = BECDockArea(rpc_server_dock.gui_id)
|
dock = BECDockArea(rpc_server_dock.gui_id)
|
||||||
dock_server = rpc_server_dock.gui
|
dock_server = rpc_server_dock.gui
|
||||||
|
|
||||||
d0 = dock.add_dock("dock_0")
|
d0 = dock.add_dock(name="dock_0")
|
||||||
|
|
||||||
bar = d0.add_widget_bec("SpiralProgressBar")
|
bar = d0.add_widget_bec("SpiralProgressBar")
|
||||||
assert bar.__class__.__name__ == "SpiralProgressBar"
|
assert bar.__class__.__name__ == "SpiralProgressBar"
|
||||||
|
@ -17,8 +17,8 @@ def cli_figure():
|
|||||||
|
|
||||||
def test_rpc_call_plot(cli_figure):
|
def test_rpc_call_plot(cli_figure):
|
||||||
fig, mock_rpc_call = cli_figure
|
fig, mock_rpc_call = cli_figure
|
||||||
fig.plot("samx", "bpm4i")
|
fig.plot(x_name="samx", y_name="bpm4i")
|
||||||
mock_rpc_call.assert_called_with("plot", "samx", "bpm4i")
|
mock_rpc_call.assert_called_with("plot", x_name="samx", y_name="bpm4i")
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_call_accepts_device_as_input(cli_figure):
|
def test_rpc_call_accepts_device_as_input(cli_figure):
|
||||||
|
@ -44,8 +44,8 @@ def test_mouse_moved_signals(qtbot):
|
|||||||
# Create a slot that will store the emitted values as tuples
|
# Create a slot that will store the emitted values as tuples
|
||||||
emitted_values_1D = []
|
emitted_values_1D = []
|
||||||
|
|
||||||
def slot(x, y_values):
|
def slot(coordinates):
|
||||||
emitted_values_1D.append((x, y_values))
|
emitted_values_1D.append(coordinates)
|
||||||
|
|
||||||
# Connect the signal to the custom slot
|
# Connect the signal to the custom slot
|
||||||
crosshair.coordinatesChanged1D.connect(slot)
|
crosshair.coordinatesChanged1D.connect(slot)
|
||||||
@ -59,7 +59,7 @@ def test_mouse_moved_signals(qtbot):
|
|||||||
crosshair.mouse_moved(event_mock)
|
crosshair.mouse_moved(event_mock)
|
||||||
|
|
||||||
# Assert the expected behavior
|
# Assert the expected behavior
|
||||||
assert emitted_values_1D == [(2.0, [5.0])]
|
assert emitted_values_1D == [(2, [5])]
|
||||||
|
|
||||||
|
|
||||||
def test_mouse_moved_signals_outside(qtbot):
|
def test_mouse_moved_signals_outside(qtbot):
|
||||||
@ -106,8 +106,8 @@ def test_mouse_moved_signals_2D(qtbot):
|
|||||||
# Create a slot that will store the emitted values as tuples
|
# Create a slot that will store the emitted values as tuples
|
||||||
emitted_values_2D = []
|
emitted_values_2D = []
|
||||||
|
|
||||||
def slot(x, y):
|
def slot(coordinates):
|
||||||
emitted_values_2D.append((x, y))
|
emitted_values_2D.append(coordinates)
|
||||||
|
|
||||||
# Connect the signal to the custom slot
|
# Connect the signal to the custom slot
|
||||||
crosshair.coordinatesChanged2D.connect(slot)
|
crosshair.coordinatesChanged2D.connect(slot)
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
|
||||||
import json
|
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pyqtgraph as pg
|
|
||||||
import pytest
|
|
||||||
import zmq
|
|
||||||
|
|
||||||
from bec_widgets.examples.eiger_plot.eiger_plot import EigerPlot
|
|
||||||
|
|
||||||
|
|
||||||
# Common fixture for all tests
|
|
||||||
@pytest.fixture
|
|
||||||
def eiger_plot_instance(qtbot):
|
|
||||||
widget = EigerPlot()
|
|
||||||
qtbot.addWidget(widget)
|
|
||||||
qtbot.waitExposed(widget)
|
|
||||||
yield widget
|
|
||||||
widget.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"fft_checked, rotation_index, transpose_checked, log_checked, expected_image",
|
|
||||||
[
|
|
||||||
(False, 0, False, False, np.array([[2, 1], [1, 5]], dtype=float)), # just mask
|
|
||||||
(False, 1, False, False, np.array([[1, 5], [2, 1]], dtype=float)), # 90 deg rotation
|
|
||||||
(False, 2, False, False, np.array([[5, 1], [1, 2]], dtype=float)), # 180 deg rotation
|
|
||||||
(False, 0, True, False, np.array([[2, 1], [1, 5]], dtype=float)), # transposed
|
|
||||||
(False, 0, False, True, np.array([[0.30103, 0.0], [0.0, 0.69897]], dtype=float)), # log
|
|
||||||
(True, 0, False, False, np.array([[5.0, 3.0], [3.0, 9.0]], dtype=float)), # FFT
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_on_image_update(
|
|
||||||
qtbot,
|
|
||||||
eiger_plot_instance,
|
|
||||||
fft_checked,
|
|
||||||
rotation_index,
|
|
||||||
transpose_checked,
|
|
||||||
log_checked,
|
|
||||||
expected_image,
|
|
||||||
):
|
|
||||||
# Initialize image and mask
|
|
||||||
eiger_plot_instance.image = np.array([[1, 2], [3, 4]], dtype=float)
|
|
||||||
eiger_plot_instance.mask = np.array([[0, 1], [1, 0]], dtype=float)
|
|
||||||
|
|
||||||
# Mock UI elements
|
|
||||||
eiger_plot_instance.checkBox_FFT = MagicMock()
|
|
||||||
eiger_plot_instance.checkBox_FFT.isChecked.return_value = fft_checked
|
|
||||||
eiger_plot_instance.comboBox_rotation = MagicMock()
|
|
||||||
eiger_plot_instance.comboBox_rotation.currentIndex.return_value = rotation_index
|
|
||||||
eiger_plot_instance.checkBox_transpose = MagicMock()
|
|
||||||
eiger_plot_instance.checkBox_transpose.isChecked.return_value = transpose_checked
|
|
||||||
eiger_plot_instance.checkBox_log = MagicMock()
|
|
||||||
eiger_plot_instance.checkBox_log.isChecked.return_value = log_checked
|
|
||||||
eiger_plot_instance.imageItem = MagicMock()
|
|
||||||
|
|
||||||
# Call the method
|
|
||||||
eiger_plot_instance.on_image_update()
|
|
||||||
|
|
||||||
# Validate the transformations
|
|
||||||
np.testing.assert_array_almost_equal(eiger_plot_instance.image, expected_image, decimal=5)
|
|
||||||
|
|
||||||
# Validate that setImage was called
|
|
||||||
eiger_plot_instance.imageItem.setImage.assert_called_with(
|
|
||||||
eiger_plot_instance.image, autoLevels=False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_ui(eiger_plot_instance):
|
|
||||||
assert isinstance(eiger_plot_instance.plot_item, pg.PlotItem)
|
|
||||||
assert isinstance(eiger_plot_instance.imageItem, pg.ImageItem)
|
|
||||||
assert isinstance(eiger_plot_instance.hist, pg.HistogramLUTItem)
|
|
||||||
|
|
||||||
|
|
||||||
def test_start_zmq_consumer(eiger_plot_instance):
|
|
||||||
with patch("threading.Thread") as MockThread:
|
|
||||||
eiger_plot_instance.start_zmq_consumer()
|
|
||||||
MockThread.assert_called_once()
|
|
||||||
MockThread.return_value.start.assert_called_once()
|
|
||||||
|
|
||||||
|
|
||||||
def test_zmq_consumer(eiger_plot_instance, qtbot):
|
|
||||||
fake_meta = json.dumps({"type": "int32", "shape": (2, 2)}).encode("utf-8")
|
|
||||||
fake_data = np.array([[1, 2], [3, 4]], dtype="int32").tobytes()
|
|
||||||
|
|
||||||
with patch("zmq.Context", autospec=True) as MockContext:
|
|
||||||
mock_socket = MagicMock()
|
|
||||||
mock_socket.recv_multipart.side_effect = ((fake_meta, fake_data),)
|
|
||||||
MockContext.return_value.socket.return_value = mock_socket
|
|
||||||
|
|
||||||
# Mocking the update_signal to check if it gets emitted
|
|
||||||
eiger_plot_instance.update_signal = MagicMock()
|
|
||||||
|
|
||||||
with patch("zmq.Poller"):
|
|
||||||
# will do only 1 iteration of the loop in the thread
|
|
||||||
eiger_plot_instance._zmq_consumer_exit_event.set()
|
|
||||||
# Run the method under test
|
|
||||||
consumer_thread = eiger_plot_instance.start_zmq_consumer()
|
|
||||||
consumer_thread.join()
|
|
||||||
|
|
||||||
# Check if zmq methods are called
|
|
||||||
# MockContext.assert_called_once()
|
|
||||||
assert MockContext.call_count == 1
|
|
||||||
mock_socket.connect.assert_called_with("tcp://129.129.95.38:20000")
|
|
||||||
mock_socket.setsockopt_string.assert_called_with(zmq.SUBSCRIBE, "")
|
|
||||||
mock_socket.recv_multipart.assert_called()
|
|
||||||
|
|
||||||
# Check if update_signal was emitted
|
|
||||||
eiger_plot_instance.update_signal.emit.assert_called_once()
|
|
||||||
|
|
||||||
# Validate the image data
|
|
||||||
np.testing.assert_array_equal(
|
|
||||||
eiger_plot_instance.image, np.array([[1, 2], [3, 4]], dtype="int32")
|
|
||||||
)
|
|
@ -239,14 +239,14 @@ def test_absolute_save_current_coordinates(motor_absolute_widget):
|
|||||||
motor_absolute_widget.coordinates_signal.connect(capture_emit)
|
motor_absolute_widget.coordinates_signal.connect(capture_emit)
|
||||||
|
|
||||||
# Trigger saving current coordinates
|
# Trigger saving current coordinates
|
||||||
motor_absolute_widget.pushButton_save.click()
|
motor_absolute_widget.ui.pushButton_save.click()
|
||||||
|
|
||||||
assert emitted_coordinates == [(motor_x_value, motor_y_value)]
|
assert emitted_coordinates == [(motor_x_value, motor_y_value)]
|
||||||
|
|
||||||
|
|
||||||
def test_absolute_set_absolute_coordinates(motor_absolute_widget):
|
def test_absolute_set_absolute_coordinates(motor_absolute_widget):
|
||||||
motor_absolute_widget.spinBox_absolute_x.setValue(5)
|
motor_absolute_widget.ui.spinBox_absolute_x.setValue(5)
|
||||||
motor_absolute_widget.spinBox_absolute_y.setValue(10)
|
motor_absolute_widget.ui.spinBox_absolute_y.setValue(10)
|
||||||
|
|
||||||
# Connect to the coordinates_signal to capture emitted values
|
# Connect to the coordinates_signal to capture emitted values
|
||||||
emitted_values = []
|
emitted_values = []
|
||||||
@ -257,7 +257,7 @@ def test_absolute_set_absolute_coordinates(motor_absolute_widget):
|
|||||||
motor_absolute_widget.coordinates_signal.connect(capture_coordinates)
|
motor_absolute_widget.coordinates_signal.connect(capture_coordinates)
|
||||||
|
|
||||||
# Simulate button click for absolute movement
|
# Simulate button click for absolute movement
|
||||||
motor_absolute_widget.pushButton_set.click()
|
motor_absolute_widget.ui.pushButton_set.click()
|
||||||
|
|
||||||
assert emitted_values == [(5, 10)]
|
assert emitted_values == [(5, 10)]
|
||||||
|
|
||||||
@ -265,14 +265,14 @@ def test_absolute_set_absolute_coordinates(motor_absolute_widget):
|
|||||||
def test_absolute_go_absolute_coordinates(motor_absolute_widget):
|
def test_absolute_go_absolute_coordinates(motor_absolute_widget):
|
||||||
motor_absolute_widget.change_motors("samx", "samy")
|
motor_absolute_widget.change_motors("samx", "samy")
|
||||||
|
|
||||||
motor_absolute_widget.spinBox_absolute_x.setValue(5)
|
motor_absolute_widget.ui.spinBox_absolute_x.setValue(5)
|
||||||
motor_absolute_widget.spinBox_absolute_y.setValue(10)
|
motor_absolute_widget.ui.spinBox_absolute_y.setValue(10)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"bec_widgets.widgets.motor_control.motor_control.MotorThread.move_absolute",
|
"bec_widgets.widgets.motor_control.motor_control.MotorThread.move_absolute",
|
||||||
new_callable=MagicMock,
|
new_callable=MagicMock,
|
||||||
) as mock_move_absolute:
|
) as mock_move_absolute:
|
||||||
motor_absolute_widget.pushButton_go_absolute.click()
|
motor_absolute_widget.ui.pushButton_go_absolute.click()
|
||||||
mock_move_absolute.assert_called_once_with("samx", "samy", (5, 10))
|
mock_move_absolute.assert_called_once_with("samx", "samy", (5, 10))
|
||||||
|
|
||||||
|
|
||||||
@ -292,8 +292,8 @@ def test_set_precision(motor_absolute_widget):
|
|||||||
motor_absolute_widget.on_config_update(CONFIG_DEFAULT)
|
motor_absolute_widget.on_config_update(CONFIG_DEFAULT)
|
||||||
motor_absolute_widget.set_precision(2)
|
motor_absolute_widget.set_precision(2)
|
||||||
|
|
||||||
assert motor_absolute_widget.spinBox_absolute_x.decimals() == 2
|
assert motor_absolute_widget.ui.spinBox_absolute_x.decimals() == 2
|
||||||
assert motor_absolute_widget.spinBox_absolute_y.decimals() == 2
|
assert motor_absolute_widget.ui.spinBox_absolute_y.decimals() == 2
|
||||||
|
|
||||||
|
|
||||||
#######################################################
|
#######################################################
|
||||||
@ -338,29 +338,29 @@ def test_initialization_and_config_update(motor_relative_widget):
|
|||||||
def test_move_motor_relative(motor_relative_widget):
|
def test_move_motor_relative(motor_relative_widget):
|
||||||
motor_relative_widget.on_config_update(CONFIG_DEFAULT)
|
motor_relative_widget.on_config_update(CONFIG_DEFAULT)
|
||||||
# Set step sizes
|
# Set step sizes
|
||||||
motor_relative_widget.spinBox_step_x.setValue(1)
|
motor_relative_widget.ui.spinBox_step_x.setValue(1)
|
||||||
motor_relative_widget.spinBox_step_y.setValue(1)
|
motor_relative_widget.ui.spinBox_step_y.setValue(1)
|
||||||
|
|
||||||
# Mock the move_relative method
|
# Mock the move_relative method
|
||||||
motor_relative_widget.motor_thread.move_relative = MagicMock()
|
motor_relative_widget.motor_thread.move_relative = MagicMock()
|
||||||
|
|
||||||
# Simulate button clicks
|
# Simulate button clicks
|
||||||
motor_relative_widget.toolButton_right.click()
|
motor_relative_widget.ui.toolButton_right.click()
|
||||||
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
||||||
motor_relative_widget.motor_x, 1
|
motor_relative_widget.motor_x, 1
|
||||||
)
|
)
|
||||||
|
|
||||||
motor_relative_widget.toolButton_left.click()
|
motor_relative_widget.ui.toolButton_left.click()
|
||||||
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
||||||
motor_relative_widget.motor_x, -1
|
motor_relative_widget.motor_x, -1
|
||||||
)
|
)
|
||||||
|
|
||||||
motor_relative_widget.toolButton_up.click()
|
motor_relative_widget.ui.toolButton_up.click()
|
||||||
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
||||||
motor_relative_widget.motor_y, 1
|
motor_relative_widget.motor_y, 1
|
||||||
)
|
)
|
||||||
|
|
||||||
motor_relative_widget.toolButton_down.click()
|
motor_relative_widget.ui.toolButton_down.click()
|
||||||
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
motor_relative_widget.motor_thread.move_relative.assert_called_with(
|
||||||
motor_relative_widget.motor_y, -1
|
motor_relative_widget.motor_y, -1
|
||||||
)
|
)
|
||||||
@ -376,21 +376,21 @@ def test_precision_update(motor_relative_widget):
|
|||||||
motor_relative_widget.precision_signal.connect(capture_precision)
|
motor_relative_widget.precision_signal.connect(capture_precision)
|
||||||
|
|
||||||
# Update precision
|
# Update precision
|
||||||
motor_relative_widget.spinBox_precision.setValue(1)
|
motor_relative_widget.ui.spinBox_precision.setValue(1)
|
||||||
|
|
||||||
assert emitted_values == [1]
|
assert emitted_values == [1]
|
||||||
assert motor_relative_widget.spinBox_step_x.decimals() == 1
|
assert motor_relative_widget.ui.spinBox_step_x.decimals() == 1
|
||||||
assert motor_relative_widget.spinBox_step_y.decimals() == 1
|
assert motor_relative_widget.ui.spinBox_step_y.decimals() == 1
|
||||||
|
|
||||||
|
|
||||||
def test_sync_step_sizes(motor_relative_widget):
|
def test_sync_step_sizes(motor_relative_widget):
|
||||||
motor_relative_widget.on_config_update(CONFIG_DEFAULT)
|
motor_relative_widget.on_config_update(CONFIG_DEFAULT)
|
||||||
motor_relative_widget.checkBox_same_xy.setChecked(True)
|
motor_relative_widget.ui.checkBox_same_xy.setChecked(True)
|
||||||
|
|
||||||
# Change step size for X
|
# Change step size for X
|
||||||
motor_relative_widget.spinBox_step_x.setValue(2)
|
motor_relative_widget.ui.spinBox_step_x.setValue(2)
|
||||||
|
|
||||||
assert motor_relative_widget.spinBox_step_y.value() == 2
|
assert motor_relative_widget.ui.spinBox_step_y.value() == 2
|
||||||
|
|
||||||
|
|
||||||
def test_change_motor_relative(motor_relative_widget):
|
def test_change_motor_relative(motor_relative_widget):
|
||||||
@ -420,11 +420,11 @@ def test_delete_selected_row(motor_coordinate_table):
|
|||||||
motor_coordinate_table.add_coordinate((3.0, 4.0))
|
motor_coordinate_table.add_coordinate((3.0, 4.0))
|
||||||
|
|
||||||
# Select the row
|
# Select the row
|
||||||
motor_coordinate_table.table.selectRow(0)
|
motor_coordinate_table.ui.table.selectRow(0)
|
||||||
|
|
||||||
# Delete the selected row
|
# Delete the selected row
|
||||||
motor_coordinate_table.delete_selected_row()
|
motor_coordinate_table.delete_selected_row()
|
||||||
assert motor_coordinate_table.table.rowCount() == 1
|
assert motor_coordinate_table.ui.table.rowCount() == 1
|
||||||
|
|
||||||
|
|
||||||
def test_add_coordinate_and_table_update(motor_coordinate_table):
|
def test_add_coordinate_and_table_update(motor_coordinate_table):
|
||||||
@ -433,20 +433,24 @@ def test_add_coordinate_and_table_update(motor_coordinate_table):
|
|||||||
|
|
||||||
# Add coordinate in Individual mode
|
# Add coordinate in Individual mode
|
||||||
motor_coordinate_table.add_coordinate((1.0, 2.0))
|
motor_coordinate_table.add_coordinate((1.0, 2.0))
|
||||||
assert motor_coordinate_table.table.rowCount() == 1
|
assert motor_coordinate_table.ui.table.rowCount() == 1
|
||||||
|
|
||||||
# Check if the coordinates match
|
# Check if the coordinates match
|
||||||
x_item_individual = motor_coordinate_table.table.cellWidget(0, 3) # Assuming X is in column 3
|
x_item_individual = motor_coordinate_table.ui.table.cellWidget(
|
||||||
y_item_individual = motor_coordinate_table.table.cellWidget(0, 4) # Assuming Y is in column 4
|
0, 3
|
||||||
|
) # Assuming X is in column 3
|
||||||
|
y_item_individual = motor_coordinate_table.ui.table.cellWidget(
|
||||||
|
0, 4
|
||||||
|
) # Assuming Y is in column 4
|
||||||
assert float(x_item_individual.text()) == 1.0
|
assert float(x_item_individual.text()) == 1.0
|
||||||
assert float(y_item_individual.text()) == 2.0
|
assert float(y_item_individual.text()) == 2.0
|
||||||
|
|
||||||
# Switch to Start/Stop and add coordinates
|
# Switch to Start/Stop and add coordinates
|
||||||
motor_coordinate_table.comboBox_mode.setCurrentIndex(1) # Switch mode
|
motor_coordinate_table.ui.comboBox_mode.setCurrentIndex(1) # Switch mode
|
||||||
|
|
||||||
motor_coordinate_table.add_coordinate((3.0, 4.0))
|
motor_coordinate_table.add_coordinate((3.0, 4.0))
|
||||||
motor_coordinate_table.add_coordinate((5.0, 6.0))
|
motor_coordinate_table.add_coordinate((5.0, 6.0))
|
||||||
assert motor_coordinate_table.table.rowCount() == 1
|
assert motor_coordinate_table.ui.table.rowCount() == 1
|
||||||
|
|
||||||
|
|
||||||
def test_plot_coordinates_signal(motor_coordinate_table):
|
def test_plot_coordinates_signal(motor_coordinate_table):
|
||||||
@ -466,26 +470,26 @@ def test_plot_coordinates_signal(motor_coordinate_table):
|
|||||||
assert received
|
assert received
|
||||||
|
|
||||||
|
|
||||||
def test_move_motor_action(motor_coordinate_table):
|
# def test_move_motor_action(motor_coordinate_table,qtbot):#TODO enable again after table refactor
|
||||||
# Add a coordinate
|
# # Add a coordinate
|
||||||
motor_coordinate_table.add_coordinate((1.0, 2.0))
|
# motor_coordinate_table.add_coordinate((1.0, 2.0))
|
||||||
|
#
|
||||||
# Mock the motor thread move_absolute function
|
# # Mock the motor thread move_absolute function
|
||||||
motor_coordinate_table.motor_thread.move_absolute = MagicMock()
|
# motor_coordinate_table.motor_thread.move_absolute = MagicMock()
|
||||||
|
#
|
||||||
# Trigger the move action
|
# # Trigger the move action
|
||||||
move_button = motor_coordinate_table.table.cellWidget(0, 1)
|
# move_button = motor_coordinate_table.table.cellWidget(0, 1)
|
||||||
move_button.click()
|
# move_button.click()
|
||||||
|
#
|
||||||
motor_coordinate_table.motor_thread.move_absolute.assert_called_with(
|
# motor_coordinate_table.motor_thread.move_absolute.assert_called_with(
|
||||||
motor_coordinate_table.motor_x, motor_coordinate_table.motor_y, (1.0, 2.0)
|
# motor_coordinate_table.motor_x, motor_coordinate_table.motor_y, (1.0, 2.0)
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
def test_plot_coordinates_signal_individual(motor_coordinate_table, qtbot):
|
def test_plot_coordinates_signal_individual(motor_coordinate_table, qtbot):
|
||||||
motor_coordinate_table.warning_message = False
|
motor_coordinate_table.warning_message = False
|
||||||
motor_coordinate_table.set_precision(3)
|
motor_coordinate_table.set_precision(3)
|
||||||
motor_coordinate_table.comboBox_mode.setCurrentIndex(0)
|
motor_coordinate_table.ui.comboBox_mode.setCurrentIndex(0)
|
||||||
|
|
||||||
# This list will store the signals emitted during the test
|
# This list will store the signals emitted during the test
|
||||||
emitted_signals = []
|
emitted_signals = []
|
||||||
@ -506,8 +510,8 @@ def test_plot_coordinates_signal_individual(motor_coordinate_table, qtbot):
|
|||||||
assert len(coordinates) > 0, "Coordinates list is empty."
|
assert len(coordinates) > 0, "Coordinates list is empty."
|
||||||
assert reference_tag == "Individual"
|
assert reference_tag == "Individual"
|
||||||
assert color == "green"
|
assert color == "green"
|
||||||
assert motor_coordinate_table.table.cellWidget(0, 3).text() == "1.000"
|
assert motor_coordinate_table.ui.table.cellWidget(0, 3).text() == "1.000"
|
||||||
assert motor_coordinate_table.table.cellWidget(0, 4).text() == "2.000"
|
assert motor_coordinate_table.ui.table.cellWidget(0, 4).text() == "2.000"
|
||||||
|
|
||||||
|
|
||||||
#######################################################
|
#######################################################
|
||||||
|
Reference in New Issue
Block a user