def _construct_UI(self): """ Construct the main GUI, consisting of: - Tabbed input widgets (left side) - Tabbed plot widgets (right side) - Logger window (right side, below plot tab) """ # ============== UI Layout with H and V-Splitter ===================== inputTabWidgets = input_tab_widgets.InputTabWidgets( self) # input widgets pltTabWidgets = plot_tab_widgets.PlotTabWidgets(self) # plot widgets self.loggerWin = QPlainTextEdit(self) # logger window self.loggerWin.setReadOnly(True) # set custom right-button context menu policy self.loggerWin.setContextMenuPolicy(Qt.CustomContextMenu) self.loggerWin.customContextMenuRequested.connect( self.logger_win_context_menu) # create context menu and define actions and shortcuts self.popMenu = QMenu(self) self.popMenu.addAction('Select &All', self.loggerWin.selectAll, "Ctrl+A") self.popMenu.addAction('&Copy Selected', self.loggerWin.copy) self.popMenu.addSeparator() self.popMenu.addAction('Clear &Window', self.loggerWin.clear) # ============================================================================= # add logger window underneath plot Tab Widgets spltVPltLogger = QSplitter(QtCore.Qt.Vertical) spltVPltLogger.addWidget(pltTabWidgets) spltVPltLogger.addWidget(self.loggerWin) # create horizontal splitter that contains all subwidget groups spltHMain = QSplitter(QtCore.Qt.Horizontal) spltHMain.addWidget(inputTabWidgets) spltHMain.addWidget(spltVPltLogger) spltHMain.setStretchFactor(1, 4) # relative initial sizes of subwidgets spltHMain.setContentsMargins(*rc.params['wdg_margins']) spltHMain.setFocus() # make spltHMain occupy the main area of QMainWindow and make QMainWindow its parent !!! self.setCentralWidget(spltHMain) spltVPltLoggerH = spltVPltLogger.size().height() spltVPltLogger.setSizes( [int(spltVPltLoggerH * 0.95), int(spltVPltLoggerH * 0.05 - 8)]) self.setWindowTitle('pyFDA - Python Filter Design and Analysis') #=============== Menubar ======================================= # aboutAction = QAction('&About', self) # aboutAction.setShortcut('Ctrl+A') # aboutAction.setStatusTip('Info about pyFDA') # # menubar = self.menuBar() # fileMenu = menubar.addMenu('&About') # fileMenu.addAction(aboutAction) # self.statusMessage("Application is initialized.") #---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) #---------------------------------------------------------------------- # SIGNALS & SLOTs #---------------------------------------------------------------------- # Here, signals about spec and design changes from lower hierarchies # are distributed. At the moment, only changes in the input widgets are # routed to the plot widgets: inputTabWidgets.sig_tx.connect(pltTabWidgets.sig_rx) inputTabWidgets.sig_tx.connect(self.process_sig_rx) pltTabWidgets.sig_tx.connect(inputTabWidgets.sig_rx) # open pop-up "about" window #aboutAction.triggered.connect(self.aboutWindow) # trigger the close event in response to sigQuit generated in another subwidget: # inputTabWidgets.input_filter_specs.sigQuit.connect(self.close) # when a message has been written, pass it via signal-slot mechanism and # print it to logger window XStream.stdout().messageWritten.connect(self.loggerWin.appendHtml)
def _construct_UI(self): """ Intitialize the widget, consisting of: - Checkboxes for selecting the info to be displayed - A large text window for displaying infos about the filter design algorithm """ bfont = QFont() bfont.setBold(True) # ============== UI Layout ===================================== # widget / subwindow for filter infos # self.butFiltPerf = QToolButton("H(f)", self) self.butFiltPerf = QPushButton(self) self.butFiltPerf.setText("H(f)") self.butFiltPerf.setCheckable(True) self.butFiltPerf.setChecked(True) self.butFiltPerf.setToolTip("Display frequency response at test frequencies.") self.butDebug = QPushButton(self) self.butDebug.setText("Debug") self.butDebug.setCheckable(True) self.butDebug.setChecked(False) self.butDebug.setToolTip("Show debugging options.") self.butAbout = QPushButton("About", self) # pop-up "About" window self.butSettings = QPushButton("Settings", self) # self.butSettings.setCheckable(True) self.butSettings.setChecked(False) self.butSettings.setToolTip("Display and set some settings") layHControls1 = QHBoxLayout() layHControls1.addWidget(self.butFiltPerf) layHControls1.addWidget(self.butAbout) layHControls1.addWidget(self.butSettings) layHControls1.addWidget(self.butDebug) self.butDocstring = QPushButton("Doc$", self) self.butDocstring.setCheckable(True) self.butDocstring.setChecked(False) self.butDocstring.setToolTip("Display docstring from python filter method.") self.butRichText = QPushButton("RTF", self) self.butRichText.setCheckable(HAS_DOCUTILS) self.butRichText.setChecked(HAS_DOCUTILS) self.butRichText.setEnabled(HAS_DOCUTILS) self.butRichText.setToolTip("Render documentation in Rich Text Format.") self.butFiltDict = QPushButton("FiltDict", self) self.butFiltDict.setToolTip("Show filter dictionary for debugging.") self.butFiltDict.setCheckable(True) self.butFiltDict.setChecked(False) self.butFiltTree = QPushButton("FiltTree", self) self.butFiltTree.setToolTip("Show filter tree for debugging.") self.butFiltTree.setCheckable(True) self.butFiltTree.setChecked(False) layHControls2 = QHBoxLayout() layHControls2.addWidget(self.butDocstring) # layHControls2.addStretch(1) layHControls2.addWidget(self.butRichText) # layHControls2.addStretch(1) layHControls2.addWidget(self.butFiltDict) # layHControls2.addStretch(1) layHControls2.addWidget(self.butFiltTree) self.frmControls2 = QFrame(self) self.frmControls2.setLayout(layHControls2) self.frmControls2.setVisible(self.butDebug.isChecked()) self.frmControls2.setContentsMargins(0, 0, 0, 0) lbl_settings_NFFT = QLabel(to_html("N_FFT =", frmt='bi'), self) self.led_settings_NFFT = QLineEdit(self) self.led_settings_NFFT.setText(str(params['N_FFT'])) self.led_settings_NFFT.setToolTip("<span>Number of FFT points for frequency " "domain widgets.</span>") layGSettings = QGridLayout() layGSettings.addWidget(lbl_settings_NFFT, 1, 0) layGSettings.addWidget(self.led_settings_NFFT, 1, 1) self.frmSettings = QFrame(self) self.frmSettings.setLayout(layGSettings) self.frmSettings.setVisible(self.butSettings.isChecked()) self.frmSettings.setContentsMargins(0, 0, 0, 0) layVControls = QVBoxLayout() layVControls.addLayout(layHControls1) layVControls.addWidget(self.frmControls2) layVControls.addWidget(self.frmSettings) self.frmMain = QFrame(self) self.frmMain.setLayout(layVControls) self.tblFiltPerf = QTableWidget(self) self.tblFiltPerf.setAlternatingRowColors(True) # self.tblFiltPerf.verticalHeader().setVisible(False) self.tblFiltPerf.horizontalHeader().setHighlightSections(False) self.tblFiltPerf.horizontalHeader().setFont(bfont) self.tblFiltPerf.verticalHeader().setHighlightSections(False) self.tblFiltPerf.verticalHeader().setFont(bfont) self.txtFiltInfoBox = QTextBrowser(self) self.txtFiltDict = QTextBrowser(self) self.txtFiltTree = QTextBrowser(self) layVMain = QVBoxLayout() layVMain.addWidget(self.frmMain) # layVMain.addLayout(self.layHControls) splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.tblFiltPerf) splitter.addWidget(self.txtFiltInfoBox) splitter.addWidget(self.txtFiltDict) splitter.addWidget(self.txtFiltTree) # setSizes uses absolute pixel values, but can be "misused" by specifying values # that are way too large: in this case, the space is distributed according # to the _ratio_ of the values: splitter.setSizes([3000, 10000, 1000, 1000]) layVMain.addWidget(splitter) layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) # ---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.butFiltPerf.clicked.connect(self._show_filt_perf) self.butAbout.clicked.connect(self._about_window) self.butSettings.clicked.connect(self._show_settings) self.led_settings_NFFT.editingFinished.connect(self._update_settings_nfft) self.butDebug.clicked.connect(self._show_debug) self.butFiltDict.clicked.connect(self._show_filt_dict) self.butFiltTree.clicked.connect(self._show_filt_tree) self.butDocstring.clicked.connect(self._show_doc) self.butRichText.clicked.connect(self._show_doc)
def _construct_UI(self) -> None: """ Intitialize the main GUI, consisting of: - A combo box to select the filter topology and an image of the topology - The input quantizer - The UI of the fixpoint filter widget - Simulation and export buttons """ # ------------------------------------------------------------------------------ # Define frame and layout for the dynamically updated filter widget # The actual filter widget is instantiated in self.set_fixp_widget() later on self.layH_fx_wdg = QHBoxLayout() # self.layH_fx_wdg.setContentsMargins(*params['wdg_margins']) frmHDL_wdg = QFrame(self) frmHDL_wdg.setLayout(self.layH_fx_wdg) # frmHDL_wdg.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # ------------------------------------------------------------------------------ # Initialize fixpoint filter combobox, title and description # ------------------------------------------------------------------------------ self.cmb_fx_wdg = QComboBox(self) self.cmb_fx_wdg.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.lblTitle = QLabel("not set", self) self.lblTitle.setWordWrap(True) self.lblTitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) layHTitle = QHBoxLayout() layHTitle.addWidget(self.cmb_fx_wdg) layHTitle.addWidget(self.lblTitle) self.frmTitle = QFrame(self) self.frmTitle.setLayout(layHTitle) self.frmTitle.setContentsMargins(*params['wdg_margins']) # ------------------------------------------------------------------------------ # Input and Output Quantizer # ------------------------------------------------------------------------------ # - instantiate widgets for input and output quantizer # - pass the quantization (sub-?) dictionary to the constructor # ------------------------------------------------------------------------------ self.wdg_w_input = UI_W(self, q_dict=fb.fil[0]['fxqc']['QI'], wdg_name='w_input', label='', lock_visible=True) self.wdg_w_input.sig_tx.connect(self.process_sig_rx_local) cmb_q = ['round', 'floor', 'fix'] self.wdg_w_output = UI_W(self, q_dict=fb.fil[0]['fxqc']['QO'], wdg_name='w_output', label='') self.wdg_w_output.sig_tx.connect(self.process_sig_rx_local) self.wdg_q_output = UI_Q(self, q_dict=fb.fil[0]['fxqc']['QO'], wdg_name='q_output', label='Output Format <i>Q<sub>Y </sub></i>:', cmb_q=cmb_q, cmb_ov=['wrap', 'sat']) self.wdg_q_output.sig_tx.connect(self.sig_rx_local) if HAS_DS: cmb_q.append('dsm') self.wdg_q_input = UI_Q(self, q_dict=fb.fil[0]['fxqc']['QI'], wdg_name='q_input', label='Input Format <i>Q<sub>X </sub></i>:', cmb_q=cmb_q) self.wdg_q_input.sig_tx.connect(self.sig_rx_local) # Layout and frame for input quantization layVQiWdg = QVBoxLayout() layVQiWdg.addWidget(self.wdg_q_input) layVQiWdg.addWidget(self.wdg_w_input) frmQiWdg = QFrame(self) # frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmQiWdg.setLayout(layVQiWdg) frmQiWdg.setContentsMargins(*params['wdg_margins']) # Layout and frame for output quantization layVQoWdg = QVBoxLayout() layVQoWdg.addWidget(self.wdg_q_output) layVQoWdg.addWidget(self.wdg_w_output) frmQoWdg = QFrame(self) # frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmQoWdg.setLayout(layVQoWdg) frmQoWdg.setContentsMargins(*params['wdg_margins']) # ------------------------------------------------------------------------------ # Dynamically updated image of filter topology (label as placeholder) # ------------------------------------------------------------------------------ # allow setting background color # lbl_fixp_img_palette = QPalette() # lbl_fixp_img_palette.setColor(QPalette(window, Qt: white)) # lbl_fixp_img_palette.setBrush(self.backgroundRole(), QColor(150, 0, 0)) # lbl_fixp_img_palette.setColor(QPalette: WindowText, Qt: blue) self.lbl_fixp_img = QLabel("img not set", self) self.lbl_fixp_img.setAutoFillBackground(True) # self.lbl_fixp_img.setPalette(lbl_fixp_img_palette) # self.lbl_fixp_img.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.embed_fixp_img(self.no_fx_filter_img) layHImg = QHBoxLayout() layHImg.setContentsMargins(0, 0, 0, 0) layHImg.addWidget(self.lbl_fixp_img) # , Qt.AlignCenter) self.frmImg = QFrame(self) self.frmImg.setLayout(layHImg) self.frmImg.setContentsMargins(*params['wdg_margins']) # ------------------------------------------------------------------------------ # Simulation and export Buttons # ------------------------------------------------------------------------------ self.butExportHDL = QPushButton(self) self.butExportHDL.setToolTip( "Create Verilog or VHDL netlist for fixpoint filter.") self.butExportHDL.setText("Create HDL") self.butSimFx = QPushButton(self) self.butSimFx.setToolTip("Start fixpoint simulation.") self.butSimFx.setText("Sim. FX") self.layHHdlBtns = QHBoxLayout() self.layHHdlBtns.addWidget(self.butSimFx) self.layHHdlBtns.addWidget(self.butExportHDL) # This frame encompasses the HDL buttons sim and convert frmHdlBtns = QFrame(self) # frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmHdlBtns.setLayout(self.layHHdlBtns) frmHdlBtns.setContentsMargins(*params['wdg_margins']) # ------------------------------------------------------------------- # Top level layout # ------------------------------------------------------------------- splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(frmHDL_wdg) splitter.addWidget(frmQoWdg) splitter.addWidget(self.frmImg) # setSizes uses absolute pixel values, but can be "misused" by specifying values # that are way too large: in this case, the space is distributed according # to the _ratio_ of the values: splitter.setSizes([3000, 3000, 5000]) layVMain = QVBoxLayout() layVMain.addWidget(self.frmTitle) layVMain.addWidget(frmHdlBtns) layVMain.addWidget(frmQiWdg) layVMain.addWidget(splitter) layVMain.addStretch() layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) # ---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) self.sig_rx_local.connect(self.process_sig_rx_local) # dynamic connection in `self._update_fixp_widget()`: # ----- # if hasattr(self.fx_filt_ui, "sig_rx"): # self.sig_rx.connect(self.fx_filt_ui.sig_rx) # if hasattr(self.fx_filt_ui, "sig_tx"): # self.fx_filt_ui.sig_tx.connect(self.sig_rx_local) # ---- # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.cmb_fx_wdg.currentIndexChanged.connect(self._update_fixp_widget) self.butExportHDL.clicked.connect(self.exportHDL) self.butSimFx.clicked.connect(lambda x: self.emit({'fx_sim': 'start'}))
def _construct_UI(self): """ Intitialize the widget, consisting of: - Matplotlib widget with NavigationToolbar - Frame with control elements """ self.bfont = QFont() self.bfont.setBold(True) self.chk_auto_N = QCheckBox(self) self.chk_auto_N.setChecked(False) self.chk_auto_N.setToolTip( "Use number of points from calling routine.") self.lbl_auto_N = QLabel("Auto " + to_html("N", frmt='i')) self.led_N = QLineEdit(self) self.led_N.setText(str(self.N)) self.led_N.setMaximumWidth(70) self.led_N.setToolTip("<span>Number of window data points.</span>") self.chk_log_t = QCheckBox("Log", self) self.chk_log_t.setChecked(False) self.chk_log_t.setToolTip("Display in dB") self.led_log_bottom_t = QLineEdit(self) self.led_log_bottom_t.setText(str(self.bottom_t)) self.led_log_bottom_t.setMaximumWidth(50) self.led_log_bottom_t.setEnabled(self.chk_log_t.isChecked()) self.led_log_bottom_t.setToolTip( "<span>Minimum display value for log. scale.</span>") self.lbl_log_bottom_t = QLabel("dB", self) self.lbl_log_bottom_t.setEnabled(self.chk_log_t.isChecked()) self.chk_norm_f = QCheckBox("Norm", self) self.chk_norm_f.setChecked(True) self.chk_norm_f.setToolTip( "Normalize window spectrum for a maximum of 1.") self.chk_half_f = QCheckBox("Half", self) self.chk_half_f.setChecked(True) self.chk_half_f.setToolTip( "Display window spectrum in the range 0 ... 0.5 f_S.") self.chk_log_f = QCheckBox("Log", self) self.chk_log_f.setChecked(True) self.chk_log_f.setToolTip("Display in dB") self.led_log_bottom_f = QLineEdit(self) self.led_log_bottom_f.setText(str(self.bottom_f)) self.led_log_bottom_f.setMaximumWidth(50) self.led_log_bottom_f.setEnabled(self.chk_log_f.isChecked()) self.led_log_bottom_f.setToolTip( "<span>Minimum display value for log. scale.</span>") self.lbl_log_bottom_f = QLabel("dB", self) self.lbl_log_bottom_f.setEnabled(self.chk_log_f.isChecked()) layHControls = QHBoxLayout() layHControls.addWidget(self.chk_auto_N) layHControls.addWidget(self.lbl_auto_N) layHControls.addWidget(self.led_N) layHControls.addStretch(1) layHControls.addWidget(self.chk_log_t) layHControls.addWidget(self.led_log_bottom_t) layHControls.addWidget(self.lbl_log_bottom_t) layHControls.addStretch(10) layHControls.addWidget(self.chk_norm_f) layHControls.addStretch(1) layHControls.addWidget(self.chk_half_f) layHControls.addStretch(1) layHControls.addWidget(self.chk_log_f) layHControls.addWidget(self.led_log_bottom_f) layHControls.addWidget(self.lbl_log_bottom_f) self.tblWinProperties = QTableWidget(self.tbl_rows, self.tbl_cols, self) self.tblWinProperties.setAlternatingRowColors(True) self.tblWinProperties.verticalHeader().setVisible(False) self.tblWinProperties.horizontalHeader().setVisible(False) self._init_table(self.tbl_rows, self.tbl_cols, " ") self.txtInfoBox = QTextBrowser(self) #---------------------------------------------------------------------- # ### frmControls ### # # This widget encompasses all control subwidgets #---------------------------------------------------------------------- self.frmControls = QFrame(self) self.frmControls.setObjectName("frmControls") self.frmControls.setLayout(layHControls) #---------------------------------------------------------------------- # ### mplwidget ### # # main widget: Layout layVMainMpl (VBox) is defined with MplWidget, # additional widgets can be added (like self.frmControls) # The widget encompasses all other widgets. #---------------------------------------------------------------------- self.mplwidget = MplWidget(self) self.mplwidget.layVMainMpl.addWidget(self.frmControls) self.mplwidget.layVMainMpl.setContentsMargins(*params['wdg_margins']) #---------------------------------------------------------------------- # ### frmInfo ### # # This widget encompasses the text info box and the table with window # parameters. #---------------------------------------------------------------------- layVInfo = QVBoxLayout(self) layVInfo.addWidget(self.tblWinProperties) layVInfo.addWidget(self.txtInfoBox) self.frmInfo = QFrame(self) self.frmInfo.setObjectName("frmInfo") self.frmInfo.setLayout(layVInfo) #---------------------------------------------------------------------- # ### splitter ### # # This widget encompasses all control subwidgets #---------------------------------------------------------------------- splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.mplwidget) splitter.addWidget(self.frmInfo) # setSizes uses absolute pixel values, but can be "misused" by specifying values # that are way too large: in this case, the space is distributed according # to the _ratio_ of the values: splitter.setSizes([3000, 1000]) layVMain = QVBoxLayout() layVMain.addWidget(splitter) self.setLayout(layVMain) #---------------------------------------------------------------------- # Set subplots # self.ax = self.mplwidget.fig.subplots(nrows=1, ncols=2) self.ax_t = self.ax[0] self.ax_f = self.ax[1] self.draw() # initial drawing #---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.chk_log_f.clicked.connect(self.update_view) self.chk_log_t.clicked.connect(self.update_view) self.led_log_bottom_t.editingFinished.connect(self.update_bottom) self.led_log_bottom_f.editingFinished.connect(self.update_bottom) self.chk_auto_N.clicked.connect(self.calc_N) self.led_N.editingFinished.connect(self.draw) self.chk_norm_f.clicked.connect(self.draw) self.chk_half_f.clicked.connect(self.update_view) self.mplwidget.mplToolbar.sig_tx.connect(self.process_sig_rx) self.tblWinProperties.itemClicked.connect(self._handle_item_clicked)
def _construct_UI(self): """ Intitialize the widget, consisting of: - Matplotlib widget with NavigationToolbar - Frame with control elements """ self.bfont = QFont() self.bfont.setBold(True) self.qfft_win_select = QFFTWinSelector(self, self.win_dict) self.lbl_N = QLabel(to_html("N =", frmt='bi')) self.led_N = QLineEdit(self) self.led_N.setText(str(self.N_view)) self.led_N.setMaximumWidth(qtext_width(N_x=8)) self.led_N.setToolTip( "<span>Number of window data points to display.</span>") # By default, the enter key triggers the default 'dialog action' in QDialog # widgets. This activates one of the pushbuttons. self.but_log_t = QPushButton("dB", default=False, autoDefault=False) self.but_log_t.setMaximumWidth(qtext_width(" dB ")) self.but_log_t.setObjectName("chk_log_time") self.but_log_t.setCheckable(True) self.but_log_t.setChecked(False) self.but_log_t.setToolTip("Display in dB") self.led_log_bottom_t = QLineEdit(self) self.led_log_bottom_t.setVisible(self.but_log_t.isChecked()) self.led_log_bottom_t.setText(str(self.bottom_t)) self.led_log_bottom_t.setMaximumWidth(qtext_width(N_x=6)) self.led_log_bottom_t.setToolTip( "<span>Minimum display value for log. scale.</span>") self.lbl_log_bottom_t = QLabel(to_html("min =", frmt='bi'), self) self.lbl_log_bottom_t.setVisible(self.but_log_t.isChecked()) self.but_norm_f = QPushButton("Max=1", default=False, autoDefault=False) self.but_norm_f.setCheckable(True) self.but_norm_f.setChecked(True) self.but_norm_f.setMaximumWidth(qtext_width(text=" Max=1 ")) self.but_norm_f.setToolTip( "Normalize window spectrum for a maximum of 1.") self.but_half_f = QPushButton("0...½", default=False, autoDefault=False) self.but_half_f.setCheckable(True) self.but_half_f.setChecked(True) self.but_half_f.setMaximumWidth(qtext_width(text=" 0...½ ")) self.but_half_f.setToolTip( "Display window spectrum in the range 0 ... 0.5 f_S.") # By default, the enter key triggers the default 'dialog action' in QDialog # widgets. This activates one of the pushbuttons. self.but_log_f = QPushButton("dB", default=False, autoDefault=False) self.but_log_f.setMaximumWidth(qtext_width(" dB ")) self.but_log_f.setObjectName("chk_log_freq") self.but_log_f.setToolTip("<span>Display in dB.</span>") self.but_log_f.setCheckable(True) self.but_log_f.setChecked(True) self.lbl_log_bottom_f = QLabel(to_html("min =", frmt='bi'), self) self.lbl_log_bottom_f.setVisible(self.but_log_f.isChecked()) self.led_log_bottom_f = QLineEdit(self) self.led_log_bottom_f.setVisible(self.but_log_t.isChecked()) self.led_log_bottom_f.setText(str(self.bottom_f)) self.led_log_bottom_f.setMaximumWidth(qtext_width(N_x=6)) self.led_log_bottom_f.setToolTip( "<span>Minimum display value for log. scale.</span>") # ---------------------------------------------------------------------- # ### frmControls ### # # This widget encompasses all control subwidgets # ---------------------------------------------------------------------- layH_win_select = QHBoxLayout() layH_win_select.addWidget(self.qfft_win_select) layH_win_select.setContentsMargins(0, 0, 0, 0) layH_win_select.addStretch(1) frmQFFT = QFrame(self) frmQFFT.setObjectName("frmQFFT") frmQFFT.setLayout(layH_win_select) hline = QHLine() layHControls = QHBoxLayout() layHControls.addWidget(self.lbl_N) layHControls.addWidget(self.led_N) layHControls.addStretch(1) layHControls.addWidget(self.lbl_log_bottom_t) layHControls.addWidget(self.led_log_bottom_t) layHControls.addWidget(self.but_log_t) layHControls.addStretch(5) layHControls.addWidget(QVLine(width=2)) layHControls.addStretch(5) layHControls.addWidget(self.but_norm_f) layHControls.addStretch(1) layHControls.addWidget(self.but_half_f) layHControls.addStretch(1) layHControls.addWidget(self.lbl_log_bottom_f) layHControls.addWidget(self.led_log_bottom_f) layHControls.addWidget(self.but_log_f) layVControls = QVBoxLayout() layVControls.addWidget(frmQFFT) layVControls.addWidget(hline) layVControls.addLayout(layHControls) frmControls = QFrame(self) frmControls.setObjectName("frmControls") frmControls.setLayout(layVControls) # ---------------------------------------------------------------------- # ### mplwidget ### # # Layout layVMainMpl (VBox) is defined within MplWidget, additional # widgets can be added below the matplotlib widget (here: frmControls) # # ---------------------------------------------------------------------- self.mplwidget = MplWidget(self) self.mplwidget.layVMainMpl.addWidget(frmControls) self.mplwidget.layVMainMpl.setContentsMargins(0, 0, 0, 0) # ---------------------------------------------------------------------- # ### frmInfo ### # # This widget encompasses the text info box and the table with window # parameters. # ---------------------------------------------------------------------- self.tbl_win_props = QTableWidget(self.tbl_rows, self.tbl_cols, self) self.tbl_win_props.setAlternatingRowColors(True) # Auto-resize of table can be set using the header (although it is invisible) self.tbl_win_props.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) # Only the columns with data are stretched, the others are minimum size self.tbl_win_props.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.tbl_win_props.horizontalHeader().setSectionResizeMode( 4, QHeaderView.Stretch) self.tbl_win_props.verticalHeader().setVisible(False) self.tbl_win_props.horizontalHeader().setVisible(False) self.tbl_win_props.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.tbl_win_props.setFixedHeight( self.tbl_win_props.rowHeight(0) * self.tbl_rows + self.tbl_win_props.frameWidth() * 2) # self.tbl_win_props.setVerticalScrollBarPolicy( # Qt.ScrollBarAlwaysOff) # self.tbl_win_props.setHorizontalScrollBarPolicy( # Qt.ScrollBarAlwaysOff) self._construct_table(self.tbl_rows, self.tbl_cols, " ") self.txtInfoBox = QTextBrowser(self) layVInfo = QVBoxLayout(self) layVInfo.addWidget(self.tbl_win_props) layVInfo.addWidget(self.txtInfoBox) frmInfo = QFrame(self) frmInfo.setObjectName("frmInfo") frmInfo.setLayout(layVInfo) # ---------------------------------------------------------------------- # ### splitter ### # # This widget encompasses all subwidgets # ---------------------------------------------------------------------- splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.mplwidget) splitter.addWidget(frmInfo) # setSizes uses absolute pixel values, but can be "misused" by # specifying values that are way too large: in this case, the space # is distributed according to the _ratio_ of the values: splitter.setSizes([3000, 800]) layVMain = QVBoxLayout() layVMain.addWidget(splitter) self.setLayout(layVMain) # ---------------------------------------------------------------------- # Set subplots # self.ax = self.mplwidget.fig.subplots(nrows=1, ncols=2) self.ax_t = self.ax[0] self.ax_f = self.ax[1] self.calc_win_draw() # initial calculation and drawing # ---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) self.sig_rx.connect(self.qfft_win_select.sig_rx) # ---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs # ---------------------------------------------------------------------- self.but_log_f.clicked.connect(self.update_view) self.but_log_t.clicked.connect(self.update_view) self.led_log_bottom_t.editingFinished.connect(self.update_bottom) self.led_log_bottom_f.editingFinished.connect(self.update_bottom) self.led_N.editingFinished.connect(self.calc_win_draw) self.but_norm_f.clicked.connect(self.calc_win_draw) self.but_half_f.clicked.connect(self.update_view) self.mplwidget.mplToolbar.sig_tx.connect(self.process_sig_rx) self.tbl_win_props.itemClicked.connect(self._handle_item_clicked) self.qfft_win_select.sig_tx.connect(self.update_fft_win)
def _construct_UI(self): """ Intitialize the widget, consisting of: - Checkboxes for selecting the info to be displayed - A large text window for displaying infos about the filter design algorithm """ bfont = QFont() bfont.setBold(True) # ============== UI Layout ===================================== # widget / subwindow for filter infos self.chkFiltPerf = QCheckBox("H(f)", self) self.chkFiltPerf.setChecked(True) self.chkFiltPerf.setToolTip( "Display frequency response at test frequencies.") self.chkDocstring = QCheckBox("Doc$", self) self.chkDocstring.setChecked(False) self.chkDocstring.setToolTip( "Display docstring from python filter method.") self.chkRichText = QCheckBox("RTF", self) self.chkRichText.setChecked(HAS_DOCUTILS) self.chkRichText.setEnabled(HAS_DOCUTILS) self.chkRichText.setToolTip( "Render documentation in Rich Text Format.") self.chkFiltDict = QCheckBox("FiltDict", self) self.chkFiltDict.setToolTip("Show filter dictionary for debugging.") self.chkFiltTree = QCheckBox("FiltTree", self) self.chkFiltTree.setToolTip("Show filter tree for debugging.") self.layHChkBoxes = QHBoxLayout() self.layHChkBoxes.addWidget(self.chkFiltPerf) self.layHChkBoxes.addStretch(1) self.layHChkBoxes.addWidget(self.chkDocstring) self.layHChkBoxes.addStretch(1) self.layHChkBoxes.addWidget(self.chkRichText) self.layHChkBoxes.addStretch(1) self.layHChkBoxes.addWidget(self.chkFiltDict) self.layHChkBoxes.addStretch(1) self.layHChkBoxes.addWidget(self.chkFiltTree) self.frmMain = QFrame(self) self.frmMain.setLayout(self.layHChkBoxes) self.tblFiltPerf = QTableWidget(self) self.tblFiltPerf.setAlternatingRowColors(True) # self.tblFiltPerf.verticalHeader().setVisible(False) self.tblFiltPerf.horizontalHeader().setHighlightSections(False) self.tblFiltPerf.horizontalHeader().setFont(bfont) self.tblFiltPerf.verticalHeader().setHighlightSections(False) self.tblFiltPerf.verticalHeader().setFont(bfont) self.txtFiltInfoBox = QTextBrowser(self) self.txtFiltDict = QTextBrowser(self) self.txtFiltTree = QTextBrowser(self) layVMain = QVBoxLayout() layVMain.addWidget(self.frmMain) # layVMain.addLayout(self.layHChkBoxes) splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.tblFiltPerf) splitter.addWidget(self.txtFiltInfoBox) splitter.addWidget(self.txtFiltDict) splitter.addWidget(self.txtFiltTree) # setSizes uses absolute pixel values, but can be "misused" by specifying values # that are way too large: in this case, the space is distributed according # to the _ratio_ of the values: splitter.setSizes([3000, 10000, 1000, 1000]) layVMain.addWidget(splitter) layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) #---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.chkFiltPerf.clicked.connect(self._show_filt_perf) self.chkFiltDict.clicked.connect(self._show_filt_dict) self.chkFiltTree.clicked.connect(self._show_filt_tree) self.chkDocstring.clicked.connect(self._show_doc) self.chkRichText.clicked.connect(self._show_doc)
def _construct_UI(self): """ Intitialize the main GUI, consisting of: - A combo box to select the filter topology and an image of the topology - The input quantizer - The UI of the fixpoint filter widget - Simulation and export buttons """ #------------------------------------------------------------------------------ # Define frame and layout for the dynamically updated filter widget # The actual filter widget is instantiated in self.set_fixp_widget() later on self.layH_fx_wdg = QHBoxLayout() #self.layH_fx_wdg.setContentsMargins(*params['wdg_margins']) frmHDL_wdg = QFrame(self) frmHDL_wdg.setLayout(self.layH_fx_wdg) #frmHDL_wdg.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) #------------------------------------------------------------------------------ # Initialize fixpoint filter combobox, title and description #------------------------------------------------------------------------------ self.cmb_wdg_fixp = QComboBox(self) self.cmb_wdg_fixp.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.lblTitle = QLabel("not set", self) self.lblTitle.setWordWrap(True) self.lblTitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) layHTitle = QHBoxLayout() layHTitle.addWidget(self.cmb_wdg_fixp) layHTitle.addWidget(self.lblTitle) self.frmTitle = QFrame(self) self.frmTitle.setLayout(layHTitle) self.frmTitle.setContentsMargins(*params['wdg_margins']) #------------------------------------------------------------------------------ # Input and Output Quantizer #------------------------------------------------------------------------------ # - instantiate widgets for input and output quantizer # - pass the quantization (sub-?) dictionary to the constructor #------------------------------------------------------------------------------ self.wdg_w_input = UI_W(self, q_dict=fb.fil[0]['fxqc']['QI'], id='w_input', label='', lock_visible=True) self.wdg_w_input.sig_tx.connect(self.process_sig_rx) cmb_q = ['round', 'floor', 'fix'] self.wdg_w_output = UI_W(self, q_dict=fb.fil[0]['fxqc']['QO'], id='w_output', label='') self.wdg_w_output.sig_tx.connect(self.process_sig_rx) self.wdg_q_output = UI_Q( self, q_dict=fb.fil[0]['fxqc']['QO'], id='q_output', label='Output Format <i>Q<sub>Y </sub></i>:', cmb_q=cmb_q, cmb_ov=['wrap', 'sat']) self.wdg_q_output.sig_tx.connect(self.sig_rx) if HAS_DS: cmb_q.append('dsm') self.wdg_q_input = UI_Q( self, q_dict=fb.fil[0]['fxqc']['QI'], id='q_input', label='Input Format <i>Q<sub>X </sub></i>:', cmb_q=cmb_q) self.wdg_q_input.sig_tx.connect(self.sig_rx) # Layout and frame for input quantization layVQiWdg = QVBoxLayout() layVQiWdg.addWidget(self.wdg_q_input) layVQiWdg.addWidget(self.wdg_w_input) frmQiWdg = QFrame(self) #frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmQiWdg.setLayout(layVQiWdg) frmQiWdg.setContentsMargins(*params['wdg_margins']) # Layout and frame for output quantization layVQoWdg = QVBoxLayout() layVQoWdg.addWidget(self.wdg_q_output) layVQoWdg.addWidget(self.wdg_w_output) frmQoWdg = QFrame(self) #frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmQoWdg.setLayout(layVQoWdg) frmQoWdg.setContentsMargins(*params['wdg_margins']) #------------------------------------------------------------------------------ # Dynamically updated image of filter topology #------------------------------------------------------------------------------ # label is a placeholder for image self.lbl_fixp_img = QLabel("img not set", self) #self.lbl_fixp_img.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.embed_fixp_img(self.no_fx_filter_img) layHImg = QHBoxLayout() layHImg.setContentsMargins(0, 0, 0, 0) layHImg.addWidget(self.lbl_fixp_img) #, Qt.AlignCenter) self.frmImg = QFrame(self) self.frmImg.setLayout(layHImg) self.frmImg.setContentsMargins(*params['wdg_margins']) self.resize_img() #------------------------------------------------------------------------------ # Simulation and export Buttons #------------------------------------------------------------------------------ self.butExportHDL = QPushButton(self) self.butExportHDL.setToolTip( "Export fixpoint filter in Verilog format.") self.butExportHDL.setText("Create HDL") self.butSimHDL = QPushButton(self) self.butSimHDL.setToolTip("Start migen fixpoint simulation.") self.butSimHDL.setText("Sim. HDL") self.butSimFxPy = QPushButton(self) self.butSimFxPy.setToolTip("Simulate filter with fixpoint effects.") self.butSimFxPy.setText("Sim. FixPy") self.layHHdlBtns = QHBoxLayout() self.layHHdlBtns.addWidget(self.butSimFxPy) self.layHHdlBtns.addWidget(self.butSimHDL) self.layHHdlBtns.addWidget(self.butExportHDL) # This frame encompasses the HDL buttons sim and convert frmHdlBtns = QFrame(self) #frmBtns.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) frmHdlBtns.setLayout(self.layHHdlBtns) frmHdlBtns.setContentsMargins(*params['wdg_margins']) # ------------------------------------------------------------------- # Top level layout # ------------------------------------------------------------------- splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(frmHDL_wdg) splitter.addWidget(frmQoWdg) splitter.addWidget(self.frmImg) # setSizes uses absolute pixel values, but can be "misused" by specifying values # that are way too large: in this case, the space is distributed according # to the _ratio_ of the values: splitter.setSizes([3000, 3000, 5000]) layVMain = QVBoxLayout() layVMain.addWidget(self.frmTitle) layVMain.addWidget(frmHdlBtns) layVMain.addWidget(frmQiWdg) layVMain.addWidget(splitter) layVMain.addStretch() layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) #---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) #---------------------------------------------------------------------- # LOCAL SIGNALS & SLOTs & EVENTFILTERS #---------------------------------------------------------------------- # monitor events and generate sig_resize event when resized self.lbl_fixp_img.installEventFilter(self) # ... then redraw image when resized self.sig_resize.connect(self.resize_img) self.cmb_wdg_fixp.currentIndexChanged.connect(self._update_fixp_widget) self.butExportHDL.clicked.connect(self.exportHDL) self.butSimHDL.clicked.connect(self.fx_sim_init) #---------------------------------------------------------------------- inst_wdg_list = self._update_filter_cmb() if len(inst_wdg_list) == 0: logger.warning("No fixpoint filters found!") else: logger.debug("Imported {0:d} fixpoint filters:\n{1}".format( len(inst_wdg_list.split("\n")) - 1, inst_wdg_list)) self._update_fixp_widget()