Skip to content

Commit daf49ef

Browse files
committedFeb 14, 2016
gui: rough conversion to the Qt docking system
1 parent ed36a96 commit daf49ef

File tree

9 files changed

+159
-130
lines changed

9 files changed

+159
-130
lines changed
 

‎artiq/frontend/artiq_gui.py

+21-27
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
import os
77

88
import PyQt5
9-
from quamash import QEventLoop, QtGui, QtCore
9+
from quamash import QEventLoop, QtGui, QtCore, QtWidgets
1010
assert QtGui is PyQt5.QtGui
11-
# pyqtgraph will pick up any already imported Qt binding.
12-
from pyqtgraph import dockarea
13-
1411

1512
from artiq import __artiq_dir__ as artiq_dir
1613
from artiq.tools import *
@@ -88,33 +85,30 @@ def main():
8885
sub_clients[notifier_name] = subscriber
8986

9087
# initialize main window
91-
win = MainWindow(args.server)
92-
dock_area = dockarea.DockArea()
93-
smgr.register(dock_area)
94-
smgr.register(win)
95-
win.setCentralWidget(dock_area)
88+
main_window = MainWindow(args.server)
89+
smgr.register(main_window)
9690
status_bar = QtGui.QStatusBar()
9791
status_bar.showMessage("Connected to {}".format(args.server))
98-
win.setStatusBar(status_bar)
92+
main_window.setStatusBar(status_bar)
9993

10094
# create UI components
101-
expmgr = experiments.ExperimentManager(status_bar, dock_area,
95+
expmgr = experiments.ExperimentManager(main_window,
10296
sub_clients["explist"],
10397
sub_clients["schedule"],
10498
rpc_clients["schedule"],
10599
rpc_clients["experiment_db"])
106100
smgr.register(expmgr)
107-
d_shortcuts = shortcuts.ShortcutsDock(win, expmgr)
101+
d_shortcuts = shortcuts.ShortcutsDock(main_window, expmgr)
108102
smgr.register(d_shortcuts)
109103
d_explorer = explorer.ExplorerDock(status_bar, expmgr, d_shortcuts,
110104
sub_clients["explist"],
111105
rpc_clients["schedule"],
112106
rpc_clients["experiment_db"])
113107

114-
d_datasets = datasets.DatasetsDock(win, sub_clients["datasets"],
108+
d_datasets = datasets.DatasetsDock(sub_clients["datasets"],
115109
rpc_clients["dataset_db"])
116110

117-
d_applets = applets.AppletsDock(dock_area, sub_clients["datasets"])
111+
d_applets = applets.AppletsDock(main_window, sub_clients["datasets"])
118112
atexit_register_coroutine(d_applets.stop)
119113
smgr.register(d_applets)
120114

@@ -126,21 +120,21 @@ def main():
126120
d_schedule = schedule.ScheduleDock(
127121
status_bar, rpc_clients["schedule"], sub_clients["schedule"])
128122

129-
logmgr = log.LogDockManager(dock_area, sub_clients["log"])
123+
logmgr = log.LogDockManager(main_window, sub_clients["log"])
130124
smgr.register(logmgr)
131125

132126
# lay out docks
133127
if os.name != "nt":
134-
dock_area.addDock(d_ttl_dds.dds_dock, "top")
135-
dock_area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
136-
dock_area.addDock(d_applets, "above", d_ttl_dds.ttl_dock)
137-
dock_area.addDock(d_datasets, "above", d_applets)
128+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_ttl_dds.dds_dock)
129+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_ttl_dds.ttl_dock)
130+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_applets)
131+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_datasets)
138132
else:
139-
dock_area.addDock(d_applets, "top")
140-
dock_area.addDock(d_datasets, "above", d_applets)
141-
dock_area.addDock(d_shortcuts, "above", d_datasets)
142-
dock_area.addDock(d_explorer, "above", d_shortcuts)
143-
dock_area.addDock(d_schedule, "bottom")
133+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_applets)
134+
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_datasets)
135+
main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_shortcuts)
136+
main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_explorer)
137+
main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_schedule)
144138

