|
|
|
import pygame
|
|
|
|
import typing
|
|
|
|
|
|
|
|
from config import font_large, WHITE, BLUE, BLACK
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Button:
|
|
|
|
"""
|
|
|
|
Just a button element for pygame
|
|
|
|
Attributes:
|
|
|
|
:param text (str): Text on the button
|
|
|
|
:param top_left ((int, int)): the coordinates of the top-left point of the button
|
|
|
|
:param width (int): the width of the button
|
|
|
|
:param height (int): the height of the button
|
|
|
|
:param padding (int): padding - the distance between rectangle border and button content
|
|
|
|
:param bg_color (Color): the background color
|
|
|
|
:param text_color (Color): color of the text
|
|
|
|
:param hovered_color (Color): the background color when the button is hovered
|
|
|
|
:param hovered_text_color (Color): the text color when the button is hovered
|
|
|
|
:param pressed_color (Color): the background color when the button is pressed
|
|
|
|
:param pressed_text_color (Color): the text color when the button is pressed
|
|
|
|
"""
|
|
|
|
text: str
|
|
|
|
top_left: typing.Tuple[int, int]
|
|
|
|
width: int
|
|
|
|
height: int
|
|
|
|
padding: int = 13
|
|
|
|
bg_color: pygame.Color = BLUE
|
|
|
|
text_color: pygame.Color = WHITE
|
|
|
|
hovered_color: pygame.Color = (BLUE * 3 + WHITE) // 4
|
|
|
|
hovered_text_color: pygame.Color = BLACK
|
|
|
|
pressed_color: pygame.Color = (BLUE + WHITE * 3) // 4
|
|
|
|
pressed_text_color: pygame.Color = BLACK
|
|
|
|
is_hovered: bool = False
|
|
|
|
is_pressed: bool = False
|
|
|
|
|
|
|
|
@property
|
|
|
|
def bottom(self) -> int:
|
|
|
|
"""
|
|
|
|
Return the y coordinate of the bottom of the button
|
|
|
|
:return: y_bottom
|
|
|
|
"""
|
|
|
|
return self.top_left[1] + self.height
|
|
|
|
|
|
|
|
@property
|
|
|
|
def right(self) -> int:
|
|
|
|
"""
|
|
|
|
Return the x coordinate of the right edge of the button
|
|
|
|
:return: x_right
|
|
|
|
"""
|
|
|
|
return self.top_left[0] + self.width
|
|
|
|
|
|
|
|
def get_colors(self) -> typing.Tuple[pygame.Color, pygame.Color]:
|
|
|
|
"""
|
|
|
|
Get background and text color considering hovered and pressed states
|
|
|
|
:return: the button's background color and the button's text color
|
|
|
|
"""
|
|
|
|
if self.is_pressed:
|
|
|
|
return self.pressed_color, self.pressed_text_color
|
|
|
|
if self.is_hovered:
|
|
|
|
return self.hovered_color, self.hovered_text_color
|
|
|
|
return self.bg_color, self.text_color
|
|
|
|
|
|
|
|
def render(self) -> pygame.Surface:
|
|
|
|
"""
|
|
|
|
Draw the button
|
|
|
|
:return: a pygame surface with the button
|
|
|
|
"""
|
|
|
|
surface: pygame.Surface = pygame.Surface((self.width, self.height))
|
|
|
|
bg_color, text_color = self.get_colors()
|
|
|
|
surface.fill(bg_color)
|
|
|
|
text_surface: pygame.Surface = font_large.render(self.text, True, text_color)
|
|
|
|
text_height: int = self.height - 2 * self.padding
|
|
|
|
text_width: int = round(text_surface.get_width() * text_height / text_surface.get_height())
|
|
|
|
text_surface: pygame.Surface = pygame.transform.scale(text_surface, (text_width, text_height))
|
|
|
|
surface.blit(text_surface, ((self.width - text_width) // 2, self.padding))
|
|
|
|
return surface
|
|
|
|
|
|
|
|
def process_event(self, event: pygame.event.Event) -> bool:
|
|
|
|
"""
|
|
|
|
Process a pygame event. If it's a click on this button, return true
|
|
|
|
:param event: a pygame event
|
|
|
|
:return: True if there was a click on the button
|
|
|
|
"""
|
|
|
|
# if this is a mouse event
|
|
|
|
if event.type in [pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION, pygame.MOUSEBUTTONDOWN]:
|
|
|
|
# if the mouse event is inside the button
|
|
|
|
if self.top_left[0] <= event.pos[0] < self.bottom and self.top_left[1] <= event.pos[1] < self.right:
|
|
|
|
if event.type == pygame.MOUSEBUTTONUP:
|
|
|
|
self.is_pressed = False
|
|
|
|
return True
|
|
|
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
|
|
|
self.is_hovered = False
|
|
|
|
self.is_pressed = True
|
|
|
|
elif event.type == pygame.MOUSEMOTION:
|
|
|
|
self.is_hovered = True
|
|
|
|
return False
|