Coverage for src/scrilla/gui/widgets/menu.py: 0%
135 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-18 18:14 +0000
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-18 18:14 +0000
1# This file is part of scrilla: https://github.com/chinchalinchin/scrilla.
3# scrilla is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License version 3
5# as published by the Free Software Foundation.
7# scrilla is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
12# You should have received a copy of the GNU General Public License
13# along with scrilla. If not, see <https://www.gnu.org/licenses/>
14# or <https://github.com/chinchalinchin/scrilla/blob/develop/main/LICENSE>.
16import sys
18from PySide6 import QtCore, QtWidgets, QtGui
20from scrilla import settings
22from scrilla.gui import utilities, definitions
23from scrilla.gui.widgets import factories, functions
25# NOTE: widget_buttons and function_widgets must preserve order.
27def _to_class(name: str):
28 if name == 'correlation':
29 return functions.CorrelationWidget
30 if name == 'plot_return_dist':
31 return functions.DistributionWidget
32 if name == 'yield_curve':
33 return functions.YieldCurveWidget
34 if name == 'discount_dividend':
35 return functions.DiscountDividendWidget
36 if name == 'risk_profile':
37 return functions.RiskProfileWidget
38 if name == 'optimize_portfolio':
39 return functions.OptimizerWidget
40 if name == 'efficient_frontier':
41 return functions.EfficientFrontierWidget
42 if name == 'moving_averages':
43 return functions.MovingAverageWidget
45class MenuWidget(QtWidgets.QWidget):
46 """
48 .. notes::
49 * Widget Hierarchy:
51 .. links::
52 * [Stack Overflow: Weird Lambda Behavior in Loops](https://stackoverflow.com/questions/19768456/weird-lambda-behaviour-in-loops)
53 """
55 def __init__(self):
56 super().__init__()
57 self._init_menu_widgets()
58 self._generate_menu_bar()
59 self._generate_splash()
60 self._arrange_menu_widgets()
61 self._stage_menu_widgets()
63 def _generate_menu_bar(self):
64 self.menu_bar = factories.atomic_widget_factory(
65 component='menu-bar')
66 self.menus = []
68 for j, menu in enumerate(definitions.MENUBAR_WIDGET):
69 self.menus.append(self.menu_bar.addMenu(menu))
70 for i, action in enumerate(definitions.MENUBAR_WIDGET[menu]):
71 q_action = QtGui.QAction(action['name'], self)
72 q_action.setShortcut(action['shortcut'])
73 if menu == 'Functions':
74 q_action.triggered.connect(
75 (lambda i: lambda: self._show_widget(i))(i)
76 )
77 elif menu == 'Account':
78 if action['name'] == 'Add API Key':
79 q_action.triggered.connect(
80 (lambda action: lambda:
81 self._show_api_key_dialog(action['options']))(action)
82 )
83 elif menu == 'View':
84 if action['name'] == 'Function Menu':
85 q_action.triggered.connect(lambda: self.function_menu.setVisible(
86 (not self.function_menu.isVisible())))
87 elif action['name'] == 'Splash Menu':
88 q_action.triggered.connect(self._clear)
90 self.menus[j].addAction(q_action)
92 def _generate_splash(self):
93 self.splash_container = factories.layout_factory(layout='vertical-box')
94 self.source_button = factories.atomic_widget_factory(
95 component='source-button', title=None)
96 self.package_button = factories.atomic_widget_factory(
97 component='package-button', title=None)
98 self.documentation_button = factories.atomic_widget_factory(
99 component='documentation-button', title=None)
100 self.splash = factories.atomic_widget_factory(
101 component='splash', title=None)
103 self.splash_button_panel = factories.layout_factory(
104 layout='horizontal-box')
106 self.splash_button_panel.layout().addStretch()
107 self.splash_button_panel.layout().addWidget(self.source_button)
108 self.splash_button_panel.layout().addWidget(self.package_button)
109 self.splash_button_panel.layout().addWidget(self.documentation_button)
110 self.splash_button_panel.layout().addStretch()
112 def _init_menu_widgets(self):
113 self.setObjectName('root')
114 self.title = factories.atomic_widget_factory(
115 component='title', title=settings.APP_NAME)
117 self.function_menu = factories.layout_factory(layout='vertical-box')
118 self.function_menu.setObjectName('grand-child')
119 self.function_title_container = factories.layout_factory(
120 layout='horizontal-box')
121 self.function_title = factories.atomic_widget_factory(
122 component='heading', title='Functions')
123 self.function_hide_button = factories.atomic_widget_factory(
124 component='hide-button', title=None)
126 self.widget_buttons = [factories.atomic_widget_factory(
127 component='button', title=function['name']) for function in definitions.FUNC_WIDGETS.values()]
128 self.exit_button = factories.atomic_widget_factory(
129 component='button', title="Exit")
131 self.function_widgets = [_to_class(function)(
132 'great-grand-child', self) for function in definitions.FUNC_WIDGETS]
134 self.display_pane = factories.layout_factory(layout='vertical-box')
135 self.display_pane.setObjectName('grand-child')
137 self.container_pane = factories.layout_factory(layout='horizontal-box')
138 self.container_pane.setObjectName('child')
140 self.setLayout(QtWidgets.QVBoxLayout())
142 def _arrange_menu_widgets(self):
143 """Arranges child widget within their layouts."""
144 self.title.setAlignment(QtCore.Qt.AlignHCenter)
146 self.container_pane.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
147 QtWidgets.QSizePolicy.Expanding))
148 self.function_menu.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum,
149 QtWidgets.QSizePolicy.Expanding))
150 self.display_pane.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
151 QtWidgets.QSizePolicy.Expanding))
152 self.title.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
153 QtWidgets.QSizePolicy.Minimum))
155 self.function_title_container.layout().addWidget(self.function_title)
156 self.function_title_container.layout().addWidget(self.function_hide_button)
158 self.function_menu.layout().addWidget(self.function_title_container)
159 for button in self.widget_buttons:
160 self.function_menu.layout().addWidget(button)
161 self.function_menu.layout().addStretch()
162 self.function_menu.layout().addWidget(self.exit_button)
164 self.splash_container.layout().addWidget(self.splash)
165 self.splash_container.layout().addStretch()
166 self.splash_container.layout().addWidget(self.splash_button_panel)
168 self.display_pane.layout().addWidget(self.splash_container)
169 for widget in self.function_widgets:
170 self.display_pane.layout().addWidget(widget)
172 self.container_pane.layout().addWidget(self.function_menu)
173 self.container_pane.layout().addWidget(self.display_pane)
175 self.layout().addWidget(self.menu_bar)
176 self.layout().addWidget(self.title)
177 self.layout().addWidget(self.container_pane)
179 def _stage_menu_widgets(self):
180 for i, button in enumerate(self.widget_buttons):
181 button.show()
182 # see #NOTE
183 button.clicked.connect((lambda i: lambda: self._show_widget(i))(i))
185 for widget in self.function_widgets:
186 widget.hide()
188 self.function_hide_button.clicked.connect(
189 lambda: utilities.switch_visibility(self.function_menu))
190 self.exit_button.clicked.connect(self.close)
191 self.source_button.clicked.connect(
192 lambda: utilities.open_browser(utilities.get_metadata('source')))
193 self.package_button.clicked.connect(
194 lambda: utilities.open_browser(utilities.get_metadata('package')))
195 self.documentation_button.clicked.connect(
196 lambda: utilities.open_browser(utilities.get_metadata('documentation')))
197 self.exit_button.show()
198 self.menu_bar.show()
200 def _clear(self):
201 for widget in self.function_widgets:
202 widget.hide()
203 self.splash_container.show()
205 @QtCore.Slot()
206 def _show_widget(self, widget_index):
207 self.splash_container.hide()
208 for widget in self.function_widgets:
209 widget.hide()
210 self.function_widgets[widget_index].show()
211 self.title.setText(list(definitions.FUNC_WIDGETS.values())[
212 widget_index]['name'])
214 @staticmethod
215 def _show_api_key_dialog(options):
216 dialog = factories.dialog_widget_factory('api-key-dialog', options)
217 dialog.exec_()
220if __name__ == "__main__":
221 app = QtWidgets.QApplication([])
223 mainWidget = MenuWidget()
224 mainWidget.resize(settings.GUI_WIDTH, settings.GUI_HEIGHT)
225 mainWidget.show()
227 sys.exit(app.exec_())