3fa571d8668ff076eb786cfb6a2e00b806c16acb
1 from logging
import info
, debug
2 from sys
import platform
, exit
3 from os
import environ
, system
4 from webbrowser
import open_new_tab
5 from xmlrpc
.client
import ServerProxy
6 from panda3d
.core
import Texture
, TextNode
, WindowProperties
, LVector2i
, \
7 TextProperties
, TextPropertiesManager
, NodePath
8 from direct
.gui
.DirectGui
import DirectButton
, DirectCheckButton
, \
9 DirectOptionMenu
, DirectSlider
10 from direct
.gui
.DirectGuiGlobals
import FLAT
11 from direct
.gui
.OnscreenText
import OnscreenText
12 from direct
.showbase
.DirectObject
import DirectObject
13 from ya2
.utils
.cursor
import MouseCursor
14 from ya2
.p3d
.p3d
import LibP3d
17 class DirectOptionMenuTest(DirectOptionMenu
):
19 def __init__(self
, parent
=None, **kw
):
20 DirectOptionMenu
.__init
__(self
, parent
, **kw
)
21 self
.initialiseoptions(DirectOptionMenuTest
)
23 def showPopupMenu(self
, event
=None):
24 super().showPopupMenu(event
)
25 self
._show
_cb
([self
.component(cmp) for cmp in self
.components()])
29 class Menu(DirectObject
):
31 def __init__(self
, fsm
, lang_mgr
, opt_file
, music
, pipeline
, scenes
,
35 self
._lang
_mgr
= lang_mgr
36 self
._opt
_file
= opt_file
38 self
._pipeline
= pipeline
40 self
._fun
_test
= fun_test
41 self
._pos
_mgr
= pos_mgr
42 self
._enforced
_res
= ''
43 self
._cursor
= MouseCursor(
44 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04),
45 (.5, .5, .5, 1), (.01, .01))
46 self
._font
= base
.loader
.load_font(
47 'assets/fonts/Hanken-Book.ttf')
49 self
._font
.set_pixels_per_unit(60)
50 self
._font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
51 self
._font
.set_outline((0, 0, 0, 1), .8, .2)
55 'text_font': self
._font
,
56 'text_fg': (.9, .9, .9, 1),
58 'frameColor': (.4, .4, .4, .14),
59 'rolloverSound': loader
.load_sfx(
60 'assets/audio/sfx/rollover.ogg'),
61 'clickSound': loader
.load_sfx(
62 'assets/audio/sfx/click.ogg')}
63 self
._common
_btn
= {'frameSize': (-4.8, 4.8, -.6, 1.2)} | self
._common
64 hlc
= self
._common
_btn
['frameColor']
65 hlc
= (hlc
[0] + .2, hlc
[1] + .2, hlc
[2] + .2, hlc
[3] + .2)
67 'item_frameColor': self
._common
_btn
['frameColor'],
68 'popupMarker_frameColor': self
._common
_btn
['frameColor'],
69 'item_relief': self
._common
_btn
['relief'],
70 'item_text_font': self
._common
_btn
['text_font'],
71 'item_text_fg': self
._common
_btn
['text_fg'],
73 'highlightColor': hlc
,
74 'text_align': TextNode
.A_center
,
76 f_s
= self
._common
_opt
['frameSize']
77 self
._common
_opt
['frameSize'] = f_s
[0], f_s
[1] - .56, f_s
[2], f_s
[3]
78 self
._common
_slider
= self
._common |
{
80 'thumb_frameColor': (.4, .4, .4, .4),
83 del self
._common
_slider
['rolloverSound']
84 del self
._common
_slider
['clickSound']
87 def enforce_res(self
, val
):
88 self
._enforced
_res
= val
89 info('enforced resolution: ' + val
)
94 self
._widgets
+= [DirectButton(
95 text
=_('Play'), pos
=(0, 1, .6), command
=self
.on_play
,
97 self
._pos
_mgr
.register('play', LibP3d
.wdg_pos(self
._widgets
[-1]))
98 self
._widgets
+= [DirectButton(
99 text
=_('Options'), pos
=(0, 1, .2), command
=self
.on_options
,
101 self
._pos
_mgr
.register('options', LibP3d
.wdg_pos(self
._widgets
[-1]))
102 self
._widgets
+= [DirectButton(
103 text
=_('Credits'), pos
=(0, 1, -.2), command
=self
.on_credits
,
105 self
._pos
_mgr
.register('credits', LibP3d
.wdg_pos(self
._widgets
[-1]))
109 ServerProxy('http://localhost:6000').destroy()
111 self
._widgets
+= [DirectButton(
112 text
=_('Exit'), pos
=(0, 1, -.6), command
=lambda: btn_exit(),
114 self
._pos
_mgr
.register('exit', LibP3d
.wdg_pos(self
._widgets
[-1]))
115 self
._rearrange
_width
()
116 self
.accept('enforce_resolution', self
.enforce_res
)
118 def _set_options(self
):
119 self
._pos
_mgr
.reset()
121 self
._lang
_funcs
= [lambda: _('English'), lambda: _('Italian')]
122 items
= [fnc() for fnc
in self
._lang
_funcs
]
126 }[self
._opt
_file
['settings']['language']]
129 self
._pos
_mgr
.remove(['english', 'italian'])
130 for lng
, btn
in zip(['english', 'italian'], comps
):
131 pos
= LibP3d
.wdg_pos(btn
)
132 self
._pos
_mgr
.register(lng
, (pos
[0] + 5, pos
[1]))
133 btn
= DirectOptionMenuTest(
134 text
=_('Language'), items
=items
, initialitem
=inititem
,
135 pos
=(0, 1, .8), command
=self
.on_language
, **self
._common
_opt
)
136 btn
._show
_cb
= lang_cb
137 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
138 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
139 self
._widgets
+= [btn
]
140 pos_lang
= LibP3d
.wdg_pos(self
._widgets
[-1])
141 self
._pos
_mgr
.register('languages', pos_lang
)
142 self
._widgets
+= [OnscreenText(
143 _('Volume'), pos
=(-.1, .55), font
=self
._common
['text_font'],
144 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
145 align
=TextNode
.A_right
)]
146 self
._widgets
+= [DirectSlider(
148 value
=self
._opt
_file
['settings']['volume'],
149 command
=self
.on_volume
,
150 **self
._common
_slider
)]
151 vol_pos
= LibP3d
.wdg_pos(self
._widgets
[-1])
152 self
._pos
_mgr
.register('volume', vol_pos
)
153 np_left
= NodePath('left_slider')
154 np_left
.set_pos(self
._widgets
[-1].get_net_transform().get_pos())
155 np_left
.set_x(np_left
.get_x() - self
._widgets
[-1].get_scale()[0])
156 lpos
= LibP3d
.wdg_pos(np_left
)
157 self
._pos
_mgr
.register('volume_0', lpos
)
158 self
._slider
= self
._widgets
[-1]
159 self
._widgets
+= [DirectCheckButton(
160 text
=_('Fullscreen'), pos
=(0, 1, .3), command
=self
.on_fullscreen
,
161 indicator_frameColor
=self
._common
_opt
['highlightColor'],
162 indicator_relief
=self
._common
_btn
['relief'],
163 indicatorValue
=self
._opt
_file
['settings']['fullscreen'],
165 self
._pos
_mgr
.register('fullscreen', LibP3d
.wdg_pos(self
._widgets
[-1]))
166 res
= self
._opt
_file
['settings']['resolution']
167 d_i
= base
.pipe
.get_display_information()
169 return d_i
.get_display_mode_width(idx
), \
170 d_i
.get_display_mode_height(idx
)
172 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
173 resolutions
= list(set(resolutions
))
174 resolutions
= sorted(resolutions
)
175 resolutions
= [(str(_res
[0]), str(_res
[1])) for _res
in resolutions
]
176 resolutions
= ['x'.join(_res
) for _res
in resolutions
]
178 res
= resolutions
[-1]
181 self
._pos
_mgr
.remove(['res_1440x900', 'res_1360x768'])
182 for tgt_res
in ['1440x900', '1360x768']:
184 if btn
['text'] == tgt_res
:
185 pos
= LibP3d
.wdg_pos(btn
)
186 self
._pos
_mgr
.register('res_' + tgt_res
, (pos
[0] + 5, pos
[1]))
187 btn
= DirectOptionMenuTest(
188 text
=_('Resolution'), items
=resolutions
, initialitem
=res
,
189 pos
=(0, 1, .05), command
=self
.on_resolution
, **self
._common
_opt
)
190 btn
._show
_cb
= res_cb
191 btn
.popupMenu
['frameColor'] = self
._common
_btn
['frameColor']
192 btn
.popupMenu
['relief'] = self
._common
_btn
['relief']
193 self
._widgets
+= [btn
]
194 pos_res
= LibP3d
.wdg_pos(self
._widgets
[-1])
195 self
._pos
_mgr
.register('resolutions', pos_res
) # 680 365
196 self
._pos
_mgr
.register('res_1440x900', [pos_res
[0] + 320, pos_res
[1] + 75])
197 self
._pos
_mgr
.register('res_1360x768', [pos_res
[0] + 430, pos_res
[1] -285])
198 self
._widgets
+= [DirectCheckButton(
199 text
=_('Antialiasing'), pos
=(0, 1, -.2), command
=self
.on_aa
,
200 indicator_frameColor
=self
._common
_opt
['highlightColor'],
201 indicator_relief
=self
._common
_btn
['relief'],
202 indicatorValue
=self
._opt
_file
['settings']['antialiasing'],
204 self
._pos
_mgr
.register('aa', LibP3d
.wdg_pos(self
._widgets
[-1]))
205 self
._widgets
+= [DirectCheckButton(
206 text
=_('Shadows'), pos
=(0, 1, -.45), command
=self
.on_shadows
,
207 indicator_frameColor
=self
._common
_opt
['highlightColor'],
208 indicator_relief
=self
._common
_btn
['relief'],
209 indicatorValue
=self
._opt
_file
['settings']['shadows'],
211 self
._pos
_mgr
.register('shadows', LibP3d
.wdg_pos(self
._widgets
[-1]))
212 self
._widgets
+= [DirectButton(
213 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
215 self
._pos
_mgr
.register('back', LibP3d
.wdg_pos(self
._widgets
[-1]))
216 self
.accept('enforce_resolution', self
.enforce_res
)
218 def _set_credits(self
):
219 self
._pos
_mgr
.reset()
221 tp_scale
= TextProperties()
222 tp_scale
.set_text_scale(.64)
223 TextPropertiesManager
.getGlobalPtr().setProperties('scale', tp_scale
)
224 self
._widgets
+= [OnscreenText(
225 _('Code and gfx\n \1scale\1Flavio Calva\2\n\n\nMusic\n \1scale\1Stefan Grossmann\2'),
226 pos
=(-.9, .55), font
=self
._common
['text_font'],
227 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
228 align
=TextNode
.A_left
)]
229 self
._widgets
+= [DirectButton(
230 text
=_('Website'), pos
=(-.6, 1, .29), command
=self
.on_website
,
231 **self
._common
_btn |
{'scale': .08})]
232 self
._widgets
+= [OnscreenText(
233 _('Special thanks to:\n \1scale\1rdb\2\n \1scale\1Luisa Tenuta\2\n \1scale\1Damiana Ercolani\2'),
234 pos
=(.1, .55), font
=self
._common
['text_font'],
235 scale
=self
._common
['scale'], fg
=self
._common
['text_fg'],
236 align
=TextNode
.A_left
)]
237 self
._widgets
+= [DirectButton(
238 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
240 self
._pos
_mgr
.register('back', LibP3d
.wdg_pos(self
._widgets
[-1]))
241 self
.accept('enforce_resolution', self
.enforce_res
)
244 self
._pos
_mgr
.reset()
246 self
._cursor
= MouseCursor(
247 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
250 cmn
= self
._common
_btn
.copy() |
{
251 'frameSize': (-2.4, 2.4, -2.4, 2.4),
252 'frameColor': (1, 1, 1, .8),
254 left
= - (dx
:= .8) * (min(4, len(self
._scenes
)) - 1) / 2
255 for i
, cls
in enumerate(self
._scenes
):
256 top
= .1 if len(self
._scenes
) < 5 else .6
257 row
= 0 if i
< 4 else 1
258 self
._widgets
+= [DirectButton(
259 text
=cls
.name(), pos
=(left
+ dx
* (i
% 4), 1, top
- dx
* row
),
260 command
=self
.start
, extraArgs
=[cls
], text_wordwrap
=6,
261 frameTexture
='assets/images/scenes/%s.dds' % cls
.__name
__,
263 name
= cls
.__name
__[5:].lower()
264 self
._pos
_mgr
.register(name
, LibP3d
.wdg_pos(self
._widgets
[-1]))
266 tnode
= self
._widgets
[-1].component('text%s' % j
).textNode
267 height
= - tnode
.getLineHeight() / 2
268 height
+= (tnode
.get_height() - tnode
.get_line_height()) / 2
269 self
._widgets
[-1].component('text%s' % j
).set_pos(0, 0, height
)
270 self
._widgets
+= [DirectButton(
271 text
=_('Back'), pos
=(0, 1, -.8), command
=self
.on_back
,
273 self
._pos
_mgr
.register('back', LibP3d
.wdg_pos(self
._widgets
[-1]))
275 def start(self
, cls
):
276 self
._fsm
.demand('Scene', cls
)
278 def on_options(self
):
280 self
._cursor
= MouseCursor(
281 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
285 def on_credits(self
):
287 self
._cursor
= MouseCursor(
288 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
292 def _rearrange_width(self
):
294 for wdg
in self
._widgets
:
295 t_n
= wdg
.component('text0')
296 u_l
= t_n
.textNode
.get_upper_left_3d()
297 l_r
= t_n
.textNode
.get_lower_right_3d()
298 max_width
= max(l_r
[0] - u_l
[0], max_width
)
299 for wdg
in self
._widgets
:
300 m_w
= max_width
/ 2 + .8
301 wdg
['frameSize'] = -m_w
, m_w
, wdg
['frameSize'][2], wdg
['frameSize'][3]
303 def on_language(self
, arg
):
305 _('English'): 'en_EN',
306 _('Italian'): 'it_IT'}[arg
]
307 self
._lang
_mgr
.set_lang(lang_code
)
308 self
._opt
_file
['settings']['language'] = lang_code
[:2]
309 self
._opt
_file
.store()
313 self
._opt
_file
['settings']['volume'] = self
._slider
['value']
314 self
._music
.set_volume(self
._slider
['value'])
316 def on_fullscreen(self
, arg
):
317 props
= WindowProperties()
318 props
.set_fullscreen(arg
)
319 if not self
._fun
_test
:
320 base
.win
.request_properties(props
)
321 # if we actually switch to fullscreen during the tests then
322 # exwm inside qemu can't restore the correct resolution
323 # i may re-enable this if/when i run the tests onto a
325 self
._opt
_file
['settings']['fullscreen'] = int(arg
)
326 self
._opt
_file
.store()
328 def on_resolution(self
, arg
):
329 info('on resolution: %s (%s)' % (arg
, self
._enforced
_res
))
330 arg
= self
._enforced
_res
or arg
331 info('set resolution: %s' % arg
)
332 props
= WindowProperties()
333 props
.set_size(LVector2i(*[int(_res
) for _res
in arg
.split('x')]))
334 base
.win
.request_properties(props
)
335 self
._opt
_file
['settings']['resolution'] = arg
336 self
._opt
_file
.store()
338 def on_aa(self
, arg
):
339 self
._pipeline
.msaa_samples
= 4 if arg
else 1
340 debug(f
'msaa: {self._pipeline.msaa_samples}')
341 self
._opt
_file
['settings']['antialiasing'] = int(arg
)
342 self
._opt
_file
.store()
344 def on_shadows(self
, arg
):
345 self
._pipeline
.enable_shadows
= int(arg
)
346 debug(f
'shadows: {self._pipeline.enable_shadows}')
347 self
._opt
_file
['settings']['shadows'] = int(arg
)
348 self
._opt
_file
.store()
350 def on_website(self
):
351 if platform
.startswith('linux'):
352 environ
['LD_LIBRARY_PATH'] = ''
353 system('xdg-open https://www.ya2.it')
355 open_new_tab('https://www.ya2.it')
358 self
._opt
_file
.store()
360 self
._cursor
= MouseCursor(
361 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
366 [wdg
.destroy() for wdg
in self
._widgets
]
367 self
._cursor
.destroy()
368 self
.ignore('enforce_resolution')