Skip to content

Add line_spacing property and change (0,0) definition #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 12, 2019
6 changes: 4 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ For a board with a built-in display.

import board
import terminalio
from adafruit_display_text import text_area
from adafruit_display_text import label

text = "Hello world"
text_area = text_area.TextArea(terminalio.FONT, text=text, width=len(text))
text_area = label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_display_text.text_area`
`adafruit_display_text.label`
====================================================

Displays text using CircuitPython's displayio.
Displays text labels using CircuitPython's displayio.

* Author(s): Scott Shawcroft

Expand All @@ -44,21 +44,23 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"

class TextArea(displayio.Group):
"""An area displaying a string of textself.
class Label(displayio.Group):
"""A label displaying a string of text. The origin point set by ``x`` and ``y``
properties will be the left edge of the bounding box, and in the center of a M
glyph (if its one line), or the (number of lines * linespacing + M)/2. That is,
it will try to have it be center-left as close as possible.

:param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``
:param str text: Text to display
:param int width: Area width in characters
:param int height: Area height in characters
:param int max_glyphs: The largest quantity of glyphs we will display
:param int color: Color of all text in RGB hex"""
def __init__(self, font, *, text=None, width=None, height=1, color=0xffffff):
if not width and not text:
raise RuntimeError("Please provide a width")
if not width:
width = len(text)
super().__init__(max_size=width * height)
self.width = width
def __init__(self, font, *, text=None, max_glyphs=None, color=0xffffff, **kwargs):
if not max_glyphs and not text:
raise RuntimeError("Please provide a max size, or initial text")
if not max_glyphs:
max_glyphs = len(text)
super().__init__(max_size=max_glyphs, **kwargs)
self.width = max_glyphs
self.font = font
self._text = None

Expand All @@ -68,36 +70,47 @@ def __init__(self, font, *, text=None, width=None, height=1, color=0xffffff):

bounds = self.font.get_bounding_box()
self.height = bounds[1]
self._line_spacing = 1.25
self._boundingbox = None

if text:
self._update_text(text)


def _update_text(self, new_text):
def _update_text(self, new_text): # pylint: disable=too-many-locals
x = 0
y = 0
i = 0
old_c = 0
y_offset = int((self.font.get_glyph(ord('M')).height -
new_text.count('\n') * self.height * self.line_spacing) / 2)
#print("y offset from baseline", y_offset)
left = right = top = bottom = 0
for character in new_text:
if character == '\n':
y += int(self.height * 1.25)
y += int(self.height * self._line_spacing)
x = 0
continue
glyph = self.font.get_glyph(ord(character))
if not glyph:
continue
position_y = y + self.height - glyph.height - glyph.dy
right = max(right, x+glyph.width)
if y == 0: # first line, find the Ascender height
top = min(top, -glyph.height+y_offset)
bottom = max(bottom, y-glyph.dy+y_offset)
position_y = y - glyph.height - glyph.dy + y_offset
position_x = x + glyph.dx
if not self._text or old_c >= len(self._text) or character != self._text[old_c]:
face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette,
default_tile=glyph.tile_index,
tile_width=glyph.width, tile_height=glyph.height,
position=(x, position_y))
position=(position_x, position_y))
if i < len(self):
self[i] = face
else:
self.append(face)
elif self._text and character == self._text[old_c]:
self[i].position = (x, position_y)
self[i].position = (position_x, position_y)

x += glyph.shift_x

Expand All @@ -112,6 +125,23 @@ def _update_text(self, new_text):
while len(self) > i:
self.pop()
self._text = new_text
self._boundingbox = (left, top, left+right, bottom-top)

@property
def bounding_box(self):
"""An (x, y, w, h) tuple that completely covers all glyphs. The
first two numbers are offset from the x, y origin of this group"""
return tuple(self._boundingbox)

@property
def line_spacing(self):
"""The amount of space between lines of text, in multiples of the font's
bounding-box height. (E.g. 1.0 is the bounding-box height)"""
return self._line_spacing

@line_spacing.setter
def line_spacing(self, spacing):
self._line_spacing = spacing

@property
def color(self):
Expand Down
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
.. use this format as the module name: "adafruit_foo.foo"

.. automodule:: adafruit_display_text.text_area
.. automodule:: adafruit_display_text.label
:members:
4 changes: 2 additions & 2 deletions examples/pyportal.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import displayio

from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.text_area import TextArea
from adafruit_display_text.label import Label

backlight = pulseio.PWMOut(microcontroller.pin.PB21) #pylint: disable=no-member

Expand All @@ -31,7 +31,7 @@
for demo_text in demos:
for font in fonts:
print("Font load {}".format(font.name))
area = TextArea(font, text=demo_text)
area = Label(font, text=demo_text)
area.y = y
splash.append(area)

Expand Down
61 changes: 61 additions & 0 deletions examples/textarea_boundingbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import board
import displayio
from adafruit_display_text.label import Label
from adafruit_bitmap_font import bitmap_font

# the current working directory (where this file is)
cwd = ("/"+__file__).rsplit('/', 1)[0]
fonts = [file for file in os.listdir(cwd+"/fonts/")
if (file.endswith(".bdf") and not file.startswith("._"))]
for i, filename in enumerate(fonts):
fonts[i] = cwd+"/fonts/"+filename
print(fonts)

##########################################################################
THE_FONT = fonts[0]
DISPLAY_STRING = "A multi-line-\nexample of\n font bounding!"
WRAP_CHARS = 40

##########################################################################
# Make the display context
splash = displayio.Group()
board.DISPLAY.show(splash)

# Make a background color fill
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
position=(0, 0))
splash.append(bg_sprite)

# Load the font
font = bitmap_font.load_font(THE_FONT)
font.load_glyphs(DISPLAY_STRING.encode('utf-8'))

print(DISPLAY_STRING)

text = Label(font, text=DISPLAY_STRING)
text.x = 20
text.y = 100
text.color = 0x0

# Make a background color fill
dims = text.bounding_box
print(dims)
textbg_bitmap = displayio.Bitmap(dims[2], dims[3], 1)
textbg_palette = displayio.Palette(1)
textbg_palette[0] = 0xFF0000
textbg_sprite = displayio.TileGrid(textbg_bitmap,
pixel_shader=textbg_palette,
position=(text.x+dims[0], text.y+dims[1]))
splash.append(textbg_sprite)
splash.append(text)
board.DISPLAY.refresh_soon()
board.DISPLAY.wait_for_frame()


while True:
pass