Skip to content

Commit

Permalink
Merge pull request #344 from MyreMylar/text_entry_box
Browse files Browse the repository at this point in the history
Adding a functional Text Entry Box
  • Loading branch information
MyreMylar authored Oct 30, 2022
2 parents 8964dea + 61aab4a commit ff02308
Show file tree
Hide file tree
Showing 24 changed files with 3,243 additions and 333 deletions.
8 changes: 7 additions & 1 deletion pygame_gui/core/drawable_shapes/drawable_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,14 @@ def build_text_layout(self):
max_dimensions=(text_actual_area_rect.width,
text_actual_area_rect.height))
text_chunk.should_centre_from_baseline = True
default_font_data = {"font": self.theming['font'],
"font_colour": (self.theming['normal_text']
if 'normal_text' in self.theming else
self.ui_manager.get_theme().get_colour('normal_text', None)),
"bg_colour": pygame.Color('#00000000')}
self.text_box_layout = TextBoxLayout(deque([text_chunk]), text_actual_area_rect,
self.text_view_rect, line_spacing=1.25)
self.text_view_rect, line_spacing=1.25,
default_font_data=default_font_data)
if 'selected_bg' in self.theming:
self.text_box_layout.selection_colour = self.theming['selected_bg']
if 'text_cursor_colour' in self.theming:
Expand Down
118 changes: 82 additions & 36 deletions pygame_gui/core/text/html_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,59 +160,86 @@ def _handle_shadow_tag(self, attributes, style):
shadow_offset = [0, 0]
shadow_colour = [50, 50, 50]
if 'size' in attributes:
shadow_size = int(attributes['size'])
if attributes['size'] is not None and len(attributes['size']) > 0:
try:
shadow_size = int(attributes['size'])
except ValueError or AttributeError:
shadow_size = 0

if 'offset' in attributes:
offset_str = attributes['offset'].split(',')
shadow_offset[0] = int(offset_str[0])
shadow_offset[1] = int(offset_str[1])
if attributes['offset'] is not None and len(attributes['offset']) > 0:
try:
offset_str = attributes['offset'].split(',')
if len(offset_str) == 2:
shadow_offset[0] = int(offset_str[0])
shadow_offset[1] = int(offset_str[1])
except ValueError or AttributeError:
shadow_offset = [0, 0]
if 'color' in attributes:
if attributes['color'][0] == '#':
shadow_colour = pygame.color.Color(attributes['color'])
else:
shadow_colour = self.ui_theme.get_colour_or_gradient(attributes['color'],
self.combined_ids)
try:
if self._is_legal_hex_colour(attributes['color']):
shadow_colour = pygame.color.Color(attributes['color'])
elif attributes['color'] is not None and len(attributes['color']) > 0:
shadow_colour = self.ui_theme.get_colour_or_gradient(attributes['color'],
self.combined_ids)
except ValueError or AttributeError:
shadow_colour = [50, 50, 50]

style['shadow_data'] = (shadow_size, shadow_offset[0],
shadow_offset[1], shadow_colour, False)

def _handle_font_tag(self, attributes, style):
if 'face' in attributes:
if 'face' in attributes and attributes['face'] is not None:
font_name = attributes['face'] if len(attributes['face']) > 0 else None
style["font_name"] = font_name
if 'pixel_size' in attributes:
if len(attributes['pixel_size']) > 0:
font_size = int(attributes['pixel_size'])
if attributes['pixel_size'] is not None and len(attributes['pixel_size']) > 0:
try:
font_size = int(attributes['pixel_size'])
except ValueError or AttributeError:
font_size = self.default_style['font_size']
else:
font_size = None
font_size = self.default_style['font_size']
style["font_size"] = font_size
elif 'size' in attributes:
if len(attributes['size']) > 0:
if float(attributes['size']) in self.font_sizes:
font_size = self.font_sizes[float(attributes['size'])]
else:
warnings.warn('Size of: ' + str(float(attributes['size'])) +
" - is not a supported html style size."
" Try .5 increments between 1 & 7 or use 'pixel_size' instead to "
"set the font size directly", category=UserWarning)
if attributes['size'] is not None and len(attributes['size']) > 0:
try:
if float(attributes['size']) in self.font_sizes:
font_size = self.font_sizes[float(attributes['size'])]
else:
warnings.warn('Size of: ' + str(float(attributes['size'])) +
" - is not a supported html style size."
" Try .5 increments between 1 & 7 or use 'pixel_size' instead to "
"set the font size directly", category=UserWarning)
font_size = self.default_style['font_size']
except ValueError or AttributeError:
font_size = self.default_style['font_size']
else:
font_size = None
font_size = self.default_style['font_size']
style["font_size"] = font_size
if 'color' in attributes:
if attributes['color'][0] == '#':
style["font_colour"] = pygame.color.Color(attributes['color'])
else:
style["font_colour"] = self.ui_theme.get_colour_or_gradient(attributes['color'],
self.combined_ids)
style["font_colour"] = self.default_style["font_colour"]
try:
if self._is_legal_hex_colour(attributes['color']):
style["font_colour"] = pygame.color.Color(attributes['color'])
elif attributes['color'] is not None and len(attributes['color']) > 0:
style["font_colour"] = self.ui_theme.get_colour_or_gradient(attributes['color'],
self.combined_ids)
except ValueError or AttributeError:
style["font_colour"] = self.default_style["font_colour"]

