"""A text component."""
from __future__ import annotations
from typing import Literal
import sdl2, sdl2.ext
from .. import Component
from .... import Vector, Font, Draw, Camera, Surface
[docs]class Text(Component):
"""
A text component. Add this to game objects or UI elements to give them text. Takes a font object to render the text.
Args:
text: The text to display. Defaults to "".
font: The font to use. Defaults to Font().
justify: The justification of the text. Defaults to "left".
anchor: The anchor of the text. The zero vector means it is centered. x component is whether to shift left,
none, or right (-1, 0, 1). y component is whether to shift top, none, or bottom (-1, 0, 1).
Defaults to Vector(0, 0).
width: The width of the text. Defaults to 0.
af: Whether to use anisotropic filtering. Defaults to True.
offset: The offset of the text from the game object. Defaults to Vector(0, 0).
rot_offset: The rotation offset of the text from the game object. Defaults to 0.
z_index: The z index of the text. Defaults to 0.
hidden: Whether the text is hidden. Defaults to False.
"""
def __init__(
self,
text: str = "",
font: Font = Font(),
justify: Literal["left", "center", "right"] = "left",
anchor: Vector | tuple[float, float] = (0, 0),
width: int = 0,
af: bool = True,
offset: Vector | tuple[float, float] = (0, 0),
rot_offset: float = 0,
z_index: int = 0,
hidden: bool = False,
):
super().__init__(offset=offset, rot_offset=rot_offset, z_index=z_index, hidden=hidden)
self._text: str = text
self.font_object: Font = font
self.anchor: Vector = Vector.create(anchor)
"""
The anchor vector of the text.
This controls the position of the text relative to the game object. Is a vector where the x value
controls the x anchor and the y value controls the y anchor. The values for each can be either -1, 0 or 1. This
offset the text around the game object center.
Example:
An anchor of ``Vector(0, 0)`` will center the text on the game object. An anchor of ``Vector(1, 1)`` will
move the text so that it's top left corner is at the game object's center.
"""
self._justify: Literal["left", "center", "right"] = justify
self._width: int = width
self._af = af
if not self.font_object:
self.font_object = Font()
self._uptodate = False
self._font = self.font_object._font
self._size = self.font_object._size
self._color = self.font_object._color.clone()
self._styles = self.font_object._styles
@property
def af(self) -> bool:
"""Whether to use anisotropic filtering."""
return self._af
@af.setter
def af(self, new: bool):
self._af = new
self._uptodate = False
@property
def text(self) -> str:
"""The text of the Text."""
return self._text
@text.setter
def text(self, new: str):
self._text = new
self._uptodate = False
@property
def justify(self) -> Literal["left", "center", "right"]:
"""
The justification of the text.
Can be one of: ``"left"``, ``"center"``, ``"right"``.
"""
return self._justify
@justify.setter
def justify(self, new: Literal["left", "center", "right"]):
if new not in ["left", "center", "right"]:
raise ValueError(f"Justification {new} is not left, center or right.")
self._justify = new
self._uptodate = False
@property
def width(self) -> int:
"""The maximum width of the text. Will automatically wrap the text. Use -1 to disable wrapping."""
return self._width
@width.setter
def width(self, new: int):
self._width = new
self._uptodate = False
def _regen(self):
"""(Re)generates the surface of the text."""
surf = self.font_object._generate(
self._text,
self._justify,
self._width,
)
self._surf = Surface._from_surf(surf, af=self._af)
sdl2.SDL_FreeSurface(surf)
[docs] def update(self):
# For developer: We need to check if the font object has changed compared to what we are rendering,
# but a font object can be shared between different texts.
if self._font != self.font_object._font or self._size != self.font_object._size or \
self._color != self.font_object._color or self._styles != self.font_object._styles:
self._font = self.font_object._font
self._size = self.font_object._size
self._color = self.font_object._color
self._styles = self.font_object._styles
self._uptodate = False
if not self._uptodate:
self._regen()
self._uptodate = True
[docs] def draw(self, camera: Camera):
if hasattr(self, "_surf"):
self._surf.rotation = self.true_rotation()
Draw.queue_surface(
self._surf,
self.true_pos() + self.anchor * self._surf.size_scaled() / 2,
self.true_z(),
camera,
)
[docs] def clone(self) -> Text:
"""Clones the text component."""
return Text(
text=self._text,
font=self.font_object.clone(),
anchor=self.anchor.clone(),
justify=self._justify,
width=self._width,
offset=self.offset.clone(),
rot_offset=self.rot_offset,
z_index=self.z_index,
)