artiq/artiq/gui/entries.py

289 lines
9.5 KiB
Python
Raw Normal View History

2015-11-30 00:21:27 +08:00
import logging
from collections import OrderedDict
2015-11-30 23:10:12 +08:00
from quamash import QtGui, QtCore
2015-07-21 23:23:32 +08:00
from pyqtgraph import LayoutWidget
from artiq.gui.tools import disable_scroll_wheel
2015-07-21 23:23:32 +08:00
2015-11-30 00:21:27 +08:00
logger = logging.getLogger(__name__)
2016-01-10 21:48:17 +08:00
class _StringEntry(QtGui.QLineEdit):
def __init__(self, argument):
QtGui.QLineEdit.__init__(self)
self.setText(argument["state"])
def update(text):
argument["state"] = text
self.textEdited.connect(update)
@staticmethod
def state_to_value(state):
return state
@staticmethod
def default_state(procdesc):
return procdesc.get("default", "")
class _BooleanEntry(QtGui.QCheckBox):
def __init__(self, argument):
QtGui.QCheckBox.__init__(self)
self.setChecked(argument["state"])
def update(checked):
argument["state"] = bool(checked)
self.stateChanged.connect(update)
@staticmethod
def state_to_value(state):
return state
@staticmethod
def default_state(procdesc):
return procdesc.get("default", False)
class _EnumerationEntry(QtGui.QComboBox):
def __init__(self, argument):
QtGui.QComboBox.__init__(self)
disable_scroll_wheel(self)
choices = argument["desc"]["choices"]
self.addItems(choices)
idx = choices.index(argument["state"])
self.setCurrentIndex(idx)
def update(index):
argument["state"] = choices[index]
self.currentIndexChanged.connect(update)
@staticmethod
def state_to_value(state):
return state
@staticmethod
def default_state(procdesc):
if "default" in procdesc:
return procdesc["default"]
else:
return procdesc["choices"][0]
class _NumberEntry(QtGui.QDoubleSpinBox):
def __init__(self, argument):
QtGui.QDoubleSpinBox.__init__(self)
disable_scroll_wheel(self)
procdesc = argument["desc"]
scale = procdesc["scale"]
self.setDecimals(procdesc["ndecimals"])
self.setSingleStep(procdesc["step"]/scale)
if procdesc["min"] is not None:
self.setMinimum(procdesc["min"]/scale)
else:
self.setMinimum(float("-inf"))
if procdesc["max"] is not None:
self.setMaximum(procdesc["max"]/scale)
else:
self.setMaximum(float("inf"))
if procdesc["unit"]:
self.setSuffix(" " + procdesc["unit"])
self.setValue(argument["state"]/scale)
def update(value):
argument["state"] = value*scale
self.valueChanged.connect(update)
@staticmethod
def state_to_value(state):
return state
@staticmethod
def default_state(procdesc):
if "default" in procdesc:
return procdesc["default"]
else:
return 0.0
2015-11-30 00:21:27 +08:00
class _NoScan(LayoutWidget):
def __init__(self, procdesc, state):
LayoutWidget.__init__(self)
scale = procdesc["scale"]
self.value = QtGui.QDoubleSpinBox()
disable_scroll_wheel(self.value)
2015-11-30 00:21:27 +08:00
self.value.setDecimals(procdesc["ndecimals"])
if procdesc["global_min"] is not None:
self.value.setMinimum(procdesc["global_min"]/scale)
else:
self.value.setMinimum(float("-inf"))
if procdesc["global_max"] is not None:
self.value.setMaximum(procdesc["global_max"]/scale)
else:
self.value.setMaximum(float("inf"))
self.value.setSingleStep(procdesc["global_step"]/scale)
if procdesc["unit"]:
self.value.setSuffix(" " + procdesc["unit"])
self.addWidget(QtGui.QLabel("Value:"), 0, 0)
self.addWidget(self.value, 0, 1)
self.value.setValue(state["value"]/scale)
def update(value):
state["value"] = value*scale
self.value.valueChanged.connect(update)
2016-01-10 21:48:17 +08:00
class _RangeScan(LayoutWidget):
2015-11-30 00:21:27 +08:00
def __init__(self, procdesc, state):
2015-07-21 23:23:32 +08:00
LayoutWidget.__init__(self)
2015-11-30 00:21:27 +08:00
scale = procdesc["scale"]
2015-07-21 23:23:32 +08:00
def apply_properties(spinbox):
2015-11-30 00:21:27 +08:00
spinbox.setDecimals(procdesc["ndecimals"])
if procdesc["global_min"] is not None:
spinbox.setMinimum(procdesc["global_min"]/scale)
2015-08-25 00:56:19 +08:00
else:
spinbox.setMinimum(float("-inf"))
2015-11-30 00:21:27 +08:00
if procdesc["global_max"] is not None:
spinbox.setMaximum(procdesc["global_max"]/scale)
2015-08-25 00:56:19 +08:00
else:
spinbox.setMaximum(float("inf"))
2015-11-30 00:21:27 +08:00
if procdesc["global_step"] is not None:
spinbox.setSingleStep(procdesc["global_step"]/scale)
if procdesc["unit"]:
spinbox.setSuffix(" " + procdesc["unit"])
2015-07-21 23:23:32 +08:00
self.addWidget(QtGui.QLabel("Min:"), 0, 0)
self.min = QtGui.QDoubleSpinBox()
disable_scroll_wheel(self.min)
2015-07-21 23:23:32 +08:00
apply_properties(self.min)
self.addWidget(self.min, 0, 1)
self.addWidget(QtGui.QLabel("Max:"), 1, 0)
2015-07-21 23:23:32 +08:00
self.max = QtGui.QDoubleSpinBox()
disable_scroll_wheel(self.max)
2015-07-21 23:23:32 +08:00
apply_properties(self.max)
self.addWidget(self.max, 1, 1)
2015-07-21 23:23:32 +08:00
self.addWidget(QtGui.QLabel("#Points:"), 2, 0)
2015-07-21 23:23:32 +08:00
self.npoints = QtGui.QSpinBox()
disable_scroll_wheel(self.npoints)
2015-07-21 23:23:32 +08:00
self.npoints.setMinimum(2)
self.npoints.setValue(10)
self.addWidget(self.npoints, 2, 1)
2015-07-21 23:23:32 +08:00
2015-11-30 00:21:27 +08:00
self.min.setValue(state["min"]/scale)
self.max.setValue(state["max"]/scale)
self.npoints.setValue(state["npoints"])
def update_min(value):
state["min"] = value*scale
def update_max(value):
state["min"] = value*scale
def update_npoints(value):
state["npoints"] = value
self.min.valueChanged.connect(update_min)
self.max.valueChanged.connect(update_max)
self.npoints.valueChanged.connect(update_npoints)
2016-01-10 21:48:17 +08:00
class _ExplicitScan(LayoutWidget):
2015-11-30 00:21:27 +08:00
def __init__(self, state):
LayoutWidget.__init__(self)
self.value = QtGui.QLineEdit()
self.addWidget(QtGui.QLabel("Sequence:"), 0, 0)
self.addWidget(self.value, 0, 1)
2015-11-30 23:10:12 +08:00
float_regexp = "[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?"
regexp = "(float)?( +float)* *".replace("float", float_regexp)
self.value.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(regexp),
self.value))
2015-11-30 00:21:27 +08:00
self.value.setText(" ".join([str(x) for x in state["sequence"]]))
def update(text):
state["sequence"] = [float(x) for x in text.split()]
self.value.textEdited.connect(update)
2015-07-21 23:23:32 +08:00
2016-01-10 21:48:17 +08:00
class _ScanEntry(LayoutWidget):
def __init__(self, argument):
2015-07-21 23:23:32 +08:00
LayoutWidget.__init__(self)
2015-11-30 00:21:27 +08:00
self.argument = argument
2015-07-21 23:23:32 +08:00
self.stack = QtGui.QStackedWidget()
self.addWidget(self.stack, 1, 0, colspan=4)
2015-11-30 00:21:27 +08:00
procdesc = argument["desc"]
state = argument["state"]
self.widgets = OrderedDict()
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
2016-01-10 21:48:17 +08:00
self.widgets["LinearScan"] = _RangeScan(procdesc, state["LinearScan"])
self.widgets["RandomScan"] = _RangeScan(procdesc, state["RandomScan"])
self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"])
2015-11-30 00:21:27 +08:00
for widget in self.widgets.values():
self.stack.addWidget(widget)
self.radiobuttons = OrderedDict()
self.radiobuttons["NoScan"] = QtGui.QRadioButton("No scan")
self.radiobuttons["LinearScan"] = QtGui.QRadioButton("Linear")
self.radiobuttons["RandomScan"] = QtGui.QRadioButton("Random")
self.radiobuttons["ExplicitScan"] = QtGui.QRadioButton("Explicit")
scan_type = QtGui.QButtonGroup()
for n, b in enumerate(self.radiobuttons.values()):
self.addWidget(b, 0, n)
scan_type.addButton(b)
b.toggled.connect(self._scan_type_toggled)
2015-11-30 00:21:27 +08:00
selected = argument["state"]["selected"]
self.radiobuttons[selected].setChecked(True)
2015-07-21 23:23:32 +08:00
2015-11-30 00:21:27 +08:00
@staticmethod
def state_to_value(state):
selected = state["selected"]
r = dict(state[selected])
r["ty"] = selected
return r
2015-07-21 23:23:32 +08:00
2015-11-27 19:30:05 +08:00
@staticmethod
2015-11-30 00:21:27 +08:00
def default_state(procdesc):
scale = procdesc["scale"]
state = {
"selected": "NoScan",
"NoScan": {"value": 0.0},
"LinearScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
"RandomScan": {"min": 0.0, "max": 100.0*scale, "npoints": 10},
"ExplicitScan": {"sequence": []}
}
if "default" in procdesc:
default = procdesc["default"]
ty = default["ty"]
state["selected"] = ty
if ty == "NoScan":
state["NoScan"]["value"] = default["value"]
elif ty == "LinearScan" or ty == "RandomScan":
for d in state["LinearScan"], state["RandomScan"]:
d["min"] = default["min"]
d["max"] = default["max"]
d["npoints"] = default["npoints"]
elif ty == "ExplicitScan":
state["ExplicitScan"]["sequence"] = default["sequence"]
else:
logger.warning("unknown default type: %s", ty)
return state
def _scan_type_toggled(self):
for ty, button in self.radiobuttons.items():
if button.isChecked():
self.stack.setCurrentWidget(self.widgets[ty])
self.argument["state"]["selected"] = ty
break
2016-01-10 21:48:17 +08:00
argty_to_entry = {
"PYONValue": _StringEntry,
"BooleanValue": _BooleanEntry,
"EnumerationValue": _EnumerationEntry,
"NumberValue": _NumberEntry,
"StringValue": _StringEntry,
"Scannable": _ScanEntry
}