Exemplo n.º 1
0
class InjSysStbyControlWidget(QWidget):
    """Injection System Control Widget."""

    expand = Signal()

    def __init__(self,
                 parent=None,
                 prefix=VACA_PREFIX,
                 is_summary=False,
                 handler=None):
        """Init."""
        super().__init__(parent)
        self.prefix = prefix
        self._inj_prefix = SiriusPVName('AS-Glob:AP-InjCtrl').substitute(
            prefix=prefix)
        self._is_summary = is_summary
        self._last_comm = None

        self._handler = handler or InjSysStandbyHandler()
        self._icon_off = qta.icon('mdi.power-off')
        self._icon_on = qta.icon('mdi.power-on')
        self._icon_check = qta.icon('fa5s.check')
        self._pixmap_check = self._icon_check.pixmap(
            self._icon_check.actualSize(QSize(16, 16)))
        self._icon_not = qta.icon('fa5s.times')
        self._pixmap_not = self._icon_not.pixmap(
            self._icon_not.actualSize(QSize(16, 16)))

        self.menu = QMenu(self)
        self.rstord_act = self.menu.addAction('Reset Commands')
        self.rstord_act.triggered.connect(self._reset_commands_order)

        if is_summary:
            self._setupSummary()
        else:
            self._setupFull()

        self._ch_cmdsts = SiriusConnectionSignal(
            self._inj_prefix.substitute(propty='InjSysCmdSts-Mon'))

        self._ch_off_order_sp = SiriusConnectionSignal(
            self._inj_prefix.substitute(propty='InjSysTurnOffOrder-SP'))
        self._ch_off_order_rb = SiriusConnectionSignal(
            self._inj_prefix.substitute(propty='InjSysTurnOffOrder-RB'))
        self._ch_on_order_sp = SiriusConnectionSignal(
            self._inj_prefix.substitute(propty='InjSysTurnOnOrder-SP'))
        self._ch_on_order_rb = SiriusConnectionSignal(
            self._inj_prefix.substitute(propty='InjSysTurnOnOrder-RB'))
        if not is_summary:
            self._ch_cmdone = SiriusConnectionSignal(
                self._inj_prefix.substitute(propty='InjSysCmdDone-Mon'))

        self._ch_cmdsts.new_value_signal[int].connect(
            self._handle_cmdsts_buttons_enbl)
        self._ch_off_order_rb.new_value_signal[str].connect(
            self._handle_buttons_color)
        self._ch_on_order_rb.new_value_signal[str].connect(
            self._handle_buttons_color)
        self._ch_off_order_rb.new_value_signal[str].connect(
            self._handle_actions_state)
        self._ch_on_order_rb.new_value_signal[str].connect(
            self._handle_actions_state)
        if not is_summary:
            self._ch_cmdone.new_value_signal[str].connect(
                self._handle_cmdone_labels)
            self._ch_cmdsts.new_value_signal[int].connect(
                self._handle_cmdsts_labels)

    def _setupSummary(self):
        self._pb_off = PyDMPushButton(self,
                                      label='',
                                      icon=self._icon_off,
                                      init_channel=self._inj_prefix.substitute(
                                          propty='InjSysTurnOff-Cmd'),
                                      pressValue=0)
        self._pb_off.setObjectName('bt')
        self._pb_off.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;}')
        self._pb_on = PyDMPushButton(self,
                                     label='',
                                     icon=self._icon_on,
                                     init_channel=self._inj_prefix.substitute(
                                         propty='InjSysTurnOn-Cmd'),
                                     pressValue=0)
        self._pb_on.setObjectName('bt')
        self._pb_on.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;}')

        self._led_sts = InjSysStbyLed(self)
        self._led_sts.setStyleSheet(
            'QLed{min-width:1.29em; max-width:1.29em;}')

        lay = QGridLayout(self)
        lay.setAlignment(Qt.AlignCenter)
        lay.addWidget(self._pb_off, 0, 0)
        lay.addWidget(self._pb_on, 0, 1)
        lay.addWidget(self._led_sts, 1, 0, 1, 2, alignment=Qt.AlignCenter)

        # menu
        for cmmtype in ['on', 'off']:
            order = getattr(self._handler, cmmtype + '_order')
            menu = QMenu('Select Turn ' + cmmtype.upper() + ' Commands', self)
            setattr(self, cmmtype + '_menu', menu)
            self.menu.addMenu(menu)
            for cmm in order:
                act = menu.addAction(self._handler.HANDLER_DESC[cmm])
                act.setObjectName(cmm)
                act.setCheckable(True)

    def _setupFull(self):
        lay = QGridLayout(self)

        lay.addWidget(QLabel('Off', self, alignment=Qt.AlignCenter), 0, 1)
        lay.addWidget(QLabel('On', self, alignment=Qt.AlignCenter), 0, 2)
        lay.addWidget(QLabel('Status', self, alignment=Qt.AlignCenter), 0, 3)

        self._checkbox_off = dict()
        self._checkbox_on = dict()
        self._labels_sts = dict()
        for idx, name in enumerate(self._handler.DEF_ON_ORDER):
            cb_off = QCheckBox(self)
            cb_off.setObjectName(name)
            self._checkbox_off[name] = cb_off
            cb_on = QCheckBox(self)
            cb_on.setObjectName(name)
            self._checkbox_on[name] = cb_on
            desc = self._handler.HANDLER_DESC[name]
            splitd = desc.split('(')
            lbl_txt = splitd[0]
            tip = ''
            if len(splitd) > 1:
                lbl_txt, tip = splitd
            lb_dsc = QLabel(lbl_txt, self, alignment=Qt.AlignLeft)
            if tip:
                lb_dsc.setToolTip(tip[:-1])
            lb_sts = QLabel('', self, alignment=Qt.AlignCenter)
            lb_sts.setObjectName(name)
            self._labels_sts[name] = lb_sts
            lay.addWidget(lb_dsc, idx + 1, 0)
            lay.addWidget(cb_off, idx + 1, 1, alignment=Qt.AlignCenter)
            lay.addWidget(cb_on, idx + 1, 2, alignment=Qt.AlignCenter)
            lay.addWidget(lb_sts, idx + 1, 3)

        self._pb_off = PyDMPushButton(self,
                                      label='',
                                      icon=self._icon_off,
                                      init_channel=self._inj_prefix.substitute(
                                          propty='InjSysTurnOff-Cmd'),
                                      pressValue=0)
        self._pb_off.setObjectName('bt')
        self._pb_off.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;}')
        self._pb_on = PyDMPushButton(self,
                                     label='',
                                     icon=self._icon_on,
                                     init_channel=self._inj_prefix.substitute(
                                         propty='InjSysTurnOn-Cmd'),
                                     pressValue=0)
        self._pb_on.setObjectName('bt')
        self._pb_on.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;}')

        self._led_sts = InjSysStbyLed(self)

        lay.addWidget(self._pb_off, 6, 1)
        lay.addWidget(self._pb_on, 6, 2)
        lay.addWidget(self._led_sts, 6, 3)

    @Slot(int)
    def _handle_cmdsts_buttons_enbl(self, new_sts):
        if new_sts == _Const.InjSysCmdSts.On:
            self._pb_on.setEnabled(False)
            self._pb_on.setIcon(
                qta.icon('fa5s.spinner', animation=qta.Spin(self._pb_on)))
            self._pb_off.setEnabled(False)
        elif new_sts == _Const.InjSysCmdSts.Off:
            self._pb_on.setEnabled(False)
            self._pb_off.setEnabled(False)
            self._pb_off.setIcon(
                qta.icon('fa5s.spinner', animation=qta.Spin(self._pb_off)))
        else:
            if not self._pb_on.isEnabled():
                self._pb_on.setEnabled(True)
                self._pb_off.setEnabled(True)
                self._pb_on.setIcon(self._icon_on)
                self._pb_off.setIcon(self._icon_off)

    @Slot(str)
    def _handle_cmdone_labels(self, new_done):
        for name in self._handler.DEF_ON_ORDER:
            lbl = self._labels_sts[name]
            if name in new_done:
                lbl.setPixmap(self._pixmap_check)
            elif self._ch_cmdsts.value == _Const.InjSysCmdSts.Idle:
                lbl.setPixmap(self._pixmap_not)

    @Slot(int)
    def _handle_cmdsts_labels(self, new_sts):
        if new_sts == _Const.InjSysCmdSts.On:
            self._last_comm = new_sts
            for name in self._handler.DEF_ON_ORDER:
                if self._ch_on_order_rb.value is None:
                    break
                lbl = self._labels_sts[name]
                if name in self._ch_on_order_rb.value:
                    icon = qta.icon('fa5s.spinner')
                    pixmap = icon.pixmap(icon.actualSize(QSize(16, 16)))
                    lbl.setPixmap(pixmap)
                else:
                    lbl.setPixmap(QPixmap())
        elif new_sts == _Const.InjSysCmdSts.Off:
            self._last_comm = new_sts
            for name in self._handler.DEF_OFF_ORDER:
                if self._ch_off_order_rb.value is None:
                    break
                lbl = self._labels_sts[name]
                if name in self._ch_off_order_rb.value:
                    icon = qta.icon('fa5s.spinner')
                    pixmap = icon.pixmap(icon.actualSize(QSize(16, 16)))
                    lbl.setPixmap(pixmap)
                else:
                    lbl.setPixmap(QPixmap())
        else:
            done = self._ch_cmdone.value
            for name in self._handler.DEF_ON_ORDER:
                if done is None or name in done:
                    continue
                lbl = self._labels_sts[name]
                if self._last_comm == _Const.InjSysCmdSts.On and \
                        name in self._ch_on_order_rb.value:
                    lbl.setPixmap(self._pixmap_not)
                elif self._last_comm == _Const.InjSysCmdSts.Off and \
                        name in self._ch_off_order_rb.value:
                    lbl.setPixmap(self._pixmap_not)
            self._last_comm = None

    @Slot()
    def _set_commands_order(self):
        if self._is_summary:
            if self.sender() in self.on_menu.actions():
                on_order = [
                    a.objectName() for a in self.on_menu.actions()
                    if a.isChecked()
                ]
                self._ch_on_order_sp.send_value_signal[str].emit(
                    ','.join(on_order))
            elif self.sender() in self.off_menu.actions():
                off_order = [
                    a.objectName() for a in self.off_menu.actions()
                    if a.isChecked()
                ]
                self._ch_off_order_sp.send_value_signal[str].emit(
                    ','.join(off_order))
        else:
            if self.sender() in self._checkbox_on.values():
                checked = [
                    w.objectName() for w in self._checkbox_on.values()
                    if w.isChecked()
                ]
                on_order = [
                    h for h in self._handler.DEF_ON_ORDER if h in checked
                ]
                self._ch_on_order_sp.send_value_signal[str].emit(
                    ','.join(on_order))
            elif self.sender() in self._checkbox_off.values():
                checked = [
                    w.objectName() for w in self._checkbox_off.values()
                    if w.isChecked()
                ]
                off_order = [
                    h for h in self._handler.DEF_OFF_ORDER if h in checked
                ]
                self._ch_off_order_sp.send_value_signal[str].emit(
                    ','.join(off_order))

    @Slot()
    def _reset_commands_order(self):
        self._ch_off_order_sp.send_value_signal[str].emit(','.join(
            self._handler.DEF_OFF_ORDER))
        self._ch_on_order_sp.send_value_signal[str].emit(','.join(
            self._handler.DEF_ON_ORDER))
        if self._is_summary:
            for menu in [self.off_menu, self.on_menu]:
                for act in menu.actions():
                    act.toggled.disconnect()
                    act.setChecked(True)
                    act.toggled.connect(self._set_commands_order)
        else:
            for group in [self._checkbox_off, self._checkbox_on]:
                for wid in group.values():
                    wid.toggled.disconnect()
                    wid.setChecked(True)
                    wid.toggled.connect(self._set_commands_order)

    @Slot()
    def _handle_buttons_color(self):
        off_color = 'yellow' if self._ch_off_order_rb.value != \
            ','.join(self._handler.DEF_OFF_ORDER) else 'white'
        self._pb_off.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;'
            'background-color: ' + off_color + ';}')
        on_color = 'yellow' if self._ch_on_order_rb.value != \
            ','.join(self._handler.DEF_ON_ORDER) else 'white'
        self._pb_on.setStyleSheet(
            '#bt{min-width:25px; max-width:25px; icon-size:20px;'
            'background-color: ' + on_color + ';}')

    @Slot(str)
    def _handle_actions_state(self, sts):
        state = 'on' if 'On' in self.sender().address else 'off'
        channel = getattr(self, '_ch_' + state + '_order_rb')
        if channel.value is None:
            return

        if self._is_summary:
            group = getattr(self, state + '_menu').actions()
        else:
            group = getattr(self, '_checkbox_' + state).values()
        for obj in group:
            obj.disconnect()
            ost = obj.objectName() in sts
            obj.setChecked(ost)
            obj.toggled.connect(self._set_commands_order)

    def contextMenuEvent(self, event):
        """Show a custom context menu."""
        self.menu.popup(self.mapToGlobal(event.pos()))
