From 5dcd570be8c17660f086d58ab70d2f195de116ee Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 19 Feb 2023 16:50:05 +0100 Subject: [PATCH] added the possibility to prevent an event to propagate to the next widgets --- NOTE.md | 6 ++++-- source/event/signal/StopEventScene.py | 2 ++ source/event/signal/StopEventWidget.py | 2 ++ source/event/signal/__init__.py | 2 ++ source/gui/scene/Game.py | 1 - source/gui/scene/MainMenu.py | 2 +- source/gui/scene/Settings.py | 10 ++++++++-- source/gui/scene/abc/Scene.py | 22 +++++++++++++++++----- source/gui/widget/Input.py | 2 +- source/gui/window/Window.py | 20 +++++++++++++++----- 10 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 source/event/signal/StopEventScene.py create mode 100644 source/event/signal/StopEventWidget.py create mode 100644 source/event/signal/__init__.py diff --git a/NOTE.md b/NOTE.md index 341b491..5172c91 100644 --- a/NOTE.md +++ b/NOTE.md @@ -1,7 +1,9 @@ -A faire : +A faire : +- Prévisualisation des bateaux sur la grille + - Faire une scène incluant par défaut les boutons "Retour" -- Ajouter un moyen d'annuler les évenements de se propager aux widgets en dessous - Police d'écriture +- Combiner le _event_wrapper de Window et Scene (?) Bug : - Appuyez sur "Créer une salle" va lancer un thread, mais il n'est pas fermé s'il l'on revient dans diff --git a/source/event/signal/StopEventScene.py b/source/event/signal/StopEventScene.py new file mode 100644 index 0000000..81595c0 --- /dev/null +++ b/source/event/signal/StopEventScene.py @@ -0,0 +1,2 @@ +class StopEventScene(Exception): + pass diff --git a/source/event/signal/StopEventWidget.py b/source/event/signal/StopEventWidget.py new file mode 100644 index 0000000..3d04bb7 --- /dev/null +++ b/source/event/signal/StopEventWidget.py @@ -0,0 +1,2 @@ +class StopEventWidget(Exception): + pass diff --git a/source/event/signal/__init__.py b/source/event/signal/__init__.py new file mode 100644 index 0000000..f49c3b9 --- /dev/null +++ b/source/event/signal/__init__.py @@ -0,0 +1,2 @@ +from .StopEventScene import StopEventScene +from .StopEventWidget import StopEventWidget diff --git a/source/gui/scene/Game.py b/source/gui/scene/Game.py index f2a9d31..27d8c04 100644 --- a/source/gui/scene/Game.py +++ b/source/gui/scene/Game.py @@ -5,7 +5,6 @@ import pyglet from source.gui.scene.abc import Scene from source.gui import widget, texture from source import core -from source.utils.dict import dict_add_prefix if TYPE_CHECKING: from source.gui.window import Window diff --git a/source/gui/scene/MainMenu.py b/source/gui/scene/MainMenu.py index 2f9e730..4ca5746 100644 --- a/source/gui/scene/MainMenu.py +++ b/source/gui/scene/MainMenu.py @@ -80,7 +80,7 @@ class MainMenu(Scene): label_batch=self.batch_label ) - self.settings.add_listener("on_click_release", lambda *_: self.window.set_scene(scene.Settings)) + self.settings.add_listener("on_click_release", lambda *_: self.window.add_scene(scene.Settings)) def on_draw(self): self.background.draw() diff --git a/source/gui/scene/Settings.py b/source/gui/scene/Settings.py index cde00fb..075c16c 100644 --- a/source/gui/scene/Settings.py +++ b/source/gui/scene/Settings.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING import pyglet +from source.event.signal import StopEventScene from source.gui.scene.abc import Scene from source.gui import widget, texture @@ -31,8 +32,7 @@ class Settings(Scene): label_batch=self.batch_label ) - from source.gui.scene import MainMenu - self.back.add_listener("on_click_release", lambda *_: self.window.set_scene(MainMenu)) + self.back.add_listener("on_click_release", lambda *_: self.window.remove_scene(self)) self.checkbox = self.add_widget( widget.Checkbox, @@ -67,3 +67,9 @@ class Settings(Scene): self.batch_checkbox.draw() self.batch_label.draw() + + def on_mouse_press_after(self, x: int, y: int, button: int, modifiers: int): + raise StopEventScene() + + def on_mouse_motion_after(self, x: int, y: int, button: int, modifiers: int): + raise StopEventScene() diff --git a/source/gui/scene/abc/Scene.py b/source/gui/scene/abc/Scene.py index b0ec6ea..f90e072 100644 --- a/source/gui/scene/abc/Scene.py +++ b/source/gui/scene/abc/Scene.py @@ -2,6 +2,8 @@ from abc import ABC from functools import lru_cache from typing import TYPE_CHECKING, Callable, Type, Any +from source.event.signal import StopEventWidget + if TYPE_CHECKING: from source.gui.window import Window from source.gui.widget.abc import Widget @@ -17,7 +19,7 @@ class Scene(ABC): def __init__(self, window: "Window", *args, **kwargs): self.window = window - self._widgets: set["Widget"] = set() + self._widgets: list["Widget"] = list() # Widget Managing @@ -31,13 +33,13 @@ class Scene(ABC): """ widget: "Widget" = widget_class(self, **widget_kwargs) - self._widgets.add(widget) + self._widgets.append(widget) return widget def remove_widget(self, widget: "Widget") -> None: """ Remove a widget from the scene. - :param scene: the widget to remove. + :param widget: the widget to remove. """ self._widgets.remove(widget) @@ -59,15 +61,25 @@ class Scene(ABC): :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.* + # 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: - getattr(widget, item, lambda *_, **__: "pass")(*args, **kwargs) + 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 diff --git a/source/gui/widget/Input.py b/source/gui/widget/Input.py index 93b4d1f..707bc57 100644 --- a/source/gui/widget/Input.py +++ b/source/gui/widget/Input.py @@ -62,7 +62,7 @@ class Input(BoxWidget): return ( texture if self.activated and (texture := self.style.get("active")) is not None else # NOQA - texture if self.invalid and (texture := self.style.get("error")) is not None else + texture if self.invalid and (texture := self.style.get("signal")) is not None else self.style.get("normal") ) diff --git a/source/gui/window/Window.py b/source/gui/window/Window.py index 18fbecf..6eae773 100644 --- a/source/gui/window/Window.py +++ b/source/gui/window/Window.py @@ -3,6 +3,7 @@ from typing import Type, Callable, TYPE_CHECKING, Any import pyglet +from source.event.signal import StopEventScene if TYPE_CHECKING: from source.gui.scene.abc import Scene @@ -17,7 +18,7 @@ class Window(pyglet.window.Window): # NOQA def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._scenes: set["Scene"] = set() + self._scenes: list["Scene"] = list() # Scene Managing @@ -33,7 +34,7 @@ class Window(pyglet.window.Window): # NOQA self.clear_scene() return self.add_scene(scene_class, *scene_args, **scene_kwargs) - def add_scene(self, scene_class: Type["Scene"], *scene_args, **scene_kwargs) -> "Scene": + def add_scene(self, scene_class: Type["Scene"], priority: int = 0, *scene_args, **scene_kwargs) -> "Scene": """ Add a scene of the window. :scene_class: the class of the scene to add. @@ -43,7 +44,7 @@ class Window(pyglet.window.Window): # NOQA """ scene: "Scene" = scene_class(window=self, *scene_args, **scene_kwargs) - self._scenes.add(scene) + self._scenes.insert(priority, scene) return scene def remove_scene(self, scene: "Scene") -> None: @@ -76,6 +77,13 @@ class Window(pyglet.window.Window): # NOQA :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) @@ -89,8 +97,10 @@ class Window(pyglet.window.Window): # NOQA def _func(*args, **kwargs) -> None: if func is not None: func(*args, **kwargs) - for scene in self._scenes: - getattr(scene, item)(*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)