Quellcode für miniworlds.actors.texts.textbox

from typing import Tuple
import miniworlds.actors.parent_actor as parent_actor
import miniworlds.actors.texts.text as text
import miniworlds.actors.shapes.shapes as shapes
import miniworlds.base.api_validation as api_validation


def _ensure_real(value, parameter_name: str) -> None:
    api_validation.ensure_real(
        value,
        parameter_name,
        api_validation.with_try_hint,
        f"{parameter_name} = 100",
    )


def _ensure_position(value, parameter_name: str = "position") -> None:
    api_validation.ensure_position_tuple(
        value,
        parameter_name,
        _ensure_real,
        api_validation.with_try_hint,
    )


[Doku] class TextBox(parent_actor.ParentActor): """A multi-line text box with fixed width and height. Long lines are automatically word-wrapped to fit within the given width. Each line is rendered as a separate `Text` actor. Args: position: Top-left position of the text box. width: Width of the text box in pixels. height: Maximum height of the text box in pixels. text: Initial text to display (keyword argument). font_size: Font size for all lines (keyword argument, default 18). border: If truthy, a rectangle outline is drawn around the box. Examples: :: box = TextBox((10, 10), 380, 200, text="Hello World!") box.font_size = 16 """
[Doku] def __init__( self, position: Tuple[float, float], width: float, height: float, **kwargs ): """Creates a text box with fixed width and height. Args: position: Top-left position of the text box. width: Maximum width in pixels before text is wrapped. height: Maximum height in pixels. border: Optional keyword argument. If truthy, draw a rectangle around the text box. font_size: Optional keyword argument. Font size used for all lines. """ _ensure_position(position) _ensure_real(width, "width") _ensure_real(height, "height") if width <= 0: raise ValueError(f"width must be > 0, got {width}") if height <= 0: raise ValueError(f"height must be > 0, got {height}") super().__init__(position) self._visible: bool = False self.line_width = width self.lines_height = height text = kwargs.get("text") self.text = text if text else "" self.position = position font_size = kwargs.get("font_size") self.font_size = 18 if not font_size else font_size self.create_line_actors() border = kwargs.get("border") if border: shapes.Rectangle(position, width, height)
[Doku] def create_line(self, position, txt="") -> text.Text: """Create a single `Text` actor for one rendered line. Args: position: Top-left position of the line. txt: Text content of the line. Returns: The created text actor. """ lineText = text.Text(position, txt) if self.font_size != 0: lineText.font_size = self.font_size lineText.topleft = position return lineText
[Doku] def create_line_actors(self): """Build visible text lines for the current text box content. The text is split line by line and then wrapped after words so that no rendered line becomes wider than `self.line_width`. Each line is stored as a child `Text` actor. Examples: :: box.text = "New text" box.create_line_actors() """ dummy = self.create_line((0, 0)) font = dummy.costume.font_manager.font words = [ line.split(" ") for line in self.text.splitlines() ] # 2D array where each row is a list of words. x, y = self.position for line in words: line_text = "" for word in line: old_text = line_text line_text = line_text + word word_size = font.size(line_text) word_width, word_height = word_size if x + word_width >= self.line_width: line_actor = self.create_line((x, y), old_text) self.children.add(line_actor) x = self.position[0] y += word_height # Start on new row. line_text = word line_text += " " if y > self.lines_height: break line_actor = self.create_line((x, y), line_text) self.children.add(line_actor) x = self.position[0] # Reset the x. y += line_actor.height # Start on new row dummy.remove()