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.right and self.top_left[1] <= event.pos[1] < self.bottom: 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 else: self.is_hovered = False return False