Duncan Tourolle ad0ac238f3
Some checks failed
Python CI / test (push) Failing after 26s
all tests passing
2025-06-07 15:20:42 +02:00

178 lines
5.2 KiB
Python

# this should contain classes for how different object can be rendered, e.g. bold, italic, regular
from PIL import ImageFont
from enum import Enum
from typing import Tuple, Union, Optional
class FontWeight(Enum):
NORMAL = "normal"
BOLD = "bold"
class FontStyle(Enum):
NORMAL = "normal"
ITALIC = "italic"
class TextDecoration(Enum):
NONE = "none"
UNDERLINE = "underline"
STRIKETHROUGH = "strikethrough"
class Font:
"""
Font class to manage text rendering properties including font face, size, color, and styling.
This class is used by the text renderer to determine how to render text.
"""
def __init__(self,
font_path: Optional[str] = None,
font_size: int = 12,
colour: Tuple[int, int, int] = (0, 0, 0),
weight: FontWeight = FontWeight.NORMAL,
style: FontStyle = FontStyle.NORMAL,
decoration: TextDecoration = TextDecoration.NONE,
background: Optional[Tuple[int, int, int, int]] = None,
language = "en_EN"):
"""
Initialize a Font object with the specified properties.
Args:
font_path: Path to the font file (.ttf, .otf). If None, uses default font.
font_size: Size of the font in points.
colour: RGB color tuple for the text.
weight: Font weight (normal or bold).
style: Font style (normal or italic).
decoration: Text decoration (none, underline, or strikethrough).
background: RGBA background color for the text. If None, transparent background.
language: Language code for hyphenation and text processing.
"""
self._font_path = font_path
self._font_size = font_size
self._colour = colour
self._weight = weight
self._style = style
self._decoration = decoration
self._background = background if background else (255, 255, 255, 0)
self.language = language
# Load the font file or use default
self._load_font()
def _load_font(self):
"""Load the font using PIL's ImageFont"""
try:
if self._font_path:
self._font = ImageFont.truetype(
self._font_path,
self._font_size
)
else:
# Use default font
self._font = ImageFont.load_default()
if self._font_size != 12: # Default size might not be 12
self._font = ImageFont.truetype(self._font.path, self._font_size)
except Exception as e:
print(f"Error loading font: {e}")
self._font = ImageFont.load_default()
@property
def font(self):
"""Get the PIL ImageFont object"""
return self._font
@property
def font_size(self):
"""Get the font size"""
return self._font_size
@property
def colour(self):
"""Get the text color"""
return self._colour
@property
def color(self):
"""Alias for colour (American spelling)"""
return self._colour
@property
def background(self):
"""Get the background color"""
return self._background
@property
def weight(self):
"""Get the font weight"""
return self._weight
@property
def style(self):
"""Get the font style"""
return self._style
@property
def decoration(self):
"""Get the text decoration"""
return self._decoration
def with_size(self, size: int):
"""Create a new Font object with modified size"""
return Font(
self._font_path,
size,
self._colour,
self._weight,
self._style,
self._decoration,
self._background
)
def with_colour(self, colour: Tuple[int, int, int]):
"""Create a new Font object with modified colour"""
return Font(
self._font_path,
self._font_size,
colour,
self._weight,
self._style,
self._decoration,
self._background
)
def with_weight(self, weight: FontWeight):
"""Create a new Font object with modified weight"""
return Font(
self._font_path,
self._font_size,
self._colour,
weight,
self._style,
self._decoration,
self._background
)
def with_style(self, style: FontStyle):
"""Create a new Font object with modified style"""
return Font(
self._font_path,
self._font_size,
self._colour,
self._weight,
style,
self._decoration,
self._background
)
def with_decoration(self, decoration: TextDecoration):
"""Create a new Font object with modified decoration"""
return Font(
self._font_path,
self._font_size,
self._colour,
self._weight,
self._style,
decoration,
self._background
)