Skip to content
88 changes: 87 additions & 1 deletion adafruit_display_text/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2020 Tim C for Adafruit Industries
# SPDX-FileCopyrightText: 2020 Tim C, 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: MIT

Expand All @@ -7,6 +7,92 @@
"""


def wrap_text_to_pixels(string, max_width, font=None, indent0="", indent1=""):
"""wrap_text_to_pixels function
A helper that will return a list of lines with word-break wrapping.
Leading and trailing whitespace in your string will be removed. If
you wish to use leading whitespace see `indend0` and `indent1`
parameters.

:param str string: The text to be wrapped.
:param int max_width: The maximum number of pixels on a line before wrapping.
:param Font font: The font to use for measuring the text.
:param str indent0: Additional character(s) to add to the first line.
:param str indent1: Additional character(s) to add to all other lines.


:return list lines: A list of the lines resulting from wrapping the
input text at max_width pixels size

"""
# pylint: disable=too-many-locals too-many-branches
if font is None:

def measure(string):
return len(string)

else:
if hasattr(font, "load_glyphs"):
font.load_glyphs(string)

def measure(string):
return sum(font.get_glyph(ord(c)).shift_x for c in string)

lines = []
partial = [indent0]
width = measure(indent0)
swidth = measure(" ")
firstword = True
for line_in_input in string.split("\n"):
for index, word in enumerate(line_in_input.split(" ")):
wwidth = measure(word)
word_parts = []
cur_part = ""

if wwidth > max_width:
for char in word:
if (
measure("".join(partial))
+ measure(cur_part)
+ measure(char)
+ measure("-")
> max_width
):
word_parts.append("".join(partial) + cur_part + "-")
cur_part = char
partial = [indent1]
else:
cur_part += char
if cur_part:
word_parts.append(cur_part)
for line in word_parts[:-1]:
lines.append(line)
partial.append(word_parts[-1])
width = measure(word_parts[-1])
if firstword:
firstword = False
else:
if firstword:
partial.append(word)
firstword = False
width += wwidth
elif width + swidth + wwidth < max_width:
if index > 0:
partial.append(" ")
partial.append(word)
width += wwidth + swidth
else:
lines.append("".join(partial))
partial = [indent1, word]
width = measure(indent1) + wwidth

lines.append("".join(partial))
partial = [indent1]
width = measure(indent1)

return lines


def wrap_text_to_lines(string, max_chars):
"""wrap_text_to_lines function
A helper that will return a list of lines with word-break wrapping
Expand Down
63 changes: 63 additions & 0 deletions examples/display_text_wrap_pixels_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# SPDX-FileCopyrightText: 2021 Tim C, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Test the wrap_text_to_pixels function. Try changing WRAP_WIDTH or text
and observe the results. The red bar represents the full size of
WRAP_WIDTH.
"""

import board
import displayio
import terminalio
from adafruit_display_text import label, wrap_text_to_pixels

WRAP_WIDTH = 140
text = (
"CircuitPython is a programming language designed to simplify experimenting "
"and learning to code on low-cost microcontroller boards. "
)

# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.)
# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.)
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus
display = board.DISPLAY

# Make the display context
main_group = displayio.Group(max_size=10)
display.show(main_group)

font = terminalio.FONT

print(text)
print(display.width)

text_area = label.Label(
font,
text="\n".join(wrap_text_to_pixels(text, WRAP_WIDTH, font)),
background_color=0x0000DD,
)

text_area.anchor_point = (0, 0)
text_area.anchored_position = (0, 0)

main_group.append(text_area)

# Create a bitmap with two colors
size_checker = displayio.Bitmap(WRAP_WIDTH, 10, 2)
# Create a two color palette
palette = displayio.Palette(2)
palette[0] = 0x0000DD
palette[1] = 0xDD0000

# Create a TileGrid using the Bitmap and Palette
tile_grid = displayio.TileGrid(size_checker, pixel_shader=palette)

tile_grid.y = text_area.bounding_box[1] + text_area.bounding_box[3] + 10

size_checker.fill(1)

main_group.append(tile_grid)

while True:
pass