class MainWindow(QtWidgets.QMainWindow): """The only window of the application.""" def __init__(self, settings): super(MainWindow, self).__init__() self.settings = settings self.setupUi() self.dock_area = DockArea() self.setCentralWidget(self.dock_area) self.createDocks() self.loadSettings() self.setWindowTitle('Rb Lock') def setupUi(self): pass def createDocks(self): self.rb_lock_widget = RbLockWidget(self.settings, self) self.rb_lock_widget_dock = Dock('Rb Lock', widget=self.rb_lock_widget) self.dock_area.addDock(self.rb_lock_widget_dock) def loadSettings(self): """Load window state from self.settings""" self.settings.beginGroup('mainwindow') geometry = self.settings.value('geometry') state = self.settings.value('windowstate') dock_string = str(self.settings.value('dockstate')) if dock_string is not "": dock_state = eval(dock_string) self.dock_area.restoreState(dock_state) self.settings.endGroup() self.restoreGeometry(geometry) self.restoreState(state) def saveSettings(self): """Save window state to self.settings.""" self.settings.beginGroup('mainwindow') self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('windowstate', self.saveState()) dock_state = self.dock_area.saveState() # dock_state returned here is a python dictionary. Coundn't find a good # way to save dicts in QSettings, hence just using representation # of it. self.settings.setValue('dockstate', repr(dock_state)) self.settings.endGroup() def closeEvent(self, event): self.rb_lock_widget.saveSettings() self.saveSettings()
class MainWindow(QMainWindow, Ui_MainWindow): """The only window of the application.""" def __init__(self, settings): super(MainWindow, self).__init__() self.settings = settings self.setupUi(self) self.dock_area = DockArea() self.setCentralWidget(self.dock_area) self.createDocks() self.loadSettings() def createDocks(self): self.zmq_subscriber = ZMQSubscriber(self.settings, self) self.zmq_subscriber_dock = Dock('Subscriber', widget=self.zmq_subscriber) self.dock_area.addDock(self.zmq_subscriber_dock) def loadSettings(self): """Load window state from self.settings""" self.settings.beginGroup('mainwindow') geometry = self.settings.value('geometry').toByteArray() state = self.settings.value('windowstate').toByteArray() dock_string = str(self.settings.value('dockstate').toString()) if dock_string is not "": dock_state = eval(dock_string) self.dock_area.restoreState(dock_state) self.settings.endGroup() self.restoreGeometry(geometry) self.restoreState(state) def saveSettings(self): """Save window state to self.settings.""" self.settings.beginGroup('mainwindow') self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('windowstate', self.saveState()) dock_state = self.dock_area.saveState() # dock_state returned here is a python dictionary. Coundn't find a good # way to save dicts in QSettings, hence just using representation # of it. self.settings.setValue('dockstate', repr(dock_state)) self.settings.endGroup() def closeEvent(self, event): self.zmq_subscriber.saveSettings() self.saveSettings()
class DockAreaTabWidgetBase(QtGui.QWidget): def __init__(self, *args, **kwargs): self.main = kwargs.pop("main") tabName = kwargs.pop("tabName") QtGui.QWidget.__init__(self, *args, **kwargs) self.setObjectName(tabName) self._layout = QtGui.QGridLayout(self) def _InitDocks(self): # Define docking area if hasattr(self, "_dockArea"): self._dockArea.setParent(None) self._dockArea = DockArea() self._plotDocks = self._defaultDockPos.keys() # Add dock to area for dock, pos in self._defaultDockPos.iteritems(): self._dockArea.addDock(dock, *pos) self._layout.addWidget(self._dockArea, 0, 0, 1, 1) def Shown(self): self.DrawFrame() def DrawFrame(self, clear = True): if clear: self.ClearPlots() for dock in self._plotDocks: if not dock.automaticDraw: continue dock.DrawPlot() def ClearPlots(self): for dock in self._plotDocks: if not dock.automaticDraw: continue dock.ClearPlot() def AutoscalePlots(self): for dock in self._plotDocks: if not dock.automaticDraw: continue dock.Autoscale() def SaveState(self): res = {} res["dockingState"] = self._dockArea.saveState() for dock in self._plotDocks: res["dock_" + dock.name()] = dock.SaveState() return res def SetState(self, state): try: if "dockingState" in state: self._dockArea.restoreState(state["dockingState"]) except: print "Docking area restore failed, restoring defaults:" traceback.print_exc() print "Restore defaults" self._InitDocks() for dock in self._plotDocks: stateName = "dock_" + dock.name() if stateName in state: dock.SetState(state[stateName])
class MainWindow(QtGui.QMainWindow): # for dock def __init__(self, parent=None): from pyqtgraph import exporters exporters.Exporter.register = self.modified_register QtGui.QMainWindow.__init__(self, parent) self.setWindowIcon(QtGui.QIcon(logo)) self.setWindowTitle('CIVET') self.setGeometry(200, 143, 1574, 740) pg.setConfigOption('background', QtGui.QColor(215, 214, 213, 255)) pg.setConfigOption('foreground', 'k') palette = QtGui.QPalette() palette.setColor(QtGui.QPalette.Background, QtGui.QColor(215, 214, 213, 255)) self.setPalette(palette) self.mainframe = QtGui.QFrame() self.copen = 0 self.sopen = 0 self.ropen = 0 self.gridstate = 0 self.current_docks = [] self.loadaction = QtGui.QAction("&Open", self) self.loadaction.setShortcut("Ctrl+O") self.loadaction.setStatusTip("Open File") self.loadaction.triggered.connect(self.loaddata) self.exportaction = QtGui.QAction("&Export", self) self.exportaction.setShortcut("Ctrl+E") self.exportaction.setStatusTip("Export to a folder") self.exportaction.triggered.connect(self.exportdata) self.viewaction1 = QtGui.QAction("&Grid View 1", self) self.viewaction1.setStatusTip("Grid View 1") self.viewaction1.triggered.connect(self.grid_view_1) self.viewaction2 = QtGui.QAction("&Grid View 2", self) self.viewaction2.setStatusTip("Grid View 2") self.viewaction2.triggered.connect(self.grid_view_2) self.about = QtGui.QAction("&Info", self) self.about.setStatusTip("Info") self.about.triggered.connect(self.about_info) self.mainMenu = self.menuBar() self.fileMenu = self.mainMenu.addMenu("&File") self.fileMenu.addAction(self.loadaction) self.fileMenu.addAction(self.exportaction) self.viewMenu = self.mainMenu.addMenu("&Display") self.viewMenu.addAction(self.viewaction1) self.viewMenu.addAction(self.viewaction2) self.aboutMenu = self.mainMenu.addMenu("&About") self.aboutMenu.addAction(self.about) self.maketoolbar() self.area = DockArea() self.drho = Dock("\u03c1") self.dlamb = Dock("\u03bb") self.dalpha = Dock("\u03b1") self.dbeta = Dock("\u03b2") self.dphase = Dock("Phase") self.dcontrols = Dock("Controls") self.layout = QtGui.QHBoxLayout() self.layout.addWidget(self.area) self.mainframe.setLayout(self.layout) self.mainframe.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised) self.mainframe.setLineWidth(8) # all those have different relative positions so made bunch of functions, not one. def modified_register(self, cls): exporters.Exporter.Exporters.append(None) def dlambadd(self): try: self.area.addDock(self.dlamb, 'bottom', self.drho) except: try: self.area.addDock(self.dlamb, 'left', self.dphase) except: self.area.addDock(self.dlamb, 'left') def drhoadd(self): try: self.area.addDock(self.drho, 'top', self.dlamb) except: try: self.area.addDock(self.drho, 'left', self.dalpha) except: self.area.addDock(self.drho, 'left') def dalphaadd(self): try: self.area.addDock(self.dalpha, 'left', self.dbeta) except: try: self.area.addDock(self.dalpha, 'right', self.drho) except: try: self.area.addDock(self.dalpha, 'top', self.dphase) except: self.area.addDock(self.dalpha, 'left') def dbetaadd(self): try: self.area.addDock(self.dbeta, 'top', self.dcontrols) except: try: self.area.addDock(self.dbeta, 'right', self.dalpha) except: self.area.addDock(self.dbeta, 'right') def dphaseadd(self): try: self.area.addDock(self.dphase, 'left', self.dcontrols) except: try: self.area.addDock(self.dphase, 'bottom', self.dalpha) except: try: self.area.addDock(self.dphase, 'right', self.dlamb) except: self.area.addDock(self.drho, 'bottom') def dcontrolsadd(self): try: self.area.addDock(self.dcontrols, 'right', self.dphase) except: try: self.area.addDock(self.dcontrols, 'bottom', self.dbeta) except: self.area.addDock(self.dcontrols, 'right') def checkbox_init(self): self.dock_on = [] self.cwindow = QtGui.QMainWindow() self.cwindow.setWindowIcon(QtGui.QIcon(logo)) self.cwindow.setWindowTitle('Plots') self.boxeswidget = QtGui.QWidget(self.cwindow) checkbox_layout = QtGui.QGridLayout(self.boxeswidget) self.ch_lamb = QtGui.QCheckBox(self.boxeswidget) self.ch_lamb.setText('\u03bb') self.ch_lamb.setChecked(True) self.ch_lamb.stateChanged.connect(lambda: self.dlamb.close( ) if not self.ch_lamb.isChecked() else self.dlambadd()) self.ch_rho = QtGui.QCheckBox(self.boxeswidget) self.ch_rho.setText('\u03c1') self.ch_rho.setChecked(True) self.ch_rho.stateChanged.connect(lambda: self.drho.close( ) if not self.ch_rho.isChecked() else self.drhoadd()) self.ch_alpha = QtGui.QCheckBox(self.boxeswidget) self.ch_alpha.setText('\u03b1') self.ch_alpha.setChecked(True) self.ch_alpha.stateChanged.connect(lambda: self.dalpha.close( ) if not self.ch_alpha.isChecked() else self.dalphaadd()) self.ch_beta = QtGui.QCheckBox(self.boxeswidget) self.ch_beta.setText('\u03b2') self.ch_beta.setChecked(True) self.ch_beta.stateChanged.connect(lambda: self.dbeta.close( ) if not self.ch_beta.isChecked() else self.dbetaadd()) self.ch_phase = QtGui.QCheckBox(self.boxeswidget) self.ch_phase.setText('Phase') self.ch_phase.setChecked(True) self.ch_phase.stateChanged.connect(lambda: self.dphase.close( ) if not self.ch_phase.isChecked() else self.dphaseadd()) self.ch_controls = QtGui.QCheckBox(self.boxeswidget) self.ch_controls.setText('Controls') self.ch_controls.setChecked(True) self.ch_controls.stateChanged.connect(lambda: self.dcontrols.close( ) if not self.ch_controls.isChecked() else self.dcontrolsadd()) checkbox_layout.addWidget(self.ch_rho, 0, 0, 1, 1) checkbox_layout.addWidget(self.ch_lamb, 1, 0, 1, 1) checkbox_layout.addWidget(self.ch_alpha, 0, 1, 1, 1) checkbox_layout.addWidget(self.ch_phase, 1, 1, 1, 1) checkbox_layout.addWidget(self.ch_beta, 0, 2, 1, 1) checkbox_layout.addWidget(self.ch_controls, 1, 2, 1, 1) self.cwindow.setCentralWidget(self.boxeswidget) def checkbox(self): if self.copen == 0: self.check_current_docks() self.closed_docks = [] for i in self.docklist: if i not in self.current_docks: self.closed_docks += [i] for i in self.closed_docks: eval(i[:5] + "ch_" + i[6:]).setChecked(False) self.cwindow.show() self.copen = 1 else: self.cwindow.hide() self.copen = 0 def about_info(self): self.awindow = QtGui.QMainWindow() self.awindow.setWindowIcon(QtGui.QIcon(logo)) self.awindow.setWindowTitle('About') labels = QtGui.QWidget(self.awindow) labels_layout = QtGui.QVBoxLayout(labels) self.line0 = QtGui.QLabel() self.line1 = QtGui.QLabel( "CIVET: Current Inspired Visualization and Evaluation of the") self.line2 = QtGui.QLabel() self.line3 = QtGui.QLabel( "Totally asymmetric simple exclusion process (TASEP)") self.line4 = QtGui.QLabel() self.line5 = QtGui.QLabel("Copyright (c) 2018,") self.line6 = QtGui.QLabel() self.line7 = QtGui.QLabel( "Wonjun Son, Dan D. Erdmann-Pham, Khanh Dao Duc, Yun S. Song") self.line8 = QtGui.QLabel() self.line9 = QtGui.QLabel("All rights reserved.") self.line10 = QtGui.QLabel() for i in range(11): eval("self.line" + str(i)).setAlignment(QtCore.Qt.AlignCenter) labels_layout.addWidget(eval("self.line" + str(i))) self.awindow.setCentralWidget(labels) self.awindow.show() def exportdata(self): self.dialog = QtGui.QFileDialog() self.dialog.setOption(QtGui.QFileDialog.ShowDirsOnly) self.dialog.setFileMode(QtGui.QFileDialog.DirectoryOnly) folder_name = self.dialog.getSaveFileName(self, "Save Directory") filepath = os.path.join(os.path.abspath(os.sep), folder_name) if not os.path.exists(filepath): makedirs(filepath) # arr = QtCore.QByteArray() # buf = QtCore.QBuffer(arr) # svg = QtSvg.QSvgGenerator() # svg.setOutputDevice(buf) # dpi = QtGui.QDesktopWidget().physicalDpiX() # svg.setResolution(dpi) svg = QtSvg.QSvgGenerator() svg.setFileName("hh") svg.setSize(QtCore.QSize(2000, 2000)) svg.setViewBox(self.rect()) svg.setTitle("SVG svg Example Drawing") svg.setDescription("An SVG drawing created by the SVG Generator ") p = QtGui.QPainter() p.begin(svg) try: self.render(p) finally: p.end() # gen.setViewBox(QtGui.QRect(0, 0, 200, 200)); # gen.setTitle(tr("SVG Gen Example Drawing")); # gen.setDescription(tr("An SVG drawing created by the SVG Generator ""Example provided with Qt.")); lambda_data = os.path.join(filepath, "Lambda_data.csv") with open(lambda_data, "w") as output: try: writer = csv.writer(output, lineterminator='\n') for val in np.array(glo_var.lambdas)[:, 1]: writer.writerow([val]) except: pass summary = os.path.join(filepath, "Summary.csv") with open(summary, "w") as output: try: writer = csv.writer(output, delimiter='\t', lineterminator='\n') writer.writerow(["alpha", glo_var.alpha]) writer.writerow(["beta", glo_var.beta]) writer.writerow(["l", glo_var.l]) writer.writerow(["Phase", self.phas.pointer.region_aft]) except: pass # for name, pitem in self.pltlist: # self.exportimg(pitem,os.path.join(filepath,name + ".svg")) # # self.exportimg(pitem,os.path.join(filepath,name + ".png")) currentanddensity = os.path.join(filepath, "Current & Density.csv") with open(currentanddensity, "w") as output: writer = csv.writer(output, delimiter='\t', lineterminator='\n') # combine alpha, beta pre and post. Do it here to lessen the computation alpha_x_data = np.concatenate([ np.array(self.jalph.alphas_pre), np.linspace(self.jalph.trans_point, 1, 2) ]) alpha_j_data = np.concatenate( [self.jalph.j_l_values, np.array([self.jalph.jpost] * 2)]) alpha_rho_data = np.array(self.jalph.rho_avg_pre + self.jalph.rho_avg_post) beta_x_data = np.concatenate([ np.array(self.jbet.betas_pre), np.linspace(self.jbet.trans_point, 1, 2) ]) beta_j_data = np.concatenate( [self.jbet.j_r_values, np.array([self.jbet.jpost] * 2)]) beta_rho_data = np.array(self.jbet.rho_avg_pre + self.jbet.rho_avg_post) alpha_data = np.vstack( [alpha_x_data, alpha_j_data, alpha_rho_data]) beta_data = np.vstack([beta_x_data, beta_j_data, beta_rho_data]) writer.writerow([ "alpha", "Current", "Average Density", '\t', '\t', "beta", "Current", "Average Density" ]) for i in range(len(alpha_x_data)): writer.writerow( list(alpha_data[:, i]) + [''] * 2 + list(beta_data[:, i])) writer.writerow('\n') writer.writerow( ['beta', glo_var.beta, '', '', '', 'alpha', glo_var.alpha, '']) writer.writerow([ 'transition point', self.jalph.trans_point, '', '', '', 'transition point', self.jbet.trans_point, '' ]) self.pdfgroup1 = ['Lambda_fig', 'Density_fig'] self.pdfgroup2 = ['Current_alpha_fig', 'Current_beta_fig'] for name, pitem in self.pltlist: # self.exportimg(pitem,os.path.join(filepath,name + ".png")) path = os.path.join(filepath, name + ".svg") # if name == 'Current_alpha_fig': # self.jalph.p3.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle) # self.jalph.p3main.plotItem.legend.items=[] # self.jalph.p3.plot(pen=self.jalph.jpen, name='J') # self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329\u03c1 \u232a') # elif name == 'Current_beta_fig': # self.jbet.p4.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle) # self.jbet.p4main.plotItem.legend.items=[] # self.jbet.p4.plot(pen=self.jbet.jpen, name='J') # self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329\u03c1 \u232a') self.exportimg(pitem, path) if name in self.pdfgroup1: self.makepdf(path, os.path.join(filepath, name + ".pdf"), 500, 260, 20, 240) elif name == 'Current_alpha_fig': self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350, 280, 30, 230) # self.jalph.p3.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle) # self.jalph.p3main.plotItem.legend.items=[] # self.jalph.p3.plot(pen=self.jalph.jpen, name='J') # self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329 \u03c1 \u232a') elif name == 'Current_beta_fig': self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350, 280, 30, 230) # self.jbet.p4.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle) # self.jbet.p4main.plotItem.legend.items=[] # self.jbet.p4.plot(pen=self.jbet.jpen, name='J') # self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329 \u03c1 \u232a') else: self.makepdf(path, os.path.join(filepath, name + ".pdf"), 410, 330, 10, 300) os.remove(path) def makepdf(self, path, name, x, y, z, q): from svglib.svglib import svg2rlg from reportlab.pdfgen import canvas from reportlab.graphics import renderPDF rlg = svg2rlg(path) rlg.scale(0.8, 0.8) c = canvas.Canvas(name) c.setPageSize((x, y)) renderPDF.draw(rlg, c, z, q) c.showPage() c.save() def exportimg(self, img, path): # self.img = pg.exporters.ImageExporter(img) # self.img.export(path) self.svg = pg.exporters.SVGExporter(img) self.svg.export(fileName=path) def maketoolbar(self): self.state = None self.titlebarstate = 1 self.toolbar = self.addToolBar("Toolbar") home = QtGui.QAction( QtGui.QIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_ComputerIcon)), 'Toggle Grid View', self) home.triggered.connect(self.toggle_grid_view) self.toolbar.addAction(home) fix = QtGui.QAction( QtGui.QIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_ArrowDown)), 'Fix current layout', self) fix.triggered.connect(self.fixdock) self.toolbar.addAction(fix) self.savedockandvaluesinit() save = QtGui.QAction( QtGui.QIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_FileDialogListView)), 'Save current layout', self) save.triggered.connect(self.popsavedockandvalues) self.toolbar.addAction(save) self.restoredockandvaluesinit() restore = QtGui.QAction( QtGui.QIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_BrowserReload)), 'Restore saved layout', self) restore.triggered.connect(self.poprestoredockandvalues) self.toolbar.addAction(restore) self.checkbox_init() checkbox = QtGui.QAction( QtGui.QIcon(QtGui.QApplication.style().standardIcon( QtGui.QStyle.SP_FileDialogDetailedView)), 'Open & close specific windows', self) checkbox.triggered.connect(self.checkbox) self.toolbar.addAction(checkbox) def fixdock(self): if self.titlebarstate == 1: self.dlamb.hideTitleBar() self.drho.hideTitleBar() self.dalpha.hideTitleBar() self.dbeta.hideTitleBar() self.dcontrols.hideTitleBar() self.dphase.hideTitleBar() self.titlebarstate = 0 else: self.dlamb.showTitleBar() self.drho.showTitleBar() self.dalpha.showTitleBar() self.dbeta.showTitleBar() self.dcontrols.showTitleBar() self.dphase.showTitleBar() self.titlebarstate = 1 def savedockandvaluesinit(self): self.swindow = QtGui.QMainWindow() self.swindow.setWindowIcon(QtGui.QIcon(logo)) self.swindow.setWindowTitle('Save') boxeswidget = QtGui.QWidget(self.swindow) checkbox_layout = QtGui.QGridLayout(boxeswidget) self.sa_dock = QtGui.QCheckBox(boxeswidget) self.sa_dock.setText('Grid View') self.sa_dock.setChecked(True) self.sa_values = QtGui.QCheckBox(boxeswidget) self.sa_values.setText('Values') self.sa_values.setChecked(True) self.save_button = QtGui.QPushButton('Save', self) self.save_button.clicked.connect(self.savedockandvalues) checkbox_layout.addWidget(self.sa_dock, 0, 0, 1, 1) checkbox_layout.addWidget(self.sa_values, 0, 1, 1, 1) checkbox_layout.addWidget(self.save_button, 1, 0, 1, 2) self.swindow.setCentralWidget(boxeswidget) def restoredockandvaluesinit(self): self.rwindow = QtGui.QMainWindow() self.rwindow.setWindowIcon(QtGui.QIcon(logo)) self.rwindow.setWindowTitle('Restore') boxeswidget = QtGui.QWidget(self.rwindow) checkbox_layout = QtGui.QGridLayout(boxeswidget) self.re_dock = QtGui.QCheckBox(boxeswidget) self.re_dock.setText('Grid View') self.re_dock.setChecked(True) self.re_values = QtGui.QCheckBox(boxeswidget) self.re_values.setText('Values') self.re_values.setChecked(True) self.restore_button = QtGui.QPushButton('Restore', self) self.restore_button.clicked.connect(self.restoredockandvalues) checkbox_layout.addWidget(self.re_dock, 0, 0, 1, 1) checkbox_layout.addWidget(self.re_values, 0, 1, 1, 1) checkbox_layout.addWidget(self.restore_button, 1, 0, 1, 2) self.rwindow.setCentralWidget(boxeswidget) def savedockandvalues(self): if self.sa_values.checkState: self.savedlambdas = deepcopy(glo_var.lambdas) self.savedalpha = glo_var.alpha self.savedbeta = glo_var.beta self.savedl = glo_var.l if self.sa_dock.checkState: self.saved_state = [] self.state = self.area.saveState() self.saved_state = self.check_current_docks()[:] self.sopen = 0 self.swindow.hide() def popsavedockandvalues(self): if self.sopen == 0: self.swindow.show() self.sopen = 1 else: self.swindow.hide() self.sopen = 0 def poprestoredockandvalues(self): if self.ropen == 0: self.rwindow.show() self.ropen = 1 else: self.rwindow.hide() self.ropen = 0 def restoredockandvalues(self): if self.re_values.checkState: glo_var.lambdas = deepcopy(self.savedlambdas) glo_var.alpha = self.savedalpha glo_var.beta = self.savedbeta glo_var.l = self.savedl self.lamb_po.update() self.rh.update() self.phas.update() self.jalph.update() self.jbet.update() self.slid.update_alpha_slid(self.slid.ws[0]) self.slid.update_beta_slid(self.slid.ws[1]) self.slid.update_l_slid(self.slid.ws[2]) if self.re_dock.checkState: if self.state != None: closed_docks = [] self.check_current_docks() # Notice after below, current dock != real current dock. But it doesn't matter since we call check current dock every time. for i in self.current_docks: if i not in self.saved_state: eval(i).close() for i in self.saved_state: if i not in self.current_docks: eval(i + "add")() self.area.restoreState(self.state) self.ropen = 0 self.rwindow.hide() def realinit(self): self.clear_buttons = [ "self.lamb_po.p1main.coordinate_label.setText(\"\")", "self.rh.p2main.coordinate_label.setText(\"\")", "self.jalph.p3main.coordinate_label.setText(\"\")", "self.jbet.p4main.coordinate_label.setText(\"\")", "self.phas.p5main.coordinate_label.setText(\"\")" ] glo_var.pass_main(self) self.docklist = [ 'self.drho', 'self.dlamb', 'self.dalpha', 'self.dbeta', 'self.dphase', 'self.dcontrols' ] self.area = DockArea() self.drho = Dock("Particle Density \u2374", closable=True) self.dlamb = Dock("Hopping Rate \u03bb", closable=True) self.dphase = Dock("Phase Diagram", closable=True) self.dcontrols = Dock("Controls", closable=True) self.dalpha = Dock( "Current J and average density \u27e8\u2374\u27e9 as a function of \u03b1", closable=True) self.dbeta = Dock( "Current J and average density \u27e8\u2374\u27e9 as a function of \u03b2", closable=True) self.layout = QtGui.QHBoxLayout() self.layout.addWidget(self.area) self.mainframe.setLayout(self.layout) self.mainframe.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised) self.mainframe.setLineWidth(8) pg.setConfigOptions(antialias=True) self.rh = rho.rho(self.drho) self.jalph = jalpha.jalpha(self.dalpha, self.rh) self.jbet = jbeta.jbeta(self.dbeta, self.rh) self.phas = phase.phase(self.dphase) self.lamb_po = lamb_pol.lamb_pol(self.dlamb) self.slid = slider.Widget(self.dcontrols, self.lamb_po, self.phas, self.rh, self.jbet, self.jalph) self.lamb_po.receive(self.slid) # default values to restore is input self.savedlambdas = glo_var.lambdas[:] self.savedalpha = glo_var.alpha self.savedbeta = glo_var.beta self.savedl = glo_var.l self.pltlist = [['Lambda_fig', self.lamb_po.p1], ['Density_fig', self.rh.p2], ['Current_alpha_fig', self.jalph.plotitemtoexport], ['Current_beta_fig', self.jbet.plotitemtoexport], ['Phase_fig', self.phas.p5]] self.grid_view_1() self.setCentralWidget(self.area) print(dir(self.area)) print(self.area.childrenRect(), "childrenRect") print(self.area.contentsRect(), "contentesRect") print(self.area.rect()) def check_current_docks(self): self.current_docks = [] for i in self.docklist: if self.area.getContainer(eval(i)): self.current_docks += [i] else: pass return self.current_docks def toggle_grid_view(self): if self.gridstate == 0: self.grid_view_2() self.gridstate = 1 else: self.grid_view_1() self.gridstate = 0 def grid_view_1(self): for i in self.docklist: try: eval(i).close() except: pass self.drho.setMinimumSize(652, 370) self.dlamb.setMinimumSize(652, 370) self.dphase.setMinimumSize(487, 465) self.dcontrols.setMinimumSize(487, 275) self.dalpha.setMinimumSize(435, 370) self.dbeta.setMinimumSize(435, 370) self.area.addDock(self.drho, 'left') self.area.addDock(self.dlamb, 'bottom', self.drho) self.area.addDock(self.dphase, 'right') self.area.addDock(self.dcontrols, 'bottom', self.dphase) self.area.addDock(self.dalpha, 'right') self.area.addDock(self.dbeta, 'bottom', self.dalpha) self.drho.setMinimumSize(0, 0) self.dlamb.setMinimumSize(0, 0) self.dphase.setMinimumSize(0, 0) self.dcontrols.setMinimumSize(0, 0) self.dalpha.setMinimumSize(0, 0) self.dbeta.setMinimumSize(0, 0) def grid_view_2(self): for i in self.docklist: try: eval(i).close() except: pass self.area.addDock(self.drho, 'top') self.area.addDock(self.dlamb, 'bottom', self.drho) self.area.addDock(self.dphase, 'bottom') self.area.addDock(self.dcontrols, 'left', self.dphase) self.area.addDock(self.dalpha, 'right') self.area.addDock(self.dbeta, 'bottom', self.dalpha) def opengraphs(self): self.mn = main.main_class(app) self.window.hide() def loaddata(self): name = QtGui.QFileDialog.getOpenFileName(self, 'Open File', '.', 'text (*.txt *.csv)') if name == "": pass else: self.read_file(name) self.realinit() def read_file(self, input): global ison temp = [] if ison == 0: ison = 1 else: self.setCentralWidget(None) glo_var.initialize() if input[-3:] == 'csv': with open(input, newline='') as csvfile: spamreader = csv.reader(csvfile, delimiter=',', quotechar='|') lis = [] for j in spamreader: lis += j num_of_inputs = len(lis) glo_var.lambdas_degree = num_of_inputs for i in range(num_of_inputs): glo_var.lambdas += [[ i / (num_of_inputs - 1), round(eval(lis[i]), 2) ]] glo_var.alpha = 0.04 glo_var.beta = 0.04 glo_var.l = 1 elif input[-3:] == 'txt': f = open(input, 'r') # Breaks the loop i try: temp = [] while (True): T = f.readline().strip() temp += [[glo_var.lambdas_degree, round(eval(T), 2)]] except: for x, y in temp: glo_var.lambdas += [[x / (glo_var.lambdas_degree - 1), y]] glo_var.l = 1 else: err = QtGui.QMessageBox(self.win) err.setIcon(QMessageBox().Warning) err.setText("Please select txt or csv file Format") err.setWindowTitle("File Format Error") err.setStandardButtons(QMessageBox.Ok) err.buttonClicked.connect() def eventFilter(self, source, event): if event.type() == QtCore.QEvent.MouseMove: if event.buttons() == QtCore.Qt.NoButton: pos = event.pos() if self.toolbar.rect().contains( pos) or not self.area.rect().contains(pos): self.clear_points() else: pass return QtGui.QMainWindow.eventFilter(self, source, event) def clear_points(self, exclude=None): if not exclude: for x in self.clear_buttons: eval(x) else: for x in self.clear_buttons[:exclude - 1] + self.clear_buttons[exclude:]: eval(x)
class DigitalLockUi(WidgetContainerBase, WidgetContainerForm): levelNameList = ["debug", "info", "warning", "error", "critical"] levelValueList = [ logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL ] plotConfigurationChanged = QtCore.pyqtSignal(object) def __init__(self, config, project): self.config = config self.project = project super(DigitalLockUi, self).__init__() self.settings = SettingsDialog.Settings() self.deviceSerial = config.get('Settings.deviceSerial') self.deviceDescription = config.get('Settings.deviceDescription') self.loggingLevel = config.get('Settings.loggingLevel', logging.INFO) self.consoleMaximumLines = config.get('Settings.consoleMaximumLines', 0) self.dockWidgetList = list() if self.loggingLevel not in self.levelValueList: self.loggingLevel = logging.INFO self.plotDict = dict() def __enter__(self): self.pulser = Controller() return self def __exit__(self, excepttype, value, traceback): self.pulser.shutdown() return False def setupUi(self, parent): super(DigitalLockUi, self).setupUi(parent) self.dockWidgetConsole.hide() self.loggerUi = LoggerLevelsUi(self.config) self.loggerUi.setupUi(self.loggerUi) self.setupAsDockWidget(self.loggerUi, "Logging", QtCore.Qt.NoDockWidgetArea) logger = logging.getLogger() self.toolBar.addWidget(ExceptionLogButton()) # Setup Console Dockwidget self.levelComboBox.addItems(self.levelNameList) # self.levelComboBox.currentIndexChanged[int].connect( self.setLoggingLevel ) self.levelComboBox.setCurrentIndex( self.levelValueList.index(self.loggingLevel)) # self.consoleClearButton.clicked.connect( self.onClearConsole ) # self.linesSpinBox.valueChanged.connect( self.onConsoleMaximumLinesChanged ) self.parent = parent self.tabList = list() self.tabDict = dict() # initialize FPGA settings self.settingsDialog = SettingsDialog.SettingsDialog( self.pulser, self.config, self.parent) self.settingsDialog.setupUi() self.settings = self.settingsDialog.settings try: configFile = os.path.splitext(self.settings.bitfile)[0] + '.yml' with open(configFile, 'r') as f: lockConfig = yaml.load(f) self.settings.onBoardADCEncoding = lockConfig['onBoardADCEncoding'] except Exception as e: logger.error('unable to load config file: {0}'.format(e)) self.settings.onBoardADCEncoding = None self.setupPlots() # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # lock status self.lockStatus = LockStatus(self.pulser, self.config, self.traceui, self.plotDict, self.settings, self.parent) self.lockStatus.setupUi() self.setupAsDockWidget(self.lockStatus, "Status", QtCore.Qt.RightDockWidgetArea) self.plotConfigurationChanged.connect( self.lockStatus.onPlotConfigurationChanged) # Trace control self.traceControl = TraceControl(self.pulser, self.config, self.traceui, self.plotDict, self.parent) self.traceControl.setupUi() self.setupAsDockWidget(self.traceControl, "Trace Control", QtCore.Qt.RightDockWidgetArea) self.plotConfigurationChanged.connect( self.traceControl.onPlotConfigurationChanged) # Lock control self.lockControl = LockControl(self.pulser, self.config, self.settings, self.parent) self.lockControl.dataChanged.connect(self.lockStatus.onControlChanged) self.lockControl.dataChanged.connect( self.traceControl.onControlChanged) self.lockControl.setupUi() self.lockStatus.newDataAvailable.connect(self.lockControl.onStreamData) self.traceControl.newDataAvailable.connect( self.lockControl.onTraceData) self.setupAsDockWidget(self.lockControl, "Control", QtCore.Qt.RightDockWidgetArea) self.actionSave.triggered.connect(self.onSave) self.actionSettings.triggered.connect(self.onSettings) self.actionExit.triggered.connect(self.onClose) self.actionProject.triggered.connect(self.onProjectSelection) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle("Digital Lock ({0})".format(self.project)) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) self.initMenu() try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.error( "Cannot restore dock state in experiment {0}. Exception occurred: " .format(self.experimentName) + str(e)) QtCore.QTimer.singleShot(300000, self.onCommitConfig) def onCommitConfig(self): self.saveConfig() self.config.saveConfig() QtCore.QTimer.singleShot(300000, self.onCommitConfig) def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get('PlotNames', ['History', 'Scope']) if len(plotNames) < 1: plotNames.append('History') for name in plotNames: dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget(widget) self.addDockWidget(area, dock) self.dockWidgetList.append(dock) if stackAbove is not None: self.tabifyDockWidget(stackAbove, dock) elif stackBelow is not None: self.tabifyDockWidget(dock, stackBelow) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText( self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } self.plotConfigurationChanged.emit(self.plotDict) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText( self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be renamed") def onProjectSelection(self): ui = ProjectInfoUi(self.project) ui.show() ui.exec_() def onSettings(self): self.settingsDialog.show() def onSave(self): logger = logging.getLogger(__name__) logger.info("Saving config") filename, _ = DataDirectory.DataDirectory().sequencefile( "digitalLock-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onMessageWrite(self, message, level=logging.DEBUG): if level >= self.loggingLevel: cursor = self.textEditConsole.textCursor() cursor.movePosition(QtGui.QTextCursor.End) if level < logging.ERROR: self.textEditConsole.setTextColor(QtCore.Qt.black) else: self.textEditConsole.setTextColor(QtCore.Qt.red) cursor.insertText(message) self.textEditConsole.setTextCursor(cursor) self.textEditConsole.ensureCursorVisible() def onClose(self): self.parent.close() def closeEvent(self, e): logger = logging.getLogger("") logger.debug("Saving Configuration") self.saveConfig() self.settingsDialog.done(0) self.lockControl.closeEvent(e) def initMenu(self): self.menuView.clear() for dock in self.dockWidgetList: self.menuView.addAction(dock.toggleViewAction()) def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in self.tabList: tab.saveConfig() self.config['Settings.deviceSerial'] = self.settings.deviceSerial self.config[ 'Settings.deviceDescription'] = self.settings.deviceDescription self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['Settings.loggingLevel'] = self.loggingLevel self.config['Settings.consoleMaximumLines'] = self.consoleMaximumLines self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.settingsDialog.saveConfig() self.loggerUi.saveConfig() self.lockControl.saveConfig() self.lockStatus.saveConfig() self.traceControl.saveConfig()
class MainWindow(QMainWindow): """ Main control window for showing the live captured images and initiating special tasks """ def __init__(self, experiment): """ Inits the camera window :param experiment: Experiment that is controlled by the GUI """ super().__init__() self.setWindowTitle('PyNTA: Python Nanoparticle Tracking Analysis') self.setMouseTracking(True) self.experiment = experiment self.area = DockArea() self.setCentralWidget(self.area) self.resize(1064, 840) self.area.setMouseTracking(True) # Main widget self.camWidget = MonitorMainWidget() self.camWidget.setup_cross_cut(self.experiment.max_height) self.camWidget.setup_cross_hair( [self.experiment.max_width, self.experiment.max_height]) self.camWidget.setup_roi_lines( [self.experiment.max_width, self.experiment.max_height]) self.camWidget.setup_mouse_tracking() self.messageWidget = messageWidget() self.cheatSheet = popOutWindow() self.dmainImage = Dock("Camera", size=(80, 35)) # sizes are in percentage self.dmainImage.addWidget(self.camWidget) self.area.addDock(self.dmainImage, 'right') self.dmessage = Dock("Messages", size=(40, 30)) self.dmessage.addWidget(self.messageWidget) self.area.addDock(self.dmessage, 'right') # # Widget for displaying information to the user # # Small window to display the results of the special task # self.trajectoryWidget = trajectoryWidget() # # Window for the camera viewer # # self.camViewer = cameraViewer(self._session, self.camera, parent=self) # # Configuration widget with a parameter tree # # self.config = ConfigWidget(self._session) # # Line cut widget # self.crossCut = crossCutWindow(parent=self) # self.popOut = popOutWindow(parent=self) #_future: for making long message pop-ups # # Select settings Window # # self.selectSettings = HDFLoader() # self.refreshTimer = QtCore.QTimer() self.refreshTimer.timeout.connect(self.updateGUI) # self.refreshTimer.timeout.connect(self.crossCut.update) # self.refreshTimer.start(self.experiment.config['GUI']['refresh_time']) # # self.acquiring = False # self.logmessage = [] # # ''' Initialize the camera and the camera related things ''' # self.max_sizex = self.camera.GetCCDWidth() # self.max_sizey = self.camera.GetCCDHeight() # self.current_width = self.max_sizex # self.current_height = self.max_sizey # # # if self._session.Camera['roi_x1'] == 0: # # self._session.Camera = {'roi_x1': 1} # # if self._session.Camera['roi_x2'] == 0 or self._session.Camera['roi_x2'] > self.max_sizex: # # self._session.Camera = {'roi_x2': self.max_sizex} # # if self._session.Camera['roi_y1'] == 0: # # self._session.Camera = {'roi_y1': 1} # # if self._session.Camera['roi_y2'] == 0 or self._session.Camera['roi_y2'] > self.max_sizey: # # self._session.Camera = {'roi_y2': self.max_sizey} # # # self.config.populateTree(self.experiment.config) # self.lastBuffer = time.time() # self.lastRefresh = time.time() # # # Program variables # self.tempimage = [] # self.bgimage = [] # self.trackinfo = np.zeros((1,5)) # real particle trajectory filled by "LocateParticle" analysis # # self.noiselvl = self._session.Tracking['noise_level'] # self.fps = 0 # self.buffertime = 0 # self.buffertimes = [] # self.refreshtimes = [] # self.totalframes = 0 # self.droppedframes = 0 # self.buffer_memory = 0 # self.waterfall_data = [] # self.watindex = 0 # Waterfall index # self.corner_roi = [] # Real coordinates of the corner of the ROI region. (Min_x and Min_y). # self.docks = [] # # self.corner_roi.append(self._session.Camera['roi_x1']) # # self.corner_roi.append(self._session.Camera['roi_y1']) # # # Program status controllers # self.continuous_saving = False # self.show_waterfall = False # self.subtract_background = False # self.save_running = False # self.accumulate_buffer = False # self.specialtask_running = False # self.dock_state = None # self.setupActions() self.setupToolbar() self.setupMenubar() # self.setupDocks() # self.setupSignals() ### This block should erased in due time and one must rely exclusively on Session variables. # self.filedir = self._session.Saving['directory'] # self.snap_filename = self._session.Saving['filename_photo'] # self.movie_filename = self._session.Saving['filename_video'] ### self.messageWidget.appendLog( 'i', 'Program started by %s' % self.experiment.config['User']['name']) def start_tracking(self): self.experiment.start_tracking() def showHelp(self): """To show the cheatsheet for shortcuts in a pop-up meassage box OBSOLETE, will be deleted after transferring info into a better message viewer! """ self.experiment.plot_histogram() # msgBox = QtGui.QMessageBox() # msgBox.setIcon(QtGui.QMessageBox.Information) # msgBox.setText("Keyboard shortcuts and Hotkeys") # msgBox.setInformativeText("Press details for a full list") # msgBox.setWindowTitle("pynta CheatSheet") # msgBox.setDetailedText(""" # F1, Show cheatsheet\n # F5, Snap image\n # F6, Continuous run\n # Alt+mouse: Select line \n # Ctrl+mouse: Crosshair \n # Ctrl+B: Toggle buffering\n # Ctrl+G: Toggle background subtraction\n # Ctrl+F: Empty buffer\n # Ctrl+C: Start tracking\n # Ctrl+V: Stop tracking\n # Ctrl+M: Autosave on\n # Ctrl+N: Autosave off\n # Ctrl+S: Save image\n # Ctrl+W: Start waterfall\n # Ctrl+Q: Exit application\n # Ctrl+Shift+W: Save waterfall data\n # Ctrl+Shift+T: Save trajectory\n # """) def setupActions(self): """Setups the actions that the program will have. It is placed into a function to make it easier to reuse in other windows. :rtype: None """ self.exitAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/power-icon.png'), '&Exit', self) self.exitAction.setShortcut('Ctrl+Q') self.exitAction.setStatusTip('Exit application') self.exitAction.triggered.connect(self.exitSafe) self.saveAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/floppy-icon.png'), '&Save image', self) self.saveAction.setShortcut('Ctrl+S') self.saveAction.setStatusTip('Save Image') self.saveAction.triggered.connect(self.saveImage) self.showHelpAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/info-icon.png'), 'Show cheatsheet', self) self.showHelpAction.setShortcut(QtCore.Qt.Key_F1) self.showHelpAction.setStatusTip('Show Cheatsheet') self.showHelpAction.triggered.connect(self.showHelp) self.saveWaterfallAction = QtGui.QAction("Save Waterfall", self) self.saveWaterfallAction.setShortcut('Ctrl+Shift+W') self.saveWaterfallAction.setStatusTip( 'Save waterfall data to new file') self.saveWaterfallAction.triggered.connect(self.saveWaterfall) self.saveTrajectoryAction = QtGui.QAction("Save Trajectory", self) self.saveTrajectoryAction.setShortcut('Ctrl+Shift+T') self.saveTrajectoryAction.setStatusTip( 'Save trajectory data to new file') self.saveTrajectoryAction.triggered.connect(self.saveTrajectory) self.snapAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/snap.png'), 'S&nap photo', self) self.snapAction.setShortcut(QtCore.Qt.Key_F5) self.snapAction.setStatusTip('Snap Image') self.snapAction.triggered.connect(self.snap) self.movieAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/video-icon.png'), 'Start &movie', self) self.movieAction.setShortcut(QtCore.Qt.Key_F6) self.movieAction.setStatusTip('Start Movie') self.movieAction.triggered.connect(self.startMovie) self.movieSaveStartAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Download-Database-icon.png'), 'Continuous saves', self) self.movieSaveStartAction.setShortcut('Ctrl+M') self.movieSaveStartAction.setStatusTip('Continuous save to disk') self.movieSaveStartAction.triggered.connect(self.movieSave) self.movieSaveStopAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Delete-Database-icon.png'), 'Stop continuous saves', self) self.movieSaveStopAction.setShortcut('Ctrl+N') self.movieSaveStopAction.setStatusTip('Stop continuous save to disk') self.movieSaveStopAction.triggered.connect(self.movieSaveStop) self.startWaterfallAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Blue-Waterfall-icon.png'), 'Start &Waterfall', self) self.startWaterfallAction.setShortcut('Ctrl+W') self.startWaterfallAction.setStatusTip('Start Waterfall') self.startWaterfallAction.triggered.connect(self.startWaterfall) self.toggleBGAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/noBg.png'), 'Toggle B&G-reduction', self) self.toggleBGAction.setShortcut('Ctrl+G') self.toggleBGAction.setStatusTip('Toggle Background Reduction') self.toggleBGAction.triggered.connect(self.start_tracking) self.setROIAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Zoom-In-icon.png'), 'Set &ROI', self) self.setROIAction.setShortcut('Ctrl+T') self.setROIAction.setStatusTip('Set ROI') self.setROIAction.triggered.connect(self.getROI) self.clearROIAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Zoom-Out-icon.png'), 'Set R&OI', self) self.clearROIAction.setShortcut('Ctrl+T') self.clearROIAction.setStatusTip('Clear ROI') self.clearROIAction.triggered.connect(self.clearROI) self.accumulateBufferAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/disk-save.png'), 'Accumulate buffer', self) self.accumulateBufferAction.setShortcut('Ctrl+B') self.accumulateBufferAction.setStatusTip( 'Start or stop buffer accumulation') self.accumulateBufferAction.triggered.connect(self.bufferStatus) self.clearBufferAction = QtGui.QAction('Clear Buffer', self) self.clearBufferAction.setShortcut('Ctrl+F') self.clearBufferAction.setStatusTip('Clears the buffer') self.clearBufferAction.triggered.connect(self.emptyQueue) self.viewerAction = QtGui.QAction('Start Viewer', self) # self.viewerAction.triggered.connect(self.camViewer.show) self.configAction = QtGui.QAction('Config Window', self) # self.configAction.triggered.connect(self.config.show) self.dockAction = QtGui.QAction('Restore Docks', self) self.dockAction.triggered.connect(self.setupDocks) self.crossCutAction = QtGui.QAction( QtGui.QIcon('pynta/View/GUI/Icons/Ruler-icon.png'), 'Show cross cut', self) # self.crossCutAction.triggered.connect(self.crossCut.show) self.settingsAction = QtGui.QAction('Load config', self) # self.settingsAction.triggered.connect(self.selectSettings.show) def setupToolbar(self): """Setups the toolbar with the desired icons. It's placed into a function to make it easier to reuse in other windows. """ self.toolbar = self.addToolBar('Exit') self.toolbar.addAction(self.exitAction) self.toolbar2 = self.addToolBar('Image') self.toolbar2.addAction(self.saveAction) self.toolbar2.addAction(self.snapAction) self.toolbar2.addAction(self.crossCutAction) self.toolbar3 = self.addToolBar('Movie') self.toolbar3.addAction(self.movieAction) self.toolbar3.addAction(self.movieSaveStartAction) self.toolbar3.addAction(self.movieSaveStopAction) self.toolbar4 = self.addToolBar('Extra') self.toolbar4.addAction(self.startWaterfallAction) self.toolbar4.addAction(self.setROIAction) self.toolbar4.addAction(self.clearROIAction) self.toolbar4.addAction(self.clearROIAction) self.toolbar4.addAction(self.toggleBGAction) self.toolbar5 = self.addToolBar('Help') self.toolbar5.addAction(self.showHelpAction) def setupMenubar(self): """Setups the menubar. """ menubar = self.menuBar() self.fileMenu = menubar.addMenu('&File') self.fileMenu.addAction(self.settingsAction) self.fileMenu.addAction(self.saveAction) self.fileMenu.addAction(self.exitAction) self.snapMenu = menubar.addMenu('&Snap') self.snapMenu.addAction(self.snapAction) self.snapMenu.addAction(self.saveAction) self.movieMenu = menubar.addMenu('&Movie') self.movieMenu.addAction(self.movieAction) self.movieMenu.addAction(self.movieSaveStartAction) self.movieMenu.addAction(self.movieSaveStopAction) self.movieMenu.addAction(self.startWaterfallAction) self.configMenu = menubar.addMenu('&Configure') self.configMenu.addAction(self.toggleBGAction) self.configMenu.addAction(self.setROIAction) self.configMenu.addAction(self.clearROIAction) self.configMenu.addAction(self.accumulateBufferAction) self.configMenu.addAction(self.clearBufferAction) self.configMenu.addAction(self.viewerAction) self.configMenu.addAction(self.configAction) self.configMenu.addAction(self.dockAction) self.saveMenu = menubar.addMenu('S&ave') self.snapMenu.addAction(self.saveAction) self.saveMenu.addAction(self.saveWaterfallAction) self.saveMenu.addAction(self.saveTrajectoryAction) self.helpMenu = menubar.addMenu('&Help') self.helpMenu.addAction(self.showHelpAction) def setupDocks(self): """Setups the docks in order to recover the initial configuration if one gets closed.""" for d in self.docks: try: d.close() except: pass self.docks = [] self.dmainImage = Dock("Camera", size=(80, 35)) #sizes are in percentage self.dwaterfall = Dock("Waterfall", size=(80, 35)) self.dparams = Dock("Parameters", size=(20, 100)) self.dtraj = Dock("Trajectory", size=(40, 30)) # self.dstatus = Dock("Status", size=(100, 3)) self.area.addDock(self.dmainImage, 'right') self.area.addDock(self.dparams, 'left', self.dmainImage) self.area.addDock(self.dtraj, 'bottom', self.dmainImage) self.area.addDock(self.dmessage, 'right', self.dtraj) self.docks.append(self.dmainImage) self.docks.append(self.dtraj) self.docks.append(self.dmessage) self.docks.append(self.dparams) self.docks.append(self.dwaterfall) # self.area.addDock(self.dstatus, 'bottom', self.dparams) self.dmainImage.addWidget(self.camWidget) self.dparams.addWidget(self.config) self.dtraj.addWidget(self.trajectoryWidget) self.dock_state = self.area.saveState() def setupSignals(self): """Setups all the signals that are going to be handled during the excution of the program.""" self.connect(self._session, QtCore.SIGNAL('updated'), self.config.populateTree) self.connect(self.config, QtCore.SIGNAL('updateSession'), self.updateSession) self.connect(self.camWidget, QtCore.SIGNAL('specialTask'), self.startSpecialTask) self.connect(self.camWidget, QtCore.SIGNAL('stopSpecialTask'), self.stopSpecialTask) self.connect(self.camViewer, QtCore.SIGNAL('stopMainAcquisition'), self.stopMovie) self.connect(self, QtCore.SIGNAL('stopChildMovie'), self.camViewer.stopCamera) self.connect(self, QtCore.SIGNAL('closeAll'), self.camViewer.closeViewer) self.connect(self.selectSettings, QtCore.SIGNAL("settings"), self.update_settings) self.connect(self, QtCore.SIGNAL('closeAll'), self.selectSettings.close) def snap(self): """Function for acquiring a single frame from the camera. It is triggered by the user. It gets the data the GUI will be updated at a fixed framerate. """ if self.experiment.acquiring: #If it is itself acquiring a message is displayed to the user warning him msgBox = QtGui.QMessageBox() msgBox.setIcon(QtGui.QMessageBox.Critical) msgBox.setText("You cant snap a photo while in free run") msgBox.setInformativeText("The program is already acquiring data") msgBox.setWindowTitle("Already acquiring") msgBox.setDetailedText( """When in free run, you can\'t trigger another acquisition. \n You should stop the free run acquisition and then snap a photo.""" ) msgBox.setStandardButtons(QtGui.QMessageBox.Ok) retval = msgBox.exec_() self.messageWidget.appendLog('e', 'Tried to snap while in free run') else: self.experiment.snap() # self.messageWidget.appendLog('i', 'Snapped photo') def toggleBGReduction(self): """Toggles between background cancellation modes. Takes a background snap if necessary """ if self.subtract_background: self.subtract_background = False self.messageWidget.appendLog('i', 'Background reduction deactivated') else: if len(self.tempimage) == 0: self.snap() self.messageWidget.appendLog('i', 'Snapped an image as background') else: self.subtract_background = True self.bgimage = self.tempimage.astype(float) self.messageWidget.appendLog('i', 'Background reduction active') def saveImage(self): """Saves the image that is being displayed to the user. """ if len(self.tempimage) >= 1: # Data will be appended to existing file fn = self._session.Saving['filename_photo'] filename = '%s.hdf5' % (fn) fileDir = self._session.Saving['directory'] if not os.path.exists(fileDir): os.makedirs(fileDir) f = h5py.File(os.path.join(fileDir, filename), "a") now = str(datetime.now()) g = f.create_group(now) dset = g.create_dataset('image', data=self.tempimage) meta = g.create_dataset('metadata', data=self._session.serialize()) f.flush() f.close() self.messageWidget.appendLog('i', 'Saved photo') def startMovie(self): self.experiment.start_free_run() def stopMovie(self): if self.acquiring: self.workerThread.keep_acquiring = False while self.workerThread.isRunning(): pass self.acquiring = False self.camera.stopAcq() self.messageWidget.appendLog('i', 'Continuous run stopped') if self.continuous_saving: self.movieSaveStop() def movieData(self): """Function just to trigger and read the camera in the separate thread. """ self.workerThread.start() def movieSave(self): """Saves the data accumulated in the queue continuously. """ if not self.continuous_saving: # Child process to save the data. It runs continuously until and exit flag # is passed through the Queue. (self.q.put('exit')) self.accumulate_buffer = True if len(self.tempimage) > 1: im_size = self.tempimage.nbytes max_element = int(self._session.Saving['max_memory'] / im_size) #self.q = Queue(0) fn = self._session.Saving['filename_video'] filename = '%s.hdf5' % (fn) fileDir = self._session.Saving['directory'] if not os.path.exists(fileDir): os.makedirs(fileDir) to_save = os.path.join(fileDir, filename) metaData = self._session.serialize( ) # This prints a YAML-ready version of the session. self.p = Process(target=workerSaver, args=( to_save, metaData, self.q, )) # self.p.start() self.continuous_saving = True self.messageWidget.appendLog('i', 'Continuous autosaving started') else: self.messageWidget.appendLog( 'w', 'Continuous savings already triggered') def movieSaveStop(self): """Stops the saving to disk. It will however flush the queue. """ if self.continuous_saving: self.q.put('Stop') self.accumulate_buffer = False #self.p.join() self.messageWidget.appendLog('i', 'Continuous autosaving stopped') self.continuous_saving = False def emptyQueue(self): """Clears the queue. """ # Worker thread for clearing the queue. self.clearWorker = Process(target=clearQueue, args=(self.q, )) self.clearWorker.start() def startWaterfall(self): """Starts the waterfall. The waterfall can be accelerated if camera supports hardware binning in the appropriate direction. If not, has to be done via software but the acquisition time cannot be improved. TODO: Fast waterfall should have separate window, since the acquisition of the full CCD will be stopped. """ if not self.show_waterfall: self.watWidget = waterfallWidget() self.area.addDock(self.dwaterfall, 'bottom', self.dmainImage) self.dwaterfall.addWidget(self.watWidget) self.show_waterfall = True Sx, Sy = self.camera.getSize() self.waterfall_data = np.zeros( (self._session.GUI['length_waterfall'], Sx)) self.watWidget.img.setImage(np.transpose(self.waterfall_data), autoLevels=False, autoRange=False, autoHistogramRange=False) self.messageWidget.appendLog('i', 'Waterfall opened') else: self.closeWaterfall() def stopWaterfall(self): """Stops the acquisition of the waterfall. """ pass def closeWaterfall(self): """Closes the waterfall widget. """ if self.show_waterfall: self.watWidget.close() self.dwaterfall.close() self.show_waterfall = False del self.waterfall_data self.messageWidget.appendLog('i', 'Waterfall closed') def setROI(self, X, Y): """ Gets the ROI from the lines on the image. It also updates the GUI to accommodate the changes. :param X: :param Y: :return: """ if not self.acquiring: self.corner_roi[0] = X[0] self.corner_roi[1] = Y[0] if self._session.Debug['to_screen']: print('Corner: %s, %s' % (self.corner_roi[0], self.corner_roi[1])) self._session.Camera = {'roi_x1': int(X[0])} self._session.Camera = {'roi_x2': int(X[1])} self._session.Camera = {'roi_y1': int(Y[0])} self._session.Camera = {'roi_y2': int(Y[1])} self.messageWidget.appendLog('i', 'Updated roi_x1: %s' % int(X[0])) self.messageWidget.appendLog('i', 'Updated roi_x2: %s' % int(X[1])) self.messageWidget.appendLog('i', 'Updated roi_y1: %s' % int(Y[0])) self.messageWidget.appendLog('i', 'Updated roi_y2: %s' % int(Y[1])) Nx, Ny = self.camera.setROI(X, Y) Sx, Sy = self.camera.getSize() self.current_width = Sx self.current_height = Sy self.tempimage = np.zeros((Nx, Ny)) self.camWidget.hline1.setValue(1) self.camWidget.hline2.setValue(Ny) self.camWidget.vline1.setValue(1) self.camWidget.vline2.setValue(Nx) self.trackinfo = np.zeros((1, 5)) #self.camWidget.img2.clear() if self.show_waterfall: self.waterfall_data = np.zeros( (self._session.GUI['length_waterfall'], self.current_width)) self.watWidget.img.setImage(np.transpose(self.waterfall_data)) self.config.populateTree(self._session) self.messageWidget.appendLog('i', 'Updated the ROI') else: self.messageWidget.appendLog('e', 'Cannot change ROI while acquiring.') def getROI(self): """Gets the ROI coordinates from the GUI and updates the values.""" y1 = np.int(self.camWidget.hline1.value()) y2 = np.int(self.camWidget.hline2.value()) x1 = np.int(self.camWidget.vline1.value()) x2 = np.int(self.camWidget.vline2.value()) X = np.sort((x1, x2)) Y = np.sort((y1, y2)) # Updates to the real values X += self.corner_roi[0] - 1 Y += self.corner_roi[1] - 1 self.setROI(X, Y) def clearROI(self): """Resets the roi to the full image. """ if not self.acquiring: self.camWidget.hline1.setValue(1) self.camWidget.vline1.setValue(1) self.camWidget.vline2.setValue(self.max_sizex) self.camWidget.hline2.setValue(self.max_sizey) self.corner_roi = [1, 1] self.getROI() else: self.messageWidget.appendLog('e', 'Cannot change ROI while acquiring.') def bufferStatus(self): """Starts or stops the buffer accumulation. """ if self.accumulate_buffer: self.accumulate_buffer = False self.messageWidget.appendLog('i', 'Buffer accumulation stopped') else: self.accumulate_buffer = True self.messageWidget.appendLog('i', 'Buffer accumulation started') def getData(self, data, origin): """Gets the data that is being gathered by the working thread. .. _getData: .. data: single image or a list of images (saved in buffer) .. origin: indicates which command has trigerred execution of this method (e.g. 'snap' of 'movie') both input variables are handed it through QThread signal that is "emit"ted """ s = 0 if origin == 'snap': # Single snap. self.acquiring = False self.workerThread.origin = None self.workerThread.keep_acquiring = False # This already happens in the worker thread itself. self.camera.stopAcq() if isinstance(data, list): for d in data: if self.accumulate_buffer: s = float(self.q.qsize()) * int(d.nbytes) / 1024 / 1024 if s < self._session.Saving['max_memory']: self.q.put(d) else: self.droppedframes += 1 if self.show_waterfall: if self.watindex == self._session.GUI['length_waterfall']: if self._session.Saving['autosave_trajectory']: self.saveWaterfall() self.waterfall_data = np.zeros( (self._session.GUI['length_waterfall'], self.current_width)) self.watindex = 0 centerline = np.int(self.current_height / 2) vbinhalf = np.int(self._session.GUI['vbin_waterfall']) if vbinhalf >= self.current_height / 2 - 1: wf = np.array([np.sum(d, 1)]) else: wf = np.array([ np.sum( d[:, centerline - vbinhalf:centerline + vbinhalf], 1) ]) self.waterfall_data[self.watindex, :] = wf self.watindex += 1 self.totalframes += 1 self.tempimage = d else: self.tempimage = data if self.accumulate_buffer: s = float(self.q.qsize()) * int(data.nbytes) / 1024 / 1024 if s < self._session.Saving['max_memory']: self.q.put(data) else: self.droppedframes += 1 if self.show_waterfall: if self.watindex == self._session.GUI['length_waterfall']: # checks if the buffer variable for waterfall image is full, saves it if requested, and sets it to zero. if self._session.Saving['autosave_trajectory']: self.saveWaterfall() self.waterfall_data = np.zeros( (self._session.GUI['length_waterfall'], self.current_width)) self.watindex = 0 centerline = np.int(self.current_height / 2) vbinhalf = np.int(self._session.GUI['vbin_waterfall'] / 2) if vbinhalf >= self.current_height - 1: wf = np.array([np.sum(data, 1)]) else: wf = np.array([ np.sum( data[:, centerline - vbinhalf:centerline + vbinhalf], 1) ]) self.waterfall_data[self.watindex, :] = wf self.watindex += 1 self.totalframes += 1 new_time = time.time() self.buffertime = new_time - self.lastBuffer self.lastBuffer = new_time self.buffer_memory = s if self._session.Debug['queue_memory']: print('Queue Memory: %3.2f MB' % self.buffer_memory) def updateGUI(self): """Updates the image displayed to the user. """ if self.experiment.temp_image is not None: img = self.experiment.temp_image self.camWidget.img.setImage(img.astype(int), autoLevels=False, autoRange=False, autoHistogramRange=False) if self.experiment.link_particles_running: self.camWidget.draw_target_pointer( self.experiment.localize_particles_image(img)) def saveWaterfall(self): """Saves the waterfall data, if any. """ if len(self.waterfall_data) > 1: fn = self._session.Saving['filename_waterfall'] filename = '%s.hdf5' % (fn) fileDir = self._session.Saving['directory'] if not os.path.exists(fileDir): os.makedirs(fileDir) f = h5py.File(os.path.join(fileDir, filename), "a") now = str(datetime.now()) g = f.create_group(now) dset = g.create_dataset('waterfall', data=self.waterfall_data) meta = g.create_dataset('metadata', data=self._session.serialize().encode( "ascii", "ignore")) f.flush() f.close() self.messageWidget.appendLog('i', 'Saved Waterfall') def saveTrajectory(self): """Saves the trajectory data, if any. """ if len(self.trackinfo) > 1: fn = self._session.Saving['filename_trajectory'] filename = '%s.hdf5' % (fn) fileDir = self._session.Saving['directory'] if not os.path.exists(fileDir): os.makedirs(fileDir) f = h5py.File(os.path.join(fileDir, filename), "a") now = str(datetime.now()) g = f.create_group(now) dset = g.create_dataset('trajectory', data=[self.trackinfo]) meta = g.create_dataset('metadata', data=self._session.serialize().encode( "ascii", "ignore")) f.flush() f.close() self.messageWidget.appendLog('i', 'Saved Trajectory') def update_settings(self, settings): new_session = _session(settings) self.updateSession(new_session) self.config.populateTree(self._session) def updateSession(self, session): """Updates the session variables passed by the config window. """ update_cam = False update_roi = False update_exposure = False update_binning = True for k in session.params['Camera']: new_prop = session.params['Camera'][k] old_prop = self._session.params['Camera'][k] if new_prop != old_prop: update_cam = True if k in ['roi_x1', 'roi_x2', 'roi_y1', 'roi_y2']: update_roi = True if self._session.Debug['to_screen']: print('Update ROI') elif k == 'exposure_time': update_exposure = True elif k in ['binning_x', 'binning_y']: update_binning = True if session.GUI['length_waterfall'] != self._session.GUI[ 'length_waterfall']: if self.show_waterfall: self.closeWaterfall() self.restart_waterfall = True self.messageWidget.appendLog('i', 'Parameters updated') self.messageWidget.appendLog( 'i', 'Measurement: %s' % session.User['measurement']) self._session = session.copy() if update_cam: if self.acquiring: self.stopMovie() if update_roi: X = np.sort( [session.Camera['roi_x1'], session.Camera['roi_x2']]) Y = np.sort( [session.Camera['roi_y1'], session.Camera['roi_y2']]) self.setROI(X, Y) if update_exposure: new_exp = self.camera.setExposure( session.Camera['exposure_time']) self._session.Camera = {'exposure_time': new_exp} self.messageWidget.appendLog('i', 'Updated exposure: %s' % new_exp) if self._session.Debug['to_screen']: print("New Exposure: %s" % new_exp) print(self._session) if update_binning: self.camera.setBinning(session.Camera['binning_x'], session.Camera['binning_y']) self.refreshTimer.stop() self.refreshTimer.start(session.GUI['refresh_time']) def startSpecialTask(self): """Starts a special task. This is triggered by the user with a special combination of actions, for example clicking with the mouse on a plot, draggin a crosshair, etc.""" if not self.specialtask_running: if self.acquiring: self.stopMovie() self.acquiring = False locy = self.camWidget.crosshair[0].getPos()[1] locx = self.camWidget.crosshair[1].getPos()[0] self.trackinfo = np.zeros((1, 5)) self.trajectoryWidget.plot.clear() imgsize = self.tempimage.shape iniloc = [locx, locy] self.specialTaskWorker = specialTaskTracking( self._session, self.camera, self.noiselvl, imgsize, iniloc) self.connect(self.specialTaskWorker, QtCore.SIGNAL('image'), self.getData) self.connect(self.specialTaskWorker, QtCore.SIGNAL('coordinates'), self.getParticleLocation) self.specialTaskWorker.start() self.specialtask_running = True self.messageWidget.appendLog('i', 'Live tracking started') else: print('Special task already running') def stopSpecialTask(self): """Stops the special task""" if self.specialtask_running: self.specialTaskWorker.keep_running = False self.specialtask_running = False if self._session.Saving['autosave_trajectory'] == True: self.saveTrajectory() self.messageWidget.appendLog('i', 'Live tracking stopped') def done(self): #self.saveRunning = False self.acquiring = False def exitSafe(self): self.close() def closeEvent(self, evnt): """ Triggered at closing. Checks that the save is complete and closes the dataFile """ self.experiment.finalize() # self.messageWidget.appendLog('i', 'Closing the program') # if self.acquiring: # self.stopMovie() # if self.specialtask_running: # self.stopSpecialTask() # while self.specialTaskWorker.isRunning(): # pass # self.emit(QtCore.SIGNAL('closeAll')) # self.camera.stopCamera() # self.movieSaveStop() # try: # # Checks if the process P exists and tries to close it. # if self.p.is_alive(): # qs = self.q.qsize() # with ProgressDialog("Finish saving data...", 0, qs) as dlg: # while self.q.qsize() > 1: # dlg.setValue(qs - self.q.qsize()) # time.sleep(0.5) # self.p.join() # except AttributeError: # pass # if self.q.qsize() > 0: # self.messageWidget.appendLog('i', 'The queue was not empty') # print('Freeing up memory...') # self.emptyQueue() # # # Save LOG. # fn = self._session.Saving['filename_log'] # timestamp = datetime.now().strftime('%H%M%S') # filename = '%s%s.log' % (fn, timestamp) # fileDir = self._session.Saving['directory'] # if not os.path.exists(fileDir): # os.makedirs(fileDir) # # f = open(os.path.join(fileDir,filename), "a") # for line in self.messageWidget.logText: # f.write(line+'\n') # f.flush() # f.close() # print('Saved LOG') super(MainWindow, self).closeEvent(evnt)
class DockAreaTabWidgetBase(QtGui.QWidget): def __init__(self, *args, **kwargs): self.main = kwargs.pop("main") tabName = kwargs.pop("tabName") QtGui.QWidget.__init__(self, *args, **kwargs) self.setObjectName(tabName) self._layout = QtGui.QGridLayout(self) def _InitDocks(self): # Define docking area if hasattr(self, "_dockArea"): self._dockArea.setParent(None) self._dockArea = DockArea() self._plotDocks = self._defaultDockPos.keys() # Add dock to area for dock, pos in self._defaultDockPos.iteritems(): self._dockArea.addDock(dock, *pos) self._layout.addWidget(self._dockArea, 0, 0, 1, 1) def Shown(self): self.DrawFrame() def DrawFrame(self, clear=True): if clear: self.ClearPlots() for dock in self._plotDocks: if not dock.automaticDraw: continue dock.DrawPlot() def ClearPlots(self): for dock in self._plotDocks: if not dock.automaticDraw: continue dock.ClearPlot() def AutoscalePlots(self): for dock in self._plotDocks: if not dock.automaticDraw: continue dock.Autoscale() def SaveState(self): res = {} res["dockingState"] = self._dockArea.saveState() for dock in self._plotDocks: res["dock_" + dock.name()] = dock.SaveState() return res def SetState(self, state): try: if "dockingState" in state: self._dockArea.restoreState(state["dockingState"]) except: print "Docking area restore failed, restoring defaults:" traceback.print_exc() print "Restore defaults" self._InitDocks() for dock in self._plotDocks: stateName = "dock_" + dock.name() if stateName in state: dock.SetState(state[stateName])
class AWGOptimizer(Form, Base): def __init__(self, deviceClass, config, parent=None): Base.__init__(self, parent) Form.__init__(self) Form.setupUi(self, self) self.config = config self.configname = "AWGOptimizer" self.setWindowTitle("AWG Optimizer") guiState = self.config.get(self.configname + ".guiState") state = self.config.get(self.configname + '.state') pos = self.config.get(self.configname + '.pos') size = self.config.get(self.configname + '.size') isMaximized = self.config.get(self.configname + '.isMaximized') restoreGuiState(self, self.config.get(self.configname + ".guiState")) if state: self.restoreState(state) if pos: self.move(pos) if size: self.resize(size) if isMaximized: self.showMaximized() self.show() self.awgUi = AWGUi(deviceClass, config, dict()) self.awgUi.setupUi(self.awgUi) self.splitter.insertWidget(1, self.awgUi) #oscilloscope plot window name = "Oscilloscope Trace" self.scopeDock = Dock(name) self.scopePlot = CoordinatePlotWidget(self, name=name) self.scopeView = self.scopePlot._graphicsView self.scopeDock.addWidget(self.scopePlot) self.area = DockArea() self.area.addDock(self.scopeDock) self.plotDict = { name: { "dock": self.scopeDock, "widget": self.scopePlot, "view": self.scopeView } } self.verticalLayout.insertWidget(0, self.area) #trace ui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, self.configname, self.plotDict, hasMeasurementLog=False, highlightUnsaved=False) self.traceui.setupUi(self.traceui) traceDock = Dock("Traces") traceDock.addWidget(self.traceui) self.area.addDock(traceDock, 'left') self.device = self.awgUi.device self.measureWaveformButton.clicked.connect(self.onMeasureWaveform) self.optimizeButton.clicked.connect(self.onOptimize) dockAreaState = self.config.get(self.configname + '.dockAreaState') try: if dockAreaState: self.area.restoreState(dockAreaState) except Exception as e: print(e) def saveConfig(self): self.config[self.configname + ".guiState"] = saveGuiState(self) self.config[self.configname + '.state'] = self.saveState() self.config[self.configname + '.pos'] = self.pos() self.config[self.configname + '.size'] = self.size() self.config[self.configname + '.isMaximized'] = self.isMaximized() self.config[self.configname + '.dockAreaState'] = self.area.saveState() self.awgUi.saveConfig() def closeEvent(self, e): self.saveConfig() def onMeasureWaveform(self): pass def onOptimize(self): pass
class MainWindow(QMainWindow, Ui_MainWindow): """Where all the action happens.""" def __init__(self, settings): super(MainWindow, self).__init__() self.settings = settings self.setupUi(self) # MainWindow is a collection of widgets in their respective docks. # We make DockArea our central widget self.dock_area = DockArea() self.setCentralWidget(self.dock_area) self.createDocks() self.initAfterCreatingDockWidgets() self.loadSettings() self.connectSignalsToSlots() # all signals in place, send out the first image # self.image_browser.populateAndEmitImageInfo() self.image_browser.initialEmit() self.roi_editor_h.initialEmit() self.roi_editor_v.initialEmit() self.roi_editor_int.initialEmit() self.roi_editor_err.initialEmit() self.loadPlugins() def loadPlugins(self): """Looks for all plugins and creates menu entries, signals and slots for them.""" self.pluginSignalMapper = QSignalMapper(self) for p in plugin_list: click_action = QAction(p.name, self) self.menuPlugins.addAction(click_action) self.connect(click_action, SIGNAL("triggered()"), self.pluginSignalMapper, SLOT("map()")) self.pluginSignalMapper.setMapping(click_action, QString(p.name)) self.connect(self.pluginSignalMapper, SIGNAL("mapped(const QString &)"), self.image_browser.handlePluginClicked) def createDocks(self): """Create all dock widgets and add them to DockArea.""" self.image_view = ImageView(self.settings, self) self.image_browser = ImageBrowser(self.settings, self) self.fitter = Fitter(self.settings, self) self.roi_editor_h = RoiEditor(self.settings, self.image_view, self, name='ROIH', pen=(1, 9), axis=1) self.roi_editor_v = RoiEditor(self.settings, self.image_view, self, name='ROIV', pen=(1, 1), axis=0) self.roi_editor_int = RoiEditor(self.settings, self.image_view, self, name='ROI Int', pen=(1, 2), axis=1) self.roi_editor_err = RoiEditor(self.settings, self.image_view, self, name='ROI Err', pen=(1, 3), axis=1) self.roi_plot_h = Plot1d(parent=self, title='ROI H') self.roi_plot_v = Plot1d(parent=self, title='ROI V') self.analyzer = Analyzer(self.settings, parent=self) # Create docks for all widgets self.dock_image_view = Dock('Image View', widget=self.image_view) self.dock_image_browser = Dock('Image Browser', widget=self.image_browser) self.dock_fitter = Dock('Fitter', widget=self.fitter) self.dock_roi_h = Dock('ROIH', widget=self.roi_editor_h) self.dock_roi_v = Dock('ROIV', widget=self.roi_editor_v) self.dock_roi_int = Dock('ROI Int', widget=self.roi_editor_int) self.dock_roi_err = Dock('ROI Err', widget=self.roi_editor_err) self.dock_roi_plot_h = Dock('ROIH Plot', widget=self.roi_plot_h) self.dock_roi_plot_v = Dock('ROIV Plot', widget=self.roi_plot_v) self.dock_analyzer = Dock('Analyze', widget=self.analyzer) self.dock_area.addDock(self.dock_image_view, position='top') self.dock_area.addDock(self.dock_image_browser, position='right', relativeTo=self.dock_image_view) self.dock_area.addDock(self.dock_fitter, position='left', relativeTo=self.dock_image_view) self.dock_area.addDock(self.dock_roi_h, position='bottom', relativeTo=self.dock_fitter) self.dock_area.addDock(self.dock_roi_v, position='below', relativeTo=self.dock_roi_h) self.dock_area.addDock(self.dock_roi_int, position='below', relativeTo=self.dock_roi_v) self.dock_area.addDock(self.dock_roi_err, position='below', relativeTo=self.dock_roi_int) self.dock_area.addDock(self.dock_roi_plot_h, position='below', relativeTo=self.dock_image_view) self.dock_area.addDock(self.dock_roi_plot_v, position='right', relativeTo=self.dock_roi_plot_h) self.dock_area.addDock(self.dock_analyzer, position='top', relativeTo=self.dock_image_browser) def initAfterCreatingDockWidgets(self): self.setWindowTitle(self.image_browser.current_directory) def connectSignalsToSlots(self): self.actionOpen_Directory.triggered.connect(self.image_browser.handleOpenDirectoryAction) self.actionDark_File.triggered.connect(self.image_browser.handleDarkFileAction) self.actionRefresh.triggered.connect(self.image_browser.handleRefreshAction) self.actionSave.triggered.connect(self.image_browser.handleSaveAnalysis) self.image_browser.windowTitleChanged.connect(self.setWindowTitle) # self.image_browser.imageChanged.connect(self.image_view.handleImageChanged) self.image_browser.imageChanged.connect(self.fitter.handleImageChanged) self.image_browser.imageChanged.connect(self.analyzer.handleImageChanged) self.roi_editor_int.roiChanged.connect(self.image_browser.handleRoiChanged) self.roi_editor_err.roiChanged.connect(self.image_browser.handleROIErrChanged) self.roi_editor_h.roiChanged.connect(self.image_browser.handleROIHChanged) self.roi_editor_v.roiChanged.connect(self.image_browser.handleROIVChanged) self.roi_editor_h.roiChanged.connect(self.fitter.handleROIHChanged) self.roi_editor_h.roiChanged.connect(self.analyzer.handleROIHChanged) self.roi_editor_v.roiChanged.connect(self.fitter.handleROIVChanged) self.roi_editor_v.roiChanged.connect(self.analyzer.handleROIVChanged) self.roi_editor_int.roiChanged.connect(self.fitter.handleROIIntChanged) self.roi_editor_int.roiChanged.connect(self.analyzer.handleROIIntChanged) self.roi_editor_err.roiChanged.connect(self.fitter.handleROIErrChanged) self.roi_editor_err.roiChanged.connect(self.analyzer.handleROIErrChanged) self.image_view.doubleClicked.connect(self.roi_editor_h.centerROI) self.image_view.doubleClicked.connect(self.roi_editor_v.centerROI) self.fitter.imageChanged.connect(self.image_view.handleImageChanged) self.fitter.horDataChanged.connect(self.roi_plot_h.handleDataChanged) self.fitter.verDataChanged.connect(self.roi_plot_v.handleDataChanged) self.fitter.doneFitting.connect(self.analyzer.handleDoneFitting) def loadSettings(self): """Load window state from self.settings""" self.settings.beginGroup('mainwindow') geometry = self.settings.value('geometry').toByteArray() state = self.settings.value('windowstate').toByteArray() dock_string = str(self.settings.value('dockstate').toString()) if dock_string is not "": dock_state = eval(dock_string) self.dock_area.restoreState(dock_state) self.settings.endGroup() self.restoreGeometry(geometry) self.restoreState(state) def saveSettings(self): """Save window state to self.settings.""" self.settings.beginGroup('mainwindow') self.settings.setValue('geometry', self.saveGeometry()) self.settings.setValue('windowstate', self.saveState()) dock_state = self.dock_area.saveState() # dock_state returned here is a python dictionary. Coundn't find a good # way to save dicts in QSettings, hence just using representation # of it. self.settings.setValue('dockstate', repr(dock_state)) self.settings.endGroup() def closeEvent(self, event): self.saveSettings() self.image_browser.saveSettings() self.roi_editor_int.saveSettings() self.roi_editor_err.saveSettings() self.roi_editor_v.saveSettings() self.roi_editor_h.saveSettings() self.analyzer.saveSettings() super(MainWindow, self).closeEvent(event) def setWindowTitle(self, newTitle=''): """Prepend IP-BEC to all window titles.""" title = 'IP-BEC: ' + newTitle super(MainWindow, self).setWindowTitle(title)
class InstrumentLoggingUi(WidgetContainerBase, WidgetContainerForm): plotConfigurationChanged = QtCore.pyqtSignal( object ) def __init__(self, project, config): super(InstrumentLoggingUi, self).__init__() self.config = config self.project = project self.dockWidgetList = list() self.plotDict = dict() self.instrument = "" def __enter__(self): return self def __exit__(self, excepttype, value, traceback): return False def setupUi(self, parent): super(InstrumentLoggingUi, self).setupUi(parent) logger = logging.getLogger() self.parent = parent self.tabList = list() self.tabDict = dict() self.setupPlots() # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict ) self.traceui.setupUi(self.traceui) self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # new fit widget self.fitWidget = FitUi(self.traceui, self.config, "Main") self.fitWidget.setupUi(self.fitWidget) self.fitWidgetDock = self.setupAsDockWidget(self.fitWidget, "Fit", QtCore.Qt.LeftDockWidgetArea) self.instrumentLoggingHandler = InstrumentLoggingHandler(self.traceui, self.plotDict, self.config, 'externalInput') self.ExternalParametersSelectionUi = InstrumentLoggingSelection(self.config, classdict=LoggingInstruments, newDataSlot=self.instrumentLoggingHandler.addData, plotNames=list(self.plotDict.keys()), instrumentLoggingHandler=self.instrumentLoggingHandler ) self.ExternalParametersSelectionUi.setupUi( self.ExternalParametersSelectionUi ) self.ExternalParameterSelectionDock = QtWidgets.QDockWidget("Params Selection") self.ExternalParameterSelectionDock.setObjectName("_ExternalParameterSelectionDock") self.ExternalParameterSelectionDock.setWidget(self.ExternalParametersSelectionUi) self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.ExternalParameterSelectionDock) self.instrumentLoggingHandler.paramTreeChanged.connect( self.ExternalParametersSelectionUi.refreshParamTree) self.instrumentLoggingDisplay = InstrumentLoggingDisplay(self.config) self.instrumentLoggingDisplay.setupUi( self.ExternalParametersSelectionUi.enabledParametersObjects, self.instrumentLoggingDisplay ) self.instrumentLoggingDisplayDock = QtWidgets.QDockWidget("Params Reading") self.instrumentLoggingDisplayDock.setObjectName("_ExternalParameterDisplayDock") self.instrumentLoggingDisplayDock.setWidget(self.instrumentLoggingDisplay) self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.instrumentLoggingDisplayDock) self.ExternalParametersSelectionUi.selectionChanged.connect( self.instrumentLoggingDisplay.setupParameters ) self.instrumentLoggingHandler.newData.connect( self.instrumentLoggingDisplay.update ) self.instrumentLoggingQueryUi = InstrumentLoggerQueryUi(self.config, self.traceui, self.plotDict ) self.instrumentLoggingQueryUi.setupUi( self.instrumentLoggingQueryUi ) self.instrumentLoggingQueryUiDock = self.setupAsDockWidget(self.instrumentLoggingQueryUi, "Query", QtCore.Qt.LeftDockWidgetArea) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle("Instrument Logger ({0})".format(self.project) ) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.warning("Cannot restore dock state in experiment {0}. Exception occurred: ".format(self.experimentName) + str(e)) QtCore.QTimer.singleShot(60000, self.onCommitConfig ) def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get( 'PlotNames', ['Scan'] ) if len(plotNames)<1: plotNames.append('Scan') for name in plotNames: dock = Dock(name) widget = DateTimePlotWidget(self, name=name) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None ): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget( widget ) self.addDockWidget(area, dock ) self.dockWidgetList.append( dock ) if stackAbove is not None: self.tabifyDockWidget( stackAbove, dock ) elif stackBelow is not None: self.tabifyDockWidget( dock, stackBelow ) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText(self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = DateTimePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} self.plotConfigurationChanged.emit( self.plotDict ) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText(self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be renamed") def onSave(self): logger = logging.getLogger(__name__) logger.info( "Saving config" ) filename, _ = DataDirectory.DataDirectory().sequencefile("InstrumentLogger-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onClose(self): self.parent.close() def closeEvent(self, e): logger = logging.getLogger(__name__) logger.info( "Close Event" ) logger = logging.getLogger("") logger.debug( "Saving Configuration" ) self.saveConfig() def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in self.tabList: tab.saveConfig() self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.ExternalParametersSelectionUi.saveConfig() self.instrumentLoggingHandler.saveConfig() self.instrumentLoggingQueryUi.saveConfig() self.instrumentLoggingDisplay.saveConfig() def onCommitConfig(self): self.saveConfig() QtCore.QTimer.singleShot(60000, self.onCommitConfig )
class WidgetBase(BaseClassTemplate): def __init__(self, parent=None, hideHistograms=False) -> None: BaseClassTemplate.__init__(self, parent=parent) self.uiBase = BaseWidgetTemplate() self.uiBase.setupUi(self) ############################################################# # ATTRIBUTES # ############################################################# self.gui_timer = QTimer() # type: QTimer self.gui_timer.timeout.connect(self.updateDisplay) if self.uiBase.wao_Display.isChecked(): self.gui_timer.start(1000. / self.uiBase.wao_frameRate.value()) self.loopLock = threading.Lock( ) # type: Threading.Lock # Asynchronous loop / display safe-threading self.hideHistograms = hideHistograms ############################################################# # PYQTGRAPH DockArea INIT # ############################################################# self.area = DockArea() self.uiBase.wao_DisplayDock.setWidget(self.area) self.gridSH = [] ############################################################# # CONNECTED BUTTONS # ############################################################# # Default path for config files self.defaultParPath = "." self.defaultAreaPath = "." self.uiBase.wao_loadConfig.clicked.connect(self.loadConfig) self.uiBase.wao_loadArea.clicked.connect(self.loadArea) self.uiBase.wao_saveArea.clicked.connect(self.saveArea) self.uiBase.wao_init.clicked.connect(self.initConfig) self.uiBase.wao_configFromFile.clicked.connect(self.addConfigFromFile) self.uiBase.wao_Display.stateChanged.connect(self.gui_timer_config) self.uiBase.wao_frameRate.setValue(2) self.uiBase.wao_loadConfig.setDisabled(False) self.uiBase.wao_init.setDisabled(True) self.disp_checkboxes = [] self.docks = {} # type: Dict[str, pg.dockarea.Dock] self.viewboxes = {} # type: Dict[str, pg.ViewBox] self.imgs = {} # type: Dict[str, pg.ImageItem] self.hists = {} # type: Dict[str, pg.HistogramLUTItem] self.PupilLines = None self.adjustSize() def gui_timer_config(self, state) -> None: self.uiBase.wao_frameRate.setDisabled(state) if state: self.gui_timer.start(1000. / self.uiBase.wao_frameRate.value()) else: self.gui_timer.stop() def closeEvent(self, event: Any) -> None: self.quitGUI(event) def quitGUI(self, event: Any = None) -> None: reply = QtWidgets.QMessageBox.question( self, 'Message', "Are you sure to quit?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: if event: event.accept() quit() else: if event: event.ignore() ############################################################# # METHODS # ############################################################# def saveArea(self, widget, filename=None): ''' Callback when a area layout file is double clicked in the file browser Place the selected file name in the browsing drop-down menu, the call the self.loadConfig callback of the load button. ''' if filename is None: filepath = QtWidgets.QFileDialog( directory=self.defaultAreaPath).getSaveFileName( self, "Select area layout file", "", "area layout file (*.area);;all files (*)") filename = filepath[0] try: with open(filename, "w+") as f: st = self.area.saveState() f.write(str(st)) except FileNotFoundError as err: warnings.warn(filename + " not loaded: " + err) def showDock(self, name): for disp_checkbox in self.disp_checkboxes: if disp_checkbox.text() == name: disp_checkbox.setChecked(True) break if name in self.docks.keys(): self.area.addDock(self.docks[name]) def restoreMyState(self, state): typ, contents, _ = state if typ == 'dock': self.showDock(contents) else: for o in contents: self.restoreMyState(o) def loadArea(self, widget=None, filename=None): # close all docks for disp_checkbox in self.disp_checkboxes: disp_checkbox.setChecked(False) for dock in self.docks.values(): if dock.isVisible(): dock.close() if filename is None: filepath = QtWidgets.QFileDialog( directory=self.defaultAreaPath).getOpenFileName( self, "Select area layout file", "", "area layout file (*.area);;all files (*)") filename = filepath[0] try: with open(filename, "r") as f: st = eval(f.readline()) # restore docks from main area if st['main'] is not None: self.restoreMyState(st["main"]) # restore docks from floating area for win in st["float"]: self.restoreMyState(win[0]['main']) # rearange dock s as in stored state self.area.restoreState(st) except FileNotFoundError as err: warnings.warn(filename + "not loaded: " + err) def addConfigFromFile(self) -> None: ''' Callback when a config file is double clicked in the file browser Place the selected file name in the browsing drop-down menu, the call the self.loadConfig callback of the load button. ''' filepath = QtWidgets.QFileDialog( directory=self.defaultParPath).getOpenFileName( self, "Select parameter file", "", "parameters file (*.py);;hdf5 file (*.h5);;all files (*)") self.uiBase.wao_selectConfig.clear() self.uiBase.wao_selectConfig.addItem(str(filepath[0])) self.loadConfig(configFile=self.uiBase.wao_selectConfig.currentText()) def update_displayDock(self): guilty_guy = self.sender().text() state = self.sender().isChecked() if state: self.area.addDock(self.docks[guilty_guy]) elif self.docks[guilty_guy].isVisible(): self.docks[guilty_guy].close() def add_dispDock(self, name: str, parent, type: str = "pg_image") -> Dock: checkBox = QtGui.QCheckBox(name, parent) checkBox.clicked.connect(self.update_displayDock) checkableAction = QtGui.QWidgetAction(parent) checkableAction.setDefaultWidget(checkBox) parent.addAction(checkableAction) self.disp_checkboxes.append(checkBox) d = Dock(name) # , closable=True) self.docks[name] = d if type == "pg_image": img = pg.ImageItem(border='w') self.imgs[name] = img viewbox = pg.ViewBox() viewbox.setAspectLocked(True) viewbox.addItem(img) # Put image in plot area self.viewboxes[name] = viewbox iv = pg.ImageView(view=viewbox, imageItem=img) viewbox.invertY(False) if (self.hideHistograms): iv.ui.histogram.hide() iv.ui.histogram.autoHistogramRange() # init levels iv.ui.histogram.setMaximumWidth(100) iv.ui.menuBtn.hide() iv.ui.roiBtn.hide() d.addWidget(iv) elif type == "pg_plot": img = pg.PlotItem(border='w') self.imgs[name] = img d.addWidget(img) elif type == "MPL": img = MatplotlibWidget() self.imgs[name] = img d.addWidget(img) # elif type == "SR": # d.addWidget(self.uiBase.wao_Strehl) return d def loadConfig(self, *args, **kwargs) -> None: ''' Callback when 'LOAD' button is hit ''' for groupbox in [ self.uiBase.wao_phasesgroup_tb, self.uiBase.wao_imagesgroup_tb, self.uiBase.wao_graphgroup_tb ]: layout = groupbox.menu() while layout and not layout.isEmpty(): w = layout.children()[0] layout.removeAction(w) w.setParent(None) self.disp_checkboxes.clear() # TODO: remove self.imgs, self.viewboxes and self.docks children for _, dock in self.docks.items(): if dock.isVisible(): dock.close() self.docks.clear() self.imgs.clear() self.viewboxes.clear() self.wao_phasesgroup_cb = QtGui.QMenu(self) self.uiBase.wao_phasesgroup_tb.setMenu(self.wao_phasesgroup_cb) self.uiBase.wao_phasesgroup_tb.setText('Select') self.uiBase.wao_phasesgroup_tb.setPopupMode( QtWidgets.QToolButton.InstantPopup) self.wao_graphgroup_cb = QtGui.QMenu(self) self.uiBase.wao_graphgroup_tb.setMenu(self.wao_graphgroup_cb) self.uiBase.wao_graphgroup_tb.setText('Select') self.uiBase.wao_graphgroup_tb.setPopupMode( QtWidgets.QToolButton.InstantPopup) self.uiBase.wao_imagesgroup_tb.setText('Select') self.wao_imagesgroup_cb = QtGui.QMenu(self) self.uiBase.wao_imagesgroup_tb.setMenu(self.wao_imagesgroup_cb) self.uiBase.wao_imagesgroup_tb.setPopupMode( QtWidgets.QToolButton.InstantPopup) # self.uiBase.wao_init.setDisabled(False) # # if (hasattr(self.sim.config, "layout")): # area_filename = self.defaultAreaPath + "/" + self.sim.config.layout + ".area" # self.loadArea(filename=area_filename) # # self.adjustSize() def loadDefaultConfig(self) -> None: import glob parlist = sorted(glob.glob(self.defaultParPath + "/*.py")) self.uiBase.wao_selectConfig.clear() self.uiBase.wao_selectConfig.addItems( [parlist[i].split('/')[-1] for i in range(len(parlist))]) def initConfig(self) -> None: self.loopLock.acquire(True) self.uiBase.wao_loadConfig.setDisabled(True) self.uiBase.wao_init.setDisabled(True) self.thread = WorkerThread(self.initConfigThread) self.thread.finished.connect(self.initConfigFinished) self.thread.start() def initConfigThread(self) -> None: pass def initConfigFinished(self) -> None: self.uiBase.wao_loadConfig.setDisabled(False) self.uiBase.wao_init.setDisabled(False) self.loopLock.release() def updateDisplay(self) -> None: if not self.loopLock.acquire(False): return else: try: pass finally: self.loopLock.release() def addSHGrid(self, pg_image, valid_sub, sspsize, pitch): # First remove the old grid, if any if self.PupilLines is not None: pg_image.removeItem(self.PupilLines) nssp_tot = valid_sub[0].size connect = np.ones((nssp_tot, 5), dtype=bool) connect[:, -1] = 0 # don't draw the segment between each trace roi_x = np.ones((nssp_tot, 5), dtype=int) roi_y = np.ones((nssp_tot, 5), dtype=int) for idx_ssp in range(nssp_tot): (x, y) = (valid_sub[0][idx_ssp], valid_sub[1][idx_ssp]) roi_x[idx_ssp, :] = [x, x, x + sspsize, x + sspsize, x] roi_y[idx_ssp, :] = [y, y + sspsize, y + sspsize, y, y] self.PupilLines = PupilBoxes(roi_x, roi_y) pg_image.addItem(self.PupilLines) def printInPlace(self, text: str) -> None: # This seems to trigger the GUI and keep it responsive print(text, end='\r', flush=True) def run(self): self.loopOnce() if not self.stop: QTimer.singleShot(0, self.run) # Update loop
class AWGUi(AWGForm, AWGBase): varDictChanged = QtCore.pyqtSignal(object) def __init__(self, deviceClass, config, globalDict, parent=None): AWGBase.__init__(self, parent) AWGForm.__init__(self) self.config = config self.configname = 'AWGUi.' + deviceClass.displayName self.globalDict = globalDict self.autoSave = self.config.get(self.configname + '.autoSave', True) self.waveformCache = OrderedDict() self.settingsDict = self.config.get(self.configname + '.settingsDict', dict()) self.settingsName = self.config.get(self.configname + '.settingsName', '') # self.settingsDict=dict() # self.settingsName='' self.recentFiles = self.config.get( self.configname + '.recentFiles', dict() ) #dict of form {basename: filename}, where filename has path and basename doesn't self.lastDir = self.config.get(self.configname + '.lastDir', getProject().configDir) Settings.deviceProperties = deviceClass.deviceProperties Settings.saveIfNecessary = self.saveIfNecessary Settings.replot = self.replot for settings in list( self.settingsDict.values() ): #make sure all pickled settings are consistent with device, in case it changed for channel in range(deviceClass.deviceProperties['numChannels']): if channel >= len(settings.channelSettingsList ): #create new channels if it's necessary settings.channelSettingsList.append({ 'segmentDataRoot': AWGSegmentNode(None), 'segmentTreeState': None, 'plotEnabled': True, 'plotStyle': Settings.plotStyles.lines }) else: settings.channelSettingsList[channel].setdefault( 'segmentDataRoot', AWGSegmentNode(None)) settings.channelSettingsList[channel].setdefault( 'segmentTreeState', None) settings.channelSettingsList[channel].setdefault( 'plotEnabled', True) settings.channelSettingsList[channel].setdefault( 'plotStyle', Settings.plotStyles.lines) self.settings = Settings( ) #we always run settings through the constructor if self.settingsName in self.settingsDict: self.settings.update(self.settingsDict[self.settingsName]) self.device = deviceClass(self.settings) def setupUi(self, parent): logger = logging.getLogger(__name__) AWGForm.setupUi(self, parent) self.setWindowTitle(self.device.displayName) self._varAsOutputChannelDict = dict() self.area = DockArea() self.splitter.insertWidget(0, self.area) self.awgChannelUiList = [] for channel in range(self.device.deviceProperties['numChannels']): awgChannelUi = AWGChannelUi(channel, self.settings, self.globalDict, self.waveformCache, parent=self) awgChannelUi.setupUi(awgChannelUi) awgChannelUi.dependenciesChanged.connect( self.onDependenciesChanged) self.awgChannelUiList.append(awgChannelUi) dock = Dock("AWG Channel {0}".format(channel)) dock.addWidget(awgChannelUi) self.area.addDock(dock, 'right') self.device.waveforms[channel] = awgChannelUi.waveform self.refreshVarDict() # Settings control self.saveButton.clicked.connect(self.onSave) self.removeButton.clicked.connect(self.onRemove) self.reloadButton.clicked.connect(self.onReload) self.settingsModel = QtCore.QStringListModel() self.settingsComboBox.setModel(self.settingsModel) self.settingsModel.setStringList(sorted(self.settingsDict.keys())) self.settingsComboBox.setCurrentIndex( self.settingsComboBox.findText(self.settingsName)) self.settingsComboBox.currentIndexChanged[str].connect(self.onLoad) self.settingsComboBox.lineEdit().editingFinished.connect( self.onComboBoxEditingFinished) self.autoSaveCheckBox.setChecked(self.autoSave) self.saveButton.setEnabled(not self.autoSave) self.saveButton.setVisible(not self.autoSave) self.reloadButton.setEnabled(not self.autoSave) self.reloadButton.setVisible(not self.autoSave) self.autoSaveCheckBox.stateChanged.connect(self.onAutoSave) #programming options table self.programmingOptionsTable.setupUi( globalDict=self.globalDict, parameterDict=self.device.parameters()) self.programmingOptionsTable.valueChanged.connect(self.device.update) # Table self.tableModel = AWGTableModel(self.settings, self.globalDict) self.tableView.setModel(self.tableModel) self.tableModel.valueChanged.connect(self.onValue) self.delegate = MagnitudeSpinBoxDelegate(self.globalDict) self.tableView.setItemDelegateForColumn(self.tableModel.column.value, self.delegate) #File self.filenameModel = QtCore.QStringListModel() self.filenameComboBox.setModel(self.filenameModel) self.filenameModel.setStringList([ basename for basename, filename in list(self.recentFiles.items()) if os.path.exists(filename) ]) self.filenameComboBox.setCurrentIndex( self.filenameComboBox.findText( os.path.basename(self.settings.filename))) self.filenameComboBox.currentIndexChanged[str].connect(self.onFilename) self.removeFileButton.clicked.connect(self.onRemoveFile) self.newFileButton.clicked.connect(self.onNewFile) self.openFileButton.clicked.connect(self.onOpenFile) self.saveFileButton.clicked.connect(self.onSaveFile) self.reloadFileButton.clicked.connect(self.onReloadFile) #cache self.cacheDepthSpinBox.setValue(self.settings.cacheDepth) self.cacheDepthSpinBox.valueChanged.connect(self.onCacheDepth) self.clearCacheButton.clicked.connect(self.onClearCache) #status bar self.label = QtGui.QLabel('Sample Rate: {0}'.format( self.settings.deviceProperties['sampleRate'])) self.statusbar.addWidget(self.label) #Restore GUI state state = self.config.get(self.configname + '.state') pos = self.config.get(self.configname + '.pos') size = self.config.get(self.configname + '.size') isMaximized = self.config.get(self.configname + '.isMaximized') dockAreaState = self.config.get(self.configname + '.dockAreaState') guiState = self.config.get(self.configname + ".guiState") restoreGuiState(self, guiState) try: if pos: self.move(pos) if size: self.resize(size) if isMaximized: self.showMaximized() if state: self.restoreState(state) for awgChannelUi in self.awgChannelUiList: channelGuiState = self.config[ self.configname + "channel{0}.guiState".format(awgChannelUi.channel)] restoreGuiState(awgChannelUi, channelGuiState) except Exception as e: logger.warning( "Error on restoring state in AWGUi {0}. Exception occurred: {1}" .format(self.device.displayName, e)) try: if dockAreaState: self.area.restoreState(dockAreaState) except Exception as e: logger.warning( "Cannot restore dock state in AWGUi {0}. Exception occurred: {1}" .format(self.device.displayName, e)) self.area.deleteLater() self.area = DockArea() self.splitter.insertWidget(0, self.area) for channelUi in self.awgChannelUiList: dock = Dock("AWG Channel {0}".format(channel)) dock.addWidget(channelUi) self.area.addDock(dock, 'right') self.saveIfNecessary() def onCacheDepth(self, newVal): self.settings.cacheDepth = newVal self.saveIfNecessary() def onClearCache(self): self.waveformCache.clear() def onComboBoxEditingFinished(self): """a settings name is typed into the combo box""" currentText = str(self.settingsComboBox.currentText()) if self.settingsName != currentText: self.settingsName = currentText if self.settingsName not in self.settingsDict: self.settingsDict[self.settingsName] = copy.deepcopy( self.settings) self.onLoad(self.settingsName) def saveIfNecessary(self): """save the current settings if autosave is on and something has changed""" currentText = str(self.settingsComboBox.currentText()) if self.settingsDict.get( self.settingsName ) != self.settings or currentText != self.settingsName: if self.autoSave: self.onSave() else: self.saveButton.setEnabled(True) def replot(self): """plot all channels""" for channelUi in self.awgChannelUiList: channelUi.replot() def onSave(self): """save current settings""" self.settingsName = str(self.settingsComboBox.currentText()) self.settingsDict[self.settingsName] = copy.deepcopy(self.settings) with BlockSignals(self.settingsComboBox) as w: self.settingsModel.setStringList(sorted(self.settingsDict.keys())) w.setCurrentIndex(w.findText(self.settingsName)) self.saveButton.setEnabled(False) def saveConfig(self): """save GUI configuration to config""" self.config[self.configname + ".guiState"] = saveGuiState(self) for awgChannelUi in self.awgChannelUiList: self.config[self.configname + "channel{0}.guiState".format( awgChannelUi.channel)] = saveGuiState(awgChannelUi) self.settings.channelSettingsList[awgChannelUi.channel][ 'segmentTreeState'] = awgChannelUi.segmentView.saveTreeState() self.config[self.configname + '.state'] = self.saveState() self.config[self.configname + '.pos'] = self.pos() self.config[self.configname + '.size'] = self.size() self.config[self.configname + '.isMaximized'] = self.isMaximized() self.config[self.configname + '.isVisible'] = self.isVisible() self.config[self.configname + '.dockAreaState'] = self.area.saveState() self.config[self.configname + '.settingsDict'] = self.settingsDict self.config[self.configname + '.settingsName'] = self.settingsName self.config[self.configname + '.autoSave'] = self.autoSave self.config[self.configname + '.recentFiles'] = self.recentFiles self.config[self.configname + '.lastDir'] = self.lastDir def onRemove(self): """Remove current settings from combo box""" name = str(self.settingsComboBox.currentText()) if name in self.settingsDict: self.settingsDict.pop(name) self.settingsName = list( self.settingsDict.keys())[0] if self.settingsDict else '' with BlockSignals(self.settingsComboBox) as w: self.settingsModel.setStringList( sorted(self.settingsDict.keys())) w.setCurrentIndex(w.findText(self.settingsName)) self.onLoad(self.settingsName) def onReload(self): """Reload settings""" name = str(self.settingsComboBox.currentText()) self.onLoad(name) def onLoad(self, name): """load settings""" for channelUi in self.awgChannelUiList: self.settings.channelSettingsList[channelUi.channel][ 'segmentTreeState'] = channelUi.segmentView.saveTreeState() name = str(name) if name in self.settingsDict: self.settingsName = name self.tableModel.beginResetModel() [ channelUi.segmentModel.beginResetModel() for channelUi in self.awgChannelUiList ] self.settings.update(self.settingsDict[self.settingsName]) self.programmingOptionsTable.setParameters( self.device.parameters()) self.saveButton.setEnabled(False) with BlockSignals(self.filenameComboBox) as w: w.setCurrentIndex( w.findText(os.path.basename(self.settings.filename))) with BlockSignals(self.cacheDepthSpinBox) as w: w.setValue(self.settings.cacheDepth) for channelUi in self.awgChannelUiList: channelUi.waveform.updateDependencies() channelUi.plotCheckbox.setChecked( self.settings.channelSettingsList[ channelUi.channel]['plotEnabled']) with BlockSignals(channelUi.styleComboBox) as w: w.setCurrentIndex(self.settings.channelSettingsList[ channelUi.channel]['plotStyle']) channelUi.segmentModel.root = self.settings.channelSettingsList[ channelUi.channel]['segmentDataRoot'] channelUi.replot() self.onDependenciesChanged() self.saveButton.setEnabled(False) self.tableModel.endResetModel() [ channelUi.segmentModel.endResetModel() for channelUi in self.awgChannelUiList ] for channelUi in self.awgChannelUiList: channelUi.segmentView.restoreTreeState( self.settings.channelSettingsList[ channelUi.channel]['segmentTreeState']) def onAutoSave(self, checked): """autosave is changed""" self.autoSave = checked self.saveButton.setEnabled(not checked) self.saveButton.setVisible(not checked) self.reloadButton.setEnabled(not checked) self.reloadButton.setVisible(not checked) if checked: self.onSave() def onValue(self, var=None, value=None): """variable value is changed in the table""" self.saveIfNecessary() self.replot() def evaluate(self, name): """re-evaluate the text in the tableModel (happens when a global changes)""" self.tableModel.evaluate(name) self.programmingOptionsTable.evaluate(name) def refreshVarDict(self): """refresh the variable dictionary by checking all waveform dependencies""" allDependencies = set() [ channelUi.waveform.updateDependencies() for channelUi in self.awgChannelUiList ] [ allDependencies.update(channelUi.waveform.dependencies) for channelUi in self.awgChannelUiList ] default = lambda varname: { 'value': Q(1, 'us'), 'text': None } if varname.startswith('Duration') else { 'value': Q(0), 'text': None } deletions = [ varname for varname in self.settings.varDict if varname not in allDependencies ] [self.settings.varDict.pop(varname) for varname in deletions ] #remove all values that aren't dependencies anymore [ self.settings.varDict.setdefault(varname, default(varname)) for varname in allDependencies ] #add missing values self.settings.varDict.sort(key=lambda val: -1 if val[0].startswith( 'Duration') else ord(str(val[0])[0])) self.varDictChanged.emit(self.varAsOutputChannelDict) for channelUi in self.awgChannelUiList: channelUi.replot() def onDependenciesChanged(self, channel=None): """When dependencies change, refresh all variables""" self.tableModel.beginResetModel() self.refreshVarDict() self.tableModel.endResetModel() self.saveIfNecessary() def onFilename(self, basename): """filename combo box is changed. Open selected file""" basename = str(basename) filename = self.recentFiles[basename] if os.path.isfile(filename) and filename != self.settings.filename: self.openFile(filename) def onRemoveFile(self): """Remove file button is clicked. Remove filename from combo box.""" text = str(self.filenameComboBox.currentText()) index = self.filenameComboBox.findText(text) if text in self.recentFiles: self.recentFiles.pop(text) with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(-1) self.onFilename(w.currentText()) def onNewFile(self): """New button is clicked. Pop up dialog asking for new name, and create file.""" filename, _ = QtWidgets.QFileDialog.getSaveFileName( self, 'New File', self.lastDir, 'YAML (*.yml)') if filename: self.lastDir, basename = os.path.split(filename) self.recentFiles[basename] = filename self.settings.filename = filename with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(w.findText(basename)) self.onSaveFile() def onOpenFile(self): """Open file button is clicked. Pop up dialog asking for filename.""" filename, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Select File', self.lastDir, 'YAML (*.yml)') if filename: self.openFile(filename) def openFile(self, filename): """Open the file 'filename'""" if os.path.exists(filename): self.lastDir, basename = os.path.split(filename) self.recentFiles[basename] = filename self.settings.filename = filename with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(w.findText(basename)) with open(filename, 'r') as f: yamldata = yaml.load(f) variables = yamldata.get('variables') channelData = yamldata.get('channelData') self.tableModel.beginResetModel() [ channelUi.segmentModel.beginResetModel() for channelUi in self.awgChannelUiList ] if channelData: for channelUi in self.awgChannelUiList: if channelUi.channel < len(channelData): self.settings.channelSettingsList[channelUi.channel][ 'segmentDataRoot'] = self.convertListToNodes( channelData[channelUi.channel], isRoot=True) channelUi.segmentModel.root = self.settings.channelSettingsList[ channelUi.channel]['segmentDataRoot'] if variables: for varname, vardata in list(variables.items()): self.settings.varDict.setdefault(varname, dict()) self.settings.varDict[varname]['value'] = Q( vardata['value'], vardata['unit']) self.settings.varDict[varname]['text'] = vardata['text'] for channelUi in self.awgChannelUiList: channelUi.waveform.updateDependencies() channelUi.replot() self.onDependenciesChanged() self.tableModel.endResetModel() [ channelUi.segmentModel.endResetModel() for channelUi in self.awgChannelUiList ] [ channelUi.segmentView.expandAll() for channelUi in self.awgChannelUiList ] else: logging.getLogger(__name__).warning( "file '{0}' does not exist".format(filename)) if filename in self.recentFiles: del self.recentFiles[filename] with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList( list(self.recentFiles.keys())) w.setCurrentIndex(-1) def convertNodeToList(self, node): nodeList = [] for childNode in node.children: if childNode.nodeType == nodeTypes.segment: nodeList.append({ 'equation': childNode.equation, 'duration': childNode.duration, 'enabled': childNode.enabled }) elif childNode.nodeType == nodeTypes.segmentSet: nodeList.append({ 'repetitions': childNode.repetitions, 'enabled': childNode.enabled, 'segments': self.convertNodeToList(childNode) }) return nodeList def convertListToNodes(self, data, parent=None, enabled=True, repetitions=None, isRoot=False): node = AWGSegmentNode(parent=None) if isRoot else AWGSegmentSet( parent=parent, enabled=enabled, repetitions=repetitions) for segment in data: if 'duration' in segment: childNode = AWGSegment(parent=node, equation=segment['equation'], duration=segment['duration'], enabled=segment['enabled']) node.children.append(childNode) elif 'repetitions' in segment: segmentSet = self.convertListToNodes( segment['segments'], parent=node, enabled=segment['enabled'], repetitions=segment['repetitions']) node.children.append(segmentSet) else: logging.getLogger(__name__).error( "Unable to convert list to nodes") return node def onSaveFile(self): """Save button is clicked. Save data to segment file""" channelData = [] for channelSettings in self.settings.channelSettingsList: segmentData = self.convertNodeToList( channelSettings['segmentDataRoot']) channelData.append(segmentData) yamldata = {'channelData': channelData} variables = { varname: { 'value': float(varValueTextDict['value'].toStringTuple()[0]), 'unit': varValueTextDict['value'].toStringTuple()[1], 'text': varValueTextDict['text'] } for varname, varValueTextDict in list( self.settings.varDict.items()) } yamldata.update({'variables': variables}) with open(self.settings.filename, 'w') as f: yaml.dump(yamldata, f, default_flow_style=False) def onReloadFile(self): self.openFile(self.settings.filename) @QtCore.pyqtProperty(dict) def varAsOutputChannelDict(self): """dict of output channels, for use in scans""" for varname in self.settings.varDict: if varname not in self._varAsOutputChannelDict: self._varAsOutputChannelDict[varname] = VarAsOutputChannel( self, varname, self.globalDict) deletions = [ varname for varname in self._varAsOutputChannelDict if varname not in self.settings.varDict ] [self._varAsOutputChannelDict.pop(varname) for varname in deletions ] #remove all values that aren't dependencies anymore return self._varAsOutputChannelDict def close(self): self.saveConfig() numTempAreas = len(self.area.tempAreas) for i in range(numTempAreas): if len(self.area.tempAreas) > 0: self.area.tempAreas[0].win.close() super(AWGUi, self).close()
class AWGOptimizer(Form, Base): def __init__(self, deviceClass, config, parent=None): Base.__init__(self, parent) Form.__init__(self) Form.setupUi(self, self) self.config = config self.configname = "AWGOptimizer" self.setWindowTitle("AWG Optimizer") guiState = self.config.get(self.configname+".guiState") state = self.config.get(self.configname+'.state') pos = self.config.get(self.configname+'.pos') size = self.config.get(self.configname+'.size') isMaximized = self.config.get(self.configname+'.isMaximized') restoreGuiState(self, self.config.get(self.configname+".guiState")) if state: self.restoreState(state) if pos: self.move(pos) if size: self.resize(size) if isMaximized: self.showMaximized() self.show() self.awgUi = AWGUi(deviceClass, config, dict()) self.awgUi.setupUi(self.awgUi) self.splitter.insertWidget(1, self.awgUi) #oscilloscope plot window name = "Oscilloscope Trace" self.scopeDock = Dock(name) self.scopePlot = CoordinatePlotWidget(self, name=name) self.scopeView = self.scopePlot._graphicsView self.scopeDock.addWidget(self.scopePlot) self.area = DockArea() self.area.addDock(self.scopeDock) self.plotDict ={name: {"dock":self.scopeDock, "widget":self.scopePlot, "view":self.scopeView}} self.verticalLayout.insertWidget(0, self.area) #trace ui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, self.configname, self.plotDict, hasMeasurementLog=False, highlightUnsaved=False) self.traceui.setupUi(self.traceui) traceDock = Dock("Traces") traceDock.addWidget(self.traceui) self.area.addDock(traceDock, 'left') self.device = self.awgUi.device self.measureWaveformButton.clicked.connect(self.onMeasureWaveform) self.optimizeButton.clicked.connect(self.onOptimize) dockAreaState = self.config.get(self.configname+'.dockAreaState') try: if dockAreaState: self.area.restoreState(dockAreaState) except Exception as e: print(e) def saveConfig(self): self.config[self.configname+".guiState"] = saveGuiState(self) self.config[self.configname+'.state'] = self.saveState() self.config[self.configname+'.pos'] = self.pos() self.config[self.configname+'.size'] = self.size() self.config[self.configname+'.isMaximized'] = self.isMaximized() self.config[self.configname+'.dockAreaState'] = self.area.saveState() self.awgUi.saveConfig() def closeEvent(self, e): self.saveConfig() def onMeasureWaveform(self): pass def onOptimize(self): pass
class PicoampMeterUi(WidgetContainerBase, WidgetContainerForm): levelNameList = ["debug", "info", "warning", "error", "critical"] levelValueList = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] plotConfigurationChanged = QtCore.pyqtSignal( object ) def __init__(self, config): self.config = config super(PicoampMeterUi, self).__init__() self.loggingLevel = config.get('Settings.loggingLevel', logging.INFO) self.consoleMaximumLines = config.get('Settings.consoleMaximumLines', 0) self.dockWidgetList = list() if self.loggingLevel not in self.levelValueList: self.loggingLevel = logging.INFO self.plotDict = dict() self.meter = None self.instrument = "" def __enter__(self): self.meter = PicoampMeter() self.meter_2 = PicoampMeter() self.meter_3 = PicoampMeter() return self def __exit__(self, excepttype, value, traceback): self.meter.close() self.meter_2.close() self.meter_3.close() return False def setupUi(self, parent): super(PicoampMeterUi, self).setupUi(parent) self.dockWidgetConsole.hide() self.loggerUi = LoggerLevelsUi(self.config) self.loggerUi.setupUi(self.loggerUi) self.setupAsDockWidget(self.loggerUi, "Logging", QtCore.Qt.NoDockWidgetArea) logger = logging.getLogger() self.toolBar.addWidget(ExceptionLogButton()) self.parent = parent self.tabList = list() self.tabDict = dict() self.setupPlots() # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # PicoampMeter Control self.meterControl = PicoampMeterControl(self.config, self.traceui, self.plotDict, self.parent, self.meter, self.meter_2, self.meter_3) self.meterControl.setupUi(self.meterControl) self.setupAsDockWidget(self.meterControl, "Control", QtCore.Qt.RightDockWidgetArea) self.actionSave.triggered.connect(self.onSave) #self.actionSettings.triggered.connect(self.onSettings) self.actionExit.triggered.connect(self.onClose) self.actionProject.triggered.connect( self.onProjectSelection) self.actionStart.triggered.connect(self.meterControl.onScan) self.actionStop.triggered.connect(self.meterControl.onStop) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle("Digital Lock ({0})".format(project) ) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) self.initMenu() try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.error("Cannot restore dock state in experiment {0}. Exception occurred: ".format(self.experimentName) + str(e)) def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get( 'PlotNames', ['Scan'] ) if len(plotNames)<1: plotNames.append('Scan') for name in plotNames: dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None ): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget( widget ) self.addDockWidget(area, dock ) self.dockWidgetList.append( dock ) if stackAbove is not None: self.tabifyDockWidget( stackAbove, dock ) elif stackBelow is not None: self.tabifyDockWidget( dock, stackBelow ) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText(self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} self.plotConfigurationChanged.emit( self.plotDict ) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText(self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be renamed") def onProjectSelection(self): ProjectSelectionUi.GetProjectSelection() def onSettings(self): self.settingsDialog.show() def onSave(self): logger = logging.getLogger(__name__) logger.info( "Saving config" ) filename, _ = DataDirectory.DataDirectory().sequencefile("digitalLock-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onMessageWrite(self,message,level=logging.DEBUG): if level>= self.loggingLevel: cursor = self.textEditConsole.textCursor() cursor.movePosition(QtGui.QTextCursor.End) if level < logging.ERROR: self.textEditConsole.setTextColor(QtCore.Qt.black) else: self.textEditConsole.setTextColor(QtCore.Qt.red) cursor.insertText(message) self.textEditConsole.setTextCursor(cursor) self.textEditConsole.ensureCursorVisible() def onClose(self): self.parent.close() def closeEvent(self, e): logger = logging.getLogger("") logger.debug( "Saving Configuration" ) self.saveConfig() def initMenu(self): self.menuView.clear() for dock in self.dockWidgetList: self.menuView.addAction(dock.toggleViewAction()) def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in self.tabList: tab.saveConfig() self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['Settings.loggingLevel'] = self.loggingLevel self.config['Settings.consoleMaximumLines'] = self.consoleMaximumLines self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.loggerUi.saveConfig() self.meterControl.saveConfig()
class InstrumentLoggingUi(WidgetContainerBase, WidgetContainerForm): levelNameList = ["debug", "info", "warning", "error", "critical"] levelValueList = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] plotConfigurationChanged = QtCore.pyqtSignal( object ) def __init__(self, project, config): super(InstrumentLoggingUi, self).__init__() self.config = config self.project = project self.dockWidgetList = list() self.plotDict = dict() self.instrument = "" self.loggingLevel = config.get('Settings.loggingLevel', logging.INFO) self.consoleMaximumLines = config.get('Settings.consoleMaximumLinesNew', 100) self.consoleEnable = config.get('Settings.consoleEnable', False) self.printMenu = None if self.loggingLevel not in self.levelValueList: self.loggingLevel = logging.INFO def __enter__(self): return self def __exit__(self, excepttype, value, traceback): return False def setupUi(self, parent): super(InstrumentLoggingUi, self).setupUi(parent) self.dockWidgetConsole.hide() self.loggerUi = LoggerLevelsUi(self.config) self.loggerUi.setupUi(self.loggerUi) self.loggerDock = QtWidgets.QDockWidget("Logging") self.loggerDock.setWidget(self.loggerUi) self.loggerDock.setObjectName("_LoggerDock") self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.loggerDock) self.loggerDock.hide() logger = logging.getLogger() self.toolBar.addWidget(ExceptionLogButton()) # Setup Console Dockwidget self.levelComboBox.addItems(self.levelNameList) self.levelComboBox.currentIndexChanged[int].connect( self.setLoggingLevel ) self.levelComboBox.setCurrentIndex( self.levelValueList.index(self.loggingLevel) ) self.consoleClearButton.clicked.connect( self.onClearConsole ) self.linesSpinBox.valueChanged.connect( self.onConsoleMaximumLinesChanged ) self.linesSpinBox.setValue( self.consoleMaximumLines ) self.checkBoxEnableConsole.stateChanged.connect( self.onEnableConsole ) self.checkBoxEnableConsole.setChecked( self.consoleEnable ) self.parent = parent self.tabDict = SequenceDict() self.setupPlots() self.preferencesUi = PreferencesUi(config, self) self.preferencesUi.setupUi(self.preferencesUi) self.preferencesUiDock = QtWidgets.QDockWidget("Print Preferences") self.preferencesUiDock.setWidget(self.preferencesUi) self.preferencesUiDock.setObjectName("_preferencesUi") self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.preferencesUiDock) # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) setattr(self.traceui, 'autoSaveTraces', self.config.get('autoSaveTraces', False)) self.traceui.autoSaveAction = QtWidgets.QAction('Autosave traces', self.traceui) self.traceui.autoSaveAction.setCheckable(True) self.traceui.autoSaveAction.setChecked(self.traceui.autoSaveTraces) self.traceui.autoSaveAction.triggered.connect(lambda checked: setattr(self.traceui, 'autoSaveTraces', checked)) self.traceui.addAction(self.traceui.autoSaveAction) traceuiDock = self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # new fit widget self.fitWidget = FitUi(self.traceui, self.config, "Main") self.fitWidget.setupUi(self.fitWidget) self.fitWidgetDock = self.setupAsDockWidget(self.fitWidget, "Fit", QtCore.Qt.LeftDockWidgetArea, stackBelow=traceuiDock) self.instrumentLoggingHandler = InstrumentLoggingHandler(self.traceui, self.plotDict, self.config, 'externalInput') self.ExternalParametersSelectionUi = InstrumentLoggingSelection(self.config, classdict=LoggingInstruments, plotNames=list(self.plotDict.keys()), instrumentLoggingHandler=self.instrumentLoggingHandler ) self.ExternalParametersSelectionUi.setupUi( self.ExternalParametersSelectionUi ) self.ExternalParameterSelectionDock = QtWidgets.QDockWidget("Params Selection") self.ExternalParameterSelectionDock.setObjectName("_ExternalParameterSelectionDock") self.ExternalParameterSelectionDock.setWidget(self.ExternalParametersSelectionUi) self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.ExternalParameterSelectionDock) self.instrumentLoggingHandler.paramTreeChanged.connect( self.ExternalParametersSelectionUi.refreshParamTree) self.instrumentLoggingHandler.setInputChannels( self.ExternalParametersSelectionUi.inputChannels() ) self.ExternalParametersSelectionUi.inputChannelsChanged.connect( self.instrumentLoggingHandler.setInputChannels ) self.instrumentLoggingDisplay = InstrumentLoggingDisplay(self.config) self.instrumentLoggingDisplay.setupUi( self.ExternalParametersSelectionUi.inputChannels(), self.instrumentLoggingDisplay ) self.instrumentLoggingDisplayDock = QtWidgets.QDockWidget("Params Reading") self.instrumentLoggingDisplayDock.setObjectName("_ExternalParameterDisplayDock") self.instrumentLoggingDisplayDock.setWidget(self.instrumentLoggingDisplay) self.addDockWidget( QtCore.Qt.RightDockWidgetArea, self.instrumentLoggingDisplayDock) self.ExternalParametersSelectionUi.inputChannelsChanged.connect( self.instrumentLoggingDisplay.setupParameters ) self.instrumentLoggingHandler.newData.connect( self.instrumentLoggingDisplay.update ) self.instrumentLoggingQueryUi = InstrumentLoggerQueryUi(self.config, self.traceui, self.plotDict ) self.instrumentLoggingQueryUi.setupUi( self.instrumentLoggingQueryUi ) self.instrumentLoggingQueryUiDock = self.setupAsDockWidget(self.instrumentLoggingQueryUi, "Query", QtCore.Qt.LeftDockWidgetArea) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle( "Instrument Logger ({0})".format(self.project) ) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.error("Cannot restore dock state in experiment {0}. Exception occurred: ".format(self.experimentName) + str(e)) self.initMenu() self.actionProject.triggered.connect( self.onProjectSelection) self.actionExit.triggered.connect(self.onClose) def onProjectSelection(self): ui = ProjectInfoUi(self.project) ui.show() ui.exec_() def onEnableConsole(self, state): self.consoleEnable = state==QtCore.Qt.Checked def onClearConsole(self): self.textEditConsole.clear() def onConsoleMaximumLinesChanged(self, maxlines): self.consoleMaximumLines = maxlines self.textEditConsole.document().setMaximumBlockCount(maxlines) def setLoggingLevel(self, index): self.loggingLevel = self.levelValueList[index] def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get( 'PlotNames', ['Scan'] ) if len(plotNames)<1: plotNames.append('Scan') for name in plotNames: dock = Dock(name) widget = DateTimePlotWidget(self, name=name) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None ): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget( widget ) self.addDockWidget(area, dock ) self.dockWidgetList.append( dock ) if stackAbove is not None: self.tabifyDockWidget( stackAbove, dock ) elif stackBelow is not None: self.tabifyDockWidget( dock, stackBelow ) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText(self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = DateTimePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} self.plotConfigurationChanged.emit( self.plotDict ) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText(self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be renamed") def onSave(self): logger = logging.getLogger(__name__) logger.info( "Saving config" ) filename, _ = DataDirectory.DataDirectory().sequencefile("InstrumentLogger-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onClose(self): self.parent.close() def onMessageWrite(self,message,level=logging.DEBUG): if self.consoleEnable and level>= self.loggingLevel: cursor = self.textEditConsole.textCursor() cursor.movePosition(QtGui.QTextCursor.End) if level < logging.ERROR: self.textEditConsole.setTextColor(QtCore.Qt.black) else: self.textEditConsole.setTextColor(QtCore.Qt.red) cursor.insertText(message) self.textEditConsole.setTextCursor(cursor) self.textEditConsole.ensureCursorVisible() def closeEvent(self, e): logger = logging.getLogger(__name__) logger.info( "Close Event" ) logger = logging.getLogger("") logger.debug( "Saving Configuration" ) self.saveConfig() def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in list(self.tabDict.values()): tab.saveConfig() self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.config['Settings.loggingLevel'] = self.loggingLevel self.config['Settings.consoleMaximumLinesNew'] = self.consoleMaximumLines self.config['Settings.consoleEnable'] = self.consoleEnable self.config['autoSaveTraces'] = self.traceui.autoSaveTraces self.ExternalParametersSelectionUi.saveConfig() self.instrumentLoggingHandler.saveConfig() self.instrumentLoggingQueryUi.saveConfig() self.preferencesUi.saveConfig() def onPrint(self, target): printer = QtPrintSupport.QPrinter(mode=QtPrintSupport.QPrinter.ScreenResolution) if self.preferencesUi.preferences().printPreferences.doPrint: dialog = QtPrintSupport.QPrintDialog(printer, self) dialog.setWindowTitle("Print Document") if dialog.exec_() != QtWidgets.QDialog.Accepted: return; printer.setResolution(self.preferencesUi.preferences().printPreferences.printResolution) pdfPrinter = QtPrintSupport.QPrinter() pdfPrinter.setOutputFormat(QtPrintSupport.QPrinter.PdfFormat); pdfPrinter.setOutputFileName(DataDirectory.DataDirectory().sequencefile(target+".pdf")[0]) self.doPrint(target, printer, pdfPrinter, self.preferencesUi.preferences().printPreferences) def doPrint(self, target, printer, pdfPrinter, preferences): widget = self.plotDict[target]['widget'] if preferences.savePdf: with SceneToPrint(widget): painter = QtGui.QPainter(pdfPrinter) widget.render( painter ) del painter # create an exporter instance, as an argument give it # the item you wish to export with SceneToPrint(widget, preferences.gridLinewidth, preferences.curveLinewidth): exporter = ImageExporter(widget._graphicsView.scene()) # set export parameters if needed pageWidth = printer.pageRect().width() pageHeight = printer.pageRect().height() exporter.parameters()['width'] = pageWidth*preferences.printWidth # (note this also affects height parameter) # save to file png = exporter.export(toBytes=True) if preferences.savePng: png.save(DataDirectory.DataDirectory().sequencefile(target+".png")[0]) if preferences.doPrint: painter = QtGui.QPainter( printer ) painter.drawImage(QtCore.QPoint(pageWidth*preferences.printX, pageHeight*preferences.printY), png) def initMenu(self): """Initialize print menu and view menu""" #View menu self.menuView.clear() dockList = self.findChildren(QtWidgets.QDockWidget) for dock in dockList: self.menuView.addAction(dock.toggleViewAction()) # Print menu if self.printMenu is not None: self.printMenu.clear() else: self.printMenu = self.menuFile.addMenu("Print") for plot in list(self.plotDict.keys()): action = self.printMenu.addAction( plot ) action.triggered.connect( partial(self.onPrint, plot ))
class InstrumentLoggingUi(WidgetContainerBase, WidgetContainerForm): levelNameList = ["debug", "info", "warning", "error", "critical"] levelValueList = [ logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL ] plotConfigurationChanged = QtCore.pyqtSignal(object) def __init__(self, project, config): super(InstrumentLoggingUi, self).__init__() self.config = config self.project = project self.dockWidgetList = list() self.plotDict = dict() self.instrument = "" self.loggingLevel = config.get('Settings.loggingLevel', logging.INFO) self.consoleMaximumLines = config.get( 'Settings.consoleMaximumLinesNew', 100) self.consoleEnable = config.get('Settings.consoleEnable', False) self.printMenu = None if self.loggingLevel not in self.levelValueList: self.loggingLevel = logging.INFO def __enter__(self): return self def __exit__(self, excepttype, value, traceback): return False def setupUi(self, parent): super(InstrumentLoggingUi, self).setupUi(parent) self.dockWidgetConsole.hide() self.loggerUi = LoggerLevelsUi(self.config) self.loggerUi.setupUi(self.loggerUi) self.loggerDock = QtWidgets.QDockWidget("Logging") self.loggerDock.setWidget(self.loggerUi) self.loggerDock.setObjectName("_LoggerDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.loggerDock) self.loggerDock.hide() logger = logging.getLogger() self.toolBar.addWidget(ExceptionLogButton()) # Setup Console Dockwidget self.levelComboBox.addItems(self.levelNameList) self.levelComboBox.currentIndexChanged[int].connect( self.setLoggingLevel) self.levelComboBox.setCurrentIndex( self.levelValueList.index(self.loggingLevel)) self.consoleClearButton.clicked.connect(self.onClearConsole) self.linesSpinBox.valueChanged.connect( self.onConsoleMaximumLinesChanged) self.linesSpinBox.setValue(self.consoleMaximumLines) self.checkBoxEnableConsole.stateChanged.connect(self.onEnableConsole) self.checkBoxEnableConsole.setChecked(self.consoleEnable) self.parent = parent self.tabDict = SequenceDict() self.setupPlots() self.preferencesUi = PreferencesUi(config, self) self.preferencesUi.setupUi(self.preferencesUi) self.preferencesUiDock = QtWidgets.QDockWidget("Print Preferences") self.preferencesUiDock.setWidget(self.preferencesUi) self.preferencesUiDock.setObjectName("_preferencesUi") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.preferencesUiDock) # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) setattr(self.traceui, 'autoSaveTraces', self.config.get('autoSaveTraces', False)) self.traceui.autoSaveAction = QtWidgets.QAction( 'Autosave traces', self.traceui) self.traceui.autoSaveAction.setCheckable(True) self.traceui.autoSaveAction.setChecked(self.traceui.autoSaveTraces) self.traceui.autoSaveAction.triggered.connect( lambda checked: setattr(self.traceui, 'autoSaveTraces', checked)) self.traceui.addAction(self.traceui.autoSaveAction) traceuiDock = self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # new fit widget self.fitWidget = FitUi(self.traceui, self.config, "Main") self.fitWidget.setupUi(self.fitWidget) self.fitWidgetDock = self.setupAsDockWidget( self.fitWidget, "Fit", QtCore.Qt.LeftDockWidgetArea, stackBelow=traceuiDock) self.instrumentLoggingHandler = InstrumentLoggingHandler( self.traceui, self.plotDict, self.config, 'externalInput') self.ExternalParametersSelectionUi = InstrumentLoggingSelection( self.config, classdict=LoggingInstruments, plotNames=list(self.plotDict.keys()), instrumentLoggingHandler=self.instrumentLoggingHandler) self.ExternalParametersSelectionUi.setupUi( self.ExternalParametersSelectionUi) self.ExternalParameterSelectionDock = QtWidgets.QDockWidget( "Params Selection") self.ExternalParameterSelectionDock.setObjectName( "_ExternalParameterSelectionDock") self.ExternalParameterSelectionDock.setWidget( self.ExternalParametersSelectionUi) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.ExternalParameterSelectionDock) self.instrumentLoggingHandler.paramTreeChanged.connect( self.ExternalParametersSelectionUi.refreshParamTree) self.instrumentLoggingHandler.setInputChannels( self.ExternalParametersSelectionUi.inputChannels()) self.ExternalParametersSelectionUi.inputChannelsChanged.connect( self.instrumentLoggingHandler.setInputChannels) self.instrumentLoggingDisplay = InstrumentLoggingDisplay(self.config) self.instrumentLoggingDisplay.setupUi( self.ExternalParametersSelectionUi.inputChannels(), self.instrumentLoggingDisplay) self.instrumentLoggingDisplayDock = QtWidgets.QDockWidget( "Params Reading") self.instrumentLoggingDisplayDock.setObjectName( "_ExternalParameterDisplayDock") self.instrumentLoggingDisplayDock.setWidget( self.instrumentLoggingDisplay) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.instrumentLoggingDisplayDock) self.ExternalParametersSelectionUi.inputChannelsChanged.connect( self.instrumentLoggingDisplay.setupParameters) self.instrumentLoggingHandler.newData.connect( self.instrumentLoggingDisplay.update) self.instrumentLoggingQueryUi = InstrumentLoggerQueryUi( self.config, self.traceui, self.plotDict) self.instrumentLoggingQueryUi.setupUi(self.instrumentLoggingQueryUi) self.instrumentLoggingQueryUiDock = self.setupAsDockWidget( self.instrumentLoggingQueryUi, "Query", QtCore.Qt.LeftDockWidgetArea) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle("Instrument Logger ({0})".format(self.project)) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.error( "Cannot restore dock state in experiment {0}. Exception occurred: " .format(self.experimentName) + str(e)) self.initMenu() self.actionProject.triggered.connect(self.onProjectSelection) self.actionExit.triggered.connect(self.onClose) def onProjectSelection(self): ui = ProjectInfoUi(self.project) ui.show() ui.exec_() def onEnableConsole(self, state): self.consoleEnable = state == QtCore.Qt.Checked def onClearConsole(self): self.textEditConsole.clear() def onConsoleMaximumLinesChanged(self, maxlines): self.consoleMaximumLines = maxlines self.textEditConsole.document().setMaximumBlockCount(maxlines) def setLoggingLevel(self, index): self.loggingLevel = self.levelValueList[index] def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get('PlotNames', ['Scan']) if len(plotNames) < 1: plotNames.append('Scan') for name in plotNames: dock = Dock(name) widget = DateTimePlotWidget(self, name=name) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget(widget) self.addDockWidget(area, dock) self.dockWidgetList.append(dock) if stackAbove is not None: self.tabifyDockWidget(stackAbove, dock) elif stackBelow is not None: self.tabifyDockWidget(dock, stackBelow) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText( self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = DateTimePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } self.plotConfigurationChanged.emit(self.plotDict) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText( self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be renamed") def onSave(self): logger = logging.getLogger(__name__) logger.info("Saving config") filename, _ = DataDirectory.DataDirectory().sequencefile( "InstrumentLogger-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onClose(self): self.parent.close() def onMessageWrite(self, message, level=logging.DEBUG): if self.consoleEnable and level >= self.loggingLevel: cursor = self.textEditConsole.textCursor() cursor.movePosition(QtGui.QTextCursor.End) if level < logging.ERROR: self.textEditConsole.setTextColor(QtCore.Qt.black) else: self.textEditConsole.setTextColor(QtCore.Qt.red) cursor.insertText(message) self.textEditConsole.setTextCursor(cursor) self.textEditConsole.ensureCursorVisible() def closeEvent(self, e): logger = logging.getLogger(__name__) logger.info("Close Event") logger = logging.getLogger("") logger.debug("Saving Configuration") self.saveConfig() def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in list(self.tabDict.values()): tab.saveConfig() self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.config['Settings.loggingLevel'] = self.loggingLevel self.config[ 'Settings.consoleMaximumLinesNew'] = self.consoleMaximumLines self.config['Settings.consoleEnable'] = self.consoleEnable self.config['autoSaveTraces'] = self.traceui.autoSaveTraces self.ExternalParametersSelectionUi.saveConfig() self.instrumentLoggingHandler.saveConfig() self.instrumentLoggingQueryUi.saveConfig() self.preferencesUi.saveConfig() def onPrint(self, target): printer = QtPrintSupport.QPrinter( mode=QtPrintSupport.QPrinter.ScreenResolution) if self.preferencesUi.preferences().printPreferences.doPrint: dialog = QtPrintSupport.QPrintDialog(printer, self) dialog.setWindowTitle("Print Document") if dialog.exec_() != QtWidgets.QDialog.Accepted: return printer.setResolution( self.preferencesUi.preferences().printPreferences.printResolution) pdfPrinter = QtPrintSupport.QPrinter() pdfPrinter.setOutputFormat(QtPrintSupport.QPrinter.PdfFormat) pdfPrinter.setOutputFileName( DataDirectory.DataDirectory().sequencefile(target + ".pdf")[0]) self.doPrint(target, printer, pdfPrinter, self.preferencesUi.preferences().printPreferences) def doPrint(self, target, printer, pdfPrinter, preferences): widget = self.plotDict[target]['widget'] if preferences.savePdf: with SceneToPrint(widget): painter = QtGui.QPainter(pdfPrinter) widget.render(painter) del painter # create an exporter instance, as an argument give it # the item you wish to export with SceneToPrint(widget, preferences.gridLinewidth, preferences.curveLinewidth): exporter = ImageExporter(widget._graphicsView.scene()) # set export parameters if needed pageWidth = printer.pageRect().width() pageHeight = printer.pageRect().height() exporter.parameters( )['width'] = pageWidth * preferences.printWidth # (note this also affects height parameter) # save to file png = exporter.export(toBytes=True) if preferences.savePng: png.save(DataDirectory.DataDirectory().sequencefile(target + ".png")[0]) if preferences.doPrint: painter = QtGui.QPainter(printer) painter.drawImage( QtCore.QPoint(pageWidth * preferences.printX, pageHeight * preferences.printY), png) def initMenu(self): """Initialize print menu and view menu""" #View menu self.menuView.clear() dockList = self.findChildren(QtWidgets.QDockWidget) for dock in dockList: self.menuView.addAction(dock.toggleViewAction()) # Print menu if self.printMenu is not None: self.printMenu.clear() else: self.printMenu = self.menuFile.addMenu("Print") for plot in list(self.plotDict.keys()): action = self.printMenu.addAction(plot) action.triggered.connect(partial(self.onPrint, plot))
class DigitalLockUi(WidgetContainerBase, WidgetContainerForm): levelNameList = ["debug", "info", "warning", "error", "critical"] levelValueList = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] plotConfigurationChanged = QtCore.pyqtSignal( object ) def __init__(self, config, project): self.config = config self.project = project super(DigitalLockUi, self).__init__() self.settings = SettingsDialog.Settings() self.deviceSerial = config.get('Settings.deviceSerial') self.deviceDescription = config.get('Settings.deviceDescription') self.loggingLevel = config.get('Settings.loggingLevel', logging.INFO) self.consoleMaximumLines = config.get('Settings.consoleMaximumLines', 0) self.dockWidgetList = list() if self.loggingLevel not in self.levelValueList: self.loggingLevel = logging.INFO self.plotDict = dict() def __enter__(self): self.pulser = Controller() return self def __exit__(self, excepttype, value, traceback): self.pulser.shutdown() return False def setupUi(self, parent): super(DigitalLockUi, self).setupUi(parent) self.dockWidgetConsole.hide() self.loggerUi = LoggerLevelsUi(self.config) self.loggerUi.setupUi(self.loggerUi) self.setupAsDockWidget(self.loggerUi, "Logging", QtCore.Qt.NoDockWidgetArea) logger = logging.getLogger() self.toolBar.addWidget(ExceptionLogButton()) # Setup Console Dockwidget self.levelComboBox.addItems(self.levelNameList) # self.levelComboBox.currentIndexChanged[int].connect( self.setLoggingLevel ) self.levelComboBox.setCurrentIndex( self.levelValueList.index(self.loggingLevel) ) # self.consoleClearButton.clicked.connect( self.onClearConsole ) # self.linesSpinBox.valueChanged.connect( self.onConsoleMaximumLinesChanged ) self.parent = parent self.tabList = list() self.tabDict = dict() # initialize FPGA settings self.settingsDialog = SettingsDialog.SettingsDialog(self.pulser, self.config, self.parent) self.settingsDialog.setupUi() self.settings = self.settingsDialog.settings try: configFile = os.path.splitext(self.settings.bitfile)[0] + '.yml' with open(configFile, 'r') as f: lockConfig = yaml.load(f) self.settings.onBoardADCEncoding = lockConfig['onBoardADCEncoding'] except Exception as e: logger.error('unable to load config file: {0}'.format(e)) self.settings.onBoardADCEncoding = None self.setupPlots() # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # lock status self.lockStatus = LockStatus(self.pulser, self.config, self.traceui, self.plotDict, self.settings, self.parent) self.lockStatus.setupUi() self.setupAsDockWidget(self.lockStatus, "Status", QtCore.Qt.RightDockWidgetArea) self.plotConfigurationChanged.connect( self.lockStatus.onPlotConfigurationChanged ) # Trace control self.traceControl = TraceControl(self.pulser, self.config, self.traceui, self.plotDict, self.parent) self.traceControl.setupUi() self.setupAsDockWidget(self.traceControl, "Trace Control", QtCore.Qt.RightDockWidgetArea) self.plotConfigurationChanged.connect( self.traceControl.onPlotConfigurationChanged ) # Lock control self.lockControl = LockControl(self.pulser, self.config, self.settings, self.parent) self.lockControl.dataChanged.connect( self.lockStatus.onControlChanged ) self.lockControl.dataChanged.connect( self.traceControl.onControlChanged ) self.lockControl.setupUi() self.lockStatus.newDataAvailable.connect( self.lockControl.onStreamData ) self.traceControl.newDataAvailable.connect( self.lockControl.onTraceData ) self.setupAsDockWidget(self.lockControl, "Control", QtCore.Qt.RightDockWidgetArea) self.actionSave.triggered.connect(self.onSave) self.actionSettings.triggered.connect(self.onSettings) self.actionExit.triggered.connect(self.onClose) self.actionProject.triggered.connect( self.onProjectSelection) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle( "Digital Lock ({0})".format(self.project) ) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) self.initMenu() try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.error("Cannot restore dock state in experiment {0}. Exception occurred: ".format(self.experimentName) + str(e)) QtCore.QTimer.singleShot(300000, self.onCommitConfig ) def onCommitConfig(self): self.saveConfig() self.config.saveConfig() QtCore.QTimer.singleShot(300000, self.onCommitConfig ) def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get( 'PlotNames', ['History', 'Scope'] ) if len(plotNames)<1: plotNames.append('History') for name in plotNames: dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None ): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget( widget ) self.addDockWidget(area, dock ) self.dockWidgetList.append( dock ) if stackAbove is not None: self.tabifyDockWidget( stackAbove, dock ) elif stackBelow is not None: self.tabifyDockWidget( dock, stackBelow ) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText(self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = CoordinatePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} self.plotConfigurationChanged.emit( self.plotDict ) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem(self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText(self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit( self.plotDict ) else: logger.info("There are no plots which can be renamed") def onProjectSelection(self): ui = ProjectInfoUi(self.project) ui.show() ui.exec_() def onSettings(self): self.settingsDialog.show() def onSave(self): logger = logging.getLogger(__name__) logger.info( "Saving config" ) filename, _ = DataDirectory.DataDirectory().sequencefile("digitalLock-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onMessageWrite(self,message,level=logging.DEBUG): if level>= self.loggingLevel: cursor = self.textEditConsole.textCursor() cursor.movePosition(QtGui.QTextCursor.End) if level < logging.ERROR: self.textEditConsole.setTextColor(QtCore.Qt.black) else: self.textEditConsole.setTextColor(QtCore.Qt.red) cursor.insertText(message) self.textEditConsole.setTextCursor(cursor) self.textEditConsole.ensureCursorVisible() def onClose(self): self.parent.close() def closeEvent(self, e): logger = logging.getLogger("") logger.debug( "Saving Configuration" ) self.saveConfig() self.settingsDialog.done(0) self.lockControl.closeEvent(e) def initMenu(self): self.menuView.clear() for dock in self.dockWidgetList: self.menuView.addAction(dock.toggleViewAction()) def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in self.tabList: tab.saveConfig() self.config['Settings.deviceSerial'] = self.settings.deviceSerial self.config['Settings.deviceDescription'] = self.settings.deviceDescription self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['Settings.loggingLevel'] = self.loggingLevel self.config['Settings.consoleMaximumLines'] = self.consoleMaximumLines self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.settingsDialog.saveConfig() self.loggerUi.saveConfig() self.lockControl.saveConfig() self.lockStatus.saveConfig() self.traceControl.saveConfig()
class InstrumentLoggingUi(WidgetContainerBase, WidgetContainerForm): plotConfigurationChanged = QtCore.pyqtSignal(object) def __init__(self, project, config): super(InstrumentLoggingUi, self).__init__() self.config = config self.project = project self.dockWidgetList = list() self.plotDict = dict() self.instrument = "" def __enter__(self): return self def __exit__(self, excepttype, value, traceback): return False def setupUi(self, parent): super(InstrumentLoggingUi, self).setupUi(parent) logger = logging.getLogger() self.parent = parent self.tabList = list() self.tabDict = dict() self.setupPlots() # Traceui self.penicons = pens.penicons().penicons() self.traceui = Traceui.Traceui(self.penicons, self.config, "Main", self.plotDict) self.traceui.setupUi(self.traceui) self.setupAsDockWidget(self.traceui, "Traces", QtCore.Qt.LeftDockWidgetArea) # new fit widget self.fitWidget = FitUi(self.traceui, self.config, "Main") self.fitWidget.setupUi(self.fitWidget) self.fitWidgetDock = self.setupAsDockWidget( self.fitWidget, "Fit", QtCore.Qt.LeftDockWidgetArea) self.instrumentLoggingHandler = InstrumentLoggingHandler( self.traceui, self.plotDict, self.config, 'externalInput') self.ExternalParametersSelectionUi = InstrumentLoggingSelection( self.config, classdict=LoggingInstruments, newDataSlot=self.instrumentLoggingHandler.addData, plotNames=list(self.plotDict.keys()), instrumentLoggingHandler=self.instrumentLoggingHandler) self.ExternalParametersSelectionUi.setupUi( self.ExternalParametersSelectionUi) self.ExternalParameterSelectionDock = QtWidgets.QDockWidget( "Params Selection") self.ExternalParameterSelectionDock.setObjectName( "_ExternalParameterSelectionDock") self.ExternalParameterSelectionDock.setWidget( self.ExternalParametersSelectionUi) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.ExternalParameterSelectionDock) self.instrumentLoggingHandler.paramTreeChanged.connect( self.ExternalParametersSelectionUi.refreshParamTree) self.instrumentLoggingDisplay = InstrumentLoggingDisplay(self.config) self.instrumentLoggingDisplay.setupUi( self.ExternalParametersSelectionUi.enabledParametersObjects, self.instrumentLoggingDisplay) self.instrumentLoggingDisplayDock = QtWidgets.QDockWidget( "Params Reading") self.instrumentLoggingDisplayDock.setObjectName( "_ExternalParameterDisplayDock") self.instrumentLoggingDisplayDock.setWidget( self.instrumentLoggingDisplay) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.instrumentLoggingDisplayDock) self.ExternalParametersSelectionUi.selectionChanged.connect( self.instrumentLoggingDisplay.setupParameters) self.instrumentLoggingHandler.newData.connect( self.instrumentLoggingDisplay.update) self.instrumentLoggingQueryUi = InstrumentLoggerQueryUi( self.config, self.traceui, self.plotDict) self.instrumentLoggingQueryUi.setupUi(self.instrumentLoggingQueryUi) self.instrumentLoggingQueryUiDock = self.setupAsDockWidget( self.instrumentLoggingQueryUi, "Query", QtCore.Qt.LeftDockWidgetArea) self.addPlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtWidgets.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) self.setWindowTitle("Instrument Logger ({0})".format(self.project)) if 'MainWindow.State' in self.config: self.parent.restoreState(self.config['MainWindow.State']) try: if 'pyqtgraph-dockareastate' in self.config: self.area.restoreState(self.config['pyqtgraph-dockareastate']) except Exception as e: logger.warning( "Cannot restore dock state in experiment {0}. Exception occurred: " .format(self.experimentName) + str(e)) QtCore.QTimer.singleShot(60000, self.onCommitConfig) def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = dict() # initialize all the plot windows we want plotNames = self.config.get('PlotNames', ['Scan']) if len(plotNames) < 1: plotNames.append('Scan') for name in plotNames: dock = Dock(name) widget = DateTimePlotWidget(self, name=name) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } def setupAsDockWidget(self, widget, name, area=QtCore.Qt.RightDockWidgetArea, stackAbove=None, stackBelow=None): dock = QtWidgets.QDockWidget(name) dock.setObjectName(name) dock.setWidget(widget) self.addDockWidget(area, dock) self.dockWidgetList.append(dock) if stackAbove is not None: self.tabifyDockWidget(stackAbove, dock) elif stackBelow is not None: self.tabifyDockWidget(dock, stackBelow) return dock def onAddPlot(self): name, ok = QtWidgets.QInputDialog.getText( self, 'Plot Name', 'Please enter a plot name: ') if ok: name = str(name) dock = Dock(name) widget = DateTimePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = { "dock": dock, "widget": widget, "view": view } self.plotConfigurationChanged.emit(self.plotDict) def onRemovePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to remove: ", list(self.plotDict.keys()), editable=False) if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be removed") def onRenamePlot(self): logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtWidgets.QInputDialog.getItem( self, "Select Plot", "Please select which plot to rename: ", list(self.plotDict.keys()), editable=False) if ok: newName, newOk = QtWidgets.QInputDialog.getText( self, 'New Plot Name', 'Please enter a new plot name: ') if newOk: name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(str(newName)) self.plotDict[newName] = self.plotDict[name] del self.plotDict[name] self.plotConfigurationChanged.emit(self.plotDict) else: logger.info("There are no plots which can be renamed") def onSave(self): logger = logging.getLogger(__name__) logger.info("Saving config") filename, _ = DataDirectory.DataDirectory().sequencefile( "InstrumentLogger-configuration.db") self.saveConfig() self.config.saveConfig(filename) def onClose(self): self.parent.close() def closeEvent(self, e): logger = logging.getLogger(__name__) logger.info("Close Event") logger = logging.getLogger("") logger.debug("Saving Configuration") self.saveConfig() def saveConfig(self): self.config['MainWindow.State'] = self.parent.saveState() for tab in self.tabList: tab.saveConfig() self.config['MainWindow.pos'] = self.pos() self.config['MainWindow.size'] = self.size() self.config['PlotNames'] = list(self.plotDict.keys()) self.config['pyqtgraph-dockareastate'] = self.area.saveState() self.ExternalParametersSelectionUi.saveConfig() self.instrumentLoggingHandler.saveConfig() self.instrumentLoggingQueryUi.saveConfig() self.instrumentLoggingDisplay.saveConfig() def onCommitConfig(self): self.saveConfig() QtCore.QTimer.singleShot(60000, self.onCommitConfig)
class AWGUi(AWGForm, AWGBase): varDictChanged = QtCore.pyqtSignal(object) def __init__(self, deviceClass, config, globalDict, parent=None): AWGBase.__init__(self, parent) AWGForm.__init__(self) self.config = config self.configname = 'AWGUi.' + deviceClass.displayName self.globalDict = globalDict self.autoSave = self.config.get(self.configname+'.autoSave', True) self.waveformCache = OrderedDict() self.settingsDict = self.config.get(self.configname+'.settingsDict', dict()) self.settingsName = self.config.get(self.configname+'.settingsName', '') # self.settingsDict=dict() # self.settingsName='' self.recentFiles = self.config.get(self.configname+'.recentFiles', dict()) #dict of form {basename: filename}, where filename has path and basename doesn't self.lastDir = self.config.get(self.configname+'.lastDir', getProject().configDir) Settings.deviceProperties = deviceClass.deviceProperties Settings.saveIfNecessary = self.saveIfNecessary Settings.replot = self.replot for settings in list(self.settingsDict.values()): #make sure all pickled settings are consistent with device, in case it changed for channel in range(deviceClass.deviceProperties['numChannels']): if channel >= len(settings.channelSettingsList): #create new channels if it's necessary settings.channelSettingsList.append({ 'segmentDataRoot':AWGSegmentNode(None), 'segmentTreeState':None, 'plotEnabled':True, 'plotStyle':Settings.plotStyles.lines}) else: settings.channelSettingsList[channel].setdefault('segmentDataRoot', AWGSegmentNode(None)) settings.channelSettingsList[channel].setdefault('segmentTreeState', None) settings.channelSettingsList[channel].setdefault('plotEnabled', True) settings.channelSettingsList[channel].setdefault('plotStyle', Settings.plotStyles.lines) self.settings = Settings() #we always run settings through the constructor if self.settingsName in self.settingsDict: self.settings.update(self.settingsDict[self.settingsName]) self.device = deviceClass(self.settings) def setupUi(self, parent): logger = logging.getLogger(__name__) AWGForm.setupUi(self, parent) self.setWindowTitle(self.device.displayName) self._varAsOutputChannelDict = dict() self.area = DockArea() self.splitter.insertWidget(0, self.area) self.awgChannelUiList = [] for channel in range(self.device.deviceProperties['numChannels']): awgChannelUi = AWGChannelUi(channel, self.settings, self.globalDict, self.waveformCache, parent=self) awgChannelUi.setupUi(awgChannelUi) awgChannelUi.dependenciesChanged.connect(self.onDependenciesChanged) self.awgChannelUiList.append(awgChannelUi) dock = Dock("AWG Channel {0}".format(channel)) dock.addWidget(awgChannelUi) self.area.addDock(dock, 'right') self.device.waveforms[channel] = awgChannelUi.waveform self.refreshVarDict() # Settings control self.saveButton.clicked.connect( self.onSave ) self.removeButton.clicked.connect( self.onRemove ) self.reloadButton.clicked.connect( self.onReload ) self.settingsModel = QtCore.QStringListModel() self.settingsComboBox.setModel(self.settingsModel) self.settingsModel.setStringList( sorted(self.settingsDict.keys()) ) self.settingsComboBox.setCurrentIndex( self.settingsComboBox.findText(self.settingsName) ) self.settingsComboBox.currentIndexChanged[str].connect( self.onLoad ) self.settingsComboBox.lineEdit().editingFinished.connect( self.onComboBoxEditingFinished ) self.autoSaveCheckBox.setChecked(self.autoSave) self.saveButton.setEnabled( not self.autoSave ) self.saveButton.setVisible( not self.autoSave ) self.reloadButton.setEnabled( not self.autoSave ) self.reloadButton.setVisible( not self.autoSave ) self.autoSaveCheckBox.stateChanged.connect(self.onAutoSave) #programming options table self.programmingOptionsTable.setupUi(globalDict=self.globalDict, parameterDict=self.device.parameters()) self.programmingOptionsTable.valueChanged.connect( self.device.update ) # Table self.tableModel = AWGTableModel(self.settings, self.globalDict) self.tableView.setModel(self.tableModel) self.tableModel.valueChanged.connect(self.onValue) self.delegate = MagnitudeSpinBoxDelegate(self.globalDict) self.tableView.setItemDelegateForColumn(self.tableModel.column.value, self.delegate) #File self.filenameModel = QtCore.QStringListModel() self.filenameComboBox.setModel(self.filenameModel) self.filenameModel.setStringList( [basename for basename, filename in list(self.recentFiles.items()) if os.path.exists(filename)] ) self.filenameComboBox.setCurrentIndex(self.filenameComboBox.findText(os.path.basename(self.settings.filename))) self.filenameComboBox.currentIndexChanged[str].connect(self.onFilename) self.removeFileButton.clicked.connect(self.onRemoveFile) self.newFileButton.clicked.connect(self.onNewFile) self.openFileButton.clicked.connect(self.onOpenFile) self.saveFileButton.clicked.connect(self.onSaveFile) self.reloadFileButton.clicked.connect(self.onReloadFile) #cache self.cacheDepthSpinBox.setValue(self.settings.cacheDepth) self.cacheDepthSpinBox.valueChanged.connect(self.onCacheDepth) self.clearCacheButton.clicked.connect(self.onClearCache) #status bar self.label = QtGui.QLabel('Sample Rate: {0}'.format(self.settings.deviceProperties['sampleRate'])) self.statusbar.addWidget(self.label) #Restore GUI state state = self.config.get(self.configname+'.state') pos = self.config.get(self.configname+'.pos') size = self.config.get(self.configname+'.size') isMaximized = self.config.get(self.configname+'.isMaximized') dockAreaState = self.config.get(self.configname+'.dockAreaState') guiState = self.config.get(self.configname+".guiState") restoreGuiState(self, guiState) try: if pos: self.move(pos) if size: self.resize(size) if isMaximized: self.showMaximized() if state: self.restoreState(state) for awgChannelUi in self.awgChannelUiList: channelGuiState = self.config[self.configname+"channel{0}.guiState".format(awgChannelUi.channel)] restoreGuiState(awgChannelUi, channelGuiState) except Exception as e: logger.warning("Error on restoring state in AWGUi {0}. Exception occurred: {1}".format(self.device.displayName, e)) try: if dockAreaState: self.area.restoreState(dockAreaState) except Exception as e: logger.warning("Cannot restore dock state in AWGUi {0}. Exception occurred: {1}".format(self.device.displayName, e)) self.area.deleteLater() self.area = DockArea() self.splitter.insertWidget(0, self.area) for channelUi in self.awgChannelUiList: dock = Dock("AWG Channel {0}".format(channel)) dock.addWidget(channelUi) self.area.addDock(dock, 'right') self.saveIfNecessary() def onCacheDepth(self, newVal): self.settings.cacheDepth = newVal self.saveIfNecessary() def onClearCache(self): self.waveformCache.clear() def onComboBoxEditingFinished(self): """a settings name is typed into the combo box""" currentText = str(self.settingsComboBox.currentText()) if self.settingsName != currentText: self.settingsName = currentText if self.settingsName not in self.settingsDict: self.settingsDict[self.settingsName] = copy.deepcopy(self.settings) self.onLoad(self.settingsName) def saveIfNecessary(self): """save the current settings if autosave is on and something has changed""" currentText = str(self.settingsComboBox.currentText()) if self.settingsDict.get(self.settingsName)!=self.settings or currentText!=self.settingsName: if self.autoSave: self.onSave() else: self.saveButton.setEnabled(True) def replot(self): """plot all channels""" for channelUi in self.awgChannelUiList: channelUi.replot() def onSave(self): """save current settings""" self.settingsName = str(self.settingsComboBox.currentText()) self.settingsDict[self.settingsName] = copy.deepcopy(self.settings) with BlockSignals(self.settingsComboBox) as w: self.settingsModel.setStringList( sorted(self.settingsDict.keys()) ) w.setCurrentIndex(w.findText(self.settingsName)) self.saveButton.setEnabled(False) def saveConfig(self): """save GUI configuration to config""" self.config[self.configname+".guiState"] = saveGuiState(self) for awgChannelUi in self.awgChannelUiList: self.config[self.configname+"channel{0}.guiState".format(awgChannelUi.channel)] = saveGuiState(awgChannelUi) self.settings.channelSettingsList[awgChannelUi.channel]['segmentTreeState'] = awgChannelUi.segmentView.saveTreeState() self.config[self.configname+'.state'] = self.saveState() self.config[self.configname+'.pos'] = self.pos() self.config[self.configname+'.size'] = self.size() self.config[self.configname+'.isMaximized'] = self.isMaximized() self.config[self.configname+'.isVisible'] = self.isVisible() self.config[self.configname+'.dockAreaState'] = self.area.saveState() self.config[self.configname+'.settingsDict'] = self.settingsDict self.config[self.configname+'.settingsName'] = self.settingsName self.config[self.configname+'.autoSave'] = self.autoSave self.config[self.configname+'.recentFiles'] = self.recentFiles self.config[self.configname+'.lastDir'] = self.lastDir def onRemove(self): """Remove current settings from combo box""" name = str(self.settingsComboBox.currentText()) if name in self.settingsDict: self.settingsDict.pop(name) self.settingsName = list(self.settingsDict.keys())[0] if self.settingsDict else '' with BlockSignals(self.settingsComboBox) as w: self.settingsModel.setStringList( sorted(self.settingsDict.keys()) ) w.setCurrentIndex(w.findText(self.settingsName)) self.onLoad(self.settingsName) def onReload(self): """Reload settings""" name = str(self.settingsComboBox.currentText()) self.onLoad(name) def onLoad(self, name): """load settings""" for channelUi in self.awgChannelUiList: self.settings.channelSettingsList[channelUi.channel]['segmentTreeState'] = channelUi.segmentView.saveTreeState() name = str(name) if name in self.settingsDict: self.settingsName = name self.tableModel.beginResetModel() [channelUi.segmentModel.beginResetModel() for channelUi in self.awgChannelUiList] self.settings.update(self.settingsDict[self.settingsName]) self.programmingOptionsTable.setParameters( self.device.parameters() ) self.saveButton.setEnabled(False) with BlockSignals(self.filenameComboBox) as w: w.setCurrentIndex(w.findText(os.path.basename(self.settings.filename))) with BlockSignals(self.cacheDepthSpinBox) as w: w.setValue(self.settings.cacheDepth) for channelUi in self.awgChannelUiList: channelUi.waveform.updateDependencies() channelUi.plotCheckbox.setChecked(self.settings.channelSettingsList[channelUi.channel]['plotEnabled']) with BlockSignals(channelUi.styleComboBox) as w: w.setCurrentIndex(self.settings.channelSettingsList[channelUi.channel]['plotStyle']) channelUi.segmentModel.root = self.settings.channelSettingsList[channelUi.channel]['segmentDataRoot'] channelUi.replot() self.onDependenciesChanged() self.saveButton.setEnabled(False) self.tableModel.endResetModel() [channelUi.segmentModel.endResetModel() for channelUi in self.awgChannelUiList] for channelUi in self.awgChannelUiList: channelUi.segmentView.restoreTreeState(self.settings.channelSettingsList[channelUi.channel]['segmentTreeState']) def onAutoSave(self, checked): """autosave is changed""" self.autoSave = checked self.saveButton.setEnabled( not checked ) self.saveButton.setVisible( not checked ) self.reloadButton.setEnabled( not checked ) self.reloadButton.setVisible( not checked ) if checked: self.onSave() def onValue(self, var=None, value=None): """variable value is changed in the table""" self.saveIfNecessary() self.replot() def evaluate(self, name): """re-evaluate the text in the tableModel (happens when a global changes)""" self.tableModel.evaluate(name) self.programmingOptionsTable.evaluate(name) def refreshVarDict(self): """refresh the variable dictionary by checking all waveform dependencies""" allDependencies = set() [channelUi.waveform.updateDependencies() for channelUi in self.awgChannelUiList] [allDependencies.update(channelUi.waveform.dependencies) for channelUi in self.awgChannelUiList] default = lambda varname:{'value':Q(1, 'us'), 'text':None} if varname.startswith('Duration') else {'value':Q(0), 'text':None} deletions = [varname for varname in self.settings.varDict if varname not in allDependencies] [self.settings.varDict.pop(varname) for varname in deletions] #remove all values that aren't dependencies anymore [self.settings.varDict.setdefault(varname, default(varname)) for varname in allDependencies] #add missing values self.settings.varDict.sort(key = lambda val: -1 if val[0].startswith('Duration') else ord( str(val[0])[0] )) self.varDictChanged.emit(self.varAsOutputChannelDict) for channelUi in self.awgChannelUiList: channelUi.replot() def onDependenciesChanged(self, channel=None): """When dependencies change, refresh all variables""" self.tableModel.beginResetModel() self.refreshVarDict() self.tableModel.endResetModel() self.saveIfNecessary() def onFilename(self, basename): """filename combo box is changed. Open selected file""" basename = str(basename) filename = self.recentFiles[basename] if os.path.isfile(filename) and filename!=self.settings.filename: self.openFile(filename) def onRemoveFile(self): """Remove file button is clicked. Remove filename from combo box.""" text = str(self.filenameComboBox.currentText()) index = self.filenameComboBox.findText(text) if text in self.recentFiles: self.recentFiles.pop(text) with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(-1) self.onFilename(w.currentText()) def onNewFile(self): """New button is clicked. Pop up dialog asking for new name, and create file.""" filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'New File', self.lastDir, 'YAML (*.yml)') if filename: self.lastDir, basename = os.path.split(filename) self.recentFiles[basename] = filename self.settings.filename = filename with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(w.findText(basename)) self.onSaveFile() def onOpenFile(self): """Open file button is clicked. Pop up dialog asking for filename.""" filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Select File', self.lastDir, 'YAML (*.yml)') if filename: self.openFile(filename) def openFile(self, filename): """Open the file 'filename'""" if os.path.exists(filename): self.lastDir, basename = os.path.split(filename) self.recentFiles[basename] = filename self.settings.filename = filename with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(w.findText(basename)) with open(filename, 'r') as f: yamldata = yaml.load(f) variables = yamldata.get('variables') channelData = yamldata.get('channelData') self.tableModel.beginResetModel() [channelUi.segmentModel.beginResetModel() for channelUi in self.awgChannelUiList] if channelData: for channelUi in self.awgChannelUiList: if channelUi.channel < len(channelData): self.settings.channelSettingsList[channelUi.channel]['segmentDataRoot'] = self.convertListToNodes(channelData[channelUi.channel], isRoot=True) channelUi.segmentModel.root = self.settings.channelSettingsList[channelUi.channel]['segmentDataRoot'] if variables: for varname, vardata in list(variables.items()): self.settings.varDict.setdefault(varname, dict()) self.settings.varDict[varname]['value'] = Q(vardata['value'], vardata['unit']) self.settings.varDict[varname]['text'] = vardata['text'] for channelUi in self.awgChannelUiList: channelUi.waveform.updateDependencies() channelUi.replot() self.onDependenciesChanged() self.tableModel.endResetModel() [channelUi.segmentModel.endResetModel() for channelUi in self.awgChannelUiList] [channelUi.segmentView.expandAll() for channelUi in self.awgChannelUiList] else: logging.getLogger(__name__).warning("file '{0}' does not exist".format(filename)) if filename in self.recentFiles: del self.recentFiles[filename] with BlockSignals(self.filenameComboBox) as w: self.filenameModel.setStringList(list(self.recentFiles.keys())) w.setCurrentIndex(-1) def convertNodeToList(self, node): nodeList = [] for childNode in node.children: if childNode.nodeType==nodeTypes.segment: nodeList.append( {'equation':childNode.equation, 'duration':childNode.duration, 'enabled':childNode.enabled} ) elif childNode.nodeType==nodeTypes.segmentSet: nodeList.append( {'repetitions':childNode.repetitions, 'enabled':childNode.enabled, 'segments':self.convertNodeToList(childNode)} ) return nodeList def convertListToNodes(self, data, parent=None, enabled=True, repetitions=None, isRoot=False): node = AWGSegmentNode(parent=None) if isRoot else AWGSegmentSet(parent=parent, enabled=enabled, repetitions=repetitions) for segment in data: if 'duration' in segment: childNode = AWGSegment(parent=node, equation=segment['equation'], duration=segment['duration'], enabled=segment['enabled']) node.children.append(childNode) elif 'repetitions' in segment: segmentSet = self.convertListToNodes(segment['segments'], parent=node, enabled=segment['enabled'], repetitions=segment['repetitions']) node.children.append(segmentSet) else: logging.getLogger(__name__).error("Unable to convert list to nodes") return node def onSaveFile(self): """Save button is clicked. Save data to segment file""" channelData = [] for channelSettings in self.settings.channelSettingsList: segmentData = self.convertNodeToList(channelSettings['segmentDataRoot']) channelData.append(segmentData) yamldata = {'channelData': channelData} variables={varname: {'value':float(varValueTextDict['value'].toStringTuple()[0]), 'unit':varValueTextDict['value'].toStringTuple()[1], 'text':varValueTextDict['text']} for varname, varValueTextDict in list(self.settings.varDict.items())} yamldata.update({'variables':variables}) with open(self.settings.filename, 'w') as f: yaml.dump(yamldata, f, default_flow_style=False) def onReloadFile(self): self.openFile(self.settings.filename) @QtCore.pyqtProperty(dict) def varAsOutputChannelDict(self): """dict of output channels, for use in scans""" for varname in self.settings.varDict: if varname not in self._varAsOutputChannelDict: self._varAsOutputChannelDict[varname] = VarAsOutputChannel(self, varname, self.globalDict) deletions = [varname for varname in self._varAsOutputChannelDict if varname not in self.settings.varDict] [self._varAsOutputChannelDict.pop(varname) for varname in deletions] #remove all values that aren't dependencies anymore return self._varAsOutputChannelDict def close(self): self.saveConfig() numTempAreas = len(self.area.tempAreas) for i in range(numTempAreas): if len(self.area.tempAreas) > 0: self.area.tempAreas[0].win.close() super(AWGUi, self).close()