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