diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 363314a9e..d49223670 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -11,6 +11,8 @@ from sipyco.pc_rpc import AsyncioClient as RPCClient from sipyco import pyon from sipyco.pipe_ipc import AsyncioChildComm +from artiq.language.scan import ScanObject + logger = logging.getLogger(__name__) @@ -37,6 +39,11 @@ class AppletControlIPC: mod = {"action": "append", "path": [key, 1], "x": value} self.ipc.update_dataset(mod) + def set_argument_value(self, expurl, name, value): + if isinstance(value, ScanObject): + value = value.describe() + self.ipc.set_argument_value(expurl, name, value) + class AppletControlRPC: def __init__(self, loop, dataset_ctl): @@ -67,6 +74,8 @@ class AppletControlRPC: mod = {"action": "append", "path": [key, 1], "x": value} self._background(self.dataset_ctl.update, mod) + def set_argument_value(self, expurl, name, value): + raise NotImplementedError class AppletIPCClient(AsyncioChildComm): def set_close_cb(self, close_cb): @@ -137,6 +146,12 @@ class AppletIPCClient(AsyncioChildComm): self.write_pyon({"action": "update_dataset", "mod": mod}) + def set_argument_value(self, expurl, name, value): + self.write_pyon({"action": "set_argument_value", + "expurl": expurl, + "name": name, + "value": value}) + class SimpleApplet: def __init__(self, main_widget_class, cmd_description=None, diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index 8a0da9fd0..254dd05ab 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -159,6 +159,23 @@ class _ArgumentEditor(QtWidgets.QTreeWidget): 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)) @@ -175,22 +192,7 @@ class _ArgumentEditor(QtWidgets.QTreeWidget): state = procdesc_to_entry(procdesc).default_state(procdesc) argument["desc"] = procdesc argument["state"] = state - - # Qt needs a setItemWidget() to handle layout correctly, - # simply replacing the entry inside the LayoutWidget - # results in a bug. - - widgets = self._arg_to_widgets[name] - - widgets["entry"].deleteLater() - widgets["entry"] = procdesc_to_entry(procdesc)(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() + self.update_argument(name, argument) def _disable_other_scans(self, current_name): for name, widgets in self._arg_to_widgets.items(): @@ -664,6 +666,20 @@ class ExperimentManager: self.submission_arguments[expurl] = arguments self.argument_ui_names[expurl] = ui_name return arguments + + def set_argument_value(self, expurl, name, value): + try: + argument = self.submission_arguments[expurl][name] + if argument["desc"]["ty"] == "Scannable": + ty = value["ty"] + argument["state"]["selected"] = ty + argument["state"][ty] = value + else: + argument["state"] = value + if expurl in self.open_experiments.keys(): + self.open_experiments[expurl].argeditor.update_argument(name, argument) + except: + logger.warn("Failed to set value for argument \"{}\" in experiment: {}.".format(name, expurl), exc_info=1) def get_submission_arguments(self, expurl): if expurl in self.submission_arguments: diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 251c2beb3..8bcf9546c 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -192,6 +192,7 @@ def main(): d_applets = applets_ccb.AppletsCCBDock(main_window, sub_clients["datasets"], rpc_clients["dataset_db"], + expmgr, extra_substitutes={ "server": args.server, "port_notify": args.port_notify, diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index 4b3d2b98b..ac1db098d 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -21,10 +21,11 @@ logger = logging.getLogger(__name__) class AppletIPCServer(AsyncioParentComm): - def __init__(self, dataset_sub, dataset_ctl): + def __init__(self, dataset_sub, dataset_ctl, expmgr): AsyncioParentComm.__init__(self) self.dataset_sub = dataset_sub self.dataset_ctl = dataset_ctl + self.expmgr = expmgr self.datasets = set() self.dataset_prefixes = [] @@ -83,6 +84,8 @@ class AppletIPCServer(AsyncioParentComm): await self.dataset_ctl.set(obj["key"], obj["value"], metadata=obj["metadata"], persist=obj["persist"]) elif action == "update_dataset": await self.dataset_ctl.update(obj["mod"]) + elif action == "set_argument_value": + self.expmgr.set_argument_value(obj["expurl"], obj["name"], obj["value"]) else: raise ValueError("unknown action in applet message") except: @@ -108,7 +111,7 @@ class AppletIPCServer(AsyncioParentComm): class _AppletDock(QDockWidgetCloseDetect): - def __init__(self, dataset_sub, dataset_ctl, uid, name, spec, extra_substitutes): + def __init__(self, dataset_sub, dataset_ctl, expmgr, uid, name, spec, extra_substitutes): QDockWidgetCloseDetect.__init__(self, "Applet: " + name) self.setObjectName("applet" + str(uid)) @@ -118,6 +121,7 @@ class _AppletDock(QDockWidgetCloseDetect): self.dataset_sub = dataset_sub self.dataset_ctl = dataset_ctl + self.expmgr = expmgr self.applet_name = name self.spec = spec self.extra_substitutes = extra_substitutes @@ -136,7 +140,7 @@ class _AppletDock(QDockWidgetCloseDetect): return self.starting_stopping = True try: - self.ipc = AppletIPCServer(self.dataset_sub, self.dataset_ctl) + self.ipc = AppletIPCServer(self.dataset_sub, self.dataset_ctl, self.expmgr) env = os.environ.copy() env["PYTHONUNBUFFERED"] = "1" env["ARTIQ_APPLET_EMBED"] = self.ipc.get_address() @@ -333,7 +337,7 @@ class _CompleterDelegate(QtWidgets.QStyledItemDelegate): class AppletsDock(QtWidgets.QDockWidget): - def __init__(self, main_window, dataset_sub, dataset_ctl, extra_substitutes={}, *, loop=None): + def __init__(self, main_window, dataset_sub, dataset_ctl, expmgr, extra_substitutes={}, *, loop=None): """ :param extra_substitutes: Map of extra ``${strings}`` to substitute in applet commands to their respective values. @@ -346,6 +350,7 @@ class AppletsDock(QtWidgets.QDockWidget): self.main_window = main_window self.dataset_sub = dataset_sub self.dataset_ctl = dataset_ctl + self.expmgr = expmgr self.extra_substitutes = extra_substitutes self.applet_uids = set() @@ -448,7 +453,7 @@ class AppletsDock(QtWidgets.QDockWidget): self.table.itemChanged.connect(self.item_changed) def create(self, item, name, spec): - dock = _AppletDock(self.dataset_sub, self.dataset_ctl, item.applet_uid, name, spec, self.extra_substitutes) + dock = _AppletDock(self.dataset_sub, self.dataset_ctl, self.expmgr, item.applet_uid, name, spec, self.extra_substitutes) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) dock.setFloating(True) asyncio.ensure_future(dock.start(), loop=self._loop)