diff --git a/source/gui/texture/Background.py b/source/gui/texture/Background.py index 7f8279b..d115f4c 100644 --- a/source/gui/texture/Background.py +++ b/source/gui/texture/Background.py @@ -1,10 +1,10 @@ from . import path from .abc import Style - +from source.gui.texture.type import Texture path = path / "background" class Background(Style): - main = path / "main.png" - game = path / "game.png" + main = Texture(path / "main.png") + game = Texture(path / "game.png") diff --git a/source/gui/texture/Button.py b/source/gui/texture/Button.py index feca348..8be2c00 100644 --- a/source/gui/texture/Button.py +++ b/source/gui/texture/Button.py @@ -1,11 +1,12 @@ from . import path from .abc import Style +from source.gui.texture.type import Texture path = path / "button" class Button: class Style1(Style): - normal = path / "normal.png" - click = path / "clicking.png" - hover = path / "hovering.png" + normal = Texture(path / "normal.png") + click = Texture(path / "clicking.png") + hover = Texture(path / "hovering.png") diff --git a/source/gui/texture/Checkbox.py b/source/gui/texture/Checkbox.py index 074ddda..04592cb 100644 --- a/source/gui/texture/Checkbox.py +++ b/source/gui/texture/Checkbox.py @@ -1,10 +1,11 @@ from . import path from .abc import Style +from .type import Texture path = path / "checkbox" class Checkbox: class Style1(Style): - disabled = path / "disabled.png" - enabled = path / "enabled.png" + disabled = Texture(path / "disabled.png") + enabled = Texture(path / "enabled.png") diff --git a/source/gui/texture/Grid.py b/source/gui/texture/Grid.py index b064e10..e3222e9 100644 --- a/source/gui/texture/Grid.py +++ b/source/gui/texture/Grid.py @@ -1,5 +1,6 @@ from . import path from .abc import Style +from .type import Texture, Animation path = path / "grid" path_boat = path / "boat" @@ -8,13 +9,13 @@ path_bomb = path / "bomb" class Grid: class Style1(Style): - background = path / "background.png" + background = Texture(path / "background.png") class Boat: class Style1(Style): - body = path_boat / "body.png" - edge = path_boat / "edge.png" - solo = path_boat / "solo.png" + body = Texture(path_boat / "body.png") + edge = Texture(path_boat / "edge.png") + solo = Texture(path_boat / "solo.png") class Bomb: class Style1(Style): @@ -23,5 +24,5 @@ class Grid: key=lambda path: int(path.stem) ) - missed = [*_animation, path_bomb / "missed.png"], 0.03, False - touched = [*_animation, path_bomb / "touched.png"], 0.03, False + missed = Animation([*_animation, path_bomb / "missed.png"], 0.03, False) + touched = Animation([*_animation, path_bomb / "touched.png"], 0.03, False) diff --git a/source/gui/texture/Input.py b/source/gui/texture/Input.py index 24580b1..99920f2 100644 --- a/source/gui/texture/Input.py +++ b/source/gui/texture/Input.py @@ -1,11 +1,12 @@ from . import path from .abc import Style +from .type import Texture path = path / "input" class Input: class Style1(Style): - normal = path / "normal.png" - active = path / "active.png" - error = path / "error.png" + normal = Texture(path / "normal.png") + active = Texture(path / "active.png") + error = Texture(path / "error.png") diff --git a/source/gui/texture/Result.py b/source/gui/texture/Result.py index d6cd08c..71d80ac 100644 --- a/source/gui/texture/Result.py +++ b/source/gui/texture/Result.py @@ -1,10 +1,11 @@ from . import path from .abc import Style +from .type import Animation path = path / "result" class Result: class Style1(Style): - victory = (path / "victory").iterdir(), 0.04, False - defeat = (path / "defeat").iterdir(), 0.04, False + victory = Animation((path / "victory").iterdir(), 0.04, False) + defeat = Animation((path / "defeat").iterdir(), 0.04, False) diff --git a/source/gui/texture/Scroller.py b/source/gui/texture/Scroller.py index be699fd..517eb1c 100644 --- a/source/gui/texture/Scroller.py +++ b/source/gui/texture/Scroller.py @@ -1,10 +1,11 @@ from . import path from .abc import Style +from .type import Texture path = path / "scroller" class Scroller: class Style1(Style): - background = path / "background.png" - cursor = path / "cursor.png" + background = Texture(path / "background.png") + cursor = Texture(path / "cursor.png") diff --git a/source/gui/texture/abc/Style.py b/source/gui/texture/abc/Style.py index a459f3f..0c7442a 100644 --- a/source/gui/texture/abc/Style.py +++ b/source/gui/texture/abc/Style.py @@ -8,33 +8,12 @@ import pyglet class Style(ABC): """ This class represent a style that can be attached to a widget. - All property of the class will be loaded into a pyglet image. - - If the property is associated to only a Path, a simple image will be loaded. - If the property is associated to a list of Path, an animation will be loaded. """ - def __init_subclass__(cls, **kwargs): - for name, args in cls.__dict__.items(): - if name.startswith("_"): continue - - if isinstance(args, Path): # if this is a normal path for a normal image - path = args - texture = pyglet.image.load(path) - - elif isinstance(args, tuple) and len(args) == 3: # if this is a tuple for an animation - paths, duration, loop = args - textures = map(pyglet.image.load, paths) - texture = pyglet.image.Animation.from_image_sequence(textures, duration, loop) - - else: - raise ValueError(f"Invalid type : {type(args)}") - - setattr(cls, name, texture) + @classmethod + def __getattr__(cls, item): + return None # by default, an object will be None if not found. @classmethod - def get(cls, item: str, default: Any = None) -> Optional[pyglet.image.AbstractImage]: + def get(cls, item, default=None): return getattr(cls, item, default) - - def __class_getitem__(cls, item: str) -> Optional[pyglet.image.AbstractImage]: - return cls.get(item) diff --git a/source/gui/texture/type/Animation.py b/source/gui/texture/type/Animation.py new file mode 100644 index 0000000..b217260 --- /dev/null +++ b/source/gui/texture/type/Animation.py @@ -0,0 +1,20 @@ +from pathlib import Path +from typing import Iterable + +import pyglet + +from source.gui.texture.type.abc import TextureType + + +class Animation(TextureType): + def __init__(self, paths: Iterable[Path], frame_duration: float, loop: bool = True): + self.paths = paths + self.frame_duration = frame_duration + self.loop = loop + + def __get__(self, instance, owner) -> pyglet.image.Animation: + return pyglet.image.Animation.from_image_sequence( + sequence=map(self.get_texture, self.paths), + duration=self.frame_duration, + loop=self.loop + ) diff --git a/source/gui/texture/type/Texture.py b/source/gui/texture/type/Texture.py new file mode 100644 index 0000000..fcd335a --- /dev/null +++ b/source/gui/texture/type/Texture.py @@ -0,0 +1,13 @@ +from pathlib import Path + +import pyglet + +from source.gui.texture.type.abc import TextureType + + +class Texture(TextureType): + def __init__(self, path: Path): + self.path = path + + def __get__(self, instance, owner) -> pyglet.image.AbstractImage: + return self.get_texture(self.path) diff --git a/source/gui/texture/type/__init__.py b/source/gui/texture/type/__init__.py new file mode 100644 index 0000000..9895cc6 --- /dev/null +++ b/source/gui/texture/type/__init__.py @@ -0,0 +1,2 @@ +from .Texture import Texture +from .Animation import Animation diff --git a/source/gui/texture/type/abc/TextureType.py b/source/gui/texture/type/abc/TextureType.py new file mode 100644 index 0000000..69cb30d --- /dev/null +++ b/source/gui/texture/type/abc/TextureType.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from pathlib import Path + +import pyglet + + +class TextureType(ABC): + loaded_image: dict[Path, pyglet.image.AbstractImage] = {} + + @classmethod + def get_texture(cls, path: Path) -> pyglet.image.AbstractImage: + if (texture := cls.loaded_image.get(path)) is None: + texture = pyglet.image.load(path) + cls.loaded_image[path] = texture + + return texture + + @abstractmethod + def __get__(self, instance, owner) -> pyglet.image.AbstractImage: + pass diff --git a/source/gui/texture/type/abc/__init__.py b/source/gui/texture/type/abc/__init__.py new file mode 100644 index 0000000..760b823 --- /dev/null +++ b/source/gui/texture/type/abc/__init__.py @@ -0,0 +1 @@ +from .TextureType import TextureType diff --git a/source/gui/widget/Button.py b/source/gui/widget/Button.py index f55c4d4..a419b37 100644 --- a/source/gui/widget/Button.py +++ b/source/gui/widget/Button.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Optional, Type +from typing import TYPE_CHECKING, Type import pyglet @@ -33,7 +33,7 @@ class Button(BoxWidget): self.style = style self.background = Sprite( - img=self.style.get("normal"), + img=self.style.normal, **dict_filter_prefix("background_", kwargs) ) @@ -60,9 +60,9 @@ class Button(BoxWidget): """ return ( - 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") + texture if self.clicking and (texture := self.style.click) is not None else # NOQA + texture if self.hovering and (texture := self.style.hover) is not None else + self.style.normal ) # refresh diff --git a/source/gui/widget/Checkbox.py b/source/gui/widget/Checkbox.py index ea4c36a..7e0accc 100644 --- a/source/gui/widget/Checkbox.py +++ b/source/gui/widget/Checkbox.py @@ -1,7 +1,5 @@ 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 @@ -33,7 +31,7 @@ class Checkbox(BoxWidget): self.style = style - self.tick = Sprite(img=self.style.get("disabled"), **kwargs) + self.tick = Sprite(img=self.style.disabled, **kwargs) self.state = state diff --git a/source/gui/widget/GameGrid.py b/source/gui/widget/GameGrid.py index befa02c..cbc2d0c 100644 --- a/source/gui/widget/GameGrid.py +++ b/source/gui/widget/GameGrid.py @@ -61,7 +61,7 @@ class GameGrid(BoxWidget): self.bomb_style = bomb_style self.background = Sprite( - img=grid_style.get("background"), + img=grid_style.background, **dict_filter_prefix("background_", kwargs) ) @@ -224,7 +224,7 @@ class GameGrid(BoxWidget): def place_bomb(self, cell: Point2D, touched: bool): self.cell_sprites[cell] = Sprite( - img=self.bomb_style.get("touched" if touched else "missed"), + img=self.bomb_style.touched if touched else self.bomb_style.missed, **self._bomb_kwargs ) diff --git a/source/gui/widget/Input.py b/source/gui/widget/Input.py index a9a808d..f6e8cd7 100644 --- a/source/gui/widget/Input.py +++ b/source/gui/widget/Input.py @@ -39,7 +39,7 @@ class Input(BoxWidget): self.regex = re.compile(regex) if isinstance(regex, str) else regex self.background = Sprite( - img=self.style.get("normal"), + img=self.style.normal, **dict_filter_prefix("background_", kwargs) ) @@ -65,9 +65,9 @@ class Input(BoxWidget): """ return ( - texture if self.activated and (texture := self.style.get("active")) is not None else # NOQA - texture if self.invalid and (texture := self.style.get("signal")) is not None else - self.style.get("normal") + texture if self.activated and (texture := self.style.active) is not None else # NOQA + texture if self.invalid and (texture := self.style.signal) is not None else + self.style.normal ) # refresh diff --git a/source/gui/widget/Scroller.py b/source/gui/widget/Scroller.py index eccbf95..e4d4299 100644 --- a/source/gui/widget/Scroller.py +++ b/source/gui/widget/Scroller.py @@ -43,12 +43,12 @@ class Scroller(BoxWidget): self.text_transform = text_transform self.background = Sprite( - img=self.style.get("background"), + img=self.style.background, **dict_filter_prefix("background_", kwargs) ) self.cursor = Sprite( - img=self.style.get("cursor"), + img=self.style.cursor, **dict_filter_prefix("cursor_", kwargs) )