145139
# load/initialize state
146140
smgr.load()
@@ -150,11 +144,11 @@ def main():
150144
# create first log dock if not already in state
151145
d_log0 = logmgr.first_log_dock()
152146
if d_log0 is not None:
153-
dock_area.addDock(d_log0, "right", d_explorer)
147+
main_window.addDockWidget(QtCore.Qt.TopDockWidgetArea, d_log0)
154148

155149
# run
156-
win.show()
157-
loop.run_until_complete(win.exit_request.wait())
150+
main_window.show()
151+
loop.run_until_complete(main_window.exit_request.wait())
158152

159153
if __name__ == "__main__":
160154
main()

‎artiq/gui/applets.py

+22-24
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from functools import partial
66

77
from quamash import QtCore, QtGui, QtWidgets
8-
from pyqtgraph import dockarea
98

109
from artiq.protocols.pipe_ipc import AsyncioParentComm
1110
from artiq.protocols import pyon
@@ -85,12 +84,13 @@ async def stop(self):
8584
await asyncio.wait([self.server_task])
8685

8786

88-
class AppletDock(dockarea.Dock):
87+
class AppletDock(QtWidgets.QDockWidget):
88+
sigClosed = QtCore.pyqtSignal()
89+
8990
def __init__(self, datasets_sub, uid, name, command):
90-
dockarea.Dock.__init__(self, "applet" + str(uid),
91-
label="Applet: " + name,
92-
closable=True)
93-
self.setMinimumSize(QtCore.QSize(500, 400))
91+
QtWidgets.QDockWidget.__init__(self, "Applet: " + name)
92+
self.setObjectName("applet" + str(uid))
93+
9494
self.datasets_sub = datasets_sub
9595
self.applet_name = name
9696
self.command = command
@@ -99,7 +99,7 @@ def __init__(self, datasets_sub, uid, name, command):
9999

100100
def rename(self, name):
101101
self.applet_name = name
102-
self.label.setText("Applet: " + name)
102+
self.setWindowTitle("Applet: " + name)
103103

104104
async def start(self):
105105
if self.starting_stopping:
@@ -127,7 +127,7 @@ def embed(self, win_id):
127127
self.embed_window = QtGui.QWindow.fromWinId(win_id)
128128
self.embed_widget = QtWidgets.QWidget.createWindowContainer(
129129
self.embed_window)
130-
self.addWidget(self.embed_widget)
130+
self.setWidget(self.embed_widget)
131131

132132
# HACK: This function would not be needed if Qt window embedding
133133
# worked correctly.
@@ -164,6 +164,10 @@ async def restart(self):
164164
await self.terminate()
165165
await self.start()
166166

167+
def closeEvent(self, event):
168+
QtWidgets.QDockWidget.closeEvent(self, event)
169+
self.sigClosed.emit()
170+
167171

168172
_templates = [
169173
("Big number", "{python} -m artiq.applets.big_number "
@@ -181,16 +185,16 @@ async def restart(self):
181185
]
182186

183187

184-
class AppletsDock(dockarea.Dock):
185-
def __init__(self, dock_area, datasets_sub):
186-
self.dock_area = dock_area
188+
class AppletsDock(QtWidgets.QDockWidget):
189+
def __init__(self, main_window, datasets_sub):
190+
QtWidgets.QDockWidget.__init__(self, "Applets")
191+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
192+
QtWidgets.QDockWidget.DockWidgetFloatable)
193+
194+
self.main_window = main_window
187195
self.datasets_sub = datasets_sub
188196
self.dock_to_checkbox = dict()
189197
self.applet_uids = set()
190-
self.workaround_pyqtgraph_bug = False
191-
192-
dockarea.Dock.__init__(self, "Applets")
193-
self.setMinimumSize(QtCore.QSize(850, 450))
194198

195199
self.table = QtWidgets.QTableWidget(0, 3)
196200
self.table.setHorizontalHeaderLabels(["Enable", "Name", "Command"])
@@ -203,7 +207,7 @@ def __init__(self, dock_area, datasets_sub):
203207
QtGui.QHeaderView.ResizeToContents)
204208
self.table.verticalHeader().hide()
205209
self.table.setTextElideMode(QtCore.Qt.ElideNone)
206-
self.addWidget(self.table)
210+
self.setWidget(self.table)
207211

208212
self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
209213
new_action = QtGui.QAction("New applet", self.table)
@@ -232,12 +236,8 @@ def __init__(self, dock_area, datasets_sub):
232236

233237
def create(self, uid, name, command):
234238
dock = AppletDock(self.datasets_sub, uid, name, command)
235-
# If a dock is floated and then dock state is restored, pyqtgraph
236-
# leaves a "phantom" window open.
237-
if self.workaround_pyqtgraph_bug:
238-
self.dock_area.addDock(dock)
239-
else:
240-
self.dock_area.floatDock(dock)
239+
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
240+
dock.setFloating(True)
241241
asyncio.ensure_future(dock.start())
242242
dock.sigClosed.connect(partial(self.on_dock_closed, dock))
243243
return dock
@@ -340,7 +340,6 @@ def save_state(self):
340340
return state
341341

342342
def restore_state(self, state):
343-
self.workaround_pyqtgraph_bug = True
344343
for uid, enabled, name, command in state:
345344
row = self.new(uid)
346345
item = QtWidgets.QTableWidgetItem()
@@ -351,4 +350,3 @@ def restore_state(self, state):
351350
self.table.setItem(row, 2, item)
352351
if enabled:
353352
self.table.item(row, 0).setCheckState(QtCore.Qt.Checked)
354-
self.workaround_pyqtgraph_bug = False

‎artiq/gui/datasets.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
from functools import partial
44
import logging
55

6-
from quamash import QtGui, QtCore
7-
from pyqtgraph import dockarea
6+
from quamash import QtGui, QtCore, QtWidgets
87
from pyqtgraph import LayoutWidget
98

109
from artiq.tools import short_format
@@ -29,14 +28,15 @@ def convert(self, k, v, column):
2928
raise ValueError
3029

3130

32-
class DatasetsDock(dockarea.Dock):
33-
def __init__(self, dialog_parent, datasets_sub, dataset_ctl):
34-
dockarea.Dock.__init__(self, "Datasets")
35-
self.dialog_parent = dialog_parent
31+
class DatasetsDock(QtWidgets.QDockWidget):
32+
def __init__(self, datasets_sub, dataset_ctl):
33+
QtWidgets.QDockWidget.__init__(self, "Datasets")
34+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
35+
QtWidgets.QDockWidget.DockWidgetFloatable)
3636
self.dataset_ctl = dataset_ctl
3737

3838
grid = LayoutWidget()
39-
self.addWidget(grid)
39+
self.setWidget(grid)
4040

4141
self.search = QtGui.QLineEdit()
4242
self.search.setPlaceholderText("search...")

‎artiq/gui/experiments.py

+40-28
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from functools import partial
44
from collections import OrderedDict
55

6-
from quamash import QtGui, QtCore
6+
from quamash import QtGui, QtCore, QtWidgets
77

8-
from pyqtgraph import dockarea, LayoutWidget
8+
from pyqtgraph import LayoutWidget
99

1010
from artiq.gui.tools import log_level_to_name
1111
from artiq.gui.entries import argty_to_entry
@@ -133,18 +133,24 @@ def restore_state(self, state):
133133
pass
134134

135135

136-
class _ExperimentDock(dockarea.Dock):
136+
class _ExperimentDock(QtWidgets.QDockWidget):
137+
sigClosed = QtCore.pyqtSignal()
138+
137139
def __init__(self, manager, expurl):
138-
dockarea.Dock.__init__(self, "Exp: " + expurl, closable=True)
139-
self.setMinimumSize(QtCore.QSize(740, 470))
140+
QtWidgets.QDockWidget.__init__(self, "Exp: " + expurl)
141+
142+
self.layout = QtWidgets.QGridLayout()
143+
top_widget = QtWidgets.QWidget()
144+
top_widget.setLayout(self.layout)
145+
self.setWidget(top_widget)
140146
self.layout.setSpacing(5)
141147
self.layout.setContentsMargins(5, 5, 5, 5)
142148

143149
self.manager = manager
144150
self.expurl = expurl
145151

146152
self.argeditor = _ArgumentEditor(self.manager, self, self.expurl)
147-
self.addWidget(self.argeditor, 0, 0, colspan=5)
153+
self.layout.addWidget(self.argeditor, 0, 0, 1, 5)
148154
self.layout.setRowStretch(0, 1)
149155

150156
scheduling = manager.get_submission_scheduling(expurl)
@@ -153,8 +159,8 @@ def __init__(self, manager, expurl):
153159
datetime = QtGui.QDateTimeEdit()
154160
datetime.setDisplayFormat("MMM d yyyy hh:mm:ss")
155161
datetime_en = QtGui.QCheckBox("Due date:")
156-
self.addWidget(datetime_en, 1, 0)
157-
self.addWidget(datetime, 1, 1)
162+
self.layout.addWidget(datetime_en, 1, 0)
163+
self.layout.addWidget(datetime, 1, 1)
158164

159165
if scheduling["due_date"] is None:
160166
datetime.setDate(QtCore.QDate.currentDate())
@@ -175,8 +181,8 @@ def update_datetime_en(checked):
175181
datetime_en.stateChanged.connect(update_datetime_en)
176182

177183
pipeline_name = QtGui.QLineEdit()
178-
self.addWidget(QtGui.QLabel("Pipeline:"), 1, 2)
179-
self.addWidget(pipeline_name, 1, 3)
184+
self.layout.addWidget(QtGui.QLabel("Pipeline:"), 1, 2)
185+
self.layout.addWidget(pipeline_name, 1, 3)
180186

181187
pipeline_name.setText(scheduling["pipeline_name"])
182188
def update_pipeline_name(text):
@@ -185,8 +191,8 @@ def update_pipeline_name(text):
185191

186192
priority = QtGui.QSpinBox()
187193
priority.setRange(-99, 99)
188-
self.addWidget(QtGui.QLabel("Priority:"), 2, 0)
189-
self.addWidget(priority, 2, 1)
194+
self.layout.addWidget(QtGui.QLabel("Priority:"), 2, 0)
195+
self.layout.addWidget(priority, 2, 1)
190196

191197
priority.setValue(scheduling["priority"])
192198
def update_priority(value):
@@ -195,7 +201,7 @@ def update_priority(value):
195201

196202
flush = QtGui.QCheckBox("Flush")
197203
flush.setToolTip("Flush the pipeline before starting the experiment")
198-
self.addWidget(flush, 2, 2, colspan=2)
204+
self.layout.addWidget(flush, 2, 2, 1, 2)
199205

200206
flush.setChecked(scheduling["flush"])
201207
def update_flush(checked):
@@ -209,8 +215,8 @@ def update_flush(checked):
209215
log_level.setToolTip("Minimum level for log entry production")
210216
log_level_label = QtGui.QLabel("Logging level:")
211217
log_level_label.setToolTip("Minimum level for log message production")
212-
self.addWidget(log_level_label, 3, 0)
213-
self.addWidget(log_level, 3, 1)
218+
self.layout.addWidget(log_level_label, 3, 0)
219+
self.layout.addWidget(log_level, 3, 1)
214220

215221
log_level.setCurrentIndex(log_levels.index(
216222
log_level_to_name(options["log_level"])))
@@ -224,8 +230,8 @@ def update_log_level(index):
224230
repo_rev_label = QtGui.QLabel("Revision:")
225231
repo_rev_label.setToolTip("Experiment repository revision "
226232
"(commit ID) to use")
227-
self.addWidget(repo_rev_label, 3, 2)
228-
self.addWidget(repo_rev, 3, 3)
233+
self.layout.addWidget(repo_rev_label, 3, 2)
234+
self.layout.addWidget(repo_rev, 3, 3)
229235

