added Image and Input widgets

This commit is contained in:
Faraphel 2023-02-14 10:36:59 +01:00
parent abf653a4e9
commit 48da47c234
13 changed files with 232 additions and 22 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

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,7 +1,7 @@
import pyglet import pyglet
from source.gui.scene.abc import Scene from source.gui.scene.abc import Scene
from source.gui.widget import Text, FPSDisplay, Button from source.gui.widget import FPSDisplay, Button, Image, Input
from source.gui.window import Window from source.gui.window import Window
# Test Scene # Test Scene
@ -13,30 +13,45 @@ class TestScene(Scene):
# loading resource # loading resource
texture_normal = pyglet.image.load("./assets/image/button/test_button_normal.png") texture_button_normal = pyglet.image.load("./assets/image/button/normal.png")
texture_hover = pyglet.image.load("./assets/image/button/test_button_hover.png") texture_button_hover = pyglet.image.load("./assets/image/button/hovering.png")
texture_click = pyglet.image.load("./assets/image/button/test_button_clicking.png") texture_button_click = pyglet.image.load("./assets/image/button/clicking.png")
texture_input_normal = pyglet.image.load("./assets/image/input/inputbox.png")
texture_input_active = pyglet.image.load("./assets/image/input/active.png")
texture_input_error = pyglet.image.load("./assets/image/input/error.png")
button_atlas = pyglet.image.atlas.TextureAtlas() texture_atlas = pyglet.image.atlas.TextureAtlas()
region_normal = button_atlas.add(texture_normal) region_button_normal = texture_atlas.add(texture_button_normal)
region_hover = button_atlas.add(texture_hover) region_button_hover = texture_atlas.add(texture_button_hover)
region_click = button_atlas.add(texture_click) region_button_click = texture_atlas.add(texture_button_click)
region_input_normal = texture_atlas.add(texture_input_normal)
region_input_active = texture_atlas.add(texture_input_active)
region_input_error = texture_atlas.add(texture_input_error)
self.background_batch = pyglet.graphics.Batch() self.background_batch = pyglet.graphics.Batch()
self.label_batch = pyglet.graphics.Batch() self.label_batch = pyglet.graphics.Batch()
# the widgets # the widgets
self.fps_display = self.add_widget(FPSDisplay) self.fps_display = self.add_widget(FPSDisplay, color=(255, 255, 255, 127))
background = self.add_widget(
Image,
x=0, y=0, width=1, height=1,
image=region_input_normal,
batch=self.background_batch,
)
label = self.add_widget( label = self.add_widget(
Button, Button,
x=0.5, y=0.5, width=0.5, height=0.5, x=0.5, y=0.5, width=0.5, height=0.5,
texture_normal=region_normal, texture_normal=region_button_normal,
texture_hover=region_hover, texture_hover=region_button_hover,
texture_click=region_click, texture_click=region_button_click,
label_text="Hello World !", label_text="Hello World !",
@ -44,15 +59,37 @@ class TestScene(Scene):
label_batch=self.label_batch, label_batch=self.label_batch,
) )
label.on_pressed = lambda button, modifiers: print("pressed", label, button, modifiers) label.on_pressed = lambda button, modifiers: window.set_scene(TestScene2)
label.on_release = lambda button, modifiers: print("release", label, button, modifiers) label.on_release = lambda button, modifiers: print("release", label, button, modifiers)
input_ = self.add_widget(
Input,
x=0.1, y=0.2, width=0.4, height=0.1,
texture_normal=region_input_normal,
texture_active=region_input_active,
texture_error=region_input_error,
# 4 numéros de 1 à 3 chiffres aséparés par des points (IP), optionnellement suivi
# de deux points ainsi que de 1 à 5 chiffres (port)
regex=r"\d{1,3}(\.\d{1,3}){3}(:\d{1,5})?",
background_batch=self.background_batch,
label_batch=self.label_batch,
)
def on_draw(self): def on_draw(self):
self.background_batch.draw() self.background_batch.draw()
self.label_batch.draw() self.label_batch.draw()
self.fps_display.draw() self.fps_display.draw()
class TestScene2(Scene):
def __init__(self, window: "Window"):
super().__init__(window)
# Create a new window # Create a new window
window = Window(resizable=True, vsync=False) window = Window(resizable=True, vsync=False)
window.add_scene(TestScene) window.add_scene(TestScene)

View file

@ -42,6 +42,7 @@ class Button(BoxWidget):
) )
self.label = pyglet.text.Label( self.label = pyglet.text.Label(
width=None, height=None,
anchor_x="center", anchor_y="center", anchor_x="center", anchor_y="center",
**dict_prefix("label_", kwargs) **dict_prefix("label_", kwargs)
) )
@ -71,11 +72,10 @@ class Button(BoxWidget):
self.background.image = self.background_texture self.background.image = self.background_texture
def _refresh_size(self) -> None: def _refresh_size(self) -> None:
self.background.x = self.x self.background.x, self.background.y = self.x, self.y
self.background.y = self.y self.background.width, self.background.height = self.width, self.height
self.background.width = self.width
self.background.height = self.height
# center the label
self.label.x = self.x + (self.width / 2) self.label.x = self.x + (self.width / 2)
self.label.y = self.y + (self.height / 2) self.label.y = self.y + (self.height / 2)

View file

