Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 47 additions & 12 deletions blacs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,25 @@
import time
from pathlib import Path
import platform
import importlib.metadata
WINDOWS = platform.system() == 'Windows'

# No splash update for Qt - the splash code has already imported it:
import qtutils
from qtutils import *
from qtutils import inmain_decorator, inmain_later, inmain, inthread, UiLoader
import qtutils.icons
from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtCore import qVersion, QTimer, Qt, QEvent
from qtutils.qt.QtGui import QIcon, QPalette, QColor
from qtutils.qt.QtWidgets import (
QMainWindow,
QToolButton,
QMessageBox,
QFileDialog,
QApplication,
QWidget
)
from qtutils.qt import QT_ENV
PYQT_VERSION_STR = importlib.metadata.version(QT_ENV)


splash.update_text("importing zmq and zprocess")
Expand Down Expand Up @@ -79,7 +88,7 @@
logger.info(f'h5py version: {h5py.version.info}')
logger.info(f'Qt enviroment: {QT_ENV}')
logger.info(f'PySide/PyQt version: {PYQT_VERSION_STR}')
logger.info(f'Qt version: {QT_VERSION_STR}')
logger.info(f'Qt version: {qVersion()}')
logger.info(f'qtutils version: {qtutils.__version__}')
logger.info(f'zprocess version: {zprocess.__version__}')
logger.info(f'labscript_utils version: {labscript_utils.__version__}')
Expand Down Expand Up @@ -136,6 +145,23 @@ def closeEvent(self, event):

QTimer.singleShot(100,self.close)

def changeEvent(self, event):

# theme update only for PySide6
if QT_ENV == 'PySide6' and event.type() == QEvent.Type.ThemeChange:
for widget in self.findChildren(QWidget):
# Complex widgets, like TreeView and TableView require triggering styleSheet and palette updates
widget.setStyleSheet(widget.styleSheet())
widget.setPalette(widget.palette())
# tab header text colors have to be done explicitly by tab
# because they use setTabTextColor
app = QApplication.instance()
self.blacs.update_all_tab_icon_and_text(
app.palette().color(QPalette.ColorRole.Text)
)

return super().changeEvent(event)


class EasterEggButton(QToolButton):
def __init__(self):
Expand Down Expand Up @@ -166,7 +192,7 @@ def on_click(self):
# Ensure they can't run the game twice at once:
self.setEnabled(False)
# Wait for the subprocess in a thread so that we know when it quits:
qtutils.inthread(self.run_measure_ball)
inthread(self.run_measure_ball)

def run_measure_ball(self):
try:
Expand Down Expand Up @@ -525,14 +551,23 @@ def update_all_tab_settings(self,settings,tab_data):
self.settings_dict[tab_name]["saved_data"] = tab_data[tab_name]['data'] if tab_name in tab_data else {}
tab.update_from_settings(self.settings_dict[tab_name])

def update_all_tab_icon_and_text(self, text_colour):
# used to repaint tab header text after theme change

for tab in self.tablist.values():
if tab._tab_text_colour == QColor('red'):
# ensure error tabs keep their red text
continue
tab._tab_text_colour = text_colour
tab.set_tab_icon_and_colour()

def on_load_front_panel(self,*args,**kwargs):
# get the file:
# create file chooser dialog
dialog = QFileDialog(None,"Select file to load", self.exp_config.get('paths','experiment_shot_storage'), "HDF5 files (*.h5 *.hdf5)")
dialog.setViewMode(QFileDialog.Detail)
dialog.setFileMode(QFileDialog.ExistingFile)
if dialog.exec_():
if dialog.exec():
selected_files = dialog.selectedFiles()
filepath = str(selected_files[0])
# Qt has this weird behaviour where if you type in the name of a file that exists
Expand All @@ -551,7 +586,7 @@ def on_load_front_panel(self,*args,**kwargs):
message.setWindowTitle("BLACS")
message.setStandardButtons(QMessageBox.Yes|QMessageBox.No)

