cleaner app starting, new application settings class
This commit is contained in:
236
swissmx.py
236
swissmx.py
@@ -28,6 +28,16 @@ logging.getLogger('matplotlib').setLevel(logging.INFO)
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||
_log = logging.getLogger("swissmx")
|
||||
|
||||
import time
|
||||
class timestamp():
|
||||
def __init__(self):
|
||||
self.t=time.time()
|
||||
def log(self,txt):
|
||||
t=time.time()
|
||||
print(txt+f'{t-self.t:6.3g}')
|
||||
self.t=t
|
||||
ts=timestamp()
|
||||
ts.log('Import part 1/7:')
|
||||
import sys, os, time
|
||||
import json, re
|
||||
import random, signal
|
||||
@@ -40,27 +50,6 @@ import random, signal
|
||||
#from helicalscan import HelicalScanGui #ZAC: orig. code
|
||||
# publisher = pubber.Publisher()
|
||||
|
||||
SKIP_ESCAPE_TRANSITIONS_IF_SAFE = "escape/skip_transitions_if_safe"
|
||||
|
||||
BEAM_MARKER_POSITIONS = "beam/marker_positions"
|
||||
BEAM_SIZE = "beam/size"
|
||||
|
||||
CRYOJET_MOTION_ENABLED = "cryojet/motion_enabled"
|
||||
CRYOJET_NOZZLE_OUT = "cryojet/nozzle_out"
|
||||
CRYOJET_NOZZLE_IN = "cryojet/nozzle_in"
|
||||
|
||||
DELTATAU_SHOW_PLOTS = "deltatau/show_plots"
|
||||
DELTATAU_OMEGACOS = "deltatau/omegacos"
|
||||
DELTATAU_SORT_POINTS = "deltatau/sort_points"
|
||||
DELTATAU_VELOCITY_SCALE = "deltatau/velocity_scale"
|
||||
|
||||
CAMERA_TRANSFORMATIONS = "camera/transformations"
|
||||
CAMERA_ZOOM_TO_PPM = "camera/zoom_to_ppm"
|
||||
|
||||
EXPERIMENT_PGROUP = "experiment/pgroup"
|
||||
EXPERIMENT_UID = "experiment/uid"
|
||||
|
||||
ACTIVATE_PULSE_PICKER = "scanning/activate_pulse_picker"
|
||||
|
||||
TASK_JUNGFRAU_SETTINGS = "jungfrau_settings"
|
||||
TASK_SETUP_PPM_CALIBRATION = "ppm_calibration"
|
||||
@@ -74,7 +63,7 @@ TASK_GRID = "grid"
|
||||
TASK_PRELOCATED = "prelocated"
|
||||
TASK_HELICAL = "helical"
|
||||
TASK_EMBL = "embl"
|
||||
|
||||
ts.log('Import part 2/7:')
|
||||
import PrelocatedCoordinatesModel # ZAC: orig. code
|
||||
from EmblModule import EmblWidget #ZAC: orig. code
|
||||
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
||||
@@ -84,7 +73,7 @@ from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
||||
#import mx_swissfel #ZAC: orig. code
|
||||
#swissfel = mx_swissfel.SwissFELMachine() #ZAC: orig. code
|
||||
#from bernina_pulse_picker import pulsePicker #ZAC: orig. code
|
||||
|
||||
ts.log('Import part 3/7:')
|
||||
import qtawesome
|
||||
import qutilities
|
||||
from PyQt5 import QtCore, QtGui
|
||||
@@ -95,7 +84,7 @@ from PyQt5.QtWidgets import (
|
||||
QMessageBox, QPlainTextEdit, QProgressBar, QProgressDialog, QPushButton, QShortcut, QSizePolicy, QSpinBox,
|
||||
QSplashScreen, QTextBrowser, QToolBox, QVBoxLayout, QWidget,)
|
||||
from PyQt5.uic import loadUiType
|
||||
|
||||
ts.log('Import part 4/7:')
|
||||
import CustomROI as CstROI
|
||||
#from CustomROI import BeamMark, Grid, CrystalCircle #ZAC: orig. code
|
||||
#from GenericDialog import GenericDialog #ZAC: orig. code
|
||||
@@ -104,21 +93,21 @@ import CustomROI as CstROI
|
||||
from epics_widgets.MotorTweak import MotorTweak
|
||||
from epics_widgets.SmaractMotorTweak import SmaractMotorTweak
|
||||
from epics_widgets.SimMotorTweak import SimMotorTweak
|
||||
|
||||
|
||||
ts.log('Import part 5/7:')
|
||||
from matplotlib import pyplot
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import pyqtgraph.exporters
|
||||
# use antialias for draw lines, interpret image data as row-major instead of col-major
|
||||
pg.setConfigOptions(antialias=True,imageAxisOrder='row-major')
|
||||
|
||||
ts.log('Import part 6/7:')
|
||||
import app_utils
|
||||
from app_config import settings, appsconf, option, toggle_option, simulated
|
||||
from app_config import AppCfg #settings, option, toggle_option
|
||||
|
||||
import epics
|
||||
from epics.ca import pend_event
|
||||
import camera,backlight,zoom,illumination,geometry
|
||||
ts.log('Import part 7/7:')
|
||||
|
||||
|
||||
#_URL = "http://PC12288:8080"
|
||||
@@ -386,7 +375,9 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
tbox.layout().addWidget(htab)
|
||||
|
||||
def add_beam_marker(self):
|
||||
w, h = settings.value(BEAM_SIZE)
|
||||
app = QApplication.instance()
|
||||
cfg = app._cfg
|
||||
w, h = cfg.value(AppCfg.BEAM_SIZE)
|
||||
self._beammark = CstROI.BeamMark([100, 100], (int(w), int(h)), parent=self)
|
||||
self.vb.addItem(self._beammark)
|
||||
|
||||
@@ -422,6 +413,8 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
self.img.setImage(pic)
|
||||
|
||||
def init_settings_tracker(self):
|
||||
app=QApplication.instance()
|
||||
cfg=app._cfg
|
||||
_log.info("configuring widget persistence")
|
||||
fields = {
|
||||
# 'folder': (self._label_folder, str),
|
||||
@@ -434,7 +427,7 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
}
|
||||
for key, f_config in fields.items():
|
||||
widget, conv = f_config
|
||||
value = settings.value(key)
|
||||
value = cfg.value(key)
|
||||
try:
|
||||
wset, wget = widget.setText, widget.text
|
||||
_log.debug("tracking text field {}".format(key))
|
||||
@@ -530,8 +523,10 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
_log.warning("failed writing {}".format(fname))
|
||||
|
||||
def persist_setting(self, s, v):
|
||||
app=QApplication.instance()
|
||||
cfg=app._cfg
|
||||
_log.debug("persisting {} = {}".format(s, v))
|
||||
settings.setValue(s, v)
|
||||
cfg.setValue(s, v)
|
||||
|
||||
def method_changed(self, index):
|
||||
method = self._tabs_daq_methods.currentWidget().accessibleName()
|
||||
@@ -2477,8 +2472,8 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
self._grids = []
|
||||
tab = self._tab_daq_method_grid
|
||||
layout = tab.layout() # gridlayout
|
||||
self._sb_grid_x_step.setValue(30.0)
|
||||
self._sb_grid_y_step.setValue(30.0)
|
||||
self._sb_grid_x_step.setValue(30)
|
||||
self._sb_grid_y_step.setValue(30)
|
||||
self._bt_add_grid.clicked.connect(self.daq_grid_add_grid)
|
||||
self._bt_remove_all_grids.clicked.connect(self.daq_grid_remove_all)
|
||||
self._find_targets_from_microscope_image.clicked.connect(
|
||||
@@ -2564,6 +2559,8 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
cont.layout().addWidget(w)
|
||||
|
||||
def init_actions(self):
|
||||
app = QApplication.instance()
|
||||
cfg = app._cfg
|
||||
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
|
||||
self.shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_S), self)
|
||||
@@ -2611,8 +2608,8 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
# icon = qtawesome.icon("material.shutter_speed")
|
||||
action = QAction("Use Pulse Picker", self)
|
||||
action.setCheckable(True)
|
||||
action.setChecked(option(ACTIVATE_PULSE_PICKER))
|
||||
action.triggered.connect(lambda: toggle_option(ACTIVATE_PULSE_PICKER))
|
||||
action.setChecked(cfg.option(AppCfg.ACTIVATE_PULSE_PICKER))
|
||||
action.triggered.connect(lambda: cfg.toggle_option(AppCfg.ACTIVATE_PULSE_PICKER))
|
||||
self.toolBar.addAction(action)
|
||||
|
||||
icon = qtawesome.icon("material.timeline")
|
||||
@@ -3120,60 +3117,33 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
|
||||
def init_settings(self):
|
||||
app = QApplication.instance()
|
||||
# settings = Settings
|
||||
#global folders
|
||||
s = settings
|
||||
keys = s.allKeys()
|
||||
|
||||
if ACTIVATE_PULSE_PICKER not in keys:
|
||||
settings.setValue(ACTIVATE_PULSE_PICKER, False)
|
||||
|
||||
if SKIP_ESCAPE_TRANSITIONS_IF_SAFE not in keys:
|
||||
settings.setValue(SKIP_ESCAPE_TRANSITIONS_IF_SAFE, False)
|
||||
cfg = app._cfg
|
||||
keys = cfg.allKeys()
|
||||
|
||||
#if EXPERIMENT_PGROUP not in keys:
|
||||
# self.update_user_and_storage()
|
||||
|
||||
if "hits/marker_size" not in keys:
|
||||
settings.setValue("hits/marker_size", 10)
|
||||
|
||||
if "window/geometry" in keys:
|
||||
self.restoreGeometry(s.value("window/geometry", ""))
|
||||
self.restoreState(s.value("window/windowState", ""))
|
||||
self.restoreGeometry(cfg.value("window/geometry", ""))
|
||||
self.restoreState(cfg.value("window/windowState", ""))
|
||||
|
||||
if "window/main_splitter" in keys:
|
||||
sizes = [int(s) for s in s.value("window/main_splitter")]
|
||||
sizes = [int(s) for s in cfg.value("window/main_splitter")]
|
||||
self._main_splitter.setSizes(sizes)
|
||||
else:
|
||||
self._main_splitter.setSizes([500, 1200])
|
||||
|
||||
if "graphs/show_auxiliary" not in keys:
|
||||
s.setValue("graphs/show_auxiliary", False)
|
||||
|
||||
if "graphs/auxiliary_graph_index" not in keys:
|
||||
s.setValue("graphs/auxiliary_graph_index", 0)
|
||||
|
||||
if "scan_request/last_location" not in keys:
|
||||
d10 = os.path.join(os.path.expanduser("~"), "Data10")
|
||||
s.setValue("scan_request/last_location", d10)
|
||||
|
||||
if BEAM_MARKER_POSITIONS in keys:
|
||||
self._beam_markers = s.value(BEAM_MARKER_POSITIONS)
|
||||
if AppCfg.BEAM_MARKER_POSITIONS in keys:
|
||||
self._beam_markers = s.value(AppCfg.BEAM_MARKER_POSITIONS)
|
||||
self.update_beam_marker_fitters()
|
||||
_log.info("read beam markers {}".format(self._beam_markers))
|
||||
|
||||
if BEAM_SIZE in keys:
|
||||
_log.info("setting beamsize from stored settings: {}".format(s.value(BEAM_SIZE)))
|
||||
else:
|
||||
_log.warning("beam size may not reflect reality, please check")
|
||||
s.setValue(BEAM_SIZE, (40, 20))
|
||||
if AppCfg.CAMERA_TRANSFORMATIONS in keys:
|
||||
app._camera.set_transformations(s.value(AppCfg.CAMERA_TRANSFORMATIONS))
|
||||
|
||||
if CAMERA_TRANSFORMATIONS in keys:
|
||||
app._camera.set_transformations(s.value(CAMERA_TRANSFORMATIONS))
|
||||
|
||||
if CAMERA_ZOOM_TO_PPM in keys:
|
||||
self._zoom_to_ppm = s.value(CAMERA_ZOOM_TO_PPM)
|
||||
_log.info(f"{CAMERA_ZOOM_TO_PPM} updated: {self._zoom_to_ppm}")
|
||||
if AppCfg.CAMERA_ZOOM_TO_PPM in keys:
|
||||
self._zoom_to_ppm = s.value(AppCfg.CAMERA_ZOOM_TO_PPM)
|
||||
_log.info(f"{AppCfg.CAMERA_ZOOM_TO_PPM} updated: {self._zoom_to_ppm}")
|
||||
self.update_ppm_fitters()
|
||||
|
||||
def really_quit(self):
|
||||
@@ -3184,11 +3154,9 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""this is called when the user clicks the window's cross icon"""
|
||||
if (
|
||||
self._do_quit
|
||||
or QMessageBox.question( self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes
|
||||
):
|
||||
if (self._do_quit or QMessageBox.question( self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes):
|
||||
app=QApplication.instance()
|
||||
cfg=app._cfg
|
||||
try:
|
||||
pv=app._camera._pv['pic']
|
||||
pv.clear_auto_monitor() # disconnect PV monitor callback -> program exit faster.
|
||||
@@ -3196,10 +3164,10 @@ class Main(QMainWindow, Ui_MainWindow):
|
||||
_log.warning('disconnect PV callback failed.')
|
||||
|
||||
_log.info('disconnect PV callback')
|
||||
settings.setValue("window/geometry", self.saveGeometry())
|
||||
settings.setValue("window/windowState", self.saveState())
|
||||
settings.setValue("window/main_splitter", self._main_splitter.sizes())
|
||||
settings.setValue("last_active", time.time())
|
||||
cfg.setValue("window/geometry", self.saveGeometry())
|
||||
cfg.setValue("window/windowState", self.saveState())
|
||||
cfg.setValue("window/main_splitter", self._main_splitter.sizes())
|
||||
cfg.setValue("last_active", time.time())
|
||||
_log.info('save settings')
|
||||
#QMainWindow.closeEvent(self, event)
|
||||
_log.info('closeEvent done')
|
||||
@@ -3242,6 +3210,27 @@ def sigint_handler(*args):
|
||||
app.quit()
|
||||
|
||||
|
||||
class StartupSplash:
|
||||
|
||||
def __init__(self):
|
||||
splash_pix = QPixmap("artwork/logo/256x256.png")
|
||||
self._wnd=splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
|
||||
splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
|
||||
splash.setEnabled(False)
|
||||
|
||||
self._prgsBar=prgs=QProgressBar(splash)
|
||||
prgs.setMaximum(100)
|
||||
prgs.setGeometry(0, splash_pix.height() - 50, splash_pix.width(), 20)
|
||||
|
||||
splash.show()
|
||||
|
||||
def set(self,i,msg):
|
||||
self._prgsBar.setValue(i)
|
||||
self._wnd.showMessage(f"<font color='red'>{msg}</font></h1>", int(Qt.AlignBottom|Qt.AlignCenter), Qt.black)
|
||||
app=QApplication.instance()
|
||||
app.processEvents()
|
||||
time.sleep(.1)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
@@ -3253,38 +3242,11 @@ def main():
|
||||
args = parser.parse_args()
|
||||
_log.info('Arguments:{}'.format(args.__dict__))
|
||||
|
||||
# needed so pycharm can restart application
|
||||
signal.signal(signal.SIGINT, sigint_handler)
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
# set app icon
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app._args=args
|
||||
|
||||
if args.sim&0x01:
|
||||
app._backlight = backlight.Backlight(None)
|
||||
else:
|
||||
app._backlight = backlight.Backlight()
|
||||
if args.sim&0x02:
|
||||
app._illumination = illumination.IlluminationControl(None)
|
||||
else:
|
||||
app._illumination = illumination.IlluminationControl()
|
||||
if args.sim&0x04:
|
||||
app._zoom = zoom.QopticZoom(None)
|
||||
else:
|
||||
app._zoom = zoom.QopticZoom()
|
||||
if args.sim&0x08:
|
||||
app._camera = camera.epics_cam(None)
|
||||
app._camera.sim_gen(mode=1)
|
||||
else:
|
||||
app._camera = camera.epics_cam()
|
||||
#app._camera.run() is called in center_piece_update
|
||||
app._geometry=geometry.geometry()
|
||||
|
||||
|
||||
|
||||
app_icon = QtGui.QIcon()
|
||||
app_icon.addFile("artwork/logo/16x16.png", QtCore.QSize(16, 16))
|
||||
app_icon.addFile("artwork/logo/24x24.png", QtCore.QSize(24, 24))
|
||||
@@ -3293,29 +3255,55 @@ def main():
|
||||
app_icon.addFile("artwork/logo/256x256.png", QtCore.QSize(256, 256))
|
||||
app.setWindowIcon(app_icon)
|
||||
|
||||
splash_pix = QPixmap("artwork/logo/256x256.png")
|
||||
splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
|
||||
splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
|
||||
splash.setEnabled(False)
|
||||
startupWin=StartupSplash()
|
||||
|
||||
progressBar = QProgressBar(splash)
|
||||
progressBar.setMaximum(10)
|
||||
progressBar.setGeometry(0, splash_pix.height() - 50, splash_pix.width(), 20)
|
||||
#for i in range(1, 20):
|
||||
# startupWin.set(i,f'sample startup text {i}')
|
||||
# #app.processEvents()
|
||||
# t = time.time()
|
||||
# #while time.time() < t + 0.1:
|
||||
# # app.processEvents()
|
||||
|
||||
splash.show()
|
||||
# splash.showMessage("<h1><font color='red'>Solid support scanning brought to you by</font></h1>", Qt.AlignTop | Qt.AlignCenter, Qt.black)
|
||||
#app._settings=QSettings("PSI", "SwissMX")
|
||||
|
||||
for i in range(1, 11):
|
||||
progressBar.setValue(i)
|
||||
t = time.time()
|
||||
while time.time() < t + 0.1:
|
||||
app.processEvents()
|
||||
app._args=args
|
||||
|
||||
startupWin.set(5, f'load settings')
|
||||
app._cfg=AppCfg()
|
||||
app._geometry=geometry.geometry()
|
||||
|
||||
startupWin.set(15, f'connect backlight')
|
||||
if args.sim&0x01:
|
||||
app._backlight = backlight.Backlight(None)
|
||||
else:
|
||||
app._backlight = backlight.Backlight()
|
||||
startupWin.set(20, f'connect illumination')
|
||||
if args.sim&0x02:
|
||||
app._illumination = illumination.IlluminationControl(None)
|
||||
else:
|
||||
app._illumination = illumination.IlluminationControl()
|
||||
startupWin.set(40, f'connect zoom')
|
||||
if args.sim&0x04:
|
||||
app._zoom = zoom.QopticZoom(None)
|
||||
else:
|
||||
app._zoom = zoom.QopticZoom()
|
||||
startupWin.set(60, f'connect camera')
|
||||
if args.sim&0x08:
|
||||
app._camera = camera.epics_cam(None)
|
||||
app._camera.sim_gen(mode=1)
|
||||
else:
|
||||
app._camera = camera.epics_cam()
|
||||
#app._camera.run() is called in center_piece_update
|
||||
|
||||
startupWin.set(60, f'start main window')
|
||||
|
||||
main = Main()
|
||||
main.show()
|
||||
splash.finish(main)
|
||||
startupWin._wnd.finish(main)
|
||||
|
||||
# needed so pycharm can restart application
|
||||
signal.signal(signal.SIGINT, sigint_handler)
|
||||
|
||||
#main.update_user_and_storage() #ZAC: orig. code
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user