def _set_load_save_icons(self): """ Set icons / tooltipps for loading and saving data to / from file or clipboard depending on selected options. """ if params['CSV']['clipboard']: self.butFromTable.setIcon(QIcon(':/to_clipboard.svg')) self.butFromTable.setToolTip( "<span>Copy table to clipboard, SELECTED items are copied as " "displayed. When nothing is selected, the whole table " "is copied with full precision in decimal format.</span>") self.butToTable.setIcon(QIcon(':/from_clipboard.svg')) self.butToTable.setToolTip("<span>Copy clipboard to table.</span>") else: self.butFromTable.setIcon(QIcon(':/save.svg')) self.butFromTable.setToolTip( "<span>" "Save table to file, SELECTED items are copied as " "displayed. When nothing is selected, the whole table " "is copied with full precision in decimal format.</span>") self.butToTable.setIcon(QIcon(':/file.svg')) self.butToTable.setToolTip("<span>Load table from file.</span>") if dirs.csv_options_handle is None: qstyle_widget(self.but_csv_options, "normal") self.but_csv_options.setChecked(False) else: qstyle_widget(self.but_csv_options, "changed") self.but_csv_options.setChecked(True)
def toggle_lock_zoom(self): """ Toggle the lock zoom settings and save the plot limits in any case: when previously unlocked, settings need to be saved when previously locked, current settings can be saved without effect """ self.mpl_widget.save_limits() # save limits in any case: self.zoom_locked = not self.zoom_locked if self.zoom_locked: self.a_lk.setIcon(QIcon(':/lock-locked.svg')) if self.a_zo.isChecked(): self.a_zo.trigger() # toggle off programmatically self.a_zo.setEnabled(False) if self.a_pa.isChecked(): self.a_pa.trigger() # toggle off programmatically self.a_pa.setEnabled(False) self.a_fv.setEnabled(False) self.a_ho.setEnabled(False) else: self.a_lk.setIcon(QIcon(':/lock-unlocked.svg')) self.a_zo.setEnabled(True) self.a_pa.setEnabled(True) self.a_fv.setEnabled(True) self.a_ho.setEnabled(True) self.sig_tx.emit({'sender':__name__, 'lock_zoom':self.zoom_locked})
def _lock_freqs(self): """ Lock / unlock frequency entries: The values of frequency related widgets are stored in normalized form (w.r.t. sampling frequency)`fb.fil[0]['f_S']`. When the sampling frequency changes, absolute frequencies displayed in the widgets change their values. Most of the time, this is the desired behaviour, the properties of discrete time systems or signals are usually defined by the normalized frequencies. When the effect of varying the sampling frequency is to be analyzed, the displayed values in the widgets can be locked by pressing the Lock button. After changing the sampling frequency, normalized frequencies have to be rescaled like `f_a *= fb.fil[0]['f_S_prev'] / fb.fil[0]['f_S']` to maintain the displayed value `f_a * f_S`. This has to be accomplished by each frequency widget (currently, these are freq_specs and freq_units). The setting is stored as bool in the global dict entry `fb.fil[0]['freq_locked'`, the signal 'view_changed':'f_S' is emitted. """ if self.butLock.isChecked(): # Lock has been activated, keep displayed frequencies locked fb.fil[0]['freq_locked'] = True self.butLock.setIcon(QIcon(':/lock-locked.svg')) else: # Lock has been unlocked, scale displayed frequencies with f_S fb.fil[0]['freq_locked'] = False self.butLock.setIcon(QIcon(':/lock-unlocked.svg')) self.emit({'view_changed': 'f_S'})
def main(): """ entry point for the pyfda application see http://pyqt.sourceforge.net/Docs/PyQt4/qapplication.html : "For any GUI application using Qt, there is precisely *one* QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time. ... Since the QApplication object does so much initialization, it must be created *before* any other objects related to the user interface are created." """ # instantiate QApplication object, passing command line arguments if len(rc.qss_rc) > 20: app = QApplication(sys.argv) app.setStyleSheet(rc.qss_rc) # this is a proper style sheet style = "Using 'pyfda' style sheet." else: qstyle = QApplication.setStyle( rc.qss_rc) # no, this is just a name for a system stylesheet app = QApplication(sys.argv) if qstyle: style = 'Using system style "{0}".'.format(rc.qss_rc) else: style = 'Style "{0}" not found, falling back to default style.'.format( rc.qss_rc) app.setWindowIcon(QIcon(':/pyfda_icon.svg')) mainw = pyFDA() logger.info("Logging to {0}".format(dirs.LOG_DIR_FILE)) logger.info(style) # Sets the active window to the active widget in response to a system event. app.setActiveWindow(mainw) mainw.setWindowIcon(QIcon(':/pyfda_icon.svg')) screen_resolution = app.desktop().screenGeometry() screen_h, screen_w = screen_resolution.height(), screen_resolution.width() logger.info("Starting pyfda with screen resolution: %d x %d", screen_w, screen_h) if screen_h < 800: delta = 50 else: delta = 100 # set position + size of main window on desktop mainw.setGeometry(20, 20, screen_w - delta, screen_h - delta) # top L / top R, dx, dy # Give the keyboard input focus to this widget if this widget # or one of its parents is the active window: # mainw.setFocus() mainw.show() #start the application's exec loop, return the exit code to the OS app.exec_() # sys.exit(app.exec_()) and app.exec_() have same behaviour
def enable_plot(self, state=None): """ Toggle the enable button and setting """ if state is not None: self.enabled = state else: self.enabled = not self.enabled if self.enabled: self.a_en.setIcon(QIcon(':/circle-check.svg')) else: self.a_en.setIcon(QIcon(':/circle-x.svg'))
def butLock_clicked(self, clicked): """ Update the icon of the push button depending on its state """ if clicked: self.butLock.setIcon(QIcon(':/lock-locked.svg')) else: self.butLock.setIcon(QIcon(':/lock-unlocked.svg')) q_icon_size = self.butLock.iconSize() # <- uncomment this for manual sizing self.butLock.setIconSize(q_icon_size) dict_sig = {'sender':__name__, 'id':self.id, 'ui':'butLock'} self.sig_tx.emit(dict_sig)
def _construct_UI(self): # ===================================================================== # Controls # ===================================================================== self.butLoad = PushButton(self, icon=QIcon(':/file.svg'), checkable=False) # self.butLoad.setIconSize(q_icon_size) self.butLoad.setToolTip("Load data from file.") self.butLoad.setEnabled(False) self.lbl_info = QLabel(to_html(" coming soon ...", frmt="b")) # ---------------------------------------------------------------------- # Main Widget # ---------------------------------------------------------------------- layH_io_par = QHBoxLayout() layH_io_par.addWidget(self.butLoad) layH_io_par.addWidget(self.lbl_info) layV_io = QVBoxLayout() layV_io.addLayout(layH_io_par) layH_io = QHBoxLayout() layH_io.addLayout(layV_io) layH_io.addStretch(10) self.wdg_top = QWidget(self) self.wdg_top.setLayout(layH_io) self.wdg_top.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
def cycle_draw_grid(self, cycle=True, axes=None): """ Cycle the grid of all axes through the states 'off', 'coarse' and 'fine' and redraw the figure. Parameters ---------- cycle : bool, optional Cycle the grid display and redraw the canvas in the end when True. When false, only restore the grid settings. axes : matplotlib axes, optional When none is passed, use local `self.mpl_widget.fig.axes` Returns ------- None. """ if cycle: self.a_gr_state = (self.a_gr_state + 1) % 3 if not axes: axes = self.mpl_widget.fig.axes for ax in self.mpl_widget.fig.axes: if hasattr( ax, "is_twin" ): # the axis is a twinx() system, suppress the gridlines ax.grid(False) else: if self.a_gr_state == 0: ax.grid(False, which='both') self.a_gr.setIcon(QIcon(':/grid_none.svg')) elif self.a_gr_state == 1: ax.grid(True, which='major', lw=0.75, ls='-') ax.grid(False, which='minor') self.a_gr.setIcon(QIcon(':/grid_coarse.svg')) else: ax.grid(True, which='major', lw=0.75, ls='-') ax.grid(True, which='minor') self.a_gr.setIcon(QIcon(':/grid_fine.svg')) if cycle: self.canvas.draw( ) # don't use self.draw(), use FigureCanvasQTAgg.draw()
def _refresh_table(self): """ (Re-)Create the displayed table from self.zpk with the desired number format. TODO: Update zpk[2]? Called by: load_dict(), _clear_table(), _zero_PZ(), _delete_cells(), add_row(), _copy_to_table() """ params['FMT_pz'] = int(self.ui.spnDigits.text()) self.tblPZ.setVisible(self.ui.butEnable.isChecked()) if self.ui.butEnable.isChecked(): self.ui.butEnable.setIcon(QIcon(':/circle-x.svg')) self._restore_gain() self.tblPZ.setHorizontalHeaderLabels(["Zeros", "Poles"]) self.tblPZ.setRowCount(max(len(self.zpk[0]), len(self.zpk[1]))) self.tblPZ.blockSignals(True) for col in range(2): for row in range(len(self.zpk[col])): self._refresh_table_item(row, col) self.tblPZ.blockSignals(False) self.tblPZ.resizeColumnsToContents() self.tblPZ.resizeRowsToContents() self.tblPZ.clearSelection() else: # disable widgets self.ui.butEnable.setIcon(QIcon(':/circle-check.svg'))
def _construct_UI(self): """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ self.bfont = QFont() self.bfont.setBold(True) self.bifont = QFont() self.bifont.setBold(True) self.bifont.setItalic(True) # q_icon_size = QSize(20, 20) # optional, size is derived from butEnable ####################################################################### # frmMain # # This frame contains all the buttons ####################################################################### # --------------------------------------------- # layHDisplay # # UI Elements for controlling the display # --------------------------------------------- self.butEnable = PushButton(self, icon=QIcon(':/circle-check.svg'), checked=True) q_icon_size = self.butEnable.iconSize() # <- uncomment this for manual sizing self.butEnable.setToolTip( "<span>Show / hide filter coefficients in an editable table." " For high order systems, table display might be slow.</span>") fix_formats = ['Dec', 'Hex', 'Bin', 'CSD'] self.cmbFormat = QComboBox(self) model = self.cmbFormat.model() item = QtGui.QStandardItem('Float') item.setData('child', Qt.AccessibleDescriptionRole) model.appendRow(item) item = QtGui.QStandardItem('Fixp.:') item.setData('parent', Qt.AccessibleDescriptionRole) item.setData(0, QtGui.QFont.Bold) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) # | Qt.ItemIsSelectable)) model.appendRow(item) for idx in range(len(fix_formats)): item = QtGui.QStandardItem(fix_formats[idx]) # item.setForeground(QtGui.QColor('red')) model.appendRow(item) self.cmbFormat.insertSeparator(1) qset_cmb_box(self.cmbFormat, 'float') self.cmbFormat.setToolTip('Set the display format.') self.cmbFormat.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.spnDigits = QSpinBox(self) self.spnDigits.setRange(0, 16) self.spnDigits.setValue(params['FMT_ba']) self.spnDigits.setToolTip("Number of digits to display.") self.lblDigits = QLabel("Digits", self) self.lblDigits.setFont(self.bifont) self.cmbQFrmt = QComboBox(self) q_formats = [('Norm. Frac.', 'qnfrac'), ('Integer', 'qint'), ('Fractional', 'qfrac')] for q in q_formats: self.cmbQFrmt.addItem(*q) self.lbl_W = QLabel("W = ", self) self.lbl_W.setFont(self.bifont) self.ledW = QLineEdit(self) self.ledW.setToolTip("Specify total wordlength.") self.ledW.setText("16") self.ledW.setMaxLength(2) # maximum of 2 digits self.ledW.setFixedWidth(30) # width of lineedit in points(?) layHDisplay = QHBoxLayout() layHDisplay.setAlignment(Qt.AlignLeft) layHDisplay.addWidget(self.butEnable) layHDisplay.addWidget(self.cmbFormat) layHDisplay.addWidget(self.spnDigits) layHDisplay.addWidget(self.lblDigits) layHDisplay.addWidget(self.cmbQFrmt) layHDisplay.addWidget(self.lbl_W) layHDisplay.addWidget(self.ledW) layHDisplay.addStretch() ####################################################################### # frmButtonsCoeffs # # This frame contains all buttons for manipulating coefficients ####################################################################### # ----------------------------------------------------------------- # layHButtonsCoeffs1 # # UI Elements for loading / storing / manipulating cells and rows # ----------------------------------------------------------------- self.cmbFilterType = QComboBox(self) self.cmbFilterType.setObjectName("comboFilterType") self.cmbFilterType.setToolTip( "<span>Select between IIR and FIR filter for manual entry." "Changing the type reloads the filter from the filter dict.</span>") self.cmbFilterType.addItems(["FIR", "IIR"]) self.cmbFilterType.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.butAddCells = QPushButton(self) self.butAddCells.setIcon(QIcon(':/row_insert_above.svg')) self.butAddCells.setIconSize(q_icon_size) self.butAddCells.setToolTip( "<span>Select cells to insert a new cell above each selected cell. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, add a row at the end.</span>") self.butDelCells = QPushButton(self) self.butDelCells.setIcon(QIcon(':/row_delete.svg')) self.butDelCells.setIconSize(q_icon_size) self.butDelCells.setToolTip( "<span>Delete selected cell(s) from the table. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, delete the last row.</span>") self.butSave = QPushButton(self) self.butSave.setIcon(QIcon(':/upload.svg')) self.butSave.setIconSize(q_icon_size) self.butSave.setToolTip( "<span>Copy coefficient table to filter dict and update all plots" "and widgets.</span>") self.butLoad = QPushButton(self) self.butLoad.setIcon(QIcon(':/download.svg')) self.butLoad.setIconSize(q_icon_size) self.butLoad.setToolTip("Reload coefficient table from filter dict.") self.butClear = QPushButton(self) self.butClear.setIcon(QIcon(':/trash.svg')) self.butClear.setIconSize(q_icon_size) self.butClear.setToolTip("Clear all table entries.") self.butFromTable = QPushButton(self) self.butFromTable.setIconSize(q_icon_size) self.butToTable = QPushButton(self) self.butToTable.setIconSize(q_icon_size) self.but_csv_options = PushButton(self, icon=QIcon(':/settings.svg'), checked=False) self.but_csv_options.setIconSize(q_icon_size) self.but_csv_options.setToolTip( "<span>Select CSV format and whether " "to copy to/from clipboard or file.</span>") self._set_load_save_icons() # initialize icon / button settings layHButtonsCoeffs1 = QHBoxLayout() layHButtonsCoeffs1.addWidget(self.cmbFilterType) layHButtonsCoeffs1.addWidget(self.butAddCells) layHButtonsCoeffs1.addWidget(self.butDelCells) layHButtonsCoeffs1.addWidget(self.butClear) layHButtonsCoeffs1.addWidget(self.butSave) layHButtonsCoeffs1.addWidget(self.butLoad) layHButtonsCoeffs1.addWidget(self.butFromTable) layHButtonsCoeffs1.addWidget(self.butToTable) layHButtonsCoeffs1.addWidget(self.but_csv_options) layHButtonsCoeffs1.addStretch() # ---------------------------------------------------------------------- # layHButtonsCoeffs2 # # Eps / set zero settings # --------------------------------------------------------------------- self.butSetZero = QPushButton("= 0", self) self.butSetZero.setToolTip( "<span>Set selected coefficients = 0 with a magnitude < ε. " "When nothing is selected, test the whole table.</span>") self.butSetZero.setIconSize(q_icon_size) lblEps = QLabel(self) lblEps.setText("<b><i>for b, a</i> <</b>") self.ledEps = QLineEdit(self) self.ledEps.setToolTip("Specify tolerance value.") layHButtonsCoeffs2 = QHBoxLayout() layHButtonsCoeffs2.addWidget(self.butSetZero) layHButtonsCoeffs2.addWidget(lblEps) layHButtonsCoeffs2.addWidget(self.ledEps) layHButtonsCoeffs2.addStretch() # ------------------------------------------------------------------- # Now put the ButtonsCoeffs HBoxes into frmButtonsCoeffs # --------------------------------------------------------------------- layVButtonsCoeffs = QVBoxLayout() layVButtonsCoeffs.addLayout(layHButtonsCoeffs1) layVButtonsCoeffs.addLayout(layHButtonsCoeffs2) layVButtonsCoeffs.setContentsMargins(0, 5, 0, 0) # This frame encompasses all Quantization Settings self.frmButtonsCoeffs = QFrame(self) self.frmButtonsCoeffs.setLayout(layVButtonsCoeffs) # ###################################################################### # frmQSettings # # This frame contains all quantization settings # ###################################################################### # ------------------------------------------------------------------- # layHW_Scale # # QFormat and scale settings # --------------------------------------------------------------------- lbl_Q = QLabel("Q =", self) lbl_Q.setFont(self.bifont) self.ledWI = QLineEdit(self) self.ledWI.setToolTip("Specify number of integer bits.") self.ledWI.setText("0") self.ledWI.setMaxLength(2) # maximum of 2 digits self.ledWI.setFixedWidth(30) # width of lineedit in points(?) self.lblDot = QLabel(".", self) # class attribute, visibility is toggled self.lblDot.setFont(self.bfont) self.ledWF = QLineEdit(self) self.ledWF.setToolTip("Specify number of fractional bits.") self.ledWF.setText("15") self.ledWF.setMaxLength(2) # maximum of 2 digits # self.ledWF.setFixedWidth(30) # width of lineedit in points(?) self.ledWF.setMaximumWidth(30) self.lblScale = QLabel("<b><i>Scale</i> =</b>", self) self.ledScale = QLineEdit(self) self.ledScale.setToolTip( "Set the scale for converting float to fixpoint representation.") self.ledScale.setText(str(1)) self.ledScale.setEnabled(False) layHWI_WF = QHBoxLayout() layHWI_WF.addWidget(lbl_Q) layHWI_WF.addWidget(self.ledWI) layHWI_WF.addWidget(self.lblDot) layHWI_WF.addWidget(self.ledWF) layHWI_WF.addStretch() layHScale = QHBoxLayout() layHScale.addWidget(self.lblScale) layHScale.addWidget(self.ledScale) layHScale.addStretch() layHW_Scale = QHBoxLayout() layHW_Scale.addLayout(layHWI_WF) layHW_Scale.addLayout(layHScale) # ------------------------------------------------------------------- # layGQOpt # # Quantization / Overflow / MSB / LSB settings # --------------------------------------------------------------------- lblQOvfl = QLabel("Ovfl.:", self) lblQOvfl.setFont(self.bifont) lblQuant = QLabel("Quant.:", self) lblQuant.setFont(self.bifont) self.cmbQOvfl = QComboBox(self) qOvfl = ['wrap', 'sat'] self.cmbQOvfl.addItems(qOvfl) qset_cmb_box(self.cmbQOvfl, 'sat') self.cmbQOvfl.setToolTip("Select overflow behaviour.") # ComboBox size is adjusted automatically to fit the longest element self.cmbQOvfl.setSizeAdjustPolicy(QComboBox.AdjustToContents) layHQOvflOpt = QHBoxLayout() layHQOvflOpt.addWidget(lblQOvfl) layHQOvflOpt.addWidget(self.cmbQOvfl) layHQOvflOpt.addStretch() self.cmbQuant = QComboBox(self) qQuant = ['none', 'round', 'fix', 'floor'] self.cmbQuant.addItems(qQuant) qset_cmb_box(self.cmbQuant, 'round') self.cmbQuant.setToolTip("Select the kind of quantization.") self.cmbQuant.setSizeAdjustPolicy(QComboBox.AdjustToContents) layHQuantOpt = QHBoxLayout() layHQuantOpt.addWidget(lblQuant) layHQuantOpt.addWidget(self.cmbQuant) layHQuantOpt.addStretch() self.butQuant = QPushButton(self) self.butQuant.setToolTip( "<span>Quantize selected coefficients / " "whole table with specified settings.</span>") self.butQuant.setIcon(QIcon(':/quantize.svg')) self.butQuant.setIconSize(q_icon_size) self.butQuant.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) lblMSBtxt = QLabel(self) lblMSBtxt.setText("<b><i>MSB</i><sub>10</sub> =</b>") self.lblMSB = QLabel(self) layHMSB = QHBoxLayout() layHMSB.addWidget(lblMSBtxt) layHMSB.addWidget(self.lblMSB) layHMSB.addStretch() lblLSBtxt = QLabel(self) lblLSBtxt.setText("<b><i>LSB</i><sub>10</sub> =</b>") self.lblLSB = QLabel(self) layHLSB = QHBoxLayout() layHLSB.addWidget(lblLSBtxt) layHLSB.addWidget(self.lblLSB) layHLSB.addStretch() layGQOpt = QGridLayout() layGQOpt.addLayout(layHQOvflOpt, 0, 0) layGQOpt.addLayout(layHQuantOpt, 0, 1) layGQOpt.addWidget(self.butQuant, 0, 2, Qt.AlignCenter) layGQOpt.addLayout(layHMSB, 1, 0) layGQOpt.addLayout(layHLSB, 1, 1) # ------------------------------------------------------------------- # Display MAX # --------------------------------------------------------------------- lblMAXtxt = QLabel(self) lblMAXtxt.setText("<b><i>Max =</i></b>") self.lblMAX = QLabel(self) layHCoeffs_MAX = QHBoxLayout() layHCoeffs_MAX.addWidget(lblMAXtxt) layHCoeffs_MAX.addWidget(self.lblMAX) layHCoeffs_MAX.addStretch() ####################################################################### # Now put all the coefficient HBoxes into frmQSettings # --------------------------------------------------------------------- layVButtonsQ = QVBoxLayout() layVButtonsQ.addLayout(layHW_Scale) layVButtonsQ.addLayout(layGQOpt) layVButtonsQ.addLayout(layHCoeffs_MAX) layVButtonsQ.setContentsMargins(0, 0, 0, 0) # This frame encompasses all Quantization Settings self.frmQSettings = QFrame(self) self.frmQSettings.setLayout(layVButtonsQ) ####################################################################### # ######################## Main UI Layout ############################ ####################################################################### # layout for frame (UI widget) layVMainF = QVBoxLayout() layVMainF.addLayout(layHDisplay) layVMainF.addWidget(self.frmQSettings) layVMainF.addWidget(QHLine()) layVMainF.addWidget(self.frmButtonsCoeffs) # This frame encompasses all UI elements frmMain = QFrame(self) frmMain.setLayout(layVMainF) layVMain = QVBoxLayout() # the following affects only the first widget (intended here) layVMain.setAlignment(Qt.AlignTop) layVMain.addWidget(frmMain) layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) ####################################################################### # --- set initial values from dict ------------ self.spnDigits.setValue(params['FMT_ba']) self.ledEps.setText(str(self.eps)) # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.but_csv_options.clicked.connect(self._open_csv_win)
def __init__(self, canv, mpl_widget, *args, **kwargs): NavigationToolbar.__init__(self, canv, mpl_widget, *args, **kwargs) #self.canvas = canv self.mpl_widget = mpl_widget #------------------------------------------------------------------------------ #---------------- Construct Toolbar using QRC icons ------------------- # ENABLE: # self.a_en = self.addAction(QIcon(':/circle-x.svg'), 'Enable Update', self.enable_plot) # self.a_en.setToolTip('Enable / disable plot') # self.a_en.setCheckable(True) # self.a_en.setChecked(True) ## self.a.setEnabled(False) # self.addSeparator() #--------------------------------------------- #--------------------------------------------- # HOME: #--------------------------------------------- self.a_ho = self.addAction(QIcon(':/home.svg'), 'Home', self.home) self.a_ho.setToolTip('Reset zoom') # BACK: self.a_ba = self.addAction(QIcon(':/action-undo.svg'), 'Back', self.back) self.a_ba.setToolTip('Back to previous zoom') #--------------------------------------------- # FORWARD: #--------------------------------------------- self.a_fw = self.addAction(QIcon(':/action-redo.svg'), 'Forward', self.forward) self.a_fw.setToolTip('Forward to next zoom') #--------------------------------------------- self.addSeparator() #--------------------------------------------- #--------------------------------------------- # PAN: #--------------------------------------------- self.a_pa = self.addAction(QIcon(':/move.svg'), 'Pan', self.pan) self.a_pa.setToolTip("Pan axes with left mouse button, zoom with right,\n" "pressing x / y / CTRL keys constrains to horizontal / vertical / diagonal movements.") self._actions['pan'] = self.a_pa self.a_pa.setCheckable(True) #--------------------------------------------- # ZOOM RECTANGLE: #--------------------------------------------- self.a_zo = self.addAction(QIcon(':/magnifying-glass.svg'), 'Zoom', self.zoom) self.a_zo.setToolTip("Zoom in / out to rectangle with left / right mouse button,\n" "pressing x / y keys constrains zoom to horizontal / vertical direction.") self._actions['zoom'] = self.a_zo self.a_zo.setCheckable(True) #--------------------------------------------- # FULL VIEW: #--------------------------------------------- self.a_fv = self.addAction(QIcon(':/fullscreen-enter.svg'), \ 'Zoom full extent', self.mpl_widget.plt_full_view) self.a_fv.setToolTip('Zoom to full extent') #--------------------------------------------- # LOCK ZOOM: #--------------------------------------------- self.a_lk = self.addAction(QIcon(':/lock-unlocked.svg'), \ 'Lock zoom', self.toggle_lock_zoom) self.a_lk.setCheckable(True) self.a_lk.setChecked(False) self.a_lk.setToolTip('Lock / unlock current zoom setting') #--------------------------------------------- # TRACKING CURSOR: #--------------------------------------------- if MPL_CURS: self.a_cr = self.addAction(QIcon(':/map-marker.svg'), \ 'Cursor', self.mpl_widget.toggle_cursor) self.a_cr.setCheckable(True) self.a_cr.setChecked(False) self.a_cr.setToolTip('Tracking Cursor') # -------------------------------------- self.addSeparator() # -------------------------------------- #--------------------------------------------- # GRID: #--------------------------------------------- self.a_gr = self.addAction(QIcon(':/grid_coarse.svg'), 'Grid', self.cycle_draw_grid) self.a_gr.setToolTip('Cycle grid: Off / coarse / fine') self.a_gr_state = 2 # 0: off, 1: major, 2: minor #--------------------------------------------- # REDRAW: #--------------------------------------------- #self.a_rd = self.addAction(QIcon(':/brush.svg'), 'Redraw', self.mpl_widget.redraw) #self.a_rd.setToolTip('Redraw Plot') # -------------------------------------- # SAVE: # -------------------------------------- self.a_sv = self.addAction(QIcon(':/save.svg'), 'Save', self.save_figure) self.a_sv.setToolTip('Save the figure') self.cb = fb.clipboard self.a_cb = self.addAction(QIcon(':/clipboard.svg'), 'To Clipboard', self.mpl2Clip) self.a_cb.setToolTip('Copy to clipboard in png format.') self.a_cb.setShortcut("Ctrl+C") # -------------------------------------- self.addSeparator() # -------------------------------------- # -------------------------------------- # SETTINGS: # -------------------------------------- if figureoptions is not None: self.a_op = self.addAction(QIcon(':/settings.svg'), 'Customize', self.edit_parameters) self.a_op.setToolTip('Edit curves line and axes parameters') # self.buttons = {} # -------------------------------------- # PRINT COORDINATES (only when mplcursors is not available): # -------------------------------------- # Add the x,y location widget at the right side of the toolbar # The stretch factor is 1 which means any resizing of the toolbar # will resize this label instead of the buttons. # -------------------------------------- if not MPL_CURS and self.coordinates: self.addSeparator() self.locLabel = QLabel("", self) self.locLabel.setAlignment( QtCore.Qt.AlignRight | QtCore.Qt.AlignTop) self.locLabel.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored)) labelAction = self.addWidget(self.locLabel) labelAction.setVisible(True) #--------------------------------------------- # HELP: #--------------------------------------------- self.a_he = self.addAction(QIcon(':/help.svg'), 'help', self.help) self.a_he.setToolTip('Open help page from https://pyfda.rtfd.org in browser') self.a_he.setDisabled(True)
def _construct_UI(self): """ Construct the User Interface """ self.layVMain = QVBoxLayout() # Widget main layout f_units = ['k', 'f_S', 'f_Ny', 'Hz', 'kHz', 'MHz', 'GHz'] self.t_units = ['', 'T_S', 'T_S', 's', 'ms', r'$\mu$s', 'ns'] bfont = QFont() bfont.setBold(True) self.lblUnits = QLabel(self) self.lblUnits.setText("Freq. Unit") self.lblUnits.setFont(bfont) self.fs_old = fb.fil[0]['f_S'] # store current sampling frequency self.lblF_S = QLabel(self) self.lblF_S.setText(to_html("f_S =", frmt='bi')) self.ledF_S = QLineEdit() self.ledF_S.setText(str(fb.fil[0]["f_S"])) self.ledF_S.setObjectName("f_S") self.ledF_S.installEventFilter(self) # filter events self.butLock = QToolButton(self) self.butLock.setIcon(QIcon(':/lock-unlocked.svg')) self.butLock.setCheckable(True) self.butLock.setChecked(False) self.butLock.setToolTip( "<span><b>Unlocked:</b> When f_S is changed, all frequency related " "widgets are updated, normalized frequencies stay the same.<br />" "<b>Locked:</b> When f_S is changed, displayed absolute frequency " "values don't change but normalized frequencies do.</span>") # self.butLock.setStyleSheet("QToolButton:checked {font-weight:bold}") layHF_S = QHBoxLayout() layHF_S.addWidget(self.ledF_S) layHF_S.addWidget(self.butLock) self.cmbUnits = QComboBox(self) self.cmbUnits.setObjectName("cmbUnits") self.cmbUnits.addItems(f_units) self.cmbUnits.setToolTip( 'Select whether frequencies are specified w.r.t. \n' 'the sampling frequency "f_S", to the Nyquist frequency \n' 'f_Ny = f_S/2 or as absolute values. "k" specifies frequencies w.r.t. f_S ' 'but plots graphs over the frequency index k.') self.cmbUnits.setCurrentIndex(1) # self.cmbUnits.setItemData(0, (0,QColor("#FF333D"),Qt.BackgroundColorRole))# # self.cmbUnits.setItemData(0, (QFont('Verdana', bold=True), Qt.FontRole) fRanges = [("0...½", "half"), ("0...1", "whole"), ("-½...½", "sym")] self.cmbFRange = QComboBox(self) self.cmbFRange.setObjectName("cmbFRange") for f in fRanges: self.cmbFRange.addItem(f[0], f[1]) self.cmbFRange.setToolTip("Select frequency range (whole or half).") self.cmbFRange.setCurrentIndex(0) # Combobox resizes with longest entry self.cmbUnits.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.cmbFRange.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.butSort = QToolButton(self) self.butSort.setText("Sort") self.butSort.setIcon(QIcon(':/sort-ascending.svg')) #self.butDelCells.setIconSize(q_icon_size) self.butSort.setCheckable(True) self.butSort.setChecked(True) self.butSort.setToolTip( "Sort frequencies in ascending order when pushed.") self.butSort.setStyleSheet("QToolButton:checked {font-weight:bold}") self.layHUnits = QHBoxLayout() self.layHUnits.addWidget(self.cmbUnits) self.layHUnits.addWidget(self.cmbFRange) self.layHUnits.addWidget(self.butSort) # Create a gridLayout consisting of QLabel and QLineEdit fields # for setting f_S, the units and the actual frequency specs: self.layGSpecWdg = QGridLayout() # sublayout for spec fields self.layGSpecWdg.addWidget(self.lblF_S, 1, 0) # self.layGSpecWdg.addWidget(self.ledF_S,1,1) self.layGSpecWdg.addLayout(layHF_S, 1, 1) self.layGSpecWdg.addWidget(self.lblUnits, 0, 0) self.layGSpecWdg.addLayout(self.layHUnits, 0, 1) frmMain = QFrame(self) frmMain.setLayout(self.layGSpecWdg) self.layVMain.addWidget(frmMain) self.layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(self.layVMain) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.cmbUnits.currentIndexChanged.connect(self.update_UI) self.butLock.clicked.connect(self._lock_freqs) self.cmbFRange.currentIndexChanged.connect(self._freq_range) self.butSort.clicked.connect(self._store_sort_flag) # ---------------------------------------------------------------------- self.update_UI() # first-time initialization
def __init__(self): super().__init__() """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ # initial settings self.N_start = 0 self.N_user = 0 self.N = 0 self.N_frame_user = 0 self.N_frame = 0 # time self.plt_time_resp = "stem" self.plt_time_stim = "line" self.plt_time_stmq = "none" self.plt_time_spgr = "none" self.bottom_t = -80 # initial value for log. scale (time) self.time_nfft_spgr = 256 # number of fft points per spectrogram segment self.time_ovlp_spgr = 128 # number of overlap points between spectrogram segments self.mode_spgr_time = "psd" # frequency self.cmb_freq_display_item = "mag" self.plt_freq_resp = "line" self.plt_freq_stim = "none" self.plt_freq_stmq = "none" self.bottom_f = -120 # initial value for log. scale self.param = None self.f_scale = fb.fil[0]['f_S'] self.t_scale = fb.fil[0]['T_S'] # list of windows that are available for FFT analysis win_names_list = [ "Boxcar", "Rectangular", "Barthann", "Bartlett", "Blackman", "Blackmanharris", "Bohman", "Cosine", "Dolph-Chebyshev", "Flattop", "General Gaussian", "Gauss", "Hamming", "Hann", "Kaiser", "Nuttall", "Parzen", "Slepian", "Triangular", "Tukey" ] self.cur_win_name = "Rectangular" # set initial window type # initialize windows dict with the list above self.win_dict = get_windows_dict(win_names_list=win_names_list, cur_win_name=self.cur_win_name) # instantiate FFT window with default windows dict self.fft_widget = Plot_FFT_win(self, self.win_dict, sym=False, title="pyFDA Spectral Window Viewer") # hide window initially, this is modeless i.e. a non-blocking popup window self.fft_widget.hide() # data / icon / tooltipp (none) for plotting styles self.plot_styles_list = [ ("Plot style"), ("none", QIcon(":/plot_style-none"), "off"), ("dots*", QIcon(":/plot_style-mkr"), "markers only"), ("line", QIcon(":/plot_style-line"), "line"), ("line*", QIcon(":/plot_style-line-mkr"), "line + markers"), ("stem", QIcon(":/plot_style-stem"), "stems"), ("stem*", QIcon(":/plot_style-stem-mkr"), "stems + markers"), ("steps", QIcon(":/plot_style-steps"), "steps"), ("steps*", QIcon(":/plot_style-steps-mkr"), "steps + markers") ] self.cmb_time_spgr_items = [ "<span>Show Spectrogram for selected signal.</span>", ("none", "None", ""), ("xn", "x[n]", "input"), ("xqn", "x_q[n]", "quantized input"), ("yn", "y[n]", "output") ] self.cmb_mode_spgr_time_items = [ "<span>Spectrogram display mode.</span>", ("psd", "PSD", "<span>Power Spectral Density, either per bin or referred to " "<i>f<sub>S</sub></i></span>"), ("magnitude", "Mag.", "Signal magnitude"), ("angle", "Angle", "Phase, wrapped to ± π"), ("phase", "Phase", "Phase (unwrapped)") ] # self.N self.cmb_freq_display_items = [ "<span>Select how to display the spectrum.</span>", ("mag", "Magnitude", "<span>Spectral magnitude</span>"), ("mag_phi", "Mag. / Phase", "<span>Magnitude and phase.</span>"), ("re_im", "Re. / Imag.", "<span>Real and imaginary part of spectrum.</span>") ] self._construct_UI() # self._enable_stim_widgets() self.update_N(emit=False) # also updates window function and win_dict
def _construct_UI(self): # ----------- --------------------------------------------------- # Run control widgets # --------------------------------------------------------------- # self.but_auto_run = QPushButtonRT(text=to_html("Auto", frmt="b"), margin=0) self.but_auto_run = QPushButton(" Auto", self) self.but_auto_run.setObjectName("but_auto_run") self.but_auto_run.setToolTip( "<span>Update response automatically when " "parameters have been changed.</span>") # self.but_auto_run.setMaximumWidth(qtext_width(text=" Auto ")) self.but_auto_run.setCheckable(True) self.but_auto_run.setChecked(True) but_height = self.but_auto_run.sizeHint().height() self.but_run = QPushButton(self) self.but_run.setIcon(QIcon(":/play.svg")) self.but_run.setIconSize(QSize(but_height, but_height)) self.but_run.setFixedSize(QSize(2 * but_height, but_height)) self.but_run.setToolTip("Run simulation") self.but_run.setEnabled(True) self.cmb_sim_select = QComboBox(self) self.cmb_sim_select.addItems(["Float", "Fixpoint"]) qset_cmb_box(self.cmb_sim_select, "Float") self.cmb_sim_select.setToolTip("<span>Simulate floating-point or " "fixpoint response.</span>") self.lbl_N_points = QLabel(to_html("N", frmt='bi') + " =", self) self.led_N_points = QLineEdit(self) self.led_N_points.setText(str(self.N)) self.led_N_points.setToolTip( "<span>Last data point. " "<i>N</i> = 0 tries to choose for you.</span>") self.led_N_points.setMaximumWidth(qtext_width(N_x=8)) self.lbl_N_start = QLabel(to_html("N_0", frmt='bi') + " =", self) self.led_N_start = QLineEdit(self) self.led_N_start.setText(str(self.N_start)) self.led_N_start.setToolTip("<span>First point to plot.</span>") self.led_N_start.setMaximumWidth(qtext_width(N_x=8)) self.lbl_N_frame = QLabel(to_html("ΔN", frmt='bi') + " =", self) self.led_N_frame = QLineEdit(self) self.led_N_frame.setText(str(self.N_frame)) self.led_N_frame.setToolTip( "<span>Frame length; longer frames calculate faster but calculation cannot " "be stopped so quickly. " "<i>ΔN</i> = 0 calculates all samples in one frame.</span>") self.led_N_frame.setMaximumWidth(qtext_width(N_x=8)) self.prg_wdg = QProgressBar(self) self.prg_wdg.setFixedHeight(but_height) self.prg_wdg.setFixedWidth(qtext_width(N_x=6)) self.prg_wdg.setMinimum(0) self.prg_wdg.setValue(0) self.but_toggle_stim_options = PushButton(" Stimuli ", checked=True) self.but_toggle_stim_options.setObjectName("but_stim_options") self.but_toggle_stim_options.setToolTip( "<span>Show / hide stimulus options.</span>") self.lbl_stim_cmplx_warn = QLabel(self) self.lbl_stim_cmplx_warn = QLabel(to_html("Cmplx!", frmt='b'), self) self.lbl_stim_cmplx_warn.setToolTip( '<span>Signal is complex valued; ' 'single-sided and H<sub>id</sub> spectra may be wrong.</span>') self.lbl_stim_cmplx_warn.setStyleSheet("background-color : yellow;" "border : 1px solid grey") self.but_fft_wdg = QPushButton(self) self.but_fft_wdg.setIcon(QIcon(":/fft.svg")) self.but_fft_wdg.setIconSize(QSize(but_height, but_height)) self.but_fft_wdg.setFixedSize(QSize(int(1.5 * but_height), but_height)) self.but_fft_wdg.setToolTip( '<span>Show / hide FFT widget (select window type ' ' and display its properties).</span>') self.but_fft_wdg.setCheckable(True) self.but_fft_wdg.setChecked(False) self.qfft_win_select = QFFTWinSelector(self, self.win_dict) self.but_fx_scale = PushButton(" FX:Int ") self.but_fx_scale.setObjectName("but_fx_scale") self.but_fx_scale.setToolTip( "<span>Display data with integer (fixpoint) scale.</span>") self.but_fx_range = PushButton(" FX:Range") self.but_fx_range.setObjectName("but_fx_limits") self.but_fx_range.setToolTip( "<span>Display limits of fixpoint range.</span>") layH_ctrl_run = QHBoxLayout() layH_ctrl_run.addWidget(self.but_auto_run) layH_ctrl_run.addWidget(self.but_run) layH_ctrl_run.addWidget(self.cmb_sim_select) layH_ctrl_run.addSpacing(10) layH_ctrl_run.addWidget(self.lbl_N_start) layH_ctrl_run.addWidget(self.led_N_start) layH_ctrl_run.addWidget(self.lbl_N_points) layH_ctrl_run.addWidget(self.led_N_points) layH_ctrl_run.addWidget(self.lbl_N_frame) layH_ctrl_run.addWidget(self.led_N_frame) layH_ctrl_run.addWidget(self.prg_wdg) layH_ctrl_run.addSpacing(20) layH_ctrl_run.addWidget(self.but_toggle_stim_options) layH_ctrl_run.addSpacing(5) layH_ctrl_run.addWidget(self.lbl_stim_cmplx_warn) layH_ctrl_run.addSpacing(20) layH_ctrl_run.addWidget(self.but_fft_wdg) layH_ctrl_run.addWidget(self.qfft_win_select) layH_ctrl_run.addSpacing(20) layH_ctrl_run.addWidget(self.but_fx_scale) layH_ctrl_run.addWidget(self.but_fx_range) layH_ctrl_run.addStretch(10) # layH_ctrl_run.setContentsMargins(*params['wdg_margins']) self.wdg_ctrl_run = QWidget(self) self.wdg_ctrl_run.setLayout(layH_ctrl_run) # --- end of run control ---------------------------------------- # ----------- --------------------------------------------------- # Controls for time domain # --------------------------------------------------------------- self.lbl_plt_time_stim = QLabel(to_html("Stim. x", frmt='bi'), self) self.cmb_plt_time_stim = QComboBox(self) qcmb_box_populate(self.cmb_plt_time_stim, self.plot_styles_list, self.plt_time_stim) self.cmb_plt_time_stim.setToolTip( "<span>Plot style for stimulus.</span>") self.lbl_plt_time_stmq = QLabel( to_html(" Fixp. Stim. x_Q", frmt='bi'), self) self.cmb_plt_time_stmq = QComboBox(self) qcmb_box_populate(self.cmb_plt_time_stmq, self.plot_styles_list, self.plt_time_stmq) self.cmb_plt_time_stmq.setToolTip( "<span>Plot style for <em>fixpoint</em> " "(quantized) stimulus.</span>") lbl_plt_time_resp = QLabel(to_html(" Resp. y", frmt='bi'), self) self.cmb_plt_time_resp = QComboBox(self) qcmb_box_populate(self.cmb_plt_time_resp, self.plot_styles_list, self.plt_time_resp) self.cmb_plt_time_resp.setToolTip( "<span>Plot style for response.</span>") self.lbl_win_time = QLabel(to_html(" Win", frmt='bi'), self) self.chk_win_time = QCheckBox(self) self.chk_win_time.setObjectName("chk_win_time") self.chk_win_time.setToolTip( '<span>Plot FFT windowing function.</span>') self.chk_win_time.setChecked(False) line1 = QVLine() line2 = QVLine(width=5) self.but_log_time = PushButton(" dB") self.but_log_time.setObjectName("but_log_time") self.but_log_time.setToolTip( "<span>Logarithmic scale for y-axis.</span>") lbl_plt_time_spgr = QLabel(to_html("Spectrogram", frmt='bi'), self) self.cmb_plt_time_spgr = QComboBox(self) qcmb_box_populate(self.cmb_plt_time_spgr, self.cmb_time_spgr_items, self.plt_time_spgr) spgr_en = self.plt_time_spgr != "none" self.cmb_mode_spgr_time = QComboBox(self) qcmb_box_populate(self.cmb_mode_spgr_time, self.cmb_mode_spgr_time_items, self.mode_spgr_time) self.cmb_mode_spgr_time.setVisible(spgr_en) self.lbl_byfs_spgr_time = QLabel(to_html(" per f_S", frmt='b'), self) self.lbl_byfs_spgr_time.setVisible(spgr_en) self.chk_byfs_spgr_time = QCheckBox(self) self.chk_byfs_spgr_time.setObjectName("chk_log_spgr") self.chk_byfs_spgr_time.setToolTip("<span>Display spectral density " "i.e. scale by f_S</span>") self.chk_byfs_spgr_time.setChecked(True) self.chk_byfs_spgr_time.setVisible(spgr_en) self.but_log_spgr_time = QPushButton("dB") self.but_log_spgr_time.setMaximumWidth(qtext_width(text=" dB")) self.but_log_spgr_time.setObjectName("but_log_spgr") self.but_log_spgr_time.setToolTip( "<span>Logarithmic scale for spectrogram.</span>") self.but_log_spgr_time.setCheckable(True) self.but_log_spgr_time.setChecked(True) self.but_log_spgr_time.setVisible(spgr_en) self.lbl_time_nfft_spgr = QLabel(to_html(" N_FFT =", frmt='bi'), self) self.lbl_time_nfft_spgr.setVisible(spgr_en) self.led_time_nfft_spgr = QLineEdit(self) self.led_time_nfft_spgr.setText(str(self.time_nfft_spgr)) self.led_time_nfft_spgr.setToolTip("<span>Number of FFT points per " "spectrogram segment.</span>") self.led_time_nfft_spgr.setVisible(spgr_en) self.lbl_time_ovlp_spgr = QLabel(to_html(" N_OVLP =", frmt='bi'), self) self.lbl_time_ovlp_spgr.setVisible(spgr_en) self.led_time_ovlp_spgr = QLineEdit(self) self.led_time_ovlp_spgr.setText(str(self.time_ovlp_spgr)) self.led_time_ovlp_spgr.setToolTip( "<span>Number of overlap data points " "between spectrogram segments.</span>") self.led_time_ovlp_spgr.setVisible(spgr_en) self.lbl_log_bottom_time = QLabel(to_html("min =", frmt='bi'), self) self.led_log_bottom_time = QLineEdit(self) self.led_log_bottom_time.setText(str(self.bottom_t)) self.led_log_bottom_time.setMaximumWidth(qtext_width(N_x=8)) self.led_log_bottom_time.setToolTip( "<span>Minimum display value for time and spectrogram plots with log. scale." "</span>") self.lbl_log_bottom_time.setVisible( self.but_log_time.isChecked() or (spgr_en and self.but_log_spgr_time.isChecked())) self.led_log_bottom_time.setVisible( self.lbl_log_bottom_time.isVisible()) # self.lbl_colorbar_time = QLabel(to_html(" Col.bar", frmt='b'), self) # self.lbl_colorbar_time.setVisible(spgr_en) # self.chk_colorbar_time = QCheckBox(self) # self.chk_colorbar_time.setObjectName("chk_colorbar_time") # self.chk_colorbar_time.setToolTip("<span>Enable colorbar</span>") # self.chk_colorbar_time.setChecked(True) # self.chk_colorbar_time.setVisible(spgr_en) layH_ctrl_time = QHBoxLayout() layH_ctrl_time.addWidget(self.lbl_plt_time_stim) layH_ctrl_time.addWidget(self.cmb_plt_time_stim) # layH_ctrl_time.addWidget(self.lbl_plt_time_stmq) layH_ctrl_time.addWidget(self.cmb_plt_time_stmq) # layH_ctrl_time.addWidget(lbl_plt_time_resp) layH_ctrl_time.addWidget(self.cmb_plt_time_resp) # layH_ctrl_time.addWidget(self.lbl_win_time) layH_ctrl_time.addWidget(self.chk_win_time) layH_ctrl_time.addSpacing(5) layH_ctrl_time.addWidget(line1) layH_ctrl_time.addSpacing(5) # layH_ctrl_time.addWidget(self.lbl_log_bottom_time) layH_ctrl_time.addWidget(self.led_log_bottom_time) layH_ctrl_time.addWidget(self.but_log_time) layH_ctrl_time.addSpacing(5) layH_ctrl_time.addWidget(line2) layH_ctrl_time.addSpacing(5) # layH_ctrl_time.addWidget(lbl_plt_time_spgr) layH_ctrl_time.addWidget(self.cmb_plt_time_spgr) layH_ctrl_time.addWidget(self.cmb_mode_spgr_time) layH_ctrl_time.addWidget(self.lbl_byfs_spgr_time) layH_ctrl_time.addWidget(self.chk_byfs_spgr_time) layH_ctrl_time.addWidget(self.but_log_spgr_time) layH_ctrl_time.addWidget(self.lbl_time_nfft_spgr) layH_ctrl_time.addWidget(self.led_time_nfft_spgr) layH_ctrl_time.addWidget(self.lbl_time_ovlp_spgr) layH_ctrl_time.addWidget(self.led_time_ovlp_spgr) layH_ctrl_time.addStretch(10) # layH_ctrl_time.setContentsMargins(*params['wdg_margins']) self.wdg_ctrl_time = QWidget(self) self.wdg_ctrl_time.setLayout(layH_ctrl_time) # ---- end time domain ------------------ # --------------------------------------------------------------- # Controls for frequency domain # --------------------------------------------------------------- self.lbl_plt_freq_stim = QLabel(to_html("Stimulus X", frmt='bi'), self) self.cmb_plt_freq_stim = QComboBox(self) qcmb_box_populate(self.cmb_plt_freq_stim, self.plot_styles_list, self.plt_freq_stim) self.cmb_plt_freq_stim.setToolTip( "<span>Plot style for stimulus.</span>") self.lbl_plt_freq_stmq = QLabel( to_html(" Fixp. Stim. X_Q", frmt='bi'), self) self.cmb_plt_freq_stmq = QComboBox(self) qcmb_box_populate(self.cmb_plt_freq_stmq, self.plot_styles_list, self.plt_freq_stmq) self.cmb_plt_freq_stmq.setToolTip( "<span>Plot style for <em>fixpoint</em> (quantized) stimulus.</span>" ) lbl_plt_freq_resp = QLabel(to_html(" Response Y", frmt='bi'), self) self.cmb_plt_freq_resp = QComboBox(self) qcmb_box_populate(self.cmb_plt_freq_resp, self.plot_styles_list, self.plt_freq_resp) self.cmb_plt_freq_resp.setToolTip( "<span>Plot style for response.</span>") self.but_log_freq = QPushButton("dB") self.but_log_freq.setMaximumWidth(qtext_width(" dB")) self.but_log_freq.setObjectName(".but_log_freq") self.but_log_freq.setToolTip( "<span>Logarithmic scale for y-axis.</span>") self.but_log_freq.setCheckable(True) self.but_log_freq.setChecked(True) self.lbl_log_bottom_freq = QLabel(to_html("min =", frmt='bi'), self) self.lbl_log_bottom_freq.setVisible(self.but_log_freq.isChecked()) self.led_log_bottom_freq = QLineEdit(self) self.led_log_bottom_freq.setText(str(self.bottom_f)) self.led_log_bottom_freq.setMaximumWidth(qtext_width(N_x=8)) self.led_log_bottom_freq.setToolTip( "<span>Minimum display value for log. scale.</span>") self.led_log_bottom_freq.setVisible(self.but_log_freq.isChecked()) if not self.but_log_freq.isChecked(): self.bottom_f = 0 self.cmb_freq_display = QComboBox(self) qcmb_box_populate(self.cmb_freq_display, self.cmb_freq_display_items, self.cmb_freq_display_item) self.cmb_freq_display.setObjectName("cmb_re_im_freq") self.but_Hf = QPushButtonRT(self, to_html("H_id", frmt="bi"), margin=5) self.but_Hf.setObjectName("chk_Hf") self.but_Hf.setToolTip( "<span>Show ideal frequency response, calculated " "from the filter coefficients.</span>") self.but_Hf.setChecked(False) self.but_Hf.setCheckable(True) self.but_freq_norm_impz = QPushButtonRT( text="<b><i>E<sub>X</sub></i> = 1</b>", margin=5) self.but_freq_norm_impz.setToolTip( "<span>Normalize the FFT of the stimulus with <i>N<sub>FFT</sub></i> for " "<i>E<sub>X</sub></i> = 1. For a dirac pulse, this yields " "|<i>Y(f)</i>| = |<i>H(f)</i>|. DC and Noise need to be " "turned off, window should be <b>Rectangular</b>.</span>") self.but_freq_norm_impz.setCheckable(True) self.but_freq_norm_impz.setChecked(True) self.but_freq_norm_impz.setObjectName("freq_norm_impz") self.but_freq_show_info = QPushButton("Info", self) self.but_freq_show_info.setMaximumWidth(qtext_width(" Info ")) self.but_freq_show_info.setObjectName("but_show_info_freq") self.but_freq_show_info.setToolTip( "<span>Show signal power in legend.</span>") self.but_freq_show_info.setCheckable(True) self.but_freq_show_info.setChecked(False) layH_ctrl_freq = QHBoxLayout() layH_ctrl_freq.addWidget(self.lbl_plt_freq_stim) layH_ctrl_freq.addWidget(self.cmb_plt_freq_stim) # layH_ctrl_freq.addWidget(self.lbl_plt_freq_stmq) layH_ctrl_freq.addWidget(self.cmb_plt_freq_stmq) # layH_ctrl_freq.addWidget(lbl_plt_freq_resp) layH_ctrl_freq.addWidget(self.cmb_plt_freq_resp) # layH_ctrl_freq.addSpacing(5) layH_ctrl_freq.addWidget(self.but_Hf) layH_ctrl_freq.addStretch(1) # layH_ctrl_freq.addWidget(self.lbl_log_bottom_freq) layH_ctrl_freq.addWidget(self.led_log_bottom_freq) layH_ctrl_freq.addWidget(self.but_log_freq) layH_ctrl_freq.addStretch(1) layH_ctrl_freq.addWidget(self.cmb_freq_display) layH_ctrl_freq.addStretch(1) layH_ctrl_freq.addWidget(self.but_freq_norm_impz) layH_ctrl_freq.addStretch(1) layH_ctrl_freq.addWidget(self.but_freq_show_info) layH_ctrl_freq.addStretch(10) # layH_ctrl_freq.setContentsMargins(*params['wdg_margins']) self.wdg_ctrl_freq = QWidget(self) self.wdg_ctrl_freq.setLayout(layH_ctrl_freq) # ---- end Frequency Domain ------------------ # ---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs # ---------------------------------------------------------------------- # connect FFT widget to qfft_selector and vice versa and to and signals upstream: self.fft_widget.sig_tx.connect(self.process_sig_rx) self.qfft_win_select.sig_tx.connect(self.process_sig_rx) # connect process_sig_rx output to both FFT widgets self.sig_tx_fft.connect(self.fft_widget.sig_rx) self.sig_tx_fft.connect(self.qfft_win_select.sig_rx) # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- # --- run control --- self.led_N_start.editingFinished.connect(self.update_N) self.led_N_points.editingFinished.connect(self.update_N) self.led_N_frame.editingFinished.connect(self.update_N) self.but_fft_wdg.clicked.connect(self.toggle_fft_wdg)
def _refresh_table(self): """ (Re-)Create the displayed table from `self.ba` (list with 2 one-dimensional numpy arrays). Data is displayed via `ItemDelegate.displayText()` in the number format set by `self.frmt`. - self.ba[0] -> b coefficients - self.ba[1] -> a coefficients The table dimensions are set according to the filter type set in `fb.fil[0]['ft']` which is either 'FIR' or 'IIR' and by the number of rows in `self.ba`. Called at the end of nearly every method. """ if np.ndim(self.ba) == 1 or fb.fil[0]['ft'] == 'FIR': self.num_rows = len(self.ba[0]) else: self.num_rows = max(len(self.ba[1]), len(self.ba[0])) # logger.warning("np.shape(ba) = {0}".format(np.shape(self.ba))) params['FMT_ba'] = int(self.ui.spnDigits.text()) # When format is 'float', disable all fixpoint options is_float = (qget_cmb_box(self.ui.cmbFormat, data=False).lower() == 'float') self.ui.spnDigits.setVisible(is_float) # number of digits can only be selected self.ui.lblDigits.setVisible(is_float) # for format = 'float' self.ui.cmbQFrmt.setVisible(not is_float) # hide unneeded widgets for format = 'float' self.ui.lbl_W.setVisible(not is_float) self.ui.ledW.setVisible(not is_float) self.ui.frmQSettings.setVisible(not is_float) # hide all q-settings for float if self.ui.butEnable.isChecked(): self.ui.butEnable.setIcon(QIcon(':/circle-x.svg')) self.ui.frmButtonsCoeffs.setVisible(True) self.tblCoeff.setVisible(True) # check whether filter is FIR and only needs one column if fb.fil[0]['ft'] == 'FIR': self.num_cols = 1 self.tblCoeff.setColumnCount(1) self.tblCoeff.setHorizontalHeaderLabels(["b"]) qset_cmb_box(self.ui.cmbFilterType, 'FIR') else: self.num_cols = 2 self.tblCoeff.setColumnCount(2) self.tblCoeff.setHorizontalHeaderLabels(["b", "a"]) qset_cmb_box(self.ui.cmbFilterType, 'IIR') self.ba[1][0] = 1.0 # restore fa[0] = 1 of denonimator polynome self.tblCoeff.setRowCount(self.num_rows) self.tblCoeff.setColumnCount(self.num_cols) # Create strings for index column (vertical header), starting with "0" idx_str = [str(n) for n in range(self.num_rows)] self.tblCoeff.setVerticalHeaderLabels(idx_str) self.tblCoeff.blockSignals(True) for col in range(self.num_cols): for row in range(self.num_rows): self._refresh_table_item(row, col) # make a[0] selectable but not editable if fb.fil[0]['ft'] == 'IIR': item = self.tblCoeff.item(0,1) item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled) item.setFont(self.ui.bfont) self.tblCoeff.blockSignals(False) self.tblCoeff.resizeColumnsToContents() self.tblCoeff.resizeRowsToContents() self.tblCoeff.clearSelection() else: self.ui.frmButtonsCoeffs.setVisible(False) self.ui.butEnable.setIcon(QIcon(':/circle-check.svg')) self.tblCoeff.setVisible(False)
def construct_UI(self): """ Create additional subwidget(s) needed for filter design: These subwidgets are instantiated dynamically when needed in select_filter.py using the handle to the filter object, fb.filObj . """ # Combobox for selecting the algorithm to estimate minimum filter order self.cmb_firwin_alg = QComboBox(self) self.cmb_firwin_alg.setObjectName('wdg_cmb_firwin_alg') self.cmb_firwin_alg.addItems(['ichige', 'kaiser', 'herrmann']) # Minimum size, can be changed in the upper hierarchy levels using layouts: self.cmb_firwin_alg.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.cmb_firwin_alg.hide() self.qfft_win_select = QFFTWinSelector(self, self.win_dict) # Minimum size, can be changed in the upper hierarchy levels using layouts: # self.qfft_win_select.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.but_fft_wdg = QPushButton(self) self.but_fft_wdg.setIcon(QIcon(":/fft.svg")) but_height = self.qfft_win_select.sizeHint().height() self.but_fft_wdg.setIconSize(QSize(but_height, but_height)) self.but_fft_wdg.setFixedSize(QSize(but_height, but_height)) self.but_fft_wdg.setToolTip( '<span>Show / hide FFT widget (select window type ' ' and display its properties).</span>') self.but_fft_wdg.setCheckable(True) self.but_fft_wdg.setChecked(False) self.layHWin1 = QHBoxLayout() # self.layHWin1.addWidget(self.cmb_firwin_win) # self.layHWin1.addWidget(self.but_fft_wdg) self.layHWin1.addWidget(self.cmb_firwin_alg) self.layHWin2 = QHBoxLayout() self.layHWin2.addWidget(self.but_fft_wdg) self.layHWin2.addWidget(self.qfft_win_select) self.layVWin = QVBoxLayout() self.layVWin.addLayout(self.layHWin1) self.layVWin.addLayout(self.layHWin2) self.layVWin.setContentsMargins(0, 0, 0, 0) # Widget containing all subwidgets (cmbBoxes, Labels, lineEdits) self.wdg_fil = QWidget(self) self.wdg_fil.setObjectName('wdg_fil') self.wdg_fil.setLayout(self.layVWin) # ---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs # ---------------------------------------------------------------------- # connect FFT widget to qfft_selector and vice versa and to signals upstream: self.fft_widget.sig_tx.connect(self.process_sig_rx) self.qfft_win_select.sig_tx.connect(self.process_sig_rx) # connect process_sig_rx output to both FFT widgets self.sig_tx_local.connect(self.fft_widget.sig_rx) self.sig_tx_local.connect(self.qfft_win_select.sig_rx) # ---------------------------------------------------------------------- # SIGNALS & SLOTs # ---------------------------------------------------------------------- self.cmb_firwin_alg.currentIndexChanged.connect( self._update_fft_window) self.but_fft_wdg.clicked.connect(self.toggle_fft_wdg)
def _construct_UI(self): """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ self.bfont = QFont() self.bfont.setBold(True) self.bifont = QFont() self.bifont.setBold(True) self.bifont.setItalic(True) # q_icon_size = QSize(20, 20) # optional, size is derived from butEnable # --------------------------------------------- # UI Elements for controlling the display # --------------------------------------------- self.butEnable = QPushButton(self) self.butEnable.setIcon(QIcon(':/circle-x.svg')) q_icon_size = self.butEnable.iconSize() # <- set this for manual icon sizing self.butEnable.setIconSize(q_icon_size) self.butEnable.setCheckable(True) self.butEnable.setChecked(True) self.butEnable.setToolTip("<span>Show / hide poles and zeros in an editable table." " For high order systems, the table display might be slow.</span>") self.cmbPZFrmt = QComboBox(self) pz_formats = [('Cartesian', 'cartesian'), ('Polar (rad)', 'polar_rad'), ('Polar (pi)', 'polar_pi'), ('Polar (°)', 'polar_deg')] # display text, data # π: u'3C0, °: u'B0, ∠: u'2220 for pz in pz_formats: self.cmbPZFrmt.addItem(*pz) self.cmbPZFrmt.setSizeAdjustPolicy(QComboBox.AdjustToContents) # self.cmbPZFrmt.setEnabled(False) self.cmbPZFrmt.setToolTip("<span>Set display format for poles and zeros to" " either cartesian (x + jy) or polar (r * ∠ Ω)." " Type 'o' for '°', '<' for '∠' and 'pi' for 'π'.</span>") self.spnDigits = QSpinBox(self) self.spnDigits.setRange(0,16) self.spnDigits.setToolTip("Number of digits to display.") self.lblDigits = QLabel("Digits", self) self.lblDigits.setFont(self.bifont) self.cmbCausal = QComboBox(self) causal_types = ['Causal', 'Acausal', 'Anticausal'] for cs in causal_types: self.cmbCausal.addItem(cs) qset_cmb_box(self.cmbCausal, 'Causal') self.cmbCausal.setToolTip('<span>Set the system type. Not implemented yet.</span>') self.cmbCausal.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.cmbCausal.setEnabled(False) layHDisplay = QHBoxLayout() layHDisplay.setAlignment(Qt.AlignLeft) layHDisplay.addWidget(self.butEnable) layHDisplay.addWidget(self.cmbPZFrmt) layHDisplay.addWidget(self.spnDigits) layHDisplay.addWidget(self.lblDigits) layHDisplay.addWidget(self.cmbCausal) layHDisplay.addStretch() # --------------------------------------------- # UI Elements for setting the gain # --------------------------------------------- self.lblNorm = QLabel(to_html("Normalize:", frmt='bi'), self) self.cmbNorm = QComboBox(self) self.cmbNorm.addItems(["None", "1", "Max"]) self.cmbNorm.setToolTip("<span>Set the gain <i>k</i> so that H(f)<sub>max</sub> is " "either 1 or the max. of the previous system.</span>") self.lblGain = QLabel(to_html("k =", frmt='bi'), self) self.ledGain = QLineEdit(self) self.ledGain.setToolTip("<span>Specify gain factor <i>k</i>" " (only possible for Normalize = 'None').</span>") self.ledGain.setText(str(1.)) self.ledGain.setObjectName("ledGain") layHGain = QHBoxLayout() layHGain.addWidget(self.lblNorm) layHGain.addWidget(self.cmbNorm) layHGain.addWidget(self.lblGain) layHGain.addWidget(self.ledGain) layHGain.addStretch() # --------------------------------------------- # UI Elements for loading / storing / manipulating cells and rows # --------------------------------------------- # self.cmbFilterType = QComboBox(self) # self.cmbFilterType.setObjectName("comboFilterType") # self.cmbFilterType.setToolTip("Select between IIR and FIR filte for manual entry.") # self.cmbFilterType.addItems(["FIR","IIR"]) # self.cmbFilterType.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.butAddCells = QPushButton(self) self.butAddCells.setIcon(QIcon(':/row_insert_above.svg')) self.butAddCells.setIconSize(q_icon_size) self.butAddCells.setToolTip("<SPAN>Select cells to insert a new cell above each selected cell. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, add a row at the end.</SPAN>") self.butDelCells = QPushButton(self) self.butDelCells.setIcon(QIcon(':/row_delete.svg')) self.butDelCells.setIconSize(q_icon_size) self.butDelCells.setToolTip("<SPAN>Delete selected cell(s) from the table. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, delete the last row.</SPAN>") self.butSave = QPushButton(self) self.butSave.setIcon(QIcon(':/upload.svg')) self.butSave.setIconSize(q_icon_size) self.butSave.setToolTip("<span>Copy P/Z table to filter dict and update all plots and widgets.</span>") self.butLoad = QPushButton(self) self.butLoad.setIcon(QIcon(':/download.svg')) self.butLoad.setIconSize(q_icon_size) self.butLoad.setToolTip("Reload P/Z table from filter dict.") self.butClear = QPushButton(self) self.butClear.setIcon(QIcon(':/trash.svg')) self.butClear.setIconSize(q_icon_size) self.butClear.setToolTip("Clear all table entries.") self.butFromTable = QPushButton(self) self.butFromTable.setIconSize(q_icon_size) self.butToTable = QPushButton(self) self.butToTable.setIconSize(q_icon_size) self.but_csv_options = QPushButton(self) self.but_csv_options.setIcon(QIcon(':/settings.svg')) self.but_csv_options.setIconSize(q_icon_size) self.but_csv_options.setToolTip("<span>Select CSV format and whether " "to copy to/from clipboard or file.</span>") self.but_csv_options.setCheckable(True) self.but_csv_options.setChecked(False) self._set_load_save_icons() # initialize icon / button settings layHButtonsCoeffs1 = QHBoxLayout() # layHButtonsCoeffs1.addWidget(self.cmbFilterType) layHButtonsCoeffs1.addWidget(self.butAddCells) layHButtonsCoeffs1.addWidget(self.butDelCells) layHButtonsCoeffs1.addWidget(self.butClear) layHButtonsCoeffs1.addWidget(self.butSave) layHButtonsCoeffs1.addWidget(self.butLoad) layHButtonsCoeffs1.addWidget(self.butFromTable) layHButtonsCoeffs1.addWidget(self.butToTable) layHButtonsCoeffs1.addWidget(self.but_csv_options) layHButtonsCoeffs1.addStretch() #------------------------------------------------------------------- # Eps / set zero settings # --------------------------------------------------------------------- self.butSetZero = QPushButton("= 0", self) self.butSetZero.setToolTip("<span>Set selected poles / zeros = 0 with a magnitude < ε. " "When nothing is selected, test the whole table.</span>") self.butSetZero.setIconSize(q_icon_size) lblEps = QLabel(self) lblEps.setText("<b><i>for ε</i> <</b>") self.ledEps = QLineEdit(self) self.ledEps.setToolTip("Specify tolerance value.") layHButtonsCoeffs2 = QHBoxLayout() layHButtonsCoeffs2.addWidget(self.butSetZero) layHButtonsCoeffs2.addWidget(lblEps) layHButtonsCoeffs2.addWidget(self.ledEps) layHButtonsCoeffs2.addStretch() # ######################## Main UI Layout ############################ # layout for frame (UI widget) layVMainF = QVBoxLayout() layVMainF.addLayout(layHDisplay) layVMainF.addLayout(layHGain) layVMainF.addLayout(layHButtonsCoeffs1) layVMainF.addLayout(layHButtonsCoeffs2) # This frame encompasses all UI elements frmMain = QFrame(self) frmMain.setLayout(layVMainF) layVMain = QVBoxLayout() layVMain.setAlignment(Qt.AlignTop) # this affects only the first widget (intended here) layVMain.addWidget(frmMain) layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) #--- set initial values from dict ------------ self.spnDigits.setValue(params['FMT_pz']) self.ledEps.setText(str(self.eps)) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.but_csv_options.clicked.connect(self._open_csv_win)
def about_window(self): """ Display an "About" window with copyright and version infos """ def to_clipboard(my_string): """ Copy version info to clipboard """ mapping = [ ('<br>', '\n'), ('<br />', '\n'), ('</tr>', '\n'), ('</th>', '\n==============\n'), ('</table>', '\n'), ('<hr>', '\n---------\n'), ('<b>', ''), ('</b>', ''), ('<tr>', ''), ('<td>', ''), ('</td>', '\t'), ('<th>', ''), (' ', ' '), ('<table>', ''), # ('</a>',''), ("<th style='font-size:large;'>", "\n") ] for k, v in mapping: my_string = my_string.replace(k, v) fb.clipboard.setText(my_string) user_dirs_str = "" if dirs.USER_DIRS: for d in dirs.USER_DIRS: user_dirs_str += d + '<br />' info_string = ("<b><a href=https://www.github.com/chipmuenk/pyfda>pyfda</a> " "Version {0} (c) 2013 - 2020 Christian Münker</b><br />" "Design, analyze and synthesize digital filters. Docs @ " "<a href=https://pyfda.rtfd.org>pyfda.rtfd.org</a>" " (<a href=https://media.readthedocs.org/pdf/pyfda/latest/pyfda.pdf>pdf</a>)<hr>"\ .format(version.__version__)) versions_string = ( "<b>OS:</b> {0} {1}<br><b>User Name:</b> {2}<br>".format( dirs.OS, dirs.OS_VER, dirs.USER_NAME)) # dir_string = ("<table><th style='font-size:large;'>Imported Modules</th>" # "<tr><td>  {0}</td></tr>"\ # .format( pyfda_lib.mod_version().replace("\n", "<br>  "))) dir_string = ( "<table><th style='font-size:large;'>Software Versions</th>") dir_string += pyfda_lib.mod_version() dir_string += "</table>" dir_string += ("<table><th style='font-size:large;'>Directories</th>" "<tr><td><b>Home:</b></td><td>{0}</td></tr>" "<tr><td><b>Install: </b></td><td>{1}</td></tr>" "<tr><td><b>Config: </b></td><td>{2}</td></tr>" "<tr><td><b>User: </b></td><td>{3}</td></tr>" "<tr><td><b>Temp:</b></td><td>{4}</td></tr>"\ .format( dirs.HOME_DIR, dirs.INSTALL_DIR, dirs.CONF_DIR, user_dirs_str[:-6], dirs.TEMP_DIR)) dir_string += ("<th style='font-size:large;'>Logging Files</th>" "<tr><td><b>Config:</b></td><td>{0}</td></tr>" "<tr><td><b>Output: </b></td><td>{1}</td></tr>" "</table>"\ .format(dirs.USER_LOG_CONF_DIR_FILE, dirs.LOG_DIR_FILE)) about_string = info_string + versions_string + dir_string #msg = QMessageBox.about(self, "About pyFDA", info_string) butClipboard = QPushButton(self) butClipboard.setIcon(QIcon(':/clipboard.svg')) butClipboard.setToolTip("Copy text to clipboard.") # butClipboard.adjustSize() # butClipboard.setFixedSize(self.checkLayout.sizeHint()) msg = QMessageBox(self) msg.setIconPixmap( QPixmap(':/pyfda_icon.svg').scaledToHeight( 32, Qt.SmoothTransformation)) msg.addButton(butClipboard, QMessageBox.ActionRole) msg.setText(about_string) # msg.setInformativeText("This is additional information") #msg.setDetailedText(versions_string) # adds a button that opens another textwindow msg.setWindowTitle("About pyFDA") msg.setStandardButtons(QMessageBox.Ok) # | QMessageBox.Cancel # close Message box with close event triggered by "x" icon msg.closeEvent = self.closeEvent butClipboard.clicked.connect(lambda: to_clipboard(about_string)) retval = msg.exec_()
def _construct_UI(self): """ initialize the User Interface """ butClipboard = QPushButton(self) butClipboard.setIcon(QIcon(':/clipboard.svg')) butClipboard.setToolTip("Copy text to clipboard.") butAbout = QPushButton(self) butAbout.setText("About") butAbout.setToolTip("Display 'About' info") butChangelog = QPushButton(self) butChangelog.setText("Changelog") butChangelog.setToolTip("Display changelog") butLicMIT = QPushButton(self) butLicMIT.setText("MIT License") butLicMIT.setToolTip("MIT License for pyFDA source code") butLicGPLv3 = QPushButton(self) butLicGPLv3.setText("GPLv3 License") butLicGPLv3.setToolTip("GPLv3 License for bundled distribution") butClose = QPushButton(self) butClose.setIcon(QIcon(':/circle-x.svg')) butClose.setToolTip("Close Window.") layGButtons = QGridLayout() layGButtons.addWidget(butClipboard, 0, 0) layGButtons.addWidget(butAbout, 0, 1) layGButtons.addWidget(butChangelog, 0, 2) layGButtons.addWidget(butLicMIT, 0, 3) layGButtons.addWidget(butLicGPLv3, 0, 4) layGButtons.addWidget(butClose, 0, 5) lblInfo = QLabel(self) lblInfo.setText(self.info_str) lblInfo.setFixedHeight(lblInfo.height() * 1.2) #lblInfo.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) lblInfo.setOpenExternalLinks(True) lblIcon = QLabel(self) lblIcon.setPixmap( QPixmap(':/pyfda_icon.svg').scaledToHeight( lblInfo.height(), Qt.SmoothTransformation)) butClipboard.setFixedWidth(lblInfo.height()) butClose.setFixedWidth(lblInfo.height()) layHInfo = QHBoxLayout() layHInfo.addWidget(lblIcon) layHInfo.addWidget(lblInfo) self.txtDisplay = QTextBrowser(self) self.txtDisplay.setOpenExternalLinks(True) self.display_about_str() self.txtDisplay.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #self.txtDisplay.setFixedHeight(self.txtDisplay.width() * 2) layVMain = QVBoxLayout() # layVMain.setAlignment(Qt.AlignTop) # this affects only the first widget (intended here) layVMain.addLayout(layGButtons) layVMain.addLayout(layHInfo) layVMain.addWidget(self.txtDisplay) layVMain.setContentsMargins(*params['wdg_margins_spc']) self.setLayout(layVMain) #self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #self.resize(0,0) #self.adjustSize() #QApplication.processEvents() butClipboard.clicked.connect( lambda: self.to_clipboard(self.info_str + self.about_str)) butAbout.clicked.connect(self.display_about_str) butChangelog.clicked.connect(self.display_changelog) butLicMIT.clicked.connect(self.display_MIT_lic) butLicGPLv3.clicked.connect(self.display_GPL_lic) butClose.clicked.connect(self.close)
def main(): """ entry point for the pyfda application see http://pyqt.sourceforge.net/Docs/PyQt4/qapplication.html : "For any GUI application using Qt, there is precisely *one* QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time. ... Since the QApplication object does so much initialization, it must be created *before* any other objects related to the user interface are created." """ # instantiate QApplication object, passing command line arguments if len(rc.qss_rc) > 20: app = QApplication(sys.argv) app.setStyleSheet(rc.qss_rc) # this is a proper style sheet style = "Using 'pyfda' style sheet." else: qstyle = QApplication.setStyle( rc.qss_rc) # no, this is just a name for a system stylesheet app = QApplication(sys.argv) if qstyle: style = 'Using system style "{0}".'.format(rc.qss_rc) else: style = 'Style "{0}" not found, falling back to default style.'.format( rc.qss_rc) mainw = pyFDA() logger.info("Logging to {0}".format(dirs.LOG_DIR_FILE)) logger.info(style) if dirs.OS.lower() == "windows": # Windows taskbar is not for "Application Windows" but for "Application # User Models", grouping several instances of an application under one # common taskbar icon. Python apps are sometimes grouped under the icon # for Pythonw.exe, sometimes the icon is just blank. The following # instructions tell Windows that pythonw is merely hosting other applications. import ctypes myappid = u'chipmuenk.pyfda.v0.4' ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) # set taskbar icon app.setWindowIcon(QIcon(':/pyfda_icon.svg')) # Sets the active window to the active widget in response to a system event app.setActiveWindow(mainw) # Set default icon for window mainw.setWindowIcon(QIcon(':/pyfda_icon.svg')) screen_resolution = app.desktop().screenGeometry() screen_h, screen_w = screen_resolution.height(), screen_resolution.width() logger.info("Starting pyfda with screen resolution: %d x %d", screen_w, screen_h) if screen_h < 800: delta = 50 else: delta = 100 # set position + size of main window on desktop mainw.setGeometry(20, 20, screen_w - delta, screen_h - delta) # top L / top R, dx, dy # Give the keyboard input focus to this widget if this widget # or one of its parents is the active window: # mainw.setFocus() mainw.show() #start the application's exec loop, return the exit code to the OS app.exec_() # sys.exit(app.exec_()) and app.exec_() have same behaviour