diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py
index 2d048a4bf..7113139a9 100644
--- a/artiq/dashboard/moninj.py
+++ b/artiq/dashboard/moninj.py
@@ -9,6 +9,7 @@ from PyQt5 import QtCore, QtWidgets
from artiq.coredevice.comm_moninj import CommMonInj, TTLOverride, TTLProbe
from artiq.coredevice.ad9912_reg import AD9912_SER_CONF
from artiq.gui.tools import LayoutWidget, QDockWidgetCloseDetect
+from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.flowlayout import FlowLayout
@@ -370,13 +371,12 @@ class _DACWidget(QtWidgets.QFrame):
self.setFrameShape(QtWidgets.QFrame.Box)
self.setFrameShadow(QtWidgets.QFrame.Raised)
- self.title = "{} ch{}".format(title, channel)
grid = QtWidgets.QGridLayout()
grid.setContentsMargins(0, 0, 0, 0)
grid.setHorizontalSpacing(0)
grid.setVerticalSpacing(0)
self.setLayout(grid)
- label = QtWidgets.QLabel(self.title)
+ label = QtWidgets.QLabel("{} ch{}".format(title, channel))
label.setAlignment(QtCore.Qt.AlignCenter)
grid.addWidget(label, 1, 1)
@@ -392,9 +392,6 @@ class _DACWidget(QtWidgets.QFrame):
self.value.setText("{:.3f} %"
.format(value))
- def to_model_path(self):
- return "dac/{}".format(self.title)
-
class _DACHandler:
def __init__(self, dm, spi_channel, channel, title):
@@ -419,6 +416,61 @@ class _DACHandler:
def sort_key(self):
return (2, self.spi_channel, self.channel)
+ def to_model_path(self):
+ return "dac/{} ch{}".format(self.title, self.channel)
+
+
+class Model(DictSyncTreeSepModel):
+ def __init__(self, init):
+ DictSyncTreeSepModel.__init__(self, "/", ["Channels"], init)
+
+ def clear(self):
+ for k in self.backing_store:
+ self._del_item(self, k.split(self.separator))
+ self.backing_store.clear()
+
+ def update(self, d):
+ for k, v in d.items():
+ self[v.to_model_path()] = v
+
+
+class _AddChannelDialog(QtWidgets.QDialog):
+ def __init__(self, parent, model):
+ QtWidgets.QDialog.__init__(self, parent=parent)
+ self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
+ self.setWindowTitle("Add channels")
+
+ layout = QtWidgets.QVBoxLayout()
+ self.setLayout(layout)
+
+ self._model = model
+ self._tree_view = QtWidgets.QTreeView()
+ self._tree_view.setHeaderHidden(True)
+ self._tree_view.setSelectionBehavior(
+ QtWidgets.QAbstractItemView.SelectItems)
+ self._tree_view.setSelectionMode(
+ QtWidgets.QAbstractItemView.ExtendedSelection)
+ self._tree_view.setModel(self._model)
+ layout.addWidget(self._tree_view)
+
+ self._button_box = QtWidgets.QDialogButtonBox(
+ QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
+ )
+ self._button_box.setCenterButtons(True)
+ self._button_box.accepted.connect(self.add_channels)
+ self._button_box.rejected.connect(self.reject)
+ layout.addWidget(self._button_box)
+
+ def add_channels(self):
+ selection = self._tree_view.selectedIndexes()
+ channels = []
+ for select in selection:
+ key = self._model.index_to_key(select)
+ if key is not None:
+ channels.append(self._model[key].ref)
+ self.channels = channels
+ self.accept()
+
_HandlerDesc = namedtuple("_HandlerDesc", "uid comment cls arguments")
@@ -799,28 +851,40 @@ class _MonInjDock(QDockWidgetCloseDetect):
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
QtWidgets.QDockWidget.DockWidgetFloatable)
self.name = name
+ self.manager = manager
grid = LayoutWidget()
+ self._channel_dialog = _AddChannelDialog(self, self.manager.channel_model)
+
+ self._channel_dialog.accepted.connect(self.add_channels)
+ add_channel_btn = QtWidgets.QToolButton()
+ add_channel_btn.setToolTip("Add channels...")
+ add_channel_btn.setIcon(
+ QtWidgets.QApplication.style().standardIcon(
+ QtWidgets.QStyle.SP_FileDialogListView))
+ add_channel_btn.clicked.connect(self._channel_dialog.open)
+ grid.addWidget(add_channel_btn, 0, 0)
newdock = QtWidgets.QToolButton()
newdock.setToolTip("Create new moninj dock")
newdock.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogNewFolder))
- # note the lambda, the default parameter is overriden otherwise
newdock.clicked.connect(lambda: manager.create_new_dock())
- grid.addWidget(newdock, 0, 0)
+ grid.addWidget(newdock, 0, 1)
self.setWidget(grid)
- self.scroll_area = QtWidgets.QScrollArea()
- grid.addWidget(self.scroll_area, 1, 0)
+ scroll_area = QtWidgets.QScrollArea()
+ grid.addWidget(scroll_area, 1, 0, 1, 10)
+ self.flow = FlowLayout()
+ grid_widget = QtWidgets.QWidget()
+ grid_widget.setLayout(self.flow)
+ scroll_area.setWidgetResizable(True)
+ scroll_area.setWidget(grid_widget)
+
+ def add_channels(self):
+ handlers = self._channel_dialog.channels
+ self.layout_widgets(handlers)
def layout_widgets(self, handlers):
- grid = FlowLayout()
- grid_widget = QtWidgets.QWidget()
- grid_widget.setLayout(grid)
-
for handler in sorted(handlers, key=lambda h: h.sort_key()):
- grid.addWidget(handler.widget)
-
- self.scroll_area.setWidgetResizable(True)
- self.scroll_area.setWidget(grid_widget)
+ self.flow.addWidget(handler.widget)
class MonInj:
@@ -829,10 +893,12 @@ class MonInj:
self.main_window = main_window
self.dm = _DeviceManager(schedule_ctl)
- self.dm.channels_cb = self.add_widgets
+ self.dm.channels_cb = self.add_channels
+ self.channel_model = Model({})
- def add_widgets(self):
- self.docks["moninj0"].layout_widgets(self.dm.handlers_by_uid.values())
+ def add_channels(self):
+ self.channel_model.clear()
+ self.channel_model.update(self.dm.handlers_by_uid)
def create_new_dock(self, add_to_area=True):
n = 0