cleaner app starting, new application settings class

This commit is contained in:
2022-07-20 17:52:55 +02:00
parent 4a6db36805
commit 569ce8a78d
8 changed files with 224 additions and 176 deletions

View File

@@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QMenu, QAction, QSpinBox, QMenu
from pyqtgraph import ROI, Point, RectROI, mkPen from pyqtgraph import ROI, Point, RectROI, mkPen
from pyqtgraph import functions as fn from pyqtgraph import functions as fn
from app_config import settings from app_config import AppCfg# settings
from math import * from math import *

View File

@@ -14,13 +14,13 @@ from pathlib import Path
#import qsingleton #ZAC: orig. code #import qsingleton #ZAC: orig. code
#from CoordinatesModel import CoordinatesModel #ZAC: orig. code #from CoordinatesModel import CoordinatesModel #ZAC: orig. code
from app_config import settings, appsconf, option from app_config import AppCfg #settings, option, appsconf
EMBL_RESULTS_TIMEOUT = "embl/results_timeout" EMBL_RESULTS_TIMEOUT = "embl/results_timeout"
EMBL_SAVE_FILES = "embl/save_files" EMBL_SAVE_FILES = "embl/save_files"
embl = appsconf["embl"] #embl = appsconf["embl"]
#import imageio #import imageio
import numpy as np import numpy as np
@@ -72,6 +72,7 @@ class EmblMessage(QObject):
def __init__(self, parent=None, **kwargs): def __init__(self, parent=None, **kwargs):
super(EmblMessage, self).__init__(parent, **kwargs) super(EmblMessage, self).__init__(parent, **kwargs)
return #ZAC: orig. code
if not embl["enabled"]: if not embl["enabled"]:
return return
context = zmq.Context() context = zmq.Context()

View File

@@ -34,7 +34,7 @@ logger = logging.getLogger(__name__)
# from coord_library import conversions # from coord_library import conversions
#import conversions #ZAC: orig. code #import conversions #ZAC: orig. code
from app_config import settings from app_config import AppCfg
#from storage import Folders #ZAC: orig. code #from storage import Folders #ZAC: orig. code
#folders = Folders() #ZAC: orig. code #folders = Folders() #ZAC: orig. code

View File

@@ -1,4 +1,3 @@
#TODO: #TODO:
# currently 2 settings/configs are used # currently 2 settings/configs are used
# QSettings -> cat ~/.config/Paul\ Scherrer\ Institut/SwissMX.conf # QSettings -> cat ~/.config/Paul\ Scherrer\ Institut/SwissMX.conf
@@ -6,54 +5,102 @@
# QSettings are changed by program # QSettings are changed by program
# #yaml is fixed and not altened by program # #yaml is fixed and not altened by program
import yaml
from PyQt5.QtCore import QSettings
from pathlib import Path
import logging import logging
logger = logging.getLogger(__name__) _log = logging.getLogger(__name__)
import os
from PyQt5.QtCore import QSettings
#import yaml
#from pathlib import Path
class AppCfg(QSettings):
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"
def __init__(self):
super(AppCfg, self).__init__("PSI", "SwissMX")
keys = self.allKeys()
if AppCfg.ACTIVATE_PULSE_PICKER not in keys:
self.setValue(AppCfg.ACTIVATE_PULSE_PICKER, False)
if AppCfg.SKIP_ESCAPE_TRANSITIONS_IF_SAFE not in keys:
self.setValue(AppCfg.SKIP_ESCAPE_TRANSITIONS_IF_SAFE, False)
if "hits/marker_size" not in keys:
self.setValue("hits/marker_size", 10)
if "graphs/show_auxiliary" not in keys:
self.setValue("graphs/show_auxiliary", False)
if "graphs/auxiliary_graph_index" not in keys:
self.setValue("graphs/auxiliary_graph_index", 0)
if "scan_request/last_location" not in keys:
d10 = os.path.join(os.path.expanduser("~"), "Data10")
self.setValue("scan_request/last_location", d10)
if AppCfg.BEAM_SIZE in keys:
_log.info("setting beamsize from stored settings: {}".format(self.value(AppCfg.BEAM_SIZE)))
else:
_log.warning("beam size may not reflect reality, please check")
self.setValue(AppCfg.BEAM_SIZE, (40, 20))
settings = QSettings("PSI", "SwissMX") def option(self,key: str) -> bool:
inst_folder = Path(__file__).absolute().parent
config_file = inst_folder / "swissmx.yaml"
configs = yaml.load(config_file.read_text(),Loader=yaml.FullLoader)
endstation = configs["configure_for"]
appsconf = configs[endstation]
simulated = appsconf.get("simulate", False)
logger.info(f"configuring for endstation: {endstation.upper()}")
if simulated:
logger.warning("SIMULATION is ACTIVE")
css_file = inst_folder / "swissmx.css"
def font(name: str) -> str:
p = Path(__file__).absolute().parent / "fonts" / name
return str(p)
def logo(size: int = 0) -> str:
p = Path(__file__).absolute().parent / "logos" / "logo.png"
if size:
p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png"
return str(p)
def option(key: str) -> bool:
try: try:
return settings.value(key, type=bool) return self.value(key, type=bool)
except: except:
logger.error(f"option {key} not known") _log.error(f"option {key} not known")
return False return False
def toggle_option(self,key: str):
v = self.value(key, type=bool)
self.setValue(key, not v)
self.sync()
#inst_folder = Path(__file__).absolute().parent
#config_file = inst_folder / "swissmx.yaml"
#configs = yaml.load(config_file.read_text(),Loader=yaml.FullLoader)
#endstation = configs["configure_for"]
#appsconf = configs[endstation]
#simulated = appsconf.get("simulate", False)
#logger.info(f"configuring for endstation: {endstation.upper()}")
#if simulated:
# logger.warning("SIMULATION is ACTIVE")
#css_file = inst_folder / "swissmx.css"
#def font(name: str) -> str:
# p = Path(__file__).absolute().parent / "fonts" / name
# return str(p)
#def logo(size: int = 0) -> str:
# p = Path(__file__).absolute().parent / "logos" / "logo.png"
# if size:
# p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png"
# return str(p)
def toggle_option(key: str):
v = settings.value(key, type=bool)
settings.setValue(key, not v)
settings.sync()

