recoded the structure of the gui

This commit is contained in:
Faraphel 2023-01-14 00:11:35 +01:00
parent e9c39ce2e3
commit 7cc837b68e
28 changed files with 396 additions and 439 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

View file

@ -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()

View file

@ -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)

View file

@ -1 +0,0 @@
from source.gui.scene.test.HelloWorldScene import HelloWorldScene

View file

@ -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)

View file

@ -1 +1 @@
from .Scene import Scene
from .BaseScene import BaseScene

View file

@ -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()

View file

@ -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()

View file

@ -1 +1 @@
from .FPSCounterScene import FPSCounterScene
from .FPSScene import FPSScene

View file

@ -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
))

View file

@ -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()

View file

@ -1,2 +1 @@
from .HelloWorldScene import HelloWorldScene
from .ButtonScene import ButtonScene

View file

@ -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

View file

@ -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

View file

@ -1 +0,0 @@
from .Button import Button

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,2 +1,3 @@
from .Widget import Widget
from .AdaptativeWidget import AdaptativeWidget
from .BaseWidget import BaseWidget
from .BaseBoxWidget import BaseBoxWidget
from .BaseAdaptativeWidget import BaseAdaptativeWidget

View file

@ -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

View file

@ -1,2 +1 @@
from .Window import Window

View file

@ -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}")

View file

@ -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()

View file

@ -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