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
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
# Test Scene
@ -13,30 +13,45 @@ class TestScene(Scene):
# loading resource
texture_normal = pyglet.image.load("./assets/image/button/test_button_normal.png")
texture_hover = pyglet.image.load("./assets/image/button/test_button_hover.png")
texture_click = pyglet.image.load("./assets/image/button/test_button_clicking.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_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()
region_normal = button_atlas.add(texture_normal)
region_hover = button_atlas.add(texture_hover)
region_click = button_atlas.add(texture_click)
texture_atlas = pyglet.image.atlas.TextureAtlas()
region_button_normal = texture_atlas.add(texture_button_normal)
region_button_hover = texture_atlas.add(texture_button_hover)
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.label_batch = pyglet.graphics.Batch()
# 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(
Button,
x=0.5, y=0.5, width=0.5, height=0.5,
texture_normal=region_normal,
texture_hover=region_hover,
texture_click=region_click,
texture_normal=region_button_normal,
texture_hover=region_button_hover,
texture_click=region_button_click,
label_text="Hello World !",
@ -44,15 +59,37 @@ class TestScene(Scene):
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)
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):
self.background_batch.draw()
self.label_batch.draw()
self.fps_display.draw()
class TestScene2(Scene):
def __init__(self, window: "Window"):
super().__init__(window)
# Create a new window
window = Window(resizable=True, vsync=False)
window.add_scene(TestScene)

View file

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

View file

@ -13,10 +13,10 @@ class FPSDisplay(Widget):
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)
self.fps_display = pyglet.window.FPSDisplay(scene.window)
self.fps_display = pyglet.window.FPSDisplay(scene.window, *args, **kwargs)
def draw(self):
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 .FPSDisplay import FPSDisplay
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._clicking = False # is the button currently clicked ?
self._activated = False # is the button activated ? (the last click was inside this widget)
# property
@ -94,6 +95,14 @@ class BoxWidget(Widget, ABC):
def clicking(self, clicking: bool):
self._clicking = clicking
@property
def activated(self):
return self._activated
@activated.setter
def activated(self, activated: bool):
self._activated = activated
# event
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):
# 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)
def on_mouse_release(self, x: int, y: int, button: int, modifiers: int):
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