View File

@@ -341,6 +341,15 @@ if __name__ == "__main__":
exit(0) exit(0)
n += 1 n += 1
else: else:
def closeEvent(cam,evt):
print(args)
try:
pv=cam._pv['pic']
pv.clear_auto_monitor() # disconnect PV monitor callback -> program exit faster.
except AttributeError:
_log.warning('disconnect PV callback failed.')
class UIcamera(epics_cam): class UIcamera(epics_cam):
def __init__(self, prefix="ESB-MX-CAM"): def __init__(self, prefix="ESB-MX-CAM"):
@@ -446,7 +455,7 @@ if __name__ == "__main__":
## Display the data and assign each frame a time value from 1.0 to 3.0 ## Display the data and assign each frame a time value from 1.0 to 3.0
cam = UIcamera(prefix=args.prefix) cam = UIcamera(prefix=args.prefix)
win.closeEvent=lambda x:closeEvent(cam, x)
#cam.set_binning(4,4) #cam.set_binning(4,4)
#cam.run() #cam.run()
@@ -470,3 +479,4 @@ if __name__ == "__main__":
## Start Qt event loop unless running in interactive mode. ## Start Qt event loop unless running in interactive mode.
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_() QtGui.QApplication.instance().exec_()

View File

@@ -1,7 +1,7 @@
from PyQt5 import QtWidgets, QtGui from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QDoubleSpinBox, QMessageBox from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QDoubleSpinBox, QMessageBox
from app_config import option, toggle_option from app_config import AppCfg #option, toggle_option
def toggle_warn(key): def toggle_warn(key):

View File

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

18
zoom.py
View File

@@ -32,7 +32,7 @@ from PyQt5.uic import loadUiType
import backlight, illumination, camera import backlight, illumination, camera
import epics import epics
from app_config import settings from app_config import AppCfg #settings
Ui_Zoom, QWidget = loadUiType("zoom.ui") Ui_Zoom, QWidget = loadUiType("zoom.ui")
MIN_ZOOM = 1 MIN_ZOOM = 1
@@ -50,19 +50,21 @@ class Zoom(QGroupBox, Ui_Zoom):
self.setTitle("Sample Viewing") self.setTitle("Sample Viewing")
def configure(self): def configure(self):
keys = settings.allKeys() app=QApplication.instance()
cfg=app._cfg
keys=cfg.allKeys()
if "sample_viewing/zoom_buttons" not in keys: if "sample_viewing/zoom_buttons" not in keys:
settings.setValue("sample_viewing/zoom_buttons", cfg.setValue("sample_viewing/zoom_buttons",
json.dumps([(1, "1"),(200, "200"),(400, "400"),(600, "600"),(800, "800"),(1000, "1000"),]),) json.dumps([(1, "1"),(200, "200"),(400, "400"),(600, "600"),(800, "800"),(1000, "1000"),]),)
buttons = json.loads(settings.value("sample_viewing/zoom_buttons")) buttons = json.loads(cfg.value("sample_viewing/zoom_buttons"))
if "backlight/backlight_pv" not in keys: if "backlight/backlight_pv" not in keys:
settings.setValue("backlight/backlight_pv", "SAR-EXPMX:MOT_BLGT") cfg.setValue("backlight/backlight_pv", "SAR-EXPMX:MOT_BLGT")
backlight_pv = settings.value("backlight/backlight_pv") backlight_pv = cfg.value("backlight/backlight_pv")
if "sample_viewing/zoom_api" not in keys: if "sample_viewing/zoom_api" not in keys:
settings.setValue("sample_viewing/zoom_api", "rest://pc12818.psi.ch:9999") cfg.setValue("sample_viewing/zoom_api", "rest://pc12818.psi.ch:9999")
zoom_api = settings.value("sample_viewing/zoom_api") zoom_api = cfg.value("sample_viewing/zoom_api")
#self.get_zoom_pv = PV(zoom_api + ":ZOOM-RBV", callback=self.zoom_update_cb) #self.get_zoom_pv = PV(zoom_api + ":ZOOM-RBV", callback=self.zoom_update_cb)
#self.status_pv = PV(zoom_api + ":ZOOM-STATUS", callback=self.zoom_status_cb) #self.status_pv = PV(zoom_api + ":ZOOM-STATUS", callback=self.zoom_status_cb)