|
|
|
import typing
|
|
|
|
|
|
|
|
import pygame
|
|
|
|
|
|
|
|
from config import font, MESSAGE_HEIGHT, WIDTH, CHAT_SELECTOR_WIDTH, HEIGHT, WHITE, DARKER_BLUE, GREY
|
|
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class TextField:
|
|
|
|
"""
|
|
|
|
Field for message input
|
|
|
|
"""
|
|
|
|
value: str = ''
|
|
|
|
width: int = WIDTH - CHAT_SELECTOR_WIDTH - 80
|
|
|
|
height: int = MESSAGE_HEIGHT * 2
|
|
|
|
top_left_corner: typing.Tuple[int, int] = (CHAT_SELECTOR_WIDTH, HEIGHT - MESSAGE_HEIGHT * 2)
|
|
|
|
is_focused: bool = False
|
|
|
|
placeholder: str = ''
|
|
|
|
cursor_position: int = 0
|
|
|
|
|
|
|
|
def render(self) -> pygame.Surface:
|
|
|
|
"""
|
|
|
|
Render the text field onto a pygame surface
|
|
|
|
:return: a surface with the field
|
|
|
|
"""
|
|
|
|
surface = pygame.Surface((self.width, self.height))
|
|
|
|
surface.fill(WHITE)
|
|
|
|
padding = 5
|
|
|
|
pygame.draw.rect(surface, DARKER_BLUE, (padding, padding, self.width - padding * 2, self.height - padding * 2))
|
|
|
|
if not self.value and self.placeholder:
|
|
|
|
placeholder_text: pygame.Surface = font.render(self.placeholder, True, GREY)
|
|
|
|
surface.blit(
|
|
|
|
placeholder_text,
|
|
|
|
(
|
|
|
|
(self.width - placeholder_text.get_width()) // 2,
|
|
|
|
(self.height - placeholder_text.get_height()) // 2
|
|
|
|
)
|
|
|
|
)
|
|
|
|
if self.value:
|
|
|
|
message_text: pygame.Surface = font.render(self.value, True, WHITE)
|
|
|
|
surface.blit(
|
|
|
|
message_text,
|
|
|
|
(
|
|
|
|
0, # or, if we want to center, `(self.width - message_text.get_width()) // 2,`
|
|
|
|
(self.height - message_text.get_height()) // 2
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return surface
|
|
|
|
|
|
|
|
def process_event(self, event: pygame.event.Event):
|
|
|
|
"""
|
|
|
|
Handle a typing event or a click (to focus)
|
|
|
|
:param event: a pygame event
|
|
|
|
"""
|
|
|
|
# If we have a click, we should focus the field if the click was inside or unfocus if it was outside
|
|
|
|
if event.type == pygame.MOUSEBUTTONUP:
|
|
|
|
self.is_focused = self.top_left_corner[0] <= event.pos[0] < self.top_left_corner[0] + self.width \
|
|
|
|
and self.top_left_corner[1] <= event.pos[1] < self.top_left_corner[1] + self.height
|
|
|
|
if self.is_focused and hasattr(event, 'key') and event.type == 768:
|
|
|
|
if event.key == pygame.K_BACKSPACE:
|
|
|
|
self.value = self.value[:-1]
|
|
|
|
self.cursor_position -= 1
|
|
|
|
elif event.key == pygame.K_LEFT:
|
|
|
|
self.cursor_position -= 1
|
|
|
|
elif event.key == pygame.K_RIGHT:
|
|
|
|
self.cursor_position += 1
|
|
|
|
elif event.unicode:
|
|
|
|
self.value = self.value[:self.cursor_position] + event.unicode + self.value[self.cursor_position:]
|
|
|
|
self.cursor_position += 1
|
|
|
|
# print(self.is_focused, event.type, getattr(event, 'key', None), getattr(event, 'unicode', None), self.value)
|
|
|
|
|
|
|
|
def collect(self) -> str:
|
|
|
|
"""
|
|
|
|
Get the current value and clear the field
|
|
|
|
:return: the value of the text input
|
|
|
|
"""
|
|
|
|
value = self.value
|
|
|
|
self.value = ''
|
|
|
|
self.cursor_position = 0
|
|
|
|
return value
|