added a Style system

This commit is contained in:
Faraphel 2023-02-19 12:02:05 +01:00
parent 1a36cd2372
commit 75c1d4b6e8
26 changed files with 202 additions and 156 deletions

10
NOTE.md
View file

@ -1,3 +1,9 @@
A faire :
- Optimiser les textures dans un dictionnaires
- Optimiser les textures similaire dans un atlas
- Faire une scène incluant par défaut les boutons "Retour"
- Utiliser des batchs
- Ajouter un moyen d'annuler les évenements de se propager aux widgets en dessous
- Police d'écriture
Bug :
- Appuyez sur "Créer une salle" va lancer un thread, mais il n'est pas fermé s'il l'on revient dans
le menu principal

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 KiB

View file

@ -3,6 +3,7 @@ import pyglet
from source.gui.scene import MainMenu
from source.gui.window import GameWindow
# Create a new window
window = GameWindow(resizable=True, vsync=True, caption="Bataille Navale")
window.add_scene(MainMenu)

View file

@ -1,10 +1,9 @@
from typing import TYPE_CHECKING
import pyglet
from source.gui.scene.abc import Scene
from source.gui import widget
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
@ -14,24 +13,12 @@ class Game(Scene):
def __init__(self, window: "Window", **kwargs):
super().__init__(window, **kwargs)
texture_input_normal = pyglet.image.load("assets/image/input/normal.png")
texture_input_active = pyglet.image.load("./assets/image/input/active.png")
texture_input_error = pyglet.image.load("./assets/image/input/error.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")
texture_game_background = pyglet.image.load("./assets/image/background/game.png")
texture_grid_background = pyglet.image.load("./assets/image/grid/background.png")
self.background = self.add_widget(
widget.Image,
x=0, y=0, width=1.0, height=1.0,
image=texture_game_background,
image=texture.Background.game,
)
self.grid_ally = self.add_widget(
@ -39,7 +26,7 @@ class Game(Scene):
x=75, y=0.25, width=0.35, height=0.5,
texture_background=texture_grid_background,
style=texture.Grid.Style1,
rows=8, columns=8,
)
@ -48,7 +35,7 @@ class Game(Scene):
x=lambda widget: widget.scene.window.width - 75 - widget.width, y=0.25, width=0.35, height=0.5,
texture_background=texture_grid_background,
style=texture.Grid.Style1,
rows=8, columns=8,
)
@ -107,9 +94,7 @@ class Game(Scene):
x=10, y=10, width=0.5, height=50,
texture_normal=texture_input_normal,
texture_active=texture_input_active,
texture_error=texture_input_error,
style=texture.Button.Style1
)
self.button_save = self.add_widget(
@ -119,9 +104,7 @@ class Game(Scene):
label_text="Sauvegarder",
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.button_quit = self.add_widget(
@ -131,9 +114,7 @@ class Game(Scene):
label_text="Quitter",
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.board_ally = core.Board(rows=8, columns=8)

View file

@ -1,9 +1,8 @@
from typing import TYPE_CHECKING
import pyglet
from source.gui.scene.abc import Scene
from source.gui import widget, scene
from source.gui import widget, scene, texture
from source.utils.dict import dict_add_prefix
if TYPE_CHECKING:
from source.gui.window import Window
@ -13,15 +12,10 @@ class MainMenu(Scene):
def __init__(self, window: "Window", *args, **kwargs):
super().__init__(window, *args, **kwargs)
texture_background = pyglet.image.load("./assets/image/background/main.jpeg")
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.background = self.add_widget(
widget.Image,
x=0.0, y=0.0, width=1.0, height=1.0,
image=texture_background
image=texture.Background.main
)
self.title = self.add_widget(
@ -39,9 +33,7 @@ class MainMenu(Scene):
label_text="Créer une salle",
label_font_size=20,
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.game_create.add_listener("on_click_release", lambda *_: self.window.set_scene(scene.RoomCreate))
@ -54,9 +46,7 @@ class MainMenu(Scene):
label_text="Rejoindre une salle",
label_font_size=20,
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.game_join.add_listener("on_click_release", lambda *_: self.window.set_scene(scene.RoomJoin))
@ -69,9 +59,7 @@ class MainMenu(Scene):
label_text="Paramètres",
label_font_size=20,
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.settings.add_listener("on_click_release", lambda *_: self.window.set_scene(scene.Settings))

View file

@ -5,7 +5,8 @@ import requests
from source import network
from source.gui.scene.abc import Scene
from source.gui import widget
from source.gui import widget, texture
from source.utils.dict import dict_add_prefix
if TYPE_CHECKING:
from source.gui.window import Window
@ -20,19 +21,13 @@ class RoomCreate(Scene):
ip_address: str = r.content.decode('utf8')
port: int = 52321
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(
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
style=texture.Button.Style1
)
from source.gui.scene import MainMenu

View file

@ -4,7 +4,8 @@ import pyglet
from source import network
from source.gui.scene.abc import Scene
from source.gui import widget
from source.gui import widget, texture
from source.utils.dict import dict_add_prefix
if TYPE_CHECKING:
from source.gui.window import Window
@ -14,23 +15,13 @@ class RoomJoin(Scene):
def __init__(self, window: "Window", *args, **kwargs):
super().__init__(window, *args, **kwargs)
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")
texture_input_normal = pyglet.image.load("assets/image/input/normal.png")
texture_input_active = pyglet.image.load("./assets/image/input/active.png")
texture_input_error = pyglet.image.load("./assets/image/input/error.png")
self.back = self.add_widget(
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
style=texture.Button.Style1
)
from source.gui.scene import MainMenu
@ -42,9 +33,7 @@ class RoomJoin(Scene):
regex=r"\d{1,3}(\.\d{1,3}){3}",
texture_normal=texture_input_normal,
texture_active=texture_input_active,
texture_error=texture_input_error
style=texture.Input.Style1
)
self.entry_port = self.add_widget(
@ -53,9 +42,7 @@ class RoomJoin(Scene):
regex=r"\d{0,5}",
texture_normal=texture_input_normal,
texture_active=texture_input_active,
texture_error=texture_input_error
style=texture.Input.Style1
)
self.connect = self.add_widget(
@ -64,9 +51,7 @@ class RoomJoin(Scene):
label_text="Se connecter",
texture_normal=texture_button_normal,
texture_hover=texture_button_hover,
texture_click=texture_button_click
style=texture.Button.Style1
)
self.connect.add_listener("on_click_release", lambda *_: network.Client(

View file

@ -1,9 +1,8 @@
from typing import TYPE_CHECKING
import pyglet
from source.gui.scene.abc import Scene
from source.gui import widget
from source.gui import widget, texture
from source.utils.dict import dict_add_prefix
if TYPE_CHECKING:
from source.gui.window import Window
@ -13,27 +12,13 @@ class Settings(Scene):
def __init__(self, window: "Window", *args, **kwargs):
super().__init__(window, *args, **kwargs)
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")
texture_grid_background = pyglet.image.load("./assets/image/grid/background.png")
self.back = self.add_widget(
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
style=texture.Button.Style1
)
from source.gui.scene import MainMenu
@ -44,8 +29,7 @@ class Settings(Scene):
x=0.45, y=0.45, width=0.1, height=0.1,
texture_disabled=texture_tick_disabled,
texture_enabled=texture_tick_enabled,
style=texture.Checkbox.Style1
)
self.scroller = self.add_widget(
@ -53,8 +37,7 @@ class Settings(Scene):
x=0.3, y=0.2, width=0.3, height=0.1,
texture_background=texture_scroller_background,
texture_cursor=texture_scroller_cursor,
style=texture.Scroller.Style1,
text_transform=lambda value: round(value, 2),
)

View file

@ -0,0 +1,10 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "background/"
class Background(Style):
main = _image_path + "main.png"
game = _image_path + "game.png"

View file

@ -0,0 +1,11 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "button/"
class Button:
class Style1(Style):
normal = _image_path + "normal.png"
click = _image_path + "clicking.png"
hover = _image_path + "hovering.png"

View file

@ -0,0 +1,10 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "checkbox/"
class Checkbox:
class Style1(Style):
disabled = _image_path + "disabled.png"
enabled = _image_path + "enabled.png"

View file

@ -0,0 +1,9 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "grid/"
class Grid:
class Style1(Style):
background = _image_path + "background.png"

View file

@ -0,0 +1,11 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "input/"
class Input:
class Style1(Style):
normal = _image_path + "normal.png"
active = _image_path + "active.png"
error = _image_path + "error.png"

View file

@ -0,0 +1,10 @@
from . import _image_path
from .abc import Style
_image_path = _image_path + "scroller/"
class Scroller:
class Style1(Style):
background = _image_path + "background.png"
cursor = _image_path + "cursor.png"

View file

@ -0,0 +1,9 @@
_image_path: str = "./assets/image/"
from .Background import Background # NOQA: E402
from .Button import Button # NOQA: E402
from .Checkbox import Checkbox # NOQA: E402
from .Grid import Grid # NOQA: E402
from .Input import Input # NOQA: E402
from .Scroller import Scroller # NOQA: E402

View file

@ -0,0 +1,22 @@
from abc import ABC
from typing import Optional, Any
import pyglet
class Style(ABC):
def __init_subclass__(cls, **kwargs):
atlas = pyglet.image.atlas.TextureAtlas()
for name, path in cls.__dict__.items():
if name.startswith("_"): continue
setattr(cls, name, atlas.add(pyglet.image.load(path)))
setattr(cls, "_atlas", atlas)
@classmethod
def get(cls, item: str, default: Any = None) -> Optional[pyglet.image.AbstractImage]:
return getattr(cls, item, default)
def __class_getitem__(cls, item: str) -> Optional[pyglet.image.AbstractImage]:
return cls.get(item)

View file

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

View file

@ -1,11 +1,12 @@
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, Type
import pyglet
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_prefix
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
@ -19,32 +20,27 @@ class Button(BoxWidget):
def __init__(self, scene: "Scene",
texture_normal: pyglet.image.AbstractImage,
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
width: Distance = None,
height: Distance = None,
texture_hover: pyglet.image.AbstractImage = None,
texture_click: pyglet.image.AbstractImage = None,
**kwargs):
super().__init__(scene, x, y, width, height)
self._texture_normal: pyglet.image.AbstractImage = texture_normal
self._texture_hover: Optional[pyglet.image.AbstractImage] = texture_hover
self._texture_click: Optional[pyglet.image.AbstractImage] = texture_click
self.style = style
self.background = Sprite(
img=self._texture_normal,
**dict_prefix("background_", kwargs)
img=self.style.get("normal"),
**dict_filter_prefix("background_", kwargs)
)
self.label = pyglet.text.Label(
width=None, height=None,
anchor_x="center", anchor_y="center",
**dict_prefix("label_", kwargs)
**dict_filter_prefix("label_", kwargs)
)
self.add_listener("on_hover_change", lambda *_: self._refresh_background())
@ -64,9 +60,9 @@ class Button(BoxWidget):
"""
return (
self._texture_click if self.clicking and self._texture_click is not None else
self._texture_hover if self.hovering and self._texture_hover is not None else
self._texture_normal
texture if self.clicking and (texture := self.style.get("click")) is not None else # NOQA
texture if self.hovering and (texture := self.style.get("hover")) is not None else
self.style.get("normal")
)
# refresh

View file

@ -1,8 +1,9 @@
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Type
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
@ -14,8 +15,7 @@ if TYPE_CHECKING:
class Checkbox(BoxWidget):
def __init__(self, scene: "Scene",
texture_disabled: pyglet.image.AbstractImage,
texture_enabled: pyglet.image.AbstractImage,
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
@ -27,10 +27,9 @@ class Checkbox(BoxWidget):
**kwargs):
super().__init__(scene, x, y, width, height)
self._texture_disabled = texture_disabled
self._texture_enabled = texture_enabled
self.style = style
self.tick = Sprite(img=self._texture_disabled, **kwargs)
self.tick = Sprite(img=self.style.get("disabled"), **kwargs)
self.state = state
@ -42,7 +41,7 @@ class Checkbox(BoxWidget):
@property
def tick_texture(self):
return self._texture_enabled if self.state else self._texture_disabled
return self.style.get("enabled" if self.state else "disabled")
def _refresh_tick(self):
self.tick.image = self.tick_texture

View file

@ -1,11 +1,12 @@
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Type
import pyglet.shapes
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_prefix
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
@ -17,7 +18,7 @@ class GameGrid(BoxWidget):
rows: int,
columns: int,
texture_background: pyglet.image.AbstractImage,
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
@ -30,15 +31,17 @@ class GameGrid(BoxWidget):
self._rows = rows
self._columns = columns
self.style = style
self.background = Sprite(
img=texture_background,
**dict_prefix("background_", kwargs)
img=style.get("background"),
**dict_filter_prefix("background_", kwargs)
)
self.lines: list[pyglet.shapes.Line] = [
pyglet.shapes.Line(
0, 0, 0, 0,
**dict_prefix("line_", kwargs)
**dict_filter_prefix("line_", kwargs)
)
for _ in range((self._columns - 1) + (self._rows - 1))
]
@ -46,7 +49,7 @@ class GameGrid(BoxWidget):
self.cursor = pyglet.shapes.Rectangle(
0, 0, 0, 0,
color=(0, 0, 0, 100),
**dict_prefix("cursor_", kwargs)
**dict_filter_prefix("cursor_", kwargs)
)
self.add_listener("on_hover_leave", lambda *_: self.hide_cursor())

View file

@ -1,12 +1,13 @@
import re
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, Type
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_prefix
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
@ -15,9 +16,7 @@ if TYPE_CHECKING:
class Input(BoxWidget):
def __init__(self, scene: "Scene",
texture_normal: pyglet.image.AbstractImage,
texture_active: pyglet.image.AbstractImage = None,
texture_error: pyglet.image.AbstractImage = None,
style: Type[Style],
regex: Optional[str | re.Pattern] = None,
@ -29,22 +28,21 @@ class Input(BoxWidget):
**kwargs):
super().__init__(scene, x, y, width, height)
self._texture_normal: pyglet.image.AbstractImage = texture_normal
self._texture_active: Optional[pyglet.image.AbstractImage] = texture_active
self._texture_error: Optional[pyglet.image.AbstractImage] = texture_error
self.style = style
self._invalid = False
self.regex = re.compile(regex) if isinstance(regex, str) else regex
self.background = Sprite(
img=self._texture_normal,
**dict_prefix("background_", kwargs)
img=self.style.get("normal"),
**dict_filter_prefix("background_", kwargs)
)
self.label = pyglet.text.Label(
width=None, height=None,
anchor_x="center", anchor_y="center",
**dict_prefix("label_", kwargs)
**dict_filter_prefix("label_", kwargs)
)
self.add_listener("on_activate_change", lambda *_: self._refresh_background())
@ -63,9 +61,9 @@ class Input(BoxWidget):
"""
return (
self._texture_active if self.activated and self._texture_active is not None else
self._texture_error if self.invalid and self._texture_error is not None else
self._texture_normal
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
self.style.get("normal")
)
# refresh

View file

@ -1,11 +1,12 @@
from typing import TYPE_CHECKING, Callable, Any
from typing import TYPE_CHECKING, Callable, Any, Type
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_prefix
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
@ -14,8 +15,7 @@ if TYPE_CHECKING:
class Scroller(BoxWidget):
def __init__(self, scene: "Scene",
texture_background: pyglet.image.AbstractImage,
texture_cursor: pyglet.image.AbstractImage,
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
@ -32,20 +32,24 @@ class Scroller(BoxWidget):
**kwargs):
super().__init__(scene, x, y, width, height)
self.style = style
self.cursor_width = cursor_width
self.text_transform = text_transform
self.background = Sprite(
img=texture_background,
**dict_prefix("background_", kwargs)
img=self.style.get("background"),
**dict_filter_prefix("background_", kwargs)
)
self.cursor = Sprite(
img=texture_cursor,
**dict_prefix("cursor_", kwargs)
img=self.style.get("cursor"),
**dict_filter_prefix("cursor_", kwargs)
)
self.label = pyglet.text.Label(
anchor_x="center", anchor_y="center",
**dict_prefix("label_", kwargs)
**dict_filter_prefix("label_", kwargs)
)
self.add_listener("on_click_release", lambda rel_x, *_: self._refresh_cursor(rel_x))

View file

@ -1,3 +1,3 @@
from .copy_array_offset import copy_array_offset
from .in_bbox import in_bbox
from .dict import dict_filter, dict_prefix
from .dict import dict_filter, dict_filter_prefix

View file

@ -4,8 +4,8 @@ from typing import Callable, Any
def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, Any]) -> dict[Any, Any]:
"""
Filter a dict object with the filter function given.
:filter_func: the function to filter with
:dictionary: the dictionary to filter
:param filter_func: the function to filter with
:param dictionary: the dictionary to filter
:return: the filtered dictionary
Example :
@ -24,11 +24,11 @@ def dict_filter(filter_func: Callable[[Any, Any], bool], dictionary: dict[Any, A
}
def dict_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
def dict_filter_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
"""
Take only the keys that start with the prefix, and remove this prefix from the keys.
:prefix: the prefix to use
:dictionary: the dictionary to filter
:param prefix: the prefix to use
:param dictionary: the dictionary to filter
:return: the dictionary with the prefix
Example:
@ -44,3 +44,17 @@ def dict_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
dictionary
).items()
}
def dict_add_prefix(prefix: str, dictionary: dict[str, Any]) -> dict[str, Any]:
"""
Add a prefix to every key of the dictionary
:param prefix: the prefix to add
:param dictionary: the dictionary to modify
:return: the dictionary with the prefix at the start of the keys
"""
return {
prefix + k: v
for k, v in dictionary.items()
}