def _handle_body_tag(self, attributes, style):
if 'bgcolor' in attributes:
if len(attributes['bgcolor']) > 0:
if attributes['bgcolor'][0] == '#':
style["bg_colour"] = pygame.color.Color(attributes['bgcolor'])
else:
style["bg_colour"] = self.ui_theme.get_colour_or_gradient(
attributes['bgcolor'],
self.combined_ids)
if attributes['bgcolor'] is not None and len(attributes['bgcolor']) > 0:
try:
if self._is_legal_hex_colour(attributes['bgcolor']):
style["bg_colour"] = pygame.color.Color(attributes['bgcolor'])
else:
style["bg_colour"] = self.ui_theme.get_colour_or_gradient(
attributes['bgcolor'],
self.combined_ids)
except ValueError or AttributeError:
style["bg_colour"] = pygame.Color('#00000000')
else:
style["bg_colour"] = pygame.Color('#00000000')

Expand All @@ -225,7 +252,9 @@ def _handle_line_break(self):
dimensions = (current_font.get_rect(' ').width,
int(round(self.current_style['font_size'] *
self.line_spacing)))
self.layout_rect_queue.append(LineBreakLayoutRect(dimensions=dimensions))
chunk = self.create_styled_text_chunk('')
self.layout_rect_queue.append(LineBreakLayoutRect(dimensions=dimensions, font=current_font))
self.layout_rect_queue.append(chunk)

def _handle_p_tag(self):
if self.in_paragraph_block:
Expand All @@ -248,7 +277,7 @@ def _handle_img_tag(self, attributes):
image_float = TextFloatPosition.RIGHT
else:
image_float = TextFloatPosition.NONE
if 'padding' in attributes:
if 'padding' in attributes and isinstance(attributes['padding'], str):
paddings = attributes['padding'].split(' ')
for index, padding in enumerate(paddings):
paddings[index] = int(padding.strip('px'))
Expand All @@ -272,6 +301,11 @@ def _handle_img_tag(self, attributes):
padding_right = paddings[0]
padding_left = paddings[0]
padding_bottom = paddings[0]
else:
padding_top = 0
padding_right = 0
padding_left = 0
padding_bottom = 0
all_paddings = Padding(padding_top, padding_right, padding_bottom, padding_left)
self.layout_rect_queue.append(ImageLayoutRect(image_path,
image_float,
Expand Down Expand Up @@ -403,3 +437,15 @@ def create_styled_text_chunk(self, text: str):
text_shadow_data=self.current_style['shadow_data'],
effect_id=self.current_style['effect_id'])
return chunk

@staticmethod
def _is_legal_hex_colour(col):
if col is not None and len(col) > 0 and col[0] == '#':
if len(col) == 7 or len(col) == 9:
for col_index in range(1, len(col)):
col_letter = col[col_index]
if col_letter not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F']:
return False
return True
return False
19 changes: 17 additions & 2 deletions pygame_gui/core/text/line_break_layout_rect.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from typing import Tuple, Optional

import pygame
from pygame.surface import Surface
from pygame.rect import Rect
from pygame import Color

from pygame_gui.core.text.text_layout_rect import TextLayoutRect

Expand All @@ -13,8 +15,17 @@ class LineBreakLayoutRect(TextLayoutRect):
:param dimensions: The dimensions of the 'line break', the height is the important thing
so the new lines are spaced correctly for the last active font.
"""
def __init__(self, dimensions: Tuple[int, int]):
def __init__(self, dimensions: Tuple[int, int], font):
super().__init__(dimensions)
self.letter_count = 1
self.is_selected = False
self.selection_colour = Color(128, 128, 128, 255)
self.selection_chunk_width = 4
self.select_surf = None
self.font = font

def __repr__(self):
return "<LineBreakLayoutRect " + super().__repr__() + " >"

def finalise(self,
target_surface: Surface,
Expand All @@ -24,4 +35,8 @@ def finalise(self,
row_bg_height: int,
x_scroll_offset: int = 0,
letter_end: Optional[int] = None):
pass
if self.is_selected:
self.select_surf = Surface((self.selection_chunk_width, row_bg_height), flags=pygame.SRCALPHA)
self.select_surf.fill(self.selection_colour)
target_surface.blit(self.select_surf, self.topleft, special_flags=pygame.BLEND_PREMULTIPLIED)

2 changes: 1 addition & 1 deletion pygame_gui/core/text/simple_test_layout_rect.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def finalise(self,
surface.fill(self.colour)
target_surface.blit(surface, self, area=target_area)

def split(self, requested_x: int, line_width: int, row_start_x: int):
def split(self, requested_x: int, line_width: int, row_start_x: int, allow_split_dashes: bool = True):

if line_width < self.smallest_split_size:
raise ValueError('Line width is too narrow')
Expand Down
Loading

0 comments on commit ff02308

Please sign in to comment.