gui: switch to Qt

This commit is contained in:
Sebastien Bourdeauducq 2015-05-22 17:05:15 +08:00
parent c91cd0ab38
commit ea53ed1af7
15 changed files with 195 additions and 791 deletions

View File

@ -4,4 +4,3 @@ from artiq.language.db import *
from artiq.language.units import check_unit from artiq.language.units import check_unit
from artiq.language.units import ps, ns, us, ms, s from artiq.language.units import ps, ns, us, ms, s
from artiq.language.units import Hz, kHz, MHz, GHz from artiq.language.units import Hz, kHz, MHz, GHz
from artiq.gui.explib import *

View File

@ -4,17 +4,14 @@ import argparse
import asyncio import asyncio
import atexit import atexit
import gbulb # Quamash must be imported first so that pyqtgraph picks up the Qt binding
from gi.repository import Gtk # it has chosen.
from quamash import QEventLoop, QtGui
from pyqtgraph.dockarea import DockArea
from artiq.protocols.file_db import FlatFileDB from artiq.protocols.file_db import FlatFileDB
from artiq.protocols.pc_rpc import AsyncioClient from artiq.gui.schedule import ScheduleDock
from artiq.protocols.sync_struct import Subscriber from artiq.gui.parameters import ParametersDock
from artiq.gui.tools import LayoutManager
from artiq.gui.scheduler import SchedulerWindow
from artiq.gui.parameters import ParametersWindow
from artiq.gui.rt_results import RTResults
from artiq.gui.explorer import ExplorerWindow
def get_argparser(): def get_argparser():
@ -38,67 +35,31 @@ def main():
args = get_argparser().parse_args() args = get_argparser().parse_args()
db = FlatFileDB(args.db_file, default_data=dict()) db = FlatFileDB(args.db_file, default_data=dict())
lmgr = LayoutManager(db)
asyncio.set_event_loop_policy(gbulb.GtkEventLoopPolicy()) app = QtGui.QApplication([])
loop = asyncio.get_event_loop() loop = QEventLoop(app)
asyncio.set_event_loop(loop)
atexit.register(lambda: loop.close()) atexit.register(lambda: loop.close())
# share the schedule control and repository connections win = QtGui.QMainWindow()
schedule_ctl = AsyncioClient() area = DockArea()
loop.run_until_complete(schedule_ctl.connect_rpc( win.setCentralWidget(area)
args.server, args.port_control, "master_schedule")) win.resize(1000, 500)
atexit.register(lambda: schedule_ctl.close_rpc()) win.setWindowTitle("ARTIQ")
repository = AsyncioClient()
loop.run_until_complete(repository.connect_rpc(
args.server, args.port_control, "master_repository"))
atexit.register(lambda: repository.close_rpc())
scheduler_win = lmgr.create_window(SchedulerWindow, d_params = ParametersDock(area)
"scheduler", area.addDock(d_params, "left")
schedule_ctl) loop.run_until_complete(d_params.sub_connect(
loop.run_until_complete(scheduler_win.sub_connect(
args.server, args.port_notify)) args.server, args.port_notify))
atexit.register( atexit.register(lambda: loop.run_until_complete(d_params.sub_close()))
lambda: loop.run_until_complete(scheduler_win.sub_close()))
parameters_win = lmgr.create_window(ParametersWindow, "parameters") d_schedule = ScheduleDock(area)
loop.run_until_complete(parameters_win.sub_connect( area.addDock(d_schedule, "top", d_params)
loop.run_until_complete(d_schedule.sub_connect(
args.server, args.port_notify)) args.server, args.port_notify))
atexit.register( atexit.register(lambda: loop.run_until_complete(d_schedule.sub_close()))
lambda: loop.run_until_complete(parameters_win.sub_close()))
def exit(*args):
lmgr.save()
Gtk.main_quit(*args)
explorer_win = lmgr.create_window(ExplorerWindow,
"explorer",
exit,
schedule_ctl,
repository)
loop.run_until_complete(explorer_win.sub_connect(
args.server, args.port_notify))
atexit.register(
lambda: loop.run_until_complete(explorer_win.sub_close()))
parameters_sub = Subscriber("parameters",
[parameters_win.init_parameters_store,
explorer_win.init_parameters_dict])
loop.run_until_complete(
parameters_sub.connect(args.server, args.port_notify))
atexit.register(
lambda: loop.run_until_complete(parameters_sub.close()))
scheduler_win.show_all()
parameters_win.show_all()
explorer_win.show_all()
rtr = RTResults()
loop.run_until_complete(rtr.sub_connect(
args.server, args.port_notify))
atexit.register(
lambda: loop.run_until_complete(rtr.sub_close()))
win.show()
loop.run_forever() loop.run_forever()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,35 +0,0 @@
import asyncio as _aio
class BaseControls:
def __init__(self, facilities):
self.facilities = facilities
@_aio.coroutine
def build(self):
self.finalize()
def finalize(self):
pass
class GladeControls(BaseControls):
def __init__(self, facilities, glade_file, top_widget_name="top"):
BaseControls.__init__(self, facilities)
self.glade_file = glade_file
self.top_widget_name = top_widget_name
@_aio.coroutine
def build(self):
# lazy import GTK so that the artiq top-level
# (which imports from us) can be imported on systems
# without GTK installed
from gi.repository import Gtk
self.builder = Gtk.Builder()
data = yield from self.facilities.get_data(self.glade_file)
self.builder.add_from_string(data)
self.finalize()
def get_top_widget(self):
return self.builder.get_object(self.top_widget_name)

View File

@ -1,152 +0,0 @@
import asyncio
import types
from gi.repository import Gtk
from artiq.gui.tools import Window, getitem, DictSyncer
from artiq.protocols.sync_struct import Subscriber
class _ExplistStoreSyncer(DictSyncer):
def order_key(self, kv_pair):
return kv_pair[0]
def convert(self, name, value):
return [name]
class ExplorerWindow(Window):
def __init__(self, exit_fn, schedule_ctl, repository, layout_dict=dict()):
self.schedule_ctl = schedule_ctl
self.repository = repository
Window.__init__(self,
title="Explorer",
default_size=(800, 570),
layout_dict=layout_dict)
self.connect("delete-event", exit_fn)
topvbox = Gtk.VBox(spacing=6)
self.add(topvbox)
menubar = Gtk.MenuBar()
topvbox.pack_start(menubar, False, False, 0)
top_menuitem = Gtk.MenuItem("Windows")
menu = Gtk.Menu()
menuitem = Gtk.MenuItem("Scheduler")
menu.append(menuitem)
menuitem = Gtk.MenuItem("Parameters")
menu.append(menuitem)
menu.append(Gtk.SeparatorMenuItem())
menuitem = Gtk.MenuItem("Quit")
menuitem.connect("activate", exit_fn)
menu.append(menuitem)
top_menuitem.set_submenu(menu)
menubar.append(top_menuitem)
top_menuitem = Gtk.MenuItem("Registry")
menu = Gtk.Menu()
menuitem = Gtk.MenuItem("Run selected")
menuitem.connect("activate", self.run)
menu.append(menuitem)
menu.append(Gtk.SeparatorMenuItem())
menuitem = Gtk.MenuItem("Add experiment")
menu.append(menuitem)
menuitem = Gtk.MenuItem("Remove experiment")
menu.append(menuitem)
top_menuitem.set_submenu(menu)
menubar.append(top_menuitem)
self.pane = Gtk.HPaned(
position=getitem(layout_dict, "pane_position", 180))
topvbox.pack_start(self.pane, True, True, 0)
explistvbox = Gtk.VBox(spacing=6)
self.pane.pack1(explistvbox)
self.explist_store = Gtk.ListStore(str)
self.explist_tree = Gtk.TreeView(self.explist_store)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Registered experiments", renderer, text=0)
self.explist_tree.append_column(column)
self.explist_tree.connect("row-activated", self.explist_row_activated)
self.explist_tree.set_activate_on_single_click(True)
scroll = Gtk.ScrolledWindow()
scroll.add(self.explist_tree)
explistvbox.pack_start(scroll, True, True, 0)
button = Gtk.Button("Run")
button.connect("clicked", self.run)
explistvbox.pack_start(button, False, False, 0)
self.pane_contents = Gtk.Label("")
self.pane.pack2(self.pane_contents)
def get_layout_dict(self):
r = Window.get_layout_dict(self)
r["pane_position"] = self.pane.get_position()
return r
@asyncio.coroutine
def sub_connect(self, host, port):
self.explist_subscriber = Subscriber("explist",
[self.init_explist_store,
self.init_explist_data])
yield from self.explist_subscriber.connect(host, port)
@asyncio.coroutine
def sub_close(self):
yield from self.explist_subscriber.close()
def init_parameters_dict(self, init):
self.parameters = init
return init
def set_pane_contents(self, widget):
self.pane_contents.destroy()
self.pane_contents = widget
self.pane.pack2(self.pane_contents)
self.pane_contents.show_all()
def init_explist_store(self, init):
return _ExplistStoreSyncer(self.explist_store, init)
def init_explist_data(self, init):
self.explist_data = init
return init
def explist_row_activated(self, widget, index, column):
self.controls = None
name = self.explist_store[index][0]
gui_file = self.explist_data[name]["gui_file"]
if gui_file is None:
self.set_pane_contents(Gtk.Label("No GUI controls"))
else:
asyncio.Task(self.load_gui_file(gui_file))
@asyncio.coroutine
def load_gui_file(self, gui_file):
gui_mod_data = yield from self.repository.get_data(gui_file)
gui_mod = dict()
exec(gui_mod_data, gui_mod)
facilities = types.SimpleNamespace(
get_data=self.repository.get_data,
get_parameter=lambda p: self.parameters[p])
self.controls = gui_mod["Controls"](facilities)
yield from self.controls.build()
self.set_pane_contents(self.controls.get_top_widget())
def run(self, widget):
store, selected = self.explist_tree.get_selection().get_selected()
if selected is not None:
name = store[selected][0]
data = self.explist_data[name]
if self.controls is None:
arguments = {}
else:
arguments = self.controls.get_arguments()
expid = {
"file": data["file"],
"experiment": data["experiment"],
"arguments": arguments
}
asyncio.async(self.schedule_ctl.submit("main", expid, None))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,74 +1,47 @@
import asyncio import asyncio
from operator import itemgetter
import time
from gi.repository import Gtk from quamash import QtGui
from pyqtgraph.dockarea import Dock
from artiq.gui.tools import Window, ListSyncer, DictSyncer
from artiq.protocols.sync_struct import Subscriber from artiq.protocols.sync_struct import Subscriber
from artiq.gui.tools import DictSyncModel
class _ParameterStoreSyncer(DictSyncer): class ParametersModel(DictSyncModel):
def order_key(self, kv_pair): def __init__(self, parent, init):
return kv_pair[0] DictSyncModel.__init__(self, ["Parameter", "Value"],
parent, init)
def convert(self, name, value): def sort_key(self, k, v):
return [name, str(value)] return k
def convert(self, k, v, column):
class _LastChangesStoreSyncer(ListSyncer): if column == 0:
def convert(self, x): return k
if len(x) == 3: elif column == 1:
timestamp, name, value = x return str(v)
else: else:
timestamp, name = x raise ValueError
value = "<deleted>"
return [time.strftime("%m/%d %H:%M:%S", time.localtime(timestamp)),
name, str(value)]
class ParametersWindow(Window): class ParametersDock(Dock):
def __init__(self, **kwargs): def __init__(self, parent):
Window.__init__(self, Dock.__init__(self, "Parameters", size=(500, 300))
title="Parameters",
default_size=(500, 500),
**kwargs)
notebook = Gtk.Notebook() self.table = QtGui.QTableView()
self.add(notebook) self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.addWidget(self.table)
self.parameters_store = Gtk.ListStore(str, str)
tree = Gtk.TreeView(self.parameters_store)
for i, title in enumerate(["Parameter", "Value"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title, renderer, text=i)
tree.append_column(column)
scroll = Gtk.ScrolledWindow()
scroll.add(tree)
notebook.insert_page(scroll, Gtk.Label("Current values"), -1)
self.lastchanges_store = Gtk.ListStore(str, str, str)
tree = Gtk.TreeView(self.lastchanges_store)
for i, title in enumerate(["Time", "Parameter", "Value"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title, renderer, text=i)
tree.append_column(column)
scroll = Gtk.ScrolledWindow()
scroll.add(tree)
notebook.insert_page(scroll, Gtk.Label("Last changes"), -1)
@asyncio.coroutine @asyncio.coroutine
def sub_connect(self, host, port): def sub_connect(self, host, port):
self.lastchanges_subscriber = Subscriber( self.subscriber = Subscriber("parameters", self.init_parameters_model)
"parameters_simplehist", self.init_lastchanges_store) yield from self.subscriber.connect(host, port)
yield from self.lastchanges_subscriber.connect(host, port)
@asyncio.coroutine @asyncio.coroutine
def sub_close(self): def sub_close(self):
yield from self.lastchanges_subscriber.close() yield from self.subscriber.close()
def init_parameters_store(self, init): def init_parameters_model(self, init):
return _ParameterStoreSyncer(self.parameters_store, init) table_model = ParametersModel(self.table, init)
self.table.setModel(table_model)
def init_lastchanges_store(self, init): return table_model
return _LastChangesStoreSyncer(self.lastchanges_store, init)

View File

@ -1,79 +0,0 @@
from gi.repository import Gtk
import cairoplot
from artiq.gui.tools import Window
class RawWindow(Window):
def __init__(self, group_name, set_names):
self.labels = dict()
Window.__init__(self, title=group_name + ": Raw values",
default_size=(200, 150))
grid = Gtk.Grid(row_spacing=6, column_spacing=6)
self.add(grid)
for i, name in enumerate(set_names):
grid.attach(Gtk.Label(name), 0, i, 1, 1)
label = Gtk.Label("-")
self.labels[name] = label
grid.attach(label, 1, i, 1, 1)
def delete(self):
self.close()
def set_data(self, data):
for name, label in self.labels.items():
if name in data:
label.set_text(str(data[name]))
class PlotWindow(Window):
def __init__(self, group_name, set_names):
self.set_names = set_names
self.data = None
Window.__init__(self, title=group_name + ": " + "/".join(set_names),
default_size=(700, 500))
self.darea = Gtk.DrawingArea()
self.darea.set_size_request(100, 100)
self.darea.connect("draw", self.on_draw)
self.add(self.darea)
def delete(self):
self.close()
class XYWindow(PlotWindow):
def on_draw(self, widget, ctx):
if self.data is not None:
data = self.filter_data()
cairoplot.scatter_plot(
ctx,
data=data,
width=widget.get_allocated_width(),
height=widget.get_allocated_height(),
x_bounds=(min(data[0])*0.98, max(data[0])*1.02),
y_bounds=(min(data[1])*0.98, max(data[1])*1.02),
border=20, axis=True, grid=True,
dots=1, discrete=True,
series_colors=[(0.0, 0.0, 0.0)],
background="white"
)
def filter_data(self):
return [
self.data[self.set_names[0]],
self.data[self.set_names[1]],
]
def set_data(self, data):
self.data = data
if not self.data:
return
# The two axes are not updated simultaneously.
# Redraw only after receiving a new point for each.
x, y = self.filter_data()
if len(x) == len(y):
self.darea.queue_draw()

View File

@ -1,120 +0,0 @@
import asyncio
from collections import defaultdict
from artiq.protocols.sync_struct import Subscriber
from artiq.gui.rt_result_views import RawWindow, XYWindow
def _create_view(group_name, set_names, view_description):
if view_description == "raw":
r = RawWindow(group_name, set_names)
elif view_description == "xy":
r = XYWindow(group_name, set_names)
else:
raise ValueError("Unknown view description: " + view_description)
r.show_all()
return r
class _Group:
def __init__(self, name, init):
self.name = name
# data key -> list of views using it
self.views = defaultdict(list)
# original data
self.data = dict()
for k, v in init.items():
self[k] = v
def all_views(self):
r = set()
for view_list in self.views.values():
for view in view_list:
r.add(view)
return r
def delete(self):
for view in self.all_views():
view.delete()
def __getitem__(self, key):
if key == "data":
return self.data
else:
raise KeyError
def __setitem__(self, key, value):
if key == "description":
self.delete()
self.views = defaultdict(list)
for set_names, view_description in value.items():
if not isinstance(set_names, tuple):
set_names = (set_names, )
view = _create_view(self.name, set_names, view_description)
view.set_data(self.data)
for set_name in set_names:
self.views[set_name].append(view)
elif key == "data":
self.data = value
for view in self.all_views():
view.set_data(self.data)
else:
raise KeyError
def on_data_modified(self, key):
for view in self.views[key]:
view.set_data(self.data)
class _Groups:
def __init__(self, init):
self.groups = dict()
for k, v in init.items():
self[k] = v
def delete(self):
for s in self.groups.values():
s.delete()
def __getitem__(self, key):
return self.groups[key]
def __setitem__(self, key, value):
if key in self.groups:
self.groups[key].delete()
self.groups[key] = _Group(key, value)
def __delitem__(self, key):
self.groups[key].delete()
del self.groups[key]
class RTResults:
def __init__(self):
self.current_groups = None
@asyncio.coroutine
def sub_connect(self, host, port):
self.sets_subscriber = Subscriber("rt_results",
self.init_groups, self.on_mod)
yield from self.sets_subscriber.connect(host, port)
@asyncio.coroutine
def sub_close(self):
yield from self.sets_subscriber.close()
def init_groups(self, init):
if self.current_groups is not None:
self.current_groups.delete()
self.current_groups = _Groups(init)
return self.current_groups
def on_mod(self, mod):
if mod["action"] != "init" and len(mod["path"]) >= 2:
path = mod["path"]
group = self.current_groups[path[0]]
if path[1] == "data":
if len(mod["path"]) >= 3:
group.on_data_modified(path[2])
else:
group.on_data_modified(mod["key"])

69
artiq/gui/schedule.py Normal file
View File

@ -0,0 +1,69 @@
import asyncio
import time
from quamash import QtGui
from pyqtgraph.dockarea import Dock
from artiq.protocols.sync_struct import Subscriber
from artiq.gui.tools import DictSyncModel
from artiq.tools import format_arguments
class _ScheduleModel(DictSyncModel):
def __init__(self, parent, init):
DictSyncModel.__init__(self,
["RID", "Pipeline", "Status", "Due date",
"File", "Experiment", "Arguments"],
parent, init)
def sort_key(self, k, v):
# order by due date, and then by RID
return (v["due_date"] or 0, k)
def convert(self, k, v, column):
if column == 0:
return k
elif column == 1:
return v["pipeline"]
elif column == 2:
return v["status"]
elif column == 3:
if v["due_date"] is None:
return ""
else:
return time.strftime("%m/%d %H:%M:%S",
time.localtime(v["due_date"]))
elif column == 4:
return v["expid"]["file"]
elif column == 5:
if v["expid"]["experiment"] is None:
return ""
else:
return v["expid"]["experiment"]
elif column == 6:
return format_arguments(v["expid"]["arguments"])
else:
raise ValueError
class ScheduleDock(Dock):
def __init__(self, parent):
Dock.__init__(self, "Schedule", size=(1000, 300))
self.table = QtGui.QTableView()
self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.addWidget(self.table)
@asyncio.coroutine
def sub_connect(self, host, port):
self.subscriber = Subscriber("schedule", self.init_schedule_model)
yield from self.subscriber.connect(host, port)
@asyncio.coroutine
def sub_close(self):
yield from self.subscriber.close()
def init_schedule_model(self, init):
table_model = _ScheduleModel(self.table, init)
self.table.setModel(table_model)
return table_model

View File

@ -1,75 +0,0 @@
import time
import asyncio
from gi.repository import Gtk
from artiq.gui.tools import Window, DictSyncer
from artiq.protocols.sync_struct import Subscriber
from artiq.tools import format_arguments
class _ScheduleStoreSyncer(DictSyncer):
def order_key(self, kv_pair):
# order by due date, and then by RID
return (kv_pair[1]["due_date"] or 0, kv_pair[0])
def convert(self, rid, v):
row = [rid, v["pipeline"], v["status"]]
if v["due_date"] is None:
row.append("")
else:
row.append(time.strftime("%m/%d %H:%M:%S",
time.localtime(v["due_date"])))
row.append(v["expid"]["file"])
if v["expid"]["experiment"] is None:
row.append("")
else:
row.append(v["expid"]["experiment"])
row.append(format_arguments(v["expid"]["arguments"]))
return row
class SchedulerWindow(Window):
def __init__(self, schedule_ctl, **kwargs):
self.schedule_ctl = schedule_ctl
Window.__init__(self,
title="Scheduler",
default_size=(950, 570),
**kwargs)
topvbox = Gtk.VBox(spacing=6)
self.add(topvbox)
self.schedule_store = Gtk.ListStore(int, str, str, str, str, str, str)
self.schedule_tree = Gtk.TreeView(self.schedule_store)
for i, title in enumerate(["RID", "Pipeline", "Status", "Due date",
"File", "Experiment", "Arguments"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title, renderer, text=i)
self.schedule_tree.append_column(column)
scroll = Gtk.ScrolledWindow()
scroll.add(self.schedule_tree)
topvbox.pack_start(scroll, True, True, 0)
button = Gtk.Button("Delete")
button.connect("clicked", self.delete)
topvbox.pack_start(button, False, False, 0)
topvbox.set_border_width(6)
def delete(self, widget):
store, selected = self.schedule_tree.get_selection().get_selected()
if selected is not None:
rid = store[selected][0]
asyncio.async(self.schedule_ctl.delete(rid))
@asyncio.coroutine
def sub_connect(self, host, port):
self.schedule_subscriber = Subscriber("schedule", self.init_schedule_store)
yield from self.schedule_subscriber.connect(host, port)
@asyncio.coroutine
def sub_close(self):
yield from self.schedule_subscriber.close()
def init_schedule_store(self, init):
return _ScheduleStoreSyncer(self.schedule_store, init)

View File

@ -1,143 +1,96 @@
import os from quamash import QtCore
from gi.repository import Gtk
data_dir = os.path.abspath(os.path.dirname(__file__)) class _DictSyncSubstruct:
def getitem(d, item, default):
try:
return d[item]
except KeyError:
return default
class Window(Gtk.Window):
def __init__(self, title, default_size, layout_dict=dict()):
Gtk.Window.__init__(self, title=title + " - ARTIQ")
self.set_wmclass("ARTIQ", "ARTIQ")
self.set_icon_from_file(os.path.join(data_dir, "icon.png"))
self.set_border_width(6)
size = getitem(layout_dict, "size", default_size)
self.set_default_size(size[0], size[1])
try:
position = layout_dict["position"]
except KeyError:
pass
else:
self.move(position[0], position[1])
def get_layout_dict(self):
return {
"size": self.get_size(),
"position": self.get_position()
}
class LayoutManager:
def __init__(self, db):
self.db = db
self.windows = dict()
def create_window(self, cls, name, *args, **kwargs):
try:
win_layouts = self.db.request("win_layouts")
layout_dict = win_layouts[name]
except KeyError:
layout_dict = dict()
win = cls(*args, layout_dict=layout_dict, **kwargs)
self.windows[name] = win
return win
def save(self):
win_layouts = {name: window.get_layout_dict()
for name, window in self.windows.items()}
self.db.set("win_layouts", win_layouts)
class ListSyncer:
def __init__(self, store, init):
self.store = store
self.store.clear()
for x in init:
self.append(x)
def append(self, x):
self.store.append(self.convert(x))
def insert(self, i, x):
self.store.insert(i, self.convert(x))
def __delitem__(self, key):
del self.store[key]
def convert(self, x):
raise NotImplementedError
class _DictSyncerSubstruct:
def __init__(self, update_cb, ref): def __init__(self, update_cb, ref):
self.update_cb = update_cb self.update_cb = update_cb
self.ref = ref self.ref = ref
def __getitem__(self, key): def __getitem__(self, key):
return _DictSyncerSubstruct(self.update_cb, self.ref[key]) return _DictSyncSubstruct(self.update_cb, self.ref[key])
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.ref[key] = value self.ref[key] = value
self.update_cb() self.update_cb()
class DictSyncer: class DictSyncModel(QtCore.QAbstractTableModel):
def __init__(self, store, init): def __init__(self, headers, parent, init):
self.store = store self.headers = headers
self.store.clear() self.data = init
self.order = [] self.row_to_key = sorted(self.data.keys(),
for k, v in sorted(init.items(), key=self.order_key): key=lambda k: self.sort_key(k, self.data[k]))
self.store.append(self.convert(k, v)) QtCore.QAbstractTableModel.__init__(self, parent)
self.order.append((k, self.order_key((k, v))))
self.local_copy = init
def _find_index(self, key): def rowCount(self, parent):
for i, e in enumerate(self.order): return len(self.data)
if e[0] == key:
return i
raise KeyError
def __setitem__(self, key, value): def columnCount(self, parent):
try: return len(self.headers)
i = self._find_index(key)
except KeyError: def data(self, index, role):
pass if not index.isValid():
return None
elif role != QtCore.Qt.DisplayRole:
return None
k = self.row_to_key[index.row()]
return self.convert(k, self.data[k], index.column())
def headerData(self, col, orientation, role):
if (orientation == QtCore.Qt.Horizontal
and role == QtCore.Qt.DisplayRole):
return self.headers[col]
return None
def _find_row(self, k, v):
lo = 0
hi = len(self.row_to_key)
while lo < hi:
mid = (lo + hi)//2
if (self.sort_key(self.row_to_key[mid],
self.data[self.row_to_key[mid]])
< self.sort_key(k, v)):
lo = mid + 1
else: else:
del self.store[i] hi = mid
del self.order[i] return lo
ord_el = self.order_key((key, value))
j = len(self.order)
for i, (k, o) in enumerate(self.order):
if o > ord_el:
j = i
break
self.store.insert(j, self.convert(key, value))
self.order.insert(j, (key, ord_el))
self.local_copy[key] = value
def __delitem__(self, key): def __setitem__(self, k, v):
i = self._find_index(key) if k in self.data:
del self.store[i] old_row = self.row_to_key.index(k)
del self.order[i] new_row = self._find_row(k, v)
del self.local_copy[key] if old_row == new_row:
self.dataChanged.emit(self.index(old_row, 0),
self.index(old_row, len(self.headers)))
else:
self.beginMoveRows(QtCore.QModelIndex(), old_row, old_row,
QtCore.QModelIndex(), new_row)
self.data[k] = v
self.row_to_key[old_row], self.row_to_key[new_row] = \
self.row_to_key[new_row], self.row_to_key[old_row]
if old_row != new_row:
self.endMoveRows()
else:
row = self._find_row(k, v)
self.beginInsertRows(QtCore.QModelIndex(), row, row)
self.data[k] = v
self.row_to_key.insert(row, k)
self.endInsertRows()
def __delitem__(self, k):
row = self.row_to_key.index(k)
self.beginRemoveRows(QtCore.QModelIndex(), row, row)
del self.row_to_key[row]
del self.data[k]
self.endRemoveRows()
def __getitem__(self, key): def __getitem__(self, key):
def update(): def update():
self[key] = self.local_copy[key] self[key] = self.data[key]
return _DictSyncerSubstruct(update, self.local_copy[key]) return _DictSyncSubstruct(update, self.data[key])
def order_key(self, kv_pair): def sort_key(self, k, v):
raise NotImplementedError raise NotImplementedError
def convert(self, key, value): def convert(self, k, v, column):
raise NotImplementedError raise NotImplementedError

View File

@ -25,7 +25,6 @@ def model_numpy(xdata, F0):
class FloppingF(Experiment, AutoDB): class FloppingF(Experiment, AutoDB):
"""Flopping F simulation""" """Flopping F simulation"""
__artiq_gui_file__ = "flopping_f_simulation_gui.py"
class DBKeys: class DBKeys:
npoints = Argument(100) npoints = Argument(100)

View File

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkAdjustment" id="F0">
<property name="lower">1000</property>
<property name="upper">2000</property>
<property name="value">1500</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkGrid" id="top">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkSpinButton" id="spinbutton1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="adjustment">F0</property>
<property name="value">1500</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="getparam">
<property name="label" translatable="yes">Get from parameter DB</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Simulated flopping frequency:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</interface>

View File

@ -1,20 +0,0 @@
from artiq import GladeControls
class Controls(GladeControls):
def __init__(self, facilities):
GladeControls.__init__(self, facilities,
"flopping_f_simulation_gui.glade")
def finalize(self):
getparam = self.builder.get_object("getparam")
getparam.connect("clicked", self.getparam)
def getparam(self, widget):
F0 = self.facilities.get_parameter("flopping_freq")
self.builder.get_object("F0").set_value(F0)
def get_arguments(self):
return {
"F0": self.builder.get_object("F0").get_value()
}

View File

@ -1,18 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from setuptools import setup, find_packages from setuptools import setup, find_packages
import os
requirements = [ requirements = [
"sphinx", "sphinx-argparse", "pyserial", "numpy", "scipy", "sphinx", "sphinx-argparse", "pyserial", "numpy", "scipy",
"python-dateutil", "prettytable", "h5py", "pydaqmx", "pyelftools" "python-dateutil", "prettytable", "h5py", "pydaqmx", "pyelftools",
"quamash", "pyqtgraph"
] ]
scripts = [ scripts = [
"artiq_client=artiq.frontend.artiq_client:main", "artiq_client=artiq.frontend.artiq_client:main",
"artiq_compile=artiq.frontend.artiq_compile:main", "artiq_compile=artiq.frontend.artiq_compile:main",
"artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main", "artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main",
"artiq_gui=artiq.frontend.artiq_gui:main",
"artiq_master=artiq.frontend.artiq_master:main", "artiq_master=artiq.frontend.artiq_master:main",
"artiq_mkfs=artiq.frontend.artiq_mkfs:main", "artiq_mkfs=artiq.frontend.artiq_mkfs:main",
"artiq_rpctool=artiq.frontend.artiq_rpctool:main", "artiq_rpctool=artiq.frontend.artiq_rpctool:main",
@ -25,13 +26,6 @@ scripts = [
"thorlabs_tcube_controller=artiq.frontend.thorlabs_tcube_controller:main", "thorlabs_tcube_controller=artiq.frontend.thorlabs_tcube_controller:main",
] ]
if os.getenv("ARTIQ_GUI") == "1":
requirements += ["pygobject", "gbulb", "cairoplot"]
scripts += [
"artiq_gui=artiq.frontend.artiq_gui:main"
]
setup( setup(
name="artiq", name="artiq",
version="0.0+dev", version="0.0+dev",
@ -43,14 +37,9 @@ setup(
license="BSD", license="BSD",
install_requires=requirements, install_requires=requirements,
extras_require={}, extras_require={},
dependency_links=[
"git+https://github.com/m-labs/gbulb.git#egg=gbulb",
"git+https://github.com/m-labs/cairoplot3.git#egg=cairoplot"
],
packages=find_packages(), packages=find_packages(),
namespace_packages=[], namespace_packages=[],
test_suite="artiq.test", test_suite="artiq.test",
package_data={"artiq": [os.path.join("gui", "icon.png")]},
ext_modules=[], ext_modules=[],
entry_points={ entry_points={
"console_scripts": scripts, "console_scripts": scripts,