Exemplo n.º 2
0
class SummaryWidget(QWidget):
    """General widget for controlling a power supply."""
    def __init__(self, name, visible_props, parent=None):
        """Build UI with dclink name."""
        super().__init__(parent)
        self._name = PVName(name)
        self._psmodel = PSSearch.conv_psname_2_psmodel(name)
        self._pstype = PSSearch.conv_psname_2_pstype(name)
        self.visible_props = sort_propties(visible_props)
        self.filled_widgets = set()
        self._prefixed_name = self._name.substitute(prefix=VACA_PREFIX)

        self._analog_name = get_analog_name(self._name)
        self._strength_name = get_strength_name(self._name)
        self._is_pulsed = IsPulsed.match(self._name)
        self._is_linac = IsLinac.match(self._name)
        self._li_has_not_strength = LIQuadHasNotStrength.match(self._name)
        self._is_fofb = FastCorrector.match(self._name)
        self._is_dclink = IsDCLink.match(self._name)
        self._is_regatron = self._psmodel == 'REGATRON_DCLink'
        self._is_reg_slave = self._pstype == 'as-dclink-regatron-slave'

        self._bbb_name = ''
        self._udc_name = ''
        if not self._is_pulsed and not self._is_linac and \
                not self._is_regatron and not self._is_fofb:
            self._bbb_name = PSSearch.conv_psname_2_bbbname(self._name)
            self._udc_name = PSSearch.conv_psname_2_udc(self._name)
        self._has_opmode = not self._is_linac and not self._is_pulsed\
            and not self._is_fofb
        self._has_ctrlmode = not self._is_regatron and not self._is_linac\
            and not self._is_fofb
        self._has_pwrstate = not self._is_reg_slave
        self._has_reset = not self._is_linac and not self._is_fofb\
            and not self._is_reg_slave
        self._has_ctrlloop = not self._is_linac and not self._is_pulsed\
            and not self._is_regatron
        self._has_parmupdt = not self._is_linac and not self._is_regatron\
            and not self._is_fofb
        self._has_wfmupdt = self._has_parmupdt and not self._is_dclink
        self._has_analsp = not self._is_reg_slave
        self._has_analrb = not self._is_regatron
        self._has_analmon = not self._is_fofb
        self._has_strength = bool(self._strength_name
                                  and not self._li_has_not_strength)
        self._has_strength_mon = self._has_strength and not self._is_fofb
        self._has_trim = HasTrim.match(self._name)

        self._create_pvs()
        self._setup_ui()

    @property
    def devname(self):
        """PS name."""
        return self._name

    @property
    def bbbname(self):
        """BBB name."""
        return self._bbb_name

    @property
    def udcname(self):
        """UDC name."""
        return self._udc_name

    def _setup_ui(self):
        """Setups widget UI."""
        lay = QHBoxLayout()
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(10)
        self._widgets_dict = dict()

        self.detail_wid = self._build_widget(name='detail', orientation='v')
        self._widgets_dict['detail'] = self.detail_wid
        lay.addWidget(self.detail_wid)

        if self._bbb_name:
            self.bbb_wid = self._build_widget(name='bbb', orientation='v')
            self._widgets_dict['bbb'] = self.bbb_wid
            lay.addWidget(self.bbb_wid)

        if self._udc_name:
            self.udc_wid = self._build_widget(name='udc', orientation='v')
            self._widgets_dict['udc'] = self.udc_wid
            lay.addWidget(self.udc_wid)

        if self._has_opmode:
            self.opmode_wid = self._build_widget(name='opmode',
                                                 orientation='v')
            self._widgets_dict['opmode'] = self.opmode_wid
            lay.addWidget(self.opmode_wid)

        if self._has_ctrlmode:
            self.ctrlmode_wid = self._build_widget(name='ctrlmode',
                                                   orientation='v')
            self._widgets_dict['ctrlmode'] = self.ctrlmode_wid
            lay.addWidget(self.ctrlmode_wid)

        self.state_wid = self._build_widget(name='state')
        self._widgets_dict['state'] = self.state_wid
        lay.addWidget(self.state_wid)

        if self._is_pulsed:
            self.pulse_wid = self._build_widget(name='pulse')
            self._widgets_dict['pulse'] = self.pulse_wid
            lay.addWidget(self.pulse_wid)

        self.intlk_wid = self._build_widget(name='intlk')
        self._widgets_dict['intlk'] = self.intlk_wid
        lay.addWidget(self.intlk_wid)

        if self._is_linac:
            self.conn_wid = self._build_widget(name='conn')
            self._widgets_dict['conn'] = self.conn_wid
            lay.addWidget(self.conn_wid)

        if self._has_reset:
            self.reset_wid = self._build_widget(name='reset')
            self._widgets_dict['reset'] = self.reset_wid
            lay.addWidget(self.reset_wid)

        if self._has_ctrlloop:
            self.ctrlloop_wid = self._build_widget(name='ctrlloop')
            self._widgets_dict['ctrlloop'] = self.ctrlloop_wid
            lay.addWidget(self.ctrlloop_wid)

        if self._has_wfmupdt:
            self.wfmupdate_wid = self._build_widget(name='wfmupdate')
            self._widgets_dict['wfmupdate'] = self.wfmupdate_wid
            lay.addWidget(self.wfmupdate_wid)

        if self._has_parmupdt:
            self.updparms_wid = self._build_widget(name='updparms')
            self._widgets_dict['updparms'] = self.updparms_wid
            lay.addWidget(self.updparms_wid)

        self.setpoint_wid = self._build_widget(name='setpoint',
                                               orientation='v')
        self._widgets_dict['setpoint'] = self.setpoint_wid
        lay.addWidget(self.setpoint_wid)

        if self._has_analrb:
            self.readback_wid = self._build_widget(name='readback',
                                                   orientation='v')
            self._widgets_dict['readback'] = self.readback_wid
            lay.addWidget(self.readback_wid)

        if self._has_analmon:
            self.monitor_wid = self._build_widget(name='monitor',
                                                  orientation='v')
            self._widgets_dict['monitor'] = self.monitor_wid
            lay.addWidget(self.monitor_wid)

        if self._has_strength:
            self.strength_sp_wid = self._build_widget(name='strength_sp',
                                                      orientation='v')
            self._widgets_dict['strength_sp'] = self.strength_sp_wid
            lay.addWidget(self.strength_sp_wid)

            self.strength_rb_wid = self._build_widget(name='strength_rb',
                                                      orientation='v')
            self._widgets_dict['strength_rb'] = self.strength_rb_wid
            lay.addWidget(self.strength_rb_wid)

        if self._has_strength_mon:
            self.strength_mon_wid = self._build_widget(name='strength_mon',
                                                       orientation='v')
            self._widgets_dict['strength_mon'] = self.strength_mon_wid
            lay.addWidget(self.strength_mon_wid)

        if self._has_trim:
            self.trim_wid = self._build_widget(name='trim', orientation='v')
            self._widgets_dict['trim'] = self.trim_wid
            lay.addWidget(self.trim_wid)

        _widths = get_prop2width(self._name)
        for name, widget in self._widgets_dict.items():
            width = _widths[name]
            widget.setStyleSheet('#' + name + '{min-width:' + str(width) +
                                 'em;'
                                 'max-width:' + str(width) + 'em;}')
            widget.setSizePolicy(QSzPlcy.Fixed, QSzPlcy.Fixed)
            widget.setVisible(name in self.visible_props)

        self.setStyleSheet("""
            PyDMStateButton{
                min-width: 2.5em; max-width: 2.5em;
                min-height: 1.5em; max-height: 1.5em;
            }
            QLed{
                min-width: 1.5em; max-width: 1.5em;
                min-height: 1.5em; max-height: 1.5em;
            }
            QLabel{
                min-height: 1.5em; max-height: 1.5em;
                qproperty-alignment: AlignCenter;
            }
        """)

        lay.addStretch()
        self.setLayout(lay)

        for prop in self.visible_props:
            self.fillWidget(prop)

    def _create_pvs(self):
        if self._has_opmode:
            if self._is_reg_slave:
                self._opmode_sts = self._prefixed_name.substitute(
                    propty='ModState-Mon')
            elif self._is_regatron:
                self._opmode_sts = self._prefixed_name.substitute(
                    propty='OpMode-Sts')
            else:
                self._opmode_sel = self._prefixed_name.substitute(
                    propty='OpMode-Sel')
                self._opmode_sts = self._prefixed_name.substitute(
                    propty='OpMode-Sts')

        if self._has_ctrlmode:
            self._ctrlmode_sts = self._prefixed_name.substitute(
                propty='CtrlMode-Mon')

        if self._has_pwrstate:
            self._pwrstate_sel = self._prefixed_name.substitute(
                propty='PwrState-Sel')
            self._pwrstate_sts = self._prefixed_name.substitute(
                propty='PwrState-Sts')

        if self._is_pulsed:
            self._pulse_sel = self._prefixed_name.substitute(
                propty='Pulse-Sel')
            self._pulse_sts = self._prefixed_name.substitute(
                propty='Pulse-Sts')

        # interlock
        if self._is_pulsed:
            self._intlk = list()
            for i in range(1, 8):
                self._intlk.append(
                    self._prefixed_name.substitute(propty='Intlk' + str(i) +
                                                   '-Mon'))
            if 'Sept' not in self._name.dev:
                self._intlk.append(
                    self._prefixed_name.substitute(propty='Intlk8-Mon'))
        elif self._is_linac:
            self._intlk = self._prefixed_name.substitute(
                propty='StatusIntlk-Mon')
        elif self._is_regatron:
            if not self._is_reg_slave:
                self._generr = self._prefixed_name.substitute(
                    propty='GenIntlk-Mon')
                self._genwrn = self._prefixed_name.substitute(
                    propty='GenWarn-Mon')
        elif self._is_fofb:
            self._intlk = [
                self._prefixed_name.substitute(
                    propty='PSAmpOverCurrFlagL-Sts'),
                self._prefixed_name.substitute(
                    propty='PSAmpOverCurrFlagR-Sts'),
                self._prefixed_name.substitute(
                    propty='PSAmpOverTempFlagL-Sts'),
                self._prefixed_name.substitute(
                    propty='PSAmpOverTempFlagR-Sts'),
            ]
        else:
            self._soft_intlk = self._prefixed_name.substitute(
                propty='IntlkSoft-Mon')
            self._hard_intlk = self._prefixed_name.substitute(
                propty='IntlkHard-Mon')

        if self._is_linac:
            self._conn = self._prefixed_name.substitute(propty='Connected-Mon')

        if self._has_reset:
            self._reset_intlk = self._prefixed_name.substitute(
                propty='Reset-Cmd')

        if self._has_ctrlloop:
            self._ctrlloop_sel = self._prefixed_name.substitute(
                propty='CtrlLoop-Sel')
            self._ctrlloop_sts = self._prefixed_name.substitute(
                propty='CtrlLoop-Sts')

        if self._has_wfmupdt:
            self._wfmupdate_sel = self._prefixed_name.substitute(
                propty='WfmUpdateAuto-Sel')
            self._wfmupdate_sts = self._prefixed_name.substitute(
                propty='WfmUpdateAuto-Sts')

        if self._has_parmupdt:
            self._updparms_cmd = self._prefixed_name.substitute(
                propty='ParamUpdate-Cmd')

        # analog control
        sp = self._analog_name
        if self._has_analsp:
            self._analog_sp = self._prefixed_name.substitute(
                propty='{}-SP'.format(sp))
        if self._has_analrb:
            self._analog_rb = self._prefixed_name.substitute(
                propty='{}-RB'.format(sp))
        if self._has_analmon:
            if self._is_reg_slave:
                self._analog_mon = self._prefixed_name.substitute(
                    propty='ModOutVolt-Mon')
            else:
                self._analog_mon = self._prefixed_name.substitute(
                    propty='{}-Mon'.format(sp))

        # strength
        if self._has_strength:
            st = self._strength_name
            self._strength_sp = self._prefixed_name.substitute(
                propty='{}-SP'.format(st))
            self._strength_rb = self._prefixed_name.substitute(
                propty='{}-RB'.format(st))
        if self._has_strength_mon:
            self._strength_mon = self._prefixed_name.substitute(
                propty='{}-Mon'.format(st))

    def _build_widget(self, name='', orientation='h'):
        widget = QWidget(self)
        widget.setObjectName(name)
        if orientation == 'h':
            lay = QHBoxLayout(widget)
        else:
            lay = QVBoxLayout(widget)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 3, 0, 3)
        return widget

    def fillWidget(self, name):
        if name in self.filled_widgets:
            return
        if name == 'detail':
            self.detail_bt = QPushButton(self)
            if self._name.dev == 'DCLink':
                self.detail_bt.setIcon(qta.icon('fa5s.list-ul'))
                self.detail_bt.setToolTip(self._name)
            else:
                self.detail_bt.setText(self._name)
            self.detail_wid.layout().addWidget(self.detail_bt)
        elif name == 'bbb' and self._bbb_name:
            self.bbb_lb = QLabel(self._bbb_name, self)
            self.bbb_wid.layout().addWidget(self.bbb_lb)
        elif name == 'udc' and self._udc_name:
            self.udc_lb = QLabel(self._udc_name, self)
            self.udc_wid.layout().addWidget(self.udc_lb)
        elif name == 'opmode' and self._has_opmode:
            opmode_list = list()
            if 'Voltage' not in self._analog_name:
                self.opmode_cb = SiriusEnumComboBox(self, self._opmode_sel)
                opmode_list.append(self.opmode_cb)
            self.opmode_lb = PyDMLabel(self, self._opmode_sts)
            opmode_list.append(self.opmode_lb)
            for wid in opmode_list:
                self.opmode_wid.layout().addWidget(wid)
        elif name == 'ctrlmode' and self._has_ctrlmode:
            self.ctrlmode_lb = PyDMLabel(self, self._ctrlmode_sts)
            self.ctrlmode_wid.layout().addWidget(self.ctrlmode_lb)
        elif name == 'state' and self._has_pwrstate:
            self.state_bt = PyDMStateButton(self, self._pwrstate_sel)
            self.state_led = SiriusLedState(self, self._pwrstate_sts)
            self.state_wid.layout().addWidget(self.state_bt)
            self.state_wid.layout().addWidget(self.state_led)
        elif name == 'pulse' and self._is_pulsed:
            self.pulse_bt = PyDMStateButton(self, self._pulse_sel)
            self.pulse_led = SiriusLedState(self, self._pulse_sts)
            self.pulse_wid.layout().addWidget(self.pulse_bt)
            self.pulse_wid.layout().addWidget(self.pulse_led)
        elif name == 'intlk':
            if self._is_pulsed:
                self.intlk_led = PyDMLedMultiChannel(
                    self, channels2values={ch: 1
                                           for ch in self._intlk})
                self.intlk_wid.layout().addWidget(self.intlk_led)
            elif self._is_linac:
                if IsLinacSpect.match(self.devname):
                    self.intlk_led = LISpectIntlkLed(self)
                else:
                    self.intlk_led = PyDMLedMultiChannel(self,
                                                         channels2values={
                                                             self._intlk: {
                                                                 'value':
                                                                 _PS_LI_INTLK,
                                                                 'comp': 'lt'
                                                             }
                                                         })
                self.intlk_wid.layout().addWidget(self.intlk_led)
            elif self._is_regatron:
                if not self._is_reg_slave:
                    self.generr_led = SiriusLedAlert(self, self._generr)
                    self.genwrn_led = SiriusLedAlert(self, self._genwrn)
                    self.intlk_wid.layout().addWidget(self.generr_led)
                    self.intlk_wid.layout().addWidget(self.genwrn_led)
            elif self._is_fofb:
                self.intlk_led = PyDMLedMultiChannel(
                    self, channels2values={ch: 1
                                           for ch in self._intlk})
                self.intlk_wid.layout().addWidget(self.intlk_led)
            else:
                self.soft_intlk_led = SiriusLedAlert(self, self._soft_intlk)
                self.hard_intlk_led = SiriusLedAlert(self, self._hard_intlk)
                self.intlk_wid.layout().addWidget(self.soft_intlk_led)
                self.intlk_wid.layout().addWidget(self.hard_intlk_led)
        elif name == 'conn' and self._is_linac:
            self.conn_led = PyDMLedMultiChannel(
                self, channels2values={self._conn: 0})
            self.conn_wid.layout().addWidget(self.conn_led)
        elif name == 'reset' and self._has_reset:
            self.reset_bt = PyDMPushButton(parent=self,
                                           init_channel=self._reset_intlk,
                                           pressValue=1)
            self.reset_bt.setIcon(qta.icon('fa5s.sync'))
            self.reset_bt.setObjectName('reset_bt')
            self.reset_bt.setStyleSheet(
                '#reset_bt{min-width:25px; max-width:25px; icon-size:20px;}')
            self.reset_wid.layout().addWidget(self.reset_bt)
        elif name == 'ctrlloop' and self._has_ctrlloop:
            if self._is_fofb:
                self.ctrlloop_bt = PyDMStateButton(self, self._ctrlloop_sel)
            else:
                self.ctrlloop_bt = PyDMStateButton(self,
                                                   self._ctrlloop_sel,
                                                   invert=True)
            self.ctrlloop_lb = PyDMLabel(self, self._ctrlloop_sts)
            self.ctrlloop_wid.layout().addWidget(self.ctrlloop_bt)
            self.ctrlloop_wid.layout().addWidget(self.ctrlloop_lb)
        elif name == 'wfmupdate' and self._has_wfmupdt:
            self.wfmupdate_bt = PyDMStateButton(self, self._wfmupdate_sel)
            self.wfmupdate_led = SiriusLedState(self, self._wfmupdate_sts)
            self.wfmupdate_wid.layout().addWidget(self.wfmupdate_bt)
            self.wfmupdate_wid.layout().addWidget(self.wfmupdate_led)
        elif name == 'updparms' and self._has_parmupdt:
            self.updparms_bt = PyDMPushButton(parent=self,
                                              init_channel=self._updparms_cmd,
                                              pressValue=1)
            self.updparms_bt.setIcon(qta.icon('fa5s.redo-alt'))
            self.updparms_bt.setObjectName('updparms_bt')
            self.updparms_bt.setStyleSheet(
                '#updparms_bt{min-width:25px;max-width:25px;icon-size:20px;}')
            self.updparms_wid.layout().addWidget(self.updparms_bt)
        elif name == 'setpoint' and self._has_analsp:
            self.setpoint = PyDMSpinboxScrollbar(self, self._analog_sp)
            if self._is_fofb:
                self.setpoint.spinbox.precisionFromPV = False
                self.setpoint.spinbox.precision = 6
            self.setpoint_wid.layout().addWidget(self.setpoint)
        elif name == 'readback' and self._has_analrb:
            self.readback = PyDMLabel(self, self._analog_rb)
            if self._is_fofb:
                self.readback.precisionFromPV = False
                self.readback.precision = 6
            self.readback_wid.layout().addWidget(self.readback)
        elif name == 'monitor' and self._has_analmon:
            self.monitor = PyDMLabel(self, self._analog_mon)
            self.monitor_wid.layout().addWidget(self.monitor)
        elif name == 'strength_sp' and self._has_strength:
            self.strength_sp_le = PyDMSpinboxScrollbar(self, self._strength_sp)
            self.strength_sp_wid.layout().addWidget(self.strength_sp_le)
        elif name == 'strength_rb' and self._has_strength:
            self.strength_rb_lb = PyDMLabel(parent=self,
                                            init_channel=self._strength_rb)
            self.strength_rb_lb.showUnits = True
            self.strength_rb_wid.layout().addWidget(self.strength_rb_lb)
        elif name == 'strength_mon' and self._has_strength_mon:
            self.strength_mon_lb = PyDMLabel(parent=self,
                                             init_channel=self._strength_mon)
            self.strength_mon_lb.showUnits = True
            self.strength_mon_wid.layout().addWidget(self.strength_mon_lb)
        elif name == 'trim' and self._has_trim:
            self.trim_bt = QPushButton(qta.icon('fa5s.angle-right'), '', self)
            self.trim_wid.layout().addWidget(self.trim_bt)
        self.filled_widgets.add(name)

    def get_detail_button(self):
        """Return psname button."""
        return self.detail_bt

    def get_trim_button(self):
        """Return trim button."""
        if self._has_trim:
            return self.trim_bt
        return None

    def set_opmode_slowref(self):
        """Set power supply OpMode to SlowRef."""
        if hasattr(self, 'opmode_cb'):
            if self.opmode_cb.isEnabled():
                index = self.opmode_cb.findText('SlowRef')
                self.opmode_cb.internal_combo_box_activated_int(index)

    def turn_on(self):
        """Turn power supply on."""
        if hasattr(self, 'state_bt'):
            if self.state_bt.isEnabled():
                if not self.state_bt.value:
                    self.state_bt.send_value()

    def turn_off(self):
        """Turn power supply off."""
        if hasattr(self, 'state_bt'):
            if self.state_bt.isEnabled():
                if self.state_bt.value:
                    self.state_bt.send_value()

    def ctrlloop_close(self):
        """Close control loop."""
        if hasattr(self, 'ctrlloop_bt'):
            if self.ctrlloop_bt.isEnabled():
                if not self.ctrlloop_bt.value:
                    self.ctrlloop_bt.send_value()

    def ctrlloop_open(self):
        """Open control loop."""
        if hasattr(self, 'ctrlloop_bt'):
            if self.ctrlloop_bt.isEnabled():
                if self.ctrlloop_bt.value:
                    self.ctrlloop_bt.send_value()

    def pulse_on(self):
        """Turn power supply on."""
        if hasattr(self, 'pulse_bt'):
            if self.pulse_bt.isEnabled():
                if not self.pulse_bt.value:
                    self.pulse_bt.send_value()

    def pulse_off(self):
        """Turn power supply off."""
        if hasattr(self, 'pulse_bt'):
            if self.pulse_bt.isEnabled():
                if self.pulse_bt.value:
                    self.pulse_bt.send_value()

    def wfmupdate_on(self):
        """Enable WfmUpdateAuto."""
        if hasattr(self, 'wfmupdate_bt'):
            if self.wfmupdate_bt.isEnabled():
                if not self.wfmupdate_bt.value:
                    self.wfmupdate_bt.send_value()

    def wfmupdate_off(self):
        """Disable WfmUpdateAuto."""
        if hasattr(self, 'wfmupdate_bt'):
            if self.wfmupdate_bt.isEnabled():
                if self.wfmupdate_bt.value:
                    self.wfmupdate_bt.send_value()

    def reset(self):
        """Reset power supply."""
        if hasattr(self, 'reset_bt'):
            if self.reset_bt.isEnabled():
                self.reset_bt.sendValue()

    def update_params(self):
        """Update power supply parameters."""
        if hasattr(self, 'updparms_bt'):
            if self.updparms_bt.isEnabled():
                self.updparms_bt.sendValue()