230236
if options["repo_rev"] is not None:
231237
repo_rev.setText(options["repo_rev"])
@@ -243,7 +249,7 @@ def update_repo_rev(text):
243249
submit.setShortcut("CTRL+RETURN")
244250
submit.setSizePolicy(QtGui.QSizePolicy.Expanding,
245251
QtGui.QSizePolicy.Expanding)
246-
self.addWidget(submit, 1, 4, rowspan=2)
252+
self.layout.addWidget(submit, 1, 4, 2, 1)
247253
submit.clicked.connect(self.submit_clicked)
248254

249255
reqterm = QtGui.QPushButton("Terminate instances")
@@ -253,7 +259,7 @@ def update_repo_rev(text):
253259
reqterm.setShortcut("CTRL+BACKSPACE")
254260
reqterm.setSizePolicy(QtGui.QSizePolicy.Expanding,
255261
QtGui.QSizePolicy.Expanding)
256-
self.addWidget(reqterm, 3, 4)
262+
self.layout.addWidget(reqterm, 3, 4)
257263
reqterm.clicked.connect(self.reqterm_clicked)
258264

259265
def submit_clicked(self):
@@ -287,7 +293,11 @@ async def _recompute_arguments_task(self):
287293

288294
self.argeditor.deleteLater()
289295
self.argeditor = _ArgumentEditor(self.manager, self, self.expurl)
290-
self.addWidget(self.argeditor, 0, 0, colspan=5)
296+
self.layout.addWidget(self.argeditor, 0, 0, 1, 5)
297+
298+
def closeEvent(self, event):
299+
QtWidgets.QDockWidget.closeEvent(self, event)
300+
self.sigClosed.emit()
291301

292302
def save_state(self):
293303
return self.argeditor.save_state()
@@ -297,11 +307,10 @@ def restore_state(self, state):
297307

298308

299309
class ExperimentManager:
300-
def __init__(self, status_bar, dock_area,
310+
def __init__(self, main_window,
301311
explist_sub, schedule_sub,
302312
schedule_ctl, experiment_db_ctl):
303-
self.status_bar = status_bar
304-
self.dock_area = dock_area
313+
self.main_window = main_window
305314
self.schedule_ctl = schedule_ctl
306315
self.experiment_db_ctl = experiment_db_ctl
307316

@@ -385,11 +394,12 @@ def get_submission_arguments(self, expurl):
385394
def open_experiment(self, expurl):
386395
if expurl in self.open_experiments:
387396
dock = self.open_experiments[expurl]
388-
self.dock_area.floatDock(dock)
397+
dock.setFloating(True)
389398
return dock
390399
dock = _ExperimentDock(self, expurl)
391400
self.open_experiments[expurl] = dock
392-
self.dock_area.floatDock(dock)
401+
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
402+
dock.setFloating(True)
393403
dock.sigClosed.connect(partial(self.on_dock_closed, expurl))
394404
return dock
395405

@@ -398,7 +408,8 @@ def on_dock_closed(self, expurl):
398408

399409
async def _submit_task(self, *args):
400410
rid = await self.schedule_ctl.submit(*args)
401-
self.status_bar.showMessage("Submitted RID {}".format(rid))
411+
self.main_window.statusBar().showMessage(
412+
"Submitted RID {}".format(rid))
402413

403414
def submit(self, expurl):
404415
file, class_name, _ = self.resolve_expurl(expurl)
@@ -436,8 +447,9 @@ async def _request_term_multiple(self, rids):
436447
rid, exc_info=True)
437448

438449
def request_inst_term(self, expurl):
439-
self.status_bar.showMessage("Requesting termination of all instances "
440-
"of '{}'".format(expurl))
450+
self.main_window.statusBar().showMessage(
451+
"Requesting termination of all instances "
452+
"of '{}'".format(expurl))
441453
file, class_name, use_repository = self.resolve_expurl(expurl)
442454
rids = []
443455
for rid, desc in self.schedule.items():

‎artiq/gui/explorer.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import logging
33
from functools import partial
44

