Ejemplo n.º 1
0
class SiriusScrnView(QWidget):
    """
    Class to read Sirius screen cameras image data.

    To allow saving a grid correctly, control calibrationgrid_flag, which
    indicates if the screen is in calibration grid position.
    You can control it by using the method/Slot updateCalibrationGridFlag.
    """

    save_files = Signal()

    def __init__(self, parent=None, prefix=_VACA_PREFIX, device=None):
        """Initialize object."""
        QWidget.__init__(self, parent=parent)
        self.prefix = prefix
        self.device = SiriusPVName(device)
        self.scrn_prefix = self.device.substitute(prefix=prefix)
        self._receivedData = False
        self.setObjectName(self.scrn_prefix.sec + 'App')

        self.screen_type_conn = SiriusConnectionSignal(
            self.scrn_prefix.substitute(propty='ScrnType-Sts'))
        self.screen_type_conn.new_value_signal.connect(
            self.updateCalibrationGridFlag)
        self._calibrationgrid_flag = self.screen_type_conn.getvalue()
        self.save_files.connect(self._saveGridLocalFiles)
        self.ch_ImgROIHeight = SiriusConnectionSignal(
            self.scrn_prefix.substitute(propty='ImgROIHeight-RB'))
        self.ch_ImgROIWidth = SiriusConnectionSignal(
            self.scrn_prefix.substitute(propty='ImgROIWidth-RB'))
        self.ch_ImgROIOffsetX = SiriusConnectionSignal(
            self.scrn_prefix.substitute(propty='ImgROIOffsetX-RB'))
        self.ch_ImgROIOffsetY = SiriusConnectionSignal(
            self.scrn_prefix.substitute(propty='ImgROIOffsetY-RB'))

        self._setupUi()
        self.setFocus(True)
        self.setFocusPolicy(Qt.StrongFocus)
        self._loadCalibrationGrid(default=True)

    @property
    def calibrationgrid_flag(self):
        """Indicate if the screen device is in calibration grid position."""
        return self._calibrationgrid_flag

    @Slot(int)
    def updateCalibrationGridFlag(self, new_state):
        """Update calibrationgrid_flag property."""
        self._calibrationgrid_flag = new_state
        if new_state == 1:
            self.pushbutton_savegrid.setEnabled(True)
        else:
            self.pushbutton_savegrid.setEnabled(False)

    def _setupUi(self):
        self.cameraview_widget = QWidget()
        self.cameraview_widget.setLayout(self._cameraviewLayout())

        self.settings_widget = QWidget(self)
        self.settings_widget.setLayout(self._settingsLayout())
        self.settings_widget.setStyleSheet("""
            .QLabel{
                min-width: 5em;}
            QLabel{
                qproperty-alignment: AlignCenter;}""")

        self.calibrationgrid_widget = QWidget(self)
        self.calibrationgrid_widget.setLayout(self._calibrationgridLayout())
        self.calibrationgrid_widget.setSizePolicy(QSzPlcy.Expanding,
                                                  QSzPlcy.Expanding)
        self.calibrationgrid_widget.layout().setAlignment(Qt.AlignHCenter)
        self.tab = QTabWidget(self)
        self.tab.setStyleSheet("""
            QTabWidget::pane {
                border-left: 2px solid gray;
                border-bottom: 2px solid gray;
                border-right: 2px solid gray;
            }""")
        self.tab.addTab(self.settings_widget, 'Camera Settings')
        self.tab.addTab(self.calibrationgrid_widget, 'Calibration')

        self.statistics_groupBox = QGroupBox('Statistics', self)
        self.statistics_groupBox.setLayout(self._statisticsLayout())
        self.statistics_groupBox.setSizePolicy(QSzPlcy.Expanding,
                                               QSzPlcy.Expanding)
        self.statistics_groupBox.setStyleSheet("""
            .QLabel{
                min-width:0.28em; max-width:0.28em;
                min-height:1.29em; max-height:1.29em;}
            QLabel{
                qproperty-alignment: AlignCenter;}
            PyDMWidget{
                min-width:4.84em; max-width:4.84em;
                min-height:1.29em; max-height:1.29em;}""")

        self.trigger_groupBox = QGroupBox('Trigger', self)
        if 'TB' in self.device or 'BO' in self.device:
            trg_prefix = 'AS-Fam:TI-Scrn-TBBO'
        elif 'TS' in self.device:
            trg_prefix = 'TS-Fam:TI-Scrn'
        hbl = QHBoxLayout(self.trigger_groupBox)
        hbl.addWidget(
            HLTriggerSimple(parent=self.trigger_groupBox,
                            device=trg_prefix,
                            prefix=self.prefix))
        self.trigger_groupBox.setLayout(hbl)
        self.trigger_groupBox.setStyleSheet("""
            PyDMWidget{
                min-width:4.84em; max-width:4.84em;
                min-height:1.29em; max-height:1.29em;}""")

        vlay = QVBoxLayout()
        vlay.addWidget(self.statistics_groupBox)
        vlay.addWidget(self.trigger_groupBox)
        vlay.setSpacing(10)

        lay = QGridLayout(self)
        lay.setHorizontalSpacing(10)
        lay.setVerticalSpacing(10)
        lay.addWidget(self.cameraview_widget, 0, 0, 1, 2)
        lay.addWidget(self.tab, 1, 0)
        lay.addLayout(vlay, 1, 1)
        lay.setRowStretch(0, 15)
        lay.setRowStretch(1, 7)

    def _cameraviewLayout(self):
        label = QLabel(self.device, self)
        label.setStyleSheet("""font-weight: bold;max-height:1.29em;""")
        label.setAlignment(Qt.AlignCenter)
        self.image_view = _SiriusImageView(
            parent=self,
            image_channel=self.scrn_prefix.substitute(propty='ImgData-Mon'),
            width_channel=self.scrn_prefix.substitute(propty='ImgROIWidth-RB'),
            offsetx_channel=self.scrn_prefix.substitute(
                propty='ImgROIOffsetX-RB'),
            offsety_channel=self.scrn_prefix.substitute(
                propty='ImgROIOffsetY-RB'),
            maxwidth_channel=self.scrn_prefix.substitute(
                propty='ImgMaxWidth-Cte'),
            maxheight_channel=self.scrn_prefix.substitute(
                propty='ImgMaxHeight-Cte'))
        self.image_view.setObjectName('ScrnView')
        self.image_view.normalizeData = True
        self.image_view.readingOrder = self.image_view.Clike
        self.image_view.maxRedrawRate = 15
        self.image_view.setStyleSheet("""
            #ScrnView{min-width:30em; min-height:24em;}""")
        self.image_view.failToSaveGrid.connect(self._showFailToSaveGridMsg)
        self.image_view.receivedData.connect(self._setReceivedDataFlag)

        lay = QGridLayout()
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(label, 0, 1)
        lay.addItem(QSpacerItem(40, 2, QSzPlcy.Preferred, QSzPlcy.Fixed), 1, 1)
        lay.addWidget(self.image_view, 2, 1)
        return lay

    def _calibrationgridLayout(self):
        self.checkBox_showgrid = QCheckBox('Show', self)
        self.checkBox_showgrid.setEnabled(False)
        self.checkBox_showgrid.setStyleSheet("""
            min-width:4em; max-width:4em;
            min-height:1.29em; max-height:1.29em;""")
        self.checkBox_showgrid.toggled.connect(
            self.image_view.showCalibrationGrid)
        self.pushbutton_savegrid = QPushButton('Save', self)
        self.pushbutton_savegrid.setEnabled(False)
        self.pushbutton_savegrid.setStyleSheet("""
            min-width:4em; max-width:4em;
            min-height:1.29em; max-height:1.29em;""")
        self.pushbutton_savegrid.clicked.connect(self._saveCalibrationGrid)
        self.pushbutton_loadgrid = QPushButton('Load', self)
        self.pushbutton_loadgrid.setStyleSheet("""
            min-width:4em; max-width:4em;
            min-height:1.29em; max-height:1.29em;""")
        self.pushbutton_loadgrid.clicked.connect(self._loadCalibrationGrid)
        hbox_grid = QHBoxLayout()
        hbox_grid.addWidget(self.checkBox_showgrid)
        hbox_grid.addWidget(self.pushbutton_savegrid)
        hbox_grid.addWidget(self.pushbutton_loadgrid)

        lb = QLabel('Show levels <')
        lb.setStyleSheet("min-width:7em;max-width:7em;")
        self.spinbox_gridfilterfactor = QSpinBoxPlus()
        self.spinbox_gridfilterfactor.setMaximum(100)
        self.spinbox_gridfilterfactor.setMinimum(0)
        self.spinbox_gridfilterfactor.setValue(
            self.image_view.calibration_grid_filterfactor)
        self.spinbox_gridfilterfactor.editingFinished.connect(
            self._setCalibrationGridFilterFactor)
        self.spinbox_gridfilterfactor.setStyleSheet("""
            min-width:4em; max-width:4em;""")
        hbox_filter = QHBoxLayout()
        hbox_filter.setSpacing(0)
        hbox_filter.addWidget(lb)
        hbox_filter.addWidget(self.spinbox_gridfilterfactor)
        hbox_filter.addWidget(QLabel(' %'))

        lb = QLabel('Remove border: ')
        lb.setStyleSheet("min-width:7em;max-width:7em;")
        self.spinbox_removeborder = QSpinBoxPlus()
        self.spinbox_removeborder.setMaximum(512)
        self.spinbox_removeborder.setMinimum(0)
        self.spinbox_removeborder.setValue(
            self.image_view.calibration_grid_removeborder)
        self.spinbox_removeborder.editingFinished.connect(
            self._setCalibrationGridBorder2Remove)
        self.spinbox_removeborder.setStyleSheet("""
            min-width:4em; max-width:4em;""")
        hbox_remove = QHBoxLayout()
        hbox_remove.setSpacing(0)
        hbox_remove.addWidget(lb)
        hbox_remove.addWidget(self.spinbox_removeborder)
        hbox_remove.addWidget(QLabel(' px'))

        hbox_EnblLED = _create_propty_layout(parent=self,
                                             prefix=self.scrn_prefix,
                                             propty='EnblLED',
                                             propty_type='enbldisabl',
                                             width=4.68)

        lay = QFormLayout()
        lay.addItem(QSpacerItem(1, 10, QSzPlcy.Ignored, QSzPlcy.Preferred))
        lay.addRow('  Grid: ', hbox_grid)
        lay.addItem(QSpacerItem(1, 10, QSzPlcy.Ignored, QSzPlcy.Preferred))
        lay.addRow('  ', hbox_filter)
        lay.addRow('  ', hbox_remove)
        lay.addItem(QSpacerItem(1, 20, QSzPlcy.Ignored, QSzPlcy.Preferred))
        lay.addRow('  LED: ', hbox_EnblLED)
        lay.addItem(QSpacerItem(1, 10, QSzPlcy.Ignored, QSzPlcy.Preferred))
        lay.setLabelAlignment(Qt.AlignRight)
        lay.setFormAlignment(Qt.AlignCenter)
        return lay

    def _settingsLayout(self):
        label_CamEnbl = QLabel('Enable: ', self)
        hbox_CamEnbl = _create_propty_layout(parent=self,
                                             prefix=self.scrn_prefix,
                                             propty='CamEnbl',
                                             propty_type='enbldisabl')

        label_CamAcqPeriod = QLabel('Acquire\nPeriod [s]:', self)
        hbox_CamAcqPeriod = _create_propty_layout(parent=self,
                                                  prefix=self.scrn_prefix,
                                                  propty='CamAcqPeriod',
                                                  propty_type='sprb',
                                                  width=5.0)

        label_CamExposureTime = QLabel('Exposure\nTime [us]:', self)
        hbox_CamExposureTime = _create_propty_layout(parent=self,
                                                     prefix=self.scrn_prefix,
                                                     propty='CamExposureTime',
                                                     propty_type='sprb',
                                                     width=5.0)

        label_CamGain = QLabel('Gain[dB]:', self)
        hbox_CamGain = _create_propty_layout(parent=self,
                                             prefix=self.scrn_prefix,
                                             propty='CamGain',
                                             width=5.0,
                                             propty_type='sprb')

        label_AutoGain = QLabel('Auto Gain: ', self)
        self.pb_autogain = PyDMPushButton(
            label='',
            icon=qta.icon('mdi.auto-fix'),
            parent=self,
            pressValue=1,
            init_channel=self.scrn_prefix.substitute(propty='CamAutoGain-Cmd'))
        self.pb_autogain.setObjectName('autog')
        self.pb_autogain.setStyleSheet(
            "#autog{min-width:25px; max-width:25px; icon-size:20px;}")

        cam_prefix = SiriusPVName(self.scrn_prefix).substitute(dev='ScrnCam')
        label_Reset = QLabel('Reset: ', self)
        self.pb_dtl = PyDMPushButton(
            label='',
            icon=qta.icon('fa5s.sync'),
            parent=self,
            pressValue=1,
            init_channel=cam_prefix.substitute(propty='Rst-Cmd'))
        self.pb_dtl.setObjectName('reset')
        self.pb_dtl.setStyleSheet(
            "#reset{min-width:25px; max-width:25px; icon-size:20px;}")

        self.pb_details = QPushButton(qta.icon('fa5s.ellipsis-h'), '', self)
        self.pb_details.setToolTip('More settings')
        self.pb_details.setObjectName('detail')
        self.pb_details.setStyleSheet(
            "#detail{min-width:25px; max-width:25px; icon-size:20px;}")
        self.pb_details.setSizePolicy(QSzPlcy.Expanding, QSzPlcy.Preferred)
        util.connect_window(self.pb_details,
                            _ScrnSettingsDetails,
                            parent=self,
                            prefix=self.prefix,
                            device=self.device)

        hbox_aux = QHBoxLayout()
        hbox_aux.addWidget(self.pb_dtl, alignment=Qt.AlignLeft)
        hbox_aux.addWidget(self.pb_details, alignment=Qt.AlignRight)

        lay = QFormLayout()
        lay.setFormAlignment(Qt.AlignCenter)
        lay.addRow(label_CamEnbl, hbox_CamEnbl)
        lay.addRow(label_CamAcqPeriod, hbox_CamAcqPeriod)
        lay.addRow(label_CamExposureTime, hbox_CamExposureTime)
        lay.addRow(label_CamGain, hbox_CamGain)
        lay.addRow(label_AutoGain, self.pb_autogain)
        lay.addRow(label_Reset, hbox_aux)
        return lay

    def _statisticsLayout(self):
        # - Method
        label_Method = QLabel('CalcMethod:', self)
        label_Method.setStyleSheet("min-width:7em;")

        self.comboBox_Method = QComboBox(self)
        self.comboBox_Method.addItem('DimFei', 0)
        self.comboBox_Method.addItem('NDStats', 1)
        self.comboBox_Method.setCurrentIndex(0)
        self.comboBox_Method.setStyleSheet("""
            QComboBox::item {height: 1em;}
            QComboBox{min-width:6em;}""")
        self.comboBox_Method.currentIndexChanged.connect(
            self._handleShowStatistics)

        # - Centroid
        label_Centroid = QLabel('Centroid [mm]: ', self)
        label_Centroid.setStyleSheet("min-width:7em;")
        label_i_Center = QLabel('(', self)
        self.PyDMLabel_CenterXDimFei = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='CenterXDimFei-Mon'))
        self.PyDMLabel_CenterXDimFei.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_CenterXNDStats = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='CenterXNDStats-Mon'))
        self.PyDMLabel_CenterXNDStats.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_CenterXNDStats.setVisible(False)
        label_m_Center = QLabel(',', self)
        self.PyDMLabel_CenterYDimFei = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='CenterYDimFei-Mon'))
        self.PyDMLabel_CenterYDimFei.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_CenterYNDStats = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='CenterYNDStats-Mon'))
        self.PyDMLabel_CenterYNDStats.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_CenterYNDStats.setVisible(False)
        label_f_Center = QLabel(')', self)

        # - Sigma
        label_Sigma = QLabel('Sigma [mm]: ', self)
        label_Sigma.setStyleSheet("min-width:7em;")
        label_i_Sigma = QLabel('(', self)
        self.PyDMLabel_SigmaXDimFei = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='SigmaXDimFei-Mon'))
        self.PyDMLabel_SigmaXDimFei.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_SigmaXNDStats = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='SigmaXNDStats-Mon'))
        self.PyDMLabel_SigmaXNDStats.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_SigmaXNDStats.setVisible(False)
        label_m_Sigma = QLabel(',', self)
        self.PyDMLabel_SigmaYDimFei = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='SigmaYDimFei-Mon'))
        self.PyDMLabel_SigmaYDimFei.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_SigmaYNDStats = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='SigmaYNDStats-Mon'))
        self.PyDMLabel_SigmaYNDStats.setStyleSheet(
            'min-width:4em; max-width:4em;')
        self.PyDMLabel_SigmaYNDStats.setVisible(False)
        label_f_Sigma = QLabel(')', self)

        # - Theta
        label_Theta = QLabel('Theta [rad]: ')
        label_Theta.setStyleSheet("min-width:7em;")
        label_i_Theta = QLabel('(', self)
        self.PyDMLabel_ThetaDimFei = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(propty='ThetaDimFei-Mon'))
        self.PyDMLabel_ThetaDimFei.setStyleSheet("max-width:12em;")
        self.PyDMLabel_ThetaNDStats = PyDMLabel(
            parent=self,
            init_channel=self.scrn_prefix.substitute(
                propty='ThetaNDStats-Mon'))
        self.PyDMLabel_ThetaNDStats.setStyleSheet("max-width:12em;")
        self.PyDMLabel_ThetaNDStats.setVisible(False)
        label_f_Theta = QLabel(')', self)

        lay = QGridLayout()
        lay.addWidget(label_Method, 1, 1, 1, 3)
        lay.addWidget(self.comboBox_Method, 1, 3, 1, 3)
        lay.addWidget(label_Centroid, 3, 1, alignment=Qt.AlignCenter)
        lay.addWidget(label_i_Center, 3, 2)
        lay.addWidget(self.PyDMLabel_CenterXDimFei, 3, 3)
        lay.addWidget(self.PyDMLabel_CenterXNDStats, 3, 3)
        lay.addWidget(label_m_Center, 3, 4)
        lay.addWidget(self.PyDMLabel_CenterYDimFei, 3, 5)
        lay.addWidget(self.PyDMLabel_CenterYNDStats, 3, 5)
        lay.addWidget(label_f_Center, 3, 6)
        lay.addWidget(label_Sigma, 5, 1, alignment=Qt.AlignCenter)
        lay.addWidget(label_i_Sigma, 5, 2)
        lay.addWidget(self.PyDMLabel_SigmaXDimFei, 5, 3)
        lay.addWidget(self.PyDMLabel_SigmaXNDStats, 5, 3)
        lay.addWidget(label_m_Sigma, 5, 4)
        lay.addWidget(self.PyDMLabel_SigmaYDimFei, 5, 5)
        lay.addWidget(self.PyDMLabel_SigmaYNDStats, 5, 5)
        lay.addWidget(label_f_Sigma, 5, 6)
        lay.addWidget(label_Theta, 7, 1, alignment=Qt.AlignCenter)
        lay.addWidget(label_i_Theta, 7, 2)
        lay.addWidget(self.PyDMLabel_ThetaDimFei, 7, 3, 1, 3)
        lay.addWidget(self.PyDMLabel_ThetaNDStats, 7, 3, 1, 3)
        lay.addWidget(label_f_Theta, 7, 6)
        return lay

    def _handleShowStatistics(self, visible):
        self.PyDMLabel_CenterXDimFei.setVisible(not visible)
        self.PyDMLabel_CenterXNDStats.setVisible(visible)
        self.PyDMLabel_CenterYDimFei.setVisible(not visible)
        self.PyDMLabel_CenterYNDStats.setVisible(visible)
        self.PyDMLabel_ThetaDimFei.setVisible(not visible)
        self.PyDMLabel_ThetaNDStats.setVisible(visible)
        self.PyDMLabel_SigmaXDimFei.setVisible(not visible)
        self.PyDMLabel_SigmaXNDStats.setVisible(visible)
        self.PyDMLabel_SigmaYDimFei.setVisible(not visible)
        self.PyDMLabel_SigmaYNDStats.setVisible(visible)

    def _saveCalibrationGrid(self):
        t = Thread(target=self._saveCalibrationGrid_thread, daemon=True)
        t.start()

    def _saveCalibrationGrid_thread(self):
        roi_h = float(self.ch_ImgROIHeight.value)
        roi_w = float(self.ch_ImgROIWidth.value)
        roi_offsetx = float(self.ch_ImgROIOffsetX.value)
        roi_offsety = float(self.ch_ImgROIOffsetY.value)

        cond = roi_h != float(self.image_view.image_maxheight) or \
            roi_w != float(self.image_view.image_maxwidth) or \
            roi_offsetx != 0 or roi_offsety != 0
        if cond:
            # Disable camera acquisition and wait for disabling
            self.PyDMStateButton_CamEnbl.send_value_signal[int].emit(0)
            state = self.SiriusLedState_CamEnbl.state
            while state == 1:
                time.sleep(0.1)
                state = self.SiriusLedState_CamEnbl.state

            # Change ROI to get entire image
            self.ch_ImgROIHeight.send_value_signal[float].emit(
                float(self.image_view.image_maxheight))
            self.ch_ImgROIWidth.send_value_signal[float].emit(
                float(self.image_view.image_maxwidth))
            self.ch_ImgROIOffsetX.send_value_signal[float].emit(0)
            self.ch_ImgROIOffsetY.send_value_signal[float].emit(0)

        # Enable led and wait for status
        self.PyDMStateButton_EnblLED.send_value_signal[int].emit(1)
        while not self.SiriusLedState_EnblLED.state:
            time.sleep(0.1)

        # Enable camera acquisition and wait for receiveing first frame
        self._receivedData = False
        self.PyDMStateButton_CamEnbl.send_value_signal[int].emit(1)
        while not self._receivedData:
            time.sleep(0.1)

        # Save grid
        self.image_view.saveCalibrationGrid()

        if cond:
            # Disable camera acquisition and wait for disabling
            self.PyDMStateButton_CamEnbl.send_value_signal[int].emit(0)
            state = self.SiriusLedState_CamEnbl.state
            while state == 1:
                time.sleep(0.1)
                state = self.SiriusLedState_CamEnbl.state

            # Change ROI to original size
            self.ch_ImgROIHeight.send_value_signal[float].emit(roi_h)
            self.ch_ImgROIWidth.send_value_signal[float].emit(roi_w)
            self.ch_ImgROIOffsetX.send_value_signal[float].emit(roi_offsetx)
            self.ch_ImgROIOffsetY.send_value_signal[float].emit(roi_offsety)

            # Enable camera acquisition
            self.PyDMStateButton_CamEnbl.send_value_signal[int].emit(1)

        # Enable showing saved grid
        time.sleep(0.1)
        self.checkBox_showgrid.setEnabled(True)
        self.save_files.emit()

    def _saveGridLocalFiles(self):
        home = os.path.expanduser('~')
        folder_month = datetime.now().strftime('%Y-%m')
        folder_day = datetime.now().strftime('%Y-%m-%d')
        path = os.path.join(home, 'mounts', 'screens-iocs', folder_month,
                            folder_day)
        if not os.path.exists(path):
            os.makedirs(path)
        fn, _ = QFileDialog.getSaveFileName(
            self, 'Save Grid As...', path + '/' + self.device +
            datetime.now().strftime('_%Y-%m-%d_%Hh%Mmin'), '*.npy')
        if not fn:
            return False

        path_default = os.path.join(home, 'mounts', 'screens-iocs', 'default')
        if not os.path.exists(path_default):
            os.makedirs(path_default)
        fn_default = path_default + '/' + self.device

        grid = self.image_view.calibrationGrid
        width = self.image_view.imageWidth
        data = np.append(width, grid)
        np.save(fn, data)
        np.save(fn_default, data)

    def _loadCalibrationGrid(self, default=False):
        home = os.path.expanduser('~')
        if not default:
            folder_month = datetime.now().strftime('%Y-%m')
            path = os.path.join(home, 'mounts', 'screens-iocs', folder_month)
            fn, _ = QFileDialog.getOpenFileName(self, 'Load Grid...', path,
                                                '*.npy')
            if not fn:
                return
            if self.device not in fn:
                ans = QMessageBox.question(
                    self, 'Warning',
                    'The name of the selected file does not contain the name' +
                    ' of this screen. Are you sure you\'re loading this grid?',
                    QMessageBox.Yes, QMessageBox.Cancel)
                if ans == QMessageBox.Cancel:
                    return
        else:
            path = os.path.join(home, 'mounts', 'screens-iocs', 'default')
            fn = path + '/' + self.device + '.npy'

        try:
            data = np.load(fn)
            self.image_view.calibrationGrid = data
        except Exception as e:
            if not default:
                QMessageBox.critical(
                    self, 'Error',
                    'Could not load calibration grid from file ' + fn + '. ' +
                    '\nError message: ' + str(e), QMessageBox.Ok)
            return

        # Enable showing saved grid
        self.checkBox_showgrid.setEnabled(True)

    def _setReceivedDataFlag(self):
        self._receivedData = True

    def _setCalibrationGridFilterFactor(self):
        self.image_view.set_calibration_grid_filterfactor(
            self.spinbox_gridfilterfactor.value())

    def _setCalibrationGridBorder2Remove(self):
        self.image_view.set_calibration_grid_border2remove(
            self.spinbox_removeborder.value())

    @Slot()
    def _showFailToSaveGridMsg(self):
        QMessageBox.warning(self, 'Warning',
                            'Could not save calibration grid!', QMessageBox.Ok)
