factorised the event_wrapper from Window and Scene to a Mixin
This commit is contained in:
parent
f38f440e9d
commit
8a385a75bf
10 changed files with 87 additions and 110 deletions
5
NOTE.md
5
NOTE.md
|
@ -1,9 +1,10 @@
|
|||
A faire :
|
||||
- Ecran de configuration de la partie
|
||||
- Nom dans les options
|
||||
- Prévisualisation des bateaux sur la grille
|
||||
|
||||
- Faire une scène incluant par défaut les boutons "Retour"
|
||||
- Police d'écriture
|
||||
- Combiner le _event_wrapper de Window et Scene (?)
|
||||
|
||||
Bug :
|
||||
- /
|
||||
- /
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
class StopEventScene(Exception):
|
||||
pass
|
|
@ -1,2 +0,0 @@
|
|||
class StopEventWidget(Exception):
|
||||
pass
|
|
@ -1,2 +0,0 @@
|
|||
from .StopEventScene import StopEventScene
|
||||
from .StopEventWidget import StopEventWidget
|
59
source/gui/event/EventPropagationMixin.py
Normal file
59
source/gui/event/EventPropagationMixin.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
from abc import abstractmethod
|
||||
from functools import lru_cache
|
||||
from typing import Callable, Any
|
||||
|
||||
from source.gui.event import StopEvent
|
||||
|
||||
|
||||
class EventPropagationMixin:
|
||||
@property
|
||||
@abstractmethod
|
||||
def childs(self):
|
||||
pass
|
||||
|
||||
@lru_cache
|
||||
def _event_wrapper(self, item: str) -> Callable:
|
||||
"""
|
||||
Un wrapper permettant d'appeler l'événement de toutes les scènes attachées.
|
||||
:param item: nom de la fonction à appeler dans la scène.
|
||||
:return: une fonction appelant l'événement original ainsi que ceux des scènes.
|
||||
"""
|
||||
|
||||
# if the event is the drawing of the objects, reverse the order of the scenes
|
||||
# so that the last drawn are the one on top
|
||||
child_transform = (
|
||||
(lambda child: reversed(child)) if item == "on_draw" else
|
||||
(lambda child: child)
|
||||
)
|
||||
|
||||
# try to get the original function
|
||||
func = None
|
||||
try: func = super().__getattribute__(item)
|
||||
except AttributeError: pass
|
||||
|
||||
# try to get a function that would get executed after everything else
|
||||
func_after = None
|
||||
try: func_after = super().__getattribute__(item + "_after")
|
||||
except AttributeError: pass
|
||||
|
||||
def _func(*args, **kwargs) -> None:
|
||||
if func is not None: func(*args, **kwargs)
|
||||
|
||||
for child in child_transform(self.childs):
|
||||
try: getattr(child, item, lambda *_, **__: "pass")(*args, **kwargs)
|
||||
# si l'erreur StopEventScene est détecté, les autres scènes ne recevront pas l'event
|
||||
except StopEvent: break
|
||||
|
||||
if func_after is not None: func_after(*args, **kwargs)
|
||||
|
||||
return _func
|
||||
|
||||
def __getattribute__(self, item: str) -> Any:
|
||||
"""
|
||||
Fonction appelée dès que l'on essaye d'accéder à l'un des attributs de l'objet.
|
||||
:param item: nom de l'attribut recherché
|
||||
:return: l'attribut de l'objet correspondant.
|
||||
"""
|
||||
|
||||
# si l'attribut est un événement (commence par "on_"), alors renvoie le dans un wrapper
|
||||
return self._event_wrapper(item) if item.startswith("on_") else super().__getattribute__(item)
|
2
source/gui/event/StopEvent.py
Normal file
2
source/gui/event/StopEvent.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
class StopEvent(Exception):
|
||||
pass
|
2
source/gui/event/__init__.py
Normal file
2
source/gui/event/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
from .StopEvent import StopEvent
|
||||
from .EventPropagationMixin import EventPropagationMixin
|
|
@ -2,7 +2,7 @@ from typing import TYPE_CHECKING
|
|||
|
||||
import pyglet
|
||||
|
||||
from source.event.signal import StopEventScene
|
||||
from source.gui.event import StopEvent
|
||||
from source.gui.scene.abc import Scene
|
||||
from source.gui import widget, texture
|
||||
|
||||
|
@ -69,7 +69,7 @@ class Settings(Scene):
|
|||
self.batch_label.draw()
|
||||
|
||||
def on_mouse_press_after(self, x: int, y: int, button: int, modifiers: int):
|
||||
raise StopEventScene()
|
||||
raise StopEvent()
|
||||
|
||||
def on_mouse_motion_after(self, x: int, y: int, button: int, modifiers: int):
|
||||
raise StopEventScene()
|
||||
raise StopEvent()
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
from abc import ABC
|
||||
from functools import lru_cache
|
||||
from typing import TYPE_CHECKING, Callable, Type, Any
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from source.event.signal import StopEventWidget
|
||||
from source.gui.event import EventPropagationMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from source.gui.window import Window
|
||||
from source.gui.widget.abc import Widget
|
||||
|
||||
|
||||
class Scene(ABC):
|
||||
class Scene(ABC, EventPropagationMixin):
|
||||
"""
|
||||
A scene that can be attached to a window.
|
||||
It allows to switch the whole comportment of the window in a simpler way.
|
||||
|
@ -21,6 +20,12 @@ class Scene(ABC):
|
|||
self.window = window
|
||||
self._widgets: list["Widget"] = list()
|
||||
|
||||
# Event propagation
|
||||
|
||||
@property
|
||||
def childs(self):
|
||||
return self._widgets
|
||||
|
||||
# Widget Managing
|
||||
|
||||
def add_widget(self, widget_class: Type["Widget"], **widget_kwargs):
|
||||
|
@ -50,45 +55,3 @@ class Scene(ABC):
|
|||
"""
|
||||
|
||||
self._widgets.clear()
|
||||
|
||||
# Event Handling
|
||||
|
||||
@lru_cache
|
||||
def _event_wrapper(self, item: str) -> Callable:
|
||||
"""
|
||||
Un wrapper permettant d'appeler l'événement de tous les widgets attachées.
|
||||
:param item: nom de la fonction à appeler dans le widget.
|
||||
:return: une fonction appelant l'événement original ainsi que ceux des scènes.
|
||||
"""
|
||||
|
||||
# Récupère la fonction originale. S'il n'y en a pas, renvoie une fonction sans effet.
|
||||
func = None
|
||||
try: func = super().__getattribute__(item)
|
||||
except AttributeError: pass
|
||||
|
||||
# Récupère une fonction qui devra s'exécuter après tout le reste
|
||||
func_after = None
|
||||
try: func_after = super().__getattribute__(item + "_after")
|
||||
except AttributeError: pass
|
||||
|
||||
def _func(*args, **kwargs) -> None:
|
||||
if func is not None: func(*args, **kwargs)
|
||||
|
||||
for widget in self._widgets:
|
||||
try: getattr(widget, item, lambda *_, **__: "pass")(*args, **kwargs)
|
||||
# si l'erreur StopEventWidget est détecté, les autres scènes ne recevront pas l'event
|
||||
except StopEventWidget: break
|
||||
|
||||
if func_after is not None: func_after(*args, **kwargs)
|
||||
|
||||
return _func
|
||||
|
||||
def __getattribute__(self, item: str) -> Any:
|
||||
"""
|
||||
Fonction appelée dès que l'on essaye d'accéder à l'un des attributs de l'objet.
|
||||
:param item: nom de l'attribut recherché
|
||||
:return: l'attribut de l'objet correspondant.
|
||||
"""
|
||||
|
||||
# si l'attribut est un événement (commence par "on_"), alors renvoie le dans un wrapper
|
||||
return self._event_wrapper(item) if item.startswith("on_") else super().__getattribute__(item)
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
from functools import lru_cache
|
||||
from typing import Type, Callable, TYPE_CHECKING, Any
|
||||
from typing import Type, TYPE_CHECKING
|
||||
|
||||
import pyglet
|
||||
|
||||
from source.event.signal import StopEventScene
|
||||
from source.gui.event import EventPropagationMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from source.gui.scene.abc import Scene
|
||||
|
||||
|
||||
class Window(pyglet.window.Window): # NOQA
|
||||
class Window(pyglet.window.Window, EventPropagationMixin): # NOQA
|
||||
"""
|
||||
A window. Based on the pyglet window object.
|
||||
Scene can be added to the window
|
||||
|
@ -20,6 +19,12 @@ class Window(pyglet.window.Window): # NOQA
|
|||
|
||||
self._scenes: list["Scene"] = list()
|
||||
|
||||
# Event Propagation
|
||||
|
||||
@property
|
||||
def childs(self):
|
||||
return self._scenes
|
||||
|
||||
# Scene Managing
|
||||
|
||||
def set_scene(self, scene_class: Type["Scene"], *scene_args, **scene_kwargs) -> "Scene":
|
||||
|
@ -66,52 +71,3 @@ class Window(pyglet.window.Window): # NOQA
|
|||
|
||||
def on_draw(self): # NOQA
|
||||
self.clear()
|
||||
|
||||
# Event Handling
|
||||
|
||||
@lru_cache
|
||||
def _event_wrapper(self, item: str) -> Callable:
|
||||
"""
|
||||
Un wrapper permettant d'appeler l'événement de toutes les scènes attachées.
|
||||
:param item: nom de la fonction à appeler dans la scène.
|
||||
:return: une fonction appelant l'événement original ainsi que ceux des scènes.
|
||||
"""
|
||||
|
||||
# if the event is the drawing of the objects, reverse the order of the scenes
|
||||
# so that the last drawn are the one on top
|
||||
scene_transform = (
|
||||
(lambda scenes: reversed(scenes)) if item == "on_draw" else
|
||||
(lambda scenes: scenes)
|
||||
)
|
||||
|
||||
# try to get the original function
|
||||
func = None
|
||||
try: func = super().__getattribute__(item)
|
||||
except AttributeError: pass
|
||||
|
||||
# try to get a function that would get executed after everything else
|
||||
func_after = None
|
||||
try: func_after = super().__getattribute__(item + "_after")
|
||||
except AttributeError: pass
|
||||
|
||||
def _func(*args, **kwargs) -> None:
|
||||
if func is not None: func(*args, **kwargs)
|
||||
|
||||
for scene in scene_transform(self._scenes):
|
||||
try: getattr(scene, item)(*args, **kwargs)
|
||||
# si l'erreur StopEventScene est détecté, les autres scènes ne recevront pas l'event
|
||||
except StopEventScene: break
|
||||
|
||||
if func_after is not None: func_after(*args, **kwargs)
|
||||
|
||||
return _func
|
||||
|
||||
def __getattribute__(self, item: str) -> Any:
|
||||
"""
|
||||
Fonction appelée dès que l'on essaye d'accéder à l'un des attributs de l'objet.
|
||||
:param item: nom de l'attribut recherché
|
||||
:return: l'attribut de l'objet correspondant.
|
||||
"""
|
||||
|
||||
# si l'attribut est un événement (commence par "on_"), alors renvoie le dans un wrapper
|
||||
return self._event_wrapper(item) if item.startswith("on_") else super().__getattribute__(item)
|
||||
|
|
Loading…
Reference in a new issue