forked from M-Labs/artiq
Compare commits
6 Commits
c4323e1179
...
eebe0fefd8
Author | SHA1 | Date |
---|---|---|
Simon Renblad | eebe0fefd8 | |
Simon Renblad | 13a36bf911 | |
Simon Renblad | 88438e2d76 | |
Simon Renblad | 1a41b16fb6 | |
Simon Renblad | 6978101b1f | |
Simon Renblad | 244c73a592 |
|
@ -10,87 +10,24 @@ import h5py
|
|||
from sipyco import pyon
|
||||
|
||||
from artiq import __artiq_dir__ as artiq_dir
|
||||
from artiq.gui.tools import (LayoutWidget, WheelFilter,
|
||||
log_level_to_name, get_open_file_name)
|
||||
from artiq.gui.entries import procdesc_to_entry
|
||||
from artiq.gui.tools import (LayoutWidget, log_level_to_name, get_open_file_name)
|
||||
from artiq.gui.entries import procdesc_to_entry, EntryTreeWidget
|
||||
from artiq.master.worker import Worker, log_worker_exception
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _ArgumentEditor(QtWidgets.QTreeWidget):
|
||||
class _ArgumentEditor(EntryTreeWidget):
|
||||
def __init__(self, dock):
|
||||
QtWidgets.QTreeWidget.__init__(self)
|
||||
self.setColumnCount(3)
|
||||
self.header().setStretchLastSection(False)
|
||||
try:
|
||||
set_resize_mode = self.header().setSectionResizeMode
|
||||
except AttributeError:
|
||||
set_resize_mode = self.header().setResizeMode
|
||||
set_resize_mode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
set_resize_mode(1, QtWidgets.QHeaderView.Stretch)
|
||||
set_resize_mode(2, QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.header().setVisible(False)
|
||||
self.setSelectionMode(self.NoSelection)
|
||||
self.setHorizontalScrollMode(self.ScrollPerPixel)
|
||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||
|
||||
self.setStyleSheet("QTreeWidget {background: " +
|
||||
self.palette().midlight().color().name() + " ;}")
|
||||
|
||||
self.viewport().installEventFilter(WheelFilter(self.viewport(), True))
|
||||
|
||||
self._groups = dict()
|
||||
self._arg_to_widgets = dict()
|
||||
EntryTreeWidget.__init__(self)
|
||||
self._dock = dock
|
||||
|
||||
if not self._dock.arguments:
|
||||
self.addTopLevelItem(QtWidgets.QTreeWidgetItem(["No arguments"]))
|
||||
gradient = QtGui.QLinearGradient(
|
||||
0, 0, 0, QtGui.QFontMetrics(self.font()).lineSpacing()*2.5)
|
||||
gradient.setColorAt(0, self.palette().base().color())
|
||||
gradient.setColorAt(1, self.palette().midlight().color())
|
||||
|
||||
for name, argument in self._dock.arguments.items():
|
||||
widgets = dict()
|
||||
self._arg_to_widgets[name] = widgets
|
||||
self.set_argument(name, argument)
|
||||
|
||||
entry = procdesc_to_entry(argument["desc"])(argument)
|
||||
widget_item = QtWidgets.QTreeWidgetItem([name])
|
||||
if argument["tooltip"]:
|
||||
widget_item.setToolTip(0, argument["tooltip"])
|
||||
widgets["entry"] = entry
|
||||
widgets["widget_item"] = widget_item
|
||||
|
||||
for col in range(3):
|
||||
widget_item.setBackground(col, gradient)
|
||||
font = widget_item.font(0)
|
||||
font.setBold(True)
|
||||
widget_item.setFont(0, font)
|
||||
|
||||
if argument["group"] is None:
|
||||
self.addTopLevelItem(widget_item)
|
||||
else:
|
||||
self._get_group(argument["group"]).addChild(widget_item)
|
||||
fix_layout = LayoutWidget()
|
||||
widgets["fix_layout"] = fix_layout
|
||||
fix_layout.addWidget(entry)
|
||||
self.setItemWidget(widget_item, 1, fix_layout)
|
||||
|
||||
recompute_argument = QtWidgets.QToolButton()
|
||||
recompute_argument.setToolTip("Re-run the experiment's build "
|
||||
"method and take the default value")
|
||||
recompute_argument.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_BrowserReload))
|
||||
recompute_argument.clicked.connect(
|
||||
partial(self._recompute_argument_clicked, name))
|
||||
fix_layout = LayoutWidget()
|
||||
fix_layout.addWidget(recompute_argument)
|
||||
self.setItemWidget(widget_item, 2, fix_layout)
|
||||
|
||||
widget_item = QtWidgets.QTreeWidgetItem()
|
||||
self.addTopLevelItem(widget_item)
|
||||
recompute_arguments = QtWidgets.QPushButton("Recompute all arguments")
|
||||
recompute_arguments.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
|
@ -100,7 +37,7 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
load = QtWidgets.QPushButton("Set arguments from HDF5")
|
||||
load.setToolTip("Set arguments from currently selected HDF5 file")
|
||||
load.setIcon(QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_DialogApplyButton))
|
||||
QtWidgets.QStyle.SP_DialogApplyButton))
|
||||
load.clicked.connect(self._load_clicked)
|
||||
|
||||
buttons = LayoutWidget()
|
||||
|
@ -108,21 +45,7 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
buttons.addWidget(load, 1, 2)
|
||||
for i, s in enumerate((1, 0, 0, 1)):
|
||||
buttons.layout.setColumnStretch(i, s)
|
||||
self.setItemWidget(widget_item, 1, buttons)
|
||||
|
||||
def _get_group(self, name):
|
||||
if name in self._groups:
|
||||
return self._groups[name]
|
||||
group = QtWidgets.QTreeWidgetItem([name])
|
||||
for col in range(3):
|
||||
group.setBackground(col, self.palette().mid())
|
||||
group.setForeground(col, self.palette().brightText())
|
||||
font = group.font(col)
|
||||
font.setBold(True)
|
||||
group.setFont(col, font)
|
||||
self.addTopLevelItem(group)
|
||||
self._groups[name] = group
|
||||
return group
|
||||
self.setItemWidget(self.bottom_item, 1, buttons)
|
||||
|
||||
def _load_clicked(self):
|
||||
asyncio.ensure_future(self._dock.load_hdf5_task())
|
||||
|
@ -130,8 +53,8 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
def _recompute_arguments_clicked(self):
|
||||
asyncio.ensure_future(self._dock._recompute_arguments())
|
||||
|
||||
def _recompute_argument_clicked(self, name):
|
||||
asyncio.ensure_future(self._recompute_argument(name))
|
||||
def reset_entry(self, key):
|
||||
asyncio.ensure_future(self._recompute_argument(key))
|
||||
|
||||
async def _recompute_argument(self, name):
|
||||
try:
|
||||
|
@ -146,29 +69,7 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
state = procdesc_to_entry(procdesc).default_state(procdesc)
|
||||
argument["desc"] = procdesc
|
||||
argument["state"] = state
|
||||
|
||||
widgets = self._arg_to_widgets[name]
|
||||
|
||||
widgets["entry"].deleteLater()
|
||||
widgets["entry"] = procdesc_to_entry(procdesc)(argument)
|
||||
widgets["fix_layout"] = LayoutWidget()
|
||||
widgets["fix_layout"].addWidget(widgets["entry"])
|
||||
self.setItemWidget(widgets["widget_item"], 1, widgets["fix_layout"])
|
||||
self.updateGeometries()
|
||||
|
||||
def save_state(self):
|
||||
expanded = []
|
||||
for k, v in self._groups.items():
|
||||
if v.isExpanded():
|
||||
expanded.append(k)
|
||||
return {"expanded": expanded}
|
||||
|
||||
def restore_state(self, state):
|
||||
for e in state["expanded"]:
|
||||
try:
|
||||
self._groups[e].setExpanded(True)
|
||||
except KeyError:
|
||||
pass
|
||||
self.update_argument(name, argument)
|
||||
|
||||
|
||||
log_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
|
@ -277,8 +178,8 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow):
|
|||
state = self.argeditor.save_state()
|
||||
self.argeditor.deleteLater()
|
||||
self.argeditor = _ArgumentEditor(self)
|
||||
self.argeditor.restore_state(state)
|
||||
self.layout.addWidget(self.argeditor, 0, 0, 1, 5)
|
||||
self.argeditor.restore_state(state)
|
||||
|
||||
async def load_hdf5_task(self, filename=None):
|
||||
if filename is None:
|
||||
|
|
|
@ -9,10 +9,9 @@ import h5py
|
|||
|
||||
from sipyco import pyon
|
||||
|
||||
from artiq.gui.entries import procdesc_to_entry, ScanEntry
|
||||
from artiq.gui.entries import procdesc_to_entry, EntryTreeWidget
|
||||
from artiq.gui.fuzzy_select import FuzzySelectWidget
|
||||
from artiq.gui.tools import (LayoutWidget, WheelFilter,
|
||||
log_level_to_name, get_open_file_name)
|
||||
from artiq.gui.tools import (LayoutWidget, log_level_to_name, get_open_file_name)
|
||||
from artiq.tools import parse_devarg_override, unparse_devarg_override
|
||||
|
||||
|
||||
|
@ -25,99 +24,21 @@ logger = logging.getLogger(__name__)
|
|||
# 2. file:<class name>@<file name>
|
||||
|
||||
|
||||
class _ArgumentEditor(QtWidgets.QTreeWidget):
|
||||
class _ArgumentEditor(EntryTreeWidget):
|
||||
def __init__(self, manager, dock, expurl):
|
||||
self.manager = manager
|
||||
self.expurl = expurl
|
||||
|
||||
QtWidgets.QTreeWidget.__init__(self)
|
||||
self.setColumnCount(3)
|
||||
self.header().setStretchLastSection(False)
|
||||
if hasattr(self.header(), "setSectionResizeMode"):
|
||||
set_resize_mode = self.header().setSectionResizeMode
|
||||
else:
|
||||
set_resize_mode = self.header().setResizeMode
|
||||
set_resize_mode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
set_resize_mode(1, QtWidgets.QHeaderView.Stretch)
|
||||
set_resize_mode(2, QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.header().setVisible(False)
|
||||
self.setSelectionMode(self.NoSelection)
|
||||
self.setHorizontalScrollMode(self.ScrollPerPixel)
|
||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||
|
||||
self.setStyleSheet("QTreeWidget {background: " +
|
||||
self.palette().midlight().color().name() + " ;}")
|
||||
|
||||
self.viewport().installEventFilter(WheelFilter(self.viewport(), True))
|
||||
|
||||
self._groups = dict()
|
||||
self._arg_to_widgets = dict()
|
||||
EntryTreeWidget.__init__(self)
|
||||
|
||||
arguments = self.manager.get_submission_arguments(self.expurl)
|
||||
|
||||
if not arguments:
|
||||
self.addTopLevelItem(QtWidgets.QTreeWidgetItem(["No arguments"]))
|
||||
|
||||
gradient = QtGui.QLinearGradient(
|
||||
0, 0, 0, QtGui.QFontMetrics(self.font()).lineSpacing()*2.5)
|
||||
gradient.setColorAt(0, self.palette().base().color())
|
||||
gradient.setColorAt(1, self.palette().midlight().color())
|
||||
for name, argument in arguments.items():
|
||||
widgets = dict()
|
||||
self._arg_to_widgets[name] = widgets
|
||||
self.set_argument(name, argument)
|
||||
|
||||
entry = procdesc_to_entry(argument["desc"])(argument)
|
||||
widget_item = QtWidgets.QTreeWidgetItem([name])
|
||||
if argument["tooltip"]:
|
||||
widget_item.setToolTip(0, argument["tooltip"])
|
||||
widgets["entry"] = entry
|
||||
widgets["widget_item"] = widget_item
|
||||
|
||||
for col in range(3):
|
||||
widget_item.setBackground(col, gradient)
|
||||
font = widget_item.font(0)
|
||||
font.setBold(True)
|
||||
widget_item.setFont(0, font)
|
||||
|
||||
if argument["group"] is None:
|
||||
self.addTopLevelItem(widget_item)
|
||||
else:
|
||||
self._get_group(argument["group"]).addChild(widget_item)
|
||||
fix_layout = LayoutWidget()
|
||||
widgets["fix_layout"] = fix_layout
|
||||
fix_layout.addWidget(entry)
|
||||
self.setItemWidget(widget_item, 1, fix_layout)
|
||||
recompute_argument = QtWidgets.QToolButton()
|
||||
recompute_argument.setToolTip("Re-run the experiment's build "
|
||||
"method and take the default value")
|
||||
recompute_argument.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_BrowserReload))
|
||||
recompute_argument.clicked.connect(
|
||||
partial(self._recompute_argument_clicked, name))
|
||||
|
||||
tool_buttons = LayoutWidget()
|
||||
tool_buttons.addWidget(recompute_argument, 1)
|
||||
|
||||
disable_other_scans = QtWidgets.QToolButton()
|
||||
widgets["disable_other_scans"] = disable_other_scans
|
||||
disable_other_scans.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_DialogResetButton))
|
||||
disable_other_scans.setToolTip("Disable all other scans in "
|
||||
"this experiment")
|
||||
disable_other_scans.clicked.connect(
|
||||
partial(self._disable_other_scans, name))
|
||||
tool_buttons.layout.setRowStretch(0, 1)
|
||||
tool_buttons.layout.setRowStretch(3, 1)
|
||||
tool_buttons.addWidget(disable_other_scans, 2)
|
||||
if not isinstance(entry, ScanEntry):
|
||||
disable_other_scans.setVisible(False)
|
||||
|
||||
self.setItemWidget(widget_item, 2, tool_buttons)
|
||||
|
||||
widget_item = QtWidgets.QTreeWidgetItem()
|
||||
self.addTopLevelItem(widget_item)
|
||||
recompute_arguments = QtWidgets.QPushButton("Recompute all arguments")
|
||||
recompute_arguments.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
|
@ -136,41 +57,10 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
buttons.layout.setColumnStretch(1, 0)
|
||||
buttons.layout.setColumnStretch(2, 0)
|
||||
buttons.layout.setColumnStretch(3, 1)
|
||||
self.setItemWidget(widget_item, 1, buttons)
|
||||
self.setItemWidget(self.bottom_item, 1, buttons)
|
||||
|
||||
def _get_group(self, name):
|
||||
if name in self._groups:
|
||||
return self._groups[name]
|
||||
group = QtWidgets.QTreeWidgetItem([name])
|
||||
for col in range(3):
|
||||
group.setBackground(col, self.palette().mid())
|
||||
group.setForeground(col, self.palette().brightText())
|
||||
font = group.font(col)
|
||||
font.setBold(True)
|
||||
group.setFont(col, font)
|
||||
self.addTopLevelItem(group)
|
||||
self._groups[name] = group
|
||||
return group
|
||||
|
||||
def update_argument(self, name, argument):
|
||||
widgets = self._arg_to_widgets[name]
|
||||
|
||||
# Qt needs a setItemWidget() to handle layout correctly,
|
||||
# simply replacing the entry inside the LayoutWidget
|
||||
# results in a bug.
|
||||
|
||||
widgets["entry"].deleteLater()
|
||||
widgets["entry"] = procdesc_to_entry(argument["desc"])(argument)
|
||||
widgets["disable_other_scans"].setVisible(
|
||||
isinstance(widgets["entry"], ScanEntry))
|
||||
widgets["fix_layout"].deleteLater()
|
||||
widgets["fix_layout"] = LayoutWidget()
|
||||
widgets["fix_layout"].addWidget(widgets["entry"])
|
||||
self.setItemWidget(widgets["widget_item"], 1, widgets["fix_layout"])
|
||||
self.updateGeometries()
|
||||
|
||||
def _recompute_argument_clicked(self, name):
|
||||
asyncio.ensure_future(self._recompute_argument(name))
|
||||
def reset_entry(self, key):
|
||||
asyncio.ensure_future(self._recompute_argument(key))
|
||||
|
||||
async def _recompute_argument(self, name):
|
||||
try:
|
||||
|
@ -187,30 +77,6 @@ class _ArgumentEditor(QtWidgets.QTreeWidget):
|
|||
argument["state"] = state
|
||||
self.update_argument(name, argument)
|
||||
|
||||
def _disable_other_scans(self, current_name):
|
||||
for name, widgets in self._arg_to_widgets.items():
|
||||
if (name != current_name
|
||||
and isinstance(widgets["entry"], ScanEntry)):
|
||||
widgets["entry"].disable()
|
||||
|
||||
def save_state(self):
|
||||
expanded = []
|
||||
for k, v in self._groups.items():
|
||||
if v.isExpanded():
|
||||
expanded.append(k)
|
||||
return {
|
||||
"expanded": expanded,
|
||||
"scroll": self.verticalScrollBar().value()
|
||||
}
|
||||
|
||||
def restore_state(self, state):
|
||||
for e in state["expanded"]:
|
||||
try:
|
||||
self._groups[e].setExpanded(True)
|
||||
except KeyError:
|
||||
pass
|
||||
self.verticalScrollBar().setValue(state["scroll"])
|
||||
|
||||
# Hooks that allow user-supplied argument editors to react to imminent user
|
||||
# actions. Here, we always keep the manager-stored submission arguments
|
||||
# up-to-date, so no further action is required.
|
||||
|
@ -433,8 +299,8 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow):
|
|||
|
||||
editor_class = self.manager.get_argument_editor_class(self.expurl)
|
||||
self.argeditor = editor_class(self.manager, self, self.expurl)
|
||||
self.argeditor.restore_state(argeditor_state)
|
||||
self.layout.addWidget(self.argeditor, 0, 0, 1, 5)
|
||||
self.argeditor.restore_state(argeditor_state)
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = QtWidgets.QMenu(self)
|
||||
|
|
|
@ -14,43 +14,16 @@ from sipyco.pipe_ipc import AsyncioParentComm
|
|||
from sipyco.logging_tools import LogParser
|
||||
from sipyco import pyon
|
||||
|
||||
from artiq.gui.entries import procdesc_to_entry
|
||||
from artiq.gui.tools import (QDockWidgetCloseDetect, LayoutWidget,
|
||||
WheelFilter)
|
||||
from artiq.gui.entries import procdesc_to_entry, EntryTreeWidget
|
||||
from artiq.gui.tools import QDockWidgetCloseDetect, LayoutWidget
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class EntryArea(QtWidgets.QTreeWidget):
|
||||
|
||||
class EntryArea(EntryTreeWidget):
|
||||
def __init__(self):
|
||||
QtWidgets.QTreeWidget.__init__(self)
|
||||
self.setColumnCount(3)
|
||||
self.header().setStretchLastSection(False)
|
||||
if hasattr(self.header(), "setSectionResizeMode"):
|
||||
set_resize_mode = self.header().setSectionResizeMode
|
||||
else:
|
||||
set_resize_mode = self.header().setResizeMode
|
||||
set_resize_mode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
set_resize_mode(1, QtWidgets.QHeaderView.Stretch)
|
||||
self.header().setVisible(False)
|
||||
self.setSelectionMode(self.NoSelection)
|
||||
self.setHorizontalScrollMode(self.ScrollPerPixel)
|
||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||
|
||||
self.setStyleSheet("QTreeWidget {background: " +
|
||||
self.palette().midlight().color().name() + " ;}")
|
||||
|
||||
self.viewport().installEventFilter(WheelFilter(self.viewport(), True))
|
||||
|
||||
self._groups = dict()
|
||||
self._arg_to_widgets = dict()
|
||||
self._arguments = dict()
|
||||
|
||||
self.gradient = QtGui.QLinearGradient(
|
||||
0, 0, 0, QtGui.QFontMetrics(self.font()).lineSpacing()*2.5)
|
||||
self.gradient.setColorAt(0, self.palette().base().color())
|
||||
self.gradient.setColorAt(1, self.palette().midlight().color())
|
||||
|
||||
EntryTreeWidget.__init__(self)
|
||||
reset_all_button = QtWidgets.QPushButton("Restore defaults")
|
||||
reset_all_button.setToolTip("Reset all to default values")
|
||||
reset_all_button.setIcon(
|
||||
|
@ -62,73 +35,16 @@ class EntryArea(QtWidgets.QTreeWidget):
|
|||
buttons.layout.setColumnStretch(1, 0)
|
||||
buttons.layout.setColumnStretch(2, 1)
|
||||
buttons.addWidget(reset_all_button, 0, 1)
|
||||
self.bottom_item = QtWidgets.QTreeWidgetItem()
|
||||
self.addTopLevelItem(self.bottom_item)
|
||||
self.setItemWidget(self.bottom_item, 1, buttons)
|
||||
self.bottom_item.setHidden(True)
|
||||
|
||||
|
||||
def setattr_argument(self, key, processor, group=None, tooltip=None):
|
||||
argument = dict()
|
||||
desc = processor.describe()
|
||||
argument["desc"] = desc
|
||||
argument["group"] = group
|
||||
argument["tooltip"] = tooltip
|
||||
self._arguments[key] = argument
|
||||
widgets = dict()
|
||||
self._arg_to_widgets[key] = widgets
|
||||
entry_class = procdesc_to_entry(argument["desc"])
|
||||
argument["state"] = entry_class.default_state(argument["desc"])
|
||||
entry = entry_class(argument)
|
||||
widget_item = QtWidgets.QTreeWidgetItem([key])
|
||||
if argument["tooltip"]:
|
||||
widget_item.setToolTip(0, argument["tooltip"])
|
||||
widgets["entry"] = entry
|
||||
widgets["widget_item"] = widget_item
|
||||
self.set_argument(key, argument)
|
||||
|
||||
if len(self._arguments) > 1:
|
||||
self.bottom_item.setHidden(False)
|
||||
|
||||
for col in range(3):
|
||||
widget_item.setBackground(col, self.gradient)
|
||||
font = widget_item.font(0)
|
||||
font.setBold(True)
|
||||
widget_item.setFont(0, font)
|
||||
|
||||
if argument["group"] is None:
|
||||
self.insertTopLevelItem(self.indexFromItem(self.bottom_item).row(), widget_item)
|
||||
else:
|
||||
self._get_group(argument["group"]).addChild(widget_item)
|
||||
self.bottom_item.setHidden(False)
|
||||
fix_layout = LayoutWidget()
|
||||
widgets["fix_layout"] = fix_layout
|
||||
fix_layout.addWidget(entry)
|
||||
self.setItemWidget(widget_item, 1, fix_layout)
|
||||
|
||||
reset_value = QtWidgets.QToolButton()
|
||||
reset_value.setToolTip("Reset to default value")
|
||||
reset_value.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_BrowserReload))
|
||||
reset_value.clicked.connect(partial(self.reset_value, key))
|
||||
|
||||
tool_buttons = LayoutWidget()
|
||||
tool_buttons.addWidget(reset_value, 0)
|
||||
self.setItemWidget(widget_item, 2, tool_buttons)
|
||||
|
||||
def _get_group(self, key):
|
||||
if key in self._groups:
|
||||
return self._groups[key]
|
||||
group = QtWidgets.QTreeWidgetItem([key])
|
||||
for col in range(3):
|
||||
group.setBackground(col, self.palette().mid())
|
||||
group.setForeground(col, self.palette().brightText())
|
||||
font = group.font(col)
|
||||
font.setBold(True)
|
||||
group.setFont(col, font)
|
||||
self.insertTopLevelItem(self.indexFromItem(self.bottom_item).row(), group)
|
||||
self._groups[key] = group
|
||||
return group
|
||||
|
||||
def __getattr__(self, key):
|
||||
return self.get_value(key)
|
||||
|
||||
|
@ -158,29 +74,15 @@ class EntryArea(QtWidgets.QTreeWidget):
|
|||
self.set_value(key, value)
|
||||
|
||||
def update_value(self, key):
|
||||
widgets = self._arg_to_widgets[key]
|
||||
argument = self._arguments[key]
|
||||
|
||||
# Qt needs a setItemWidget() to handle layout correctly,
|
||||
# simply replacing the entry inside the LayoutWidget
|
||||
# results in a bug.
|
||||
|
||||
widgets["entry"].deleteLater()
|
||||
widgets["entry"] = procdesc_to_entry(argument["desc"])(argument)
|
||||
widgets["fix_layout"].deleteLater()
|
||||
widgets["fix_layout"] = LayoutWidget()
|
||||
widgets["fix_layout"].addWidget(widgets["entry"])
|
||||
self.setItemWidget(widgets["widget_item"], 1, widgets["fix_layout"])
|
||||
self.updateGeometries()
|
||||
self.update_argument(key, argument)
|
||||
|
||||
def reset_value(self, key):
|
||||
procdesc = self._arguments[key]["desc"]
|
||||
self._arguments[key]["state"] = procdesc_to_entry(procdesc).default_state(procdesc)
|
||||
self.update_value(key)
|
||||
self.reset_entry(key)
|
||||
|
||||
def reset_all(self):
|
||||
for key in self._arguments.keys():
|
||||
self.reset_value(key)
|
||||
self.reset_entry(key)
|
||||
|
||||
|
||||
class AppletIPCServer(AsyncioParentComm):
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import logging
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from artiq.gui.tools import LayoutWidget, disable_scroll_wheel
|
||||
from artiq.gui.tools import LayoutWidget, disable_scroll_wheel, WheelFilter
|
||||
from artiq.gui.scanwidget import ScanWidget
|
||||
from artiq.gui.scientific_spinbox import ScientificSpinBox
|
||||
|
||||
|
@ -11,6 +12,158 @@ from artiq.gui.scientific_spinbox import ScientificSpinBox
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EntryTreeWidget(QtWidgets.QTreeWidget):
|
||||
def __init__(self):
|
||||
QtWidgets.QTreeWidget.__init__(self)
|
||||
self.setColumnCount(3)
|
||||
self.header().setStretchLastSection(False)
|
||||
if hasattr(self.header(), "setSectionResizeMode"):
|
||||
set_resize_mode = self.header().setSectionResizeMode
|
||||
else:
|
||||
set_resize_mode = self.header().setResizeMode
|
||||
set_resize_mode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
set_resize_mode(1, QtWidgets.QHeaderView.Stretch)
|
||||
set_resize_mode(2, QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.header().setVisible(False)
|
||||
self.setSelectionMode(self.NoSelection)
|
||||
self.setHorizontalScrollMode(self.ScrollPerPixel)
|
||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||
|
||||
self.setStyleSheet("QTreeWidget {background: " +
|
||||
self.palette().midlight().color().name() + " ;}")
|
||||
|
||||
self.viewport().installEventFilter(WheelFilter(self.viewport(), True))
|
||||
|
||||
self._groups = dict()
|
||||
self._arg_to_widgets = dict()
|
||||
self._arguments = dict()
|
||||
|
||||
self.gradient = QtGui.QLinearGradient(
|
||||
0, 0, 0, QtGui.QFontMetrics(self.font()).lineSpacing() * 2.5)
|
||||
self.gradient.setColorAt(0, self.palette().base().color())
|
||||
self.gradient.setColorAt(1, self.palette().midlight().color())
|
||||
|
||||
self.bottom_item = QtWidgets.QTreeWidgetItem()
|
||||
self.addTopLevelItem(self.bottom_item)
|
||||
self.bottom_item.setHidden(True)
|
||||
|
||||
def set_argument(self, key, argument):
|
||||
self._arguments[key] = argument
|
||||
widgets = dict()
|
||||
self._arg_to_widgets[key] = widgets
|
||||
entry_class = procdesc_to_entry(argument["desc"])
|
||||
argument["state"] = entry_class.default_state(argument["desc"])
|
||||
entry = entry_class(argument)
|
||||
widget_item = QtWidgets.QTreeWidgetItem([key])
|
||||
if argument["tooltip"]:
|
||||
widget_item.setToolTip(0, argument["tooltip"])
|
||||
widgets["entry"] = entry
|
||||
widgets["widget_item"] = widget_item
|
||||
|
||||
if len(self._arguments) > 1:
|
||||
self.bottom_item.setHidden(False)
|
||||
|
||||
for col in range(3):
|
||||
widget_item.setBackground(col, self.gradient)
|
||||
font = widget_item.font(0)
|
||||
font.setBold(True)
|
||||
widget_item.setFont(0, font)
|
||||
|
||||
if argument["group"] is None:
|
||||
self.insertTopLevelItem(self.indexFromItem(self.bottom_item).row(), widget_item)
|
||||
else:
|
||||
self._get_group(argument["group"]).addChild(widget_item)
|
||||
self.bottom_item.setHidden(False)
|
||||
fix_layout = LayoutWidget()
|
||||
widgets["fix_layout"] = fix_layout
|
||||
fix_layout.addWidget(entry)
|
||||
self.setItemWidget(widget_item, 1, fix_layout)
|
||||
|
||||
reset_entry = QtWidgets.QToolButton()
|
||||
reset_entry.setToolTip("Reset to default value")
|
||||
reset_entry.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_BrowserReload))
|
||||
reset_entry.clicked.connect(partial(self.reset_entry, key))
|
||||
|
||||
disable_other_scans = QtWidgets.QToolButton()
|
||||
widgets["disable_other_scans"] = disable_other_scans
|
||||
disable_other_scans.setIcon(
|
||||
QtWidgets.QApplication.style().standardIcon(
|
||||
QtWidgets.QStyle.SP_DialogResetButton))
|
||||
disable_other_scans.setToolTip("Disable other scans")
|
||||
disable_other_scans.clicked.connect(
|
||||
partial(self._disable_other_scans, key))
|
||||
if not isinstance(entry, ScanEntry):
|
||||
disable_other_scans.setVisible(False)
|
||||
|
||||
tool_buttons = LayoutWidget()
|
||||
tool_buttons.layout.setRowStretch(0, 1)
|
||||
tool_buttons.layout.setRowStretch(3, 1)
|
||||
tool_buttons.addWidget(reset_entry, 1)
|
||||
tool_buttons.addWidget(disable_other_scans, 2)
|
||||
self.setItemWidget(widget_item, 2, tool_buttons)
|
||||
|
||||
def _get_group(self, key):
|
||||
if key in self._groups:
|
||||
return self._groups[key]
|
||||
group = QtWidgets.QTreeWidgetItem([key])
|
||||
for col in range(3):
|
||||
group.setBackground(col, self.palette().mid())
|
||||
group.setForeground(col, self.palette().brightText())
|
||||
font = group.font(col)
|
||||
font.setBold(True)
|
||||
group.setFont(col, font)
|
||||
self.insertTopLevelItem(self.indexFromItem(self.bottom_item).row(), group)
|
||||
self._groups[key] = group
|
||||
return group
|
||||
|
||||
def _disable_other_scans(self, current_key):
|
||||
for key, widgets in self._arg_to_widgets.items():
|
||||
if (key != current_key and isinstance(widgets["entry"], ScanEntry)):
|
||||
widgets["entry"].disable()
|
||||
|
||||
def update_argument(self, key, argument):
|
||||
widgets = self._arg_to_widgets[key]
|
||||
|
||||
# Qt needs a setItemWidget() to handle layout correctly,
|
||||
# simply replacing the entry inside the LayoutWidget
|
||||
# results in a bug.
|
||||
|
||||
widgets["entry"].deleteLater()
|
||||
widgets["entry"] = procdesc_to_entry(argument["desc"])(argument)
|
||||
widgets["disable_other_scans"].setVisible(
|
||||
isinstance(widgets["entry"], ScanEntry))
|
||||
widgets["fix_layout"].deleteLater()
|
||||
widgets["fix_layout"] = LayoutWidget()
|
||||
widgets["fix_layout"].addWidget(widgets["entry"])
|
||||
self.setItemWidget(widgets["widget_item"], 1, widgets["fix_layout"])
|
||||
self.updateGeometries()
|
||||
|
||||
def reset_entry(self, key):
|
||||
procdesc = self._arguments[key]["desc"]
|
||||
self._arguments[key]["state"] = procdesc_to_entry(procdesc).default_state(procdesc)
|
||||
self.update_argument(key, self._arguments[key])
|
||||
|
||||
def save_state(self):
|
||||
expanded = []
|
||||
for k, v in self._groups.items():
|
||||
if v.isExpanded():
|
||||
expanded.append(k)
|
||||
return {
|
||||
"expanded": expanded,
|
||||
"scroll": self.verticalScrollBar().value()
|
||||
}
|
||||
|
||||
def restore_state(self, state):
|
||||
for e in state["expanded"]:
|
||||
try:
|
||||
self._groups[e].setExpanded(True)
|
||||
except KeyError:
|
||||
pass
|
||||
self.verticalScrollBar().setValue(state["scroll"])
|
||||
|
||||
|
||||
class StringEntry(QtWidgets.QLineEdit):
|
||||
def __init__(self, argument):
|
||||
QtWidgets.QLineEdit.__init__(self)
|
||||
|
|
|
@ -121,15 +121,19 @@ class DictSyncModel(QtCore.QAbstractTableModel):
|
|||
old_row = self.row_to_key.index(k)
|
||||
new_row = self._find_row(k, v)
|
||||
if old_row == new_row:
|
||||
self.backing_store[k] = v
|
||||
self.dataChanged.emit(self.index(old_row, 0),
|
||||
self.index(old_row, len(self.headers)-1))
|
||||
else:
|
||||
self.beginMoveRows(QtCore.QModelIndex(), old_row, old_row,
|
||||
QtCore.QModelIndex(), new_row)
|
||||
self.backing_store[k] = v
|
||||
self.row_to_key[old_row], self.row_to_key[new_row] = \
|
||||
self.row_to_key[new_row], self.row_to_key[old_row]
|
||||
if old_row != new_row:
|
||||
begin = min(old_row, new_row)
|
||||
end = max(old_row, new_row)
|
||||
self.beginMoveRows(QtCore.QModelIndex(), begin + 1, end - 1,
|
||||
QtCore.QModelIndex(), begin)
|
||||
self.backing_store[k] = v
|
||||
self.row_to_key.pop(old_row)
|
||||
if old_row < new_row:
|
||||
new_row -= 1
|
||||
self.row_to_key.insert(new_row, k)
|
||||
self.endMoveRows()
|
||||
else:
|
||||
row = self._find_row(k, v)
|
||||
|
|
Loading…
Reference in New Issue