Source code for siriushla.as_ap_posang.HLPosAng

#!/usr/bin/env python-sirius

"""HLA as_ap_posang module."""

from epics import PV as _PV
from qtpy.QtWidgets import QGridLayout, QLabel, QGroupBox, QAbstractItemView, \
    QSizePolicy as QSzPlcy, QSpacerItem, QPushButton, QHeaderView, QWidget, \
    QMessageBox, QApplication, QHBoxLayout
from qtpy.QtCore import Qt
import qtawesome as qta
from pydm.widgets import PyDMLineEdit, PyDMPushButton

from siriuspy.envars import VACA_PREFIX as _VACA_PREFIX
from siriuspy.posang.csdev import Const
from siriuspy.namesys import SiriusPVName as _PVName

from siriushla import util as _hlautil
from siriushla.widgets import SiriusMainWindow, PyDMLogLabel, SiriusLedAlert, \
    PyDMSpinboxScrollbar, PyDMLedMultiChannel, SiriusConnectionSignal, \
    SiriusLabel, SiriusWaveformTable, SiriusSpinbox, CALabel
from siriushla.as_ps_control import PSDetailWindow as _PSDetailWindow
from siriushla.as_pu_control import PUDetailWindow as _PUDetailWindow
from siriushla.as_ap_configdb import LoadConfigDialog as _LoadConfigDialog