5-
from quamash import QtGui, QtCore
6-
from pyqtgraph import dockarea
5+
from quamash import QtGui, QtCore, QtWidgets
76
from pyqtgraph import LayoutWidget
87

98
from artiq.gui.models import DictSyncTreeSepModel
@@ -116,13 +115,19 @@ def __init__(self, init):
116115
DictSyncTreeSepModel.__init__(self, "/", ["Experiment"], init)
117116

118117

119-
class ExplorerDock(dockarea.Dock):
118+
class ExplorerDock(QtWidgets.QDockWidget):
120119
def __init__(self, status_bar, exp_manager, d_shortcuts,
121120
explist_sub, schedule_ctl, experiment_db_ctl):
122-
dockarea.Dock.__init__(self, "Explorer")
123-
self.setMinimumSize(QtCore.QSize(300, 300))
124-
self.layout.setSpacing(5)
125-
self.layout.setContentsMargins(5, 5, 5, 5)
121+
QtWidgets.QDockWidget.__init__(self, "Explorer")
122+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
123+
QtWidgets.QDockWidget.DockWidgetFloatable)
124+
125+
layout = QtWidgets.QGridLayout()
126+
top_widget = QtWidgets.QWidget()
127+
top_widget.setLayout(layout)
128+
self.setWidget(top_widget)
129+
layout.setSpacing(5)
130+
layout.setContentsMargins(5, 5, 5, 5)
126131

