Skip to content

Commit f8e8189

Browse files
authored
Add the FontTTF bindings for the TTF API (#210)
* Add new FontTTF class * Try a workaround for old TTF versions * Revert FontTTF RW changes * Last-ditch effort to fix tests on old win64 DLLs * Try adding faulthandler for pypy-3.7 * Whoops * Enforce GC on font and sprite tests, try pypy fix * Check whether test or sprite changes fixed pypy * Keep track of ttf de-init to avoid segfaults * Revert custom PyPy CI config * Fix empty lines and unicode input * Allow specifying line heights as percentages * Add FontTTF rendering example * Add experimental support for RWops fonts
1 parent d549fc5 commit f8e8189

File tree

8 files changed

+936
-49
lines changed

8 files changed

+936
-49
lines changed

.github/workflows/run_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
python -m pip install --upgrade pip
5353
python -m pip install numpy pytest pillow
5454
python -m pip install pysdl2-dll
55-
55+
5656
- name: Install and test PySDL2
5757
run: |
5858
python -m pip install .

doc/modules/ext/ttf.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,14 @@
33
`sdl2.ext.ttf` - Rendering Text With TrueType Fonts
44
===================================================
55

6+
The :mod:`sdl2.ext.ttf` module provides the :class:`~sdl2.ext.FontTTF` class,
7+
which provides a friendly and Pythonic API for font rendering based around
8+
the **SDL_ttf** library. **SDL_ttf** can be installed as a Python dependency
9+
with ``pysdl2-dll`` on platforms that support it).
10+
11+
Additionally, this module provides the deprecated :class:`~sdl2.ext.FontManager`
12+
class, which provides a different (and less featureful) API for rendering text
13+
using **SDL_ttf**.
14+
615
.. automodule:: sdl2.ext.ttf
716
:members:

