from __future__ import annotations
from typing import Optional
from neoscore.core import neoscore
from neoscore.core.font import Font
from neoscore.core.layout_controllers import NewLine
from neoscore.core.point import ORIGIN, Point, PointDef
from neoscore.core.positioned_object import PositionedObject
from neoscore.core.units import ZERO, Unit
from neoscore.interface.rich_text_interface import RichTextInterface
[docs]class RichText(PositionedObject):
"""A graphical rich text object.
Unlike its simpler counterpart in ``Text``, this supports rich
formatting with HTML input. As neoscore is currently backed by Qt,
this input supports Qt's HTML subset documented at
https://doc.qt.io/qt-5/richtext-html-subset.html
"""
[docs] def __init__(
self,
pos: PointDef,
parent: Optional[PositionedObject],
html_text: str,
width: Optional[Unit] = None,
font: Optional[Font] = None,
scale: float = 1,
rotation: float = 0,
transform_origin: PointDef = ORIGIN,
):
"""
Args:
pos: Position relative to the parent
parent: The parent (core-level) object or None
html_text: The text to be displayed, written in HTML.
width: The maximum width for the displayed text. If omitted,
lines will only break when explicitly called for by the HTML.
font: The default font to display the text in.
scale: A scaling factor relative to the font size.
rotation: Rotation angle in degrees.
transform_origin: The origin point for rotation and scaling transforms
"""
super().__init__(pos, parent)
if font:
self._font = font
else:
self._font = neoscore.default_font
self._html_text = html_text
self._width = width
self._scale = scale
self._rotation = rotation
self.transform_origin = transform_origin
@property
def breakable_length(self) -> Unit:
"""The breakable length of the object.
This is always 0, meaning RichText objects cannot be broken
across Flowable lines.
"""
return ZERO
@property
def html_text(self) -> str:
"""The text to be displayed, written in HTML."""
return self._html_text
@html_text.setter
def html_text(self, value: str):
self._html_text = value
@property
def width(self) -> Optional[Unit]:
"""The maximum width for the displayed text.
If omitted, lines will only break when explicitly called for
by the HTML.
"""
return self._width
@width.setter
def width(self, value: Optional[Unit]):
self._width = value
@property
def font(self) -> Font:
"""The default font used to display the text.
HTML markup can override this to different styles and famililes.
"""
return self._font
@font.setter
def font(self, value: Font):
self._font = value
# Since RichText isn't breakable (for now?), we only need to
# implement complete rendering
[docs] def render_complete(
self,
pos: Point,
flowable_line: Optional[NewLine] = None,
flowable_x: Optional[Unit] = None,
):
interface = RichTextInterface(
pos,
None if flowable_line else self.parent.interface_for_children,
self.scale,
self.rotation,
self.transform_origin,
self.html_text,
self.font.interface,
self.width,
)
interface.render()
self.interfaces.append(interface)