Ejemplo n.º 2
0
    def generate_pv_controls(self, pv_name, curve_color):
        """
        Generate a set of widgets to manage the appearance of a curve. The set of widgets includes:
            1. A checkbox which shows the curve on the chart if checked, and hide the curve if not
               checked
            2. Three buttons -- Modify..., Focus, and Remove. Modify... will bring up the Curve
               Settings dialog. Focus adjusts the chart's zooming for the current curve.
               Remove will delete the curve from the chart
        Parameters
        ----------
        pv_name: str
            The name of the PV the current curve is being plotted for
        curve_color : QColor
            The color of the curve to paint for the checkbox label to help the user track the curve
            to the checkbox
        """
        individual_curve_layout = QVBoxLayout()

        size_policy = QSizePolicy()
        size_policy.setVerticalPolicy(QSizePolicy.Fixed)
        size_policy.setHorizontalPolicy(QSizePolicy.Fixed)

        individual_curve_grpbx = QGroupBox()
        individual_curve_grpbx.setMinimumWidth(300)
        individual_curve_grpbx.setMinimumHeight(120)
        individual_curve_grpbx.setAlignment(Qt.AlignTop)

        individual_curve_grpbx.setSizePolicy(size_policy)

        individual_curve_grpbx.setObjectName(pv_name + "_grb")
        individual_curve_grpbx.setLayout(individual_curve_layout)

        checkbox = QCheckBox(parent=individual_curve_grpbx)
        checkbox.setObjectName(pv_name + "_chb")

        palette = checkbox.palette()
        palette.setColor(QPalette.Active, QPalette.WindowText, curve_color)
        checkbox.setPalette(palette)

        display_name = pv_name.split("://")[1]
        if len(display_name) > MAX_DISPLAY_PV_NAME_LENGTH:
            # Only display max allowed number of characters of the PV Name
            display_name = display_name[
                           :int(MAX_DISPLAY_PV_NAME_LENGTH / 2) - 1] + "..." + \
                           display_name[
                           -int(MAX_DISPLAY_PV_NAME_LENGTH / 2) + 2:]

        checkbox.setText(display_name)

        data_text = QLabel(parent=individual_curve_grpbx)
        data_text.setWordWrap(True)
        data_text.setObjectName(pv_name + "_lbl")
        data_text.setPalette(palette)

        checkbox.setChecked(True)
        checkbox.toggled.connect(
            partial(self.handle_curve_chkbox_toggled, checkbox))
        if not self.chart.findCurve(pv_name).isVisible():
            checkbox.setChecked(False)

        modify_curve_btn = QPushButton("Modify...",
                                       parent=individual_curve_grpbx)
        modify_curve_btn.setObjectName(pv_name + "_btn_modify")
        modify_curve_btn.setMaximumWidth(80)
        modify_curve_btn.clicked.connect(
            partial(self.display_curve_settings_dialog, pv_name))

        focus_curve_btn = QPushButton("Focus", parent=individual_curve_grpbx)
        focus_curve_btn.setObjectName(pv_name + "_btn_focus")
        focus_curve_btn.setMaximumWidth(80)
        focus_curve_btn.clicked.connect(partial(self.focus_curve, pv_name))

        clear_curve_btn = QPushButton("Clear", parent=individual_curve_grpbx)
        clear_curve_btn.setObjectName(pv_name + "_btn_clear")
        clear_curve_btn.setMaximumWidth(80)
        clear_curve_btn.clicked.connect(partial(self.clear_curve, pv_name))

        # annotate_curve_btn = QPushButton("Annotate...",
        #                                  parent=individual_curve_grpbx)
        # annotate_curve_btn.setObjectName(pv_name+"_btn_ann")
        # annotate_curve_btn.setMaximumWidth(80)
        # annotate_curve_btn.clicked.connect(
        #     partial(self.annotate_curve, pv_name))

        remove_curve_btn = QPushButton("Remove", parent=individual_curve_grpbx)
        remove_curve_btn.setObjectName(pv_name + "_btn_remove")
        remove_curve_btn.setMaximumWidth(80)
        remove_curve_btn.clicked.connect(partial(self.remove_curve, pv_name))

        curve_btn_layout = QHBoxLayout()
        curve_btn_layout.setSpacing(5)
        curve_btn_layout.addWidget(modify_curve_btn)
        curve_btn_layout.addWidget(focus_curve_btn)
        curve_btn_layout.addWidget(clear_curve_btn)
        # curve_btn_layout.addWidget(annotate_curve_btn)
        curve_btn_layout.addWidget(remove_curve_btn)

        individual_curve_layout.addWidget(checkbox)
        individual_curve_layout.addWidget(data_text)
        individual_curve_layout.addLayout(curve_btn_layout)

        self.curve_settings_layout.addWidget(individual_curve_grpbx)

        self.tab_panel.setCurrentIndex(0)
