diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index a7db9047b..a1bc2ec00 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -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 _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.