|
|
|
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)
|