From daf49efa04cd0991ec5fb7b3d062e1dd9d90d835 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 14 Feb 2016 12:15:57 +0100 Subject: [PATCH] gui: rough conversion to the Qt docking system --- artiq/frontend/artiq_gui.py | 48 ++++++++++++-------------- artiq/gui/applets.py | 46 ++++++++++++------------- artiq/gui/datasets.py | 14 ++++---- artiq/gui/experiments.py | 68 ++++++++++++++++++++++--------------- artiq/gui/explorer.py | 25 ++++++++------ artiq/gui/log.py | 35 ++++++++++++------- artiq/gui/moninj.py | 11 +++--- artiq/gui/schedule.py | 11 +++--- artiq/gui/shortcuts.py | 31 ++++++++++------- 9 files changed, 159 insertions(+), 130 deletions(-) diff --git a/artiq/frontend/artiq_gui.py b/artiq/frontend/artiq_gui.py index 4de976196..1a882c45e 100755 --- a/artiq/frontend/artiq_gui.py +++ b/artiq/frontend/artiq_gui.py @@ -6,11 +6,8 @@ import atexit import os import PyQt5 -from quamash import QEventLoop, QtGui, QtCore +from quamash import QEventLoop, QtGui, QtCore, QtWidgets assert QtGui is PyQt5.QtGui -# pyqtgraph will pick up any already imported Qt binding. -from pyqtgraph import dockarea - from artiq import __artiq_dir__ as artiq_dir from artiq.tools import * @@ -88,33 +85,30 @@ def main(): sub_clients[notifier_name] = subscriber # initialize main window - win = MainWindow(args.server) - dock_area = dockarea.DockArea() - smgr.register(dock_area) - smgr.register(win) - win.setCentralWidget(dock_area) + main_window = MainWindow(args.server) + smgr.register(main_window) status_bar = QtGui.QStatusBar() status_bar.showMessage("Connected to {}".format(args.server)) - win.setStatusBar(status_bar) + main_window.setStatusBar(status_bar) # create UI components - expmgr = experiments.ExperimentManager(status_bar, dock_area, + expmgr = experiments.ExperimentManager(main_window, sub_clients["explist"], sub_clients["schedule"], rpc_clients["schedule"], rpc_clients["experiment_db"]) smgr.register(expmgr) - d_shortcuts = shortcuts.ShortcutsDock(win, expmgr) + d_shortcuts = shortcuts.ShortcutsDock(main_window, expmgr) smgr.register(d_shortcuts) d_explorer = explorer.ExplorerDock(status_bar, expmgr, d_shortcuts, sub_clients["explist"], rpc_clients["schedule"], rpc_clients["experiment_db"]) - d_datasets = datasets.DatasetsDock(win, sub_clients["datasets"], + d_datasets = datasets.DatasetsDock(sub_clients["datasets"], rpc_clients["dataset_db"]) - d_applets = applets.AppletsDock(dock_area, sub_clients["datasets"]) + d_applets = applets.AppletsDock(main_window, sub_clients["datasets"]) atexit_register_coroutine(d_applets.stop) smgr.register(d_applets) @@ -126,21 +120,21 @@ def main(): d_schedule = schedule.ScheduleDock( status_bar, rpc_clients["schedule"], sub_clients["schedule"]) - logmgr = log.LogDockManager(dock_area, sub_clients["log"]) + logmgr = log.LogDockManager(main_window, sub_clients["log"]) smgr.register(logmgr) # lay out docks if os.name != "nt": - dock_area.addDock(d_ttl_dds.dds_dock, "top") - dock_area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock) - dock_area.addDock(d_applets, "above", d_ttl_dds.ttl_dock) - dock_area.addDock(d_datasets, "above", d_applets) + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_ttl_dds.dds_dock) + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_ttl_dds.ttl_dock) + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_applets) + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_datasets) else: - dock_area.addDock(d_applets, "top") - dock_area.addDock(d_datasets, "above", d_applets) - dock_area.addDock(d_shortcuts, "above", d_datasets) - dock_area.addDock(d_explorer, "above", d_shortcuts) - dock_area.addDock(d_schedule, "bottom") + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_applets) + main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_datasets) + main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_shortcuts) + main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_explorer) + main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_schedule) # load/initialize state smgr.load() @@ -150,11 +144,11 @@ def main(): # create first log dock if not already in state d_log0 = logmgr.first_log_dock() if d_log0 is not None: - dock_area.addDock(d_log0, "right", d_explorer) + main_window.addDockWidget(QtCore.Qt.TopDockWidgetArea, d_log0) # run - win.show() - loop.run_until_complete(win.exit_request.wait()) + main_window.show() + loop.run_until_complete(main_window.exit_request.wait()) if __name__ == "__main__": main() diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index 811713f42..9507c87c3 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -5,7 +5,6 @@ import shlex from functools import partial from quamash import QtCore, QtGui, QtWidgets -from pyqtgraph import dockarea from artiq.protocols.pipe_ipc import AsyncioParentComm from artiq.protocols import pyon @@ -85,12 +84,13 @@ class AppletIPCServer(AsyncioParentComm): await asyncio.wait([self.server_task]) -class AppletDock(dockarea.Dock): +class AppletDock(QtWidgets.QDockWidget): + sigClosed = QtCore.pyqtSignal() + def __init__(self, datasets_sub, uid, name, command): - dockarea.Dock.__init__(self, "applet" + str(uid), - label="Applet: " + name, - closable=True) - self.setMinimumSize(QtCore.QSize(500, 400)) + QtWidgets.QDockWidget.__init__(self, "Applet: " + name) + self.setObjectName("applet" + str(uid)) + self.datasets_sub = datasets_sub self.applet_name = name self.command = command @@ -99,7 +99,7 @@ class AppletDock(dockarea.Dock): def rename(self, name): self.applet_name = name - self.label.setText("Applet: " + name) + self.setWindowTitle("Applet: " + name) async def start(self): if self.starting_stopping: @@ -127,7 +127,7 @@ class AppletDock(dockarea.Dock): self.embed_window = QtGui.QWindow.fromWinId(win_id) self.embed_widget = QtWidgets.QWidget.createWindowContainer( self.embed_window) - self.addWidget(self.embed_widget) + self.setWidget(self.embed_widget) # HACK: This function would not be needed if Qt window embedding # worked correctly. @@ -164,6 +164,10 @@ class AppletDock(dockarea.Dock): await self.terminate() await self.start() + def closeEvent(self, event): + QtWidgets.QDockWidget.closeEvent(self, event) + self.sigClosed.emit() + _templates = [ ("Big number", "{python} -m artiq.applets.big_number " @@ -181,16 +185,16 @@ _templates = [ ] -class AppletsDock(dockarea.Dock): - def __init__(self, dock_area, datasets_sub): - self.dock_area = dock_area +class AppletsDock(QtWidgets.QDockWidget): + def __init__(self, main_window, datasets_sub): + QtWidgets.QDockWidget.__init__(self, "Applets") + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) + + self.main_window = main_window self.datasets_sub = datasets_sub self.dock_to_checkbox = dict() self.applet_uids = set() - self.workaround_pyqtgraph_bug = False - - dockarea.Dock.__init__(self, "Applets") - self.setMinimumSize(QtCore.QSize(850, 450)) self.table = QtWidgets.QTableWidget(0, 3) self.table.setHorizontalHeaderLabels(["Enable", "Name", "Command"]) @@ -203,7 +207,7 @@ class AppletsDock(dockarea.Dock): QtGui.QHeaderView.ResizeToContents) self.table.verticalHeader().hide() self.table.setTextElideMode(QtCore.Qt.ElideNone) - self.addWidget(self.table) + self.setWidget(self.table) self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) new_action = QtGui.QAction("New applet", self.table) @@ -232,12 +236,8 @@ class AppletsDock(dockarea.Dock): def create(self, uid, name, command): dock = AppletDock(self.datasets_sub, uid, name, command) - # If a dock is floated and then dock state is restored, pyqtgraph - # leaves a "phantom" window open. - if self.workaround_pyqtgraph_bug: - self.dock_area.addDock(dock) - else: - self.dock_area.floatDock(dock) + self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) + dock.setFloating(True) asyncio.ensure_future(dock.start()) dock.sigClosed.connect(partial(self.on_dock_closed, dock)) return dock @@ -340,7 +340,6 @@ class AppletsDock(dockarea.Dock): return state def restore_state(self, state): - self.workaround_pyqtgraph_bug = True for uid, enabled, name, command in state: row = self.new(uid) item = QtWidgets.QTableWidgetItem() @@ -351,4 +350,3 @@ class AppletsDock(dockarea.Dock): self.table.setItem(row, 2, item) if enabled: self.table.item(row, 0).setCheckState(QtCore.Qt.Checked) - self.workaround_pyqtgraph_bug = False diff --git a/artiq/gui/datasets.py b/artiq/gui/datasets.py index ccb0c19f3..50f4e60b8 100644 --- a/artiq/gui/datasets.py +++ b/artiq/gui/datasets.py @@ -3,8 +3,7 @@ from collections import OrderedDict from functools import partial import logging -from quamash import QtGui, QtCore -from pyqtgraph import dockarea +from quamash import QtGui, QtCore, QtWidgets from pyqtgraph import LayoutWidget from artiq.tools import short_format @@ -29,14 +28,15 @@ class Model(DictSyncTreeSepModel): raise ValueError -class DatasetsDock(dockarea.Dock): - def __init__(self, dialog_parent, datasets_sub, dataset_ctl): - dockarea.Dock.__init__(self, "Datasets") - self.dialog_parent = dialog_parent +class DatasetsDock(QtWidgets.QDockWidget): + def __init__(self, datasets_sub, dataset_ctl): + QtWidgets.QDockWidget.__init__(self, "Datasets") + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) self.dataset_ctl = dataset_ctl grid = LayoutWidget() - self.addWidget(grid) + self.setWidget(grid) self.search = QtGui.QLineEdit() self.search.setPlaceholderText("search...") diff --git a/artiq/gui/experiments.py b/artiq/gui/experiments.py index 8b8b90590..5a964df1c 100644 --- a/artiq/gui/experiments.py +++ b/artiq/gui/experiments.py @@ -3,9 +3,9 @@ import asyncio from functools import partial from collections import OrderedDict -from quamash import QtGui, QtCore +from quamash import QtGui, QtCore, QtWidgets -from pyqtgraph import dockarea, LayoutWidget +from pyqtgraph import LayoutWidget from artiq.gui.tools import log_level_to_name from artiq.gui.entries import argty_to_entry @@ -133,10 +133,16 @@ class _ArgumentEditor(QtGui.QTreeWidget): pass -class _ExperimentDock(dockarea.Dock): +class _ExperimentDock(QtWidgets.QDockWidget): + sigClosed = QtCore.pyqtSignal() + def __init__(self, manager, expurl): - dockarea.Dock.__init__(self, "Exp: " + expurl, closable=True) - self.setMinimumSize(QtCore.QSize(740, 470)) + QtWidgets.QDockWidget.__init__(self, "Exp: " + expurl) + + self.layout = QtWidgets.QGridLayout() + top_widget = QtWidgets.QWidget() + top_widget.setLayout(self.layout) + self.setWidget(top_widget) self.layout.setSpacing(5) self.layout.setContentsMargins(5, 5, 5, 5) @@ -144,7 +150,7 @@ class _ExperimentDock(dockarea.Dock): self.expurl = expurl self.argeditor = _ArgumentEditor(self.manager, self, self.expurl) - self.addWidget(self.argeditor, 0, 0, colspan=5) + self.layout.addWidget(self.argeditor, 0, 0, 1, 5) self.layout.setRowStretch(0, 1) scheduling = manager.get_submission_scheduling(expurl) @@ -153,8 +159,8 @@ class _ExperimentDock(dockarea.Dock): datetime = QtGui.QDateTimeEdit() datetime.setDisplayFormat("MMM d yyyy hh:mm:ss") datetime_en = QtGui.QCheckBox("Due date:") - self.addWidget(datetime_en, 1, 0) - self.addWidget(datetime, 1, 1) + self.layout.addWidget(datetime_en, 1, 0) + self.layout.addWidget(datetime, 1, 1) if scheduling["due_date"] is None: datetime.setDate(QtCore.QDate.currentDate()) @@ -175,8 +181,8 @@ class _ExperimentDock(dockarea.Dock): datetime_en.stateChanged.connect(update_datetime_en) pipeline_name = QtGui.QLineEdit() - self.addWidget(QtGui.QLabel("Pipeline:"), 1, 2) - self.addWidget(pipeline_name, 1, 3) + self.layout.addWidget(QtGui.QLabel("Pipeline:"), 1, 2) + self.layout.addWidget(pipeline_name, 1, 3) pipeline_name.setText(scheduling["pipeline_name"]) def update_pipeline_name(text): @@ -185,8 +191,8 @@ class _ExperimentDock(dockarea.Dock): priority = QtGui.QSpinBox() priority.setRange(-99, 99) - self.addWidget(QtGui.QLabel("Priority:"), 2, 0) - self.addWidget(priority, 2, 1) + self.layout.addWidget(QtGui.QLabel("Priority:"), 2, 0) + self.layout.addWidget(priority, 2, 1) priority.setValue(scheduling["priority"]) def update_priority(value): @@ -195,7 +201,7 @@ class _ExperimentDock(dockarea.Dock): flush = QtGui.QCheckBox("Flush") flush.setToolTip("Flush the pipeline before starting the experiment") - self.addWidget(flush, 2, 2, colspan=2) + self.layout.addWidget(flush, 2, 2, 1, 2) flush.setChecked(scheduling["flush"]) def update_flush(checked): @@ -209,8 +215,8 @@ class _ExperimentDock(dockarea.Dock): log_level.setToolTip("Minimum level for log entry production") log_level_label = QtGui.QLabel("Logging level:") log_level_label.setToolTip("Minimum level for log message production") - self.addWidget(log_level_label, 3, 0) - self.addWidget(log_level, 3, 1) + self.layout.addWidget(log_level_label, 3, 0) + self.layout.addWidget(log_level, 3, 1) log_level.setCurrentIndex(log_levels.index( log_level_to_name(options["log_level"]))) @@ -224,8 +230,8 @@ class _ExperimentDock(dockarea.Dock): repo_rev_label = QtGui.QLabel("Revision:") repo_rev_label.setToolTip("Experiment repository revision " "(commit ID) to use") - self.addWidget(repo_rev_label, 3, 2) - self.addWidget(repo_rev, 3, 3) + self.layout.addWidget(repo_rev_label, 3, 2) + self.layout.addWidget(repo_rev, 3, 3) if options["repo_rev"] is not None: repo_rev.setText(options["repo_rev"]) @@ -243,7 +249,7 @@ class _ExperimentDock(dockarea.Dock): submit.setShortcut("CTRL+RETURN") submit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - self.addWidget(submit, 1, 4, rowspan=2) + self.layout.addWidget(submit, 1, 4, 2, 1) submit.clicked.connect(self.submit_clicked) reqterm = QtGui.QPushButton("Terminate instances") @@ -253,7 +259,7 @@ class _ExperimentDock(dockarea.Dock): reqterm.setShortcut("CTRL+BACKSPACE") reqterm.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - self.addWidget(reqterm, 3, 4) + self.layout.addWidget(reqterm, 3, 4) reqterm.clicked.connect(self.reqterm_clicked) def submit_clicked(self): @@ -287,7 +293,11 @@ class _ExperimentDock(dockarea.Dock): self.argeditor.deleteLater() self.argeditor = _ArgumentEditor(self.manager, self, self.expurl) - self.addWidget(self.argeditor, 0, 0, colspan=5) + self.layout.addWidget(self.argeditor, 0, 0, 1, 5) + + def closeEvent(self, event): + QtWidgets.QDockWidget.closeEvent(self, event) + self.sigClosed.emit() def save_state(self): return self.argeditor.save_state() @@ -297,11 +307,10 @@ class _ExperimentDock(dockarea.Dock): class ExperimentManager: - def __init__(self, status_bar, dock_area, + def __init__(self, main_window, explist_sub, schedule_sub, schedule_ctl, experiment_db_ctl): - self.status_bar = status_bar - self.dock_area = dock_area + self.main_window = main_window self.schedule_ctl = schedule_ctl self.experiment_db_ctl = experiment_db_ctl @@ -385,11 +394,12 @@ class ExperimentManager: def open_experiment(self, expurl): if expurl in self.open_experiments: dock = self.open_experiments[expurl] - self.dock_area.floatDock(dock) + dock.setFloating(True) return dock dock = _ExperimentDock(self, expurl) self.open_experiments[expurl] = dock - self.dock_area.floatDock(dock) + self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) + dock.setFloating(True) dock.sigClosed.connect(partial(self.on_dock_closed, expurl)) return dock @@ -398,7 +408,8 @@ class ExperimentManager: async def _submit_task(self, *args): rid = await self.schedule_ctl.submit(*args) - self.status_bar.showMessage("Submitted RID {}".format(rid)) + self.main_window.statusBar().showMessage( + "Submitted RID {}".format(rid)) def submit(self, expurl): file, class_name, _ = self.resolve_expurl(expurl) @@ -436,8 +447,9 @@ class ExperimentManager: rid, exc_info=True) def request_inst_term(self, expurl): - self.status_bar.showMessage("Requesting termination of all instances " - "of '{}'".format(expurl)) + self.main_window.statusBar().showMessage( + "Requesting termination of all instances " + "of '{}'".format(expurl)) file, class_name, use_repository = self.resolve_expurl(expurl) rids = [] for rid, desc in self.schedule.items(): diff --git a/artiq/gui/explorer.py b/artiq/gui/explorer.py index bdb456323..73ce6ce96 100644 --- a/artiq/gui/explorer.py +++ b/artiq/gui/explorer.py @@ -2,8 +2,7 @@ import asyncio import logging from functools import partial -from quamash import QtGui, QtCore -from pyqtgraph import dockarea +from quamash import QtGui, QtCore, QtWidgets from pyqtgraph import LayoutWidget from artiq.gui.models import DictSyncTreeSepModel @@ -116,13 +115,19 @@ class Model(DictSyncTreeSepModel): DictSyncTreeSepModel.__init__(self, "/", ["Experiment"], init) -class ExplorerDock(dockarea.Dock): +class ExplorerDock(QtWidgets.QDockWidget): def __init__(self, status_bar, exp_manager, d_shortcuts, explist_sub, schedule_ctl, experiment_db_ctl): - dockarea.Dock.__init__(self, "Explorer") - self.setMinimumSize(QtCore.QSize(300, 300)) - self.layout.setSpacing(5) - self.layout.setContentsMargins(5, 5, 5, 5) + QtWidgets.QDockWidget.__init__(self, "Explorer") + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) + + layout = QtWidgets.QGridLayout() + top_widget = QtWidgets.QWidget() + top_widget.setLayout(layout) + self.setWidget(top_widget) + layout.setSpacing(5) + layout.setContentsMargins(5, 5, 5, 5) self.status_bar = status_bar self.exp_manager = exp_manager @@ -132,7 +137,7 @@ class ExplorerDock(dockarea.Dock): self.el = QtGui.QTreeView() self.el.setHeaderHidden(True) self.el.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems) - self.addWidget(self.el, 0, 0, colspan=2) + layout.addWidget(self.el, 0, 0, 1, 2) self.el.doubleClicked.connect( partial(self.expname_action, "open_experiment")) @@ -140,7 +145,7 @@ class ExplorerDock(dockarea.Dock): open.setIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_DialogOpenButton)) open.setToolTip("Open the selected experiment (Return)") - self.addWidget(open, 1, 0) + layout.addWidget(open, 1, 0) open.clicked.connect( partial(self.expname_action, "open_experiment")) @@ -148,7 +153,7 @@ class ExplorerDock(dockarea.Dock): submit.setIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_DialogOkButton)) submit.setToolTip("Schedule the selected experiment (Ctrl+Return)") - self.addWidget(submit, 1, 1) + layout.addWidget(submit, 1, 1) submit.clicked.connect( partial(self.expname_action, "submit")) diff --git a/artiq/gui/log.py b/artiq/gui/log.py index afa981593..d853e0f1b 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -4,8 +4,8 @@ import time import re from functools import partial -from quamash import QtGui, QtCore -from pyqtgraph import dockarea, LayoutWidget +from quamash import QtGui, QtCore, QtWidgets +from pyqtgraph import LayoutWidget from artiq.gui.tools import log_level_to_name @@ -140,13 +140,15 @@ class _LogFilterProxyModel(QtCore.QSortFilterProxyModel): self.invalidateFilter() -class _LogDock(dockarea.Dock): +class _LogDock(QtWidgets.QDockWidget): + sigClosed = QtCore.pyqtSignal() + def __init__(self, manager, name, log_sub): - dockarea.Dock.__init__(self, name, label="Log") - self.setMinimumSize(QtCore.QSize(720, 250)) + QtWidgets.QDockWidget.__init__(self, "Log") + self.setObjectName(name) grid = LayoutWidget() - self.addWidget(grid) + self.setWidget(grid) grid.addWidget(QtGui.QLabel("Minimum level: "), 0, 0) self.filter_level = QtGui.QComboBox() @@ -252,6 +254,10 @@ class _LogDock(dockarea.Dock): self.table_model_filter.rowsInserted.connect(self.rows_inserted_after) self.table_model_filter.rowsRemoved.connect(self.rows_removed) + def closeEvent(self, event): + QtWidgets.QDockWidget.closeEvent(self, event) + self.sigClosed.emit() + def save_state(self): return { "min_level_idx": self.filter_level.currentIndex(), @@ -279,8 +285,8 @@ class _LogDock(dockarea.Dock): class LogDockManager: - def __init__(self, dock_area, log_sub): - self.dock_area = dock_area + def __init__(self, main_window, log_sub): + self.main_window = main_window self.log_sub = log_sub self.docks = dict() @@ -294,7 +300,8 @@ class LogDockManager: dock = _LogDock(self, name, self.log_sub) self.docks[name] = dock if add_to_area: - self.dock_area.floatDock(dock) + self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) + dock.setFloating(True) dock.sigClosed.connect(partial(self.on_dock_closed, name)) self.update_closable() return dock @@ -304,9 +311,12 @@ class LogDockManager: self.update_closable() def update_closable(self): - closable = len(self.docks) > 1 + flags = (QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) + if len(self.docks) > 1: + flags |= QtWidgets.QDockWidget.DockWidgetClosable for dock in self.docks.values(): - dock.setClosable(closable) + dock.setFeatures(flags) def save_state(self): return {name: dock.save_state() for name, dock in self.docks.items()} @@ -317,8 +327,9 @@ class LogDockManager: for name, dock_state in state.items(): dock = _LogDock(self, name, self.log_sub) dock.restore_state(dock_state) - self.dock_area.addDock(dock) + self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) self.docks[name] = dock + self.update_closable() def first_log_dock(self): if self.docks: diff --git a/artiq/gui/moninj.py b/artiq/gui/moninj.py index 8982fa297..755ceecad 100644 --- a/artiq/gui/moninj.py +++ b/artiq/gui/moninj.py @@ -4,8 +4,7 @@ import socket import struct from operator import itemgetter -from quamash import QtGui, QtCore -from pyqtgraph import dockarea +from quamash import QtGui, QtCore, QtWidgets from artiq.tools import TaskObject from artiq.protocols.sync_struct import Subscriber @@ -213,14 +212,16 @@ class _DeviceManager: return None -class _MonInjDock(dockarea.Dock): +class _MonInjDock(QtWidgets.QDockWidget): def __init__(self, name): - dockarea.Dock.__init__(self, name) + QtWidgets.QDockWidget.__init__(self, name) + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) self.grid = QtGui.QGridLayout() gridw = QtGui.QWidget() gridw.setLayout(self.grid) - self.addWidget(gridw) + self.setWidget(gridw) def layout_widgets(self, widgets): w = self.grid.itemAt(0) diff --git a/artiq/gui/schedule.py b/artiq/gui/schedule.py index 1bac023c8..4265c5ea7 100644 --- a/artiq/gui/schedule.py +++ b/artiq/gui/schedule.py @@ -2,7 +2,7 @@ import asyncio import time from functools import partial -from quamash import QtGui, QtCore +from quamash import QtGui, QtCore, QtWidgets from pyqtgraph import dockarea from artiq.gui.models import DictSyncModel @@ -55,10 +55,11 @@ class Model(DictSyncModel): raise ValueError -class ScheduleDock(dockarea.Dock): +class ScheduleDock(QtWidgets.QDockWidget): def __init__(self, status_bar, schedule_ctl, schedule_sub): - dockarea.Dock.__init__(self, "Schedule") - self.setMinimumSize(QtCore.QSize(740, 200)) + QtWidgets.QDockWidget.__init__(self, "Schedule") + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) self.status_bar = status_bar self.schedule_ctl = schedule_ctl @@ -71,7 +72,7 @@ class ScheduleDock(dockarea.Dock): self.table.verticalHeader().setResizeMode( QtGui.QHeaderView.ResizeToContents) self.table.verticalHeader().hide() - self.addWidget(self.table) + self.setWidget(self.table) self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) request_termination_action = QtGui.QAction("Request termination", self.table) diff --git a/artiq/gui/shortcuts.py b/artiq/gui/shortcuts.py index db05bfa2b..7ffec34db 100644 --- a/artiq/gui/shortcuts.py +++ b/artiq/gui/shortcuts.py @@ -2,53 +2,60 @@ import logging from functools import partial from quamash import QtGui, QtCore, QtWidgets -from pyqtgraph import dockarea +from pyqtgraph import LayoutWidget logger = logging.getLogger(__name__) -class ShortcutsDock(dockarea.Dock): +class ShortcutsDock(QtWidgets.QDockWidget): def __init__(self, main_window, exp_manager): - dockarea.Dock.__init__(self, "Shortcuts") - self.layout.setSpacing(5) - self.layout.setContentsMargins(5, 5, 5, 5) + QtWidgets.QDockWidget.__init__(self, "Shortcuts") + self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | + QtWidgets.QDockWidget.DockWidgetFloatable) + + layout = QtWidgets.QGridLayout() + top_widget = QtWidgets.QWidget() + top_widget.setLayout(layout) + self.setWidget(top_widget) + layout.setSpacing(5) + layout.setContentsMargins(5, 5, 5, 5) self.exp_manager = exp_manager self.shortcut_widgets = dict() for n, title in enumerate(["Key", "Experiment"]): label = QtGui.QLabel("" + title + "") - self.addWidget(label, 0, n) + layout.addWidget(label, 0, n) label.setMaximumHeight(label.sizeHint().height()) - self.layout.setColumnStretch(1, 1) + layout.setColumnStretch(1, 1) for i in range(12): row = i + 1 - self.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0) + layout.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0) label = QtGui.QLabel() label.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored) - self.addWidget(label, row, 1) + layout.addWidget(label, row, 1) clear = QtGui.QToolButton() clear.setIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_DialogResetButton)) - self.addWidget(clear, row, 2) + layout.addWidget(clear, row, 2) clear.clicked.connect(partial(self.set_shortcut, i, "")) open = QtGui.QToolButton() open.setIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_DialogOpenButton)) - self.addWidget(open, row, 3) + layout.addWidget(open, row, 3) open.clicked.connect(partial(self._open_experiment, i)) submit = QtGui.QPushButton("Submit") submit.setIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_DialogOkButton)) - self.addWidget(submit, row, 4) + layout.addWidget(submit, row, 4) submit.clicked.connect(partial(self._activated, i)) clear.hide()