diff --git a/assets/test_button_clicking.png b/assets/test_button_clicking.png deleted file mode 100644 index 13a3ed3..0000000 Binary files a/assets/test_button_clicking.png and /dev/null differ diff --git a/assets/test_button_hover.png b/assets/test_button_hover.png deleted file mode 100644 index 89cbda0..0000000 Binary files a/assets/test_button_hover.png and /dev/null differ diff --git a/assets/test_button_normal.png b/assets/test_button_normal.png deleted file mode 100644 index 706e5f1..0000000 Binary files a/assets/test_button_normal.png and /dev/null differ diff --git a/main.pyw b/main.pyw index b55b3ab..330234a 100644 --- a/main.pyw +++ b/main.pyw @@ -1,19 +1,14 @@ import pyglet +from source.gui.scene.debug import FPSScene +from source.gui.scene.test import HelloWorldScene from source.gui.window import Window -from source.gui.scene.debug import FPSCounterScene -from source.gui.scene.test import ButtonScene -# Créer une fenêtre -window = Window(resizable=True, visible=False) -# performance and button test +# Create a new window +window = Window(resizable=True, vsync=False) +window.add_scene(HelloWorldScene(), FPSScene()) -button_scene = ButtonScene() -fps_counter_scene = FPSCounterScene() +# Start the event loop +pyglet.app.run(interval=0) -window.add_scene(button_scene, fps_counter_scene) - -# Lance la fenêtre -window.set_visible(True) -pyglet.app.run() diff --git a/source/gui/scene/MainMenu.py b/source/gui/scene/MainMenu.py deleted file mode 100644 index cbf0fe3..0000000 --- a/source/gui/scene/MainMenu.py +++ /dev/null @@ -1,15 +0,0 @@ -from source.gui.scene.base import Scene - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from source.gui.window import Window - - -class MainMenuScene(Scene): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def on_draw(self, window: "Window"): - super().on_draw(window) - diff --git a/source/gui/scene/__init__.py b/source/gui/scene/__init__.py index 3bcdbb8..e69de29 100644 --- a/source/gui/scene/__init__.py +++ b/source/gui/scene/__init__.py @@ -1 +0,0 @@ -from source.gui.scene.test.HelloWorldScene import HelloWorldScene diff --git a/source/gui/scene/base/Scene.py b/source/gui/scene/base/BaseScene.py similarity index 84% rename from source/gui/scene/base/Scene.py rename to source/gui/scene/base/BaseScene.py index 93dcb03..7e4948b 100644 --- a/source/gui/scene/base/Scene.py +++ b/source/gui/scene/base/BaseScene.py @@ -1,37 +1,33 @@ -from pyglet.event import EventDispatcher - -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: - from source.gui.widget.base import Widget from source.gui.window import Window + from source.gui.widget.base import BaseWidget -class Scene(EventDispatcher): +class BaseScene: """ - This class represent a scene that can be applied to a pyglet window. - - The scene can represent anything like the main menu, the game, the - options' menu, the multiplayer menu, ... + A scene that can be attached to a window """ - def __init__(self, widgets: list["Widget"] = None): - self._widgets: list["Widget"] = [] - if widgets is not None: self.add_widget(*widgets) + def __init__(self): + self._widgets: list["BaseWidget"] = [] + self._window: Optional["Window"] = None - def add_widget(self, *widgets: "Widget", priority: int = 0) -> None: + # widget + + def add_widget(self, *widgets: "BaseWidget", priority: int = 0) -> None: for widget in widgets: self._widgets.insert(priority, widget) widget.on_scene_added(self) - def remove_widget(self, *widgets: "Widget") -> None: + def remove_widget(self, *widgets: "BaseWidget") -> None: for widget in widgets: widget.on_scene_removed(self) self._widgets.remove(widget) def clear_widget(self) -> None: - for widget in self._widgets: widget.on_scene_removed(self) - self._widgets.clear() + self.remove_widget(*self._widgets) # scene event @@ -41,7 +37,19 @@ class Scene(EventDispatcher): def on_window_removed(self, window: "Window"): # when the Scene is removed from a window for widget in self._widgets: widget.on_window_removed(window, self) - # window event + # window + + @property + def window(self) -> "Window": + return self._window + + @window.setter + def window(self, window: "Window"): + if self._window is not None: self.on_window_removed(self._window) + self._window = window + if self._window is not None: self.on_window_added(self._window) + + # event def on_draw(self, window: "Window"): for widget in self._widgets: widget.on_draw(window, self) diff --git a/source/gui/scene/base/__init__.py b/source/gui/scene/base/__init__.py index 8abb0fe..ab09621 100644 --- a/source/gui/scene/base/__init__.py +++ b/source/gui/scene/base/__init__.py @@ -1 +1 @@ -from .Scene import Scene +from .BaseScene import BaseScene diff --git a/source/gui/scene/debug/FPSCounterScene.py b/source/gui/scene/debug/FPSCounterScene.py deleted file mode 100644 index 728d1c1..0000000 --- a/source/gui/scene/debug/FPSCounterScene.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Optional, TYPE_CHECKING - -import pyglet - -from source.gui.scene.base import Scene - -if TYPE_CHECKING: - from source.gui.window import Window - - -class FPSCounterScene(Scene): - """ - This scene represent a simple FPS Counter. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fps_display: Optional[pyglet.window.FPSDisplay] = None - - def on_window_added(self, window: "Window"): - super().on_window_added(window) - - # the fps display need to be defined here because it is the moment where the window is first accessible - self.fps_display = pyglet.window.FPSDisplay(window=window) - - def on_draw(self, window: "Window") -> None: - super().on_draw(window) - - self.fps_display.draw() diff --git a/source/gui/scene/debug/FPSScene.py b/source/gui/scene/debug/FPSScene.py new file mode 100644 index 0000000..906793c --- /dev/null +++ b/source/gui/scene/debug/FPSScene.py @@ -0,0 +1,20 @@ +from typing import TYPE_CHECKING + +import pyglet.window + +from source.gui.scene.base import BaseScene + +if TYPE_CHECKING: + from source.gui.window import Window + + +class FPSScene(BaseScene): + def __init__(self): + super().__init__() + self._fps_display = None + + def on_window_added(self, window: "Window"): + self._fps_display = pyglet.window.FPSDisplay(window) + + def on_draw(self, window: "Window"): + self._fps_display.draw() diff --git a/source/gui/scene/debug/__init__.py b/source/gui/scene/debug/__init__.py index 103cb11..a8d0b54 100644 --- a/source/gui/scene/debug/__init__.py +++ b/source/gui/scene/debug/__init__.py @@ -1 +1 @@ -from .FPSCounterScene import FPSCounterScene +from .FPSScene import FPSScene diff --git a/source/gui/scene/test/ButtonScene.py b/source/gui/scene/test/ButtonScene.py deleted file mode 100644 index dd23ee8..0000000 --- a/source/gui/scene/test/ButtonScene.py +++ /dev/null @@ -1,30 +0,0 @@ -import pyglet - -from source.gui.scene.base import Scene -from source.gui.widget import Button - - -class ButtonScene(Scene): - """ - This is a simple scene to test Button and their adaptable size - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - button_normal_image = pyglet.image.load("./assets/test_button_normal.png") - button_hover_image = pyglet.image.load("./assets/test_button_hover.png") - button_click_image = pyglet.image.load("./assets/test_button_clicking.png") - - for x in range(10): - for y in range(10): - self.add_widget(Button( - x * 0.1, y * 0.1, 0.1, 0.1, - - text=f"{x}-{y}", - font_size=10, - on_release=lambda self, *a, **b: print(self, "clicked !"), - normal_image=button_normal_image, - hover_image=button_hover_image, - click_image=button_click_image - )) diff --git a/source/gui/scene/test/HelloWorldScene.py b/source/gui/scene/test/HelloWorldScene.py index 4dad084..af6c0fb 100644 --- a/source/gui/scene/test/HelloWorldScene.py +++ b/source/gui/scene/test/HelloWorldScene.py @@ -1,59 +1,55 @@ -from datetime import datetime, timedelta +from typing import TYPE_CHECKING import pyglet -from source.gui.scene.base import Scene - -from typing import TYPE_CHECKING +from source.gui.scene.base import BaseScene +from source.gui.widget.Button import Button if TYPE_CHECKING: from source.gui.window import Window -class HelloWorldScene(Scene): - """ - This scene is a simple Hello World. +class HelloWorldScene(BaseScene): + def __init__(self): + super().__init__() - You can type anything with the keyboard or use backspace to remove characters. - The text is centered on the screen. - """ + self.button_atlas = None + self.sprite_batch = None + self.label_batch = None - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def on_window_added(self, window: "Window") -> None: + normal_texture = pyglet.image.load("./assets/image/button/test_button_normal.png") + hover_texture = pyglet.image.load("./assets/image/button/test_button_hover.png") + click_texture = pyglet.image.load("./assets/image/button/test_button_clicking.png") - self.label = pyglet.text.Label( - "Hello World !", - anchor_x="center", - anchor_y="center" - ) + self.button_atlas = pyglet.image.atlas.TextureAtlas() + normal_region = self.button_atlas.add(normal_texture) + hover_region = self.button_atlas.add(hover_texture) + click_region = self.button_atlas.add(click_texture) - # remember the cooldown for the backspace button - self._hold_backspace_last_call: datetime = datetime.now() + self.sprite_batch = pyglet.graphics.Batch() + self.label_batch = pyglet.graphics.Batch() - def on_draw(self, window: "Window") -> None: + for x in range(10): + for y in range(10): + self.add_widget(Button( + x=x*0.1, y=y*0.1, width=0.1, height=0.1, + + normal_texture=normal_region, + hover_texture=hover_region, + click_texture=click_region, + + label_text=f"TEST TEST CENTERING {x}.{y}", + label_multiline=True, + + label_batch=self.label_batch, + sprite_batch=self.sprite_batch, + )) + + super().on_window_added(window) + + def on_draw(self, window: "Window"): super().on_draw(window) - self.label.draw() - - def on_resize(self, window: "Window", width: int, height: int) -> None: - super().on_resize(window, width, height) - - self.label.x = width // 2 - self.label.y = height // 2 - - def on_text(self, window: "Window", char: str): - super().on_text(window, char) - - self.label.text += char - - def on_key_held(self, window: "Window", dt: float, symbol: int, modifiers: int): - super().on_key_held(window, dt, symbol, modifiers) - - if symbol == pyglet.window.key.BACKSPACE: - - # add a cooldown of 0.1 second on the backspace key - now = datetime.now() - if self._hold_backspace_last_call + timedelta(seconds=0.1) < now: - self._hold_backspace_last_call = now - - self.label.text = self.label.text[:-1] + self.sprite_batch.draw() + self.label_batch.draw() diff --git a/source/gui/scene/test/__init__.py b/source/gui/scene/test/__init__.py index d2a1e98..7d9c684 100644 --- a/source/gui/scene/test/__init__.py +++ b/source/gui/scene/test/__init__.py @@ -1,2 +1 @@ from .HelloWorldScene import HelloWorldScene -from .ButtonScene import ButtonScene diff --git a/source/gui/sprite/Sprite.py b/source/gui/sprite/Sprite.py index c23376f..44a4ae1 100644 --- a/source/gui/sprite/Sprite.py +++ b/source/gui/sprite/Sprite.py @@ -2,12 +2,15 @@ import pyglet.sprite class Sprite(pyglet.sprite.Sprite): - def __init__(self, *args, **kwargs): + def __init__(self, *args, width: int = None, height: int = None, **kwargs): super().__init__(*args, **kwargs) self._orig_width: int = self.width self._orig_height: int = self.height + if width is not None: self.width = width + if height is not None: self.height = height + @pyglet.sprite.Sprite.width.setter def width(self, width: int): self.scale_x = width / self._orig_width diff --git a/source/gui/widget/Button.py b/source/gui/widget/Button.py index a0d45ca..da11499 100644 --- a/source/gui/widget/Button.py +++ b/source/gui/widget/Button.py @@ -1,155 +1,179 @@ -from typing import Callable, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable -import pyglet +import pyglet.image from source.gui.sprite import Sprite -from source.gui.widget.base import AdaptativeWidget +from source.gui.widget.base import BaseAdaptativeWidget from source.type import Percentage from source.utils import in_bbox if TYPE_CHECKING: - from typing import Self - from source.gui.scene.base import Scene from source.gui.window import Window + from source.gui.scene.base import BaseScene -class Button(AdaptativeWidget): +class Button(BaseAdaptativeWidget): def __init__(self, + # position x: int | Percentage, y: int | Percentage, width: int | Percentage, height: int | Percentage, - normal_image: pyglet.image.AbstractImage, - hover_image: pyglet.image.AbstractImage = None, - click_image: pyglet.image.AbstractImage = None, + # background + normal_texture: pyglet.image.AbstractImage, + hover_texture: pyglet.image.AbstractImage = None, + click_texture: pyglet.image.AbstractImage = None, - on_press: Optional[Callable] = None, - on_release: Optional[Callable] = None, + # label + label_text: str = "", + label_font_name: str = None, + label_font_size: int = None, + label_bold: bool = False, + label_italic: bool = False, + label_stretch: bool = False, + label_color: tuple[int, int, int, int] = (255, 255, 255, 255), + label_align: str = "center", + label_multiline: bool = False, + label_dpi: int = None, + label_rotation: int = 0, - *args, **kwargs + # callback function + on_press: Callable = None, + on_release: Callable = None, + + # batch + label_batch: pyglet.graphics.Batch = None, + sprite_batch: pyglet.graphics.Batch = None, + + # group + label_group: pyglet.graphics.Group = None, + sprite_group: pyglet.graphics.Group = None, ): super().__init__(x, y, width, height) - # TODO: use batch ? - # TODO: use texture bin and animation to simplify the image handling ? - # TODO: font_size dynamic sizing too ? + self._normal_texture = normal_texture + self._hover_texture = hover_texture + self._click_texture = click_texture - # the label used for the text - self._label = pyglet.text.Label( - anchor_x="center", anchor_y="center", - *args, **kwargs + self.on_press = on_press + self.on_release = on_release + + self._label = None + self._label_kwargs = { + "text": label_text, + "font_name": label_font_name, + "font_size": label_font_size, + "bold": label_bold, + "italic": label_italic, + "stretch": label_stretch, + "color": label_color, + "align": label_align, + "multiline": label_multiline, + "dpi": label_dpi, + "rotation": label_rotation, + + "batch": label_batch, + "group": label_group, + } + + self._sprite = None + self._sprite_kwargs = { + "batch": sprite_batch, + "group": sprite_group, + } + + self._hover = False + self._click = False + + # button update + + @property + def hover(self) -> bool: + return self._hover + + @hover.setter + def hover(self, hover: bool) -> None: + self._hover = hover + self._update_sprite() + + @property + def click(self) -> bool: + return self._click + + @click.setter + def click(self, click: bool) -> None: + self._click = click + self._update_sprite() + + @property + def background_texture(self) -> pyglet.image.AbstractImage: + return ( + self._click_texture if self._click else + self._hover_texture if self._hover else + self._normal_texture ) - # the button background - self._hovering = False - self._clicking = False + def _update_sprite(self): + self._sprite.image = self.background_texture - self._sprite = Sprite(normal_image) - - self._normal_image = normal_image - self._hover_image = hover_image if hover_image is not None else normal_image - self._click_image = click_image if click_image is not None else normal_image - - # the event when the button is clicked - self.on_press: Optional[Callable[["Self", "Window", "Scene", int, int, int, int], None]] = on_press - self.on_release: Optional[Callable[["Self", "Window", "Scene", int, int, int, int], None]] = on_release - - # update the size of the widget - self._update_size() - - # function - - def _update_sprite(self) -> None: - self._sprite.image = self.background_image - - def _update_size(self): + def update_size(self): self._sprite.x = self.x self._sprite.y = self.y self._sprite.width = self.width self._sprite.height = self.height - self._label.x = self.x + (self.width // 2) - self._label.y = self.y + (self.height // 2) - - # button getter and setter - - @property - def hovering(self) -> bool: return self._hovering - - @hovering.setter - def hovering(self, hovering: bool): - self._hovering = hovering - self._update_sprite() - - @property - def clicking(self) -> bool: - return self._clicking - - @clicking.setter - def clicking(self, clicking: bool): - self._clicking = clicking - self._update_sprite() - - @property - def background_image(self) -> pyglet.image.AbstractImage: - return ( - self._click_image if self._clicking - else self._hover_image if self._hovering - else self._normal_image - ) - - # label getter and setter - - @AdaptativeWidget.x.setter - def x(self, x: int): - super().x = x - self._update_size() - - @AdaptativeWidget.y.setter - def y(self, y: int): - super().y = y - self._update_size() - - @AdaptativeWidget.width.setter - def width(self, width: int): - super().width = width - self._update_size() - - @AdaptativeWidget.height.setter - def height(self, height: int): - super().height = height - self._update_size() + self._label.x = self.x + self.width / 2 + self._label.y = self.y + self.height / 2 + self._label.width = self.width # event - def on_mouse_press(self, window: "Window", scene: "Scene", x: int, y: int, button: int, modifiers: int): + def on_window_added(self, window: "Window", scene: "BaseScene"): + super().on_window_added(window, scene) + + self._label = pyglet.text.Label( + x=self.x + self.width / 2, + y=self.y + self.height / 2, + + width=self.width, + anchor_x="center", anchor_y="center", + + **self._label_kwargs + ) + + self._sprite = Sprite( + self._normal_texture, + + x=self.x, y=self.y, + width=self.width, height=self.height, + + **self._sprite_kwargs + ) + + def on_mouse_motion(self, window: "Window", scene: "BaseScene", x: int, y: int, dx: int, dy: int): + self.hover = in_bbox((x, y), self.bbox) + + def on_mouse_press(self, window: "Window", scene: "BaseScene", x: int, y: int, button: int, modifiers: int): if not in_bbox((x, y), self.bbox): return - self.clicking = True + self.click = True if self.on_press is not None: self.on_press(self, window, scene, x, y, button, modifiers) - def on_mouse_release(self, window: "Window", scene: "Scene", x: int, y: int, button: int, modifiers: int): - old_clicking = self.clicking - self.clicking = False + def on_mouse_release(self, window: "Window", scene: "BaseScene", x: int, y: int, button: int, modifiers: int): + old_click = self.click + self.click = False if not in_bbox((x, y), self.bbox): return # if this button was the one hovered when the click was pressed - if old_clicking and self.on_release is not None: + if old_click and self.on_release is not None: self.on_release(self, window, scene, x, y, button, modifiers) - def on_mouse_motion(self, window: "Window", scene: "Scene", x: int, y: int, dx: int, dy: int): - self.hovering = in_bbox((x, y), self.bbox) - def on_draw(self, window: "Window", scene: "Scene"): - if self._sprite is not None: self._sprite.draw() - self._label.draw() - - def on_resize(self, window: "Window", scene: "Scene", width: int, height: int): - super().on_resize(window, scene, width, height) - self._update_size() +# TODO: on_resize seem really slow +# TODO: make the percentage dynamic or non dynamic diff --git a/source/gui/widget/__init__.py b/source/gui/widget/__init__.py index 631babf..e69de29 100644 --- a/source/gui/widget/__init__.py +++ b/source/gui/widget/__init__.py @@ -1 +0,0 @@ -from .Button import Button diff --git a/source/gui/widget/base/AdaptativeWidget.py b/source/gui/widget/base/AdaptativeWidget.py deleted file mode 100644 index 1429f34..0000000 --- a/source/gui/widget/base/AdaptativeWidget.py +++ /dev/null @@ -1,75 +0,0 @@ -from source.gui.widget.base import Widget - -from typing import TYPE_CHECKING - -from source.type import BBox, Percentage - -if TYPE_CHECKING: - from source.gui.window import Window - from source.gui.scene.base import Scene - - -class AdaptativeWidget(Widget): - """ - Similar to a normal Widget - - If the x, y, width or height is a float (representing a percentage), it will change depending on the window size - """ - - def __init__(self, - - x: int | Percentage, - y: int | Percentage, - width: int | Percentage, - height: int | Percentage, - ): - - self._x = x - self._y = y - self._width = width - self._height = height - - self._window_width = 0 - self._window_height = 0 - - # getter / setter - - @property - def x(self) -> int: - return self._x if isinstance(self._x, int) else self._x * self._window_width - - @x.setter - def x(self, x: int | Percentage) -> None: - self._x = x - - @property - def y(self) -> int: - return self._y if isinstance(self._y, int) else self._y * self._window_height - - @y.setter - def y(self, y: int | Percentage) -> None: - self._y = y - - @property - def width(self) -> int: - return self._width if isinstance(self._width, int) else self._width * self._window_width - - @width.setter - def width(self, width: int | Percentage) -> None: - self._width = width - - @property - def height(self) -> int: - return self._height if isinstance(self._height, int) else self._height * self._window_height - - @height.setter - def height(self, height: int | Percentage) -> None: - self._height = height - - @property - def bbox(self) -> BBox: - return self.x, self.y, self.x + self.width, self.y + self.height - - def on_resize(self, window: "Window", scene: "Scene", width: int, height: int): - self._window_width = width - self._window_height = height diff --git a/source/gui/widget/base/BaseAdaptativeWidget.py b/source/gui/widget/base/BaseAdaptativeWidget.py new file mode 100644 index 0000000..fc77a16 --- /dev/null +++ b/source/gui/widget/base/BaseAdaptativeWidget.py @@ -0,0 +1,44 @@ +from typing import Optional + +from source.gui.widget.base import BaseBoxWidget +from source.type import Percentage + + +class BaseAdaptativeWidget(BaseBoxWidget): + def __init__(self, x: int | Percentage, y: int | Percentage, width: int | Percentage, height: int | Percentage): + super().__init__(x, y, width, height) + + self._window_width: Optional[int] = None + self._window_height: Optional[int] = None + + # getter / setter + + def on_window_added(self, window: "Window", scene: "BaseScene"): + self._window_width = window.width + self._window_height = window.height + + @property + def x(self) -> int: + return self._x if isinstance(self._x, int) else self._x * self._window_width + + @property + def y(self) -> int: + return self._y if isinstance(self._y, int) else self._y * self._window_height + + @property + def width(self) -> int: + return self._width if isinstance(self._width, int) else self._width * self._window_width + + @property + def height(self) -> int: + return self._height if isinstance(self._height, int) else self._height * self._window_height + + # event + + def update_size(self): pass + + def on_resize(self, window: "Window", scene: "BaseScene", width: int, height: int): + self._window_width = width + self._window_height = height + + self.update_size() diff --git a/source/gui/widget/base/BaseBoxWidget.py b/source/gui/widget/base/BaseBoxWidget.py new file mode 100644 index 0000000..7441630 --- /dev/null +++ b/source/gui/widget/base/BaseBoxWidget.py @@ -0,0 +1,48 @@ +from source.gui.widget.base import BaseWidget +from source.type import BBox + + +class BaseBoxWidget(BaseWidget): + def __init__(self, x: int, y: int, width: int, height: int): + self._x = x + self._y = y + self._width = width + self._height = height + + # getter and setter, allow subclass to react when one of these value is changed + + @property + def x(self): + return self._x + + @x.setter + def x(self, x: int) -> None: + self._x = x + + @property + def y(self): + return self._y + + @y.setter + def y(self, y: int) -> None: + self._y = y + + @property + def width(self): + return self._width + + @width.setter + def width(self, width: int) -> None: + self._width = width + + @property + def height(self): + return self._height + + @height.setter + def height(self, height: int) -> None: + self._height = height + + @property + def bbox(self) -> BBox: + return self.x, self.y, self.x + self.width, self.y + self.height diff --git a/source/gui/widget/base/BaseWidget.py b/source/gui/widget/base/BaseWidget.py new file mode 100644 index 0000000..48a9c3f --- /dev/null +++ b/source/gui/widget/base/BaseWidget.py @@ -0,0 +1,50 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from source.gui.scene.base import BaseScene + from source.gui.window import Window + + +class BaseWidget: + """ + This class represent a widget that can be attached to a Scene. + + It can be used to create a button, a label, ... + """ + + # widget event + + def on_scene_added(self, scene: "BaseScene"): pass + def on_scene_removed(self, scene: "BaseScene"): pass + + # scene event + + def on_window_added(self, window: "Window", scene: "BaseScene"): pass + def on_window_removed(self, window: "Window", scene: "BaseScene"): pass + + # global event + + def on_draw(self, window: "Window", scene: "BaseScene"): pass + def on_resize(self, window: "Window", scene: "BaseScene", width: int, height: int): pass + def on_hide(self, window: "Window", scene: "BaseScene"): pass + def on_show(self, window: "Window", scene: "BaseScene"): pass + def on_close(self, window: "Window", scene: "BaseScene"): pass + def on_expose(self, window: "Window", scene: "BaseScene"): pass + def on_activate(self, window: "Window", scene: "BaseScene"): pass + def on_deactivate(self, window: "Window", scene: "BaseScene"): pass + def on_text(self, window: "Window", scene: "BaseScene", char: str): pass + def on_move(self, window: "Window", scene: "BaseScene", x: int, y: int): pass + def on_context_lost(self, window: "Window", scene: "BaseScene"): pass + def on_context_state_lost(self, window: "Window", scene: "BaseScene"): pass + def on_key_press(self, window: "Window", scene: "BaseScene", symbol: int, modifiers: int): pass + def on_key_release(self, window: "Window", scene: "BaseScene", symbol: int, modifiers: int): pass + def on_key_held(self, window: "Window", scene: "BaseScene", dt: float, symbol: int, modifiers: int): pass + def on_mouse_enter(self, window: "Window", scene: "BaseScene", x: int, y: int): pass + def on_mouse_leave(self, window: "Window", scene: "BaseScene", x: int, y: int): pass + def on_text_motion(self, window: "Window", scene: "BaseScene", motion: int): pass + def on_text_motion_select(self, window: "Window", scene: "BaseScene", motion: int): pass + def on_mouse_motion(self, window: "Window", scene: "BaseScene", x: int, y: int, dx: int, dy: int): pass + def on_mouse_press(self, window: "Window", scene: "BaseScene", x: int, y: int, button: int, modifiers: int): pass + def on_mouse_release(self, window: "Window", scene: "BaseScene", x: int, y: int, button: int, modifiers: int): pass + def on_mouse_drag(self, window: "Window", scene: "BaseScene", x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int): pass + def on_mouse_scroll(self, window: "Window", scene: "BaseScene", x: int, y: int, scroll_x: float, scroll_y: float): pass diff --git a/source/gui/widget/base/Widget.py b/source/gui/widget/base/Widget.py deleted file mode 100644 index 8a6f489..0000000 --- a/source/gui/widget/base/Widget.py +++ /dev/null @@ -1,50 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from source.gui.scene.base import Scene - from source.gui.window import Window - - -class Widget: - """ - This class represent a widget that can be attached to a Scene. - - It can be used to create a button, a label, ... - """ - - # widget event - - def on_scene_added(self, scene: "Scene"): pass - def on_scene_removed(self, scene: "Scene"): pass - - # scene event - - def on_window_added(self, window: "Window", scene: "Scene"): pass - def on_window_removed(self, window: "Window", scene: "Scene"): pass - - # global event - - def on_draw(self, window: "Window", scene: "Scene"): pass - def on_resize(self, window: "Window", scene: "Scene", width: int, height: int): pass - def on_hide(self, window: "Window", scene: "Scene"): pass - def on_show(self, window: "Window", scene: "Scene"): pass - def on_close(self, window: "Window", scene: "Scene"): pass - def on_expose(self, window: "Window", scene: "Scene"): pass - def on_activate(self, window: "Window", scene: "Scene"): pass - def on_deactivate(self, window: "Window", scene: "Scene"): pass - def on_text(self, window: "Window", scene: "Scene", char: str): pass - def on_move(self, window: "Window", scene: "Scene", x: int, y: int): pass - def on_context_lost(self, window: "Window", scene: "Scene"): pass - def on_context_state_lost(self, window: "Window", scene: "Scene"): pass - def on_key_press(self, window: "Window", scene: "Scene", symbol: int, modifiers: int): pass - def on_key_release(self, window: "Window", scene: "Scene", symbol: int, modifiers: int): pass - def on_key_held(self, window: "Window", scene: "Scene", dt: float, symbol: int, modifiers: int): pass - def on_mouse_enter(self, window: "Window", scene: "Scene", x: int, y: int): pass - def on_mouse_leave(self, window: "Window", scene: "Scene", x: int, y: int): pass - def on_text_motion(self, window: "Window", scene: "Scene", motion: int): pass - def on_text_motion_select(self, window: "Window", scene: "Scene", motion: int): pass - def on_mouse_motion(self, window: "Window", scene: "Scene", x: int, y: int, dx: int, dy: int): pass - def on_mouse_press(self, window: "Window", scene: "Scene", x: int, y: int, button: int, modifiers: int): pass - def on_mouse_release(self, window: "Window", scene: "Scene", x: int, y: int, button: int, modifiers: int): pass - def on_mouse_drag(self, window: "Window", scene: "Scene", x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int): pass - def on_mouse_scroll(self, window: "Window", scene: "Scene", x: int, y: int, scroll_x: float, scroll_y: float): pass diff --git a/source/gui/widget/base/__init__.py b/source/gui/widget/base/__init__.py index 7503b5c..e3b8a26 100644 --- a/source/gui/widget/base/__init__.py +++ b/source/gui/widget/base/__init__.py @@ -1,2 +1,3 @@ -from .Widget import Widget -from .AdaptativeWidget import AdaptativeWidget +from .BaseWidget import BaseWidget +from .BaseBoxWidget import BaseBoxWidget +from .BaseAdaptativeWidget import BaseAdaptativeWidget diff --git a/source/gui/window/Window.py b/source/gui/window/Window.py index 62f4e2c..f8a134e 100644 --- a/source/gui/window/Window.py +++ b/source/gui/window/Window.py @@ -1,76 +1,47 @@ -from typing import Optional, Callable, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable import pyglet.window if TYPE_CHECKING: - from source.gui.scene.base import Scene + from source.gui.scene import BaseScene -class Window(pyglet.window.Window): # NOQA - pycharm think pyglet window is abstract +class Window(pyglet.window.Window): # NOQA """ - This class represent a Window based on the pyglet Window object. - - Allow to use a "Scene" system to create very different interface like - a main menu, options menu, ... that can overlay each other without - putting everything in the window code. + Same as the original pyglet class, but allow to set a scene. """ - def __init__(self, scenes: Optional[list["Scene"]] = None, *args, **kwargs): + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._scenes: list["Scene"] = [] - if scenes is not None: self.add_scene(*scenes) - # add a keys handler to the window - self.keys = pyglet.window.key.KeyStateHandler() - self.push_handlers(self.keys) + # scene + self._scenes = [] # a dictionary linking a key pressed to the corresponding event function self._on_key_held_events: dict[(int, int), Callable] = {} - # scene methods + # keys event handler + self.keys_handler = pyglet.window.key.KeyStateHandler() + self.push_handlers(self.keys_handler) - def set_scene(self, *scenes: "Scene") -> None: - """ - Set the scene(s) of the window - :param scenes: the scene(s) to set - """ - self.clear_scene() - for scene in scenes: self.add_scene(scene) + # scene system - def clear_scene(self) -> None: - """ - Clear all the scenes of the window - """ - for scene in self._scenes: scene.on_window_removed(self) - self._scenes.clear() + def set_scene(self, *scenes: "BaseScene"): + self.clear() + self.add_scene(*scenes) - def add_scene(self, *scenes: "Scene", priority: int = 0) -> None: - """ - Add a scene to the window - :param scenes: the scene to add - :param priority: the priority level of the scene. The higher, the more the scene will be drawn on top - """ + def add_scene(self, *scenes: "BaseScene", priority: int = 0): for scene in scenes: self._scenes.insert(priority, scene) scene.on_window_added(self) - def remove_scene(self, *scenes: "Scene") -> None: - """ - Remove a scene from the window - :param scenes: the scene to remove - """ + def remove_scene(self, *scenes: "BaseScene"): for scene in scenes: scene.on_window_removed(self) self._scenes.remove(scene) - def get_scenes(self): - """ - Get the list of the scenes - :return: the list of all the scenes currently used - """ - return self._scenes.copy() - - # window event methods + def clear_scene(self): + self.remove_scene(*self._scenes) # NOTE: it is too difficult to refactor all the event because : # - There is no event "on_any_event" or equivalent diff --git a/source/gui/window/__init__.py b/source/gui/window/__init__.py index 2391d96..262037f 100644 --- a/source/gui/window/__init__.py +++ b/source/gui/window/__init__.py @@ -1,2 +1 @@ from .Window import Window - diff --git a/source/reseau_test/client.py b/source/reseau_test/client.py index 7f039e9..71945aa 100644 --- a/source/reseau_test/client.py +++ b/source/reseau_test/client.py @@ -8,7 +8,7 @@ from source.core.enums import Orientation, BombState from source.core.error import InvalidBoatPosition, InvalidBombPosition, PositionAlreadyShot with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect(("127.0.0.1", 7878)) + s.connect(("127.0.0.1", 52321)) print(f"[Client] Connecté avec {s}") diff --git a/source/reseau_test/server.py b/source/reseau_test/server.py index d3f266f..d91ea33 100644 --- a/source/reseau_test/server.py +++ b/source/reseau_test/server.py @@ -8,7 +8,8 @@ from source.core.enums import Orientation, BombState from source.core.error import InvalidBoatPosition, InvalidBombPosition, PositionAlreadyShot with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("127.0.0.1", 7878)) + host = socket.gethostname() + s.bind((host, 52321)) s.listen() conn, addr = s.accept() diff --git a/source/type.py b/source/type.py index 71a8148..f169c90 100644 --- a/source/type.py +++ b/source/type.py @@ -1,3 +1,3 @@ Point2D = tuple[int, int] BBox = tuple[int, int, int, int] -Percentage = float # a percentage is a value between 0 and 1 +Percentage = float