diff --git a/assets/image/scroller/background.png b/assets/image/scroller/background.png new file mode 100644 index 0000000..aaf01ca Binary files /dev/null and b/assets/image/scroller/background.png differ diff --git a/assets/image/scroller/cursor.png b/assets/image/scroller/cursor.png new file mode 100644 index 0000000..e88fe4e Binary files /dev/null and b/assets/image/scroller/cursor.png differ diff --git a/source/gui/scene/MainMenu.py b/source/gui/scene/MainMenu.py index 9ec521e..ebd3950 100644 --- a/source/gui/scene/MainMenu.py +++ b/source/gui/scene/MainMenu.py @@ -4,7 +4,8 @@ import pyglet from source.gui.scene import RoomJoin, RoomCreate, Settings from source.gui.scene.abc import Scene -from source.gui.widget import Image, Text, Button, FPSDisplay +from source.gui.widget import Image, Text, Button +from source.gui.widget.debug import FPSDisplay if TYPE_CHECKING: from source.gui.window import Window @@ -45,7 +46,7 @@ class MainMenu(Scene): texture_click=texture_button_click ) - self.game_create.on_release = lambda button, modifiers: self.window.set_scene(RoomCreate) + self.game_create.on_release = lambda *_: self.window.set_scene(RoomCreate) self.game_join = self.add_widget( Button, @@ -60,7 +61,7 @@ class MainMenu(Scene): texture_click=texture_button_click ) - self.game_join.on_release = lambda button, modifiers: self.window.set_scene(RoomJoin) + self.game_join.on_release = lambda *_: self.window.set_scene(RoomJoin) self.settings = self.add_widget( Button, @@ -75,7 +76,7 @@ class MainMenu(Scene): texture_click=texture_button_click ) - self.settings.on_release = lambda button, modifiers: self.window.set_scene(Settings) + self.settings.on_release = lambda *_: self.window.set_scene(Settings) self.fps_display = self.add_widget(FPSDisplay, color=(255, 255, 255, 180)) diff --git a/source/gui/scene/RoomCreate.py b/source/gui/scene/RoomCreate.py index 3fee1d7..14a3b65 100644 --- a/source/gui/scene/RoomCreate.py +++ b/source/gui/scene/RoomCreate.py @@ -35,7 +35,7 @@ class RoomCreate(Scene): ) from source.gui.scene import MainMenu - self.back.on_release = lambda button, modifiers: self.window.set_scene(MainMenu) + self.back.on_release = lambda *_: self.window.set_scene(MainMenu) self.label_ip = self.add_widget( Text, diff --git a/source/gui/scene/RoomJoin.py b/source/gui/scene/RoomJoin.py index fc6e6cf..0c7cf9d 100644 --- a/source/gui/scene/RoomJoin.py +++ b/source/gui/scene/RoomJoin.py @@ -33,7 +33,7 @@ class RoomJoin(Scene): ) from source.gui.scene import MainMenu - self.back.on_release = lambda button, modifiers: self.window.set_scene(MainMenu) + self.back.on_release = lambda *_: self.window.set_scene(MainMenu) self.entry_ip = self.add_widget( Input, diff --git a/source/gui/scene/Settings.py b/source/gui/scene/Settings.py index f1f4f94..8964763 100644 --- a/source/gui/scene/Settings.py +++ b/source/gui/scene/Settings.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING import pyglet from source.gui.scene.abc import Scene -from source.gui.widget import Checkbox +from source.gui.widget import Checkbox, Scroller, Button if TYPE_CHECKING: from source.gui.window import Window @@ -16,6 +16,27 @@ class Settings(Scene): texture_tick_disabled = pyglet.image.load("./assets/image/checkbox/disabled.png") texture_tick_enabled = pyglet.image.load("./assets/image/checkbox/enabled.png") + texture_scroller_background = pyglet.image.load("./assets/image/scroller/background.png") + texture_scroller_cursor = pyglet.image.load("./assets/image/scroller/cursor.png") + + texture_button_normal = pyglet.image.load("./assets/image/button/normal.png") + texture_button_hover = pyglet.image.load("./assets/image/button/hovering.png") + texture_button_click = pyglet.image.load("./assets/image/button/clicking.png") + + self.back = self.add_widget( + Button, + x=20, y=20, width=0.2, height=0.1, + + label_text="Retour", + + texture_normal=texture_button_normal, + texture_hover=texture_button_hover, + texture_click=texture_button_click + ) + + from source.gui.scene import MainMenu + self.back.on_release = lambda *_: self.window.set_scene(MainMenu) + self.checkbox = self.add_widget( Checkbox, @@ -25,5 +46,18 @@ class Settings(Scene): texture_enabled=texture_tick_enabled, ) + self.scroller = self.add_widget( + Scroller, + + x=0.3, y=0.2, width=0.3, height=0.1, + + texture_background=texture_scroller_background, + texture_cursor=texture_scroller_cursor, + + text_transform=lambda value: round(value, 2), + ) + def on_draw(self): self.checkbox.draw() + self.scroller.draw() + self.back.draw() diff --git a/source/gui/widget/Checkbox.py b/source/gui/widget/Checkbox.py index 3b71e70..b3de67d 100644 --- a/source/gui/widget/Checkbox.py +++ b/source/gui/widget/Checkbox.py @@ -65,7 +65,7 @@ class Checkbox(BoxWidget): def on_resize(self, width: int, height: int): self._refresh_size() - def on_release(self, button: int, modifiers: int): + def on_release(self, rel_x: int, rel_y: int, button: int, modifiers: int): # lorsque le bouton est enclenché, inverse son état self.state = not self.state diff --git a/source/gui/widget/Scroller.py b/source/gui/widget/Scroller.py new file mode 100644 index 0000000..12cdfde --- /dev/null +++ b/source/gui/widget/Scroller.py @@ -0,0 +1,121 @@ +from typing import TYPE_CHECKING, Callable, Any + +import pyglet.image + +from source.gui.sprite import Sprite +from source.gui.widget.abc import BoxWidget +from source.type import Distance, Percentage +from source.utils import dict_prefix + +if TYPE_CHECKING: + from source.gui.scene.abc import Scene + + +class Scroller(BoxWidget): + def __init__(self, scene: "Scene", + + texture_background: pyglet.image.AbstractImage, + texture_cursor: pyglet.image.AbstractImage, + + x: Distance = 0, + y: Distance = 0, + width: Distance = None, + height: Distance = None, + + from_: float = 0, + value: float = 0.5, + to: float = 1, + + cursor_width: Percentage = 0.1, + text_transform: Callable[[float], Any] = lambda value: value, + + **kwargs): + super().__init__(scene, x, y, width, height) + + self.cursor_width = cursor_width + self.text_transform = text_transform + + self.background = Sprite( + img=texture_background, + **dict_prefix("background_", kwargs) + ) + self.cursor = Sprite( + img=texture_cursor, + **dict_prefix("cursor_", kwargs) + ) + self.label = pyglet.text.Label( + anchor_x="center", anchor_y="center", + **dict_prefix("label_", kwargs) + ) + + self._from = from_ + self._to = to + self.value = value + + # refresh + + def _refresh(self): + # background + self.background.x, self.background.y = self.x, self.y + self.background.width, self.background.height = self.width, self.height + + # cursor + self.cursor.width = self.width * self.cursor_width + self.cursor.height = self.height + self.cursor.y = self.y + self.cursor.x = ( + # the base offset + self.x + # position the cursor relatively to the start and the end of the range + + (self.value - self.from_) / (self.to - self.from_) * self.background.width + # center the cursor with its own width + - (self.cursor.width / 2) + ) + + # label + self.label.x = self.x + (self.width / 2) + self.label.y = self.y + (self.height / 2) + self.label.text = str(self.text_transform(self.value)) + + # property + + def on_pressed(self, rel_x: int, rel_y: int, button: int, modifiers: int): + self.value = rel_x / self.width + + @property + def value(self): + return self._value + + @value.setter + def value(self, value: float): + if not self.from_ <= value <= self.to: raise ValueError(f"The value is not in range") + self._value = value + self._refresh() + + @property + def from_(self): + return self._from + + @from_.setter + def from_(self, from_: float): + self._from = from_ + self._refresh() + + @property + def to(self): + return self._to + + @to.setter + def to(self, to: float): + self._to = to + self._refresh() + + # event + + def on_resize(self, width: int, height: int): + self._refresh() + + def draw(self): + self.background.draw() + self.cursor.draw() + self.label.draw() diff --git a/source/gui/widget/__init__.py b/source/gui/widget/__init__.py index 86070be..096854d 100644 --- a/source/gui/widget/__init__.py +++ b/source/gui/widget/__init__.py @@ -1,6 +1,6 @@ from .Text import Text -from .FPSDisplay import FPSDisplay from .Button import Button from .Input import Input from .Image import Image from .Checkbox import Checkbox +from .Scroller import Scroller diff --git a/source/gui/widget/abc/BoxWidget.py b/source/gui/widget/abc/BoxWidget.py index 68ffcd5..ddca25c 100644 --- a/source/gui/widget/abc/BoxWidget.py +++ b/source/gui/widget/abc/BoxWidget.py @@ -157,7 +157,7 @@ class BoxWidget(Widget, ABC): self.activated = True # if the click is inside the bbox, enable the activated state self.clicking = True # the widget is now clicked - self.on_pressed(button, modifiers) + self.on_pressed(x - self.x, y - self.y, button, modifiers) def on_mouse_release(self, x: int, y: int, button: int, modifiers: int): old_click: bool = self._clicking @@ -166,14 +166,14 @@ class BoxWidget(Widget, ABC): if not in_bbox((x, y), self.bbox): return # if this button was the one hovered when the click was pressed - if old_click: self.on_release(button, modifiers) + if old_click: self.on_release(x - self.x, y - self.y, button, modifiers) - def on_pressed(self, button: int, modifiers: int): + def on_pressed(self, rel_x: int, rel_y: int, button: int, modifiers: int): """ This event is called when the bbox is pressed """ - def on_release(self, button: int, modifiers: int): + def on_release(self, rel_x: int, rel_y: int, button: int, modifiers: int): """ This event is called when the bbox is released """ \ No newline at end of file diff --git a/source/gui/widget/FPSDisplay.py b/source/gui/widget/debug/FPSDisplay.py similarity index 100% rename from source/gui/widget/FPSDisplay.py rename to source/gui/widget/debug/FPSDisplay.py diff --git a/source/gui/widget/debug/__init__.py b/source/gui/widget/debug/__init__.py new file mode 100644 index 0000000..292fa2b --- /dev/null +++ b/source/gui/widget/debug/__init__.py @@ -0,0 +1 @@ +from .FPSDisplay import FPSDisplay