Skip to content

Commit 071bbcc

Browse files
committed
Redocument FontManager & improve error handling
1 parent 04c499c commit 071bbcc

File tree

2 files changed

+128
-100
lines changed

2 files changed

+128
-100
lines changed

doc/modules/ext/ttf.rst

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,7 @@
11
.. currentmodule:: sdl2.ext
22

3-
Text rendering routines
4-
=======================
3+
`sdl2.ext.ttf` - Rendering Text With TrueType Fonts
4+
===================================================
55

6-
.. class:: FontManager(font_path : str[, alias=None[, size=16[, color=Color(255, 255, 255)[, bg_color=Color(0, 0, 0)[, index=0]]]]])
7-
8-
Manage fonts and rendering of text.
9-
10-
One font path must be given to initialise the FontManager.
11-
:attr:`default_font` will be set to this font. *size* is the default
12-
font size in pixels. *color* and *bg_color* will give the FontManager
13-
a default color. *index* will select a specific font face from a file
14-
containing multiple font faces. The first face is always at index 0. It can
15-
be used for TTC (TrueType Font Collection) fonts.
16-
17-
.. attribute:: bg_color
18-
19-
The :class:`sdl2.ext.Color` to be used as background color.
20-
21-
.. attribute:: color
22-
23-
The :class:`sdl2.ext.Color` to be used for rendering text.
24-
25-
.. attribute:: default_font
26-
27-
Returns the name of the current default font being used by the
28-
:class:`FontManager`. On assigning :attr:`default_font`,
29-
the value must be a loaded font alias.
30-
31-
.. attribute:: size
32-
33-
The default font size in pixels.
34-
35-
.. method:: add(font_path : str[, alias=None[, size=None[, index=0]]])) -> sdl2.sdlttf.TTF_Font
36-
37-
Add a font to the :class:`FontManager`. *alias* is by default the
38-
font name, any other name can be passed, *size* is the font size
39-
in pixels and defaults to :attr:`size`. *index* selects a specific font
40-
face from a TTC (TrueType Font Collection) file. Returns the font pointer
41-
stored in :attr:`fonts`.
42-
43-
.. method:: close()
44-
45-
Closes all fonts used by the :class:`FontManager`.
46-
47-
.. method:: render(text : str[, alias=None[, size=None[, width=None[, color=None[, bg_color=None[, **kwargs]]]]]]) -> sdl2.SDL_Surface
48-
49-
Renders text to a surface. This method uses the font designated by
50-
the passed *alias* or, if *alias* is omitted, by the set
51-
:attr:`default_font`. A *size* can be passed even if the font was
52-
not loaded with this size. A *width* can be given for automatic line
53-
wrapping. If no *bg_color* or *color* are given, it will default to
54-
the FontManager's :attr:`bg_color` and :attr:`color`.
6+
.. automodule:: sdl2.ext.ttf
7+
:members:

sdl2/ext/ttf.py

Lines changed: 124 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
"""Font and text rendering routines."""
21
import os
32
from .. import surface, pixels
4-
from .common import SDLError
3+
from .common import raise_sdl_err
54
from .compat import *
65
from .color import Color, convert_to_color
76
from .draw import prepare_color
7+
from .resources import _validate_path
88

99
_HASSDLTTF = True
1010
try:
@@ -16,26 +16,79 @@
1616
__all__ = ["FontManager"]
1717

1818