if message.exec_() == QMessageBox.Yes:
if message.exec() == QMessageBox.Yes:
front_panel_settings = FrontPanelSettings(filepath, self.connection_table)
settings,question,error,tab_data = front_panel_settings.restore()
#TODO: handle question/error
Expand Down Expand Up @@ -583,7 +618,7 @@ def on_load_front_panel(self,*args,**kwargs):
message.setText("Unable to load the front panel. The error encountered is printed below.\n\n%s"%str(e))
message.setIcon(QMessageBox.Information)
message.setWindowTitle("BLACS")
message.exec_()
message.exec()
finally:
dialog.deleteLater()
else:
Expand All @@ -592,7 +627,7 @@ def on_load_front_panel(self,*args,**kwargs):
message.setText("You did not select a file ending with .h5 or .hdf5. Please try again")
message.setIcon(QMessageBox.Information)
message.setWindowTitle("BLACS")
message.exec_()
message.exec()
QTimer.singleShot(10,self.on_load_front_panel)

def on_save_exit(self):
Expand Down Expand Up @@ -679,7 +714,7 @@ def on_save_front_panel(self,*args,**kwargs):
dialog.setFileMode(QFileDialog.AnyFile)
dialog.setAcceptMode(QFileDialog.AcceptSave)

if dialog.exec_():
if dialog.exec():
current_file = str(dialog.selectedFiles()[0])
if not current_file.endswith('.h5'):
current_file += '.h5'
Expand Down Expand Up @@ -775,6 +810,6 @@ def process(self,h5_filepath):
splash.hide()

def execute_program():
qapplication.exec_()
qapplication.exec()

sys.exit(execute_program())
7 changes: 3 additions & 4 deletions blacs/analysis_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
import sys
import queue

from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtCore import Qt, QSize
from qtutils.qt.QtGui import QIcon

from qtutils import *
from qtutils import inmain_decorator, UiLoader
from zprocess import TimeoutError, raise_exception_in_thread
from zprocess.security import AuthenticationFailure
from labscript_utils.ls_zprocess import zmq_get
Expand Down
7 changes: 3 additions & 4 deletions blacs/compile_and_restart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
import os
import shutil

from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtCore import Qt, QTimer
from qtutils.qt.QtWidgets import QDialog

from qtutils import *
from qtutils import inmain_decorator, UiLoader
import runmanager
from labscript_utils.qtwidgets.outputbox import OutputBox

Expand Down
29 changes: 20 additions & 9 deletions blacs/device_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@
import time
from queue import Queue

from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtCore import QTimer
from qtutils.qt.QtGui import QIcon
from qtutils.qt.QtWidgets import (
QWidget,
QSpacerItem,
QSizePolicy,
QPushButton,
QHBoxLayout,
QApplication,
QVBoxLayout,
)

import labscript_utils.excepthook
from qtutils import UiLoader
Expand Down Expand Up @@ -339,15 +347,15 @@ def auto_place_widgets(self,*args):
for arg in args:
# A default sort algorithm that just returns the object (this is equivalent to not specifying the sort gorithm)
sort_algorithm = lambda x: x
if type(arg) == type(()) and len(arg) > 1 and type(arg[1]) == type({}) and len(arg[1].keys()) > 0:
if isinstance(arg, tuple) and len(arg) > 1 and isinstance(arg[1], dict) and len(arg[1].keys()) > 0:
# we have a name, use it!
name = arg[0]
widget_dict = arg[1]
if len(arg) > 2:
sort_algorithm = arg[2]
else:
# ignore things that are not dictionaries or empty dictionaries
if type(arg) != type({}) or len(arg.keys()) < 1:
if not isinstance(arg, dict) or len(arg.keys()) < 1:
continue
if isinstance(self.get_channel(list(arg.keys())[0]),AO):
name = 'Analog Outputs'
Expand Down Expand Up @@ -472,7 +480,7 @@ def check_remote_values(self):

# If no results were returned, raise an exception so that we don't keep calling this function over and over again,
# filling up the text box with the same error, eventually consuming all CPU/memory of the PC
if not self._last_remote_values or type(self._last_remote_values) != type({}):
if not self._last_remote_values or not isinstance(self._last_programmed_values, dict):
raise Exception('Failed to get remote values from device. Is it still connected?')

# A variable to indicate if any of the channels have a changed value
Expand Down Expand Up @@ -949,18 +957,20 @@ class MyWindow(QWidget):
def __init__(self,*args,**kwargs):
QWidget.__init__(self,*args,**kwargs)
self.are_we_closed = False
self.my_tabs = []

