Source code for rubato.utils.font

"""The font module for text rendering"""
from typing import List, Literal
import sdl2, sdl2.sdlttf, sdl2.ext, sdl2.sdlgfx
from importlib.resources import files

from . import Color, Vector


[docs]class Font: """ This is the font object that is used to render text. Args: font: The font to use. Can also be a path to a font file. Defaults to Roboto. size: The size of the font. Defaults to 16. styles: The styles to apply to the font. Defaults to []. Fill with only the following: bold, italic, underline, strikethrough. color: The color of the font. Defaults to Color(0, 0, 0). """ _text_fonts = { "Comfortaa": "Comfortaa-Regular.ttf", "Fredoka": "Fredoka-Regular.ttf", "Merriweather": "Merriweather-Regular.ttf", "Roboto": "Roboto-Regular.ttf", "SourceCodePro": "SourceCodePro-Regular.ttf", "PressStart": "PressStart2P-Regular.ttf", } _text_styles = { "bold": sdl2.sdlttf.TTF_STYLE_BOLD, "italic": sdl2.sdlttf.TTF_STYLE_ITALIC, "underline": sdl2.sdlttf.TTF_STYLE_UNDERLINE, "strikethrough": sdl2.sdlttf.TTF_STYLE_STRIKETHROUGH, } def __init__( self, font: str | Literal["Comfortaa", "Fredoka", "Merriweather", "Roboto", "SourceCodePro", "PressStart"] = "Roboto", size: int = 16, styles: List[str] = [], color: Color = Color(0, 0, 0), ): self._size = size self._styles = styles self._color = color if font in Font._text_fonts: self._font_path = str(files("rubato.static.fonts").joinpath(Font._text_fonts[font])) else: self._font_path = font try: self._font = sdl2.ext.FontTTF(self._font_path, self._size, self._color.to_tuple()) except ValueError as e: raise FileNotFoundError(f"Font {font} cannot be found.") from e self.apply_styles() @property def size(self) -> int: """The size of the text in points.""" return self._size @size.setter def size(self, new: int): self._size = new sdl2.sdlttf.TTF_SetFontSize(self._font, new) @property def color(self) -> Color: """The color of the text.""" return self._color @color.setter def color(self, new: Color): self._color = new self._font = sdl2.ext.FontTTF(self._font_path, self._size, self._color.to_tuple())
[docs] def generate_surface( self, text: str, align: Vector = Vector(0, 0), width: int = 0, rot: int = 0 ) -> sdl2.SDL_Surface: """ Generate the surface containing the text. Args: text: The text to render. align: The alignment to use. Defaults to Vector(0, 0). width: The maximum width to use. Defaults to -1. rot: The rotation of the text in degrees. Defaults to 0. Raises: ValueError: The width is too small for the text. ValueError: The size of the text is too large for the font. Returns: sdl2.SDL_Surface: The surface containing the text. """ try: return sdl2.sdlgfx.rotozoomSurface( self._font.render_text(text, width=None if width <= 0 else width, align=align), rot, 1, 1 ) except RuntimeError as e: raise ValueError(f"The width {width} is too small for the text.") from e except OSError as e: raise ValueError(f"The size {self._size} is too big for the text.") from e
[docs] def add_style(self, style: str): """ Adds a style to the font. Args: style: The style to add. Can be one of the following: bold, italic, underline, strikethrough. """ if style in Font._text_styles and style not in self._styles: self._styles.append(style) self.apply_styles() else: raise ValueError(f"Style {style} is not valid or is already applied.")
[docs] def remove_style(self, style: str): """ Removes a style from the font. Args: style: The style to remove. Can be one of the following: bold, italic, underline, strikethrough. """ if style in self._styles: self._styles.remove(style) self.apply_styles() else: raise ValueError(f"Style {style} is not currently applied.")
[docs] def apply_styles(self): """Applies the styles to the font.""" s = 0x00 for style in self._styles: s |= Font._text_styles[style] sdl2.sdlttf.TTF_SetFontStyle(self._font.get_ttf_font(), s)