19+
def _ttf_init():
20+
if not _HASSDLTTF:
21+
raise RuntimeError("SDL_ttf is required, but is not installed.")
22+
23+
# Check if TTF already initialized, return immediately if it was
24+
if sdlttf.TTF_WasInit() > 0:
25+
return
26+
27+
# Handle a weirdness in how TTF_Init and TTF_Quit work: TTF_Init
28+
# blindly increments TTF_WasInit every time it's called and TTF_Quit
29+
# blindly decrements it, but TTF_Quit only *actually* quits when
30+
# TTF_WasInit - 1 == 0. Here, we try to ensure we're starting at 0.
31+
while sdlttf.TTF_WasInit() < 1:
32+
ret = sdlttf.TTF_Init()
33+
if ret != 0:
34+
raise_sdl_err("initializing the SDL_ttf library")
35+
36+
37+
def _ttf_quit():
38+
if not _HASSDLTTF:
39+
raise RuntimeError("SDL_ttf is required, but is not installed.")
40+
41+
# Make sure WasInit is non-negative before trying to quit
42+
while sdlttf.TTF_WasInit() < 1:
43+
ret = sdlttf.TTF_Init()
44+
if ret != 0:
45+
raise_sdl_err("initializing the SDL_ttf library")
46+
47+
# Actually quit the library (won't really quit until TTF_WasInit == 0)
48+
while sdlttf.TTF_WasInit > 0:
49+
sdlttf.TTF_Quit()
50+
51+
52+
1953
class FontManager(object):
20-
"""Manage fonts and rendering of text."""
54+
"""A class for managing and rendering TrueType fonts.
55+
56+
.. note::
57+
This class is has been deprecated in favor of the more flexible
58+
:class:`~sdl2.ext.FontTTF` class.
59+
60+
This class provides a basic wrapper around the SDL_ttf library. One font
61+
path must be given to initialise the FontManager.
62+
63+
The first face is always at index 0. It can be used for TTC (TrueType Font
64+
Collection) fonts.
65+
66+
Args:
67+
font_path (str): The relative (or absolute) path to the font
68+
to load.
69+
alias (str, optional): The name to give the font within the
70+
FontManager. Defaults to the font filename if not specified.
71+
size (int, optional): The size (in pt) at which to load the default
72+
font. Defaults to 16pt if not specified.
73+
color (~sdl2.ext.Color): The default font rendering color. Defaults
74+
to opaque white if not specified.
75+
bg_color (~sdl2.ext.Color, optional): The default background surface
76+
color. Defaults to a fully-transparent background if not specified.
77+
index (int, optional): The index of the font face to load if the
78+
font file contains multiple faces. Defaults to 0 (first face in
79+
the file) if not specified.
80+
81+
Attributes:
82+
size (int): The default font size in pt.
83+
84+
"""
2185
def __init__(self, font_path, alias=None, size=16,
2286
color=Color(255, 255, 255), bg_color=Color(0, 0, 0), index=0):
23-
"""Initialize the FontManager
24-
25-
One font path must be given to initialize the FontManager. The
26-
default_font will be set to this font. color and bg_color
27-
will give the FontManager a default color. size is the default
28-
font size in pixels.
29-
"""
30-
if not _HASSDLTTF:
31-
raise UnsupportedError(FontManager,
32-
"FontManager requires sdlttf support")
33-
if sdlttf.TTF_WasInit() == 0 and sdlttf.TTF_Init() != 0:
34-
raise SDLError()
87+
_ttf_init()
3588
self.fonts = {} # fonts = {alias: {size:font_ptr}}
3689
self.aliases = {} # aliases = {alias:font_path}
37-
self._textcolor = pixels.SDL_Color(0, 0, 0)
38-
self._bgcolor = pixels.SDL_Color(255, 255, 255)
90+
self._textcolor = None
91+
self._bgcolor = None
3992
self.color = color
4093
self.bg_color = bg_color
4194
self.size = size
@@ -46,7 +99,7 @@ def __del__(self):
4699
self.close()
47100

48101
def close(self):
49-
"""Close all opened fonts."""
102+
"""Closes all fonts opened by the class."""
50103
for alias, fonts in self.fonts.items():
51104
for size, font in fonts.items():
52105
if font:
@@ -55,10 +108,23 @@ def close(self):
55108
self.aliases = {}
56109

57110
def add(self, font_path, alias=None, size=None, index=0):
58-
"""Add a font to the Font Manager.
111+
"""Adds a font to the :class:`FontManager`.
112+
113+
Args:
114+
font_path (str): The relative (or absolute) path to the font
115+
to load.
116+
alias (str, optional): The name to give the font within the
117+
FontManager. Defaults to the font filename if not specified.
118+
size (int, optional): The size (in pt) at which to load the font.
119+
Defaults to the FontManager's default size if not specified.
120+
index (int, optional): The index of the font face to load if the
121+
font file contains multiple faces. Defaults to 0 (first face in
122+
the file) if not specified.
123+
124+
Returns:
125+
:obj:`~sdl2.sdlttf.TTF_Font`: A pointer to the ctypes font object
126+
for the added font.
59127
60-
alias is by default the font name. But another name can be
61-
passed. Returns the font pointer stored in self.fonts.
62128
"""
63129
size = size or self.size
64130
if alias is None:
@@ -87,13 +153,11 @@ def _load_font(self, font_path, size, index=0):
87153
88154
Raises an exception if something went wrong.
89155
"""
90-
if index == 0:
91-
font = sdlttf.TTF_OpenFont(byteify(font_path, "utf-8"), size)
92-
else:
93-
font = sdlttf.TTF_OpenFontIndex(byteify(font_path, "utf-8"), size,
94-
index)
156+
fullpath, fname = _validate_path(font_path, "a font")
157+
fullpath = byteify(fullpath)
158+
font = sdlttf.TTF_OpenFontIndex(fullpath, size, index)
95159
if not font:
96-
raise SDLError(sdlttf.TTF_GetError())
160+
raise_sdl_err("opening the font '{0}'".format(fname))
97161
return font
98162

99163
def _change_font_size(self, alias, size):
@@ -105,43 +169,39 @@ def _change_font_size(self, alias, size):
105169