doc/news.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ New Features:
6262
widths and heights for each mapped character in a bitmap font (PR #208)
6363
* Added a new argument ``line_h`` to :meth:`sdl2.ext.BitmapFont.render_on` to
6464
allow specifying custom line heights (PR #208)
65+
* Added the :class:`~sdl2.ext.FontTTF` class, providing a new and flexible
66+
Pythonic wrapper around the :mod:`~sdl2.sdlttf` module for opening and
67+
rendering text with TrueType and OpenType fonts. New features include custom
68+
line heights for multi-line text, left/right/center justification operations
69+
for multiline text, and specifying font sizes in units of pixels in addition
70+
to pt (PR #210)
6571

6672
Fixed Bugs:
6773

@@ -135,6 +141,8 @@ Deprecation Notices:
135141
have been deprecated due to their complexity and maintenance burden. New
136142
functions and classes for creating GUIs with PySDL2 may be introduced in a
137143
future release (PR #209)
144+
* The :class:`~sdl2.ext.FontManager` class has been deprecated in favor of the
145+
new and more flexible :class:`~sdl2.ext.FontTTF` class (PR #210)
138146

139147

140148
0.9.9

examples/ttf.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Test font rendering using the FontTTF class
2+
3+
# This example allows you to try typing out some text in a given font, and
4+
# supports the following keys:
5+
# - Left/Right Arrow Keys: Cycles text alignment (left/right/center)
6+
# - Up/Down Arrow Keys: Increases/decreases line height
7+
# - Tab: Cycles font rendering style
8+
9+
import os
10+
import sys
11+
import sdl2.ext
12+
from sdl2.sdlttf import TTF_FontLineSkip
13+
from sdl2.ext import FontTTF
14+
15+
filepath = os.path.abspath(os.path.dirname(__file__))
16+
RESOURCES = sdl2.ext.Resources(filepath, "resources")
17+
BLACK_RGBA = (0, 0, 0, 255)
18+
WHITE_RGBA = (255, 255, 255, 255)
19+
20+
21+
def update_text(renderer, surface):
22+
# Create a texture for the surface and render it to the screen
23+
tx = sdl2.ext.Texture(renderer, surface)
24+
renderer.clear(BLACK_RGBA)
25+
renderer.copy(tx, dstrect=(10, 10))
26+
renderer.present()
27+
28+
29+
def run():
30+
# Initialize SDL2 and create a Window and Renderer
31+
sdl2.ext.init()
32+
window = sdl2.ext.Window("Font Rendering", size=(800, 500))
33+
renderflags = sdl2.SDL_RENDERER_SOFTWARE
34+
if "-hardware" in sys.argv:
35+
renderflags = (
36+
sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC
37+
)
38+
renderer = sdl2.ext.Renderer(window, flags=renderflags)
39+
window.show()
40+
41+
# Create and initialize a font to render text with
42+
fontpath = RESOURCES.get_path("tuffy.ttf")
43+
font = FontTTF(fontpath, "20px", WHITE_RGBA)
44+
45+
# Add some additional font styles
46+
styles = ['default', 'small', 'red', 'large', 'bg_fill']
47+
font.add_style('small', '10px', WHITE_RGBA)
48+
font.add_style('red', '20px', (255, 0, 0))
49+
font.add_style('large', '35px', WHITE_RGBA)
50+
font.add_style('bg_fill', '20px', BLACK_RGBA, WHITE_RGBA)
51+
52+
# Initialize font rendering options
53+
line_height = TTF_FontLineSkip(font.get_ttf_font())
54+
alignments = ["left", "center", "right"]
55+
align_idx = 0
56+
style_idx = 0
57+
58+
# Set a default string with which to render text
59+
txt = u"Hi There!\nYou can edit this text using the keyboard and delete keys."
60+
61+
# Render the text and present it on the screen
62+
txt_rendered = font.render_text(txt, width=780)
63+
update_text(renderer, txt_rendered)
64+
65+
# Tell SDL2 to start reading Text Editing events. This allows for proper
66+
# handling of unicode characters and modifier keys.
67+
sdl2.SDL_StartTextInput()
68+
69+
# Create a simple event loop and wait for keydown, text editing, and quit events.
70+
running = True
71+
while running:
72+
events = sdl2.ext.get_events()
73+
for event in events:
74+
update_txt = False
75+
if event.type == sdl2.SDL_QUIT:
76+
running = False
77+
break
78+
79+
# Handle non-standard keyboard events
80+
elif event.type == sdl2.SDL_KEYDOWN:
81+
update_txt = True
82+
sdl_keysym = event.key.keysym.sym
83+
# If backspace pressed, remove last character (if any) from txt
84+
if sdl_keysym == sdl2.SDLK_BACKSPACE:
85+
txt = txt[:-1]
86+
# If enter/return pressed, insert a newline
87+
elif sdl_keysym == sdl2.SDLK_RETURN:
88+
txt = txt + u"\n"
89+
# If left or right arrow pressed, change text alignment mode
90+
elif sdl_keysym == sdl2.SDLK_LEFT:
91+
align_idx = (align_idx - 1) % 3
92+
elif sdl_keysym == sdl2.SDLK_RIGHT:
93+
align_idx = (align_idx + 1) % 3
94+
elif sdl_keysym == sdl2.SDLK_UP:
95+
line_height += 1
96+
elif sdl_keysym == sdl2.SDLK_DOWN:
97+
if line_height > 1:
98+
line_height -= 1
99+
# If tab pressed, cycle through the different font styles
100+
elif sdl_keysym == sdl2.SDLK_TAB:
101+
style_idx = (style_idx + 1) % len(styles)
102+
103+
# Handle text input events
104+
elif event.type == sdl2.SDL_TEXTINPUT:
105+
update_txt = True
106+
txt += event.text.text.decode("utf-8")
107+
108+
# If txt has changed since the start of the loop, update the renderer
109+
if update_txt:
110+
align = alignments[align_idx]
111+
style = styles[style_idx]
112+
txt_rendered = font.render_text(
113+
txt, style, width=780, line_h=line_height, align=align
114+
)
115+
update_text(renderer, txt_rendered)
116+
117+
# Now that we're done, close everything down and quit SDL2
118+
font.close()
119+
renderer.destroy()
120+
window.close()
121+
sdl2.ext.quit()
122+
return 0
123+
124+
if __name__ == "__main__":
125+
sys.exit(run())

sdl2/ext/compat.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ def _to_unicode(x, enc):
3737
return str(x)
3838

3939

40+
def _is_text(x):
41+
return isinstance(x, (str, bytes, unicode))
42+
43+
4044
def utf8(x):
4145
"""Converts input to a unicode string in a Python 2/3 agnostic manner.
4246

0 commit comments

Comments
 (0)