class Input_PZ_UI(QWidget): """ Create the UI for the FilterPZ class """ sig_rx = pyqtSignal(object) # incoming sig_tx = pyqtSignal(object) # outgoing def __init__(self, parent): """ Pass instance `parent` of parent class (FilterCoeffs) """ super(Input_PZ_UI, self).__init__(parent) # self.parent = parent # instance of the parent (not the base) class self.eps = 1.e-4 # # tolerance value for e.g. setting P/Z to zero self._construct_UI() #------------------------------------------------------------------------------ def process_sig_rx(self, dict_sig=None): """ Process signals coming from the CSV pop-up window """ logger.debug("PROCESS_SIG_RX\n{0}".format(pprint_log(dict_sig))) if 'closeEvent' in dict_sig: self._close_csv_win() self.sig_tx.emit({'sender':__name__, 'ui_changed': 'csv'}) return # probably not needed elif 'ui_changed' in dict_sig: self._set_load_save_icons() # update icons file <-> clipboard # inform e.g. the p/z input widget about changes in CSV options self.sig_tx.emit({'sender':__name__, 'ui_changed': 'csv'}) #------------------------------------------------------------------------------ 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 _open_csv_win(self): """ Pop-up window for CSV options """ if self.but_csv_options.isChecked(): qstyle_widget(self.but_csv_options, "changed") else: qstyle_widget(self.but_csv_options, "normal") if dirs.csv_options_handle is None: # no handle to the window? Create a new instance if self.but_csv_options.isChecked(): # Important: Handle to window must be class attribute otherwise it # (and the attached window) is deleted immediately when it goes out of scope dirs.csv_options_handle = CSV_option_box(self) dirs.csv_options_handle.sig_tx.connect(self.process_sig_rx) dirs.csv_options_handle.show() # modeless i.e. non-blocking popup window else: if not self.but_csv_options.isChecked(): # this should not happen if dirs.csv_options_handle is None: logger.warning("CSV options window is already closed!") else: dirs.csv_options_handle.close() self.sig_tx.emit({'sender':__name__, 'ui_changed': 'csv'}) #------------------------------------------------------------------------------ def _close_csv_win(self): dirs.csv_options_handle = None self.but_csv_options.setChecked(False) qstyle_widget(self.but_csv_options, "normal") #------------------------------------------------------------------------------ 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)
class UI_W(QWidget): """ Widget for entering integer and fractional bits. The result can be read out via the attributes `self.WI`, `self.WF` and `self.W`. The constructor accepts a dictionary for initial widget settings. The following keys are defined; default values are used for missing keys: 'wdg_name' : 'ui_w' # widget name 'label' : 'WI.WF' # widget text label 'visible' : True # Is widget visible? 'enabled' : True # Is widget enabled? 'fractional' : True # Display WF, otherwise WF=0 'lbl_sep' : '.' # label between WI and WF field 'max_led_width' : 30 # max. length of lineedit field 'WI' : 0 # number of frac. *bits* 'WI_len' : 2 # max. number of integer *digits* 'tip_WI' : 'Number of integer bits' # Mouse-over tooltip 'WF' : 15 # number of frac. *bits* 'WF_len' : 2 # max. number of frac. *digits* 'tip_WF' : 'Number of frac. bits' # Mouse-over tooltip 'lock_visible' : False # Pushbutton for locking visible 'tip_lock' : 'Lock input/output quant.'# Tooltip for lock push button 'combo_visible' : False # Enable integrated combo widget 'combo_items' : ['auto', 'full', 'man'] # Combo selection 'tip_combo' : 'Calculate Acc. width.' # tooltip for combo """ # sig_rx = pyqtSignal(object) # incoming, sig_tx = pyqtSignal(object) # outcgoing from pyfda.libs.pyfda_qt_lib import emit def __init__(self, parent, q_dict, **kwargs): super(UI_W, self).__init__(parent) self.q_dict = q_dict # pass a dict with initial settings for construction self._construct_UI(**kwargs) self.ui2dict(s='init') # initialize the class attributes def _construct_UI(self, **kwargs): """ Construct widget from quantization dict, individual settings and the default dict below """ # default settings dict_ui = { 'wdg_name': 'ui_w', 'label': 'WI.WF', 'lbl_sep': '.', 'max_led_width': 30, 'WI': 0, 'WI_len': 2, 'tip_WI': 'Number of integer bits', 'WF': 15, 'WF_len': 2, 'tip_WF': 'Number of fractional bits', 'enabled': True, 'visible': True, 'fractional': True, 'combo_visible': False, 'combo_items': ['auto', 'full', 'man'], 'tip_combo': 'Calculate Acc. width.', 'lock_visible': False, 'tip_lock': 'Lock input/output quantization.' } #: default values if self.q_dict: dict_ui.update(self.q_dict) for k, v in kwargs.items(): if k not in dict_ui: logger.warning("Unknown key {0}".format(k)) else: dict_ui.update({k: v}) self.wdg_name = dict_ui['wdg_name'] if not dict_ui['fractional']: dict_ui['WF'] = 0 self.WI = dict_ui['WI'] self.WF = dict_ui['WF'] self.W = int(self.WI + self.WF + 1) if self.q_dict: self.q_dict.update({'WI': self.WI, 'WF': self.WF, 'W': self.W}) else: self.q_dict = {'WI': self.WI, 'WF': self.WF, 'W': self.W} lblW = QLabel(to_html(dict_ui['label'], frmt='bi'), self) self.cmbW = QComboBox(self) self.cmbW.addItems(dict_ui['combo_items']) self.cmbW.setVisible(dict_ui['combo_visible']) self.cmbW.setToolTip(dict_ui['tip_combo']) self.cmbW.setObjectName("cmbW") self.butLock = QPushButton(self) self.butLock.setCheckable(True) self.butLock.setChecked(False) self.butLock.setVisible(dict_ui['lock_visible']) self.butLock.setToolTip(dict_ui['tip_lock']) self.ledWI = QLineEdit(self) self.ledWI.setToolTip(dict_ui['tip_WI']) self.ledWI.setMaxLength(dict_ui['WI_len']) # maximum of 2 digits self.ledWI.setFixedWidth( dict_ui['max_led_width']) # width of lineedit in points self.ledWI.setObjectName("WI") lblDot = QLabel(dict_ui['lbl_sep'], self) lblDot.setVisible(dict_ui['fractional']) self.ledWF = QLineEdit(self) self.ledWF.setToolTip(dict_ui['tip_WF']) self.ledWF.setMaxLength(dict_ui['WI_len']) # maximum of 2 digits self.ledWF.setFixedWidth( dict_ui['max_led_width']) # width of lineedit in points self.ledWF.setVisible(dict_ui['fractional']) self.ledWF.setObjectName("WF") layH = QHBoxLayout() layH.addWidget(lblW) layH.addStretch() layH.addWidget(self.cmbW) layH.addWidget(self.butLock) layH.addWidget(self.ledWI) layH.addWidget(lblDot) layH.addWidget(self.ledWF) layH.setContentsMargins(0, 0, 0, 0) frmMain = QFrame(self) frmMain.setLayout(layH) layVMain = QVBoxLayout() # Widget main layout layVMain.addWidget(frmMain) layVMain.setContentsMargins(0, 5, 0, 0) # *params['wdg_margins']) self.setLayout(layVMain) # ---------------------------------------------------------------------- # INITIAL SETTINGS # ---------------------------------------------------------------------- self.ledWI.setText(qstr(dict_ui['WI'])) self.ledWF.setText(qstr(dict_ui['WF'])) frmMain.setEnabled(dict_ui['enabled']) frmMain.setVisible(dict_ui['visible']) # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.ledWI.editingFinished.connect(self.ui2dict) self.ledWF.editingFinished.connect(self.ui2dict) self.butLock.clicked.connect(self.butLock_clicked) self.cmbW.currentIndexChanged.connect(self.ui2dict) # initialize button icon self.butLock_clicked(self.butLock.isChecked()) def quant_coeffs(self, q_dict: dict, coeffs: iterable, to_int: bool = False) -> list: """ Quantize the coefficients, scale and convert them to integer and return them as a list of integers This is called every time one of the coefficient subwidgets is edited or changed. Parameters: ----------- q_dict: dict Dictionary with quantizer settings for coefficients coeffs: iterable a list or ndarray of coefficients to be quantized Returns: -------- A list of integer coeffcients, quantized and scaled with the settings of the passed quantization dict """ # Create coefficient quantizer instance using the passed quantization parameters # dict from `input_widgets/input_coeffs.py` (and stored in the central # filter dict) Q_coeff = fx.Fixed(q_dict) Q_coeff.frmt = 'dec' # always use decimal format for coefficients if coeffs is None: logger.error("Coeffs empty!") # quantize floating point coefficients with the selected scale (WI.WF), # next convert array float -> array of fixp # -> list of int (scaled by 2^WF) when `to_int == True` if to_int: return list(Q_coeff.float2frmt(coeffs) * (1 << Q_coeff.WF)) else: return list(Q_coeff.fixp(coeffs)) # -------------------------------------------------------------------------- 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 = {'wdg_name': self.wdg_name, 'ui': 'butLock'} self.emit(dict_sig) # -------------------------------------------------------------------------- def ui2dict(self, s=None): """ Update the attributes `self.WI`, `self.WF` and `self.W` and `self.q_dict` when one of the QLineEdit widgets has been edited. Emit a signal with `{'ui':objectName of the sender}`. """ self.WI = int( safe_eval(self.ledWI.text(), self.WI, return_type="int", sign='poszero')) self.ledWI.setText(qstr(self.WI)) self.WF = int( safe_eval(self.ledWF.text(), self.WF, return_type="int", sign='poszero')) self.ledWF.setText(qstr(self.WF)) self.W = int(self.WI + self.WF + 1) self.q_dict.update({'WI': self.WI, 'WF': self.WF, 'W': self.W}) if self.sender(): obj_name = self.sender().objectName() logger.debug("sender: {0}".format(obj_name)) dict_sig = {'wdg_name': self.wdg_name, 'ui': obj_name} self.emit(dict_sig) elif s == 'init': logger.debug("called by __init__") else: logger.error("sender without name!") # -------------------------------------------------------------------------- def dict2ui(self, q_dict=None): """ Update the widgets `WI` and `WF` and the corresponding attributes from the dict passed as the argument """ if q_dict is None: q_dict = self.q_dict if 'WI' in q_dict: self.WI = safe_eval(q_dict['WI'], self.WI, return_type="int", sign='poszero') self.ledWI.setText(qstr(self.WI)) else: logger.warning("No key 'WI' in dict!") if 'WF' in q_dict: self.WF = safe_eval(q_dict['WF'], self.WF, return_type="int", sign='poszero') self.ledWF.setText(qstr(self.WF)) else: logger.warning("No key 'WF' in dict!") self.W = self.WF + self.WI + 1
class Input_Coeffs_UI(QWidget): """ Create the UI for the FilterCoeffs class """ sig_rx = pyqtSignal(dict) # incoming sig_tx = pyqtSignal(dict) # outgoing def __init__(self, parent): super(Input_Coeffs_UI, self).__init__(parent) self.eps = 1.e-6 # initialize tolerance value self._construct_UI() #------------------------------------------------------------------------------ def process_sig_rx(self, dict_sig=None): """ Process signals coming from the CSV pop-up window """ logger.debug("PROCESS_SIG_RX:\n{0}".format(pprint_log(dict_sig))) if 'closeEvent' in dict_sig: self._close_csv_win() self.sig_tx.emit({'sender': __name__, 'ui_changed': 'csv'}) return # probably not needed elif 'ui_changed' in dict_sig: self._set_load_save_icons() # update icons file <-> clipboard # inform e.g. the p/z input widget about changes in CSV options self.sig_tx.emit({'sender': __name__, 'ui_changed': 'csv'}) #------------------------------------------------------------------------------ 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 = QPushButton(self) self.butEnable.setIcon(QIcon(':/circle-x.svg')) q_icon_size = self.butEnable.iconSize( ) # <- uncomment this for manual sizing self.butEnable.setIconSize(q_icon_size) self.butEnable.setCheckable(True) self.butEnable.setChecked(True) 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 = 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() #---------------------------------------------------------------------- # 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() 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_ba']) self.ledEps.setText(str(self.eps)) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.but_csv_options.clicked.connect(self._open_csv_win) #------------------------------------------------------------------------------ def _open_csv_win(self): """ Pop-up window for CSV options """ if self.but_csv_options.isChecked(): qstyle_widget(self.but_csv_options, "changed") else: qstyle_widget(self.but_csv_options, "normal") if dirs.csv_options_handle is None: # no handle to the window? Create a new instance if self.but_csv_options.isChecked(): # Important: Handle to window must be class attribute otherwise it # (and the attached window) is deleted immediately when it goes out of scope dirs.csv_options_handle = CSV_option_box(self) dirs.csv_options_handle.sig_tx.connect(self.process_sig_rx) dirs.csv_options_handle.show( ) # modeless i.e. non-blocking popup window else: if not self.but_csv_options.isChecked(): # this should not happen if dirs.csv_options_handle is None: logger.warning("CSV options window is already closed!") else: dirs.csv_options_handle.close() self.sig_tx.emit({'sender': __name__, 'ui_changed': 'csv'}) #------------------------------------------------------------------------------ def _close_csv_win(self): dirs.csv_options_handle = None self.but_csv_options.setChecked(False) qstyle_widget(self.but_csv_options, "normal") #------------------------------------------------------------------------------ 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)