1# -*- coding: utf-8 -*- 2""" 3Tabbed container with all input widgets 4 5Author: Christian Münker 6""" 7from __future__ import print_function, division, unicode_literals, absolute_import 8import sys 9import logging 10logger = logging.getLogger(__name__) 11 12from ..compat import QTabWidget, QWidget, QVBoxLayout, QScrollArea, pyqtSignal 13 14SCROLL = True 15 16import pyfda.filterbroker as fb 17from pyfda.pyfda_rc import params 18 19from pyfda.input_widgets import (filter_specs, file_io, filter_coeffs, 20 filter_info, filter_pz) 21try: 22 import myhdl 23except ImportError: 24 fb.MYHDL = False 25else: 26 fb.MYHDL = True 27 from pyfda.hdl_generation import hdl_specs 28 29 30class InputTabWidgets(QWidget): 31 """ 32 Create a tabbed widget for various input subwidgets 33 """ 34 # class variables (shared between instances if more than one exists) 35 sigViewChanged = pyqtSignal() # emitted when view (e.g. single / double sided f) has changed 36 sigSpecsChanged = pyqtSignal() # emitted when specs have been changed 37 sigFilterDesigned = pyqtSignal() # emitted when filter has been designed 38 39 40 def __init__(self, parent): 41 42 if fb.MYHDL: 43 logger.info("Info: Module myHDL v{0} found -> filter synthesis enabled!".format(myhdl.__version__)) 44 45 super(InputTabWidgets, self).__init__(parent) 46 47 self.filter_specs = filter_specs.FilterSpecs(self) 48 self.filter_specs.setObjectName("filter_specs") 49 self.file_io = file_io.File_IO(self) 50 self.file_io.setObjectName("inputFiles") 51 self.filter_coeffs = filter_coeffs.FilterCoeffs(self) 52 self.filter_coeffs.setObjectName("filter_coeffs") 53 self.filter_pz = filter_pz.FilterPZ(self) 54 self.filter_pz.setObjectName("filter_pz") 55 self.filter_info = filter_info.FilterInfo(self) 56 self.filter_info.setObjectName("filter_info") 57 if fb.MYHDL: 58 self.hdlSpecs = hdl_specs.HDLSpecs(self) 59 60 self._construct_UI() 61 62 63 def _construct_UI(self): 64 """ Initialize UI with tabbed input widgets """ 65 tabWidget = QTabWidget(self) 66 tabWidget.setObjectName("input_tabs") 67 68 tabWidget.addTab(self.filter_specs, 'Specs') 69 tabWidget.addTab(self.file_io, 'Files') 70 tabWidget.addTab(self.filter_coeffs, 'b,a') 71 tabWidget.addTab(self.filter_pz, 'P/Z') 72 tabWidget.addTab(self.filter_info, 'Info') 73 if fb.MYHDL: 74 tabWidget.addTab(self.hdlSpecs, 'HDL') 75 76 layVMain = QVBoxLayout() 77 78 #setContentsMargins -> number of pixels between frame window border 79 layVMain.setContentsMargins(*params['wdg_margins']) 80 81#-------------------------------------- 82 if SCROLL: 83 scroll = QScrollArea(self) 84 scroll.setWidget(tabWidget) 85 scroll.setWidgetResizable(True) # Size of monitored widget is allowed to grow: 86 87 layVMain.addWidget(scroll) 88 else: 89 layVMain.addWidget(tabWidget) # add the tabWidget directly 90 91 self.setLayout(layVMain) # set the main layout of the window 92 93 94 #---------------------------------------------------------------------- 95 # SIGNALS & SLOTs 96 #---------------------------------------------------------------------- 97 # Collect "specs changed" / "filter designed" signals from all input 98 # widgets and route them to plot / input widgets that need to be updated 99 # 100 # Check: 101 #http://www.pythoncentral.io/pysidepyqt-tutorial-creating-your-own-signals-and-slots/#custom-tab-2-pyqt 102 # 103 # sigSpecsChanged: signal indicating that filter SPECS have changed, 104 # requiring update of some plot widgets and input widgets: 105 self.filter_specs.sigSpecsChanged.connect(self.update_specs) 106 # sigViewChanged: signal indicating that PLOT VIEW has changed, 107 # requiring update of some plot widgets only: 108 self.filter_specs.sigViewChanged.connect(self.update_view) 109 # 110 # sigFilterDesigned: signal indicating that filter has been DESIGNED, 111 # requiring update of all plot and some input widgets: 112 self.filter_specs.sigFilterDesigned.connect(self.update_all) 113 self.filter_coeffs.sigFilterDesigned.connect(self.update_all) 114 self.filter_pz.sigFilterDesigned.connect(self.update_all) 115 116 # The following three widgets require a reloading of the select_filter 117 # widget to update the filter selection: 118 self.filter_coeffs.sigFilterDesigned.connect(self.load_all) 119 self.filter_pz.sigFilterDesigned.connect(self.load_all) 120 self.file_io.sigFilterLoaded.connect(self.load_all) 121 #---------------------------------------------------------------------- 122 123 def update_view(self): 124 """ 125 Slot for InputSpecs.sigViewChanged 126 127 Propagate new PLOT VIEW (e.g. log scale) to plot widgets via pyfda.py 128 129 Update plot widgets via sigSpecsChanged signal that need new 130 specs, e.g. plotHf widget for the filter regions 131 """ 132 self.filter_info.load_dict() # update frequency unit of info widget 133 logger.debug("Emit sigViewChanged!") 134 self.sigViewChanged.emit() # pyFDA -> PlotTabWidgets.update_specs 135 136 137 def update_specs(self): 138 """ 139 Slot for FilterSpecs.sigSpecsChanged 140 141 Propagate new filter SPECS from filter dict to other input widgets and 142 to plot widgets via pyfda.py 143 144 - Update input widgets that can / need to display specs (except inputSpecs 145 - the origin of the signal !!) 146 - Update plot widgets via sigSpecsChanged signal that need new 147 specs, e.g. plotHf widget for the filter regions 148 """ 149 150 self.filter_specs.color_design_button("changed") 151 self.filter_info.load_dict() 152 if fb.MYHDL: 153 self.hdlSpecs.update_UI() 154 logger.debug("Emit sigSpecsChanged!") 155 self.sigSpecsChanged.emit() # pyFDA -> PlotTabWidgets.update_specs 156 157 def load_all(self): 158 """ 159 Called when a new filter has been LOADED: 160 Pass new filter data from the global filter dict 161 - Specifically call SelectFilter.load_dict 162 - Update the input widgets that can / need to display filter data 163 - Update all plot widgets via the signal sigFilterDesigned 164 """ 165 self.filter_specs.color_design_button("ok") 166 self.filter_specs.sel_fil.load_dict() # update select_filter widget 167 self.update_all() 168 169 170 def update_all(self): 171 """ 172 Slot for sigFilterDesigned from InputSpecs, FilterCoeffs, FilterPZ 173 174 Called when a new filter has been DESIGNED: 175 - Pass new filter data from the global filter dict 176 - Update the input widgets that can / need to display filter data 177 - Update all plot widgets via the signal sigFilterDesigned 178 179 """ 180 sender_name = "" 181 if self.sender(): # origin of signal that triggered the slot 182 sender_name = self.sender().objectName() 183 logger.debug("updateAll called by %s", sender_name) 184 185 self.filter_specs.load_dict() 186 self.filter_info.load_dict() 187 self.filter_coeffs.load_dict() 188 self.filter_pz.load_dict() 189 190 logger.debug("Emit sigFilterDesigned!") 191 self.sigFilterDesigned.emit() # pyFDA -> PlotTabWidgets.update_data 192 193 194#------------------------------------------------------------------------ 195 196def main(): 197 from pyfda import pyfda_rc as rc 198 from ..compat import QApplication 199 app = QApplication(sys.argv) 200 app.setStyleSheet(rc.css_rc) 201 202 mainw = InputTabWidgets(None) 203 app.setActiveWindow(mainw) 204 mainw.show() 205 sys.exit(app.exec_()) 206 207if __name__ == "__main__": 208 main() 209