127132
self.status_bar = status_bar
128133
self.exp_manager = exp_manager
@@ -132,23 +137,23 @@ def __init__(self, status_bar, exp_manager, d_shortcuts,
132137
self.el = QtGui.QTreeView()
133138
self.el.setHeaderHidden(True)
134139
self.el.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
135-
self.addWidget(self.el, 0, 0, colspan=2)
140+
layout.addWidget(self.el, 0, 0, 1, 2)
136141
self.el.doubleClicked.connect(
137142
partial(self.expname_action, "open_experiment"))
138143

139144
open = QtGui.QPushButton("Open")
140145
open.setIcon(QtGui.QApplication.style().standardIcon(
141146
QtGui.QStyle.SP_DialogOpenButton))
142147
open.setToolTip("Open the selected experiment (Return)")
143-
self.addWidget(open, 1, 0)
148+
layout.addWidget(open, 1, 0)
144149
open.clicked.connect(
145150
partial(self.expname_action, "open_experiment"))
146151

147152
submit = QtGui.QPushButton("Submit")
148153
submit.setIcon(QtGui.QApplication.style().standardIcon(
149154
QtGui.QStyle.SP_DialogOkButton))
150155
submit.setToolTip("Schedule the selected experiment (Ctrl+Return)")
151-
self.addWidget(submit, 1, 1)
156+
layout.addWidget(submit, 1, 1)
152157
submit.clicked.connect(
153158
partial(self.expname_action, "submit"))
154159

‎artiq/gui/log.py

+23-12
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import re
55
from functools import partial
66

7-
from quamash import QtGui, QtCore
8-
from pyqtgraph import dockarea, LayoutWidget
7+
from quamash import QtGui, QtCore, QtWidgets
8+
from pyqtgraph import LayoutWidget
99

1010
from artiq.gui.tools import log_level_to_name
1111

@@ -140,13 +140,15 @@ def set_freetext(self, freetext):
140140
self.invalidateFilter()
141141

142142

143-
class _LogDock(dockarea.Dock):
143+
class _LogDock(QtWidgets.QDockWidget):
144+
sigClosed = QtCore.pyqtSignal()
145+
144146
def __init__(self, manager, name, log_sub):
145-
dockarea.Dock.__init__(self, name, label="Log")
146-
self.setMinimumSize(QtCore.QSize(720, 250))
147+
QtWidgets.QDockWidget.__init__(self, "Log")
148+
self.setObjectName(name)
147149

148150
grid = LayoutWidget()
149-
self.addWidget(grid)
151+
self.setWidget(grid)
150152

151153
grid.addWidget(QtGui.QLabel("Minimum level: "), 0, 0)
152154
self.filter_level = QtGui.QComboBox()
@@ -252,6 +254,10 @@ def set_model(self, model):
252254
self.table_model_filter.rowsInserted.connect(self.rows_inserted_after)
253255
self.table_model_filter.rowsRemoved.connect(self.rows_removed)
254256

257+
def closeEvent(self, event):
258+
QtWidgets.QDockWidget.closeEvent(self, event)
259+
self.sigClosed.emit()
260+
255261
def save_state(self):
256262
return {
257263
"min_level_idx": self.filter_level.currentIndex(),
@@ -279,8 +285,8 @@ def restore_state(self, state):
279285

280286

281287
class LogDockManager:
282-
def __init__(self, dock_area, log_sub):
283-
self.dock_area = dock_area
288+
def __init__(self, main_window, log_sub):
289+
self.main_window = main_window
284290
self.log_sub = log_sub
285291
self.docks = dict()
286292

@@ -294,7 +300,8 @@ def create_new_dock(self, add_to_area=True):
294300
dock = _LogDock(self, name, self.log_sub)
295301
self.docks[name] = dock
296302
if add_to_area:
297-
self.dock_area.floatDock(dock)
303+
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
304+
dock.setFloating(True)
298305
dock.sigClosed.connect(partial(self.on_dock_closed, name))
299306
self.update_closable()
300307
return dock
@@ -304,9 +311,12 @@ def on_dock_closed(self, name):
304311
self.update_closable()
305312

306313
def update_closable(self):
307-
closable = len(self.docks) > 1
314+
flags = (QtWidgets.QDockWidget.DockWidgetMovable |
315+
QtWidgets.QDockWidget.DockWidgetFloatable)
316+
if len(self.docks) > 1:
317+
flags |= QtWidgets.QDockWidget.DockWidgetClosable
308318
for dock in self.docks.values():
309-
dock.setClosable(closable)
319+
dock.setFeatures(flags)
310320

311321
def save_state(self):
312322
return {name: dock.save_state() for name, dock in self.docks.items()}
@@ -317,8 +327,9 @@ def restore_state(self, state):
317327
for name, dock_state in state.items():
318328
dock = _LogDock(self, name, self.log_sub)
319329
dock.restore_state(dock_state)
320-
self.dock_area.addDock(dock)
330+
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
321331
self.docks[name] = dock
332+
self.update_closable()
322333

323334
def first_log_dock(self):
324335
if self.docks:

‎artiq/gui/moninj.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import struct
55
from operator import itemgetter
66

7-
from quamash import QtGui, QtCore
8-
from pyqtgraph import dockarea
7+
from quamash import QtGui, QtCore, QtWidgets
98

109
from artiq.tools import TaskObject
1110
from artiq.protocols.sync_struct import Subscriber
@@ -213,14 +212,16 @@ def get_core_addr(self):
213212
return None
214213

215214

216-
class _MonInjDock(dockarea.Dock):
215+
class _MonInjDock(QtWidgets.QDockWidget):
217216
def __init__(self, name):
218-
dockarea.Dock.__init__(self, name)
217+
QtWidgets.QDockWidget.__init__(self, name)
218+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
219+
QtWidgets.QDockWidget.DockWidgetFloatable)
219220

220221
self.grid = QtGui.QGridLayout()
221222
gridw = QtGui.QWidget()
222223
gridw.setLayout(self.grid)
223-
self.addWidget(gridw)
224+
self.setWidget(gridw)
224225

225226
def layout_widgets(self, widgets):
226227
w = self.grid.itemAt(0)

‎artiq/gui/schedule.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import time
33
from functools import partial
44

5-
from quamash import QtGui, QtCore
5+
from quamash import QtGui, QtCore, QtWidgets
66
from pyqtgraph import dockarea
77

88
from artiq.gui.models import DictSyncModel
@@ -55,10 +55,11 @@ def convert(self, k, v, column):
5555
raise ValueError
5656

5757

58-
class ScheduleDock(dockarea.Dock):
58+
class ScheduleDock(QtWidgets.QDockWidget):
5959
def __init__(self, status_bar, schedule_ctl, schedule_sub):
60-
dockarea.Dock.__init__(self, "Schedule")
61-
self.setMinimumSize(QtCore.QSize(740, 200))
60+
QtWidgets.QDockWidget.__init__(self, "Schedule")
61+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
62+
QtWidgets.QDockWidget.DockWidgetFloatable)
6263