106170
@property
107171
def color(self):
108-
"""The text color to be used."""
109-
return Color(self._textcolor.r, self._textcolor.g, self._textcolor.b,
110-
self._textcolor.a)
172+
""":obj:`~sdl2.ext.Color`: The color to use for rendering text."""
173+
c = self._textcolor
174+
return Color(c.r, c.g, c.b, c.a)
111175

112176
@color.setter
113177
def color(self, value):
114-
"""The text color to be used."""
115178
c = convert_to_color(value)
116179
self._textcolor = pixels.SDL_Color(c.r, c.g, c.b, c.a)
117180

118181
@property
119182
def bg_color(self):
120-
"""The background color to be used."""
121-
return Color(self._bgcolor.r, self._bgcolor.g, self._bgcolor.b,
122-
self._bgcolor.a)
183+
""":obj:`~sdl2.ext.Color`: The background color to use for rendering."""
184+
c = self._bgcolor
185+
return Color(c.r, c.g, c.b, c.a)
123186

124187
@bg_color.setter
125188
def bg_color(self, value):
126-
"""The background color to be used."""
127189
c = convert_to_color(value)
128190
self._bgcolor = pixels.SDL_Color(c.r, c.g, c.b, c.a)
129191

130192
@property
131193
def default_font(self):
132-
"""Returns the name of the current default_font."""
194+
"""str: The name of the default font. Must be set to the alias of a
195+
currently-loaded font.
196+
197+
"""
133198
for alias in self.fonts:
134199
for size, font in self.fonts[alias].items():
135200
if font == self._default_font:
136201
return alias
137202

138203
@default_font.setter
139204
def default_font(self, value):
140-
"""value must be a font alias
141-
142-
Set the default_font to the given font name alias,
143-
provided it's loaded in the font manager.
144-
"""
145205
alias = value
146206
size = self.size
147207
if alias not in self.fonts:
@@ -156,11 +216,26 @@ def render(self, text, alias=None, size=None, width=None, color=None,
156216
bg_color=None, **kwargs):
157217
"""Renders text to a surface.
158218
159-
This method uses the font designated by the alias or the
160-
default_font. A size can be passed even if the font was not
161-
loaded with this size. A width can be given for line wrapping.
162-
If no bg_color or color are given, it will default to the
163-
FontManager's bg_color and color.
219+
Args:
220+
text (str): The text to render.
221+
alias (str, optional): The alias of the font to use for rendering
222+
the text. Defaults to the FontManager's default font if not
223+
specified.
224+
size (int, optional): The size (in pt) at which to render the font.
225+
Defaults to the FontManager's default size if not specified.
226+
width (int, optional): The width (in pixels) of the output surface.
227+
If a line of text exceeds this value, it will be automatically
228+
wrapped to fit within the specified width. Defaults to ``None``.
229+
color (~sdl2.ext.Color): The font rendering color. Defaults to the
230+
FontManager's default color if not specified.
231+
bg_color (~sdl2.ext.Color, optional): The background surface color.
232+
Defaults to the FontManager's default background color if not
233+
specified.
234+
235+
Returns:
236+
:obj:`~sdl2.SDL_Surface`: A 32-bit ARGB surface containing the
237+
rendered text.
238+
164239
"""
165240
alias = alias or self.default_font
166241
size = size or self.size
@@ -187,7 +262,7 @@ def render(self, text, alias=None, size=None, width=None, color=None,
187262
fontsf = sdlttf.TTF_RenderUTF8_Blended_Wrapped(font, text, color,
188263
width)
189264
if not fontsf:
190-
raise SDLError(sdlttf.TTF_GetError())
265+
raise_sdl_err("rendering the text")
191266
if bg_color != pixels.SDL_Color(0, 0, 0):
192267
fontsf = fontsf.contents
193268
w, h = fontsf.w, fontsf.h
@@ -196,7 +271,7 @@ def render(self, text, alias=None, size=None, width=None, color=None,
196271
bgsf = surface.SDL_CreateRGBSurfaceWithFormat(0, w, h, bpp, fmt)
197272
if not bgsf:
198273
surface.SDL_FreeSurface(fontsf)
199-
raise SDLError()
274+
raise_sdl_err("creating the background surface")
200275
bg_color = prepare_color(bg_color, bgsf.contents)
201276
surface.SDL_FillRect(bgsf, None, bg_color)
202277
surface.SDL_BlitSurface(fontsf, None, bgsf, None)
@@ -209,5 +284,5 @@ def render(self, text, alias=None, size=None, width=None, color=None,
209284
sf = sdlttf.TTF_RenderUTF8_Shaded(font, text, color,
210285
bg_color)
211286
if not sf:
212-
raise SDLError(sdlttf.TTF_GetError())
287+
raise_sdl_err("rendering the text")
213288
return sf.contents

0 commit comments

Comments
 (0)