Skip to content

Updated background color handling for label #49

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 21 commits into from
Jun 6, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 85 additions & 24 deletions adafruit_display_text/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,19 @@ def __init__(
color=0xFFFFFF,
background_color=None,
line_spacing=1.25,
background_tight=False,
padding_top=0,
padding_bottom=0,
padding_left=0,
padding_right=0,
**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)
max_glyphs = len(text) + 1 # add one for the background bitmap tileGrid
super().__init__(max_size=max_glyphs, **kwargs)

self.width = max_glyphs
self._font = font
self._text = None
Expand All @@ -87,28 +93,48 @@ def __init__(
self.y = y

self.palette = displayio.Palette(2)
if background_color is not None:
self.palette[0] = background_color
self.palette.make_opaque(0)
self._transparent_background = False
else:
self.palette[0] = 0
self.palette.make_transparent(0)
self._transparent_background = True
self.palette[0] = 0
self.palette.make_transparent(0)
self._transparent_background = True
self.palette[1] = color

self._background_color = background_color

bounds = self._font.get_bounding_box()
self.height = bounds[1]
self._line_spacing = line_spacing
self._boundingbox = None

self._background_tight = background_tight # sets padding status for text background

self._background_palette = displayio.Palette(1)
self.append(
displayio.TileGrid(
displayio.Bitmap(0, 0, 1), pixel_shader=self._background_palette
)
) # initialize with a blank tilegrid placeholder for background

self._padding_top = padding_top
self._padding_bottom = padding_bottom
self._padding_left = padding_left
self._padding_right = padding_right

if text is not None:
self._update_text(str(text))

def _update_background_color(self, new_color):

if new_color == None:
self._background_palette.make_transparent(0)
else:
self._background_palette.make_opaque(0)
self._background_palette[0] = new_color
self._background_color = new_color

def _update_text(self, new_text): # pylint: disable=too-many-locals
x = 0
y = 0
i = 0
i = 1
old_c = 0
y_offset = int(
(
Expand All @@ -118,17 +144,21 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
/ 2
)
left = right = top = bottom = 0
lines = 1
for character in new_text:
if character == "\n":
y += int(self.height * self._line_spacing)
x = 0
lines += 1
continue
glyph = self._font.get_glyph(ord(character))
if not glyph:
continue
right = max(right, x + glyph.width + glyph.shift_x)
right = max(
right, x + glyph.shift_x
) # studied the docs! This is the correct spacing
if y == 0: # first line, find the Ascender height
top = min(top, -glyph.height + y_offset)
top = min(top, -glyph.height - glyph.dy + y_offset)
bottom = max(bottom, y - glyph.dy + y_offset)
position_y = y - glyph.height - glyph.dy + y_offset
position_x = x + glyph.dx
Expand Down Expand Up @@ -161,14 +191,14 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
else:
self.append(face)
elif self._text and character == self._text[old_c]:

try:
self[i].position = (position_x, position_y)
except AttributeError:
self[i].x = position_x
self[i].y = position_y

x += glyph.shift_x

# TODO skip this for control sequences or non-printables.
i += 1
old_c += 1
Expand All @@ -188,6 +218,46 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
self._text = new_text
self._boundingbox = (left, top, left + right, bottom - top)

if self._background_tight: # draw a tight bounding box
box_width = self._boundingbox[2]
box_height = self._boundingbox[3]
x_box_offset = 0
y_box_offset = top

else: # draw a "loose" bounding box to include any ascenders/descenders.

# check a few glyphs for maximum ascender and descender height
# Enhancement: it would be preferred to access the font "FONT_ASCENT" and "FONT_DESCENT" in the imported BDF file
glyphs = "M j'" # choose glyphs with highest ascender and lowest descender, will depend upon font used
ascender_max = descender_max = 0
for char in glyphs:
thisGlyph = self._font.get_glyph(ord(char))
ascender_max = max(ascender_max, thisGlyph.height + thisGlyph.dy)
descender_max = max(descender_max, -thisGlyph.dy)

box_width = self._boundingbox[2] + self._padding_left + self._padding_right
x_box_offset = -self._padding_left
box_height = (
(ascender_max + descender_max)
+ int((lines - 1) * self.height * self._line_spacing)
+ self._padding_top
+ self._padding_bottom
)
y_box_offset = -ascender_max + y_offset - self._padding_top

self._update_background_color(self._background_color)
box_width = max(0, box_width) # remove any negative values
box_height = max(0, box_height) # remove any negative values

background_bitmap = displayio.Bitmap(box_width, box_height, 1)
tile_grid = displayio.TileGrid(
background_bitmap,
pixel_shader=self._background_palette,
x=left + x_box_offset,
y=y_box_offset,
)
self[0] = tile_grid # update the background bitmap in first item of the group

@property
def bounding_box(self):
"""An (x, y, w, h) tuple that completely covers all glyphs. The
Expand Down Expand Up @@ -216,20 +286,11 @@ def color(self, new_color):
@property
def background_color(self):
"""Color of the background as an RGB hex number."""
if not self._transparent_background:
return self.palette[0]
return None
return self._background_color

@background_color.setter
def background_color(self, new_color):
if new_color is not None:
self.palette[0] = new_color
self.palette.make_opaque(0)
self._transparent_background = False
else:
self.palette[0] = 0
self.palette.make_transparent(0)
self._transparent_background = True
self._update_background_color(new_color)

@property
def text(self):
Expand Down
130 changes: 130 additions & 0 deletions examples/display_text_background_color_padding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""
This examples shows the use color and background_color
"""
import board
import displayio
import time
import terminalio
import fontio
import sys
import busio

# from adafruit_st7789 import ST7789
from adafruit_ili9341 import ILI9341
from adafruit_display_text import label

# Setup the SPI display

print("Starting the display...") # goes to serial only
displayio.release_displays()


spi = board.SPI()
tft_cs = board.D9 # arbitrary, pin not used
tft_dc = board.D10
tft_backlight = board.D12
tft_reset = board.D11

while not spi.try_lock():
spi.configure(baudrate=32000000)
pass
spi.unlock()

display_bus = displayio.FourWire(
spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_reset,
baudrate=32000000,
polarity=1,
phase=1,
)

print("spi.frequency: {}".format(spi.frequency))

DISPLAY_WIDTH = 320
DISPLAY_HEIGHT = 240

# display = ST7789(display_bus, width=240, height=240, rotation=0, rowstart=80, colstart=0)
display = ILI9341(
display_bus,
width=DISPLAY_WIDTH,
height=DISPLAY_HEIGHT,
rotation=180,
auto_refresh=True,
)

display.show(None)

# font=terminalio.FONT

from adafruit_bitmap_font import bitmap_font

font = bitmap_font.load_font("fonts/BitstreamVeraSans-Roman-24.bdf")


text = []
text.append("none") # no ascenders or descenders
text.append("pop quops") # only descenders
text.append("MONSTERs are tall") # only ascenders
text.append("MONSTERs ate pop quops") # both ascenders and descenders
text.append("MONSTER quops\nnewline quops") # with newline

display.auto_refresh = True
myGroup = displayio.Group(max_size=6)
display.show(myGroup)

text_area = []
myPadding = 4

for i, thisText in enumerate(text):
text_area.append(
label.Label(
font,
text=thisText,
color=0xFFFFFF,
background_color=None,
background_tight=False,
padding_top=myPadding,
padding_bottom=myPadding,
padding_left=myPadding,
padding_right=myPadding,
)
)

this_x = 10
this_y = 10 + i * 40
text_area[i].x = 10
text_area[i].y = 3 + i * 50
text_area[i].anchor_point = (0, 0)
text_area[i].anchored_position = (this_x, this_y)
myGroup.append(text_area[i])

print("background color is {}".format(text_area[0].background_color))


while True:
time.sleep(2)
text_area[
0
].text = "text" # change some text in an existing text box (must fit within existing # of characters)

for area in text_area:
area.background_color = 0xFF0000
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0x000088
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0x00FF00
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0xFF0000
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = None
print("background color is {}".format(text_area[0].background_color))