Ejemplo n.º 3
0
    def generate_pv_controls(self, pv_name, curve_color):
        """
        Generate a set of widgets to manage the appearance of a curve. The set of widgets includes:
            1. A checkbox which shows the curve on the chart if checked, and hide the curve if not checked
            2. Two buttons -- Modify... and Remove. Modify... will bring up the Curve Settings dialog. Remove will
               delete the curve from the chart
        This set of widgets will be hidden initially, until the first curve is plotted.

        Parameters
        ----------
        pv_name: str
            The name of the PV the current curve is being plotted for

        curve_color : QColor
            The color of the curve to paint for the checkbox label to help the user track the curve to the checkbox
        """
        checkbox = QCheckBox()
        checkbox.setObjectName(pv_name)

        palette = checkbox.palette()
        palette.setColor(QPalette.Active, QPalette.WindowText, curve_color)
        checkbox.setPalette(palette)

        display_name = pv_name.split("://")[1]
        if len(display_name) > MAX_DISPLAY_PV_NAME_LENGTH:
            # Only display max allowed number of characters of the PV Name
            display_name = display_name[:int(MAX_DISPLAY_PV_NAME_LENGTH / 2) - 1] + "..." + \
                           display_name[-int(MAX_DISPLAY_PV_NAME_LENGTH / 2) + 2:]

        checkbox.setText(display_name)

        data_text = QLabel()
        data_text.setObjectName(pv_name)
        data_text.setPalette(palette)

        checkbox.setChecked(True)
        checkbox.clicked.connect(
            partial(self.handle_curve_chkbox_toggled, checkbox))

        curve_btn_layout = QHBoxLayout()

        modify_curve_btn = QPushButton("Modify...")
        modify_curve_btn.setObjectName(pv_name)
        modify_curve_btn.setMaximumWidth(100)
        modify_curve_btn.clicked.connect(
            partial(self.display_curve_settings_dialog, pv_name))

        focus_curve_btn = QPushButton("Focus")
        focus_curve_btn.setObjectName(pv_name)
        focus_curve_btn.setMaximumWidth(100)
        focus_curve_btn.clicked.connect(partial(self.focus_curve, pv_name))

        annotate_curve_btn = QPushButton("Annotate...")
        annotate_curve_btn.setObjectName(pv_name)
        annotate_curve_btn.setMaximumWidth(100)
        annotate_curve_btn.clicked.connect(
            partial(self.annotate_curve, pv_name))

        remove_curve_btn = QPushButton("Remove")
        remove_curve_btn.setObjectName(pv_name)
        remove_curve_btn.setMaximumWidth(100)
        remove_curve_btn.clicked.connect(partial(self.remove_curve, pv_name))

        curve_btn_layout.addWidget(modify_curve_btn)
        curve_btn_layout.addWidget(focus_curve_btn)
        curve_btn_layout.addWidget(annotate_curve_btn)
        curve_btn_layout.addWidget(remove_curve_btn)

        individual_curve_layout = QVBoxLayout()
        individual_curve_layout.addWidget(checkbox)
        individual_curve_layout.addWidget(data_text)
        individual_curve_layout.addLayout(curve_btn_layout)

        size_policy = QSizePolicy()
        size_policy.setVerticalPolicy(QSizePolicy.Fixed)
        individual_curve_grpbx = QGroupBox()
        individual_curve_grpbx.setSizePolicy(size_policy)

        individual_curve_grpbx.setObjectName(pv_name)
        individual_curve_grpbx.setLayout(individual_curve_layout)

        self.curve_settings_layout.addWidget(individual_curve_grpbx)
        self.tab_panel.show()
