8f21d5bdb1404f5417fc258d2cbbb41f72f0b1fe
1 from logging
import info
, debug
2 from sys
import platform
, exit
3 from os
import environ
, system
5 from importlib
import import_module
6 from inspect
import isclass
7 from webbrowser
import open_new_tab
8 from panda3d
.core
import Texture
, TextNode
, WindowProperties
, LVector2i
, \
9 TextProperties
, TextPropertiesManager
10 from direct
.gui
.DirectGui
import DirectButton
, DirectCheckButton
, \
11 DirectOptionMenu
, DirectSlider
, DirectCheckButton
12 from direct
.gui
.DirectGuiGlobals
import FLAT
13 from direct
.gui
.OnscreenText
import OnscreenText
14 from direct
.showbase
.DirectObject
import DirectObject
15 from ya2
.utils
.cursor
import MouseCursor
16 from logics
.scene
import Scene
17 from panda3d
.bullet
import BulletWorld
20 class Menu(DirectObject
):
22 def __init__(self
, fsm
, lang_mgr
, opt_file
, music
, pipeline
, scenes
, fun_test
):
25 self
._lang
_mgr
= lang_mgr
26 self
._opt
_file
= opt_file
28 self
._pipeline
= pipeline
30 self
._fun
_test
= fun_test
31 self
._enforced
_res
= ''
32 self
._cursor
= MouseCursor(
33 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
35 self
._font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
37 self
._font
.set_pixels_per_unit(60)
38 self
._font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
39 self
._font
.set_outline((0, 0, 0, 1), .8, .2)
43 'text_font': self
._font
,
44 'text_fg': (.9, .9, .9, 1),
46 'frameColor': (.4, .4, .4, .14),
47 'rolloverSound': loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
48 'clickSound': loader
.load_sfx('assets/audio/sfx/click.ogg')}
49 self
._common
_btn
= {'frameSize': (-4.8, 4.8, -.6, 1.2)} | self
._common
50 hlc
= self
._common
_btn
['frameColor']
51 hlc
= (hlc
[0] + .2, hlc
[1] + .2, hlc
[2] + .2, hlc
[3] + .2)
53 'item_frameColor': self
._common
_btn
['frameColor'],
54 'popupMarker_frameColor': self
._common
_btn
['frameColor'],
55 'item_relief': self
._common
_btn
['relief'],
56 'item_text_font': self
._common
_btn
['text_font'],
57 'item_text_fg': self
._common
_btn
['text_fg'],
59 'highlightColor': hlc
,
60 'text_align': TextNode
.A_center
,
62 f_s
= self
._common
_opt
['frameSize']
63 self
._common
_opt
['frameSize'] = f_s
[0], f_s
[1] - .56, f_s
[2], f_s
[3]
64 self
._common
_slider
= self
._common |
{
66 'thumb_frameColor': (.4, .4, .4, .4),
69 del self
._common
_slider
['rolloverSound']
70 del self
._common
_slider
['clickSound']
73 def enforce_res(self
, val
):
74 self
._enforced
_res
= val
75 info('enforced resolution: ' + val
)
79 self
._widgets
+= [DirectButton(
80 text
=_('Play'), pos
=(0, 1, .6), command
=self
.on_play
,
82 self
._widgets
+= [DirectButton(
83 text
=_('Options'), pos
=(0, 1, .2), command
=self
.on_options
,
85 self
._widgets
+= [DirectButton(
86 text
=_('Credits'), pos
=(0, 1, -.2), command
=self
.on_credits
,
88 self
._widgets
+= [DirectButton(
89 text
=_('Exit'), pos
=(0, 1, -.6), command
=lambda: exit(),
91 self
._rearrange
_width
()
92 self
.accept('enforce_resolution', self
.enforce_res
)
94 def _set_options(self
):
96 self
._lang
_funcs
= [lambda: _('English'), lambda: _('Italian')]
97 items
= [fnc() for fnc
in self
._lang
_funcs
]
101 }[self
._opt
_file
['settings']['language']]
102 btn
= DirectOptionMenu(
103 text
=_('Language'), items
=items
, initialitem
=inititem
,
104 pos
=(0, 1, .8), command
=self
.on_language
, **self
._common
_opt
)
105 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
106 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
107 self
._widgets
+= [btn
]
108 self
._widgets
+= [OnscreenText(
109 _('Volume'), pos
=(-.1, .55), font
=self
._common
['text_font'],
110 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
111 align
=TextNode
.A_right
)]
112 self
._widgets
+= [DirectSlider(
114 value
=self
._opt
_file
['settings']['volume'],
115 command
=self
.on_volume
,
116 **self
._common
_slider
)]
117 self
._slider
= self
._widgets
[-1]
118 self
._widgets
+= [DirectCheckButton(
119 text
=_('Fullscreen'), pos
=(0, 1, .3), command
=self
.on_fullscreen
,
120 indicator_frameColor
=self
._common
_opt
['highlightColor'],
121 indicator_relief
=self
._common
_btn
['relief'],
122 indicatorValue
=self
._opt
_file
['settings']['fullscreen'],
124 res
= self
._opt
_file
['settings']['resolution']
125 d_i
= base
.pipe
.get_display_information()
127 return d_i
.get_display_mode_width(idx
), \
128 d_i
.get_display_mode_height(idx
)
130 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
131 resolutions
= list(set(resolutions
))
132 resolutions
= sorted(resolutions
)
133 resolutions
= [(str(_res
[0]), str(_res
[1])) for _res
in resolutions
]
134 resolutions
= ['x'.join(_res
) for _res
in resolutions
]
136 res
= resolutions
[-1]
137 btn
= DirectOptionMenu(
138 text
=_('Resolution'), items
=resolutions
, initialitem
=res
,
139 pos
=(0, 1, .05), command
=self
.on_resolution
, **self
._common
_opt
)
140 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
141 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
142 self
._widgets
+= [btn
]
143 self
._widgets
+= [DirectCheckButton(
144 text
=_('Antialiasing'), pos
=(0, 1, -.2), command
=self
.on_aa
,
145 indicator_frameColor
=self
._common
_opt
['highlightColor'],
146 indicator_relief
=self
._common
_btn
['relief'],
147 indicatorValue
=self
._opt
_file
['settings']['antialiasing'],
149 self
._widgets
+= [DirectCheckButton(
150 text
=_('Shadows'), pos
=(0, 1, -.45), command
=self
.on_shadows
,
151 indicator_frameColor
=self
._common
_opt
['highlightColor'],
152 indicator_relief
=self
._common
_btn
['relief'],
153 indicatorValue
=self
._opt
_file
['settings']['shadows'],
155 self
._widgets
+= [DirectButton(
156 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
158 self
.accept('enforce_resolution', self
.enforce_res
)
160 def _set_credits(self
):
162 tp_scale
= TextProperties()
163 tp_scale
.set_text_scale(.64)
164 TextPropertiesManager
.getGlobalPtr().setProperties('scale', tp_scale
)
165 self
._widgets
+= [OnscreenText(
166 _('Code and gfx\n \1scale\1Flavio Calva\2\n\n\nMusic\n \1scale\1Stefan Grossmann\2'),
167 pos
=(-.9, .55), font
=self
._common
['text_font'],
168 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
169 align
=TextNode
.A_left
)]
170 self
._widgets
+= [DirectButton(
171 text
=_('Website'), pos
=(-.6, 1, .29), command
=self
.on_website
,
172 **self
._common
_btn |
{'scale': .08})]
173 self
._widgets
+= [OnscreenText(
174 _('Special thanks to:\n \1scale\1rdb\2\n \1scale\1Luisa Tenuta\2\n \1scale\1Damiana Ercolani\2'),
175 pos
=(.1, .55), font
=self
._common
['text_font'],
176 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
177 align
=TextNode
.A_left
)]
178 self
._widgets
+= [DirectButton(
179 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
181 self
.accept('enforce_resolution', self
.enforce_res
)
185 self
._cursor
= MouseCursor(
186 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
189 cmn
= self
._common
_btn
.copy() |
{
190 'frameSize': (-2.4, 2.4, -2.4, 2.4),
191 'frameColor': (1, 1, 1, .8),
193 left
= - (dx
:= .8) * (min(4, len(self
._scenes
)) - 1) / 2
194 for i
, cls
in enumerate(self
._scenes
):
195 top
= .1 if len(self
._scenes
) < 5 else .6
196 row
= 0 if i
< 4 else 1
197 self
._widgets
+= [DirectButton(
198 text
=cls
.name(), pos
=(left
+ dx
* (i
% 4), 1, top
- dx
* row
),
199 command
=self
.start
, extraArgs
=[cls
], text_wordwrap
=6,
200 frameTexture
='assets/images/scenes/%s.dds' % cls
.__name
__,
203 tnode
= self
._widgets
[-1].component('text%s' % j
).textNode
204 height
= - tnode
.getLineHeight() / 2
205 height
+= (tnode
.get_height() - tnode
.get_line_height()) / 2
206 self
._widgets
[-1].component('text%s' % j
).set_pos(0, 0, height
)
207 self
._widgets
+= [DirectButton(
208 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
211 def start(self
, cls
):
212 self
._fsm
.demand('Scene', cls
)
214 def on_options(self
):
216 self
._cursor
= MouseCursor(
217 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
221 def on_credits(self
):
223 self
._cursor
= MouseCursor(
224 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
228 def _rearrange_width(self
):
230 for wdg
in self
._widgets
:
231 t_n
= wdg
.component('text0')
232 u_l
= t_n
.textNode
.get_upper_left_3d()
233 l_r
= t_n
.textNode
.get_lower_right_3d()
234 max_width
= max(l_r
[0] - u_l
[0], max_width
)
235 for wdg
in self
._widgets
:
236 m_w
= max_width
/ 2 + .8
237 wdg
['frameSize'] = -m_w
, m_w
, wdg
['frameSize'][2], wdg
['frameSize'][3]
239 def on_language(self
, arg
):
241 _('English'): 'en_EN',
242 _('Italian'): 'it_IT'}[arg
]
243 self
._lang
_mgr
.set_lang(lang_code
)
244 self
._opt
_file
['settings']['language'] = lang_code
[:2]
245 self
._opt
_file
.store()
249 self
._opt
_file
['settings']['volume'] = self
._slider
['value']
250 self
._music
.set_volume(self
._slider
['value'])
252 def on_fullscreen(self
, arg
):
253 props
= WindowProperties()
254 props
.set_fullscreen(arg
)
255 if not self
._fun
_test
:
256 base
.win
.request_properties(props
)
257 # if we actually switch to fullscreen during the tests then
258 # exwm inside qemu can't restore the correct resolution
259 # i may re-enable this if/when i run the tests onto a
261 self
._opt
_file
['settings']['fullscreen'] = int(arg
)
262 self
._opt
_file
.store()
264 def on_resolution(self
, arg
):
265 info('on resolution: %s (%s)' % (arg
, self
._enforced
_res
))
266 arg
= self
._enforced
_res
or arg
267 info('set resolution: %s' % arg
)
268 props
= WindowProperties()
269 props
.set_size(LVector2i(*[int(_res
) for _res
in arg
.split('x')]))
270 base
.win
.request_properties(props
)
271 self
._opt
_file
['settings']['resolution'] = arg
272 self
._opt
_file
.store()
274 def on_aa(self
, arg
):
275 self
._pipeline
.msaa_samples
= 4 if arg
else 1
276 debug(f
'msaa: {self._pipeline.msaa_samples}')
277 self
._opt
_file
['settings']['antialiasing'] = int(arg
)
278 self
._opt
_file
.store()
280 def on_shadows(self
, arg
):
281 self
._pipeline
.enable_shadows
= int(arg
)
282 debug(f
'shadows: {self._pipeline.enable_shadows}')
283 self
._opt
_file
['settings']['shadows'] = int(arg
)
284 self
._opt
_file
.store()
286 def on_website(self
):
287 if platform
.startswith('linux'):
288 environ
['LD_LIBRARY_PATH'] = ''
289 system('xdg-open https://www.ya2.it')
291 open_new_tab('https://www.ya2.it')
294 self
._opt
_file
.store()
296 self
._cursor
= MouseCursor(
297 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
302 [wdg
.destroy() for wdg
in self
._widgets
]
303 self
._cursor
.destroy()
304 self
.ignore('enforce_resolution')