[docs] class PosAngCorr(SiriusMainWindow): """Main Class.""" def __init__(self, parent=None, prefix='', tl=None): """Class construc.""" super(PosAngCorr, self).__init__(parent) if not prefix: self._prefix = _VACA_PREFIX else: self._prefix = prefix self._tl = tl.upper() base_name = _PVName('TL-Glob:AP-PosAng') self.posang_prefix = base_name.substitute( prefix=self._prefix, sec=self._tl) self.setObjectName(self._tl+'App') self.setWindowTitle(self._tl + ' Position and Angle Correction Window') if self._tl == 'TS': self._is_chsept = False ch3_pv = _PV(self.posang_prefix.substitute(propty='CH3-Cte'), connection_timeout=1) if not ch3_pv.wait_for_connection(): self._is_chsept = True if tl == 'ts': corr_h = (Const.TS_CORRH_POSANG_CHSEPT if self._is_chsept else Const.TS_CORRH_POSANG_SEPTSEPT) corr_v = Const.TS_CORRV_POSANG elif tl == 'tb': corr_h = Const.TB_CORRH_POSANG corr_v = Const.TB_CORRV_POSANG self.corrs = dict() self.corrs['CH1'] = _PVName(corr_h[0]) self.corrs['CH2'] = _PVName(corr_h[1]) if len(corr_h) == 3: self.corrs['CH3'] = _PVName(corr_h[2]) self.corrs['CV1'] = _PVName(corr_v[0]) self.corrs['CV2'] = _PVName(corr_v[1]) if len(corr_v) == 4: self.corrs['CV3'] = _PVName(corr_v[2]) self.corrs['CV4'] = _PVName(corr_v[3]) self._just_need_update = False self._update_ref_action = False self._my_input_widgets = list() pvname_injmode = _PVName("AS-Glob:AP-InjCtrl:Mode-Sts") pvname_injmode = pvname_injmode.substitute(prefix=self._prefix) pvname_stdby = _PVName("AS-Glob:AP-InjCtrl:TopUpPUStandbyEnbl-Sts") pvname_stdby = pvname_stdby.substitute(prefix=self._prefix) self.injctrl_enbl_rules = ( '[{"name": "EnblRule", "property": "Enable", ' + '"expression": "ch[1]!=1 or ch[1]==1 and not ch[0]",' + '"channels": [{"channel": "' + pvname_stdby + '", "trigger": true}, {"channel": "' + pvname_injmode + '", "trigger": true}]}]') self.injctrl_vis_rules = ( '[{"name": "VisibleRule", "property": "Visible", ' + '"expression": "ch[1] and ch[0]", ' + '"channels": [{"channel": "' + pvname_stdby + '", "trigger": true}, {"channel": "' + pvname_injmode + '", "trigger": true}]}]') self._setupUi() self.setFocus(True) self.setFocusPolicy(Qt.StrongFocus) self._ask_message = QMessageBox(self) self._ask_message.setWindowTitle('Message') self._ask_message.setText( 'The '+self._tl+' PosAng IOC indicates reference needs to ' 'be updated! Do you want to update the reference?') self._ask_message.setStandardButtons(QMessageBox.No | QMessageBox.Yes) self._ask_message.setDefaultButton(QMessageBox.No) self.app = QApplication.instance() self.app.focusChanged.connect(self._spinbox_onfocus) def _setupUi(self): cwt = QWidget(self) self.setCentralWidget(cwt) # label lab = QLabel( '<h3>'+self._tl+' Position and Angle Correction</h3>', cwt) lab.setStyleSheet(""" min-height:1.55em; max-height: 1.55em; qproperty-alignment: 'AlignVCenter | AlignRight'; background-color: qlineargradient(spread:pad, x1:1, y1:0.0227273, x2:0, y2:0, stop:0 rgba(173, 190, 207, 255), stop:1 rgba(213, 213, 213, 255));""") # warning self.lb_rule_warning = CALabel(self) self.lb_rule_warning.setText( "WARNING:Disable injection standby mode to change PosAng.") if self._tl != 'TB': self.lb_rule_warning.rules = self.injctrl_vis_rules self.lb_rule_warning.setStyleSheet("color: yellow; font-weight: bold;") # update reference button self.pb_updateref = PyDMPushButton( self, 'Update Reference', pressValue=1, init_channel=self.posang_prefix.substitute( propty='SetNewRefKick-Cmd')) if self._tl != 'TB': self.pb_updateref.rules = self.injctrl_enbl_rules self.pb_updateref.setStyleSheet( 'min-height: 2.4em; max-height: 2.4em;') self.led_needrefupdt = SiriusLedAlert( self, self.posang_prefix.substitute(propty='NeedRefUpdate-Mon')) self.ch_needrefupdt = SiriusConnectionSignal( self.posang_prefix.substitute(propty='NeedRefUpdate-Mon')) self.ch_needrefupdt.new_value_signal[int].connect( self._handle_need_update_ref_led) self.led_needrefupdt.setStyleSheet( 'QLed{min-width: 1.29em; max-width: 1.29em;}') box_ref = QHBoxLayout() box_ref.setContentsMargins(0, 0, 0, 0) box_ref.addWidget(self.pb_updateref) box_ref.addWidget(self.led_needrefupdt) # delta setters self.hgbox = QGroupBox('Horizontal', self) self.hgbox.setLayout(self._setupDeltaControlLayout('x')) self.vgbox = QGroupBox('Vertical', self) self.vgbox.setLayout(self._setupDeltaControlLayout('y')) # correctors self.corrgbox = QGroupBox('Correctors', self) self.corrgbox.setLayout(self._setupCorrectorsLayout()) # status self.statgbox = QGroupBox('Correction Status', self) self.statgbox.setLayout(self._setupStatusLayout()) glay = QGridLayout(cwt) glay.setHorizontalSpacing(12) glay.setVerticalSpacing(12) glay.addWidget(lab, 0, 0, 1, 2) glay.addWidget(self.lb_rule_warning, 1, 0, 1, 2) glay.addLayout(box_ref, 2, 0, 1, 2) glay.addWidget(self.hgbox, 3, 0) glay.addWidget(self.vgbox, 3, 1) glay.addWidget(self.corrgbox, 4, 0, 1, 2) glay.addWidget(self.statgbox, 5, 0, 1, 2) # menu act_settings = self.menuBar().addAction('Settings') _hlautil.connect_window(act_settings, CorrParamsDetailWindow, parent=self, tl=self._tl, prefix=self._prefix) # stlesheet self.setStyleSheet(""" SiriusSpinbox{ min-width: 5em; max-width: 5em; } SiriusLabel, PyDMSpinboxScrollbar{ min-width: 8em; max-width: 8em; } QPushButton{ min-width: 8em; } QLabel{ min-height: 1.35em; qproperty-alignment: AlignCenter; } """) def _setupDeltaControlLayout(self, axis=''): # pos label_pos = QLabel("<h4>Δ"+axis+"</h4>", self) sb_deltapos = SiriusSpinbox(self, self.posang_prefix.substitute( propty='DeltaPos'+axis.upper()+'-SP')) sb_deltapos.step_exponent = -2 sb_deltapos.update_step_size() if self._tl != 'TB': sb_deltapos.rules = self.injctrl_enbl_rules lb_deltapos = SiriusLabel(self, self.posang_prefix.substitute( propty='DeltaPos'+axis.upper()+'-RB'), keep_unit=True) lb_deltapos.showUnits = True self._my_input_widgets.append(sb_deltapos) # ang label_ang = QLabel("<h4>Δ"+axis+"'</h4>", self) sb_deltaang = SiriusSpinbox(self, self.posang_prefix.substitute( propty='DeltaAng'+axis.upper()+'-SP')) sb_deltaang.step_exponent = -2 sb_deltaang.update_step_size() if self._tl != 'TB': sb_deltaang.rules = self.injctrl_enbl_rules lb_deltaang = SiriusLabel(self, self.posang_prefix.substitute( propty='DeltaAng'+axis.upper()+'-RB'), keep_unit=True) lb_deltaang.showUnits = True self._my_input_widgets.append(sb_deltaang) lay = QGridLayout() lay.setVerticalSpacing(12) lay.setHorizontalSpacing(12) lay.addItem( QSpacerItem(10, 0, QSzPlcy.Expanding, QSzPlcy.Ignored), 0, 0) lay.addWidget(label_pos, 0, 1) lay.addWidget(sb_deltapos, 0, 2) lay.addWidget(lb_deltapos, 0, 3) lay.addWidget(label_ang, 1, 1) lay.addWidget(sb_deltaang, 1, 2) lay.addWidget(lb_deltaang, 1, 3) lay.addItem( QSpacerItem(10, 0, QSzPlcy.Expanding, QSzPlcy.Ignored), 0, 4) return lay def _setupCorrectorsLayout(self): lay = QGridLayout() lay.setVerticalSpacing(9) lay.setHorizontalSpacing(9) label_kicksp = QLabel('<h4>Kick-SP</h4>', self) label_kickrb = QLabel('<h4>Kick-RB</h4>', self) label_kickref = QLabel('<h4>RefKick-Mon</h4>', self) lay.addWidget(label_kicksp, 0, 2) lay.addWidget(label_kickrb, 0, 3) lay.addWidget(label_kickref, 0, 4) idx = 1 for corrid, corr in self.corrs.items(): pbt = QPushButton(qta.icon('fa5s.list-ul'), '', self) pbt.setObjectName('pbt') pbt.setStyleSheet(""" #pbt{ min-width:25px; max-width:25px; min-height:25px; max-height:25px; icon-size:20px;} """) if corr.dis == 'PU': _hlautil.connect_window( pbt, _PUDetailWindow, self, devname=corr) else: _hlautil.connect_window( pbt, _PSDetailWindow, self, psname=corr) lb_name = QLabel(corr, self) le_sp = PyDMSpinboxScrollbar( self, corr.substitute(prefix=self._prefix, propty='Kick-SP')) le_sp.spinbox.setAlignment(Qt.AlignCenter) le_sp.scrollbar.limitsFromPV = True lb_rb = SiriusLabel(self, corr.substitute( prefix=self._prefix, propty='Kick-RB'), keep_unit=True) lb_rb.showUnits = True lb_ref = SiriusLabel(self, self.posang_prefix.substitute( propty='RefKick'+corrid+'-Mon'), keep_unit=True) lb_ref.showUnits = True lay.addWidget(pbt, idx, 0, alignment=Qt.AlignTop) lay.addWidget( lb_name, idx, 1, alignment=Qt.AlignLeft | Qt.AlignTop) lay.addWidget(le_sp, idx, 2, alignment=Qt.AlignTop) lay.addWidget(lb_rb, idx, 3, alignment=Qt.AlignTop) lay.addWidget(lb_ref, idx, 4, alignment=Qt.AlignTop) idx += 1 lay.addItem( QSpacerItem(0, 15, QSzPlcy.Preferred, QSzPlcy.Fixed), idx, 0) kckr = 'BO-01D:PU-InjKckr' if self._tl == 'TB' \ else 'SI-01SA:PU-InjNLKckr' self._kckr_name = _PVName(kckr) lay.addItem(QSpacerItem(0, 8, QSzPlcy.Ignored, QSzPlcy.Fixed)) pb_kckr = QPushButton(qta.icon('fa5s.list-ul'), '', self) pb_kckr.setObjectName('pb') pb_kckr.setStyleSheet(""" #pb{ min-width:25px; max-width:25px; min-height:25px; max-height:25px; icon-size:20px;} """) lb_kckr_name = QLabel(self._kckr_name, self) _hlautil.connect_window( pb_kckr, _PUDetailWindow, self, devname=self._kckr_name) lb_kckr_sp = PyDMSpinboxScrollbar( self, self._kckr_name.substitute( prefix=self._prefix, propty='Kick-SP')) lb_kckr_sp.scrollbar.limitsFromPV = True lb_kckr_rb = SiriusLabel(self, self._kckr_name.substitute( prefix=self._prefix, propty='Kick-RB'), keep_unit=True) lb_kckr_rb.showUnits = True lb_kckr_mn = SiriusLabel(self, self._kckr_name.substitute( prefix=self._prefix, propty='Kick-Mon'), keep_unit=True) lb_kckr_mn.showUnits = True lay.addWidget(pb_kckr, idx+2, 0, alignment=Qt.AlignTop) lay.addWidget( lb_kckr_name, idx+2, 1, alignment=Qt.AlignLeft | Qt.AlignTop) lay.addWidget(lb_kckr_sp, idx+2, 2, alignment=Qt.AlignTop) lay.addWidget(lb_kckr_rb, idx+2, 3, alignment=Qt.AlignTop) lay.addWidget(lb_kckr_mn, idx+2, 4, alignment=Qt.AlignTop) if self._tl == 'TB': pref = self._prefix + ('-' if self._prefix else '') lay.addItem(QSpacerItem(0, 8, QSzPlcy.Ignored, QSzPlcy.Fixed)) label_voltsp = QLabel('<h4>Amplitude-SP</h4>', self) label_voltrb = QLabel('<h4>Amplitude-RB</h4>', self) lay.addWidget(label_voltsp, idx+3, 2) lay.addWidget(label_voltrb, idx+3, 3) lb_kly2_name = QLabel('Klystron 2', self) le_kly2_sp = PyDMSpinboxScrollbar( self, pref+'LA-RF:LLRF:KLY2:SET_AMP') le_kly2_sp.spinbox.precisionFromPV = False le_kly2_sp.spinbox.precision = 2 le_kly2_sp.spinbox.setAlignment(Qt.AlignCenter) le_kly2_sp.scrollbar.limitsFromPV = True lb_kly2_rb = SiriusLabel( self, pref+'LA-RF:LLRF:KLY2:GET_AMP', keep_unit=True) lb_kly2_rb.precisionFromPV = False lb_kly2_rb.precision = 2 lb_kly2_rb.showUnits = True lay.addWidget(lb_kly2_name, idx+4, 1, alignment=Qt.AlignLeft | Qt.AlignTop) lay.addWidget(le_kly2_sp, idx+4, 2, alignment=Qt.AlignTop) lay.addWidget(lb_kly2_rb, idx+4, 3, alignment=Qt.AlignTop) return lay def _setupStatusLayout(self): self.log = PyDMLogLabel( self, self.posang_prefix.substitute(propty='Log-Mon')) self.lb_sts0 = QLabel(Const.STATUSLABELS[0], self) self.led_sts0 = SiriusLedAlert( self, self.posang_prefix.substitute(propty='Status-Mon'), bit=0) self.lb_sts1 = QLabel(Const.STATUSLABELS[1], self) self.led_sts1 = SiriusLedAlert( self, self.posang_prefix.substitute(propty='Status-Mon'), bit=1) self.lb_sts2 = QLabel(Const.STATUSLABELS[2], self) self.led_sts2 = SiriusLedAlert( self, self.posang_prefix.substitute(propty='Status-Mon'), bit=2) self.lb_sts3 = QLabel(Const.STATUSLABELS[3], self) self.led_sts3 = SiriusLedAlert( self, self.posang_prefix.substitute(propty='Status-Mon'), bit=3) self.pb_config = PyDMPushButton( self, label='Config Correctors', pressValue=1, init_channel=self.posang_prefix.substitute(propty='ConfigPS-Cmd')) lay = QGridLayout() lay.setVerticalSpacing(12) lay.setHorizontalSpacing(12) lay.addWidget(self.log, 0, 0, 6, 1) lay.addWidget(self.lb_sts0, 1, 2) lay.addWidget(self.led_sts0, 1, 1) lay.addWidget(self.lb_sts1, 2, 2) lay.addWidget(self.led_sts1, 2, 1) lay.addWidget(self.lb_sts2, 3, 2) lay.addWidget(self.led_sts2, 3, 1) lay.addWidget(self.lb_sts3, 4, 2) lay.addWidget(self.led_sts3, 4, 1) lay.addWidget(self.pb_config, 5, 1, 1, 2) if self._tl == 'TS': ch1pvn = self.posang_prefix.substitute(propty='CH1-Cte') self.led_corrtype = PyDMLedMultiChannel( self, {ch1pvn: self.corrs['CH1']}) self.lb_corrtype = QLabel( 'Control ' + ('CH-Sept' if self._is_chsept else 'Sept-Sept')) lay.addWidget(self.led_corrtype, 0, 1) lay.addWidget(self.lb_corrtype, 0, 2) return lay def _handle_need_update_ref_led(self, value): self._just_need_update = bool(value) def _spinbox_onfocus(self, old_focus, new_focus): if not self._update_ref_action and not self._just_need_update: return if self.led_needrefupdt.value != 0: if new_focus in self._my_input_widgets and self._just_need_update: ans = self._ask_message.exec_() if ans == QMessageBox.No: self._update_ref_action = False else: self._update_ref_action = True self.pb_updateref.sendValue() self._just_need_update = False
[docs] class CorrParamsDetailWindow(SiriusMainWindow): """Correction parameters detail window.""" def __init__(self, tl, parent=None, prefix=None): """Class constructor.""" super(CorrParamsDetailWindow, self).__init__(parent) self._tl = tl self._prefix = prefix self.posang_prefix = _PVName(self._tl+'-Glob:AP-PosAng') self.posang_prefix = self.posang_prefix.substitute(prefix=prefix) self.setObjectName(tl.upper()+'App') self.setWindowTitle( self._tl + ' Position and Angle Correction Parameters') self._setupUi() def _setupUi(self): label_configname = QLabel('<h4>Configuration Name</h4>', self, alignment=Qt.AlignCenter) self.pydmlinedit_configname = _ConfigLineEdit( self, self.posang_prefix.substitute(propty='ConfigName-SP')) self.pydmlabel_configname = SiriusLabel( self, self.posang_prefix.substitute(propty='ConfigName-RB')) label_matrix_x = QLabel('<h4>Matrix X</h4>', self, alignment=Qt.AlignCenter) self.table_matrix_x = SiriusWaveformTable( self, self.posang_prefix.substitute(propty='RespMatX-Mon')) self.table_matrix_x.setObjectName('table_matrix_x') self.table_matrix_x.setStyleSheet(""" #table_matrix_x{ min-width:12em; max-width:12em; min-height:4.65em; max-height:4.65em;}""") self.table_matrix_x.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_matrix_x.setRowCount(2) self.table_matrix_x.setColumnCount(2) self.table_matrix_x.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_matrix_x.horizontalHeader().setVisible(False) self.table_matrix_x.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_matrix_x.verticalHeader().setVisible(False) self.table_matrix_x.setSizePolicy( QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) columns = 2 if self._tl == 'TB' else 4 width = 12 if self._tl == 'TB' else 24 label_matrix_y = QLabel('<h4>Matrix Y</h4>', self, alignment=Qt.AlignCenter) self.table_matrix_y = SiriusWaveformTable( self, self.posang_prefix.substitute(propty='RespMatY-Mon')) self.table_matrix_y.setObjectName('table_matrix_y') self.table_matrix_y.setStyleSheet(""" #table_matrix_y{ min-width:valem; max-width:valem; min-height:4.65em; max-height:4.65em;}""".replace( 'val', str(width))) self.table_matrix_y.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_matrix_y.setRowCount(2) self.table_matrix_y.setColumnCount(columns) self.table_matrix_y.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_matrix_y.horizontalHeader().setVisible(False) self.table_matrix_y.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_matrix_y.verticalHeader().setVisible(False) self.table_matrix_y.setSizePolicy( QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) self.bt_apply = QPushButton('Ok', self) self.bt_apply.clicked.connect(self.close) lay = QGridLayout() lay.addItem( QSpacerItem(20, 10, QSzPlcy.Minimum, QSzPlcy.Expanding), 0, 0) lay.addWidget(label_configname, 1, 0, 1, columns) lay.addWidget(self.pydmlinedit_configname, 2, 0, 1, columns) lay.addWidget(self.pydmlabel_configname, 3, 0, 1, columns) lay.addItem( QSpacerItem(20, 10, QSzPlcy.Minimum, QSzPlcy.Expanding), 4, 0) lay.addWidget(label_matrix_x, 5, 0, 1, columns) lay.addWidget(self.table_matrix_x, 6, (columns/2)-1, 1, columns) lay.addItem( QSpacerItem(20, 10, QSzPlcy.Minimum, QSzPlcy.Expanding), 7, 0) lay.addWidget(label_matrix_y, 8, 0, 1, columns) lay.addWidget(self.table_matrix_y, 9, 0, 1, columns) lay.addItem( QSpacerItem(20, 10, QSzPlcy.Minimum, QSzPlcy.Expanding), 10, 0) lay.addWidget(self.bt_apply, 11, columns-1) for i in range(columns): lay.setColumnStretch(i, 1) self.centralwidget = QGroupBox('Correction Parameters') self.centralwidget.setLayout(lay) self.setCentralWidget(self.centralwidget) self.setStyleSheet(""" SiriusLabel{ min-width:valem; max-width:valem; }""".replace('val', str(width)))
class _ConfigLineEdit(PyDMLineEdit): """Configuration line edit.""" def mouseReleaseEvent(self, _): """Reimplement mouseReleaseEvent.""" if 'TB' in self.channel: config_type = 'tb_posang_respm' elif 'TS' in self.channel: config_type = 'ts_posang_respm' popup = _LoadConfigDialog(config_type) popup.configname.connect(self._config_changed) popup.exec_() def _config_changed(self, configname): self.setText(configname) self.send_value() self.value_changed(configname)