Ejemplo n.º 4
0
class OpticsCorrWindow(SiriusMainWindow):
    """Class to include some intelligence in the .ui files."""

    def __init__(self, acc, opticsparam, parent=None, prefix=_VACA_PREFIX):
        """Initialize some widgets."""
        super(OpticsCorrWindow, self).__init__(parent)
        self.prefix = prefix
        self.acc = acc.upper()
        self.param = opticsparam
        self.ioc_prefix = _PVName(
            self.acc+'-Glob:AP-'+self.param.title()+'Corr')
        self.ioc_prefix = self.ioc_prefix.substitute(prefix=self.prefix)
        self.title = self.acc + ' ' + self.param.title() + ' Correction'

        if self.param == 'tune':
            self.param_pv = 'DeltaTune{0}-{1}'
            self.intstrength = 'KL'
            self.intstrength_calcdesc = 'DeltaKL-Mon'
            self.intstrength_calcpv = 'DeltaKL{}-Mon'
            self.fams = list(_Const.SI_QFAMS_TUNECORR) if self.acc == 'SI' \
                else list(_Const.BO_QFAMS_TUNECORR)
        elif self.param == 'chrom':
            self.param_pv = 'Chrom{0}-{1}'
            self.intstrength = 'SL'
            self.intstrength_calcdesc = 'CalcSL-Mon'
            self.intstrength_calcpv = 'SL{}-Mon'
            self.fams = list(_Const.SI_SFAMS_CHROMCORR) if self.acc == 'SI' \
                else list(_Const.BO_SFAMS_CHROMCORR)

        self.setWindowTitle(self.title)
        self.setObjectName(self.acc+'App')
        self._setupUi()
        self.setFocus(True)
        self.setFocusPolicy(Qt.StrongFocus)

    def _setupUi(self):
        label = QLabel('<h3>'+self.title+'</h3>', self)
        label.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));""")

        self.gb_status = QGroupBox('Status', self)
        self.gb_status.setLayout(self._setupStatusLayout())

        self.wid_optics = QWidget()
        lay_optics = QGridLayout(self.wid_optics)
        lay_optics.setContentsMargins(0, 0, 0, 0)
        self.gb_optprm = QGroupBox(
            'ΔTune' if self.param == 'tune' else 'Chromaticity', self)
        self.gb_optprm.setLayout(self._setupOpticsParamLayout())
        if self.param == 'tune':
            self.pb_updref = PyDMPushButton(
                self, label='Update Reference', pressValue=1,
                init_channel=self.ioc_prefix.substitute(propty='SetNewRefKL-Cmd'))
            self.pb_updref.setStyleSheet('min-height:2.4em; max-height:2.4em;')
            lay_optics.addWidget(self.pb_updref, 0, 0, 1, 2)
            lay_optics.addWidget(self.gb_optprm, 1, 0)

            if self.acc == 'SI':
                self.gb_digmon = QGroupBox('Tune Monitor', self)
                self.gb_digmon.setLayout(self._setupDigMonLayout())
                lay_optics.addWidget(self.gb_digmon, 1, 1)
                lay_optics.setColumnStretch(0, 3)
                lay_optics.setColumnStretch(1, 1)
        else:
            lay_optics.addWidget(self.gb_optprm, 0, 0)

        self.gb_fams = QGroupBox('Families', self)
        self.gb_fams.setLayout(self._setupFamiliesLayout())
        self.gb_fams.setSizePolicy(QSzPly.Preferred, QSzPly.Expanding)

        self.gb_iocctrl = QGroupBox('IOC Control', self)
        self.gb_iocctrl.setLayout(self._setupIOCControlLayout())

        cwt = QWidget()
        self.setCentralWidget(cwt)
        if self.acc == 'SI':
            vlay1 = QVBoxLayout()
            vlay1.setAlignment(Qt.AlignTop)
            vlay1.addWidget(self.wid_optics)
            vlay1.addWidget(self.gb_fams)
            lay = QGridLayout(cwt)
            lay.addWidget(label, 0, 0, 1, 2)
            lay.addLayout(vlay1, 1, 0, alignment=Qt.AlignTop)
            lay.addWidget(self.gb_iocctrl, 1, 1)
            lay.addWidget(self.gb_status, 2, 0, 1, 2)
            lay.setColumnStretch(0, 1)
            lay.setColumnStretch(1, 1)
            lay.setRowStretch(0, 1)
            lay.setRowStretch(1, 15)
            lay.setRowStretch(2, 5)
        else:
            lay = QVBoxLayout(cwt)
            lay.addWidget(label)
            lay.addWidget(self.wid_optics)
            lay.addWidget(self.gb_fams)
            lay.addWidget(self.gb_iocctrl)
            lay.addWidget(self.gb_status)

        self.setStyleSheet("""
            PyDMLabel{
                qproperty-alignment: AlignCenter;
            }""")

    def _setupStatusLayout(self):
        self.log_label = PyDMLogLabel(
            self, self.ioc_prefix.substitute(propty='Log-Mon'))

        lay = QVBoxLayout()
        lay.addWidget(self.log_label)
        return lay

    def _setupOpticsParamLayout(self):
        self.lb_x = QLabel('<h4>X</h4>', self, alignment=Qt.AlignCenter)
        self.lb_y = QLabel('<h4>Y</h4>', self, alignment=Qt.AlignCenter)
        self.lb_sp = QLabel('<h4>SP</h4>', self, alignment=Qt.AlignCenter)
        self.lb_rb = QLabel('<h4>RB</h4>', self, alignment=Qt.AlignCenter)
        self.lb_mon = QLabel(
            '<h4>Estimative</h4>', self, alignment=Qt.AlignCenter)

        self.sb_paramx = PyDMSpinbox(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('X', 'SP')))
        self.sb_paramx.showStepExponent = False
        self.sb_paramy = PyDMSpinbox(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('Y', 'SP')))
        self.sb_paramy.showStepExponent = False

        self.lb_paramx = PyDMLabel(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('X', 'RB')))
        self.lb_paramy = PyDMLabel(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('Y', 'RB')))

        self.lb_prmmonx = PyDMLabel(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('X', 'Mon')))
        self.lb_prmmony = PyDMLabel(self, self.ioc_prefix.substitute(
            propty=self.param_pv.format('Y', 'Mon')))

        self.bt_apply = PyDMPushButton(
            self, label='Apply', pressValue=1,
            init_channel=self.ioc_prefix.substitute(
                propty='ApplyDelta-Cmd'))

        lay = QGridLayout()
        lay.addWidget(self.lb_sp, 0, 1)
        lay.addWidget(self.lb_rb, 0, 2)
        lay.addWidget(self.lb_x, 1, 0)
        lay.addWidget(self.sb_paramx, 1, 1)
        lay.addWidget(self.lb_paramx, 1, 2)
        lay.addWidget(self.lb_y, 2, 0)
        lay.addWidget(self.sb_paramy, 2, 1)
        lay.addWidget(self.lb_paramy, 2, 2)
        lay.addWidget(self.lb_mon, 0, 3)
        lay.addWidget(self.lb_prmmonx, 1, 3)
        lay.addWidget(self.lb_prmmony, 2, 3)
        lay.addWidget(self.bt_apply, 3, 1)
        lay.setColumnStretch(0, 1)
        lay.setColumnStretch(1, 5)
        lay.setColumnStretch(2, 5)
        lay.setColumnStretch(3, 5)

        if self.acc == 'SI' and self.param == 'chrom':
            self._icon_absval = qta.icon(
                'mdi.alpha-a', 'mdi.alpha-b', 'mdi.alpha-s', options=[
                    dict(scale_factor=1.5, offset=(-0.4, 0.0)),
                    dict(scale_factor=1.5, offset=(0.0, 0.0)),
                    dict(scale_factor=1.5, offset=(+0.4, 0.0))])
            self._icon_delta = qta.icon('mdi.delta')
            self._is_setting = 'absolut'
            self.pb_change_sp = QPushButton(self._icon_absval, '', self)
            self.pb_change_sp.clicked.connect(self._change_chrom_sp)

            self.sb_paramx_delta = PyDMSpinbox(
                self, self.ioc_prefix.substitute(propty='DeltaChromX-SP'))
            self.sb_paramx_delta.showStepExponent = False
            self.sb_paramx_delta.setVisible(False)

            self.sb_paramy_delta = PyDMSpinbox(
                self, self.ioc_prefix.substitute(propty='DeltaChromY-SP'))
            self.sb_paramy_delta.showStepExponent = False
            self.sb_paramy_delta.setVisible(False)

            self.lb_paramx_delta = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='DeltaChromX-RB'))
            self.lb_paramx_delta.setVisible(False)
            self.lb_paramy_delta = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='DeltaChromY-RB'))
            self.lb_paramy_delta.setVisible(False)

            self.lb_mon.setText('Implem.\nEstimative')
            self.lb_mon.setStyleSheet('font-weight: bold;')
            self.lb_calcmon = QLabel(
                'Calcd.\nEstimative', self, alignment=Qt.AlignCenter)
            self.lb_calcmon.setStyleSheet('font-weight: bold;')

            self.lb_prmcalcmonx = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='CalcChromX-Mon'))
            self.lb_prmcalcmony = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='CalcChromY-Mon'))

            lay.addWidget(self.pb_change_sp, 0, 0)
            lay.addWidget(self.sb_paramx_delta, 1, 1)
            lay.addWidget(self.sb_paramy_delta, 2, 1)
            lay.addWidget(self.lb_paramx_delta, 1, 2)
            lay.addWidget(self.lb_paramy_delta, 2, 2)
            lay.addWidget(self.lb_calcmon, 0, 4)
            lay.addWidget(self.lb_prmcalcmonx, 1, 4)
            lay.addWidget(self.lb_prmcalcmony, 2, 4)
        return lay

    def _setupDigMonLayout(self):
        lb_x = QLabel('<h4>X</h4>', self, alignment=Qt.AlignCenter)
        lb_y = QLabel('<h4>Y</h4>', self, alignment=Qt.AlignCenter)
        self.lb_tunex = PyDMLabel(self, 'SI-Glob:DI-Tune-H:TuneFrac-Mon')
        self.lb_tuney = PyDMLabel(self, 'SI-Glob:DI-Tune-V:TuneFrac-Mon')

        lay = QGridLayout()
        lay.addWidget(lb_x, 0, 0)
        lay.addWidget(self.lb_tunex, 0, 1)
        lay.addWidget(lb_y, 1, 0)
        lay.addWidget(self.lb_tuney, 1, 1)
        lay.setColumnStretch(0, 1)
        lay.setColumnStretch(1, 5)
        return lay

    def _setupFamiliesLayout(self):
        lay = QGridLayout()

        lb_family = QLabel('<h4>Family</h4>', self, alignment=Qt.AlignCenter)
        lb_family.setStyleSheet('max-height:1.29em;')
        lay.addWidget(lb_family, 0, 1)

        lb_rbdesc = QLabel('<h4>'+self.intstrength+'-RB</h4>', self,
                           alignment=Qt.AlignCenter)
        lb_rbdesc.setStyleSheet('max-height:1.29em;')
        lay.addWidget(lb_rbdesc, 0, 2)

        if self.param == 'tune':
            lb_refdesc = QLabel('<h4>RefKL-Mon</h4>', self,
                                alignment=Qt.AlignCenter)
            lb_refdesc.setStyleSheet('max-height:1.29em;')
            lay.addWidget(lb_refdesc, 0, 3)

        lb_lastddesc = QLabel('<h4>'+self.intstrength_calcdesc+'</h4>', self,
                              alignment=Qt.AlignCenter)
        lb_lastddesc.setStyleSheet('max-height:1.29em;')
        lay.addWidget(lb_lastddesc, 0, 4)

        row = 1
        for fam in self.fams:
            dev_name = _PVName(self.acc+'-Fam:PS-'+fam)
            pref_name = dev_name.substitute(prefix=self.prefix)

            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;}""")
            _hlautil.connect_window(
                pbt, _PSDetailWindow, parent=self, psname=dev_name)
            lay.addWidget(pbt, row, 0)

            lb_name = QLabel(fam, self, alignment=Qt.AlignCenter)
            lay.addWidget(lb_name, row, 1)

            lb_rb = PyDMLabel(self, pref_name.substitute(
                propty=self.intstrength+'-RB'))
            lay.addWidget(lb_rb, row, 2)

            if self.param == 'tune':
                lb_ref = PyDMLabel(self, self.ioc_prefix.substitute(
                    propty='RefKL'+fam+'-Mon'))
                lay.addWidget(lb_ref, row, 3)

            lb_calc = PyDMLabel(self, self.ioc_prefix.substitute(
                propty=self.intstrength_calcpv.format(fam)))
            lay.addWidget(lb_calc, row, 4)
            row += 1
        return lay

    def _setupIOCControlLayout(self):
        lay = QGridLayout()

        lb_sts = QLabel('<h4>Status</h4>', self)
        self.led_sts = _StatusLed(self, self.ioc_prefix.substitute(
            propty='Status-Mon'))
        lay.addWidget(lb_sts, 0, 0)
        lay.addWidget(self.led_sts, 0, 1, alignment=Qt.AlignLeft)

        lb_conf = QLabel('<h4>Configuration</h4>')
        self.bt_dtls = QPushButton(qta.icon('fa5s.list-ul'), '', self)
        _hlautil.connect_window(
            self.bt_dtls, _CorrParamsDetailWindow, parent=self,
            acc=self.acc, opticsparam=self.param,
            prefix=self.prefix, fams=self.fams)
        lay.addWidget(lb_conf, 2, 0, 1, 2)
        lay.addWidget(self.bt_dtls, 2, 2, alignment=Qt.AlignRight)

        lb_cname = QLabel('Name', self)
        self.le_cname = _ConfigLineEdit(
            self, self.ioc_prefix.substitute(
                propty='ConfigName-SP'))
        self.lb_cname = PyDMLabel(self, self.ioc_prefix.substitute(
            propty='ConfigName-RB'))
        lay.addWidget(lb_cname, 3, 0)
        lay.addWidget(self.le_cname, 3, 1, 1, 2)
        lay.addWidget(self.lb_cname, 4, 1, 1, 2)

        row = 5
        if self.acc == 'SI':
            lay.addItem(
                QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), 5, 0)
            row = 6

            if self.param == 'chrom':
                lb_meas_chrom = QLabel('<h4>Chrom. Measurement</h4>')
                lay.addWidget(lb_meas_chrom, 6, 0, 1, 3)

                lb_meas_chrom_dfRF = QLabel('ΔFreq RF [Hz]', self)
                self.sb_meas_chrom_dfRF = PyDMSpinbox(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromDeltaFreqRF-SP'))
                self.sb_meas_chrom_dfRF.showStepExponent = False
                self.lb_meas_chrom_dfRF = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromDeltaFreqRF-RB'))
                lay.addWidget(lb_meas_chrom_dfRF, 7, 0)
                lay.addWidget(self.sb_meas_chrom_dfRF, 7, 1)
                lay.addWidget(self.lb_meas_chrom_dfRF, 7, 2)

                lb_meas_chrom_wait = QLabel('Wait Tune [s]', self)
                self.sb_meas_chrom_wait = PyDMSpinbox(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromWaitTune-SP'))
                self.sb_meas_chrom_wait.showStepExponent = False
                self.lb_meas_chrom_wait = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromWaitTune-RB'))
                lay.addWidget(lb_meas_chrom_wait, 8, 0)
                lay.addWidget(self.sb_meas_chrom_wait, 8, 1)
                lay.addWidget(self.lb_meas_chrom_wait, 8, 2)

                lb_meas_chrom_nrsteps = QLabel('Nr Steps', self)
                self.sb_meas_chrom_nrsteps = PyDMSpinbox(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromNrSteps-SP'))
                self.sb_meas_chrom_nrsteps.showStepExponent = False
                self.lb_meas_chrom_nrsteps = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromNrSteps-RB'))
                lay.addWidget(lb_meas_chrom_nrsteps, 9, 0)
                lay.addWidget(self.sb_meas_chrom_nrsteps, 9, 1)
                lay.addWidget(self.lb_meas_chrom_nrsteps, 9, 2)

                lay.addItem(
                    QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), 10, 0)

                lb_meas_chrom_x = QLabel('Meas. Chrom X', self)
                self.lb_meas_chrom_x = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromX-Mon'))
                lay.addWidget(lb_meas_chrom_x, 11, 0)
                lay.addWidget(self.lb_meas_chrom_x, 11, 1)

                lb_meas_chrom_y = QLabel('Meas. Chrom Y', self)
                self.lb_meas_chrom_y = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromY-Mon'))
                lay.addWidget(lb_meas_chrom_y, 12, 0)
                lay.addWidget(self.lb_meas_chrom_y, 12, 1)

                lay.addItem(
                    QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), 13, 0)

                self.lb_meas_chrom_sts = PyDMLabel(
                    self, self.ioc_prefix.substitute(
                        propty='MeasChromStatus-Mon'))
                self.bt_meas_chrom_start = PyDMPushButton(
                    self, icon=qta.icon('fa5s.play'), label='',
                    init_channel=self.ioc_prefix.substitute(
                        propty='MeasChrom-Cmd'),
                    pressValue=_Const.MeasCmd.Start)
                self.bt_meas_chrom_start.setObjectName('start')
                self.bt_meas_chrom_start.setStyleSheet(
                    '#start{min-width:25px; max-width:25px; icon-size:20px;}')
                self.bt_meas_chrom_stop = PyDMPushButton(
                    self, icon=qta.icon('fa5s.stop'), label='',
                    init_channel=self.ioc_prefix.substitute(
                        propty='MeasChrom-Cmd'),
                    pressValue=_Const.MeasCmd.Stop)
                self.bt_meas_chrom_stop.setObjectName('stop')
                self.bt_meas_chrom_stop.setStyleSheet(
                    '#stop{min-width:25px; max-width:25px; icon-size:20px;}')
                self.bt_meas_chrom_rst = PyDMPushButton(
                    self, icon=qta.icon('fa5s.sync'), label='',
                    init_channel=self.ioc_prefix.substitute(
                        propty='MeasChrom-Cmd'),
                    pressValue=_Const.MeasCmd.Reset)
                self.bt_meas_chrom_rst.setObjectName('rst')
                self.bt_meas_chrom_rst.setStyleSheet(
                    '#rst{min-width:25px; max-width:25px; icon-size:20px;}')
                hbox_cmd = QHBoxLayout()
                hbox_cmd.addWidget(self.bt_meas_chrom_start)
                hbox_cmd.addWidget(self.bt_meas_chrom_stop)
                hbox_cmd.addWidget(self.bt_meas_chrom_rst)
                lay.addWidget(self.lb_meas_chrom_sts, 14, 0, 1, 2)
                lay.addLayout(hbox_cmd, 14, 2)

                lay.addItem(
                    QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), 15, 0)
                row = 15

            # configuration measurement
            lb_meas_conf = QLabel('<h4>Config. Measurement</h4>')
            lay.addWidget(lb_meas_conf, row+1, 0, 1, 3)

            mag_type = 'Q' if self.param == 'tune' else 'S'
            unit = '[1/m]' if self.param == 'tune' else '[1/m2]'

            lb_meas_conf_dfamF = QLabel(
                'Fam. Δ'+self.intstrength+' '+mag_type+'F '+unit, self)
            self.sb_meas_conf_dfamF = PyDMSpinbox(
                self, self.ioc_prefix.substitute(
                    propty='MeasConfigDelta'+self.intstrength +
                           'Fam'+mag_type+'F-SP'))
            self.sb_meas_conf_dfamF.showStepExponent = False
            self.lb_meas_conf_dfamF = PyDMLabel(
                self, self.ioc_prefix.substitute(
                    propty='MeasConfigDelta'+self.intstrength +
                           'Fam'+mag_type+'F-RB'))
            lay.addWidget(lb_meas_conf_dfamF, row+2, 0)
            lay.addWidget(self.sb_meas_conf_dfamF, row+2, 1)
            lay.addWidget(self.lb_meas_conf_dfamF, row+2, 2)

            lb_meas_conf_dfamD = QLabel(
                'Fam. Δ'+self.intstrength+' '+mag_type+'D '+unit, self)
            self.sb_meas_conf_dfamD = PyDMSpinbox(
                self, self.ioc_prefix.substitute(
                    propty='MeasConfigDelta'+self.intstrength +
                           'Fam'+mag_type+'D-SP'))
            self.sb_meas_conf_dfamD.showStepExponent = False
            self.lb_meas_conf_dfamD = PyDMLabel(
                self, self.ioc_prefix.substitute(
                    propty='MeasConfigDelta'+self.intstrength +
                           'Fam'+mag_type+'D-RB'))
            lay.addWidget(lb_meas_conf_dfamD, row+3, 0)
            lay.addWidget(self.sb_meas_conf_dfamD, row+3, 1)
            lay.addWidget(self.lb_meas_conf_dfamD, row+3, 2)

            lb_meas_conf_wait = QLabel('Wait [s]', self)
            self.sb_meas_conf_wait = PyDMSpinbox(
                self, self.ioc_prefix.substitute(propty='MeasConfigWait-SP'))
            self.sb_meas_conf_wait.showStepExponent = False
            self.lb_meas_conf_wait = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='MeasConfigWait-RB'))
            lay.addWidget(lb_meas_conf_wait, row+4, 0)
            lay.addWidget(self.sb_meas_conf_wait, row+4, 1)
            lay.addWidget(self.lb_meas_conf_wait, row+4, 2)

            lb_meas_conf_cname = QLabel('Name to save', self)
            self.le_meas_conf_name = PyDMLineEdit(
                self, self.ioc_prefix.substitute(propty='MeasConfigName-SP'))
            self.lb_meas_conf_name = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='MeasConfigName-RB'))
            lay.addWidget(lb_meas_conf_cname, row+5, 0)
            lay.addWidget(self.le_meas_conf_name, row+5, 1, 1, 2)
            lay.addWidget(self.lb_meas_conf_name, row+6, 1, 1, 2)

            lb_meas_conf_save = QLabel('Force Save', self)
            self.bt_meas_conf_save = PyDMPushButton(
                self, icon=qta.icon('mdi.content-save'), label='',
                init_channel=self.ioc_prefix.substitute(
                    propty='MeasConfigSave-Cmd'),
                pressValue=1)
            self.bt_meas_conf_save.setObjectName('save')
            self.bt_meas_conf_save.setStyleSheet(
                '#save{min-width:25px; max-width:25px; icon-size:20px;}')
            lay.addWidget(lb_meas_conf_save, row+7, 0)
            lay.addWidget(
                self.bt_meas_conf_save, row+7, 1, alignment=Qt.AlignLeft)

            lay.addItem(
                QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), row+8, 0)

            self.lb_meas_conf_sts = PyDMLabel(
                self, self.ioc_prefix.substitute(
                    propty='MeasConfigStatus-Mon'))
            self.bt_meas_conf_start = PyDMPushButton(
                self, icon=qta.icon('fa5s.play'), label='',
                init_channel=self.ioc_prefix.substitute(
                    propty='MeasConfig-Cmd'),
                pressValue=_Const.MeasCmd.Start)
            self.bt_meas_conf_start.setObjectName('start')
            self.bt_meas_conf_start.setStyleSheet(
                '#start{min-width:25px; max-width:25px; icon-size:20px;}')
            self.bt_meas_conf_stop = PyDMPushButton(
                self, icon=qta.icon('fa5s.stop'), label='',
                init_channel=self.ioc_prefix.substitute(
                    propty='MeasConfig-Cmd'),
                pressValue=_Const.MeasCmd.Stop)
            self.bt_meas_conf_stop.setObjectName('stop')
            self.bt_meas_conf_stop.setStyleSheet(
                '#stop{min-width:25px; max-width:25px; icon-size:20px;}')
            self.bt_meas_conf_rst = PyDMPushButton(
                self, icon=qta.icon('fa5s.sync'), label='',
                init_channel=self.ioc_prefix.substitute(
                    propty='MeasConfig-Cmd'),
                pressValue=_Const.MeasCmd.Reset)
            self.bt_meas_conf_rst.setObjectName('rst')
            self.bt_meas_conf_rst.setStyleSheet(
                '#rst{min-width:25px; max-width:25px; icon-size:20px;}')
            hbox_cmd = QHBoxLayout()
            hbox_cmd.addWidget(self.bt_meas_conf_start)
            hbox_cmd.addWidget(self.bt_meas_conf_stop)
            hbox_cmd.addWidget(self.bt_meas_conf_rst)
            lay.addWidget(self.lb_meas_conf_sts, row+9, 0, 1, 2)
            lay.addLayout(hbox_cmd, row+9, 2)

            lay.addItem(
                QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Fixed), row+10, 0)

            # correction settings
            lb_corr = QLabel('<h4>Settings</h4>')
            lay.addWidget(lb_corr, row+11, 0, 1, 3)

            lb_meth = QLabel('Method', self)
            self.cb_method = PyDMEnumComboBox(
                self, self.ioc_prefix.substitute(propty='CorrMeth-Sel'))
            self.lb_method = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='CorrMeth-Sts'))
            lay.addWidget(lb_meth, row+12, 0)
            lay.addWidget(self.cb_method, row+12, 1)
            lay.addWidget(self.lb_method, row+12, 2)

            lb_grp = QLabel('Grouping', self)
            self.cb_group = PyDMEnumComboBox(
                self, self.ioc_prefix.substitute(propty='CorrGroup-Sel'))
            self.lb_group = PyDMLabel(
                self, self.ioc_prefix.substitute(propty='CorrGroup-Sts'))
            lay.addWidget(lb_grp, row+13, 0)
            lay.addWidget(self.cb_group, row+13, 1)
            lay.addWidget(self.lb_group, row+13, 2)

            if self.param == 'tune':
                lb_sync = QLabel('Sync', self)
                self.bt_sync = PyDMStateButton(
                    self, self.ioc_prefix.substitute(propty='SyncCorr-Sel'))
                self.bt_sync.shape = 1
                self.lb_sync = PyDMLabel(
                    self, self.ioc_prefix.substitute(propty='SyncCorr-Sts'))
                lay.addWidget(lb_sync, row+14, 0)
                lay.addWidget(self.bt_sync, row+14, 1)
                lay.addWidget(self.lb_sync, row+14, 2)
            row = row + 15

        lay.addItem(
            QSpacerItem(1, 20, QSzPly.Ignored, QSzPly.Expanding), row, 0)
        return lay

    def _change_chrom_sp(self):
        cond = self._is_setting == 'absolut'
        self._is_setting = 'delta' if cond else 'absolut'
        icon = self._icon_delta if cond else self._icon_absval
        textX = '<h4>Δ-SP</h4>' if cond else '<h4>SP</h4>'
        textY = '<h4>Δ-RB</h4>' if cond else '<h4>RB</h4>'
        self.sb_paramx.setVisible(not cond)
        self.lb_paramx.setVisible(not cond)
        self.sb_paramy.setVisible(not cond)
        self.lb_paramy.setVisible(not cond)
        self.sb_paramx_delta.setVisible(cond)
        self.lb_paramx_delta.setVisible(cond)
        self.sb_paramy_delta.setVisible(cond)
        self.lb_paramy_delta.setVisible(cond)
        self.pb_change_sp.setIcon(icon)
        self.lb_sp.setText(textX)
        self.lb_rb.setText(textY)