Source code for siriushla.bl_ap_imgproc.main
"""BL AP ImgProc."""
from datetime import datetime
from qtpy.QtCore import Qt, QTimer
from qtpy.QtWidgets import QWidget, QGridLayout, QHBoxLayout, \
QVBoxLayout, QGroupBox, QLabel, QSizePolicy, QTabWidget, \
QPushButton, QScrollArea
import qtawesome as qta
from pydm.widgets import PyDMPushButton
from ..widgets import SiriusEnumComboBox
from ..widgets.dialog import StatusDetailDialog
from siriuspy.envars import VACA_PREFIX as _VACA_PREFIX
from .. import util as _util
from ..util import get_appropriate_color
from ..widgets import SiriusLabel, SiriusLedState, \
SiriusLineEdit, PyDMLogLabel, PyDMStateButton, \
SiriusConnectionSignal, SiriusSpinbox, SiriusLedAlert
from .util import PVS_IMGPROCCTRL, PVS_IMGPROCOVERVIEW, PVS_DVF, \
IMG_PVS, LOG_PV, COMBOBOX_PVS, LINEEDIT_PVS, STATEBUT_PVS, \
LED_ALERT_PVS, LED_STATE_PVS, LED_DETAIL_PVS, INTLK_PVS
from .image import DVFImageView
from .blintlkctl import BLIntckCtrl
[docs]
class BLImgProc(QWidget):
"""Image Processing Window."""
def __init__(self, dvf, parent=None, prefix=_VACA_PREFIX):
"""."""
super().__init__(parent=parent)
self.setObjectName('SIApp')
self.prefix = prefix + ('-' if prefix else '')
self.dvf = dvf
self.device = self.prefix + self.dvf
self.blpps = BLIntckCtrl(self.device)
self.setWindowTitle(self.device + ' Image Processing Window')
self.setWindowIcon(
qta.icon('mdi.camera-metering-center',
color=get_appropriate_color('SI')))
self._lbl_timestamp = {}
self.timestamp = {}
self.img_view = None
self.loading = QPushButton("")
self.open_beamline_btn = None
self.enable_gamma_btn = None
self.gamma_enabled_conn = None
self._setupUi()
self.timer = QTimer()
self.timer.timeout.connect(self.update_bl_open_status)
self.timer.start(1000)
[docs]
def generate_pv_name(self, sufix):
"""."""
if len(sufix) != 2:
return self.add_prefixes(sufix)
pv_list = []
for sf in sufix:
try:
pvname = self.add_prefixes(sf)
pv_list.append(pvname)
except:
pv_list.append(sf)
return pv_list
[docs]
def format_datetime_lbl(self, value, pvname):
"""."""
dtval = datetime.fromtimestamp(value)
datetime_lbl = dtval.strftime("%d/%m/%Y, %H:%M:%S")
datetime_lbl += '.{:03d}'.format(int(1e3*(value % 1)))
self._lbl_timestamp[pvname].setText(datetime_lbl)
[docs]
def create_time_widget(self, pvname):
"""."""
lbl_time = QLabel('0000-00-00 0:00:00.0', self)
self._lbl_timestamp[pvname] = lbl_time
self._lbl_timestamp[pvname].channel = pvname
self.timestamp[pvname] = SiriusConnectionSignal(pvname)
self.timestamp[pvname].new_value_signal[float].connect(
lambda value: self.format_datetime_lbl(value, pvname))
return self._lbl_timestamp[pvname]
[docs]
def select_widget(
self, pv_name, widget_type='label', units=True, labels=None):
"""."""
pvname = self.generate_pv_name(pv_name)
if widget_type == 'label':
wid = SiriusLabel(init_channel=pvname, keep_unit=True)
wid.showUnits = units
wid.setAlignment(Qt.AlignCenter)
wid.setMaximumHeight(50)
elif widget_type == 'setpoint_readback_combo':
sprb_type = ['enumcombo', 'label', True]
wid = self.setpoint_readback_widget(pv_name, sprb_type)
elif widget_type == 'setpoint_readback_edit':
sprb_type = ['edit', 'label', False]
wid = self.setpoint_readback_widget(pv_name, sprb_type)
elif widget_type == 'setpoint_readback_sbut':
sprb_type = ['switch', 'led_state', True]
wid = self.setpoint_readback_widget(pv_name, sprb_type)
elif widget_type == 'setpoint_readback_spin':
sprb_type = ['spin', 'label', True]
wid = self.setpoint_readback_widget(pv_name, sprb_type)
elif widget_type == 'led_state':
wid = SiriusLedState(init_channel=pvname)
wid.offColor = wid.Yellow
elif widget_type == 'led_alert':
wid = SiriusLedAlert(init_channel=pvname)
wid.onColor = wid.Yellow
elif widget_type == 'leddetail':
led = SiriusLedAlert(init_channel=pvname[0])
details = QPushButton(qta.icon('fa5s.ellipsis-h'), '', self)
details.setObjectName('bt')
details.setStyleSheet(
'#bt{min-width:25px;max-width:25px;icon-size:20px;}')
_util.connect_window(
details, StatusDetailDialog, pvname=pvname[0], parent=self,
labels=pvname[1], section="SI", title='Status Detailed')
wid = QWidget()
hlay = QHBoxLayout(wid)
hlay.addWidget(led)
hlay.addWidget(details)
elif widget_type == 'log':
wid = PyDMLogLabel(init_channel=pvname)
elif widget_type == 'edit':
wid = SiriusLineEdit(init_channel=pvname)
wid.setAlignment(Qt.AlignCenter)
elif widget_type == 'switch':
wid = PyDMStateButton(init_channel=pvname)
elif widget_type == 'enumcombo':
wid = SiriusEnumComboBox(self, init_channel=pvname)
elif widget_type == 'image':
wid = DVFImageView(self.device, pvname)
elif widget_type == 'time':
wid = self.create_time_widget(pvname)
wid.setAlignment(Qt.AlignCenter)
elif widget_type == 'spin':
wid = SiriusSpinbox(init_channel=pvname)
elif widget_type == 'cmd':
wid = PyDMPushButton(init_channel=pvname, pressValue=1)
wid.setIcon(qta.icon('fa5s.sync'))
wid.setObjectName('bt')
wid.setStyleSheet(
'#bt{min-width:25px;max-width:25px;icon-size:20px;}')
else:
wid = QLabel("Widget has not been implemented yet!")
return wid
[docs]
def setpoint_readback_widget(self, pv_list, sprb_type):
"""."""
wid = QWidget()
wid.setContentsMargins(0, 0, 0, 0)
if sprb_type[2]:
lay = QHBoxLayout()
else:
lay = QVBoxLayout()
wid.setLayout(lay)
for x in range(0, 2):
widget = self.select_widget(
pv_list[x], sprb_type[x], units=False)
widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
lay.addWidget(widget)
return wid
[docs]
def create_widget(self, title, pv_name):
"""."""
if title in LED_ALERT_PVS:
wid_type = 'led_alert'
elif title in LED_STATE_PVS:
wid_type = 'led_state'
elif title in LED_DETAIL_PVS:
wid_type = 'leddetail'
elif 'Time' in pv_name and 'Proc' not in pv_name:
wid_type = 'time'
elif '-Cmd' in pv_name:
wid_type = 'cmd'
elif title in LOG_PV:
wid_type = 'log'
elif title in IMG_PVS:
wid_type = 'image'
elif len(pv_name) != 2:
wid_type = 'label'
elif title in COMBOBOX_PVS:
wid_type = 'setpoint_readback_combo'
elif title in LINEEDIT_PVS:
wid_type = 'setpoint_readback_edit'
elif title in STATEBUT_PVS:
wid_type = 'setpoint_readback_sbut'
else:
wid_type = 'setpoint_readback_spin'
hlay = QHBoxLayout()
wid = self.select_widget(pv_name, wid_type)
if wid_type not in ['log', 'image']:
title_wid = QLabel(title + ': ')
title_wid.setAlignment(Qt.AlignRight)
hlay.addWidget(
title_wid, alignment=Qt.AlignRight | Qt.AlignVCenter)
hlay.addWidget(wid, alignment=Qt.AlignLeft)
else:
hlay.addWidget(wid)
return hlay
[docs]
def create_box_group(self, title, pv_info):
"""."""
wid = QGroupBox(title) if title else QWidget()
gbox = QGridLayout(wid)
count = 0
for title, pv in pv_info.items():
if title in ['X', 'Y']:
widget = self.create_box_group(title, pv)
hpos = 0 if title == 'X' else 1
gbox.addWidget(widget, count, hpos, 1, 1)
if title == 'Y':
count += 1
else:
pv_lay = self.create_widget(title, pv)
gbox.addLayout(pv_lay, count, 0, 1, 2)
count += 1
return wid
def _setupTab(self, content, use_scroll=False):
cont_wid = QWidget()
cont_wid.setObjectName('wid')
glay = QGridLayout()
for title, pv_data in content.items():
loc = pv_data[0]
if len(pv_data[1:]) > 1:
wid = QGroupBox(title, self)
widlay = QHBoxLayout(wid)
for data in pv_data[1:]:
col = self.create_box_group("", data)
widlay.addWidget(col)
else:
wid = self.create_box_group(title, pv_data[1])
glay.addWidget(wid, *loc)
glay.setColumnStretch(0, 3)
glay.setColumnStretch(1, 1)
glay.setColumnStretch(2, 1)
cont_wid.setLayout(glay)
if use_scroll:
sc_area = QScrollArea()
sc_area.setWidgetResizable(True)
cont_wid.setStyleSheet('#wid{background-color: transparent;}')
sc_area.setWidget(cont_wid)
return sc_area
return cont_wid
[docs]
def toggle_beamline_btns(self, value):
"""."""
if value == 1:
state = True
else:
state = False
self.end_processing_cmd()
self.open_beamline_btn.setEnabled(state)
[docs]
def end_processing_cmd(self):
"""."""
self.enable_gamma_btn.setEnabled(True)
self.open_beamline_btn.setEnabled(True)
self.loading.setVisible(False)
[docs]
def start_processing_cmd(self):
"""."""
self.enable_gamma_btn.setEnabled(False)
self.open_beamline_btn.setEnabled(False)
self.loading.setVisible(True)
[docs]
def intlk_cmd(self, cmd):
"""."""
self.start_processing_cmd()
if cmd == "enable_gamma":
self.blpps.gamma_enable()
elif cmd == "open_beamline":
self.blpps.beamline_open()
def _setup_gamma_control_widget(self):
wid = QGroupBox()
lay = QHBoxLayout()
wid.setLayout(lay)
wid.setTitle("Gamma")
wid.setMaximumHeight(200)
self.enable_gamma_btn = QPushButton("Enable")
self.enable_gamma_btn.clicked.connect(
lambda: self.intlk_cmd("enable_gamma"))
lay.addWidget(self.enable_gamma_btn)
pvname = INTLK_PVS["gamma"]
widget = SiriusLedState(init_channel=pvname)
self.gamma_enabled_conn = SiriusConnectionSignal(pvname)
self.gamma_enabled_conn.new_value_signal[int].connect(
self.toggle_beamline_btns)
lay.addWidget(widget)
return wid
[docs]
def update_bl_open_status(self):
"""."""
# update open status led
status_bl = self.blpps.beamline_opened
old_val = self.pydm_led.value
self.pydm_led.value_changed(status_bl)
if old_val != status_bl:
self.end_processing_cmd()
# update log error label
error_bl = self.blpps.blintlk.error_log
self.pydm_lbl.setText(error_bl)
def _setup_enable_beamline_widgets(self):
wid = QGroupBox()
lay = QHBoxLayout()
wid.setLayout(lay)
wid.setTitle("Open Beamline")
wid.setMaximumHeight(200)
self.open_beamline_btn = QPushButton("Open")
self.open_beamline_btn.clicked.connect(
lambda: self.intlk_cmd("open_beamline"))
lay.addWidget(self.open_beamline_btn)
self.pydm_led = SiriusLedState()
self.pydm_led.stateColors = [
self.pydm_led.DarkGreen,
self.pydm_led.LightGreen, self.pydm_led.Gray]
lay.addWidget(self.pydm_led)
return wid
def _setup_beamline_error_log(self):
wid = QGroupBox()
lay = QHBoxLayout()
wid.setLayout(lay)
wid.setTitle("Beamline Status")
wid.setMaximumHeight(200)
self.beamline_error_log = QLabel('Error log: ')
lay.addWidget(self.beamline_error_log)
self.pydm_lbl = QLabel(self.blpps.blintlk.error_log)
lay.addWidget(self.pydm_lbl)
return wid
def _setup_beamline_controls_widgets(self):
wid = QGroupBox()
lay = QVBoxLayout()
wid.setLayout(lay)
self.loading.setIcon(qta.icon(
'fa5s.spinner', animation=qta.Spin(self.loading)))
self.loading.setVisible(False)
self.loading.setFlat(True)
lay.addWidget(self.loading)
widget = self._setup_gamma_control_widget()
lay.setAlignment(Qt.AlignTop)
lay.addWidget(widget)
widget = self._setup_enable_beamline_widgets()
lay.addWidget(widget)
widget = self._setup_beamline_error_log()
lay.addWidget(widget)
return wid
def _setupUi(self):
main_lay = QVBoxLayout()
tab = QTabWidget()
tab.setObjectName('SITab')
title = QLabel(
'<h3>'+self.device+' Image Processing<h3>', self,
alignment=Qt.AlignCenter)
main_lay.addWidget(title)
img_wid = self._setupTab(PVS_IMGPROCOVERVIEW)
tab.addTab(img_wid, "View")
imgproc_wid = self._setupTab(PVS_IMGPROCCTRL)
tab.addTab(imgproc_wid, "Settings")
dvf_wid = self._setupTab(PVS_DVF, use_scroll=True)
tab.addTab(dvf_wid, "DVF")
cax_wid = self._setup_beamline_controls_widgets()
tab.addTab(cax_wid, "CAX")
main_lay.addWidget(tab)
self.setLayout(main_lay)