Commit | Line | Data |
---|---|---|
94a18c21 | 1 | from logging import info, debug |
2612dfc8 FC |
2 | from sys import platform, exit |
3 | from os import environ, system | |
8c9bf90e FC |
4 | from glob import glob |
5 | from importlib import import_module | |
6 | from inspect import isclass | |
2612dfc8 FC |
7 | from webbrowser import open_new_tab |
8 | from panda3d.core import Texture, TextNode, WindowProperties, LVector2i, \ | |
9 | TextProperties, TextPropertiesManager | |
4071c6d8 | 10 | from direct.gui.DirectGui import DirectButton, DirectCheckButton, \ |
6fff1464 | 11 | DirectOptionMenu, DirectSlider, DirectCheckButton |
4071c6d8 | 12 | from direct.gui.DirectGuiGlobals import FLAT |
e1e44d5c | 13 | from direct.gui.OnscreenText import OnscreenText |
407412a5 | 14 | from lib.engine.gui.cursor import MouseCursor |
0d5a5427 FC |
15 | from pmachines.scene import Scene |
16 | from panda3d.bullet import BulletWorld | |
4071c6d8 FC |
17 | |
18 | ||
19 | class Menu: | |
20 | ||
a9aba267 | 21 | def __init__(self, fsm, lang_mgr, opt_file, music, pipeline): |
4071c6d8 FC |
22 | self._fsm = fsm |
23 | self._lang_mgr = lang_mgr | |
24 | self._opt_file = opt_file | |
e1e44d5c | 25 | self._music = music |
a9aba267 | 26 | self._pipeline = pipeline |
407412a5 FC |
27 | self._cursor = MouseCursor( |
28 | 'assets/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1), | |
29 | (.01, .01)) | |
4071c6d8 FC |
30 | self._font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') |
31 | self._font.clear() | |
32 | self._font.set_pixels_per_unit(60) | |
33 | self._font.set_minfilter(Texture.FTLinearMipmapLinear) | |
34 | self._font.set_outline((0, 0, 0, 1), .8, .2) | |
e1e44d5c | 35 | self._widgets = [] |
4071c6d8 FC |
36 | self._common = { |
37 | 'scale': .12, | |
38 | 'text_font': self._font, | |
39 | 'text_fg': (.9, .9, .9, 1), | |
40 | 'relief': FLAT, | |
41 | 'frameColor': (.4, .4, .4, .14), | |
42 | 'rolloverSound': loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
43 | 'clickSound': loader.load_sfx('assets/audio/sfx/click.ogg')} | |
75b89b83 | 44 | self._common_btn = {'frameSize': (-4.8, 4.8, -.6, 1.2)} | self._common |
6fff1464 FC |
45 | hlc = self._common_btn['frameColor'] |
46 | hlc = (hlc[0] + .2, hlc[1] + .2, hlc[2] + .2, hlc[3] + .2) | |
47 | self._common_opt = { | |
48 | 'item_frameColor': self._common_btn['frameColor'], | |
49 | 'popupMarker_frameColor': self._common_btn['frameColor'], | |
50 | 'item_relief': self._common_btn['relief'], | |
51 | 'item_text_font': self._common_btn['text_font'], | |
52 | 'item_text_fg': self._common_btn['text_fg'], | |
53 | 'textMayChange': 1, | |
54 | 'highlightColor': hlc, | |
55 | 'text_align': TextNode.A_center, | |
56 | } | self._common_btn | |
57 | f_s = self._common_opt['frameSize'] | |
58 | self._common_opt['frameSize'] = f_s[0], f_s[1] - .56, f_s[2], f_s[3] | |
e1e44d5c FC |
59 | self._common_slider = self._common | { |
60 | 'range': (0, 1), | |
61 | 'thumb_frameColor': (.4, .4, .4, .4), | |
62 | 'thumb_scale': 1.6, | |
63 | 'scale': .4} | |
64 | del self._common_slider['rolloverSound'] | |
65 | del self._common_slider['clickSound'] | |
4071c6d8 FC |
66 | self._set_main() |
67 | ||
68 | def _set_main(self): | |
e1e44d5c FC |
69 | self._widgets = [] |
70 | self._widgets += [DirectButton( | |
4071c6d8 FC |
71 | text=_('Play'), pos=(0, 1, .6), command=self.on_play, |
72 | **self._common_btn)] | |
e1e44d5c | 73 | self._widgets += [DirectButton( |
2612dfc8 | 74 | text=_('Options'), pos=(0, 1, .2), command=self.on_options, |
4071c6d8 | 75 | **self._common_btn)] |
e1e44d5c | 76 | self._widgets += [DirectButton( |
2612dfc8 | 77 | text=_('Credits'), pos=(0, 1, -.2), command=self.on_credits, |
4071c6d8 | 78 | **self._common_btn)] |
e1e44d5c | 79 | self._widgets += [DirectButton( |
2612dfc8 | 80 | text=_('Exit'), pos=(0, 1, -.6), command=lambda: exit(), |
4071c6d8 | 81 | **self._common_btn)] |
75b89b83 | 82 | self._rearrange_width() |
4071c6d8 FC |
83 | |
84 | def _set_options(self): | |
e1e44d5c | 85 | self._widgets = [] |
4071c6d8 FC |
86 | self._lang_funcs = [lambda: _('English'), lambda: _('Italian')] |
87 | items = [fnc() for fnc in self._lang_funcs] | |
88 | inititem = { | |
89 | 'en': _('English'), | |
90 | 'it': _('Italian') | |
91 | }[self._opt_file['settings']['language']] | |
4071c6d8 FC |
92 | btn = DirectOptionMenu( |
93 | text=_('Language'), items=items, initialitem=inititem, | |
a9aba267 | 94 | pos=(0, 1, .8), command=self.on_language, **self._common_opt) |
4071c6d8 FC |
95 | btn.popupMenu['frameColor'] = self._common_btn['frameColor'] |
96 | btn.popupMenu['relief'] = self._common_btn['relief'] | |
e1e44d5c FC |
97 | self._widgets += [btn] |
98 | self._widgets += [OnscreenText( | |
a9aba267 | 99 | _('Volume'), pos=(-.1, .55), font=self._common['text_font'], |
e1e44d5c FC |
100 | scale=self._common['scale'], fg=self._common['text_fg'], |
101 | align=TextNode.A_right)] | |
102 | self._widgets += [DirectSlider( | |
a9aba267 | 103 | pos=(.5, 1, .57), |
e1e44d5c FC |
104 | value=self._opt_file['settings']['volume'], |
105 | command=self.on_volume, | |
106 | **self._common_slider)] | |
107 | self._slider = self._widgets[-1] | |
6fff1464 | 108 | self._widgets += [DirectCheckButton( |
a9aba267 | 109 | text=_('Fullscreen'), pos=(0, 1, .3), command=self.on_fullscreen, |
6fff1464 FC |
110 | indicator_frameColor=self._common_opt['highlightColor'], |
111 | indicator_relief=self._common_btn['relief'], | |
112 | indicatorValue=self._opt_file['settings']['fullscreen'], | |
113 | **self._common_btn)] | |
114 | res = self._opt_file['settings']['resolution'] | |
115 | d_i = base.pipe.get_display_information() | |
116 | def _res(idx): | |
117 | return d_i.get_display_mode_width(idx), \ | |
118 | d_i.get_display_mode_height(idx) | |
119 | resolutions = [ | |
120 | _res(idx) for idx in range(d_i.get_total_display_modes())] | |
121 | resolutions = list(set(resolutions)) | |
122 | resolutions = sorted(resolutions) | |
123 | resolutions = [(str(_res[0]), str(_res[1])) for _res in resolutions] | |
124 | resolutions = ['x'.join(_res) for _res in resolutions] | |
125 | if not res: | |
126 | res = resolutions[-1] | |
127 | btn = DirectOptionMenu( | |
128 | text=_('Resolution'), items=resolutions, initialitem=res, | |
a9aba267 | 129 | pos=(0, 1, .05), command=self.on_resolution, **self._common_opt) |
6fff1464 FC |
130 | btn.popupMenu['frameColor'] = self._common_btn['frameColor'] |
131 | btn.popupMenu['relief'] = self._common_btn['relief'] | |
132 | self._widgets += [btn] | |
a9aba267 FC |
133 | self._widgets += [DirectCheckButton( |
134 | text=_('Antialiasing'), pos=(0, 1, -.2), command=self.on_aa, | |
135 | indicator_frameColor=self._common_opt['highlightColor'], | |
136 | indicator_relief=self._common_btn['relief'], | |
137 | indicatorValue=self._opt_file['settings']['antialiasing'], | |
138 | **self._common_btn)] | |
5fdf77d0 FC |
139 | self._widgets += [DirectCheckButton( |
140 | text=_('Shadows'), pos=(0, 1, -.45), command=self.on_shadows, | |
141 | indicator_frameColor=self._common_opt['highlightColor'], | |
142 | indicator_relief=self._common_btn['relief'], | |
143 | indicatorValue=self._opt_file['settings']['shadows'], | |
144 | **self._common_btn)] | |
e1e44d5c | 145 | self._widgets += [DirectButton( |
a9aba267 | 146 | text=_('Back'), pos=(0, 1, -.8), command=self.on_back, |
4071c6d8 FC |
147 | **self._common_btn)] |
148 | ||
2612dfc8 FC |
149 | def _set_credits(self): |
150 | self._widgets = [] | |
151 | tp_scale = TextProperties() | |
152 | tp_scale.set_text_scale(.64) | |
153 | TextPropertiesManager.getGlobalPtr().setProperties('scale', tp_scale) | |
154 | self._widgets += [OnscreenText( | |
155 | _('Code and gfx\n \1scale\1Flavio Calva\2\n\n\nMusic\n \1scale\1Stefan Grossmann\2'), | |
156 | pos=(-.9, .55), font=self._common['text_font'], | |
157 | scale=self._common['scale'], fg=self._common['text_fg'], | |
158 | align=TextNode.A_left)] | |
159 | self._widgets += [DirectButton( | |
160 | text=_('Website'), pos=(-.6, 1, .29), command=self.on_website, | |
161 | **self._common_btn | {'scale': .08})] | |
162 | self._widgets += [OnscreenText( | |
163 | _('Supporters\n \1scale\1rdb\2\n \1scale\1Luisa Tenuta\2\n \1scale\1Damiana Ercolani\2'), | |
164 | pos=(.1, .55), font=self._common['text_font'], | |
165 | scale=self._common['scale'], fg=self._common['text_fg'], | |
166 | align=TextNode.A_left)] | |
167 | self._widgets += [DirectButton( | |
168 | text=_('Back'), pos=(0, 1, -.8), command=self.on_back, | |
169 | **self._common_btn)] | |
170 | ||
4071c6d8 | 171 | def on_play(self): |
8c9bf90e FC |
172 | scene_classes = [] |
173 | for _file in glob('pmachines/scenes/*.py'): | |
174 | _fn = _file.replace('.py', '').replace('/', '.') | |
175 | for member in import_module(_fn).__dict__.values(): | |
176 | if isclass(member) and issubclass(member, Scene) and \ | |
177 | member != Scene: | |
178 | scene_classes += [member] | |
0d5a5427 FC |
179 | self.destroy() |
180 | self._widgets = [] | |
8c9bf90e FC |
181 | cmn = self._common_btn.copy() | { |
182 | 'frameSize': (-2.4, 2.4, -2.4, 2.4), | |
183 | 'frameColor': (1, 1, 1, .8)} | |
0d5a5427 | 184 | self._widgets += [DirectButton( |
8c9bf90e | 185 | text=scene_classes[0].name(), pos=(-.4, 1, .1), command=self.start, |
63e7aeb2 FC |
186 | extraArgs=[scene_classes[0]], |
187 | frameTexture='assets/images/scenes/%s.png' % scene_classes[0].__name__, | |
188 | **cmn)] | |
8c9bf90e FC |
189 | self._widgets += [DirectButton( |
190 | text=scene_classes[1].name(), pos=(.4, 1, .1), command=self.start, | |
63e7aeb2 FC |
191 | extraArgs=[scene_classes[1]], |
192 | frameTexture='assets/images/scenes/%s.png' % scene_classes[1].__name__, | |
193 | **cmn)] | |
0d5a5427 FC |
194 | self._widgets += [DirectButton( |
195 | text=_('Back'), pos=(0, 1, -.8), command=self.on_back, | |
196 | **self._common_btn)] | |
197 | ||
8c9bf90e FC |
198 | def start(self, cls): |
199 | self._fsm.demand('Scene', cls) | |
4071c6d8 FC |
200 | |
201 | def on_options(self): | |
202 | self.destroy() | |
203 | self._set_options() | |
204 | ||
2612dfc8 FC |
205 | def on_credits(self): |
206 | self.destroy() | |
207 | self._set_credits() | |
208 | ||
75b89b83 FC |
209 | def _rearrange_width(self): |
210 | max_width = 0 | |
211 | for wdg in self._widgets: | |
212 | t_n = wdg.component('text0') | |
213 | u_l = t_n.textNode.get_upper_left_3d() | |
214 | l_r = t_n.textNode.get_lower_right_3d() | |
215 | max_width = max(l_r[0] - u_l[0], max_width) | |
216 | for wdg in self._widgets: | |
217 | m_w = max_width / 2 + .8 | |
218 | wdg['frameSize'] = -m_w, m_w, wdg['frameSize'][2], wdg['frameSize'][3] | |
219 | ||
4071c6d8 FC |
220 | def on_language(self, arg): |
221 | lang_code = { | |
222 | _('English'): 'en_EN', | |
223 | _('Italian'): 'it_IT'}[arg] | |
224 | self._lang_mgr.set_lang(lang_code) | |
225 | self._opt_file['settings']['language'] = lang_code[:2] | |
226 | self._opt_file.store() | |
227 | self.on_options() | |
228 | ||
e1e44d5c FC |
229 | def on_volume(self): |
230 | self._opt_file['settings']['volume'] = self._slider['value'] | |
231 | self._music.set_volume(self._slider['value']) | |
232 | ||
6fff1464 FC |
233 | def on_fullscreen(self, arg): |
234 | props = WindowProperties() | |
235 | props.set_fullscreen(arg) | |
236 | base.win.request_properties(props) | |
237 | self._opt_file['settings']['fullscreen'] = int(arg) | |
238 | self._opt_file.store() | |
239 | ||
240 | def on_resolution(self, arg): | |
241 | props = WindowProperties() | |
242 | props.set_size(LVector2i(*[int(_res) for _res in arg.split('x')])) | |
243 | base.win.request_properties(props) | |
244 | self._opt_file['settings']['resolution'] = arg | |
245 | self._opt_file.store() | |
246 | ||
a9aba267 FC |
247 | def on_aa(self, arg): |
248 | self._pipeline.msaa_samples = 4 if arg else 1 | |
94a18c21 | 249 | debug(f'msaa: {self._pipeline.msaa_samples}') |
a9aba267 FC |
250 | self._opt_file['settings']['antialiasing'] = int(arg) |
251 | self._opt_file.store() | |
252 | ||
5fdf77d0 FC |
253 | def on_shadows(self, arg): |
254 | self._pipeline.enable_shadows = int(arg) | |
94a18c21 | 255 | debug(f'shadows: {self._pipeline.enable_shadows}') |
5fdf77d0 FC |
256 | self._opt_file['settings']['shadows'] = int(arg) |
257 | self._opt_file.store() | |
258 | ||
2612dfc8 FC |
259 | def on_website(self): |
260 | if platform.startswith('linux'): | |
261 | environ['LD_LIBRARY_PATH'] = '' | |
262 | system('xdg-open https://www.ya2.it') | |
263 | else: | |
264 | open_new_tab('https://www.ya2.it') | |
265 | ||
4071c6d8 | 266 | def on_back(self): |
e1e44d5c | 267 | self._opt_file.store() |
4071c6d8 FC |
268 | self.destroy() |
269 | self._set_main() | |
270 | ||
271 | def destroy(self): | |
e1e44d5c | 272 | [wdg.destroy() for wdg in self._widgets] |
407412a5 | 273 | self._cursor.destroy() |