Traktor/myenv/Lib/site-packages/pygame/examples/textinput.py

236 lines
7.4 KiB
Python
Raw Permalink Normal View History

2024-05-26 05:12:46 +02:00
#!/usr/bin/env python
""" pg.examples.textinput
A little "console" where you can write in text.
Shows how to use the TEXTEDITING and TEXTINPUT events.
"""
import sys
import os
from typing import List
import pygame
import pygame as pg
import pygame.freetype as freetype
# This environment variable is important
# If not added the candidate list will not show
os.environ["SDL_IME_SHOW_UI"] = "1"
class TextInput:
"""
A simple TextInput class that allows you to receive inputs in pygame.
"""
# Add font name for each language,
# otherwise some text can't be correctly displayed.
FONT_NAMES = ",".join(
str(x)
for x in [
"notosanscjktcregular",
"notosansmonocjktcregular",
"notosansregular,",
"microsoftjhengheimicrosoftjhengheiuilight",
"microsoftyaheimicrosoftyaheiuilight",
"msgothicmsuigothicmspgothic",
"msmincho",
"Arial",
]
)
def __init__(
self, prompt: str, pos, screen_dimensions, print_event: bool, text_color="white"
) -> None:
self.prompt = prompt
self.print_event = print_event
# position of chatlist and chatbox
self.CHAT_LIST_POS = pg.Rect((pos[0], pos[1] + 50), (screen_dimensions[0], 400))
self.CHAT_BOX_POS = pg.Rect(pos, (screen_dimensions[1], 40))
self.CHAT_LIST_MAXSIZE = 20
self._ime_editing = False
self._ime_text = ""
self._ime_text_pos = 0
self._ime_editing_text = ""
self._ime_editing_pos = 0
self.chat_list: List[str] = []
# Freetype
# The font name can be a comma separated list
# of font names to search for.
self.font = freetype.SysFont(self.FONT_NAMES, 24)
self.font_small = freetype.SysFont(self.FONT_NAMES, 16)
self.text_color = text_color
print("Using font: " + self.font.name)
def update(self, events) -> None:
"""
Updates the text input widget
"""
for event in events:
if event.type == pg.KEYDOWN:
if self.print_event:
print(event)
if self._ime_editing:
if len(self._ime_editing_text) == 0:
self._ime_editing = False
continue
if event.key == pg.K_BACKSPACE:
if len(self._ime_text) > 0 and self._ime_text_pos > 0:
self._ime_text = (
self._ime_text[0 : self._ime_text_pos - 1]
+ self._ime_text[self._ime_text_pos :]
)
self._ime_text_pos = max(0, self._ime_text_pos - 1)
elif event.key == pg.K_DELETE:
self._ime_text = (
self._ime_text[0 : self._ime_text_pos]
+ self._ime_text[self._ime_text_pos + 1 :]
)
elif event.key == pg.K_LEFT:
self._ime_text_pos = max(0, self._ime_text_pos - 1)
elif event.key == pg.K_RIGHT:
self._ime_text_pos = min(
len(self._ime_text), self._ime_text_pos + 1
)
# Handle ENTER key
elif event.key in [pg.K_RETURN, pg.K_KP_ENTER]:
# Block if we have no text to append
if len(self._ime_text) == 0:
continue
# Append chat list
self.chat_list.append(self._ime_text)
if len(self.chat_list) > self.CHAT_LIST_MAXSIZE:
self.chat_list.pop(0)
self._ime_text = ""
self._ime_text_pos = 0
elif event.type == pg.TEXTEDITING:
if self.print_event:
print(event)
self._ime_editing = True
self._ime_editing_text = event.text
self._ime_editing_pos = event.start
elif event.type == pg.TEXTINPUT:
if self.print_event:
print(event)
self._ime_editing = False
self._ime_editing_text = ""
self._ime_text = (
self._ime_text[0 : self._ime_text_pos]
+ event.text
+ self._ime_text[self._ime_text_pos :]
)
self._ime_text_pos += len(event.text)
def draw(self, screen: pygame.Surface) -> None:
"""
Draws the text input widget onto the provided surface
"""
# Chat List updates
chat_height = self.CHAT_LIST_POS.height / self.CHAT_LIST_MAXSIZE
for i, chat in enumerate(self.chat_list):
self.font_small.render_to(
screen,
(self.CHAT_LIST_POS.x, self.CHAT_LIST_POS.y + i * chat_height),
chat,
self.text_color,
)
# Chat box updates
start_pos = self.CHAT_BOX_POS.copy()
ime_text_l = self.prompt + self._ime_text[0 : self._ime_text_pos]
ime_text_m = (
self._ime_editing_text[0 : self._ime_editing_pos]
+ "|"
+ self._ime_editing_text[self._ime_editing_pos :]
)
ime_text_r = self._ime_text[self._ime_text_pos :]
rect_text_l = self.font.render_to(
screen, start_pos, ime_text_l, self.text_color
)
start_pos.x += rect_text_l.width
# Editing texts should be underlined
rect_text_m = self.font.render_to(
screen,
start_pos,
ime_text_m,
self.text_color,
None,
freetype.STYLE_UNDERLINE,
)
start_pos.x += rect_text_m.width
self.font.render_to(screen, start_pos, ime_text_r, self.text_color)
class Game:
"""
A class that handles the game's events, mainloop etc.
"""
# CONSTANTS
# Frames per second, the general speed of the program
FPS = 50
# Size of window
SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
BG_COLOR = "black"
def __init__(self, caption: str) -> None:
# Initialize
pg.init()
self.screen = pg.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT))
pg.display.set_caption(caption)
self.clock = pg.time.Clock()
# Text input
# Set to true or add 'showevent' in argv to see IME and KEYDOWN events
self.print_event = "showevent" in sys.argv
self.text_input = TextInput(
prompt="> ",
pos=(0, 20),
screen_dimensions=(self.SCREEN_WIDTH, self.SCREEN_HEIGHT),
print_event=self.print_event,
text_color="green",
)
def main_loop(self) -> None:
pg.key.start_text_input()
input_rect = pg.Rect(80, 80, 320, 40)
pg.key.set_text_input_rect(input_rect)
while True:
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
pg.quit()
return
self.text_input.update(events)
# Screen updates
self.screen.fill(self.BG_COLOR)
self.text_input.draw(self.screen)
pg.display.update()
self.clock.tick(self.FPS)
# Main loop process
def main():
game = Game("Text Input Example")
game.main_loop()
if __name__ == "__main__":
main()