forked from M-Labs/artiq
1
0
Fork 0

interactive_args: add InteractiveArgsDock

This commit is contained in:
Simon Renblad 2024-03-07 16:07:45 +08:00
parent 65a57e1f8c
commit d0d25addc0
1 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,151 @@
import logging
import asyncio
from PyQt5 import QtCore, QtWidgets, QtGui
from artiq.tools import elide
from artiq.gui.tools import LayoutWidget
from artiq.gui.models import DictSyncModel
from artiq.gui.applets import EntryArea
logger = logging.getLogger(__name__)
class Model(DictSyncModel):
def __init__(self, init):
DictSyncModel.__init__(self, ["RID", "Title", "Args"], init)
def convert(self, k, v, column):
if column == 0:
return k
elif column == 1:
txt = ":" + v["title"] if v["title"] != "" else ""
return str(k) + txt
elif column == 2:
return v["arglist_desc"]
else:
raise ValueError
def sort_key(self, k, v):
return k
class _InteractiveArgsRequest(QtWidgets.QWidget):
supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int)
def __init__(self, rid, title, arglist_desc):
QtWidgets.QWidget.__init__(self)
self.rid = rid
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
title_txt = title if title != "" else str(self.rid)
self.title_lbl = QtWidgets.QLabel(title_txt)
layout.addWidget(self.title_lbl, 0, 0, 1, 2)
self.entry_area = EntryArea()
layout.addWidget(self.entry_area, 1, 0, 1, 2)
for args in arglist_desc:
self.entry_area.setattr_argument_procdesc(*args)
self.cancel_btn = QtWidgets.QPushButton("Cancel")
self.cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogCancelButton))
self.cancel_btn.clicked.connect(self.cancel)
layout.addWidget(self.cancel_btn, 2, 0, 1, 1)
self.supply_btn = QtWidgets.QPushButton("Supply")
self.supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogOkButton))
self.supply_btn.clicked.connect(self.supply)
layout.addWidget(self.supply_btn, 2, 1, 1, 1)
def supply(self):
self.supplied.emit(self.rid, self.entry_area.get_values())
def cancel(self):
self.cancelled.emit(self.rid)
class _InteractiveArgsView(QtWidgets.QTabWidget):
supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int)
def __init__(self):
QtWidgets.QTabWidget.__init__(self)
self.model = Model({})
def setModel(self, model):
for i in range(self.count()):
widget = self.widget(i)
self.removeTab(i)
widget.deleteLater()
self.model = model
self.model.dataChanged.connect(self.dataChanged)
self.model.rowsInserted.connect(self.rowsInserted)
self.model.rowsMoved.connect(self.rowsMoved)
self.model.rowsRemoved.connect(self.rowsRemoved)
for i in range(self.model.rowCount(QtCore.QModelIndex())):
self._insert_widget(i)
def _insert_widget(self, row):
rid = self.model.data(self.model.index(row, 0), QtCore.Qt.DisplayRole)
title = self.model.data(self.model.index(row, 1), QtCore.Qt.DisplayRole)
arglist_desc = self.model.data(self.model.index(row, 2), QtCore.Qt.DisplayRole)
inter_args_request = _InteractiveArgsRequest(rid, title, arglist_desc)
inter_args_request.supplied.connect(self.supplied)
inter_args_request.cancelled.connect(self.cancelled)
self.insertTab(row, inter_args_request, title)
def dataChanged(self, top_left, bottom_right, roles):
row = top_left.row()
widget = self.widget(row)
self.removeTab(row)
self._insert_widget(row)
widget.deleteLater()
def rowsInserted(self, parent, first, last):
self._insert_widget(first)
def rowsMoved(self, src_parent, src_start, src_end, dest_parent, dest_end):
widget = self.widget(src_start)
self.insertTab(dest_end, widget)
def rowsRemoved(self, parent, first, last):
widget = self.widget(first)
self.removeTab(first)
widget.deleteLater()
class InteractiveArgsDock(QtWidgets.QDockWidget):
def __init__(self, interactive_args_sub, interactive_args_rpc):
QtWidgets.QDockWidget.__init__(self, "Interactive Args")
self.setObjectName("Interactive Args")
self.setFeatures(
QtWidgets.QDockWidget.DockWidgetMovable | QtWidgets.QDockWidget.DockWidgetFloatable)
self.interactive_args_rpc = interactive_args_rpc
layout = LayoutWidget(self)
self.setWidget(layout)
self.request_view = _InteractiveArgsView()
self.request_view.supplied.connect(self.supply)
self.request_view.cancelled.connect(self.cancel)
layout.addWidget(self.request_view, 0, 0)
interactive_args_sub.add_setmodel_callback(self.request_view.setModel)
def supply(self, rid, values):
asyncio.ensure_future(self._supply_task(rid, values))
async def _supply_task(self, rid, values):
try:
await self.interactive_args_rpc.supply(rid, values)
except:
logger.error("dashboard failed to supply interactive arguments for experiment: %d",
rid, exc_info=True)
def cancel(self, rid):
asyncio.ensure_future(self._cancel_task(rid))
async def _cancel_task(self, rid):
try:
await self.interactive_args_rpc.cancel(rid)
except:
logger.error("dashboard failed to cancel input request for experiment: %d",
rid, exc_info=True)