From 4721e5e7fad3b81da51192bd53c0f040ecd40f74 Mon Sep 17 00:00:00 2001 From: EKNr1 Date: Thu, 5 Dec 2024 18:47:13 +0100 Subject: [PATCH] Rearranged folder structure in the pygame tools. (No warranty that everything still works. ) --- __init__.py | 1 + examples/gui.py | 11 +- pg.py | 473 ------------------------- pygame_tools/__init__.py | 2 + pygame_tools/utils.py | 50 +++ pygame_tools/widgets/__init__.py | 7 + pygame_tools/widgets/button.py | 29 ++ pygame_tools/widgets/hover.py | 37 ++ pygame_tools/widgets/multiline_text.py | 105 ++++++ pygame_tools/widgets/text_button.py | 64 ++++ pygame_tools/widgets/text_input.py | 140 ++++++++ text.py | 8 +- 12 files changed, 447 insertions(+), 480 deletions(-) create mode 100644 __init__.py delete mode 100644 pg.py create mode 100644 pygame_tools/__init__.py create mode 100644 pygame_tools/utils.py create mode 100644 pygame_tools/widgets/__init__.py create mode 100644 pygame_tools/widgets/button.py create mode 100644 pygame_tools/widgets/hover.py create mode 100644 pygame_tools/widgets/multiline_text.py create mode 100644 pygame_tools/widgets/text_button.py create mode 100644 pygame_tools/widgets/text_input.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..a93a4bf --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/python3 diff --git a/examples/gui.py b/examples/gui.py index 4d38b28..2416048 100644 --- a/examples/gui.py +++ b/examples/gui.py @@ -1,7 +1,8 @@ #!/usr/bin/python3 import pygame -from wobbl_tools import pg +from wobbl_tools.pygame_tools.utils import * +from wobbl_tools.pygame_tools.widgets import TextButton, Button, MultilineText class GUI: @@ -72,7 +73,7 @@ class ExampleMenu(Page): setattr(self, name_lower + "_button", len(buttons)) - buttons.append(pg.TextButton(button_text, (0, 0), change_page, (self, name_lower + "_example"))) + buttons.append(TextButton(button_text, (0, 0), change_page, (self, name_lower + "_example"))) start_pos = (10, 10) spacing = 10 @@ -94,7 +95,7 @@ class ExampleMenu(Page): w, h = button.size button.rect = pygame.Rect((x, y), (w, h)) - button.button = pg.Button(button.rect, button.function, button.args, key=button.key) + button.button = Button(button.rect, button.function, button.args, key=button.key) buttons[i] = button @@ -113,9 +114,9 @@ class ExampleMenu(Page): class MultilineTextExample(Page): def load(self): - self.heading = self.app.big_font.render("Multiline Text", True, pg.white) + self.heading = self.app.big_font.render("Multiline Text", True, white) - self.text = pg.MultilineText( + self.text = MultilineText( "If you want to create multiple lines of text in pygame, " + "you have to create multiple text objects and blit them one another.\n" + 'The class "MultilineText()" does this automatically. ' + diff --git a/pg.py b/pg.py deleted file mode 100644 index 4fe1c77..0000000 --- a/pg.py +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/python3 - -import pygame -from wobbl_tools import text -from typing import Union, Callable - - -pygame.init() - -log = text.Log() - -buttonlist = False -buttons = [] - -# colors -black = (8, 8, 8) -gray = (40, 40, 40) -light_gray = (128, 128, 128) -white = (250, 250, 250) - -default_font = pygame.font.Font(pygame.font.get_default_font(), 16) - - -class Hover: - """ - Used to execute a function when the mouse hovers over a rectangle. - """ - def __init__(self, rect: pygame.Rect, function=None, args: tuple=None): - self.rect = rect - self.function = function - self.args = args - - self.active = True - - def check(self, mouse_pos: tuple): - if self.active: - mx, my = mouse_pos - - if self.rect.collidepoint((mx, my)): - if not self.function is None: - if self.args is None: - self.function() - - else: - self.function(*self.args) - - return True - - return False - - -class Button: - """ - Creates a button from a pygame.Rect. - """ - def __init__(self, rect: pygame.Rect, function=None, args: tuple=None, key: int=0): # key: 0 = left 1 = mouse wheel pressed 2 = right - self.rect = rect - self.function = function - self.args = args - self.key = key - - self.active = True - - self.hover = Hover(rect, function, args) - - if buttonlist: - buttons.append(self) - - def check(self, mouse_pos: tuple, pressed): # check if the button is pressed - if self.active: - if pressed[self.key]: - return self.hover.check(mouse_pos) - - return False - - -class TextButton(pygame.sprite.Sprite): - """ - Creates a button from just some string and a position. - """ - def __init__(self, text: str, position: tuple, function=None, args: tuple=None, key: int=0, text_color: tuple=white, bg_color: tuple=gray, font: pygame.font.Font=default_font, padding: tuple=(8, 8), border_radius: int=0, line_thickness: int = 0): - pygame.sprite.Sprite.__init__(self) - - self.text = text - self.position = position - self.text_color = text_color - self.font = font - self.function = function - self.args = args - self.key = key - self.bg_color = bg_color - self.padding = padding - self.border_radius = border_radius - self.line_thickness = line_thickness - - self.image, self.size = self.generate_surface() - self.rect = self.make_rect() - - self.button = Button(self.rect, self.function, args, self.key) - - def generate_surface(self): - text_object = self.font.render(self.text, True, self.text_color) - - w, h = text_object.get_size() - w, h = w + self.padding[0] * 2, h + self.padding[1] * 2 - - surface = pygame.Surface((w, h), pygame.SRCALPHA) - - pygame.draw.rect(surface, self.bg_color, pygame.Rect((0, 0), (w, h)), self.line_thickness, self.border_radius) - surface.blit(text_object, (self.padding[0], self.padding[1])) - - return surface, (w, h) - - def make_rect(self): - return pygame.Rect(self.position, self.size) - - def draw(self, surface: pygame.Surface): - surface.blit(self.image, self.position) - - def check(self, mouse_pos, pressed): - return self.button.check(mouse_pos, pressed) - - -# class HoverTitle: # coming soon -# def __init__(self, position: tuple=None, size: tuple=None, page: str=None, popup: str = None, collideable=None, delay: int=20): -# self.x, self.y = position -# self.width, self.height = size -# self.page = page -# self.popup = popup -# self.collideable = collideable -# self.delay = delay - - -class TextInput: - """ - Creates an input object at a given position. - """ - def __init__( - self, - position: Union[tuple, Callable], - surface: pygame.Surface, - width: int=None, - font: pygame.font.Font=default_font, - bg_color: tuple=(255, 255, 255), - text_color: tuple=black, - desc_text_color: tuple=light_gray, - desc_text: str="", - default_text: str="", - padding: tuple=(8, 8), - cursor_blink_interval: int=30, - border_radius: int=-1, - max_length: int=128 - ): - self.surface = surface - self.font = font - self.bg_color = bg_color - self.text_color = text_color - self.desc_text_color = desc_text_color - self.desc_text = desc_text - self.text = default_text - self.padding = padding - self.focused = True - self.cursor_blink_interval = cursor_blink_interval - self.ticks_til_blink = cursor_blink_interval - self.blink = False - self.border_radius = border_radius - self.max_length = max_length - self.cursor_position = len(default_text) - - sx, sy = surface.get_size() - - if width is None: - self.width = round(sx / 4) - - else: - self.width = width - - self.description_text_object = font.render(self.desc_text, True, self.desc_text_color) - self.text_object = font.render(self.text, True, self.text_color) - self.text_blink_object = font.render(self.text + "|", True, self.text_color) - - self.height = self.text_object.get_height() - - if type(position) is tuple: - self.position = position - - else: - self.position = position(size=self.size) - self.callable_position = position - - self.rect = self.generate_rect() - - def generate_rect(self): - x, y = self.position - px, py = self.padding - x -= px - y -= py - - return pygame.Rect((x, y), (self.width + px * 2, self.height + py * 2)) - - def blit(self): - pygame.draw.rect(self.surface, self.bg_color, self.rect, border_radius=self.border_radius) - - if self.focused: - if self.blink: - self.surface.blit(self.text_blink_object, self.position) - - else: - self.surface.blit(self.text_object, self.position) - - def loop(self): - """Call this function every tick to make the cursor blink.""" - - self.ticks_til_blink -= 1 - - if self.ticks_til_blink == -1: - self.ticks_til_blink = self.cursor_blink_interval - self.blink = not self.blink - - def keypress(self, event: pygame.event, pressed_keys, special_keys): - """ - Call this function when a key is pressed to get user input like this: - - for event in pygame.event.get(): - if event.type == pygame.KEYDOWN: - TextInput.keypress(event, pygame.key.get_pressed(), pygame.key.get_mods()) - """ - - if self.max_length is None or len(self.text) <= self.max_length: - key_unicode = event.unicode - key = event.key - - if key < 32 or key > 101106 or special_keys & pygame.KMOD_CTRL or special_keys & pygame.KMOD_RCTRL or key > 126 and key < 161: - if key == pygame.K_BACKSPACE: - if self.cursor_position > 0: - self.text = text.rsap(self.text, "", self.cursor_position - 1) - self.cursor_position -= 1 - - elif key == pygame.K_LEFT: - if self.cursor_position > 0: - self.cursor_position -= 1 - - elif key == pygame.K_RIGHT: - if self.cursor_position < len(self.text): - self.cursor_position += 1 - - else: - self.text = text.asap(self.text, key_unicode, self.cursor_position) - self.cursor_position += 1 - - self.regenerate_objects() - - def regenerate_objects(self): - self.rect = self.generate_rect() - - self.text_object = self.font.render(self.text, True, self.text_color) - self.text_blink_object = self.font.render(text.asap(self.text, "|", self.cursor_position), True, self.text_color) - - t_width, t_height = self.text_blink_object.get_size() - - if t_width > self.width: - self.text_blink_object = crop_surface(self.text_blink_object, (t_width - (t_width - (t_width - self.width)), 0), (t_width - (t_width - self.width), t_height)) - self.text_object = crop_surface(self.text_object, (t_width - (t_width - (t_width - self.width)), 0), (t_width - (t_width - self.width), t_height)) - - -class MultilineTextOld: - """ - Early version of multiline text. - Creates a surface with text on it. - You can use a "\\n" to create a newline. - When the max_width parameter is set, newlines generate automatically. - When you know the width of the widest character in your font, yau can set the char_width parameter. It will make the text creation a bit faster. - Use "surface.blit(multiline_text.surface, pos)" to draw it on a surface. - """ - def __init__(self, text: str, font: pygame.font.Font=default_font, color: tuple=white, max_chars: int=None, max_width: int=None, char_width: int=None): - self.text = text - self.font = font - self.color = color - self.max_chars = max_chars - - if char_width is None: - char_width = font.render(text, True, white).get_width() // len(text) # get the width of a character by the font - - if max_chars is None and not max_width is None: - self.max_width = max_width // char_width - 10 - - self.surface = self.generate_surface() - - def generate_surface(self): - lines = [] - line = "" - - length = 1 - - if self.max_width is None: - for char in self.text: - if char == "\n": - lines.append(line) - length = 1 - line = "" - - else: - line += char - - length += 1 - - else: - for char in self.text: - if char == "\n" or len(line) + 1 > self.max_width: - lines.append(line) - length = 1 - - line = "" - - if not char == "\n": - line = char - - else: - line += char - - length += 1 - - lines.append(line) - - texts = [] - - for line in lines: - texts.append(self.font.render(line, True, self.color)) - - w = max(texts, key=lambda t: t.get_width()).get_width() - h = texts[0].get_height() - sh = h * len(lines) - - surface = pygame.Surface((w, sh), flags=pygame.SRCALPHA) - - x, y = 0, 0 - - for text in texts: - surface.blit(text, (x, y)) - - y += h - - return surface - - -class MultilineText: - """ - Creates a surface with text on it. - You can use a "\\n" to create a newline. - When the max_width parameter is set, newlines generate automatically. - When you know the width of the widest character in your font, yau can set the char_width parameter. It will make the text creation a bit faster. - Use "surface.blit(multiline_text.surface, pos)" to draw it on a surface. - """ - def __init__(self, text: str, font: pygame.font.Font=default_font, color: tuple=white, max_width: int=None): - self.text = text - self.font = font - self.color = color - self.max_width = max_width - - self.surface = self.generate_surface() - - def generate_surface(self): - lines = [] - line = "" - - length = 1 - - if self.max_width is None: - for char in self.text: - if char == "\n": - lines.append(line) - length = 1 - line = "" - - else: - line += char - - length += 1 - - else: - for char in self.text: - if char == "\n": - lines.append(line) - - length = 1 - line = "" - - elif self.font.size(line)[0] >= self.max_width - 8: - if " " in line: - # remove last word - - words = line.split(" ") - - last_word = words[len(words) - 1] - words.pop(len(words) - 1) - - line = "" - - for word in words: # convert the list back to a string - line += word + " " - - line = line[:len(line) - 1] # remove last space character - - lines.append(line) - - line = last_word + char - - else: - lines.append(line) - - length = 1 - line = char - - else: - line += char - - length += 1 - - lines.append(line) - - texts = [] - - for line in lines: - texts.append(self.font.render(line, True, self.color)) - - if self.max_width is None: - w = max(texts, key=lambda t: t.get_width()).get_width() - - else: - w = self.max_width - - h = texts[0].get_height() - sh = h * len(lines) - - surface = pygame.Surface((w, sh), flags=pygame.SRCALPHA) - - x, y = 0, 0 - - for text in texts: - surface.blit(text, (x, y)) - - y += h - - return surface - - -def set_rot_point(img, pos): - """ - Blits the image on an empty surface to change the center of rotation. - """ - w, h = img.get_size() - w, h = w * 2, h * 2 - - img2 = pygame.Surface((w, h), pygame.SRCALPHA) - img2.blit(img, (w / 2 - pos[0], h / 2 - pos[1])) - return img2, (w, h) - - -def crop_surface(surface: pygame.Surface, position: tuple, size: tuple): - new_surface = pygame.Surface(size, flags=pygame.SRCALPHA) - - x, y = position - x = -x - y = -y - - new_surface.blit(surface, (x, y)) - - return new_surface - - -def check_buttons(mouse_pos, pressed): - for button in buttons: - button.check(mouse_pos, pressed) diff --git a/pygame_tools/__init__.py b/pygame_tools/__init__.py new file mode 100644 index 0000000..ecf7241 --- /dev/null +++ b/pygame_tools/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/python3 + diff --git a/pygame_tools/utils.py b/pygame_tools/utils.py new file mode 100644 index 0000000..828f295 --- /dev/null +++ b/pygame_tools/utils.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 + +import pygame +from wobbl_tools import text +from typing import Union, Callable + + +pygame.init() + +log = text.Log() + +buttonlist = False +buttons = [] + +# colors +black = (8, 8, 8) +gray = (40, 40, 40) +light_gray = (128, 128, 128) +white = (250, 250, 250) + +default_font = pygame.font.Font(pygame.font.get_default_font(), 16) + + +def set_rot_point(img, pos): + """ + Blits the image on an empty surface to change the center of rotation. + """ + w, h = img.get_size() + w, h = w * 2, h * 2 + + img2 = pygame.Surface((w, h), pygame.SRCALPHA) + img2.blit(img, (w / 2 - pos[0], h / 2 - pos[1])) + return img2, (w, h) + + +def crop_surface(surface: pygame.Surface, position: tuple, size: tuple): + new_surface = pygame.Surface(size, flags=pygame.SRCALPHA) + + x, y = position + x = -x + y = -y + + new_surface.blit(surface, (x, y)) + + return new_surface + + +def check_buttons(mouse_pos, pressed): + for button in buttons: + button.check(mouse_pos, pressed) \ No newline at end of file diff --git a/pygame_tools/widgets/__init__.py b/pygame_tools/widgets/__init__.py new file mode 100644 index 0000000..e778ec5 --- /dev/null +++ b/pygame_tools/widgets/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.widgets.hover import Hover +from wobbl_tools.pygame_tools.widgets.button import Button +from wobbl_tools.pygame_tools.widgets.text_button import TextButton +from wobbl_tools.pygame_tools.widgets.text_input import TextInput +from wobbl_tools.pygame_tools.widgets.multiline_text import MultilineText diff --git a/pygame_tools/widgets/button.py b/pygame_tools/widgets/button.py new file mode 100644 index 0000000..fff8bf8 --- /dev/null +++ b/pygame_tools/widgets/button.py @@ -0,0 +1,29 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.utils import * +from wobbl_tools.pygame_tools.widgets import Hover + + +class Button: + """ + Creates a button from a pygame.Rect. + """ + def __init__(self, rect: pygame.Rect, function=None, args: tuple=None, key: int=0): # key: 0 = left 1 = mouse wheel pressed 2 = right + self.rect = rect + self.function = function + self.args = args + self.key = key + + self.active = True + + self.hover = Hover(rect, function, args) + + if buttonlist: + buttons.append(self) + + def check(self, mouse_pos: tuple, pressed): # check if the button is pressed + if self.active: + if pressed[self.key]: + return self.hover.check(mouse_pos) + + return False diff --git a/pygame_tools/widgets/hover.py b/pygame_tools/widgets/hover.py new file mode 100644 index 0000000..254ebfb --- /dev/null +++ b/pygame_tools/widgets/hover.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.utils import * + + +class Hover: + """ + Used to execute a function when the mouse hovers over a rectangle. + """ + def __init__(self, rect: pygame.Rect, function=None, args: tuple=None): + """ + :param rect: A pygame.Rect, if the mouse hovers over this rectangle, the function gets executed. + :param function: The function that gets executed when the mouse hovers over the rect. + :param tuple args: A tuple that contains the arguments that will get passed to the function. + """ + + self.rect = rect + self.function = function + self.args = args + + self.active = True + + def check(self, mouse_pos: tuple): + if self.active: + mx, my = mouse_pos + + if self.rect.collidepoint((mx, my)): + if not self.function is None: + if self.args is None: + self.function() + + else: + self.function(*self.args) + + return True + + return False \ No newline at end of file diff --git a/pygame_tools/widgets/multiline_text.py b/pygame_tools/widgets/multiline_text.py new file mode 100644 index 0000000..6aaa988 --- /dev/null +++ b/pygame_tools/widgets/multiline_text.py @@ -0,0 +1,105 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.utils import * + + +class MultilineText: + """ + Creates a surface with text on it. + You can use "\\n" to create a newline. + When the max_width parameter is set, newlines generate automatically. + If you know the width of the widest character in your font, you can set the char_width parameter, + it will make the text creation a bit faster. + Use "surface.blit(multiline_text.surface, pos)" to draw it on a surface. + """ + def __init__(self, text: str, font: pygame.font.Font=default_font, color: tuple=white, max_width: int=None): + self.text = text + self.font = font + self.color = color + self.max_width = max_width + + self.surface = self.generate_surface() + + def generate_surface(self): + lines = [] + line = "" + + length = 1 + + if self.max_width is None: + for char in self.text: + if char == "\n": + lines.append(line) + length = 1 + line = "" + + else: + line += char + + length += 1 + + else: + for char in self.text: + if char == "\n": + lines.append(line) + + length = 1 + line = "" + + elif self.font.size(line)[0] >= self.max_width - 8: + if " " in line: + # remove last word + + words = line.split(" ") + + last_word = words[len(words) - 1] + words.pop(len(words) - 1) + + line = "" + + for word in words: # convert the list back to a string + line += word + " " + + line = line[:len(line) - 1] # remove last space character + + lines.append(line) + + line = last_word + char + + else: + lines.append(line) + + length = 1 + line = char + + else: + line += char + + length += 1 + + lines.append(line) + + texts = [] + + for line in lines: + texts.append(self.font.render(line, True, self.color)) + + if self.max_width is None: + w = max(texts, key=lambda t: t.get_width()).get_width() + + else: + w = self.max_width + + h = texts[0].get_height() + sh = h * len(lines) + + surface = pygame.Surface((w, sh), flags=pygame.SRCALPHA) + + x, y = 0, 0 + + for text in texts: + surface.blit(text, (x, y)) + + y += h + + return surface diff --git a/pygame_tools/widgets/text_button.py b/pygame_tools/widgets/text_button.py new file mode 100644 index 0000000..d1491d5 --- /dev/null +++ b/pygame_tools/widgets/text_button.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.utils import * +from wobbl_tools.pygame_tools.widgets import Button + + +class TextButton(pygame.sprite.Sprite): + """ + Creates a button from just some string and a position. + """ + def __init__( + self, + text: str, + position: tuple, + function=None, + args: tuple=None, + key: int=0, + text_color: tuple=white, + bg_color: tuple=gray, + font: pygame.font.Font=default_font, + padding: tuple=(8, 8), + border_radius: int=0, + line_thickness: int = 0 + ): + pygame.sprite.Sprite.__init__(self) + + self.text = text + self.position = position + self.text_color = text_color + self.font = font + self.function = function + self.args = args + self.key = key + self.bg_color = bg_color + self.padding = padding + self.border_radius = border_radius + self.line_thickness = line_thickness + + self.image, self.size = self.generate_surface() + self.rect = self.make_rect() + + self.button = Button(self.rect, self.function, args, self.key) + + def generate_surface(self): + text_object = self.font.render(self.text, True, self.text_color) + + w, h = text_object.get_size() + w, h = w + self.padding[0] * 2, h + self.padding[1] * 2 + + surface = pygame.Surface((w, h), pygame.SRCALPHA) + + pygame.draw.rect(surface, self.bg_color, pygame.Rect((0, 0), (w, h)), self.line_thickness, self.border_radius) + surface.blit(text_object, (self.padding[0], self.padding[1])) + + return surface, (w, h) + + def make_rect(self): + return pygame.Rect(self.position, self.size) + + def draw(self, surface: pygame.Surface): + surface.blit(self.image, self.position) + + def check(self, mouse_pos, pressed): + return self.button.check(mouse_pos, pressed) diff --git a/pygame_tools/widgets/text_input.py b/pygame_tools/widgets/text_input.py new file mode 100644 index 0000000..0080fef --- /dev/null +++ b/pygame_tools/widgets/text_input.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 + +from wobbl_tools.pygame_tools.utils import * + + +class TextInput: + """ + Creates an input object at a given position. + """ + + def __init__( + self, + position: Union[tuple, Callable], + surface: pygame.Surface, + width: int = None, + font: pygame.font.Font = default_font, + bg_color: tuple = (255, 255, 255), + text_color: tuple = black, + desc_text_color: tuple = light_gray, + desc_text: str = "", + default_text: str = "", + padding: tuple = (8, 8), + cursor_blink_interval: int = 30, + border_radius: int = -1, + max_length: int = 128 + ): + self.surface = surface + self.font = font + self.bg_color = bg_color + self.text_color = text_color + self.desc_text_color = desc_text_color + self.desc_text = desc_text + self.text = default_text + self.padding = padding + self.focused = True + self.cursor_blink_interval = cursor_blink_interval + self.ticks_til_blink = cursor_blink_interval + self.blink = False + self.border_radius = border_radius + self.max_length = max_length + self.cursor_position = len(default_text) + + sx, sy = surface.get_size() + + if width is None: + self.width = round(sx / 4) + + else: + self.width = width + + self.description_text_object = font.render(self.desc_text, True, self.desc_text_color) + self.text_object = font.render(self.text, True, self.text_color) + self.text_blink_object = font.render(self.text + "|", True, self.text_color) + + self.height = self.text_object.get_height() + + if type(position) is tuple: + self.position = position + + else: + self.position = position(size=self.size) + self.callable_position = position + + self.rect = self.generate_rect() + + def generate_rect(self): + x, y = self.position + px, py = self.padding + x -= px + y -= py + + return pygame.Rect((x, y), (self.width + px * 2, self.height + py * 2)) + + def blit(self): + pygame.draw.rect(self.surface, self.bg_color, self.rect, border_radius=self.border_radius) + + if self.focused: + if self.blink: + self.surface.blit(self.text_blink_object, self.position) + + else: + self.surface.blit(self.text_object, self.position) + + def loop(self): + """Call this function every tick to make the cursor blink.""" + + self.ticks_til_blink -= 1 + + if self.ticks_til_blink == -1: + self.ticks_til_blink = self.cursor_blink_interval + self.blink = not self.blink + + def keypress(self, event: pygame.event, pressed_keys, special_keys): + """ + Call this function when a key is pressed to get user input like this: + + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN: + TextInput.keypress(event, pygame.key.get_pressed(), pygame.key.get_mods()) + """ + + if self.max_length is None or len(self.text) <= self.max_length: + key_unicode = event.unicode + key = event.key + + if key < 32 or key > 101106 or special_keys & pygame.KMOD_CTRL or special_keys & pygame.KMOD_RCTRL or key > 126 and key < 161: + if key == pygame.K_BACKSPACE: + if self.cursor_position > 0: + self.text = text.rsap(self.text, "", self.cursor_position - 1) + self.cursor_position -= 1 + + elif key == pygame.K_LEFT: + if self.cursor_position > 0: + self.cursor_position -= 1 + + elif key == pygame.K_RIGHT: + if self.cursor_position < len(self.text): + self.cursor_position += 1 + + else: + self.text = text.asap(self.text, key_unicode, self.cursor_position) + self.cursor_position += 1 + + self.regenerate_objects() + + def regenerate_objects(self): + self.rect = self.generate_rect() + + self.text_object = self.font.render(self.text, True, self.text_color) + self.text_blink_object = self.font.render(text.asap(self.text, "|", self.cursor_position), True, + self.text_color) + + t_width, t_height = self.text_blink_object.get_size() + + if t_width > self.width: + self.text_blink_object = crop_surface(self.text_blink_object, + (t_width - (t_width - (t_width - self.width)), 0), + (t_width - (t_width - self.width), t_height)) + self.text_object = crop_surface(self.text_object, (t_width - (t_width - (t_width - self.width)), 0), + (t_width - (t_width - self.width), t_height)) diff --git a/text.py b/text.py index f83a980..41ae5d5 100644 --- a/text.py +++ b/text.py @@ -4,8 +4,12 @@ import random from wobbl_tools import buntcheck -def format_string(text: str, prefix: str = "§", suffix: str = "", - auto_rs: bool = True): # formats the text e.g. text after "§red" is colored red +def format_string( + text: str, + prefix: str = "§", + suffix: str = "", + auto_rs: bool = True +): # formats the text e.g. text after "§red" is colored red color_ansi = buntcheck.color_ansi for color in color_ansi: