def __init__(self, parent=None): QDialog.__init__( self, parent, flags=Qt.WindowSystemMenuHint | Qt.WindowTitleHint) self.setWindowTitle('Read Model') self.treeview = parent self.setAttribute(Qt.WA_DeleteOnClose) fixed_dir_layout = QHBoxLayout() browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select model directory")) browse_btn.clicked.connect(self.select_directory) self.wd_edit = QLineEdit() fixed_dir_layout.addWidget(self.wd_edit) fixed_dir_layout.addWidget(browse_btn) fixed_dir_layout.setContentsMargins(0, 0, 0, 0) namelabel = QLabel(_("Model Name")) self.nameEdit = QLineEdit(self) self.importWidget = ImportAsWidget(self, self.nameEdit) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) mainLayout = QGridLayout(self) mainLayout.addLayout(fixed_dir_layout, 0, 0, 1, 2) mainLayout.addWidget(namelabel, 1, 0) mainLayout.addWidget(self.nameEdit, 1, 1) mainLayout.addWidget(self.importWidget, 2, 0, 1, 2) mainLayout.addWidget(self.buttonBox, 3, 0, 1, 2) # mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(mainLayout)
def setupui(self): vbl = QGridLayout(self) lab = QLabel('<h2>' + self.bpm + ' Triggered Acquisitions</h2>') lab.setAlignment(Qt.AlignCenter) vbl.addWidget(lab, 0, 0, 1, 2) self.stack = QStackedLayout() multi_pass = MultiTurnData(parent=self, acq_type='ACQ', prefix=self.prefix, bpm=self.bpm) multi_pass.setObjectName('multi_pass') single_pass = SinglePassData(parent=self, prefix=self.prefix, bpm=self.bpm) single_pass.setObjectName('single_pass') self.stack.addWidget(multi_pass) self.stack.addWidget(single_pass) vbl.addLayout(self.stack, 1, 0) config = ACQTrigConfigs(parent=self, prefix=self.prefix, bpm=self.bpm, data_prefix='ACQ') config.setObjectName('config') vbl.addWidget(config, 1, 1) self.setStyleSheet(""" #multi_pass{ min-width:50em; min-height:48em;} #single_pass{ min-width:50em; min-height:48em;} #config{ min-height:21em;}""")
def __init__(self, parent=None, prefix='', is_main=False): """Init.""" super().__init__(parent) self.setObjectName('ITApp') ld_tienbl = QLabel('Enable Pulses', self, alignment=Qt.AlignCenter) bt_tienblsel = PyDMStateButton( self, prefix + 'IT-EGH:TI-TrigGen:ChanOut-Sel') led_tienblsts = SiriusLedState( self, prefix + 'IT-EGH:TI-TrigGen:ChanOut-Sts') lay = QGridLayout(self) lay.setAlignment(Qt.AlignCenter) lay.setContentsMargins(0, 0, 0, 0) glay = QGridLayout() glay.addWidget(ld_tienbl, 0, 0, 1, 2) glay.addWidget(bt_tienblsel, 1, 0) glay.addWidget(led_tienblsts, 1, 1) if not is_main: gbox = QGroupBox('Timing', self) gbox.setLayout(glay) lay.addWidget(gbox) else: lb_title = QLabel('<h3>IT - Timing</h3>', self, alignment=Qt.AlignCenter) lay.setHorizontalSpacing(15) lay.setVerticalSpacing(15) lay.addWidget(lb_title, 0, 0) lay.addLayout(glay, 1, 0)
def _setupCoeffSettingsWidget(self): ld_coefchoo = QLabel('Choose Set', self, alignment=Qt.AlignRight) cb_coefchoo = PyDMEnumComboBox(self, self.dev_pref + ':LDSET') pb_coefload = PyDMPushButton(parent=self, label='Apply Set', icon=qta.icon('mdi.upload'), init_channel=self.dev_pref + ':BO_CPCOEFF', pressValue=1) pb_coefload.setStyleSheet("icon-size:20px;") pb_coefvrfy = PyDMPushButton(parent=self, label='Verify Set', icon=qta.icon('mdi.check-circle-outline'), init_channel=self.dev_pref + ':BO_CVERIFY', pressValue=1) pb_coefvrfy.setStyleSheet("icon-size:20px;") ld_gen = QLabel('<h4>Generate Coefficients</h4>', self, alignment=Qt.AlignCenter) ld_gengain = QLabel('Gain [0-1]', self, alignment=Qt.AlignRight) sb_gengain = PyDMSpinbox(self, self.dev_pref + ':FLT_GAIN') sb_gengain.showStepExponent = False ld_genphs = QLabel('Phase [°]', self, alignment=Qt.AlignRight) sb_genphs = PyDMSpinbox(self, self.dev_pref + ':FLT_PHASE') sb_genphs.showStepExponent = False ld_genfreq = QLabel('Frequency [0-1]', self, alignment=Qt.AlignRight) sb_genfreq = PyDMSpinbox(self, self.dev_pref + ':FLT_FREQ') sb_genfreq.showStepExponent = False ld_genntap = QLabel('Number of taps', self, alignment=Qt.AlignRight) sb_genntap = PyDMSpinbox(self, self.dev_pref + ':FLT_TAPS') sb_genntap.showStepExponent = False wid = QWidget(self) lay_genset = QGridLayout(wid) lay_genset.setVerticalSpacing(6) lay_genset.setHorizontalSpacing(9) lay_genset.addWidget(ld_gen, 0, 1, 1, 2) lay_genset.addWidget(ld_gengain, 1, 1) lay_genset.addWidget(sb_gengain, 1, 2) lay_genset.addWidget(ld_genphs, 2, 1) lay_genset.addWidget(sb_genphs, 2, 2) lay_genset.addWidget(ld_genfreq, 3, 1) lay_genset.addWidget(sb_genfreq, 3, 2) lay_genset.addWidget(ld_genntap, 4, 1) lay_genset.addWidget(sb_genntap, 4, 2) lay_genset.addWidget(ld_coefchoo, 5, 1) lay_genset.addWidget(cb_coefchoo, 5, 2) lay = QGridLayout() lay_genset.addLayout(lay, 6, 1, 1, 2) lay.addWidget(pb_coefload, 0, 0) lay.addWidget(pb_coefvrfy, 0, 2) lay.setColumnStretch(1, 2) lay_genset.setRowStretch(7, 2) lay_genset.setColumnStretch(0, 2) lay_genset.setColumnStretch(3, 2) return wid
def setup_gui(self): """Setup the main layout of the widget.""" layout = QGridLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas, 0, 0, Qt.AlignCenter) layout.addLayout(self.setup_toolbar(), 0, 1, 2, 1) layout.setRowStretch(1, 100) layout.setSizeConstraint(layout.SetFixedSize)
def _setupFBSettingsWidget(self): gbox_settings = QGroupBox('FeedBack Settings', self) ld_fbpatt = QLabel('Feedback Mask', self) le_fbpatt = PyDMLineEdit(self, self.dev_pref + ':FB_PATTERN') ld_cfpatt = QLabel('Alternate Mask', self) le_cfpatt = PyDMLineEdit(self, self.dev_pref + ':CF_PATTERN') ld_alter_inuse = QLabel('Alternate Set In Use', self) led_alter_inuse = SiriusLedState( self, self.dev_pref + ':CF_PATTERN_SUB.VALB') ld_fbenbl = QLabel('Enable', self) pb_fbenbl = PyDMStateButton(self, self.dev_pref + ':FBCTRL') ld_coefsel = QLabel('Coeficient Set', self) cb_coefsel = PyDMEnumComboBox(self, self.dev_pref + ':SETSEL') ld_sftgain = QLabel('Shift Gain', self) sb_sftgain = PyDMSpinbox(self, self.dev_pref + ':SHIFTGAIN') sb_sftgain.showStepExponent = False ld_downspl = QLabel('Downsampling', self) sb_downspl = PyDMSpinbox(self, self.dev_pref + ':PROC_DS') sb_downspl.showStepExponent = False ld_satthrs = QLabel('Sat. Threshold [%]', self) sb_satthrs = PyDMSpinbox(self, self.dev_pref + ':SAT_THRESHOLD') sb_satthrs.showStepExponent = False lay_patt = QGridLayout() lay_patt.addWidget(ld_fbpatt, 0, 0) lay_patt.addWidget(le_fbpatt, 0, 1) lay_patt.addWidget(ld_cfpatt, 1, 0) lay_patt.addWidget(le_cfpatt, 1, 1) lay_patt.addWidget(ld_alter_inuse, 2, 0) lay_patt.addWidget(led_alter_inuse, 2, 1) lay = QGridLayout(gbox_settings) lay.addWidget(ld_fbenbl, 0, 1) lay.addWidget(pb_fbenbl, 0, 2) lay.addWidget(ld_downspl, 0, 4) lay.addWidget(sb_downspl, 0, 5) lay.addWidget(ld_coefsel, 1, 1) lay.addWidget(cb_coefsel, 1, 2) lay.addWidget(ld_sftgain, 1, 4) lay.addWidget(sb_sftgain, 1, 5) lay.addWidget(ld_satthrs, 2, 1) lay.addWidget(sb_satthrs, 2, 2) lay.addLayout(lay_patt, 4, 1, 1, 5) lay.setColumnStretch(0, 3) lay.setColumnStretch(6, 3) lay.setColumnStretch(3, 2) lay.setRowStretch(3, 2) lay.setRowStretch(5, 3) return gbox_settings
class HistogramWidget(QWidget): def __init__( self, x: np.ndarray, y: np.ndarray, xlabel: Optional[str] = None, ylabel: Optional[str] = None, parent=None, ): super(HistogramWidget, self).__init__(parent) # set the width of the histogram plot to match the napari layer control width self.setMinimumWidth(240) self.setMaximumWidth(240) self.hist_plot = Histogram(x, y, xlabel=xlabel, ylabel=ylabel, parent=self) self.hist_plot.setMaximumWidth(230) self.thresh_text = QLineEdit() self.text_layout = QHBoxLayout() self.text_layout.addWidget(QLabel("SNR threshold:")) self.text_layout.addWidget(self.thresh_text) self.text_layout.addItem(QSpacerItem(5, 1)) self.grid_layout = QGridLayout(self) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) # self.grid_layout.setColumnMinimumWidth(0, 86) # self.grid_layout.setColumnStretch(1, 1) self.grid_layout.addWidget(self.hist_plot, 0, 0, 4, 6) self.grid_layout.addLayout(self.text_layout, 4, 0) self.grid_layout.setRowStretch(5, 1) self.grid_layout.setColumnStretch(1, 1) self.setLayout(self.grid_layout) self.threshold_changed_callbacks = [] self._on_hist_thresh_change() # connect events self.hist_plot.connect_line_dragged(self._on_hist_thresh_change) self.thresh_text.returnPressed.connect(self._on_thresh_text_change) def _on_hist_thresh_change(self): hist_thresh_value = self.hist_plot._vert_line.getPos()[0] self.thresh_text.setText(f"{hist_thresh_value:.2f}") for func in self.threshold_changed_callbacks: func() def _on_thresh_text_change(self): hist_thresh_value = float(self.thresh_text.text()) self.hist_plot._vert_line.setValue(hist_thresh_value)
def __init__(self, parent=None): super(WidgetGallery, self).__init__(parent) self.originalPalette = QApplication.palette() styleComboBox = QComboBox() styleComboBox.addItems(QStyleFactory.keys()) styleLabel = QLabel("&Style:") styleLabel.setBuddy(styleComboBox) self.useStylePaletteCheckBox = QCheckBox( "&Use style's standard palette") self.useStylePaletteCheckBox.setChecked(True) disableWidgetsCheckBox = QCheckBox("&Disable widgets") self.createTopLeftGroupBox() self.createTopRightGroupBox() self.createBottomLeftTabWidget() self.createBottomRightGroupBox() self.createProgressBar() styleComboBox.activated[str].connect(self.changeStyle) self.useStylePaletteCheckBox.toggled.connect(self.changePalette) disableWidgetsCheckBox.toggled.connect( self.topLeftGroupBox.setDisabled) disableWidgetsCheckBox.toggled.connect( self.topRightGroupBox.setDisabled) disableWidgetsCheckBox.toggled.connect( self.bottomLeftTabWidget.setDisabled) disableWidgetsCheckBox.toggled.connect( self.bottomRightGroupBox.setDisabled) topLayout = QHBoxLayout() topLayout.addWidget(styleLabel) topLayout.addWidget(styleComboBox) topLayout.addStretch(1) topLayout.addWidget(self.useStylePaletteCheckBox) topLayout.addWidget(disableWidgetsCheckBox) mainLayout = QGridLayout() mainLayout.addLayout(topLayout, 0, 0, 1, 2) mainLayout.addWidget(self.topLeftGroupBox, 1, 0) mainLayout.addWidget(self.topRightGroupBox, 1, 1) mainLayout.addWidget(self.bottomLeftTabWidget, 2, 0) mainLayout.addWidget(self.bottomRightGroupBox, 2, 1) mainLayout.addWidget(self.progressBar, 3, 0, 1, 2) mainLayout.setRowStretch(1, 1) mainLayout.setRowStretch(2, 1) mainLayout.setColumnStretch(0, 1) mainLayout.setColumnStretch(1, 1) self.setLayout(mainLayout) self.changeStyle('Windows') self.val = 0
def setup_gui(self): """Setup the main layout of the widget.""" layout = QGridLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas, 0, 1) layout.addLayout(self.setup_toolbar(), 0, 3, 2, 1) layout.setColumnStretch(0, 100) layout.setColumnStretch(2, 100) layout.setRowStretch(1, 100)
def setupUI(self): mainLayout = QGridLayout() leftLayout = QVBoxLayout() rightLayout = QVBoxLayout() self.highLightLauncher = HighlightLauncher(self) leftLayout.addWidget(self.highLightLauncher) rightLayout.addWidget(self.noteEditor()) rightLayout.addWidget(self.textToSpeechUtility()) rightLayout.addWidget(self.utilities()) rightLayout.addStretch() mainLayout.addLayout(leftLayout, 0, 0, 1, 2) mainLayout.addLayout(rightLayout, 0, 2, 1, 1) self.setLayout(mainLayout)
def setup_ui(self): """Initialize widgets.""" info_label = QLabel() info_label.setText("Hit enter to capture your image!") self.image_label = QLabel() self.image_label.setMinimumSize(240, 320) self.image_label.setScaledContents(True) button_layout = QGridLayout() self.style_buttons = [ QRadioButton(settings.STYLE_SHORTCUTS[i] + ". " + style.name if i < len(settings.STYLE_SHORTCUTS) else style.name) for i, style in enumerate(self.styles) ] self.style_buttons[self.styles.index( self.selected_style)].setChecked(True) self.style_button_group = QButtonGroup() for i, btn in enumerate(self.style_buttons): button_layout.addWidget(btn, i // 3, i % 3) self.style_button_group.addButton(btn, i) btn.clicked.connect( partial(lambda style: self.style_button_clicked(style), self.styles[i])) ctrl_layout = QHBoxLayout() if not settings.KIOSK: fullscreen_button = QPushButton('[ ]') fullscreen_button.setMaximumWidth( fullscreen_button.fontMetrics().boundingRect('[ ]').width() + 10) fullscreen_button.clicked.connect(self.toggle_fullscreen) ctrl_layout.addWidget(fullscreen_button) ctrl_layout.addStretch(1) self.size_combo = QComboBox() for s in settings.SIZES: self.size_combo.addItem(s) self.size_combo.setCurrentIndex(settings.SIZES.index(self.quality)) ctrl_layout.addWidget(self.size_combo) self.size_combo.activated[str].connect(self.quality_choice) button_layout.addLayout(ctrl_layout, (len(self.style_buttons) - 1) // 3 + 1, 0, 1, 3) main_layout = QVBoxLayout() main_layout.addWidget(info_label) main_layout.addWidget(self.image_label, 1) main_layout.addLayout(button_layout) self.setLayout(main_layout)
def __init__(self, parent=None, modelpath=None): QDialog.__init__( self, parent, Qt.WindowSystemMenuHint | Qt.WindowTitleHint) self.setWindowTitle('Write Model') self.treeview = parent self.setAttribute(Qt.WA_DeleteOnClose) fixed_dir_layout = QHBoxLayout() browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self) browse_btn.setToolTip(_("Select Model Location")) browse_btn.clicked.connect(self.select_directory) namelabel = QLabel(_("Location")) self.wd_edit = QLineEdit(self) fixed_dir_layout.addWidget(namelabel) fixed_dir_layout.addWidget(self.wd_edit) fixed_dir_layout.addWidget(browse_btn) fixed_dir_layout.setContentsMargins(0, 0, 0, 0) namelabel = QLabel(_("Folder/File")) self.nameEdit = QLineEdit(self) if modelpath: location = "/".join(modelpath.split("/")[:-1]) name = modelpath.split("/")[-1] self.wd_edit.setText(location) self.nameEdit.setText(name) self.backupCheck = QCheckBox(_("Back up old folder")) self.backupCheck.setCheckState(Qt.Checked) self.zipmodelCheck = QCheckBox(_("Zip Model")) self.zipmodelCheck.setCheckState(Qt.Unchecked) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) mainLayout = QGridLayout(self) mainLayout.addLayout(fixed_dir_layout, 0, 0, 1, 2) mainLayout.addWidget(namelabel, 1, 0) mainLayout.addWidget(self.nameEdit, 1, 1) mainLayout.addWidget(self.backupCheck, 2, 0, 1, 2) mainLayout.addWidget(self.zipmodelCheck, 3, 0, 1, 2) mainLayout.addWidget(self.buttonBox, 4, 0, 1, 2) # mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(mainLayout)
def _setupBCSettingsWidget(self): gbox_settings = QGroupBox('Bunch Cleaning Settings', self) ld_bcenbl = QLabel('Enable', self) cb_bcenbl = PyDMStateButton(self, self.dev_pref + ':CLEAN_ENABLE') ld_bcamp = QLabel('Amplitude', self) sb_bcamp = PyDMSpinbox(self, self.dev_pref + ':CLEAN_AMPL') sb_bcamp.showStepExponent = False lb_svamp = PyDMLabel(self, self.dev_pref + ':CLEAN_SAVE_AMPL') ld_bctune = QLabel('Tune', self) sb_bctune = PyDMSpinbox(self, self.dev_pref + ':CLEAN_TUNE') sb_bctune.showStepExponent = False lb_svfreq = PyDMLabel(self, self.dev_pref + ':CLEAN_SAVE_FREQ') ld_bcspan = QLabel('Span', self) le_bcspan = PyDMLineEdit(self, self.dev_pref + ':CLEAN_SPAN') lb_svspan = PyDMLabel(self, self.dev_pref + ':CLEAN_SAVE_SPAN') ld_bcper = QLabel('Period', self) le_bcper = PyDMLineEdit(self, self.dev_pref + ':CLEAN_PERIOD') lb_svper = PyDMLabel(self, self.dev_pref + ':CLEAN_SAVE_PERIOD') ld_bcpatt = QLabel('Mask', self) le_bcpatt = PyDMLineEdit(self, self.dev_pref + ':CLEAN_PATTERN') lay_clean = QGridLayout(gbox_settings) lay_clean.addWidget(QLabel('SAVED VALS.'), 0, 2) lay_clean.addWidget(ld_bcamp, 1, 0) lay_clean.addWidget(sb_bcamp, 1, 1) lay_clean.addWidget(lb_svamp, 1, 2) lay_clean.addWidget(ld_bctune, 2, 0) lay_clean.addWidget(sb_bctune, 2, 1) lay_clean.addWidget(lb_svfreq, 2, 2) lay_clean.addWidget(ld_bcspan, 3, 0) lay_clean.addWidget(le_bcspan, 3, 1) lay_clean.addWidget(lb_svspan, 3, 2) lay_clean.addWidget(ld_bcper, 4, 0) lay_clean.addWidget(le_bcper, 4, 1) lay_clean.addWidget(lb_svper, 4, 2) lay_clean.addWidget(ld_bcenbl, 5, 0) lay_clean.addWidget(cb_bcenbl, 5, 1) lay = QGridLayout() lay.addWidget(ld_bcpatt, 0, 0) lay.addWidget(le_bcpatt, 0, 1) lay_clean.addLayout(lay, 6, 0, 1, 3) return gbox_settings
def displayControlMPS(self, tab_type): ''' Display the desired tab widget ''' wid = QWidget(self) if_glay = QGridLayout() if tab_type != 0: if_glay.addLayout(self.displayTempGroups(), 0, 0, 1, 1) if_glay.setAlignment(Qt.AlignTop) wid.setLayout(if_glay) if tab_type == 0: self.mps_glay = if_glay self.changeWid(self.mps_glay) return wid
def _setupUi(self): self.label_title = QLabel('SI Current and Lifetime') self.label_title.setStyleSheet(""" font-size:1.2em; font-weight:bold; 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.label_title.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.settings = QWidget() vlay_sett = QVBoxLayout(self.settings) vlay_sett.setContentsMargins(0, 0, 0, 0) vlay_sett.addWidget(self._setupCurrentSettingsWidget()) vlay_sett.addWidget(self._setupLifetimeSettigsWidget()) vlay_sett.addWidget(self._setupGraphSettingsWidget()) self.pb_showsett = QPushButton('<', self) self.pb_showsett.setObjectName('showsett') self.pb_showsett.setToolTip('Hide settings') self.pb_showsett.setStyleSheet( '#showsett{min-width:0.7em;max-width:0.7em;}') self.pb_showsett.released.connect(self._handle_settings_vis) self.pb_showeff = QPushButton('v', self) self.pb_showeff.setObjectName('showeff') self.pb_showeff.setToolTip('Show efficiency graph') self.pb_showeff.setStyleSheet( '#showeff{min-width:0.7em;max-width:0.7em;}') self.pb_showeff.released.connect(self._handle_efficiency_vis) hbox_visi = QHBoxLayout() hbox_visi.addStretch() hbox_visi.addWidget(self.pb_showsett) hbox_visi.addWidget(self.pb_showeff) self.eff_graph = EffMonitor(self, self.prefix, self.device.sec) self.eff_graph.setVisible(False) cw = QWidget() self.setCentralWidget(cw) lay = QGridLayout(cw) lay.addWidget(self.label_title, 0, 0, 1, 2) lay.addLayout(self._setupGraphPanelLayout(), 1, 0) lay.addWidget(self.settings, 1, 1) lay.addLayout(hbox_visi, 2, 0, 1, 2, alignment=Qt.AlignRight) lay.addWidget(self.eff_graph, 3, 0, 1, 2) lay.setColumnStretch(0, 6) lay.setColumnStretch(1, 1)
def _setupUi(self): fbsett_wid = self._setupFeedbackSettings() status_wid = self._setupStatusWidget() lay = QGridLayout(self) lay.setAlignment(Qt.AlignTop | Qt.AlignCenter) if self._is_resumed: led_gensts = SiriusLedAlert(self, self.dev_pref+':ERRSUM') dev_label = QLabel( '<h3>'+self._label+'</h3>', self, alignment=Qt.AlignCenter) self.pb_detail = QPushButton(qta.icon('fa5s.ellipsis-v'), '', self) self.pb_detail.setObjectName('dtls') self.pb_detail.setStyleSheet( '#dtls{min-width:20px;max-width:20px;icon-size:15px;}') cmd = ['sirius-hla-si-di-bbb.py', '-dev', self.dev_pref] if self._prefix: cmd.extend(['-p', self._prefix]) connect_newprocess(self.pb_detail, cmd, self) hbox_label = QHBoxLayout() hbox_label.setContentsMargins(0, 0, 0, 0) hbox_label.addWidget(led_gensts, alignment=Qt.AlignLeft) hbox_label.addWidget(dev_label) hbox_label.addWidget(self.pb_detail, alignment=Qt.AlignRight) hbox_label.setStretch(0, 1) hbox_label.setStretch(1, 10) hbox_label.setStretch(2, 1) wid = QWidget(self) wid.setObjectName('box') wid.setStyleSheet(""" #box{border: 2px solid gray;}""") lay_box = QGridLayout(wid) lay_box.setVerticalSpacing(15) lay_box.addLayout(hbox_label, 0, 0) lay_box.addWidget(fbsett_wid, 1, 0) lay_box.addWidget(status_wid, 2, 0) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(wid) else: info_wid = BbBInfoWidget(self, self._prefix, self._device) lay.addWidget(fbsett_wid, 0, 1) lay.addWidget(status_wid, 0, 2) lay.addWidget(info_wid, 0, 3) lay.setColumnStretch(0, 3) lay.setColumnStretch(4, 3) lay.setRowStretch(1, 3)
def _setupUi(self): self._ld_ilkistop = QLabel('Stop\n(Input)', self) self._led_ilkistop = PyDMLed( self, self.dev_pref.substitute(propty='IntlkInStop-Mon')) self._led_ilkistop.offColor = PyDMLed.LightGreen self._led_ilkistop.onColor = PyDMLed.Red self._lb_ilkistop = PyDMLabel( self, self.dev_pref.substitute(propty='IntlkInStop-Mon')) hbox_ilkistop = QHBoxLayout() hbox_ilkistop.addWidget(self._led_ilkistop) hbox_ilkistop.addWidget(self._lb_ilkistop) self._ld_ilkieopn = QLabel('Emergency Open Gap\n(Input)', self) self._led_ilkieopn = PyDMLed( self, self.dev_pref.substitute(propty='IntlkInEOpnGap-Mon')) self._led_ilkieopn.offColor = PyDMLed.LightGreen self._led_ilkieopn.onColor = PyDMLed.Red self._lb_ilkieopn = PyDMLabel( self, self.dev_pref.substitute(propty='IntlkInEOpnGap-Mon')) hbox_eopngap = QHBoxLayout() hbox_eopngap.addWidget(self._led_ilkieopn) hbox_eopngap.addWidget(self._lb_ilkieopn) self._ld_ilkogapopn = QLabel('Gap Opened\n(Output)', self) self._lb_ilkogapopn = PyDMLabel( self, self.dev_pref.substitute(propty='IntlkOutGapStt-Mon')) self._lb_ilkogapopn.setAlignment(Qt.AlignCenter) self._ld_ilkopwr = QLabel('Power Enabled\n(Output)', self) self._led_ilkopwr = PyDMLed( self, self.dev_pref.substitute(propty='IntlkOutPwrEnbld-Mon')) self._led_ilkopwr.offColor = PyDMLed.Red self._led_ilkopwr.onColor = PyDMLed.LightGreen lay = QGridLayout(self) lay.addWidget( QLabel('<h4>Interlock status</h4>', self, alignment=Qt.AlignCenter), 0, 0, 1, 2) lay.addWidget(self._ld_ilkistop, 1, 0) lay.addLayout(hbox_ilkistop, 1, 1) lay.addWidget(self._ld_ilkieopn, 2, 0) lay.addLayout(hbox_eopngap, 2, 1) lay.addWidget(self._ld_ilkogapopn, 3, 0) lay.addWidget(self._lb_ilkogapopn, 3, 1) lay.addWidget(self._ld_ilkopwr, 4, 0) lay.addWidget(self._led_ilkopwr, 4, 1)
def _setupUi(self): self._label_dev = QLabel('Power supply: ', self) self._label_dev.setStyleSheet( 'min-width: 8em; max-width: 8em;') self.cb_sec = QComboBox(self) for item in self._choose_sec: self.cb_sec.addItem(item) self.cb_sec.setCurrentText('SI') self.cb_sec.currentTextChanged.connect( self._handle_cb_visibility) self.cb_sec.currentTextChanged.connect( self._set_psnames) self.cb_sub = QComboBox(self) self.cb_sub.setEditable(True) self.cb_sub.setMaxVisibleItems(10) for item in self._choose_sub: self.cb_sub.addItem(item) self.cb_sub.currentTextChanged.connect( self._set_psnames) glay_choose = QGridLayout() glay_choose.addWidget(self.cb_sub, 0, 0) self.cb_dev = dict() for sec in self._choose_sec: visible = sec == 'SI' self.cb_dev[sec] = QComboBox(self) self.cb_dev[sec].setMaxVisibleItems(10) self.cb_dev[sec].setVisible(visible) for item in self._choose_dev[sec]: self.cb_dev[sec].addItem(item) self.cb_dev[sec].currentTextChanged.connect( self._set_psnames) glay_choose.addWidget(self.cb_dev[sec], 0, 1) lay = QGridLayout(self) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self._label_dev, 0, 0) lay.addWidget(self.cb_sec, 0, 1) lay.addLayout(glay_choose, 0, 2)
def _setupUi(self): self._label_prop = QLabel('Properties: ', self) self._label_prop.setStyleSheet( 'min-width: 8em; max-width: 8em;') self._label_symb = QLabel() icon = qta.icon('mdi.record-circle-outline') pixmap = icon.pixmap(icon.actualSize(QSize(20, 20))) self._label_symb.setPixmap(pixmap) self._label_symb.setSizePolicy(QSzPlcy.Fixed, QSzPlcy.Fixed) self.cb_prop_symb = QComboBox(self) self.cb_prop_symb.currentTextChanged.connect( self.propty_symb_changed.emit) self.cb_prop_symb.setSizePolicy( QSzPlcy.Expanding, QSzPlcy.Preferred) self.cb_prop_symb.setMaxVisibleItems(10) self.cb_prop_symb.addItems(self._choose_prop_symb) hbox_prop_symb = QHBoxLayout() hbox_prop_symb.addWidget(self._label_symb) hbox_prop_symb.addWidget(self.cb_prop_symb) self._label_line = QLabel() icon = qta.icon('mdi.pulse') pixmap = icon.pixmap(icon.actualSize(QSize(20, 20))) self._label_line.setPixmap(pixmap) self._label_line.setSizePolicy(QSzPlcy.Fixed, QSzPlcy.Fixed) self.cb_prop_line = QComboBox(self) self.cb_prop_line.currentTextChanged.connect( self.propty_line_changed.emit) self.cb_prop_line.setSizePolicy( QSzPlcy.Expanding, QSzPlcy.Preferred) self.cb_prop_line.setMaxVisibleItems(10) self.cb_prop_line.addItems(self._choose_prop_line) hbox_prop_line = QHBoxLayout() hbox_prop_line.addWidget(self._label_line) hbox_prop_line.addWidget(self.cb_prop_line) lay = QGridLayout(self) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self._label_prop, 0, 0) lay.addLayout(hbox_prop_symb, 0, 1) lay.addLayout(hbox_prop_line, 0, 2)
def _setupUi(self): self.gbox_reliablemeas = self._setupReliableMeasWidget() self.gbox_generalsettings = self._setupGeneralSettingsWidget() self.gbox_trigger = self._setupTriggerWidget() self.gbox_config = self._setupConfigurationWidget() self.gbox_normalmode = self._setupMeasSettingsWidget('Normal') self.gbox_fastmode = self._setupMeasSettingsWidget('Fast') lay_mode = QGridLayout() lay_mode.addWidget(self.gbox_normalmode, 0, 0) lay_mode.addWidget(self.gbox_fastmode, 0, 0) self.mode_channel = SiriusConnectionSignal( self.dcct_prefix.substitute(propty='MeasMode-Sel')) self.mode_channel.new_value_signal.connect(self._showMeasModeSettings) lay = QGridLayout() lay.addWidget( QLabel('<h3>' + self.device + ' Settings Details</h3>', self, alignment=Qt.AlignCenter), 0, 0, 1, 2) lay.addWidget(self.gbox_reliablemeas, 1, 0) lay.addWidget(self.gbox_generalsettings, 2, 0) lay.addWidget(self.gbox_config, 3, 0) lay.addWidget(self.gbox_trigger, 3, 1) lay.addLayout(lay_mode, 1, 1, 2, 1) lay.setVerticalSpacing(15) lay.setHorizontalSpacing(15) lay.setRowStretch(0, 1) lay.setRowStretch(1, 3) lay.setRowStretch(2, 7) lay.setRowStretch(3, 2) self.setLayout(lay) self.setStyleSheet(""" PyDMSpinbox, PyDMLabel{ min-width:6em; max-width:6em; qproperty-alignment: AlignCenter;} PyDMLedMultiChannel, PyDMStateButton, PyDMEnumComboBox{ min-width:6em; max-width:6em;}""")
def displayTempGroup(self, pv_data, title): ''' Display one temperature group''' dtg_glay = QGridLayout() dtg_glay.setHorizontalSpacing(0) group = QGroupBox() count = [1, 1] dtg_glay = self.getSingleTitle(title, dtg_glay) for counter_prefix in range(1, pv_data[0][0] + 1): for counter_name in range(1, pv_data[0][1] + 1): pv_name = self.genStringTempPV(pv_data[1], counter_prefix, counter_name) dtg_glay.addLayout(self.tempMonBox(pv_name), count[0], count[1], 1, 1) count = self.updateCount(count, title) group.setTitle(title) group.setLayout(dtg_glay) return group
def _setupUi(self): '''Build the graphic interface''' wid = QWidget(self) if_glay = QGridLayout() if_glay.addLayout(self.display_header(), 0, 0, 1, 3) if_glay.addLayout(self.display_graph(), 1, 0, 2, 1) if_glay.addLayout(self.display_mainData(), 1, 1, 1, 1) if_glay.addLayout(self.display_selectors(), 1, 2, 1, 1) if_glay.setAlignment(Qt.AlignTop) if_glay.setColumnStretch(0, 10) wid.setLayout(if_glay) self.setCentralWidget(wid)
def _setupUi(self): self._ld_bbb = QLabel('<h3>BbB Control Window</h3>', self, alignment=Qt.AlignCenter) self._but_fbe = QPushButton('FBE', self) window = create_window_from_widget(BbBGPIOWidget, title='Front-Back End', icon=get_bbb_icon()) connect_window(self._but_fbe, window, self, prefix=self.prefix, device='SI-Glob:DI-BbBProc-L') hlay = QHBoxLayout() hlay.addWidget(self._but_fbe) hlay.addStretch() hlay.addWidget(self._ld_bbb) hlay.addStretch() idcs_types = ['H', 'V', 'L'] cwt = QWidget(self) self.setCentralWidget(cwt) lay = QGridLayout(cwt) for col, idc in enumerate(idcs_types): dev_pref = 'SI-Glob:DI-BbBProc-' + idc wid = BbBMainSettingsWidget(self, self.prefix, dev_pref) set_bbb_color(wid, dev_pref) lay.addWidget(wid, 1, col) self._bbb_widgets.append(wid) lay.addLayout(hlay, 0, 0, 1, len(idcs_types)) lay.setRowStretch(0, 1) lay.setRowStretch(1, 6)
def __init__(self, parent): super().__init__(parent) self.setWindowTitle("Interpolate bad channels") vbox = QVBoxLayout(self) grid = QGridLayout() grid.addWidget(QLabel("Reset bads:"), 0, 0) self.reset_bads_checkbox = QCheckBox() self.reset_bads_checkbox.setChecked(True) grid.addWidget(self.reset_bads_checkbox, 0, 1) grid.addWidget(QLabel("Mode:"), 1, 0) self.mode_select = QComboBox() self.modes = {"Accurate": "accurate", "Fast": "fast"} self.mode_select.addItems(self.modes.keys()) self.mode_select.setCurrentText("Accurate") grid.addWidget(self.mode_select, 1, 1) grid.addWidget(QLabel("Origin (x, y, z):"), 2, 0) hbox = QHBoxLayout() self.x = QDoubleSpinBox() self.x.setValue(0) self.x.setDecimals(3) hbox.addWidget(self.x) self.y = QDoubleSpinBox() self.y.setValue(0) self.y.setDecimals(3) hbox.addWidget(self.y) self.z = QDoubleSpinBox() self.z.setValue(0.04) self.z.setDecimals(3) hbox.addWidget(self.z) grid.addLayout(hbox, 2, 1) vbox.addLayout(grid) buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) vbox.addWidget(buttonbox) buttonbox.accepted.connect(self.accept) buttonbox.rejected.connect(self.reject) vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)
def _setupUi(self): ld_gpio = QLabel('<h3>GPIO Settings</h3>', self, alignment=Qt.AlignCenter) vlay1 = QVBoxLayout() vlay1.addWidget(self._setupFrontBackEndRegsWidget()) vlay1.addWidget(self._setupOtherControlsWidget()) vlay2 = QVBoxLayout() vlay2.addWidget(self._setupPhaseServoLoopWidget()) vlay2.addWidget(self._setupThermoWidget()) lay = QGridLayout(self) lay.addWidget(ld_gpio, 0, 1, 1, 2) lay.addLayout(vlay1, 1, 1) lay.addLayout(vlay2, 1, 2) lay.addWidget(self._setupMonitorsWidget(), 2, 1, 1, 2) lay.setColumnStretch(0, 3) lay.setColumnStretch(3, 3) lay.setRowStretch(3, 3) self.setStyleSheet("""PyDMLabel{qproperty-alignment: AlignCenter;}""")
def get_singular_values_widget(self, parent): """.""" svs_wid = QWidget(parent) svs_lay = QGridLayout(svs_wid) wid = self.create_pair(svs_wid, 'MinSingValue') lbl = QLabel('Min. SV: ') svs_lay.addWidget(lbl, 0, 0) svs_lay.addWidget(wid, 0, 1) wid = self.create_pair(svs_wid, 'TikhonovRegConst') lbl = QLabel('Tikhonov: ') svs_lay.addWidget(lbl, 1, 0) svs_lay.addWidget(wid, 1, 1) lbl = QLabel('Nr Sing Vals') lbls = SiriusLabel( svs_wid, self.devpref.substitute(propty='NrSingValues-Mon')) btn = QPushButton('', svs_wid) btn.setToolTip('Check Singular Values') btn.setIcon(qta.icon('mdi.chart-line')) btn.setObjectName('btn') btn.setStyleSheet('#btn{max-width:30px; icon-size:30px;}') hbl = QHBoxLayout() hbl.addWidget(btn) hbl.addStretch() hbl.addWidget(lbl) hbl.addWidget(lbls) svs_lay.addLayout(hbl, 2, 0, 1, 2) Window = create_window_from_widget( SingularValues, title='Check Singular Values') connect_window( btn, Window, svs_wid, device=self.device, prefix=self.prefix) return svs_wid
class Form(QWidget): def __init__(self, parent=None): super(Form, self).__init__(parent) self.layout = QVBoxLayout() self.layout.setContentsMargins(5, 5, 5, 5) h_layout = QHBoxLayout() self.list = QListWidget() self.list.resize(20, 50) h_layout.addWidget(self.list) manager = ResourceManager() self.data = manager.run(100) self.grid = QGridLayout(self) self.grid.addLayout(self.layout, 0, 0, 4, 4) self.grid.addLayout(h_layout, 0, 2, 1, 1) for key, value in self.data.items(): self.list.addItem(key) self.setLayout(self.grid) self.list.currentTextChanged.connect(self.rewrite_data) def rewrite_data(self, args): self.layout = QVBoxLayout() self.grid.addLayout(self.layout, 0, 0, 1, 1) for key, value in self.data[args].items(): chart = QChart() chart_view = QChartView(chart) series = QLineSeries() series.setName(key) for i in value: series.append(QPointF(i[0], i[1])) chart.addSeries(series) chart.createDefaultAxes() self.layout.addWidget(chart_view) def start(self): self.message('Настройти до конца') def message(self, message): error = QErrorMessage(self) error.showMessage(message)
def displayGroup(self, pv_data, title, group_type): ''' Display one MPS group ''' dg_glay = QGridLayout() group = QGroupBox() count = [1, 1] dg_glay = self.getSingleTitle(title, dg_glay) index = 0 for pv_name in pv_data.get('name'): if title != 'Gate Valve': if group_type == 0: dg_glay.addLayout( self.dispayHiddenControls( pv_name, self.getPVControl(pv_data.get('control'), index), self.getPVConfig(pv_data.get('config'), index)), count[0], count[1], 1, 1) else: dg_glay.addLayout( self.dispayAllControls( pv_name, self.getPVControl(pv_data.get('control'), index), self.getPVConfig(pv_data.get('config'), index)), count[0], count[1], 1, 1) else: dg_glay.addLayout( self.gateValve( pv_name, self.getPVConfig(pv_data.get('config'), index)), count[0], count[1], 1, 1) count = self.updateCount(count, title) index += 1 group.setTitle(title) group.setLayout(dg_glay) return group
def __init__(self, parent, enable_replace=False): QWidget.__init__(self, parent) self.enable_replace = enable_replace self.editor = None self.is_code_editor = None glayout = QGridLayout() glayout.setContentsMargins(0, 0, 0, 0) self.setLayout(glayout) self.close_button = create_toolbutton( self, triggered=self.hide, icon=ima.icon('DialogCloseButton')) glayout.addWidget(self.close_button, 0, 0) # Find layout self.search_text = PatternComboBox(self, tip=_("Search string"), adjust_to_minimum=False) self.return_shift_pressed.connect( lambda: self.find(changed=False, forward=False, rehighlight=False, multiline_replace_check=False)) self.return_pressed.connect( lambda: self.find(changed=False, forward=True, rehighlight=False, multiline_replace_check=False)) self.search_text.lineEdit().textEdited.connect( self.text_has_been_edited) self.number_matches_text = QLabel(self) self.previous_button = create_toolbutton(self, triggered=self.find_previous, icon=ima.icon('ArrowUp'), tip=_("Find previous")) self.next_button = create_toolbutton(self, triggered=self.find_next, icon=ima.icon('ArrowDown'), tip=_("Find next")) self.next_button.clicked.connect(self.update_search_combo) self.previous_button.clicked.connect(self.update_search_combo) self.re_button = create_toolbutton(self, icon=ima.icon('regex'), tip=_("Regular expression")) self.re_button.setCheckable(True) self.re_button.toggled.connect(lambda state: self.find()) self.case_button = create_toolbutton( self, icon=ima.icon("format_letter_case"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.toggled.connect(lambda state: self.find()) self.words_button = create_toolbutton(self, icon=get_icon("whole_words.png"), tip=_("Whole words")) self.words_button.setCheckable(True) self.words_button.toggled.connect(lambda state: self.find()) self.highlight_button = create_toolbutton( self, icon=get_icon("highlight.png"), tip=_("Highlight matches")) self.highlight_button.setCheckable(True) self.highlight_button.toggled.connect(self.toggle_highlighting) hlayout = QHBoxLayout() self.widgets = [ self.close_button, self.search_text, self.number_matches_text, self.previous_button, self.next_button, self.re_button, self.case_button, self.words_button, self.highlight_button ] for widget in self.widgets[1:]: hlayout.addWidget(widget) glayout.addLayout(hlayout, 0, 1) # Replace layout replace_with = QLabel(_("Replace with:")) self.replace_text = PatternComboBox(self, adjust_to_minimum=False, tip=_('Replace string')) self.replace_text.valid.connect( lambda _: self.replace_find(focus_replace_text=True)) self.replace_button = create_toolbutton( self, text=_('Replace/find next'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find, text_beside_icon=True) self.replace_sel_button = create_toolbutton( self, text=_('Replace in selection'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find_selection, text_beside_icon=True) self.replace_sel_button.clicked.connect(self.update_replace_combo) self.replace_sel_button.clicked.connect(self.update_search_combo) self.replace_all_button = create_toolbutton( self, text=_('Replace all'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find_all, text_beside_icon=True) self.replace_all_button.clicked.connect(self.update_replace_combo) self.replace_all_button.clicked.connect(self.update_search_combo) self.replace_layout = QHBoxLayout() widgets = [ replace_with, self.replace_text, self.replace_button, self.replace_sel_button, self.replace_all_button ] for widget in widgets: self.replace_layout.addWidget(widget) glayout.addLayout(self.replace_layout, 1, 1) self.widgets.extend(widgets) self.replace_widgets = widgets self.hide_replace() self.search_text.setTabOrder(self.search_text, self.replace_text) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.shortcuts = self.create_shortcuts(parent) self.highlight_timer = QTimer(self) self.highlight_timer.setSingleShot(True) self.highlight_timer.setInterval(1000) self.highlight_timer.timeout.connect(self.highlight_matches) self.search_text.installEventFilter(self)
class DataFrameEditor(QDialog): """ Dialog for displaying and editing DataFrame and related objects. Signals ------- sig_option_changed(str, object): Raised if an option is changed. Arguments are name of option and its new value. """ sig_option_changed = Signal(str, object) def __init__(self, parent=None): QDialog.__init__(self, parent) # Destroying the C++ object right after closing the dialog box, # otherwise it may be garbage-collected in another QThread # (e.g. the editor's analysis thread in Spyder), thus leading to # a segmentation fault on UNIX or an application crash on Windows self.setAttribute(Qt.WA_DeleteOnClose) self.is_series = False self.layout = None def setup_and_check(self, data, title=''): """ Setup DataFrameEditor: return False if data is not supported, True otherwise. Supported types for data are DataFrame, Series and Index. """ self.layout = QGridLayout() self.setLayout(self.layout) self.setWindowIcon(ima.icon('arredit')) if title: title = to_text_string(title) + " - %s" % data.__class__.__name__ else: title = _("%s editor") % data.__class__.__name__ if isinstance(data, Series): self.is_series = True data = data.to_frame() elif isinstance(data, Index): data = DataFrame(data) self.setWindowTitle(title) self.resize(600, 500) self.dataModel = DataFrameModel(data, parent=self) self.dataTable = DataFrameView(self, self.dataModel) self.layout.addWidget(self.dataTable) self.setLayout(self.layout) self.setMinimumSize(400, 300) # Make the dialog act as a window self.setWindowFlags(Qt.Window) btn_layout = QHBoxLayout() btn = QPushButton(_("Format")) # disable format button for int type btn_layout.addWidget(btn) btn.clicked.connect(self.change_format) btn = QPushButton(_('Resize')) btn_layout.addWidget(btn) btn.clicked.connect(self.resize_to_contents) bgcolor = QCheckBox(_('Background color')) bgcolor.setChecked(self.dataModel.bgcolor_enabled) bgcolor.setEnabled(self.dataModel.bgcolor_enabled) bgcolor.stateChanged.connect(self.change_bgcolor_enable) btn_layout.addWidget(bgcolor) self.bgcolor_global = QCheckBox(_('Column min/max')) self.bgcolor_global.setChecked(self.dataModel.colum_avg_enabled) self.bgcolor_global.setEnabled(not self.is_series and self.dataModel.bgcolor_enabled) self.bgcolor_global.stateChanged.connect(self.dataModel.colum_avg) btn_layout.addWidget(self.bgcolor_global) btn_layout.addStretch() bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) btn_layout.addWidget(bbox) self.layout.addLayout(btn_layout, 2, 0) return True def change_bgcolor_enable(self, state): """ This is implementet so column min/max is only active when bgcolor is """ self.dataModel.bgcolor(state) self.bgcolor_global.setEnabled(not self.is_series and state > 0) def change_format(self): """ Ask user for display format for floats and use it. This function also checks whether the format is valid and emits `sig_option_changed`. """ format, valid = QInputDialog.getText(self, _('Format'), _("Float formatting"), QLineEdit.Normal, self.dataModel.get_format()) if valid: format = str(format) try: format % 1.1 except: msg = _("Format ({}) is incorrect").format(format) QMessageBox.critical(self, _("Error"), msg) return if not format.startswith('%'): msg = _("Format ({}) should start with '%'").format(format) QMessageBox.critical(self, _("Error"), msg) return self.dataModel.set_format(format) self.sig_option_changed.emit('dataframe_format', format) def get_value(self): """Return modified Dataframe -- this is *not* a copy""" # It is import to avoid accessing Qt C++ object as it has probably # already been destroyed, due to the Qt.WA_DeleteOnClose attribute df = self.dataModel.get_data() if self.is_series: return df.iloc[:, 0] else: return df def resize_to_contents(self): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.dataTable.resizeColumnsToContents() self.dataModel.fetch_more(columns=True) self.dataTable.resizeColumnsToContents() QApplication.restoreOverrideCursor()
def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel(_( "<p>Please select the JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel, and enter " "the SSH information if connecting to a remote machine. " "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) self.pn.setText('22') un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 2, 1, 3) # SSH authentication layout auth_layout = QGridLayout() auth_layout.addWidget(self.pw_radio, 1, 0) auth_layout.addWidget(pw_label, 1, 1) auth_layout.addWidget(self.pw, 1, 2) auth_layout.addWidget(self.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_group.setLayout(auth_layout) # Remote kernel layout rm_layout = QVBoxLayout() rm_layout.addLayout(ssh_layout) rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) rm_layout.addWidget(auth_group) self.rm_group.setLayout(rm_layout) self.rm_group.setCheckable(True) self.rm_group.setChecked(False) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addWidget(self.accept_btns)
class PyChopGui(QMainWindow): """ GUI Class using PyQT for PyChop to help users plan inelastic neutron experiments at spallation sources by calculating the resolution and flux at a given neutron energies. """ instruments = {} choppers = {} minE = {} maxE = {} def __init__(self): super(PyChopGui, self).__init__() self.folder = os.path.dirname(sys.modules[self.__module__].__file__) for fname in os.listdir(self.folder): if fname.endswith('.yaml'): instobj = Instrument(os.path.join(self.folder, fname)) self.instruments[instobj.name] = instobj self.choppers[instobj.name] = instobj.getChopperNames() self.minE[instobj.name] = max([instobj.emin, 0.01]) self.maxE[instobj.name] = instobj.emax self.drawLayout() self.setInstrument(list(self.instruments.keys())[0]) self.resaxes_xlim = 0 self.qeaxes_xlim = 0 self.isFramePlotted = 0 def setInstrument(self, instname): """ Defines the instrument parameters by the name of the instrument. """ self.engine = self.instruments[str(instname)] self.tabs.setTabEnabled(self.tdtabID, False) self.widgets['ChopperCombo']['Combo'].clear() self.widgets['FrequencyCombo']['Combo'].clear() self.widgets['FrequencyCombo']['Label'].setText('Frequency') self.widgets['PulseRemoverCombo']['Combo'].clear() for item in self.choppers[str(instname)]: self.widgets['ChopperCombo']['Combo'].addItem(item) rep = self.engine.moderator.source_rep maxfreq = self.engine.chopper_system.max_frequencies # At the moment, the GUI only supports up to two independent frequencies if not hasattr(maxfreq, '__len__') or len(maxfreq) == 1: self.widgets['PulseRemoverCombo']['Combo'].hide() self.widgets['PulseRemoverCombo']['Label'].hide() for fq in range(rep, (maxfreq[0] if hasattr(maxfreq, '__len__') else maxfreq) + 1, rep): self.widgets['FrequencyCombo']['Combo'].addItem(str(fq)) if hasattr(self.engine.chopper_system, 'frequency_names'): self.widgets['FrequencyCombo']['Label'].setText(self.engine.chopper_system.frequency_names[0]) else: self.widgets['PulseRemoverCombo']['Combo'].show() self.widgets['PulseRemoverCombo']['Label'].show() if hasattr(self.engine.chopper_system, 'frequency_names'): for idx, chp in enumerate([self.widgets['FrequencyCombo']['Label'], self.widgets['PulseRemoverCombo']['Label']]): chp.setText(self.engine.chopper_system.frequency_names[idx]) for fq in range(rep, maxfreq[0] + 1, rep): self.widgets['FrequencyCombo']['Combo'].addItem(str(fq)) for fq in range(rep, maxfreq[1] + 1, rep): self.widgets['PulseRemoverCombo']['Combo'].addItem(str(fq)) if len(self.engine.chopper_system.choppers) > 1: self.widgets['MultiRepCheck'].setEnabled(True) self.tabs.setTabEnabled(self.tdtabID, True) else: self.widgets['MultiRepCheck'].setEnabled(False) self.widgets['MultiRepCheck'].setChecked(False) self.widgets['Chopper2Phase']['Edit'].hide() self.widgets['Chopper2Phase']['Label'].hide() if self.engine.chopper_system.isPhaseIndependent: self.widgets['Chopper2Phase']['Edit'].show() self.widgets['Chopper2Phase']['Label'].show() self.widgets['Chopper2Phase']['Edit'].setText(str(self.engine.chopper_system.defaultPhase[0])) self.widgets['Chopper2Phase']['Label'].setText(self.engine.chopper_system.phaseNames[0]) # Special case for MERLIN - hide phase control from normal users if 'MERLIN' in str(instname) and not self.instSciAct.isChecked(): self.widgets['Chopper2Phase']['Edit'].hide() self.widgets['Chopper2Phase']['Label'].hide() self.engine.setChopper(str(self.widgets['ChopperCombo']['Combo'].currentText())) self.engine.setFrequency(float(self.widgets['FrequencyCombo']['Combo'].currentText())) val = self.flxslder.val * self.maxE[self.engine.instname] / 100 self.flxedt.setText('%3.2f' % (val)) nframe = self.engine.moderator.n_frame if hasattr(self.engine.moderator, 'n_frame') else 1 self.repfig_nframe_edit.setText(str(nframe)) self.repfig_nframe_rep1only.setChecked(False) if hasattr(self.engine.chopper_system, 'default_frequencies'): cb = [self.widgets['FrequencyCombo']['Combo'], self.widgets['PulseRemoverCombo']['Combo']] for idx, freq in enumerate(self.engine.chopper_system.default_frequencies): cb[idx].setCurrentIndex([i for i in range(cb[idx].count()) if str(freq) in cb[idx].itemText(i)][0]) if idx > 1: break self.tabs.setTabEnabled(self.qetabID, False) if self.engine.has_detector and hasattr(self.engine.detector, 'tthlims'): self.tabs.setTabEnabled(self.qetabID, True) def setChopper(self, choppername): """ Defines the Fermi chopper slit package type by name, or the disk chopper arrangement variant. """ self.engine.setChopper(str(choppername)) self.engine.setFrequency(float(self.widgets['FrequencyCombo']['Combo'].currentText())) # Special case for MERLIN - only enable multirep for 'G' chopper if 'MERLIN' in self.engine.instname: if 'G' in str(choppername): self.widgets['MultiRepCheck'].setEnabled(True) self.tabs.setTabEnabled(self.tdtabID, True) self.widgets['Chopper2Phase']['Edit'].setText('1500') self.widgets['Chopper2Phase']['Label'].setText('Disk chopper phase delay time') if self.instSciAct.isChecked(): self.widgets['Chopper2Phase']['Edit'].show() self.widgets['Chopper2Phase']['Label'].show() else: self.widgets['MultiRepCheck'].setEnabled(False) self.widgets['MultiRepCheck'].setChecked(False) self.tabs.setTabEnabled(self.tdtabID, False) self.widgets['Chopper2Phase']['Edit'].hide() self.widgets['Chopper2Phase']['Label'].hide() def setFreq(self, freqtext=None, **kwargs): """ Sets the chopper frequency(ies), in Hz. """ freq_gui = float(self.widgets['FrequencyCombo']['Combo'].currentText()) freq_in = kwargs['manual_freq'] if ('manual_freq' in kwargs.keys()) else freq_gui if len(self.engine.getFrequency()) > 1 and (not hasattr(freq_in, '__len__') or len(freq_in)==1): freqpr = float(self.widgets['PulseRemoverCombo']['Combo'].currentText()) freq_in = [freq_in, freqpr] if not self.widgets['Chopper2Phase']['Label'].isHidden(): chop2phase = self.widgets['Chopper2Phase']['Edit'].text() if isinstance(self.engine.chopper_system.defaultPhase[0], string_types): chop2phase = str(chop2phase) else: chop2phase = float(chop2phase) % (1e6 / self.engine.moderator.source_rep) self.engine.setFrequency(freq_in, phase=chop2phase) else: self.engine.setFrequency(freq_in) def setEi(self): """ Sets the incident energy (or focused incident energy for multi-rep case). """ try: eitxt = float(self.widgets['EiEdit']['Edit'].text()) self.engine.setEi(eitxt) if self.eiPlots.isChecked(): self.calc_callback() except ValueError: raise ValueError('No Ei specified, or Ei string not understood') def calc_callback(self): """ Calls routines to calculate the resolution / flux and to update the Matplotlib graphs. """ try: if self.engine.getChopper() is None: self.setChopper(self.widgets['ChopperCombo']['Combo'].currentText()) self.setEi() self.setFreq() self.calculate() if self.errormess: idx = [i for i, ei in enumerate(self.eis) if np.abs(ei - self.engine.getEi()) < 1.e-4] if idx and self.flux[idx[0]] == 0: raise ValueError(self.errormess) self.errormessage(self.errormess) self.plot_res() self.plot_frame() if self.instSciAct.isChecked(): self.update_script() except ValueError as err: self.errormessage(err) self.plot_flux_ei() self.plot_flux_hz() def calculate(self): """ Performs the resolution and flux calculations. """ self.errormess = None if self.engine.getEi() is None: self.setEi() if self.widgets['MultiRepCheck'].isChecked(): en = np.linspace(0, 0.95, 200) self.eis = self.engine.getAllowedEi() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always', UserWarning) self.res = self.engine.getMultiRepResolution(en) self.flux = self.engine.getMultiRepFlux() if len(w) > 0: mess = [str(w[i].message) for i in range(len(w))] self.errormess = '\n'.join([m for m in mess if 'tchop' in m]) else: en = np.linspace(0, 0.95*self.engine.getEi(), 200) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always', UserWarning) self.res = self.engine.getResolution(en) self.flux = self.engine.getFlux() if len(w) > 0: raise ValueError(w[0].message) def _set_overplot(self, overplot, axisname): axis = getattr(self, axisname) if overplot: if matplotlib.compare_versions('2.1.0',matplotlib.__version__): axis.hold(True) else: setattr(self, axisname+'_xlim', 0) axis.clear() axis.axhline(color='k') def plot_res(self): """ Plots the resolution in the resolution tab """ overplot = self.widgets['HoldCheck'].isChecked() multiplot = self.widgets['MultiRepCheck'].isChecked() self._set_overplot(overplot, 'resaxes') self._set_overplot(overplot, 'qeaxes') inst = self.engine.instname freq = self.engine.getFrequency() if hasattr(freq, '__len__'): freq = freq[0] if multiplot: if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.resaxes.hold(True) for ie, Ei in enumerate(self.eis): en = np.linspace(0, 0.95*Ei, 200) if any(self.res[ie]): if not self.flux[ie]: continue line, = self.resaxes.plot(en, self.res[ie]) label_text = '%s_%3.2fmeV_%dHz_Flux=%fn/cm2/s' % (inst, Ei, freq, self.flux[ie]) line.set_label(label_text) if self.tabs.isTabEnabled(self.qetabID): self.plot_qe(Ei, label_text, hold=True) self.resaxes_xlim = max(Ei, self.resaxes_xlim) if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.resaxes.hold(False) else: ei = self.engine.getEi() en = np.linspace(0, 0.95*ei, 200) line, = self.resaxes.plot(en, self.res) chopper = self.engine.getChopper() label_text = '%s_%s_%3.2fmeV_%dHz_Flux=%fn/cm2/s' % (inst, chopper, ei, freq, self.flux) line.set_label(label_text) if self.tabs.isTabEnabled(self.qetabID): self.plot_qe(ei, label_text, overplot) self.resaxes_xlim = max(ei, self.resaxes_xlim) self.resaxes.set_xlim([0, self.resaxes_xlim]) self.resaxes.legend().draggable() self.resaxes.set_xlabel('Energy Transfer (meV)') self.resaxes.set_ylabel(r'$\Delta$E (meV FWHM)') self.rescanvas.draw() def plot_qe(self, Ei, label_text, hold=False): """ Plots the Q-E diagram """ from scipy import constants E2q, meV2J = (2. * constants.m_n / (constants.hbar ** 2), constants.e / 1000.) en = np.linspace(-Ei / 5., Ei, 100) q2 = [] for tth in self.engine.detector.tthlims: q = np.sqrt(E2q * (2 * Ei - en - 2 * np.sqrt(Ei * (Ei - en)) * np.cos(np.deg2rad(tth))) * meV2J) / 1e10 q2.append(np.concatenate((np.flipud(q), q))) self._set_overplot(hold, 'qeaxes') self.qeaxes_xlim = max(np.max(q2), self.qeaxes_xlim) line, = self.qeaxes.plot(np.hstack(q2), np.concatenate((np.flipud(en), en)).tolist() * len(self.engine.detector.tthlims)) line.set_label(label_text) self.qeaxes.set_xlim([0, self.qeaxes_xlim]) self.qeaxes.legend().draggable() self.qeaxes.set_xlabel(r'$|Q| (\mathrm{\AA}^{-1})$') self.qeaxes.set_ylabel('Energy Transfer (meV)') self.qecanvas.draw() def plot_flux_ei(self, **kwargs): """ Plots the flux vs Ei in the middle tab """ inst = self.engine.instname chop = self.engine.getChopper() freq = self.engine.getFrequency() overplot = self.widgets['HoldCheck'].isChecked() if hasattr(freq, '__len__'): freq = freq[0] update = kwargs['update'] if 'update' in kwargs.keys() else False # Do not recalculate if all relevant parameters still the same. _, labels = self.flxaxes2.get_legend_handles_labels() searchStr = '([A-Z]+) "(.+)" ([0-9]+) Hz' tmpinst = [] if (labels and (overplot or len(labels) == 1)) or update: for prevtitle in labels: prevInst, prevChop, prevFreq = re.search(searchStr, prevtitle).groups() if update: tmpinst.append(copy.deepcopy(Instrument(self.instruments[prevInst], prevChop, float(prevFreq)))) else: if inst == prevInst and chop == prevChop and freq == float(prevFreq): return ne = 25 mn = self.minE[inst] mx = (self.flxslder.val/100)*self.maxE[inst] eis = np.linspace(mn, mx, ne) flux = eis*0 elres = eis*0 if update: self.flxaxes1.clear() self.flxaxes2.clear() if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.flxaxes1.hold(True) self.flxaxes2.hold(True) for ii, instrument in enumerate(tmpinst): for ie, ei in enumerate(eis): with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = instrument.getFlux(ei) elres[ie] = instrument.getResolution(0., ei)[0] self.flxaxes1.plot(eis, flux) line, = self.flxaxes2.plot(eis, elres) line.set_label(labels[ii]) else: for ie, ei in enumerate(eis): with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = self.engine.getFlux(ei) elres[ie] = self.engine.getResolution(0., ei)[0] if overplot: if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.flxaxes1.hold(True) self.flxaxes2.hold(True) else: self.flxaxes1.clear() self.flxaxes2.clear() self.flxaxes1.plot(eis, flux) line, = self.flxaxes2.plot(eis, elres) line.set_label('%s "%s" %d Hz' % (inst, chop, freq)) self.flxaxes1.set_xlim([mn, mx]) self.flxaxes2.set_xlim([mn, mx]) self.flxaxes1.set_xlabel('Incident Energy (meV)') self.flxaxes1.set_ylabel('Flux (n/cm$^2$/s)') self.flxaxes1.set_xlabel('Incident Energy (meV)') self.flxaxes2.set_ylabel('Elastic Resolution FWHM (meV)') lg = self.flxaxes2.legend() lg.draggable() self.flxcanvas.draw() def update_slider(self, val=None): """ Callback function for the x-axis slider of the flux tab """ if val is None: val = float(self.flxedt.text()) / self.maxE[self.engine.instname] * 100 if val < self.minE[self.engine.instname]: self.errormessage("Max Ei must be greater than %2.1f" % (self.minE[self.engine.instname])) val = (self.minE[self.engine.instname]+0.1) / self.maxE[self.engine.instname] * 100 self.flxslder.set_val(val) else: val = self.flxslder.val * self.maxE[self.engine.instname] / 100 self.flxedt.setText('%3.2f' % (val)) self.plot_flux_ei(update=True) self.flxcanvas.draw() def plot_flux_hz(self): """ Plots the flux vs freq in the middle tab """ inst = self.engine.instname chop = self.engine.getChopper() ei = float(self.widgets['EiEdit']['Edit'].text()) overplot = self.widgets['HoldCheck'].isChecked() # Do not recalculate if one of the plots has the same parametersc _, labels = self.frqaxes2.get_legend_handles_labels() searchStr = '([A-Z]+) "(.+)" Ei = ([0-9.-]+) meV' if labels and (overplot or len(labels) == 1): for prevtitle in labels: prevInst, prevChop, prevEi = re.search(searchStr, prevtitle).groups() if inst == prevInst and chop == prevChop and abs(ei-float(prevEi)) < 0.01: return freq0 = self.engine.getFrequency() rep = self.engine.moderator.source_rep maxfreq = self.engine.chopper_system.max_frequencies freqs = range(rep, (maxfreq[0] if hasattr(maxfreq, '__len__') else maxfreq) + 1, rep) flux = np.zeros(len(freqs)) elres = np.zeros(len(freqs)) for ie, freq in enumerate(freqs): if hasattr(freq0, '__len__'): self.setFreq(manual_freq=[freq] + freq0[1:]) else: self.setFreq(manual_freq=freq) with warnings.catch_warnings(record=True): warnings.simplefilter('always', UserWarning) flux[ie] = self.engine.getFlux(ei) elres[ie] = self.engine.getResolution(0., ei)[0] if overplot: if matplotlib.compare_versions('2.1.0',matplotlib.__version__): self.frqaxes1.hold(True) self.frqaxes2.hold(True) else: self.frqaxes1.clear() self.frqaxes2.clear() self.setFreq(manual_freq=freq0) self.frqaxes1.set_xlabel('Chopper Frequency (Hz)') self.frqaxes1.set_ylabel('Flux (n/cm$^2$/s)') line, = self.frqaxes1.plot(freqs, flux, 'o-') self.frqaxes1.set_xlim([0, np.max(freqs)]) self.frqaxes2.set_xlabel('Chopper Frequency (Hz)') self.frqaxes2.set_ylabel('Elastic Resolution FWHM (meV)') line, = self.frqaxes2.plot(freqs, elres, 'o-') line.set_label('%s "%s" Ei = %5.3f meV' % (inst, chop, ei)) lg = self.frqaxes2.legend() lg.draggable() self.frqaxes2.set_xlim([0, np.max(freqs)]) self.frqcanvas.draw() def instSciCB(self): """ Callback function for the "Instrument Scientist Mode" menu option """ # MERLIN is a special case - want to hide ability to change phase from users if 'MERLIN' in self.engine.instname and 'G' in self.engine.getChopper(): if self.instSciAct.isChecked(): self.widgets['Chopper2Phase']['Edit'].show() self.widgets['Chopper2Phase']['Label'].show() self.widgets['Chopper2Phase']['Edit'].setText('1500') self.widgets['Chopper2Phase']['Label'].setText('Disk chopper phase delay time') else: self.widgets['Chopper2Phase']['Edit'].hide() self.widgets['Chopper2Phase']['Label'].hide() if self.instSciAct.isChecked(): self.tabs.insertTab(self.scrtabID, self.scrtab, 'ScriptOutput') self.scrtab.show() else: self.tabs.removeTab(self.scrtabID) self.scrtab.hide() def errormessage(self, message): msg = QMessageBox() msg.setText(str(message)) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def loadYaml(self): yaml_file = QFileDialog().getOpenFileName(self.mainWidget, 'Open Instrument YAML File', self.folder, 'Files (*.yaml)') if isinstance(yaml_file, tuple): yaml_file = yaml_file[0] yaml_file = str(yaml_file) new_folder = os.path.dirname(yaml_file) if new_folder != self.folder: self.folder = new_folder try: new_inst = Instrument(yaml_file) except (RuntimeError, AttributeError, ValueError) as err: self.errormessage(err) newname = new_inst.name if newname in self.instruments.keys() and not self.overwriteload.isChecked(): overwrite, newname = self._ask_overwrite() if overwrite == 1: return elif overwrite == 0: newname = new_inst.name self.instruments[newname] = new_inst self.choppers[newname] = new_inst.getChopperNames() self.minE[newname] = max([new_inst.emin, 0.01]) self.maxE[newname] = new_inst.emax self.updateInstrumentList() combo = self.widgets['InstrumentCombo']['Combo'] idx = [i for i in range(combo.count()) if str(combo.itemText(i)) == newname] combo.setCurrentIndex(idx[0]) self.setInstrument(newname) def _ask_overwrite(self): msg = QDialog() msg.setWindowTitle('Load overwrite') layout = QGridLayout() layout.addWidget(QLabel('Instrument %s already exists in memory. Overwrite this?'), 0, 0, 1, -1) buttons = [QPushButton(label) for label in ['Load and overwrite', 'Cancel Load', 'Load and rename to']] locations = [[1, 0], [1, 1], [2, 0]] self.overwrite_flag = 1 def overwriteCB(idx): self.overwrite_flag = idx msg.accept() for idx, button in enumerate(buttons): button.clicked.connect(lambda _, idx=idx: overwriteCB(idx)) layout.addWidget(button, locations[idx][0], locations[idx][1]) newname = QLineEdit() newname.editingFinished.connect(lambda: overwriteCB(2)) layout.addWidget(newname, 2, 1) msg.setLayout(layout) msg.exec_() newname = str(newname.text()) if not newname or newname in self.instruments: self.errormessage('Invalid instrument name. Cancelling load.') self.overwrite_flag = 1 return self.overwrite_flag, newname def updateInstrumentList(self): combo = self.widgets['InstrumentCombo']['Combo'] old_instruments = [str(combo.itemText(i)) for i in range(combo.count())] new_instruments = [inst for inst in self.instruments if inst not in old_instruments] for inst in new_instruments: combo.addItem(inst) def plot_frame(self): """ Plots the distance-time diagram in the right tab """ if len(self.engine.chopper_system.choppers) > 1: self.engine.n_frame = int(self.repfig_nframe_edit.text()) self.repaxes.clear() self.engine.plotMultiRepFrame(self.repaxes, first_rep=self.repfig_nframe_rep1only.isChecked()) self.repcanvas.draw() def _gen_text_ei(self, ei, obj_in): obj = Instrument(obj_in) obj.setEi(ei) en = np.linspace(0, 0.95*ei, 10) try: flux = self.engine.getFlux() res = self.engine.getResolution(en) except ValueError as err: self.errormessage(err) raise ValueError(err) tsqvan, tsqdic, tsqmodchop = obj.getVanVar() v_mod, v_chop = tuple(np.sqrt(tsqmodchop[:2]) * 1e6) x0, _, x1, x2, _ = obj.chopper_system.getDistances() first_component = 'moderator' if x0 != tsqmodchop[2]: x0 = tsqmodchop[2] first_component = 'chopper 1' txt = '# ------------------------------------------------------------- #\n' txt += '# Ei = %8.2f meV\n' % (ei) txt += '# Flux = %8.2f n/cm2/s\n' % (flux) txt += '# Elastic resolution = %6.2f meV\n' % (res[0]) txt += '# Time width at sample = %6.2f us, of which:\n' % (1e6*np.sqrt(tsqvan)) for ky, val in list(tsqdic.items()): txt += '# %20s : %6.2f us\n' % (ky, 1e6*np.sqrt(val)) txt += '# %s distances:\n' % (obj.instname) txt += '# x0 = %6.2f m (%s to Fermi)\n' % (x0, first_component) txt += '# x1 = %6.2f m (Fermi to sample)\n' % (x1) txt += '# x2 = %6.2f m (sample to detector)\n' % (x2) txt += '# Approximate inelastic resolution is given by:\n' txt += '# dE = 2 * E2V * sqrt(ef**3 * t_van**2) / x2\n' txt += '# where: E2V = 4.373e-4 meV/(m/us) conversion from energy to speed\n' txt += '# t_van**2 = (geom*t_mod)**2 + ((1+geom)*t_chop)**2\n' txt += '# geom = (x1 + x2*(ei/ef)**1.5) / x0\n' txt += '# and t_mod and t_chop are the moderator and chopper time widths at the\n' txt += '# moderator and chopper positions (not at the sample as listed above).\n' txt += '# Which in this case is:\n' txt += '# %.4e*sqrt(ef**3 * ( (%6.5f*(%.3f+%.3f*(ei/ef)**1.5))**2 \n' % (874.78672e-6/x2, v_mod, x1/x0, x2/x0) txt += '# + (%6.5f*(%.3f+%.3f*(ei/ef)**1.5))**2) )\n' % (v_chop, 1+x1/x0, x2/x0) txt += '# EN (meV) Full dE (meV) Approx dE (meV)\n' for ii in range(len(res)): ef = ei-en[ii] approx = (874.78672e-6/x2)*np.sqrt(ef**3 * ((v_mod*((x1/x0)+(x2/x0)*(ei/ef)**1.5))**2 + (v_chop*(1+(x1/x0)+(x2/x0)*(ei/ef)**1.5))**2)) txt += '%12.5f %12.5f %12.5f\n' % (en[ii], res[ii], approx) return txt def genText(self): """ Generates text output of the resolution function versus energy transfer and other information. """ multiplot = self.widgets['MultiRepCheck'].isChecked() obj = self.engine if obj.getChopper() is None: self.setChopper(self.widgets['ChopperCombo']['Combo'].currentText()) if obj.getEi() is None: self.setEi() instname, chtyp, freqs, ei_in = tuple([obj.instname, obj.getChopper(), obj.getFrequency(), obj.getEi()]) txt = '# ------------------------------------------------------------- #\n' txt += '# Chop calculation for instrument %s\n' % (instname) if obj.isFermi: txt += '# with chopper %s at %3i Hz\n' % (chtyp, freqs[0]) else: txt += '# in %s mode with:\n' % (chtyp) freq_names = obj.chopper_system.frequency_names for idx in range(len(freq_names)): txt += '# %s at %3i Hz\n' % (freq_names[idx], freqs[idx]) txt += self._gen_text_ei(ei_in, obj) if multiplot: for ei in sorted(self.engine.getAllowedEi()): if np.abs(ei - ei_in) > 0.001: txt += self._gen_text_ei(ei, obj) return txt def showText(self): """ Creates a dialog to show the generated text output. """ try: generatedText = self.genText() except ValueError: return self.txtwin = QDialog() self.txtedt = QTextEdit() self.txtbtn = QPushButton('OK') self.txtwin.layout = QVBoxLayout(self.txtwin) self.txtwin.layout.addWidget(self.txtedt) self.txtwin.layout.addWidget(self.txtbtn) self.txtbtn.clicked.connect(self.txtwin.deleteLater) self.txtedt.setText(generatedText) self.txtedt.setReadOnly(True) self.txtwin.setWindowTitle('Resolution information') self.txtwin.setWindowModality(Qt.ApplicationModal) self.txtwin.setAttribute(Qt.WA_DeleteOnClose) self.txtwin.setMinimumSize(400, 600) self.txtwin.resize(400, 600) self.txtwin.show() self.txtloop = QEventLoop() self.txtloop.exec_() def saveText(self): """ Saves the generated text to a file (opens file dialog). """ fname = QFileDialog.getSaveFileName(self, 'Open file', '') if isinstance(fname, tuple): fname = fname[0] fid = open(fname, 'w') fid.write(self.genText()) fid.close() def update_script(self): """ Updates the text window with information about the previous calculation. """ if self.widgets['MultiRepCheck'].isChecked(): out = self.engine.getMultiWidths() new_str = '\n' for ie, ee in enumerate(out['Eis']): res = out['Energy'][ie] percent = res / ee * 100 chop_width = out['chopper'][ie] mod_width = out['moderator'][ie] new_str += 'Ei is %6.2f meV, resolution is %6.2f ueV, percentage resolution is %6.3f\n' % (ee, res * 1000, percent) new_str += 'FWHM at sample from chopper and moderator are %6.2f us, %6.2f us\n' % (chop_width, mod_width) else: ei = self.engine.getEi() out = self.engine.getWidths() res = out['Energy'] percent = res / ei * 100 chop_width = out['chopper'] mod_width = out['moderator'] new_str = '\nEi is %6.2f meV, resolution is %6.2f ueV, percentage resolution is %6.3f\n' % (ei, res * 1000, percent) new_str += 'FWHM at sample from chopper and moderator are %6.2f us, %6.2f us\n' % (chop_width, mod_width) self.scredt.append(new_str) def onHelp(self): """ Shows the help page """ try: from pymantidplot.proxies import showCustomInterfaceHelp showCustomInterfaceHelp("PyChop") except ImportError: helpTxt = "PyChop is a tool to allow direct inelastic neutron\nscattering users to estimate the inelastic resolution\n" helpTxt += "and incident flux for a given spectrometer setting.\n\nFirst select the instrument, chopper settings and\n" helpTxt += "Ei, and then click 'Calculate and Plot'. Data for all\nthe graphs will be generated (may take 1-2s) and\n" helpTxt += "all graphs will be updated. If the 'Hold current plot'\ncheck box is ticked, additional settings will be\n" helpTxt += "overplotted on the existing graphs if they are\ndifferent from previous settings.\n\nMore in-depth help " helpTxt += "can be obtained from the\nMantid help pages." self.hlpwin = QDialog() self.hlpedt = QLabel(helpTxt) self.hlpbtn = QPushButton('OK') self.hlpwin.layout = QVBoxLayout(self.hlpwin) self.hlpwin.layout.addWidget(self.hlpedt) self.hlpwin.layout.addWidget(self.hlpbtn) self.hlpbtn.clicked.connect(self.hlpwin.deleteLater) self.hlpwin.setWindowTitle('Help') self.hlpwin.setWindowModality(Qt.ApplicationModal) self.hlpwin.setAttribute(Qt.WA_DeleteOnClose) self.hlpwin.setMinimumSize(370, 300) self.hlpwin.resize(370, 300) self.hlpwin.show() self.hlploop = QEventLoop() self.hlploop.exec_() def drawLayout(self): """ Draws the GUI layout. """ self.widgetslist = [ ['pair', 'show', 'Instrument', 'combo', self.instruments, self.setInstrument, 'InstrumentCombo'], ['pair', 'show', 'Chopper', 'combo', '', self.setChopper, 'ChopperCombo'], ['pair', 'show', 'Frequency', 'combo', '', self.setFreq, 'FrequencyCombo'], ['pair', 'hide', 'Pulse remover chopper freq', 'combo', '', self.setFreq, 'PulseRemoverCombo'], ['pair', 'show', 'Ei', 'edit', '', self.setEi, 'EiEdit'], ['pair', 'hide', 'Chopper 2 phase delay time', 'edit', '5', self.setFreq, 'Chopper2Phase'], ['spacer'], ['single', 'show', 'Calculate and Plot', 'button', self.calc_callback, 'CalculateButton'], ['single', 'show', 'Hold current plot', 'check', lambda: None, 'HoldCheck'], ['single', 'show', 'Show multi-reps', 'check', lambda: None, 'MultiRepCheck'], ['spacer'], ['single', 'show', 'Show data ascii window', 'button', self.showText, 'ShowAsciiButton'], ['single', 'show', 'Save data as ascii', 'button', self.saveText, 'SaveAsciiButton'] ] self.droplabels = [] self.dropboxes = [] self.singles = [] self.widgets = {} self.leftPanel = QVBoxLayout() self.rightPanel = QVBoxLayout() self.tabs = QTabWidget(self) self.fullWindow = QGridLayout() for widget in self.widgetslist: if 'pair' in widget[0]: self.droplabels.append(QLabel(widget[2])) if 'combo' in widget[3]: self.dropboxes.append(QComboBox(self)) self.dropboxes[-1].activated['QString'].connect(widget[5]) for item in widget[4]: self.dropboxes[-1].addItem(item) self.widgets[widget[-1]] = {'Combo':self.dropboxes[-1], 'Label':self.droplabels[-1]} elif 'edit' in widget[3]: self.dropboxes.append(QLineEdit(self)) self.dropboxes[-1].returnPressed.connect(widget[5]) self.widgets[widget[-1]] = {'Edit':self.dropboxes[-1], 'Label':self.droplabels[-1]} else: raise RuntimeError('Bug in code - widget %s is not recognised.' % (widget[3])) self.leftPanel.addWidget(self.droplabels[-1]) self.leftPanel.addWidget(self.dropboxes[-1]) if 'hide' in widget[1]: self.droplabels[-1].hide() self.dropboxes[-1].hide() elif 'single' in widget[0]: if 'check' in widget[3]: self.singles.append(QCheckBox(widget[2], self)) self.singles[-1].stateChanged.connect(widget[4]) elif 'button' in widget[3]: self.singles.append(QPushButton(widget[2])) self.singles[-1].clicked.connect(widget[4]) else: raise RuntimeError('Bug in code - widget %s is not recognised.' % (widget[3])) self.leftPanel.addWidget(self.singles[-1]) if 'hide' in widget[1]: self.singles[-1].hide() self.widgets[widget[-1]] = self.singles[-1] elif 'spacer' in widget[0]: self.leftPanel.addItem(QSpacerItem(0, 35)) else: raise RuntimeError('Bug in code - widget class %s is not recognised.' % (widget[0])) # Right panel, matplotlib figures self.resfig = Figure() self.resfig.patch.set_facecolor('white') self.rescanvas = FigureCanvas(self.resfig) self.resaxes = self.resfig.add_subplot(111) self.resaxes.axhline(color='k') self.resaxes.set_xlabel('Energy Transfer (meV)') self.resaxes.set_ylabel(r'$\Delta$E (meV FWHM)') self.resfig_controls = NavigationToolbar(self.rescanvas, self) self.restab = QWidget(self.tabs) self.restabbox = QVBoxLayout() self.restabbox.addWidget(self.rescanvas) self.restabbox.addWidget(self.resfig_controls) self.restab.setLayout(self.restabbox) self.flxfig = Figure() self.flxfig.patch.set_facecolor('white') self.flxcanvas = FigureCanvas(self.flxfig) self.flxaxes1 = self.flxfig.add_subplot(121) self.flxaxes1.set_xlabel('Incident Energy (meV)') self.flxaxes1.set_ylabel('Flux (n/cm$^2$/s)') self.flxaxes2 = self.flxfig.add_subplot(122) self.flxaxes2.set_xlabel('Incident Energy (meV)') self.flxaxes2.set_ylabel('Elastic Resolution FWHM (meV)') self.flxfig_controls = NavigationToolbar(self.flxcanvas, self) self.flxsldfg = Figure() self.flxsldfg.patch.set_facecolor('white') self.flxsldcv = FigureCanvas(self.flxsldfg) self.flxsldax = self.flxsldfg.add_subplot(111) self.flxslder = Slider(self.flxsldax, 'Ei (meV)', 0, 100, valinit=100) self.flxslder.valtext.set_visible(False) self.flxslder.on_changed(self.update_slider) self.flxedt = QLineEdit() self.flxedt.setText('1000') self.flxedt.returnPressed.connect(self.update_slider) self.flxtab = QWidget(self.tabs) self.flxsldbox = QHBoxLayout() self.flxsldbox.addWidget(self.flxsldcv) self.flxsldbox.addWidget(self.flxedt) self.flxsldwdg = QWidget() self.flxsldwdg.setLayout(self.flxsldbox) sz = self.flxsldwdg.maximumSize() sz.setHeight(50) self.flxsldwdg.setMaximumSize(sz) self.flxtabbox = QVBoxLayout() self.flxtabbox.addWidget(self.flxcanvas) self.flxtabbox.addWidget(self.flxsldwdg) self.flxtabbox.addWidget(self.flxfig_controls) self.flxtab.setLayout(self.flxtabbox) self.frqfig = Figure() self.frqfig.patch.set_facecolor('white') self.frqcanvas = FigureCanvas(self.frqfig) self.frqaxes1 = self.frqfig.add_subplot(121) self.frqaxes1.set_xlabel('Chopper Frequency (Hz)') self.frqaxes1.set_ylabel('Flux (n/cm$^2$/s)') self.frqaxes2 = self.frqfig.add_subplot(122) self.frqaxes1.set_xlabel('Chopper Frequency (Hz)') self.frqaxes2.set_ylabel('Elastic Resolution FWHM (meV)') self.frqfig_controls = NavigationToolbar(self.frqcanvas, self) self.frqtab = QWidget(self.tabs) self.frqtabbox = QVBoxLayout() self.frqtabbox.addWidget(self.frqcanvas) self.frqtabbox.addWidget(self.frqfig_controls) self.frqtab.setLayout(self.frqtabbox) self.repfig = Figure() self.repfig.patch.set_facecolor('white') self.repcanvas = FigureCanvas(self.repfig) self.repaxes = self.repfig.add_subplot(111) self.repaxes.axhline(color='k') self.repaxes.set_xlabel(r'TOF ($\mu$sec)') self.repaxes.set_ylabel('Distance (m)') self.repfig_controls = NavigationToolbar(self.repcanvas, self) self.repfig_nframe_label = QLabel('Number of frames to plot') self.repfig_nframe_edit = QLineEdit('1') self.repfig_nframe_button = QPushButton('Replot') self.repfig_nframe_button.clicked.connect(lambda: self.plot_frame()) self.repfig_nframe_rep1only = QCheckBox('First Rep Only') self.repfig_nframe_box = QHBoxLayout() self.repfig_nframe_box.addWidget(self.repfig_nframe_label) self.repfig_nframe_box.addWidget(self.repfig_nframe_edit) self.repfig_nframe_box.addWidget(self.repfig_nframe_button) self.repfig_nframe_box.addWidget(self.repfig_nframe_rep1only) self.reptab = QWidget(self.tabs) self.repfig_nframe = QWidget(self.reptab) self.repfig_nframe.setLayout(self.repfig_nframe_box) self.repfig_nframe.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)) self.reptabbox = QVBoxLayout() self.reptabbox.addWidget(self.repcanvas) self.reptabbox.addWidget(self.repfig_nframe) self.reptabbox.addWidget(self.repfig_controls) self.reptab.setLayout(self.reptabbox) self.qefig = Figure() self.qefig.patch.set_facecolor('white') self.qecanvas = FigureCanvas(self.qefig) self.qeaxes = self.qefig.add_subplot(111) self.qeaxes.axhline(color='k') self.qeaxes.set_xlabel(r'$|Q| (\mathrm{\AA}^{-1})$') self.qeaxes.set_ylabel('Energy Transfer (meV)') self.qefig_controls = NavigationToolbar(self.qecanvas, self) self.qetabbox = QVBoxLayout() self.qetabbox.addWidget(self.qecanvas) self.qetabbox.addWidget(self.qefig_controls) self.qetab = QWidget(self.tabs) self.qetab.setLayout(self.qetabbox) self.scrtab = QWidget(self.tabs) self.scredt = QTextEdit() self.scrcls = QPushButton("Clear") self.scrcls.clicked.connect(lambda: self.scredt.clear()) self.scrbox = QVBoxLayout() self.scrbox.addWidget(self.scredt) self.scrbox.addWidget(self.scrcls) self.scrtab.setLayout(self.scrbox) self.scrtab.hide() self.tabs.addTab(self.restab, 'Resolution') self.tabs.addTab(self.flxtab, 'Flux-Ei') self.tabs.addTab(self.frqtab, 'Flux-Freq') self.tabs.addTab(self.reptab, 'Time-Distance') self.tdtabID = 3 self.tabs.setTabEnabled(self.tdtabID, False) self.tabs.addTab(self.qetab, 'Q-E') self.qetabID = 4 self.tabs.setTabEnabled(self.qetabID, False) self.scrtabID = 5 self.rightPanel.addWidget(self.tabs) self.menuLoad = QMenu('Load') self.loadAct = QAction('Load YAML', self.menuLoad) self.loadAct.triggered.connect(self.loadYaml) self.menuLoad.addAction(self.loadAct) self.menuOptions = QMenu('Options') self.instSciAct = QAction('Instrument Scientist Mode', self.menuOptions, checkable=True) self.instSciAct.triggered.connect(self.instSciCB) self.menuOptions.addAction(self.instSciAct) self.eiPlots = QAction('Press Enter in Ei box updates plots', self.menuOptions, checkable=True) self.menuOptions.addAction(self.eiPlots) self.overwriteload = QAction('Always overwrite instruments in memory', self.menuOptions, checkable=True) self.menuOptions.addAction(self.overwriteload) self.menuBar().addMenu(self.menuLoad) self.menuBar().addMenu(self.menuOptions) self.leftPanelWidget = QWidget() self.leftPanelWidget.setLayout(self.leftPanel) self.leftPanelWidget.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)) self.fullWindow.addWidget(self.leftPanelWidget, 0, 0) self.fullWindow.addLayout(self.rightPanel, 0, 1) self.helpbtn = QPushButton("?", self) self.helpbtn.setMaximumWidth(30) self.helpbtn.clicked.connect(self.onHelp) self.fullWindow.addWidget(self.helpbtn, 1, 0, 1, -1) self.mainWidget = QWidget() self.mainWidget.setLayout(self.fullWindow) self.setCentralWidget(self.mainWidget) self.setWindowTitle('PyChopGUI') self.show()
def __init__(self, parent=None): QWidget.__init__(self, parent) self.current_radio = None self.dedicated_radio = None self.systerm_radio = None self.runconf = RunConfiguration() firstrun_o = CONF.get("run", ALWAYS_OPEN_FIRST_RUN_OPTION, False) # --- General settings ---- common_group = QGroupBox(_("General settings")) common_layout = QGridLayout() common_group.setLayout(common_layout) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 0, 0) self.clo_edit = QLineEdit() self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 0, 1) self.wd_cb = QCheckBox(_("Working directory:")) common_layout.addWidget(self.wd_cb, 1, 0) wd_layout = QHBoxLayout() self.wd_edit = QLineEdit() self.wd_cb.toggled.connect(self.wd_edit.setEnabled) self.wd_edit.setEnabled(False) wd_layout.addWidget(self.wd_edit) browse_btn = QPushButton(ima.icon("DirOpenIcon"), "", self) browse_btn.setToolTip(_("Select directory")) browse_btn.clicked.connect(self.select_directory) wd_layout.addWidget(browse_btn) common_layout.addLayout(wd_layout, 1, 1) self.post_mortem_cb = QCheckBox(_("Enter debugging mode when " "errors appear during execution")) common_layout.addWidget(self.post_mortem_cb) # --- Interpreter --- interpreter_group = QGroupBox(_("Console")) interpreter_layout = QVBoxLayout() interpreter_group.setLayout(interpreter_layout) self.current_radio = QRadioButton(CURRENT_INTERPRETER) interpreter_layout.addWidget(self.current_radio) self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER) interpreter_layout.addWidget(self.dedicated_radio) self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER) interpreter_layout.addWidget(self.systerm_radio) # --- Dedicated interpreter --- new_group = QGroupBox(_("Dedicated Python console")) self.current_radio.toggled.connect(new_group.setDisabled) new_layout = QGridLayout() new_group.setLayout(new_layout) self.interact_cb = QCheckBox(_("Interact with the Python " "console after execution")) new_layout.addWidget(self.interact_cb, 1, 0, 1, -1) self.show_kill_warning_cb = QCheckBox(_("Show warning when killing" " running process")) new_layout.addWidget(self.show_kill_warning_cb, 2, 0, 1, -1) self.pclo_cb = QCheckBox(_("Command line options:")) new_layout.addWidget(self.pclo_cb, 3, 0) self.pclo_edit = QLineEdit() self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled) self.pclo_edit.setEnabled(False) self.pclo_edit.setToolTip(_("<b>-u</b> is added to the " "other options you set here")) new_layout.addWidget(self.pclo_edit, 3, 1) # Checkbox to preserve the old behavior, i.e. always open the dialog # on first run hline = QFrame() hline.setFrameShape(QFrame.HLine) hline.setFrameShadow(QFrame.Sunken) self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog")) self.firstrun_cb.clicked.connect(self.set_firstrun_o) self.firstrun_cb.setChecked(firstrun_o) layout = QVBoxLayout() layout.addWidget(interpreter_group) layout.addWidget(common_group) layout.addWidget(new_group) layout.addWidget(hline) layout.addWidget(self.firstrun_cb) self.setLayout(layout)
def setup_page(self): newcb = self.create_checkbox # --- Introspection --- # Basic features group basic_features_group = QGroupBox(_("Basic features")) completion_box = newcb(_("Enable code completion"), 'code_completion') goto_definition_box = newcb( _("Enable Go to definition"), 'jedi_definition', tip=_("If this option is enabled, left-clicking on\n" "an object name while pressing the {} key will go to\n" "that object's definition (if resolved).".format(self.CTRL))) follow_imports_box = newcb(_("Follow imports when going to a " "definition"), 'jedi_definition/follow_imports') show_signature_box = newcb(_("Show calltips"), 'jedi_signature_help') basic_features_layout = QVBoxLayout() basic_features_layout.addWidget(completion_box) basic_features_layout.addWidget(goto_definition_box) basic_features_layout.addWidget(follow_imports_box) basic_features_layout.addWidget(show_signature_box) basic_features_group.setLayout(basic_features_layout) # Advanced group advanced_group = QGroupBox(_("Advanced")) modules_textedit = self.create_textedit( _("Preload the following modules to make completion faster " "and more accurate:"), 'preload_modules' ) if is_dark_interface(): modules_textedit.textbox.setStyleSheet( "border: 1px solid #32414B;" ) advanced_layout = QVBoxLayout() advanced_layout.addWidget(modules_textedit) advanced_group.setLayout(advanced_layout) # --- Linting --- # Linting options linting_label = QLabel(_("Spyder can optionally highlight syntax " "errors and possible problems with your " "code in the editor.")) linting_label.setOpenExternalLinks(True) linting_label.setWordWrap(True) linting_check = self.create_checkbox( _("Enable basic linting"), 'pyflakes') linting_complexity_box = self.create_checkbox( _("Enable complexity linting with " "the Mccabe package"), 'mccabe') # Linting layout linting_layout = QVBoxLayout() linting_layout.addWidget(linting_label) linting_layout.addWidget(linting_check) linting_layout.addWidget(linting_complexity_box) linting_widget = QWidget() linting_widget.setLayout(linting_layout) # --- Code style tab --- # Code style label pep_url = ( '<a href="https://www.python.org/dev/peps/pep-0008">PEP 8</a>') code_style_codes_url = _( "<a href='http://pycodestyle.pycqa.org/en/stable" "/intro.html#error-codes'>pycodestyle error codes</a>") code_style_label = QLabel( _("Spyder can use pycodestyle to analyze your code for " "conformance to the {} convention. You can also " "manually show or hide specific warnings by their " "{}.").format(pep_url, code_style_codes_url)) code_style_label.setOpenExternalLinks(True) code_style_label.setWordWrap(True) # Code style checkbox code_style_check = self.create_checkbox( _("Enable code style linting"), 'pycodestyle') # Code style options self.code_style_filenames_match = self.create_lineedit( _("Only check filenames matching these patterns:"), 'pycodestyle/filename', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Check Python files: *.py")) self.code_style_exclude = self.create_lineedit( _("Exclude files or directories matching these patterns:"), 'pycodestyle/exclude', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Exclude all test files: (?!test_).*\\.py")) code_style_select = self.create_lineedit( _("Show the following errors or warnings:").format( code_style_codes_url), 'pycodestyle/select', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: E113, W391")) code_style_ignore = self.create_lineedit( _("Ignore the following errors or warnings:"), 'pycodestyle/ignore', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: E201, E303")) code_style_max_line_length = self.create_spinbox( _("Maximum allowed line length:"), None, 'pycodestyle/max_line_length', min_=10, max_=500, step=1, tip=_("Default is 79")) # Code style layout code_style_g_layout = QGridLayout() code_style_g_layout.addWidget( self.code_style_filenames_match.label, 1, 0) code_style_g_layout.addWidget( self.code_style_filenames_match.textbox, 1, 1) code_style_g_layout.addWidget(self.code_style_exclude.label, 2, 0) code_style_g_layout.addWidget(self.code_style_exclude.textbox, 2, 1) code_style_g_layout.addWidget(code_style_select.label, 3, 0) code_style_g_layout.addWidget(code_style_select.textbox, 3, 1) code_style_g_layout.addWidget(code_style_ignore.label, 4, 0) code_style_g_layout.addWidget(code_style_ignore.textbox, 4, 1) code_style_g_layout.addWidget(code_style_max_line_length.plabel, 5, 0) code_style_g_layout.addWidget( code_style_max_line_length.spinbox, 5, 1) # Set Code style options enabled/disabled code_style_g_widget = QWidget() code_style_g_widget.setLayout(code_style_g_layout) code_style_g_widget.setEnabled(self.get_option('pycodestyle')) code_style_check.toggled.connect(code_style_g_widget.setEnabled) # Code style layout code_style_layout = QVBoxLayout() code_style_layout.addWidget(code_style_label) code_style_layout.addWidget(code_style_check) code_style_layout.addWidget(code_style_g_widget) code_style_widget = QWidget() code_style_widget.setLayout(code_style_layout) # --- Docstring tab --- # Docstring style label numpy_url = ( "<a href='https://numpydoc.readthedocs.io/en/" "latest/format.html'>Numpy</a>") pep257_url = ( "<a href='https://www.python.org/dev/peps/pep-0257/'>PEP 257</a>") docstring_style_codes = _( "<a href='http://www.pydocstyle.org/en/stable" "/error_codes.html'>page</a>") docstring_style_label = QLabel( _("Here you can decide if you want to perform style analysis on " "your docstrings according to the {} or {} conventions. You can " "also decide if you want to show or ignore specific errors, " "according to the codes found on this {}.").format( numpy_url, pep257_url, docstring_style_codes)) docstring_style_label.setOpenExternalLinks(True) docstring_style_label.setWordWrap(True) # Docstring style checkbox docstring_style_check = self.create_checkbox( _("Enable docstring style linting"), 'pydocstyle') # Docstring style options docstring_style_convention = self.create_combobox( _("Choose the convention used to lint docstrings: "), (("Numpy", 'numpy'), ("PEP 257", 'pep257'), ("Custom", 'custom')), 'pydocstyle/convention') self.docstring_style_select = self.create_lineedit( _("Show the following errors:"), 'pydocstyle/select', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: D413, D414")) self.docstring_style_ignore = self.create_lineedit( _("Ignore the following errors:"), 'pydocstyle/ignore', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: D107, D402")) self.docstring_style_match = self.create_lineedit( _("Only check filenames matching these patterns:"), 'pydocstyle/match', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Skip test files: (?!test_).*\\.py")) self.docstring_style_match_dir = self.create_lineedit( _("Only check in directories matching these patterns:"), 'pydocstyle/match_dir', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Skip dot directories: [^\\.].*")) # Custom option handling docstring_style_convention.combobox.currentTextChanged.connect( self.setup_docstring_style_convention) current_convention = docstring_style_convention.combobox.currentText() self.setup_docstring_style_convention(current_convention) # Docstring style layout docstring_style_g_layout = QGridLayout() docstring_style_g_layout.addWidget( docstring_style_convention.label, 1, 0) docstring_style_g_layout.addWidget( docstring_style_convention.combobox, 1, 1) docstring_style_g_layout.addWidget( self.docstring_style_select.label, 2, 0) docstring_style_g_layout.addWidget( self.docstring_style_select.textbox, 2, 1) docstring_style_g_layout.addWidget( self.docstring_style_ignore.label, 3, 0) docstring_style_g_layout.addWidget( self.docstring_style_ignore.textbox, 3, 1) docstring_style_g_layout.addWidget( self.docstring_style_match.label, 4, 0) docstring_style_g_layout.addWidget( self.docstring_style_match.textbox, 4, 1) docstring_style_g_layout.addWidget( self.docstring_style_match_dir.label, 5, 0) docstring_style_g_layout.addWidget( self.docstring_style_match_dir.textbox, 5, 1) # Set Docstring style options enabled/disabled docstring_style_g_widget = QWidget() docstring_style_g_widget.setLayout(docstring_style_g_layout) docstring_style_g_widget.setEnabled(self.get_option('pydocstyle')) docstring_style_check.toggled.connect( docstring_style_g_widget.setEnabled) # Docstring style layout docstring_style_layout = QVBoxLayout() docstring_style_layout.addWidget(docstring_style_label) docstring_style_layout.addWidget(docstring_style_check) docstring_style_layout.addWidget(docstring_style_g_widget) docstring_style_widget = QWidget() docstring_style_widget.setLayout(docstring_style_layout) # --- Advanced tab --- # Advanced label advanced_label = QLabel( _("Please don't modify these values unless " "you know what you're doing!")) advanced_label.setWordWrap(True) advanced_label.setAlignment(Qt.AlignJustify) # Advanced options advanced_command_launch = self.create_lineedit( _("Command to launch the Python language server: "), 'advanced/command_launch', alignment=Qt.Horizontal, word_wrap=False) advanced_host = self.create_lineedit( _("IP Address and port to bind the server to: "), 'advanced/host', alignment=Qt.Horizontal, word_wrap=False) advanced_port = self.create_spinbox( ":", "", 'advanced/port', min_=1, max_=65535, step=1) # Advanced layout advanced_g_layout = QGridLayout() advanced_g_layout.addWidget(advanced_command_launch.label, 1, 0) advanced_g_layout.addWidget(advanced_command_launch.textbox, 1, 1) advanced_g_layout.addWidget(advanced_host.label, 2, 0) advanced_host_port_g_layout = QGridLayout() advanced_host_port_g_layout.addWidget(advanced_host.textbox, 1, 0) advanced_host_port_g_layout.addWidget(advanced_port.plabel, 1, 1) advanced_host_port_g_layout.addWidget(advanced_port.spinbox, 1, 2) advanced_g_layout.addLayout(advanced_host_port_g_layout, 2, 1) advanced_widget = QWidget() advanced_layout = QVBoxLayout() advanced_layout.addWidget(advanced_label) advanced_layout.addLayout(advanced_g_layout) advanced_widget.setLayout(advanced_layout) # --- Other servers tab --- # Section label servers_label = QLabel( _("Spyder uses the <a href=\"{lsp_url}\">Language Server " "Protocol</a> to provide code completion and linting " "for its Editor. Here, you can setup and configure LSP servers " "for languages other than Python, so Spyder can provide such " "features for those languages as well." ).format(lsp_url=LSP_URL)) servers_label.setOpenExternalLinks(True) servers_label.setWordWrap(True) servers_label.setAlignment(Qt.AlignJustify) # Servers table table_group = QGroupBox(_('Available servers:')) self.table = LSPServerTable(self, text_color=ima.MAIN_FG_COLOR) table_layout = QVBoxLayout() table_layout.addWidget(self.table) table_group.setLayout(table_layout) # Buttons self.reset_btn = QPushButton(_("Reset to default values")) self.new_btn = QPushButton(_("Set up a new server")) self.delete_btn = QPushButton(_("Delete currently selected server")) self.delete_btn.setEnabled(False) # Slots connected to buttons self.new_btn.clicked.connect(self.create_new_server) self.reset_btn.clicked.connect(self.reset_to_default) self.delete_btn.clicked.connect(self.delete_server) # Buttons layout btns = [self.new_btn, self.delete_btn, self.reset_btn] buttons_layout = QGridLayout() for i, btn in enumerate(btns): buttons_layout.addWidget(btn, i, 1) buttons_layout.setColumnStretch(0, 1) buttons_layout.setColumnStretch(1, 2) buttons_layout.setColumnStretch(2, 1) # Combined layout servers_widget = QWidget() servers_layout = QVBoxLayout() servers_layout.addSpacing(-10) servers_layout.addWidget(servers_label) servers_layout.addWidget(table_group) servers_layout.addSpacing(10) servers_layout.addLayout(buttons_layout) servers_widget.setLayout(servers_layout) # --- Tabs organization --- tabs = QTabWidget() tabs.addTab(self.create_tab(basic_features_group, advanced_group), _('Introspection')) tabs.addTab(self.create_tab(linting_widget), _('Linting')) tabs.addTab(self.create_tab(code_style_widget), _('Code style')) tabs.addTab(self.create_tab(docstring_style_widget), _('Docstring style')) tabs.addTab(self.create_tab(advanced_widget), _('Advanced')) tabs.addTab(self.create_tab(servers_widget), _('Other languages')) vlayout = QVBoxLayout() vlayout.addWidget(tabs) self.setLayout(vlayout)
def __init__(self, parent, enable_replace=False): QWidget.__init__(self, parent) self.enable_replace = enable_replace self.editor = None self.is_code_editor = None glayout = QGridLayout() glayout.setContentsMargins(0, 0, 0, 0) self.setLayout(glayout) self.close_button = create_toolbutton(self, triggered=self.hide, icon=ima.icon('DialogCloseButton')) glayout.addWidget(self.close_button, 0, 0) # Find layout self.search_text = PatternComboBox(self, tip=_("Search string"), adjust_to_minimum=False) self.search_text.valid.connect( lambda state: self.find(changed=False, forward=True, rehighlight=False)) self.search_text.lineEdit().textEdited.connect( self.text_has_been_edited) self.previous_button = create_toolbutton(self, triggered=self.find_previous, icon=ima.icon('ArrowUp')) self.next_button = create_toolbutton(self, triggered=self.find_next, icon=ima.icon('ArrowDown')) self.next_button.clicked.connect(self.update_search_combo) self.previous_button.clicked.connect(self.update_search_combo) self.re_button = create_toolbutton(self, icon=ima.icon('advanced'), tip=_("Regular expression")) self.re_button.setCheckable(True) self.re_button.toggled.connect(lambda state: self.find()) self.case_button = create_toolbutton(self, icon=get_icon("upper_lower.png"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.toggled.connect(lambda state: self.find()) self.words_button = create_toolbutton(self, icon=get_icon("whole_words.png"), tip=_("Whole words")) self.words_button.setCheckable(True) self.words_button.toggled.connect(lambda state: self.find()) self.highlight_button = create_toolbutton(self, icon=get_icon("highlight.png"), tip=_("Highlight matches")) self.highlight_button.setCheckable(True) self.highlight_button.toggled.connect(self.toggle_highlighting) hlayout = QHBoxLayout() self.widgets = [self.close_button, self.search_text, self.previous_button, self.next_button, self.re_button, self.case_button, self.words_button, self.highlight_button] for widget in self.widgets[1:]: hlayout.addWidget(widget) glayout.addLayout(hlayout, 0, 1) # Replace layout replace_with = QLabel(_("Replace with:")) self.replace_text = PatternComboBox(self, adjust_to_minimum=False, tip=_('Replace string')) self.replace_button = create_toolbutton(self, text=_('Replace/find'), icon=ima.icon('DialogApplyButton'), triggered=self.replace_find, text_beside_icon=True) self.replace_button.clicked.connect(self.update_replace_combo) self.replace_button.clicked.connect(self.update_search_combo) self.all_check = QCheckBox(_("Replace all")) self.replace_layout = QHBoxLayout() widgets = [replace_with, self.replace_text, self.replace_button, self.all_check] for widget in widgets: self.replace_layout.addWidget(widget) glayout.addLayout(self.replace_layout, 1, 1) self.widgets.extend(widgets) self.replace_widgets = widgets self.hide_replace() self.search_text.setTabOrder(self.search_text, self.replace_text) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.shortcuts = self.create_shortcuts(parent) self.highlight_timer = QTimer(self) self.highlight_timer.setSingleShot(True) self.highlight_timer.setInterval(1000) self.highlight_timer.timeout.connect(self.highlight_matches)
def setup(self): """Setup the ShortcutEditor with the provided arguments.""" # Widgets icon_info = HelperToolButton() icon_info.setIcon(get_std_icon('MessageBoxInformation')) layout_icon_info = QVBoxLayout() layout_icon_info.setContentsMargins(0, 0, 0, 0) layout_icon_info.setSpacing(0) layout_icon_info.addWidget(icon_info) layout_icon_info.addStretch(100) self.label_info = QLabel() self.label_info.setText( _("Press the new shortcut and select 'Ok' to confirm, " "click 'Cancel' to revert to the previous state, " "or use 'Clear' to unbind the command from a shortcut.")) self.label_info.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.label_info.setWordWrap(True) layout_info = QHBoxLayout() layout_info.setContentsMargins(0, 0, 0, 0) layout_info.addLayout(layout_icon_info) layout_info.addWidget(self.label_info) layout_info.setStretch(1, 100) self.label_current_sequence = QLabel(_("Current shortcut:")) self.text_current_sequence = QLabel(self.current_sequence) self.label_new_sequence = QLabel(_("New shortcut:")) self.text_new_sequence = ShortcutLineEdit(self) self.text_new_sequence.setPlaceholderText(_("Press shortcut.")) self.helper_button = HelperToolButton() self.helper_button.setIcon(QIcon()) self.label_warning = QLabel() self.label_warning.setWordWrap(True) self.label_warning.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.button_default = QPushButton(_('Default')) self.button_ok = QPushButton(_('Ok')) self.button_ok.setEnabled(False) self.button_clear = QPushButton(_('Clear')) self.button_cancel = QPushButton(_('Cancel')) button_box = QHBoxLayout() button_box.addWidget(self.button_default) button_box.addStretch(100) button_box.addWidget(self.button_ok) button_box.addWidget(self.button_clear) button_box.addWidget(self.button_cancel) # New Sequence button box self.btn_clear_sequence = create_toolbutton( self, icon=ima.icon('editclear'), tip=_("Clear all entered key sequences"), triggered=self.clear_new_sequence) self.button_back_sequence = create_toolbutton( self, icon=ima.icon('ArrowBack'), tip=_("Remove last key sequence entered"), triggered=self.back_new_sequence) newseq_btnbar = QHBoxLayout() newseq_btnbar.setSpacing(0) newseq_btnbar.setContentsMargins(0, 0, 0, 0) newseq_btnbar.addWidget(self.button_back_sequence) newseq_btnbar.addWidget(self.btn_clear_sequence) # Setup widgets self.setWindowTitle(_('Shortcut: {0}').format(self.name)) self.helper_button.setToolTip('') style = """ QToolButton { margin:1px; border: 0px solid grey; padding:0px; border-radius: 0px; }""" self.helper_button.setStyleSheet(style) icon_info.setToolTip('') icon_info.setStyleSheet(style) # Layout layout_sequence = QGridLayout() layout_sequence.setContentsMargins(0, 0, 0, 0) layout_sequence.addLayout(layout_info, 0, 0, 1, 4) layout_sequence.addItem(QSpacerItem(15, 15), 1, 0, 1, 4) layout_sequence.addWidget(self.label_current_sequence, 2, 0) layout_sequence.addWidget(self.text_current_sequence, 2, 2) layout_sequence.addWidget(self.label_new_sequence, 3, 0) layout_sequence.addWidget(self.helper_button, 3, 1) layout_sequence.addWidget(self.text_new_sequence, 3, 2) layout_sequence.addLayout(newseq_btnbar, 3, 3) layout_sequence.addWidget(self.label_warning, 4, 2, 1, 2) layout_sequence.setColumnStretch(2, 100) layout_sequence.setRowStretch(4, 100) layout = QVBoxLayout(self) layout.addLayout(layout_sequence) layout.addSpacing(10) layout.addLayout(button_box) layout.setSizeConstraint(layout.SetFixedSize) # Signals self.button_ok.clicked.connect(self.accept_override) self.button_clear.clicked.connect(self.unbind_shortcut) self.button_cancel.clicked.connect(self.reject) self.button_default.clicked.connect(self.set_sequence_to_default) # Set all widget to no focus so that we can register <Tab> key # press event. widgets = ( self.label_warning, self.helper_button, self.text_new_sequence, self.button_clear, self.button_default, self.button_cancel, self.button_ok, self.btn_clear_sequence, self.button_back_sequence) for w in widgets: w.setFocusPolicy(Qt.NoFocus) w.clearFocus()
class ArrayEditor(QDialog): """Array Editor Dialog""" def __init__(self, parent=None): QDialog.__init__(self, parent) # Destroying the C++ object right after closing the dialog box, # otherwise it may be garbage-collected in another QThread # (e.g. the editor's analysis thread in Spyder), thus leading to # a segmentation fault on UNIX or an application crash on Windows self.setAttribute(Qt.WA_DeleteOnClose) self.data = None self.arraywidget = None self.stack = None self.layout = None # Values for 3d array editor self.dim_indexes = [{}, {}, {}] self.last_dim = 0 # Adjust this for changing the startup dimension def setup_and_check(self, data, title='', readonly=False, xlabels=None, ylabels=None): """ Setup ArrayEditor: return False if data is not supported, True otherwise """ self.data = data is_record_array = data.dtype.names is not None is_masked_array = isinstance(data, np.ma.MaskedArray) if data.size == 0: self.error(_("Array is empty")) return False if data.ndim > 3: self.error(_("Arrays with more than 3 dimensions are not supported")) return False if xlabels is not None and len(xlabels) != self.data.shape[1]: self.error(_("The 'xlabels' argument length do no match array " "column number")) return False if ylabels is not None and len(ylabels) != self.data.shape[0]: self.error(_("The 'ylabels' argument length do no match array row " "number")) return False if not is_record_array: dtn = data.dtype.name if dtn not in SUPPORTED_FORMATS and not dtn.startswith('str') \ and not dtn.startswith('unicode'): arr = _("%s arrays") % data.dtype.name self.error(_("%s are currently not supported") % arr) return False self.layout = QGridLayout() self.setLayout(self.layout) self.setWindowIcon(ima.icon('arredit')) if title: title = to_text_string(title) + " - " + _("NumPy array") else: title = _("Array editor") if readonly: title += ' (' + _('read only') + ')' self.setWindowTitle(title) self.resize(600, 500) # Stack widget self.stack = QStackedWidget(self) if is_record_array: for name in data.dtype.names: self.stack.addWidget(ArrayEditorWidget(self, data[name], readonly, xlabels, ylabels)) elif is_masked_array: self.stack.addWidget(ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.stack.addWidget(ArrayEditorWidget(self, data.data, readonly, xlabels, ylabels)) self.stack.addWidget(ArrayEditorWidget(self, data.mask, readonly, xlabels, ylabels)) elif data.ndim == 3: pass else: self.stack.addWidget(ArrayEditorWidget(self, data, readonly, xlabels, ylabels)) self.arraywidget = self.stack.currentWidget() self.stack.currentChanged.connect(self.current_widget_changed) self.layout.addWidget(self.stack, 1, 0) # Buttons configuration btn_layout = QHBoxLayout() if is_record_array or is_masked_array or data.ndim == 3: if is_record_array: btn_layout.addWidget(QLabel(_("Record array fields:"))) names = [] for name in data.dtype.names: field = data.dtype.fields[name] text = name if len(field) >= 3: title = field[2] if not is_text_string(title): title = repr(title) text += ' - '+title names.append(text) else: names = [_('Masked data'), _('Data'), _('Mask')] if data.ndim == 3: # QSpinBox self.index_spin = QSpinBox(self, keyboardTracking=False) self.index_spin.valueChanged.connect(self.change_active_widget) # QComboBox names = [str(i) for i in range(3)] ra_combo = QComboBox(self) ra_combo.addItems(names) ra_combo.currentIndexChanged.connect(self.current_dim_changed) # Adding the widgets to layout label = QLabel(_("Axis:")) btn_layout.addWidget(label) btn_layout.addWidget(ra_combo) self.shape_label = QLabel() btn_layout.addWidget(self.shape_label) label = QLabel(_("Index:")) btn_layout.addWidget(label) btn_layout.addWidget(self.index_spin) self.slicing_label = QLabel() btn_layout.addWidget(self.slicing_label) # set the widget to display when launched self.current_dim_changed(self.last_dim) else: ra_combo = QComboBox(self) ra_combo.currentIndexChanged.connect(self.stack.setCurrentIndex) ra_combo.addItems(names) btn_layout.addWidget(ra_combo) if is_masked_array: label = QLabel(_("<u>Warning</u>: changes are applied separately")) label.setToolTip(_("For performance reasons, changes applied "\ "to masked array won't be reflected in "\ "array's data (and vice-versa).")) btn_layout.addWidget(label) btn_layout.addStretch() bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) btn_layout.addWidget(bbox) self.layout.addLayout(btn_layout, 2, 0) self.setMinimumSize(400, 300) # Make the dialog act as a window self.setWindowFlags(Qt.Window) return True def current_widget_changed(self, index): self.arraywidget = self.stack.widget(index) def change_active_widget(self, index): """ This is implemented for handling negative values in index for 3d arrays, to give the same behavior as slicing """ string_index = [':']*3 string_index[self.last_dim] = '<font color=red>%i</font>' self.slicing_label.setText((r"Slicing: [" + ", ".join(string_index) + "]") % index) if index < 0: data_index = self.data.shape[self.last_dim] + index else: data_index = index slice_index = [slice(None)]*3 slice_index[self.last_dim] = data_index stack_index = self.dim_indexes[self.last_dim].get(data_index) if stack_index == None: stack_index = self.stack.count() self.stack.addWidget(ArrayEditorWidget(self, self.data[slice_index])) self.dim_indexes[self.last_dim][data_index] = stack_index self.stack.update() self.stack.setCurrentIndex(stack_index) def current_dim_changed(self, index): """ This change the active axis the array editor is plotting over in 3D """ self.last_dim = index string_size = ['%i']*3 string_size[index] = '<font color=red>%i</font>' self.shape_label.setText(('Shape: (' + ', '.join(string_size) + ') ') % self.data.shape) if self.index_spin.value() != 0: self.index_spin.setValue(0) else: # this is done since if the value is currently 0 it does not emit # currentIndexChanged(int) self.change_active_widget(0) self.index_spin.setRange(-self.data.shape[index], self.data.shape[index]-1) @Slot() def accept(self): """Reimplement Qt method""" for index in range(self.stack.count()): self.stack.widget(index).accept_changes() QDialog.accept(self) def get_value(self): """Return modified array -- this is *not* a copy""" # It is import to avoid accessing Qt C++ object as it has probably # already been destroyed, due to the Qt.WA_DeleteOnClose attribute return self.data def error(self, message): """An error occured, closing the dialog box""" QMessageBox.critical(self, _("Array editor"), message) self.setAttribute(Qt.WA_DeleteOnClose) self.reject() @Slot() def reject(self): """Reimplement Qt method""" if self.arraywidget is not None: for index in range(self.stack.count()): self.stack.widget(index).reject_changes() QDialog.reject(self)
def add_color_scheme_stack(self, scheme_name, custom=False): """Add a stack for a given scheme and connects the CONF values.""" color_scheme_groups = [ (_('Text'), ["normal", "comment", "string", "number", "keyword", "builtin", "definition", "instance", ]), (_('Highlight'), ["currentcell", "currentline", "occurrence", "matched_p", "unmatched_p", "ctrlclick"]), (_('Background'), ["background", "sideareas"]) ] parent = self.parent line_edit = parent.create_lineedit(_("Scheme name:"), '{0}/name'.format(scheme_name)) self.widgets[scheme_name] = {} # Widget setup line_edit.label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.setWindowTitle(_('Color scheme editor')) # Layout name_layout = QHBoxLayout() name_layout.addWidget(line_edit.label) name_layout.addWidget(line_edit.textbox) self.scheme_name_textbox[scheme_name] = line_edit.textbox if not custom: line_edit.textbox.setDisabled(True) if not self.isVisible(): line_edit.setVisible(False) cs_layout = QVBoxLayout() cs_layout.addLayout(name_layout) h_layout = QHBoxLayout() v_layout = QVBoxLayout() for index, item in enumerate(color_scheme_groups): group_name, keys = item group_layout = QGridLayout() for row, key in enumerate(keys): option = "{0}/{1}".format(scheme_name, key) value = self.parent.get_option(option) name = syntaxhighlighters.COLOR_SCHEME_KEYS[key] if is_text_string(value): label, clayout = parent.create_coloredit( name, option, without_layout=True, ) label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) group_layout.addWidget(label, row+1, 0) group_layout.addLayout(clayout, row+1, 1) # Needed to update temp scheme to obtain instant preview self.widgets[scheme_name][key] = [clayout] else: label, clayout, cb_bold, cb_italic = parent.create_scedit( name, option, without_layout=True, ) label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) group_layout.addWidget(label, row+1, 0) group_layout.addLayout(clayout, row+1, 1) group_layout.addWidget(cb_bold, row+1, 2) group_layout.addWidget(cb_italic, row+1, 3) # Needed to update temp scheme to obtain instant preview self.widgets[scheme_name][key] = [clayout, cb_bold, cb_italic] group_box = QGroupBox(group_name) group_box.setLayout(group_layout) if index == 0: h_layout.addWidget(group_box) else: v_layout.addWidget(group_box) h_layout.addLayout(v_layout) cs_layout.addLayout(h_layout) stackitem = QWidget() stackitem.setLayout(cs_layout) self.stack.addWidget(stackitem) self.order.append(scheme_name)
def setup_page(self): self.ICON = ima.icon('eyedropper') names = self.get_option("names") try: names.pop(names.index(u'Custom')) except ValueError: pass custom_names = self.get_option("custom_names", []) # Interface options theme_group = QGroupBox(_("Main interface")) # Interface Widgets ui_themes = ['Automatic', 'Light', 'Dark'] ui_theme_choices = list(zip(ui_themes, [ui_theme.lower() for ui_theme in ui_themes])) ui_theme_combo = self.create_combobox(_('Interface theme'), ui_theme_choices, 'ui_theme', restart=True) styles = [str(txt) for txt in list(QStyleFactory.keys())] # Don't offer users the possibility to change to a different # style in Gtk-based desktops # Fixes Issue 2036 if is_gtk_desktop() and ('GTK+' in styles): styles = ['GTK+'] choices = list(zip(styles, [style.lower() for style in styles])) style_combo = self.create_combobox(_('Qt windows style'), choices, 'windows_style', default=self.main.default_style) self.style_combobox = style_combo.combobox themes = ['Spyder 2', 'Spyder 3'] icon_choices = list(zip(themes, [theme.lower() for theme in themes])) icons_combo = self.create_combobox(_('Icon theme'), icon_choices, 'icon_theme', restart=True) theme_comboboxes_layout = QGridLayout() theme_comboboxes_layout.addWidget(ui_theme_combo.label, 0, 0) theme_comboboxes_layout.addWidget(ui_theme_combo.combobox, 0, 1) theme_comboboxes_layout.addWidget(style_combo.label, 1, 0) theme_comboboxes_layout.addWidget(self.style_combobox, 1, 1) theme_comboboxes_layout.addWidget(icons_combo.label, 2, 0) theme_comboboxes_layout.addWidget(icons_combo.combobox, 2, 1) theme_layout = QVBoxLayout() theme_layout.addLayout(theme_comboboxes_layout) theme_group.setLayout(theme_layout) # Syntax coloring options syntax_group = QGroupBox(_("Syntax highlighting theme")) # Syntax Widgets edit_button = QPushButton(_("Edit selected scheme")) create_button = QPushButton(_("Create new scheme")) self.delete_button = QPushButton(_("Delete scheme")) self.reset_button = QPushButton(_("Reset to defaults")) self.preview_editor = CodeEditor(self) self.stacked_widget = QStackedWidget(self) self.scheme_editor_dialog = SchemeEditor(parent=self, stack=self.stacked_widget) self.scheme_choices_dict = {} schemes_combobox_widget = self.create_combobox('', [('', '')], 'selected') self.schemes_combobox = schemes_combobox_widget.combobox # Syntax layout syntax_layout = QGridLayout(syntax_group) btns = [self.schemes_combobox, edit_button, self.reset_button, create_button, self.delete_button] for i, btn in enumerate(btns): syntax_layout.addWidget(btn, i, 1) syntax_layout.setColumnStretch(0, 1) syntax_layout.setColumnStretch(1, 2) syntax_layout.setColumnStretch(2, 1) syntax_layout.setContentsMargins(0, 12, 0, 12) # Fonts options fonts_group = QGroupBox(_("Fonts")) # Fonts widgets plain_text_font = self.create_fontgroup( option='font', title=_("Plain text"), fontfilters=QFontComboBox.MonospacedFonts, without_group=True) rich_text_font = self.create_fontgroup( option='rich_font', title=_("Rich text"), without_group=True) # Fonts layouts fonts_layout = QGridLayout() fonts_layout.addWidget(plain_text_font.fontlabel, 0, 0) fonts_layout.addWidget(plain_text_font.fontbox, 0, 1) fonts_layout.addWidget(plain_text_font.sizelabel, 0, 2) fonts_layout.addWidget(plain_text_font.sizebox, 0, 3) fonts_layout.addWidget(rich_text_font.fontlabel, 1, 0) fonts_layout.addWidget(rich_text_font.fontbox, 1, 1) fonts_layout.addWidget(rich_text_font.sizelabel, 1, 2) fonts_layout.addWidget(rich_text_font.sizebox, 1, 3) fonts_group.setLayout(fonts_layout) # Left options layout options_layout = QVBoxLayout() options_layout.addWidget(theme_group) options_layout.addWidget(syntax_group) options_layout.addWidget(fonts_group) # Right preview layout preview_group = QGroupBox(_("Preview")) preview_layout = QVBoxLayout() preview_layout.addWidget(self.preview_editor) preview_group.setLayout(preview_layout) # Combined layout combined_layout = QGridLayout() combined_layout.setRowStretch(0, 1) combined_layout.setColumnStretch(1, 100) combined_layout.addLayout(options_layout, 0, 0) combined_layout.addWidget(preview_group, 0, 1) self.setLayout(combined_layout) # Signals and slots create_button.clicked.connect(self.create_new_scheme) edit_button.clicked.connect(self.edit_scheme) self.reset_button.clicked.connect(self.reset_to_default) self.delete_button.clicked.connect(self.delete_scheme) self.schemes_combobox.currentIndexChanged.connect(self.update_preview) self.schemes_combobox.currentIndexChanged.connect(self.update_buttons) # Setup for name in names: self.scheme_editor_dialog.add_color_scheme_stack(name) for name in custom_names: self.scheme_editor_dialog.add_color_scheme_stack(name, custom=True) self.update_combobox() self.update_preview() self.update_qt_style_combobox()
def setup(self): """Setup the ShortcutEditor with the provided arguments.""" # Widgets icon_info = HelperToolButton() icon_info.setIcon(get_std_icon('MessageBoxInformation')) layout_icon_info = QVBoxLayout() layout_icon_info.setContentsMargins(0, 0, 0, 0) layout_icon_info.setSpacing(0) layout_icon_info.addWidget(icon_info) layout_icon_info.addStretch(100) self.label_info = QLabel() self.label_info.setText( _("Press the new shortcut and select 'Ok' to confirm, " "click 'Cancel' to revert to the previous state, " "or use 'Clear' to unbind the command from a shortcut.")) self.label_info.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.label_info.setWordWrap(True) layout_info = QHBoxLayout() layout_info.setContentsMargins(0, 0, 0, 0) layout_info.addLayout(layout_icon_info) layout_info.addWidget(self.label_info) layout_info.setStretch(1, 100) self.label_current_sequence = QLabel(_("Current shortcut:")) self.text_current_sequence = QLabel(self.current_sequence) self.label_new_sequence = QLabel(_("New shortcut:")) self.text_new_sequence = ShortcutLineEdit(self) self.text_new_sequence.setPlaceholderText(_("Press shortcut.")) self.helper_button = HelperToolButton() self.helper_button.setIcon(QIcon()) self.label_warning = QLabel() self.label_warning.setWordWrap(True) self.label_warning.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.button_default = QPushButton(_('Default')) self.button_ok = QPushButton(_('Ok')) self.button_ok.setEnabled(False) self.button_clear = QPushButton(_('Clear')) self.button_cancel = QPushButton(_('Cancel')) button_box = QHBoxLayout() button_box.addWidget(self.button_default) button_box.addStretch(100) button_box.addWidget(self.button_ok) button_box.addWidget(self.button_clear) button_box.addWidget(self.button_cancel) # New Sequence button box self.btn_clear_sequence = create_toolbutton( self, icon=ima.icon('editclear'), tip=_("Clear all entered key sequences"), triggered=self.clear_new_sequence) self.button_back_sequence = create_toolbutton( self, icon=ima.icon('ArrowBack'), tip=_("Remove last key sequence entered"), triggered=self.back_new_sequence) newseq_btnbar = QHBoxLayout() newseq_btnbar.setSpacing(0) newseq_btnbar.setContentsMargins(0, 0, 0, 0) newseq_btnbar.addWidget(self.button_back_sequence) newseq_btnbar.addWidget(self.btn_clear_sequence) # Setup widgets self.setWindowTitle(_('Shortcut: {0}').format(self.name)) self.helper_button.setToolTip('') style = """ QToolButton { margin:1px; border: 0px solid grey; padding:0px; border-radius: 0px; }""" self.helper_button.setStyleSheet(style) icon_info.setToolTip('') icon_info.setStyleSheet(style) # Layout layout_sequence = QGridLayout() layout_sequence.setContentsMargins(0, 0, 0, 0) layout_sequence.addLayout(layout_info, 0, 0, 1, 4) layout_sequence.addItem(QSpacerItem(15, 15), 1, 0, 1, 4) layout_sequence.addWidget(self.label_current_sequence, 2, 0) layout_sequence.addWidget(self.text_current_sequence, 2, 2) layout_sequence.addWidget(self.label_new_sequence, 3, 0) layout_sequence.addWidget(self.helper_button, 3, 1) layout_sequence.addWidget(self.text_new_sequence, 3, 2) layout_sequence.addLayout(newseq_btnbar, 3, 3) layout_sequence.addWidget(self.label_warning, 4, 2, 1, 2) layout_sequence.setColumnStretch(2, 100) layout_sequence.setRowStretch(4, 100) layout = QVBoxLayout() layout.addLayout(layout_sequence) layout.addSpacing(5) layout.addLayout(button_box) self.setLayout(layout) # Signals self.button_ok.clicked.connect(self.accept_override) self.button_clear.clicked.connect(self.unbind_shortcut) self.button_cancel.clicked.connect(self.reject) self.button_default.clicked.connect(self.set_sequence_to_default) # Set all widget to no focus so that we can register <Tab> key # press event. widgets = ( self.label_warning, self.helper_button, self.text_new_sequence, self.button_clear, self.button_default, self.button_cancel, self.button_ok, self.btn_clear_sequence, self.button_back_sequence) for w in widgets: w.setFocusPolicy(Qt.NoFocus) w.clearFocus()