diff --git a/adafruit_display_text/__init__.py b/adafruit_display_text/__init__.py index 58f8ce0..34b6046 100644 --- a/adafruit_display_text/__init__.py +++ b/adafruit_display_text/__init__.py @@ -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 @@ -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 diff --git a/examples/display_text_wrap_pixels_test.py b/examples/display_text_wrap_pixels_test.py new file mode 100644 index 0000000..1b0ff60 --- /dev/null +++ b/examples/display_text_wrap_pixels_test.py @@ -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