120 lines
3.6 KiB
Python
120 lines
3.6 KiB
Python
import itertools
|
|
from math import inf
|
|
from typing import Type, TYPE_CHECKING
|
|
|
|
import pyglet
|
|
|
|
from source.gui.event import EventPropagationMixin
|
|
|
|
if TYPE_CHECKING:
|
|
from source.gui.scene.abc import Scene
|
|
|
|
|
|
class Window(pyglet.window.Window, EventPropagationMixin): # NOQA
|
|
"""
|
|
Une fenêtre basée sur l'objet Window de pyglet.
|
|
Des scènes peuvent y être placé.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._scenes: list["Scene"] = list()
|
|
|
|
# Event Propagation
|
|
|
|
@property
|
|
def childs(self):
|
|
"""
|
|
Renvoie les scènes de la fenêtre. Utilisé pour la propagation d'événements.
|
|
:return: les scènes de la fenêtre.
|
|
"""
|
|
return self._scenes
|
|
|
|
# FPS
|
|
|
|
@staticmethod
|
|
def get_fps() -> float:
|
|
"""
|
|
Renvoie le nombre de FPS actuel de la fenêtre.
|
|
:return: le nombre de FPS actuel de la fenêtre.
|
|
"""
|
|
|
|
# on récupère la fonction responsable du rafraichissement de la fenêtre
|
|
refresh_func = pyglet.app.event_loop._redraw_windows # NOQA
|
|
|
|
# on récupère l'événement correspondant dans l'horloge de l'application
|
|
refresh_event = next(filter(
|
|
lambda item: item.func is refresh_func,
|
|
itertools.chain(
|
|
pyglet.clock._default._schedule_interval_items, # NOQA
|
|
pyglet.clock._default._schedule_items # NOQA
|
|
)
|
|
))
|
|
|
|
# renvoie infini s'il n'y avait pas de fréquence, sinon 1 / fréquence pour avoir le nombre de FPS
|
|
return inf if isinstance(refresh_event, pyglet.clock._ScheduledItem) else 1 / refresh_event.interval # NOQA
|
|
|
|
@staticmethod
|
|
def set_fps(value: float):
|
|
"""
|
|
Définit le nombre de FPS de la fenêtre.
|
|
:param value: nombre de FPS souhaité
|
|
"""
|
|
|
|
# on récupère la fonction responsable du rafraichissement de la fenêtre
|
|
refresh_func = pyglet.app.event_loop._redraw_windows # NOQA
|
|
|
|
# désactive le rafraichissement de la fenêtre
|
|
pyglet.clock.unschedule(refresh_func)
|
|
|
|
if value == inf:
|
|
# si la valeur est infinie, rafraichi dès que possible
|
|
pyglet.clock.schedule(refresh_func)
|
|
else:
|
|
# sinon rafraichi à la fréquence indiquée (1 / FPS)
|
|
pyglet.clock.schedule_interval(refresh_func, 1 / value)
|
|
|
|
# Scene Managing
|
|
|
|
def set_scene(self, scene_class: Type["Scene"], **scene_kwargs) -> "Scene":
|
|
"""
|
|
Défini la scène actuelle pour la fenêtre.
|
|
:scene_class: la classe de la scène à ajouter
|
|
:scene_kwargs: les arguments clés de la scène
|
|
:return: la nouvelle scène créée
|
|
"""
|
|
|
|
self.clear_scene()
|
|
return self.add_scene(scene_class, **scene_kwargs)
|
|
|
|
def add_scene(self, scene_class: Type["Scene"], priority: int = 0, **scene_kwargs) -> "Scene":
|
|
"""
|
|
Ajoute une scène à la fenêtre.
|
|
:scene_class: la classe de la scène à ajouter
|
|
:scene_kwargs: les arguments clés de la scène
|
|
:return: la nouvelle scène créée
|
|
"""
|
|
|
|
scene: "Scene" = scene_class(window=self, **scene_kwargs)
|
|
self._scenes.insert(priority, scene)
|
|
return scene
|
|
|
|
def remove_scene(self, scene: "Scene") -> None:
|
|
"""
|
|
Retire une scène spécifique de la fenêtre
|
|
:scene: la scène à retirer
|
|
"""
|
|
|
|
self._scenes.remove(scene)
|
|
|
|
def clear_scene(self) -> None:
|
|
"""
|
|
Retire toutes les scènes de la fenêtre.
|
|
"""
|
|
|
|
self._scenes.clear()
|
|
|
|
# Base Event
|
|
|
|
def on_draw(self): # NOQA
|
|
self.clear()
|