6364
self.status_bar = status_bar
6465
self.schedule_ctl = schedule_ctl
@@ -71,7 +72,7 @@ def __init__(self, status_bar, schedule_ctl, schedule_sub):
7172
self.table.verticalHeader().setResizeMode(
7273
QtGui.QHeaderView.ResizeToContents)
7374
self.table.verticalHeader().hide()
74-
self.addWidget(self.table)
75+
self.setWidget(self.table)
7576

7677
self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
7778
request_termination_action = QtGui.QAction("Request termination", self.table)

‎artiq/gui/shortcuts.py

+19-12
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,60 @@
22
from functools import partial
33

44
from quamash import QtGui, QtCore, QtWidgets
5-
from pyqtgraph import dockarea
5+
from pyqtgraph import LayoutWidget
66

77

88
logger = logging.getLogger(__name__)
99

1010

11-
class ShortcutsDock(dockarea.Dock):
11+
class ShortcutsDock(QtWidgets.QDockWidget):
1212
def __init__(self, main_window, exp_manager):
13-
dockarea.Dock.__init__(self, "Shortcuts")
14-
self.layout.setSpacing(5)
15-
self.layout.setContentsMargins(5, 5, 5, 5)
13+
QtWidgets.QDockWidget.__init__(self, "Shortcuts")
14+
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
15+
QtWidgets.QDockWidget.DockWidgetFloatable)
16+
17+
layout = QtWidgets.QGridLayout()
18+
top_widget = QtWidgets.QWidget()
19+
top_widget.setLayout(layout)
20+
self.setWidget(top_widget)
21+
layout.setSpacing(5)
22+
layout.setContentsMargins(5, 5, 5, 5)
1623

1724
self.exp_manager = exp_manager
1825
self.shortcut_widgets = dict()
1926

2027
for n, title in enumerate(["Key", "Experiment"]):
2128
label = QtGui.QLabel("<b>" + title + "</b>")
22-
self.addWidget(label, 0, n)
29+
layout.addWidget(label, 0, n)
2330
label.setMaximumHeight(label.sizeHint().height())
24-
self.layout.setColumnStretch(1, 1)
31+
layout.setColumnStretch(1, 1)
2532

2633
for i in range(12):
2734
row = i + 1
2835

29-
self.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0)
36+
layout.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0)
3037

3138
label = QtGui.QLabel()
3239
label.setSizePolicy(QtGui.QSizePolicy.Ignored,
3340
QtGui.QSizePolicy.Ignored)
34-
self.addWidget(label, row, 1)
41+
layout.addWidget(label, row, 1)
3542

3643
clear = QtGui.QToolButton()
3744
clear.setIcon(QtGui.QApplication.style().standardIcon(
3845
QtGui.QStyle.SP_DialogResetButton))
39-
self.addWidget(clear, row, 2)
46+
layout.addWidget(clear, row, 2)
4047
clear.clicked.connect(partial(self.set_shortcut, i, ""))
4148

4249
open = QtGui.QToolButton()
4350
open.setIcon(QtGui.QApplication.style().standardIcon(
4451
QtGui.QStyle.SP_DialogOpenButton))
45-
self.addWidget(open, row, 3)
52+
layout.addWidget(open, row, 3)
4653
open.clicked.connect(partial(self._open_experiment, i))
4754

4855
submit = QtGui.QPushButton("Submit")
4956
submit.setIcon(QtGui.QApplication.style().standardIcon(
5057
QtGui.QStyle.SP_DialogOkButton))
51-
self.addWidget(submit, row, 4)
58+
layout.addWidget(submit, row, 4)
5259
submit.clicked.connect(partial(self._activated, i))
5360

5461
clear.hide()

0 commit comments

Comments
 (0)
Please sign in to comment.