@ -13,10 +13,10 @@ class FPSDisplay(Widget):
A widget that display the current FPS of the scene's window A widget that display the current FPS of the scene's window
""" """
def __init__(self, scene: "Scene"): def __init__(self, scene: "Scene", *args, **kwargs):
super().__init__(scene) super().__init__(scene)
self.fps_display = pyglet.window.FPSDisplay(scene.window) self.fps_display = pyglet.window.FPSDisplay(scene.window, *args, **kwargs)
def draw(self): def draw(self):
self.fps_display.draw() self.fps_display.draw()

View file

@ -0,0 +1,43 @@
from typing import TYPE_CHECKING
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.widget.abc import BoxWidget
from source.type import Percentage
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class Image(BoxWidget):
def __init__(self, scene: "Scene",
image: pyglet.image.AbstractImage,
x: Percentage = 0,
y: Percentage = 0,
width: Percentage = None,
height: Percentage = None,
*args, **kwargs):
super().__init__(scene, x, y, width, height)
self.image = Sprite(img=image, *args, **kwargs)
self._refresh_size()
# refresh
def _refresh_size(self):
self.image.width, self.image.height = self.width, self.height
# event
def on_resize(self, width: int, height: int):
self._refresh_size()
# draw
def draw(self):
self.image.draw()

115
source/gui/widget/Input.py Normal file
View file

@ -0,0 +1,115 @@
import re
from typing import TYPE_CHECKING, Optional
import pyglet.image
from source.gui.sprite import Sprite
from source.gui.widget.abc import BoxWidget
from source.type import Percentage
from source.utils import dict_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
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,
regex: Optional[str | re.Pattern] = None,
x: Percentage = 0,
y: Percentage = 0,
width: Percentage = None,
height: Percentage = None,
*args, **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._invalid = False
self.regex = re.compile(regex) if isinstance(regex, str) else regex
self.background = Sprite(
img=self._texture_normal,
**dict_prefix("background_", kwargs)
)
self.label = pyglet.text.Label(
width=None, height=None,
anchor_x="center", anchor_y="center",
**dict_prefix("label_", kwargs)
)
# background
@property
def background_texture(self) -> pyglet.image.AbstractImage:
"""
Return the correct texture for the background.
The clicking texture per default, if hover the hovered texture (if it exists)
and if click the clicking texture (if it exists)
:return: the corresponding texture
"""
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
)
# refresh
def _refresh_background(self) -> None:
self.background.image = self.background_texture
def _refresh_size(self) -> None:
self.background.x, self.background.y = self.x, self.y
self.background.width, self.background.height = self.width, self.height
# center the label
self.label.x = self.x + (self.width / 2)
self.label.y = self.y + (self.height / 2)
@BoxWidget.activated.setter
def activated(self, activated: bool) -> None:
BoxWidget.activated.fset(self, activated)
self._refresh_background()
# property
@property
def invalid(self):
return self._invalid
@invalid.setter
def invalid(self, invalid: bool):
self._invalid = invalid
self._refresh_background()
# event
def on_key_press(self, symbol: int, modifiers: int):
if not self.activated: return # ignore si ce widget est désactivé / non sélectionné
if symbol == pyglet.window.key.BACKSPACE: # si la touche "supprimé" est enfoncé
self.label.text = self.label.text[0:-1] # retire le dernier caractère du texte
def on_text(self, char: str):
if not self.activated: return # ignore si ce widget est désactivé / non sélectionné
self.label.text += char # ajoute le caractère au label
if self.regex is not None: # si il y a un regex de validation, applique le pour vérifier le texte
self.invalid = self.regex.fullmatch(self.label.text) is None
def on_resize(self, width: int, height: int):
self._refresh_size()
def draw(self):
self.background.draw()
self.label.draw()

View file

@ -1,3 +1,5 @@
from .Text import Text from .Text import Text
from .FPSDisplay import FPSDisplay from .FPSDisplay import FPSDisplay
from .Button import Button from .Button import Button
from .Input import Input
from .Image import Image

View file

@ -29,6 +29,7 @@ class BoxWidget(Widget, ABC):
self._hovering = False # is the button currently hovered ? self._hovering = False # is the button currently hovered ?
self._clicking = False # is the button currently clicked ? self._clicking = False # is the button currently clicked ?
self._activated = False # is the button activated ? (the last click was inside this widget)
# property # property
@ -94,6 +95,14 @@ class BoxWidget(Widget, ABC):
def clicking(self, clicking: bool): def clicking(self, clicking: bool):
self._clicking = clicking self._clicking = clicking
@property
def activated(self):
return self._activated
@activated.setter
def activated(self, activated: bool):
self._activated = activated
# event # event
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int): # NOQA def on_mouse_motion(self, x: int, y: int, dx: int, dy: int): # NOQA
@ -125,15 +134,19 @@ class BoxWidget(Widget, ABC):
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int): def on_mouse_press(self, x: int, y: int, button: int, modifiers: int):
# if this button was the one hovered when the click was pressed # if this button was the one hovered when the click was pressed
if not in_bbox((x, y), self.bbox): return
self.clicking = True if not in_bbox((x, y), self.bbox):
self.activated = False # if the click was not in the bbox, disable the activated state
return
self.activated = True # if the click is inside the bbox, enable the activated state
self.clicking = True # the widget is now clicked
self.on_press(button, modifiers) self.on_press(button, modifiers)
def on_mouse_release(self, x: int, y: int, button: int, modifiers: int): def on_mouse_release(self, x: int, y: int, button: int, modifiers: int):
old_click: bool = self._clicking old_click: bool = self._clicking
self.clicking = False self.clicking = False # the widget is no longer clicked
if not in_bbox((x, y), self.bbox): return if not in_bbox((x, y), self.bbox): return