+++ /dev/null
-from logging import info, debug
-from sys import platform, exit
-from os import environ, system
-from glob import glob
-from importlib import import_module
-from inspect import isclass
-from webbrowser import open_new_tab
-from panda3d.core import Texture, TextNode, WindowProperties, LVector2i, \
- TextProperties, TextPropertiesManager
-from direct.gui.DirectGui import DirectButton, DirectCheckButton, \
- DirectOptionMenu, DirectSlider, DirectCheckButton
-from direct.gui.DirectGuiGlobals import FLAT
-from direct.gui.OnscreenText import OnscreenText
-from lib.engine.gui.cursor import MouseCursor
-from pmachines.scene import Scene
-from panda3d.bullet import BulletWorld
-
-
-class Menu:
-
- def __init__(self, fsm, lang_mgr, opt_file, music, pipeline):
- self._fsm = fsm
- self._lang_mgr = lang_mgr
- self._opt_file = opt_file
- self._music = music
- self._pipeline = pipeline
- self._cursor = MouseCursor(
- 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
- (.01, .01))
- self._font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
- self._font.clear()
- self._font.set_pixels_per_unit(60)
- self._font.set_minfilter(Texture.FTLinearMipmapLinear)
- self._font.set_outline((0, 0, 0, 1), .8, .2)
- self._widgets = []
- self._common = {
- 'scale': .12,
- 'text_font': self._font,
- 'text_fg': (.9, .9, .9, 1),
- 'relief': FLAT,
- 'frameColor': (.4, .4, .4, .14),
- 'rolloverSound': loader.load_sfx('assets/audio/sfx/rollover.ogg'),
- 'clickSound': loader.load_sfx('assets/audio/sfx/click.ogg')}
- self._common_btn = {'frameSize': (-4.8, 4.8, -.6, 1.2)} | self._common
- hlc = self._common_btn['frameColor']
- hlc = (hlc[0] + .2, hlc[1] + .2, hlc[2] + .2, hlc[3] + .2)
- self._common_opt = {
- 'item_frameColor': self._common_btn['frameColor'],
- 'popupMarker_frameColor': self._common_btn['frameColor'],
- 'item_relief': self._common_btn['relief'],
- 'item_text_font': self._common_btn['text_font'],
- 'item_text_fg': self._common_btn['text_fg'],
- 'textMayChange': 1,
- 'highlightColor': hlc,
- 'text_align': TextNode.A_center,
- } | self._common_btn
- f_s = self._common_opt['frameSize']
- self._common_opt['frameSize'] = f_s[0], f_s[1] - .56, f_s[2], f_s[3]
- self._common_slider = self._common | {
- 'range': (0, 1),
- 'thumb_frameColor': (.4, .4, .4, .4),
- 'thumb_scale': 1.6,
- 'scale': .4}
- del self._common_slider['rolloverSound']
- del self._common_slider['clickSound']
- self._set_main()
-
- def _set_main(self):
- self._widgets = []
- self._widgets += [DirectButton(
- text=_('Play'), pos=(0, 1, .6), command=self.on_play,
- **self._common_btn)]
- self._widgets += [DirectButton(
- text=_('Options'), pos=(0, 1, .2), command=self.on_options,
- **self._common_btn)]
- self._widgets += [DirectButton(
- text=_('Credits'), pos=(0, 1, -.2), command=self.on_credits,
- **self._common_btn)]
- self._widgets += [DirectButton(
- text=_('Exit'), pos=(0, 1, -.6), command=lambda: exit(),
- **self._common_btn)]
- self._rearrange_width()
-
- def _set_options(self):
- self._widgets = []
- self._lang_funcs = [lambda: _('English'), lambda: _('Italian')]
- items = [fnc() for fnc in self._lang_funcs]
- inititem = {
- 'en': _('English'),
- 'it': _('Italian')
- }[self._opt_file['settings']['language']]
- btn = DirectOptionMenu(
- text=_('Language'), items=items, initialitem=inititem,
- pos=(0, 1, .8), command=self.on_language, **self._common_opt)
- btn.popupMenu['frameColor'] = self._common_btn['frameColor']
- btn.popupMenu['relief'] = self._common_btn['relief']
- self._widgets += [btn]
- self._widgets += [OnscreenText(
- _('Volume'), pos=(-.1, .55), font=self._common['text_font'],
- scale=self._common['scale'], fg=self._common['text_fg'],
- align=TextNode.A_right)]
- self._widgets += [DirectSlider(
- pos=(.5, 1, .57),
- value=self._opt_file['settings']['volume'],
- command=self.on_volume,
- **self._common_slider)]
- self._slider = self._widgets[-1]
- self._widgets += [DirectCheckButton(
- text=_('Fullscreen'), pos=(0, 1, .3), command=self.on_fullscreen,
- indicator_frameColor=self._common_opt['highlightColor'],
- indicator_relief=self._common_btn['relief'],
- indicatorValue=self._opt_file['settings']['fullscreen'],
- **self._common_btn)]
- res = self._opt_file['settings']['resolution']
- d_i = base.pipe.get_display_information()
- def _res(idx):
- return d_i.get_display_mode_width(idx), \
- d_i.get_display_mode_height(idx)
- resolutions = [
- _res(idx) for idx in range(d_i.get_total_display_modes())]
- resolutions = list(set(resolutions))
- resolutions = sorted(resolutions)
- resolutions = [(str(_res[0]), str(_res[1])) for _res in resolutions]
- resolutions = ['x'.join(_res) for _res in resolutions]
- if not res:
- res = resolutions[-1]
- btn = DirectOptionMenu(
- text=_('Resolution'), items=resolutions, initialitem=res,
- pos=(0, 1, .05), command=self.on_resolution, **self._common_opt)
- btn.popupMenu['frameColor'] = self._common_btn['frameColor']
- btn.popupMenu['relief'] = self._common_btn['relief']
- self._widgets += [btn]
- self._widgets += [DirectCheckButton(
- text=_('Antialiasing'), pos=(0, 1, -.2), command=self.on_aa,
- indicator_frameColor=self._common_opt['highlightColor'],
- indicator_relief=self._common_btn['relief'],
- indicatorValue=self._opt_file['settings']['antialiasing'],
- **self._common_btn)]
- self._widgets += [DirectCheckButton(
- text=_('Shadows'), pos=(0, 1, -.45), command=self.on_shadows,
- indicator_frameColor=self._common_opt['highlightColor'],
- indicator_relief=self._common_btn['relief'],
- indicatorValue=self._opt_file['settings']['shadows'],
- **self._common_btn)]
- self._widgets += [DirectButton(
- text=_('Back'), pos=(0, 1, -.8), command=self.on_back,
- **self._common_btn)]
-
- def _set_credits(self):
- self._widgets = []
- tp_scale = TextProperties()
- tp_scale.set_text_scale(.64)
- TextPropertiesManager.getGlobalPtr().setProperties('scale', tp_scale)
- self._widgets += [OnscreenText(
- _('Code and gfx\n \1scale\1Flavio Calva\2\n\n\nMusic\n \1scale\1Stefan Grossmann\2'),
- pos=(-.9, .55), font=self._common['text_font'],
- scale=self._common['scale'], fg=self._common['text_fg'],
- align=TextNode.A_left)]
- self._widgets += [DirectButton(
- text=_('Website'), pos=(-.6, 1, .29), command=self.on_website,
- **self._common_btn | {'scale': .08})]
- self._widgets += [OnscreenText(
- _('Special thanks to:\n \1scale\1rdb\2\n \1scale\1Luisa Tenuta\2\n \1scale\1Damiana Ercolani\2'),
- pos=(.1, .55), font=self._common['text_font'],
- scale=self._common['scale'], fg=self._common['text_fg'],
- align=TextNode.A_left)]
- self._widgets += [DirectButton(
- text=_('Back'), pos=(0, 1, -.8), command=self.on_back,
- **self._common_btn)]
-
- def on_play(self):
- scenes = []
- for _file in glob('pmachines/scenes/*.py'):
- _fn = _file.replace('.py', '').replace('/', '.')
- for member in import_module(_fn).__dict__.values():
- if isclass(member) and issubclass(member, Scene) and \
- member != Scene:
- scenes += [member]
- scenes = sorted(scenes, key=lambda elm: elm.sorting)
- self.destroy()
- self._cursor = MouseCursor(
- 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
- (.01, .01))
- self._widgets = []
- cmn = self._common_btn.copy() | {
- 'frameSize': (-2.4, 2.4, -2.4, 2.4),
- 'frameColor': (1, 1, 1, .8),
- 'text_scale': .64}
- left = - (dx := .8) * (min(4, len(scenes)) - 1) / 2
- for i, cls in enumerate(scenes):
- top = .1 if len(scenes) < 5 else .6
- row = 0 if i < 4 else 1
- self._widgets += [DirectButton(
- text=cls.name(), pos=(left + dx * (i % 4), 1, top - dx * row),
- command=self.start, extraArgs=[cls], text_wordwrap=6,
- frameTexture='assets/images/scenes/%s.dds' % cls.__name__,
- **cmn)]
- for j in range(4):
- tnode = self._widgets[-1].component('text%s' % j).textNode
- height = - tnode.getLineHeight() / 2
- height += (tnode.get_height() - tnode.get_line_height()) / 2
- self._widgets[-1].component('text%s' % j).set_pos(0, 0, height)
- self._widgets += [DirectButton(
- text=_('Back'), pos=(0, 1, -.8), command=self.on_back,
- **self._common_btn)]
-
- def start(self, cls):
- self._fsm.demand('Scene', cls)
-
- def on_options(self):
- self.destroy()
- self._cursor = MouseCursor(
- 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
- (.01, .01))
- self._set_options()
-
- def on_credits(self):
- self.destroy()
- self._cursor = MouseCursor(
- 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
- (.01, .01))
- self._set_credits()
-
- def _rearrange_width(self):
- max_width = 0
- for wdg in self._widgets:
- t_n = wdg.component('text0')
- u_l = t_n.textNode.get_upper_left_3d()
- l_r = t_n.textNode.get_lower_right_3d()
- max_width = max(l_r[0] - u_l[0], max_width)
- for wdg in self._widgets:
- m_w = max_width / 2 + .8
- wdg['frameSize'] = -m_w, m_w, wdg['frameSize'][2], wdg['frameSize'][3]
-
- def on_language(self, arg):
- lang_code = {
- _('English'): 'en_EN',
- _('Italian'): 'it_IT'}[arg]
- self._lang_mgr.set_lang(lang_code)
- self._opt_file['settings']['language'] = lang_code[:2]
- self._opt_file.store()
- self.on_options()
-
- def on_volume(self):
- self._opt_file['settings']['volume'] = self._slider['value']
- self._music.set_volume(self._slider['value'])
-
- def on_fullscreen(self, arg):
- props = WindowProperties()
- props.set_fullscreen(arg)
- base.win.request_properties(props)
- self._opt_file['settings']['fullscreen'] = int(arg)
- self._opt_file.store()
-
- def on_resolution(self, arg):
- props = WindowProperties()
- props.set_size(LVector2i(*[int(_res) for _res in arg.split('x')]))
- base.win.request_properties(props)
- self._opt_file['settings']['resolution'] = arg
- self._opt_file.store()
-
- def on_aa(self, arg):
- self._pipeline.msaa_samples = 4 if arg else 1
- debug(f'msaa: {self._pipeline.msaa_samples}')
- self._opt_file['settings']['antialiasing'] = int(arg)
- self._opt_file.store()
-
- def on_shadows(self, arg):
- self._pipeline.enable_shadows = int(arg)
- debug(f'shadows: {self._pipeline.enable_shadows}')
- self._opt_file['settings']['shadows'] = int(arg)
- self._opt_file.store()
-
- def on_website(self):
- if platform.startswith('linux'):
- environ['LD_LIBRARY_PATH'] = ''
- system('xdg-open https://www.ya2.it')
- else:
- open_new_tab('https://www.ya2.it')
-
- def on_back(self):
- self._opt_file.store()
- self.destroy()
- self._cursor = MouseCursor(
- 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
- (.01, .01))
- self._set_main()
-
- def destroy(self):
- [wdg.destroy() for wdg in self._widgets]
- self._cursor.destroy()