import numpy as np
from lys import multicut, Wave
from lys.Qt import QtWidgets, QtCore
from .widgets import AliveIndicator, SettingsButton
[docs]
class MultiDetectorGUI(QtWidgets.QWidget):
"""
GUI for MultiDetectorInterface.
Only for implementation in lys.
"""
def __init__(self, obj, wait=False, interval=1, iter=1):
super().__init__()
self._obj = obj
self._params = {"wait": wait, "interval": interval, "iter": iter}
self._frameCount = None
self._obj.busyStateChanged.connect(self._setButtonState)
self._obj.aliveStateChanged.connect(self._setButtonState)
self._obj.dataAcquired.connect(self._dataAcquired)
self._obj.busyStateChanged.connect(self._onAcqFinished)
self._initLayout()
def _initLayout(self):
# Data display widget
self._mcut = multicut(Wave(np.random.rand(*self._obj.dataShape), *self._obj.axes), returnInstance=True, subWindow=False)
self._mcut.widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self._mcut.loadDefaultTemplate()
self._mcut.cui.dimensionChanged.connect(lambda: self._mcut.loadDefaultTemplate())
# Acquisition control widgets
if self._obj.exposure is not None:
def setExposure(value):
self._obj.exposure = value
expTime = QtWidgets.QDoubleSpinBox()
expTime.setValue(self._obj.exposure)
expTime.setRange(0, np.infty)
expTime.setDecimals(5)
expTime.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
expTime.valueChanged.connect(setExposure)
exposeLabel = QtWidgets.QLabel("Exp. (s)")
exposeLabel.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
# Buttons
self._acquire = QtWidgets.QPushButton("Acquire", clicked=lambda: self._onAcquire("acquire"))
self._stream = QtWidgets.QPushButton("Stream", clicked=lambda: self._onAcquire("stream"))
self._stop = QtWidgets.QPushButton("Stop", clicked=self._obj.stop)
self._stop.setEnabled(False)
# Layout setup
imageLayout = QtWidgets.QHBoxLayout()
imageLayout.addWidget(self._mcut.widget)
controlsLayout = QtWidgets.QHBoxLayout()
controlsLayout.addWidget(AliveIndicator(self._obj))
if self._obj.exposure is not None:
controlsLayout.addWidget(exposeLabel)
controlsLayout.addWidget(expTime)
controlsLayout.addWidget(self._acquire)
controlsLayout.addWidget(self._stream)
controlsLayout.addWidget(self._stop)
controlsLayout.addWidget(SettingsButton(clicked=self._showSettings))
mainLayout = QtWidgets.QVBoxLayout()
mainLayout.addLayout(imageLayout, stretch=1)
mainLayout.addLayout(controlsLayout, stretch=0)
self.setLayout(mainLayout)
def _update(self):
if self._frameCount is not None:
self._mcut.cui.updateRawWave(axes=self._obj.axes)
def _dataAcquired(self, data):
if data:
if self._frameCount is None:
self._frameCount = 0
d = Wave(np.zeros(self._obj.dataShape), *self._obj.axes)
self._mcut.cui.setRawWave(d)
self._mcut.cui.updateRawWave(data, update=False)
self._frameCount += 1
# Update frame display every N frames or on last frame
if self._frameCount == np.prod(self._obj.indexShape):
update = True
else:
update = False if self._params["interval"] is None else self._frameCount % self._params["interval"] == 0
if update:
self._update()
def _onAcqFinished(self, b):
if b is False: # Not busy anymore
self._frameCount = None
def _onAcquire(self, mode="acquire"):
if mode == "acquire":
self._obj.startAcq(wait=self._params["wait"], iter=self._params["iter"])
else:
self._obj.startAcq(iter=-1)
def _setButtonState(self):
if not self._obj.isAlive:
self._acquire.setEnabled(False)
self._stream.setEnabled(False)
self._stop.setEnabled(False)
elif self._obj.isBusy:
self._acquire.setEnabled(False)
self._stream.setEnabled(False)
self._stop.setEnabled(True)
else:
self._acquire.setEnabled(True)
self._stream.setEnabled(True)
self._stop.setEnabled(False)
def _showSettings(self):
settingsWindow = _SettingsDialog(self, self._obj, self._params)
settingsWindow.updated.connect(self._update)
settingsWindow.exec_()
class _SettingsDialog(QtWidgets.QDialog):
updated = QtCore.pyqtSignal()
def __init__(self, parent, obj, params):
super().__init__(parent)
self.setWindowTitle("Detector Settings")
tabs = QtWidgets.QTabWidget()
tabs.addTab(_GeneralPanel(params, updated=self.updated.emit), "General")
tabs.addTab(obj.settingsWidget(), "Optional")
layout = QtWidgets.QVBoxLayout()
layout.addWidget(tabs)
self.setLayout(layout)
class _GeneralPanel(QtWidgets.QWidget):
updated = QtCore.pyqtSignal()
def __init__(self, params, updated=None):
super().__init__()
self._params = params
self.__initLayout(params["interval"])
if updated is not None:
self.updated.connect(updated)
def __initLayout(self, interval):
self._iter = QtWidgets.QSpinBox()
self._iter.setRange(1, 2**31 - 1)
self._updateInterval = QtWidgets.QSpinBox()
self._updateInterval.setRange(1, 2**31 - 1)
if interval is None:
self._updateInterval.setEnabled(False)
else:
self._updateInterval.setValue(interval)
self._scheduledUpdateCheck = QtWidgets.QCheckBox("Update every", checked=interval is not None, toggled=self._changeInterval)
self._iter.valueChanged.connect(self._changeInterval)
self._updateInterval.valueChanged.connect(self._changeInterval)
self._scheduledUpdateCheck.stateChanged.connect(self._updateInterval.setEnabled)
grid = QtWidgets.QGridLayout()
grid.addWidget(QtWidgets.QLabel("Repeat"), 0, 0)
grid.addWidget(self._iter, 0, 1)
grid.addWidget(QtWidgets.QLabel("times"), 0, 2)
grid.addWidget(self._scheduledUpdateCheck, 1, 0)
grid.addWidget(self._updateInterval, 1, 1)
grid.addWidget(QtWidgets.QLabel("frames"), 1, 2)
grid.addWidget(QtWidgets.QPushButton("Update", clicked=self.updated.emit), 1, 3)
self.setLayout(grid)
def _changeInterval(self):
if self._scheduledUpdateCheck.isChecked():
self._params["interval"] = self._updateInterval.value()
else:
self._params["interval"] = None
self._params["iter"] = self._iter.value()