def closeEvent(self,event):
if not self.are_we_closed:
event.ignore()
self.my_tab.close_tab()
for tab in self.my_tabs:
tab.close_tab()
self.are_we_closed = True
QTimer.singleShot(1000,self.close)
else:
event.accept()

def add_my_tab(self,tab):
self.my_tab = tab
self.my_tabs.append(tab)

app = QApplication(sys.argv)
window = MyWindow()
Expand All @@ -971,8 +981,9 @@ def add_my_tab(self,tab):
tab1 = MyDAQTab(notebook,settings = {'device_name': 'ni_pcie_6363_0', 'connection_table':connection_table})
tab2 = MyDummyTab(notebook,settings = {'device_name': 'intermediate_device', 'connection_table':connection_table})
window.add_my_tab(tab1)
window.add_my_tab(tab2)
window.show()
def run():
app.exec_()
app.exec()

sys.exit(run())
14 changes: 9 additions & 5 deletions blacs/experiment_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@
from tempfile import gettempdir
from binascii import hexlify

from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtCore import Qt, QItemSelectionModel
from qtutils.qt.QtGui import QIcon, QAction, QStandardItemModel, QStandardItem
from qtutils.qt.QtWidgets import (
QTreeView,
QMenu,
QFileDialog,
)

import zprocess
from labscript_utils.ls_zprocess import ProcessTree
process_tree = ProcessTree.instance()
import labscript_utils.h5_lock, h5py

from qtutils import *
from qtutils import inmain_decorator, inmain

from labscript_utils.qtwidgets.elide_label import elide_label
from labscript_utils.connections import ConnectionTable
Expand Down Expand Up @@ -988,7 +992,7 @@ def restart_function(device_name):
message = self.process_request(path)
except Exception:
# TODO: make this error popup for the user
self._logger.exception('Failed to copy h5_file (%s) for repeat run'%s)
self._logger.exception('Failed to copy h5_file (%s) for repeat run' % path)
logger.info(message)

self.set_status("Idle")
Expand Down
16 changes: 7 additions & 9 deletions blacs/front_panel_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@
import os
import logging

from qtutils.qt.QtCore import *
from qtutils.qt.QtGui import *
from qtutils.qt.QtWidgets import *
from qtutils.qt.QtWidgets import QMessageBox

import labscript_utils.excepthook
import numpy
import labscript_utils.h5_lock, h5py
from qtutils import *
from qtutils import inmain_decorator

from labscript_utils.connections import ConnectionTable

Expand Down Expand Up @@ -137,7 +135,7 @@ def handle_return_code(self,row,result,settings,question,error):
# This is because we have the original channel, and the moved channel in the same place
#-1: Device no longer in the connection table, throw error
#-2: Device parameters not compatible, throw error
if type(result) == tuple:
if isinstance(result, tuple):
connection = result[1]
result = result[0]

Expand Down Expand Up @@ -285,7 +283,7 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl

if save_conn_table or result:
with h5py.File(current_file,'r+') as hdf5_file:
if hdf5_file['/'].get('front_panel') != None:
if hdf5_file['/'].get('front_panel') is not None:
# Create a dialog to ask whether we can overwrite!
overwrite = False
if not silent:
Expand All @@ -296,7 +294,7 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
message.setDefaultButton(QMessageBox.No)
message.setIcon(QMessageBox.Question)
message.setWindowTitle("BLACS")
resp = message.exec_()
resp = message.exec()

if resp == QMessageBox.Yes :
overwrite = True
Expand All @@ -313,7 +311,7 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
message.setText("Front Panel not saved.")
message.setIcon(QMessageBox.Information)
message.setWindowTitle("BLACS")
message.exec_()
message.exec()
else:
logger.info("Front Panel not saved as it already existed in the h5 file '"+current_file+"'")
return
Expand All @@ -327,7 +325,7 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
message.setText("The Front Panel was not saved as the file selected contains a connection table which is not a subset of the BLACS connection table.")
message.setIcon(QMessageBox.Information)
message.setWindowTitle("BLACS")
message.exec_()
message.exec()
else:
logger.info("Front Panel not saved as the connection table in the h5 file '"+current_file+"' didn't match the current connection table.")
return
Expand Down
Loading