from __future__ import annotations import typing from dataclasses import dataclass, field import pygame from config import CHAT_SELECTOR_WIDTH, HEIGHT, DARK_BLUE, WHITE, GREY, BLUE, font, CHAT_PREVIEW_HEIGHT, MEDIUM_BLUE @dataclass class ChatSelector: """ The widget with the list of chats. It's a dataclass, it should be initialized using the `from_chats` classmethod Attributes: chats (List[dc.Chat]): list of all chats, where each chat is a native Rust struct Chat active_chat (int): the index of the current selected chat hovered_chat (int or None): the index of the current hovered chat width (int): the width of this widget height (int): the height of this widget chat_height (int): height of one chat """ chats: typing.List['dc.Chat'] = field(default_factory=list) active_chat: int = -1 hovered_chat: typing.Optional[int] = None width: int = CHAT_SELECTOR_WIDTH height: int = HEIGHT chat_height: int = CHAT_PREVIEW_HEIGHT def render(self) -> pygame.Surface: """ Creates a pygame surface and draws the list of chats on it :return: the surface with the chat selector """ surface: pygame.Surface = pygame.Surface((self.width, self.height)) surface.fill(GREY) for i, chat in enumerate(self.chats): bg_color, text_color = DARK_BLUE, WHITE if i == self.hovered_chat: bg_color = MEDIUM_BLUE if i == self.active_chat: bg_color = BLUE title_surface: pygame.Surface = font.render(chat.profile.name, True, text_color) pygame.draw.rect(surface, bg_color, (3, i * self.chat_height + 1, self.width - 6, self.chat_height - 2)) surface.blit(title_surface, (7, i * self.chat_height + 10)) return surface def process_event(self, event: pygame.event.Event) -> bool: """ Process a click: select the necessary chat if this click is in the widget :param event: a pygame event :return: True if a chat was changed """ if event.type == pygame.MOUSEMOTION: if 0 < event.pos[0] < self.width \ and 0 < event.pos[1] < min(self.height, len(self.chats) * self.chat_height) - 2: self.hovered_chat = event.pos[1] // self.chat_height else: self.hovered_chat = None if event.type == pygame.MOUSEBUTTONUP and event.pos[0] < self.width: self.hovered_chat = None self.active_chat = event.pos[1] // self.chat_height return True return False @classmethod def from_chats(cls, chats: typing.List['dc.Chat'], **kwargs) -> ChatSelector: """ Create a new ChatSelector from a list of Rust chats :param chats: the list of chats :param kwargs: optional additional arguments """ return cls(chats, **kwargs)