Skip to content
2 changes: 2 additions & 0 deletions arcade/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ def configure_logging(level: Optional[int] = None):
from .text import (
draw_text,
load_font,
create_text_texture,
create_text_sprite,
Text,
)
Expand Down Expand Up @@ -331,6 +332,7 @@ def configure_logging(level: Optional[int] = None):
'get_sprites_at_point',
'SpatialHash',
'get_timings',
'create_text_texture',
'create_text_sprite',
'clear_timings',
'get_window',
Expand Down
111 changes: 84 additions & 27 deletions arcade/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from arcade.types import Color, Point, RGBA255
from arcade.resources import resolve
from arcade.utils import PerformanceWarning, warning

from warnings import warn

def load_font(path: Union[str, Path]) -> None:
"""
Expand Down Expand Up @@ -569,8 +569,7 @@ def position(self, point: Point):
self._label.position = *point, self._label.z


def create_text_sprite(
text: str,
def create_text_texture(text: str,
color: RGBA255 = arcade.color.WHITE,
font_size: float = 12,
width: int = 0,
Expand All @@ -580,17 +579,13 @@ def create_text_sprite(
italic: bool = False,
anchor_x: str = "left",
multiline: bool = False,
texture_atlas: Optional[arcade.TextureAtlas] = None,
) -> arcade.Sprite:
texture_atlas: Optional[arcade.TextureAtlas] = None):
"""
Creates a sprite containing text based off of :py:class:`~arcade.Text`.

Internally this creates a Text object and an empty texture. It then uses either the
provided texture atlas, or gets the default one, and draws the Text object into the
texture atlas.
Creates a texture containing text based off of :py:class:`~pyglet.text.Label`.

It then creates a sprite referencing the newly created texture, and positions it
accordingly, and that is final result that is returned from the function.
Internally this creates a :py:class:`~pyglet.text.Label` object and an empty texture. It then uses either the
provided texture atlas, or gets the default one, and draws the `~pyglet.text.Label` object into the
texture atlas. Then it returns the texture.

If you are providing a custom texture atlas, something important to keep in mind is
that the resulting Sprite can only be added to SpriteLists which use that atlas. If
Expand All @@ -611,40 +606,102 @@ def create_text_sprite(
:param Optional[arcade.TextureAtlas] texture_atlas: The texture atlas to use for the
newly created texture. The default global atlas will be used if this is None.
"""
text_object = Text(
text,
start_x=0,
start_y=0,
color=color,

if align != "center" and align != "left" and align != "right":
raise ValueError("The 'align' parameter must be equal to 'left', 'right', or 'center'.")

adjusted_font = _attempt_font_name_resolution(font_name)
_label = pyglet.text.Label(
text=text,
font_name=adjusted_font,
font_size=font_size,
anchor_x=anchor_x,
color=Color.from_iterable(color),
width=width,
align=align,
font_name=font_name,
bold=bold,
italic=italic,
anchor_x=anchor_x,
anchor_y="baseline",
multiline=multiline,
)
group=None,
)

if not _label.content_width or not _label.content_height:
warn("Either width or height is 0")
return arcade.Texture.create_empty(text, (0, 0))
size = (
int(text_object.right - text_object.left),
int(text_object.top - text_object.bottom),
int(_label.content_width),
int(_label.content_height),
)
text_object.y = -text_object.bottom

texture = arcade.Texture.create_empty(text, size)

if not texture_atlas:
texture_atlas = arcade.get_window().ctx.default_atlas
texture_atlas.add(texture)
with texture_atlas.render_into(texture) as fbo:
fbo.clear((0, 0, 0, 255))
text_object.draw()
_draw_pyglet_label(_label)
return texture


def create_text_sprite(
text: str,
color: RGBA255 = arcade.color.WHITE,
font_size: float = 12,
width: int = 0,
align: str = "left",
font_name: FontNameOrNames = ("calibri", "arial"),
bold: bool = False,
italic: bool = False,
anchor_x: str = "left",
multiline: bool = False,
texture_atlas: Optional[arcade.TextureAtlas] = None,
) -> arcade.Sprite:
"""
Creates a sprite containing text based off of :py:func:`create_text_texture`.

Internally this calls the create_text_texture function and gives it the relevant information.
When it is done, the create_text_texture function returns a texture.

The create_text_sprite then creates a sprite referencing the newly created texture, and positions it
accordingly, and that is final result that is returned from the function.

If you are providing a custom texture atlas, something important to keep in mind is
that the resulting Sprite can only be added to SpriteLists which use that atlas. If
it is added to a SpriteList which uses a different atlas, you will likely just see
a black box drawn in its place.

:param str text: Initial text to display. Can be an empty string
:param RGBA255 color: Color of the text as a tuple or list of 3 (RGB) or 4 (RGBA) integers
:param float font_size: Size of the text in points
:param float width: A width limit in pixels
:param str align: Horizontal alignment; values other than "left" require width to be set
:param FontNameOrNames font_name: A font name, path to a font file, or list of names
:param bool bold: Whether to draw the text as bold
:param bool italic: Whether to draw the text as italic
:param str anchor_x: How to calculate the anchor point's x coordinate.
Options: "left", "center", or "right"
:param bool multiline: Requires width to be set; enables word wrap rather than clipping
:param Optional[arcade.TextureAtlas] texture_atlas: The texture atlas to use for the
newly created texture. The default global atlas will be used if this is None.
"""

texture = create_text_texture(text,
color = color,
font_size = font_size,
width = width,
align = align,
font_name = font_name,
bold = bold,
italic = italic,
anchor_x = anchor_x,
multiline = multiline,
texture_atlas = texture_atlas)
size = texture._size
return arcade.Sprite(
texture,
center_x=text_object.right - (size[0] / 2),
center_y=text_object.top,
center_x=size[0]/2,
center_y=size[1],
)


Expand Down
3 changes: 0 additions & 3 deletions tests/unit/text/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,3 @@ def new_text(*args, **kwargs) -> None:

window.flip()


# def test_create_text_sprite(window):
# pass
9 changes: 7 additions & 2 deletions tests/unit/text/test_text_sprite.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import pytest
import arcade

def test_text_texture(window):
texture = arcade.create_text_texture("Hello World")
assert isinstance(texture, arcade.Texture)
assert texture.width == pytest.approx(80, rel=10)
assert texture.height == pytest.approx(20, rel=5)

def test_create(window):
def test_text_sprite(window):
sprite = arcade.create_text_sprite("Hello World")
assert isinstance(sprite, arcade.Sprite)
assert sprite.width == pytest.approx(75, rel=10)
assert sprite.width == pytest.approx(80, rel=10)
assert sprite.height == pytest.approx(20, rel=5)