ya2 · news · projects · code · about

menu: two rows
[pmachines.git] / pmachines / menu.py
index f4c4ff2924e67cc2945060f966f0f9bffefa4fc9..494973d444e03ed816a06eff4ab2cefbd1344b8a 100644 (file)
@@ -1,6 +1,9 @@
-from logging import info
+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
@@ -8,6 +11,9 @@ 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:
@@ -18,6 +24,9 @@ class Menu:
         self._opt_file = opt_file
         self._music = music
         self._pipeline = pipeline
+        self._cursor = MouseCursor(
+            'assets/buttons/arrowUpLeft.png', (.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)
@@ -32,7 +41,7 @@ class Menu:
             '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': (-3.8, 3.8, -.6, 1.2)} | self._common
+        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 = {
@@ -70,6 +79,7 @@ class Menu:
         self._widgets += [DirectButton(
             text=_('Exit'), pos=(0, 1, -.6), command=lambda: exit(),
             **self._common_btn)]
+        self._rearrange_width()
 
     def _set_options(self):
         self._widgets = []
@@ -150,7 +160,7 @@ class Menu:
             text=_('Website'), pos=(-.6, 1, .29), command=self.on_website,
             **self._common_btn | {'scale': .08})]
         self._widgets += [OnscreenText(
-            _('Supporters\n  \1scale\1rdb\2\n  \1scale\1Luisa Tenuta\2\n  \1scale\1Damiana Ercolani\2'),
+            _('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)]
@@ -159,16 +169,63 @@ class Menu:
             **self._common_btn)]
 
     def on_play(self):
-        self._fsm.demand('Scene')
+        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/buttons/arrowUpLeft.png', (.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)}
+        left = - (dx := .8) * (min(3, len(scenes)) - 1) / 2
+        for i, cls in enumerate(scenes):
+            top = .1 if len(scenes) < 4 else .6
+            row = 0 if i < 3 else 1
+            self._widgets += [DirectButton(
+                text=cls.name(), pos=(left + dx * (i % 3), 1, top - dx * row),
+                command=self.start, extraArgs=[cls], text_wordwrap=4,
+                frameTexture='assets/images/scenes/%s.png' % cls.__name__,
+                **cmn)]
+        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/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1),
+            (.01, .01))
         self._set_options()
 
     def on_credits(self):
         self.destroy()
+        self._cursor = MouseCursor(
+            'assets/buttons/arrowUpLeft.png', (.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',
@@ -198,13 +255,13 @@ class Menu:
 
     def on_aa(self, arg):
         self._pipeline.msaa_samples = 4 if arg else 1
-        info(f'msaa: {self._pipeline.msaa_samples}')
+        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)
-        info(f'shadows: {self._pipeline.enable_shadows}')
+        debug(f'shadows: {self._pipeline.enable_shadows}')
         self._opt_file['settings']['shadows'] = int(arg)
         self._opt_file.store()
 
@@ -218,7 +275,11 @@ class Menu:
     def on_back(self):
         self._opt_file.store()
         self.destroy()
+        self._cursor = MouseCursor(
+            'assets/buttons/arrowUpLeft.png', (.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()