Skip to content

Commit 1f2bf53

Browse files
authored
Merge pull request adafruit#49 from kmatch98/background
Updated background color handling for label
2 parents b536f4f + 05bd0ad commit 1f2bf53

File tree

2 files changed

+218
-28
lines changed

2 files changed

+218
-28
lines changed

adafruit_display_text/label.py

Lines changed: 93 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,19 @@ def __init__(
7272
color=0xFFFFFF,
7373
background_color=None,
7474
line_spacing=1.25,
75+
background_tight=False,
76+
padding_top=0,
77+
padding_bottom=0,
78+
padding_left=0,
79+
padding_right=0,
7580
**kwargs
7681
):
7782
if not max_glyphs and not text:
7883
raise RuntimeError("Please provide a max size, or initial text")
7984
if not max_glyphs:
80-
max_glyphs = len(text)
85+
max_glyphs = len(text) + 1 # add one for the background bitmap tileGrid
8186
super().__init__(max_size=max_glyphs, **kwargs)
87+
8288
self.width = max_glyphs
8389
self._font = font
8490
self._text = None
@@ -87,28 +93,94 @@ def __init__(
8793
self.y = y
8894

8995
self.palette = displayio.Palette(2)
90-
if background_color is not None:
91-
self.palette[0] = background_color
92-
self.palette.make_opaque(0)
93-
self._transparent_background = False
94-
else:
95-
self.palette[0] = 0
96-
self.palette.make_transparent(0)
97-
self._transparent_background = True
96+
self.palette[0] = 0
97+
self.palette.make_transparent(0)
9898
self.palette[1] = color
9999

100-
bounds = self._font.get_bounding_box()
101-
self.height = bounds[1]
100+
self.height = self._font.get_bounding_box()[1]
102101
self._line_spacing = line_spacing
103102
self._boundingbox = None
104103

104+
self._background_tight = (
105+
background_tight # sets padding status for text background box
106+
)
107+
108+
self._background_color = background_color
109+
self._background_palette = displayio.Palette(1)
110+
self.append(
111+
displayio.TileGrid(
112+
displayio.Bitmap(0, 0, 1), pixel_shader=self._background_palette
113+
)
114+
) # initialize with a blank tilegrid placeholder for background
115+
116+
self._padding_top = padding_top
117+
self._padding_bottom = padding_bottom
118+
self._padding_left = padding_left
119+
self._padding_right = padding_right
120+
105121
if text is not None:
106122
self._update_text(str(text))
107123

124+
def _create_background_box(self, lines, y_offset):
125+
126+
left = self._boundingbox[0]
127+
128+
if self._background_tight: # draw a tight bounding box
129+
box_width = self._boundingbox[2]
130+
box_height = self._boundingbox[3]
131+
x_box_offset = 0
132+
y_box_offset = self._boundingbox[1]
133+
134+
else: # draw a "loose" bounding box to include any ascenders/descenders.
135+
136+
# check a few glyphs for maximum ascender and descender height
137+
# Enhancement: it would be preferred to access the font "FONT_ASCENT" and
138+
# "FONT_DESCENT" in the imported BDF file
139+
glyphs = "M j'" # choose glyphs with highest ascender and lowest
140+
# descender, will depend upon font used
141+
ascender_max = descender_max = 0
142+
for char in glyphs:
143+
this_glyph = self._font.get_glyph(ord(char))
144+
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
145+
descender_max = max(descender_max, -this_glyph.dy)
146+
147+
box_width = self._boundingbox[2] + self._padding_left + self._padding_right
148+
x_box_offset = -self._padding_left
149+
box_height = (
150+
(ascender_max + descender_max)
151+
+ int((lines - 1) * self.height * self._line_spacing)
152+
+ self._padding_top
153+
+ self._padding_bottom
154+
)
155+
y_box_offset = -ascender_max + y_offset - self._padding_top
156+
157+
self._update_background_color(self._background_color)
158+
box_width = max(0, box_width) # remove any negative values
159+
box_height = max(0, box_height) # remove any negative values
160+
161+
background_bitmap = displayio.Bitmap(box_width, box_height, 1)
162+
tile_grid = displayio.TileGrid(
163+
background_bitmap,
164+
pixel_shader=self._background_palette,
165+
x=left + x_box_offset,
166+
y=y_box_offset,
167+
)
168+
169+
return tile_grid
170+
171+
def _update_background_color(self, new_color):
172+
173+
if new_color is None:
174+
self._background_palette.make_transparent(0)
175+
else:
176+
self._background_palette.make_opaque(0)
177+
self._background_palette[0] = new_color
178+
self._background_color = new_color
179+
108180
def _update_text(self, new_text): # pylint: disable=too-many-locals
109181
x = 0
110182
y = 0
111-
i = 0
183+
i = 1
112184
old_c = 0
113185
y_offset = int(
114186
(
@@ -118,17 +190,19 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
118190
/ 2
119191
)
120192
left = right = top = bottom = 0
193+
lines = 1
121194
for character in new_text:
122195
if character == "\n":
123196
y += int(self.height * self._line_spacing)
124197
x = 0
198+
lines += 1
125199
continue
126200
glyph = self._font.get_glyph(ord(character))
127201
if not glyph:
128202
continue
129-
right = max(right, x + glyph.width + glyph.shift_x)
203+
right = max(right, x + glyph.shift_x)
130204
if y == 0: # first line, find the Ascender height
131-
top = min(top, -glyph.height + y_offset)
205+
top = min(top, -glyph.height - glyph.dy + y_offset)
132206
bottom = max(bottom, y - glyph.dy + y_offset)
133207
position_y = y - glyph.height - glyph.dy + y_offset
134208
position_x = x + glyph.dx
@@ -161,14 +235,14 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
161235
else:
162236
self.append(face)
163237
elif self._text and character == self._text[old_c]:
238+
164239
try:
165240
self[i].position = (position_x, position_y)
166241
except AttributeError:
167242
self[i].x = position_x
168243
self[i].y = position_y
169244

170245
x += glyph.shift_x
171-
172246
# TODO skip this for control sequences or non-printables.
173247
i += 1
174248
old_c += 1
@@ -187,6 +261,7 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
187261
self.pop()
188262
self._text = new_text
189263
self._boundingbox = (left, top, left + right, bottom - top)
264+
self[0] = self._create_background_box(lines, y_offset)
190265

191266
@property
192267
def bounding_box(self):
@@ -216,20 +291,11 @@ def color(self, new_color):
216291
@property
217292
def background_color(self):
218293
"""Color of the background as an RGB hex number."""
219-
if not self._transparent_background:
220-
return self.palette[0]
221-
return None
294+
return self._background_color
222295

223296
@background_color.setter
224297
def background_color(self, new_color):
225-
if new_color is not None:
226-
self.palette[0] = new_color
227-
self.palette.make_opaque(0)
228-
self._transparent_background = False
229-
else:
230-
self.palette[0] = 0
231-
self.palette.make_transparent(0)
232-
self._transparent_background = True
298+
self._update_background_color(new_color)
233299

234300
@property
235301
def text(self):
@@ -256,8 +322,7 @@ def font(self, new_font):
256322
current_anchored_position = self.anchored_position
257323
self._text = ""
258324
self._font = new_font
259-
bounds = self._font.get_bounding_box()
260-
self.height = bounds[1]
325+
self.height = self._font.get_bounding_box()[1]
261326
self._update_text(str(old_text))
262327
self.anchored_position = current_anchored_position
263328

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
This examples shows the use color and background_color
3+
"""
4+
import time
5+
import board
6+
import displayio
7+
8+
9+
# from adafruit_st7789 import ST7789
10+
from adafruit_ili9341 import ILI9341
11+
from adafruit_display_text import label
12+
from adafruit_bitmap_font import bitmap_font
13+
14+
# Setup the SPI display
15+
16+
print("Starting the display...") # goes to serial only
17+
displayio.release_displays()
18+
19+
20+
spi = board.SPI()
21+
tft_cs = board.D9 # arbitrary, pin not used
22+
tft_dc = board.D10
23+
tft_backlight = board.D12
24+
tft_reset = board.D11
25+
26+
while not spi.try_lock():
27+
spi.configure(baudrate=32000000)
28+
spi.unlock()
29+
30+
display_bus = displayio.FourWire(
31+
spi,
32+
command=tft_dc,
33+
chip_select=tft_cs,
34+
reset=tft_reset,
35+
baudrate=32000000,
36+
polarity=1,
37+
phase=1,
38+
)
39+
40+
print("spi.frequency: {}".format(spi.frequency))
41+
42+
DISPLAY_WIDTH = 320
43+
DISPLAY_HEIGHT = 240
44+
45+
# display = ST7789(display_bus, width=240, height=240, rotation=0, rowstart=80, colstart=0)
46+
display = ILI9341(
47+
display_bus,
48+
width=DISPLAY_WIDTH,
49+
height=DISPLAY_HEIGHT,
50+
rotation=180,
51+
auto_refresh=True,
52+
)
53+
54+
display.show(None)
55+
56+
# font=terminalio.FONT # this is the Builtin fixed dimension font
57+
58+
font = bitmap_font.load_font("fonts/BitstreamVeraSans-Roman-24.bdf")
59+
60+
61+
text = []
62+
text.append("none") # no ascenders or descenders
63+
text.append("pop quops") # only descenders
64+
text.append("MONSTERs are tall") # only ascenders
65+
text.append("MONSTERs ate pop quops") # both ascenders and descenders
66+
text.append("MONSTER quops\nnewline quops") # with newline
67+
68+
display.auto_refresh = True
69+
myGroup = displayio.Group(max_size=6)
70+
display.show(myGroup)
71+
72+
text_area = []
73+
myPadding = 4
74+
75+
for i, thisText in enumerate(text):
76+
text_area.append(
77+
label.Label(
78+
font,
79+
text=thisText,
80+
color=0xFFFFFF,
81+
background_color=None,
82+
background_tight=False,
83+
padding_top=myPadding,
84+
padding_bottom=myPadding,
85+
padding_left=myPadding,
86+
padding_right=myPadding,
87+
)
88+
)
89+
90+
this_x = 10
91+
this_y = 10 + i * 40
92+
text_area[i].x = 10
93+
text_area[i].y = 3 + i * 50
94+
text_area[i].anchor_point = (0, 0)
95+
text_area[i].anchored_position = (this_x, this_y)
96+
myGroup.append(text_area[i])
97+
98+
print("background color is {}".format(text_area[0].background_color))
99+
100+
101+
while True:
102+
time.sleep(2)
103+
text_area[0].text = "text" # change some text in an existing text box
104+
# Note: changed text must fit within existing number of characters
105+
# when the Label was created
106+
107+
for area in text_area:
108+
area.background_color = 0xFF0000
109+
print("background color is {:06x}".format(text_area[0].background_color))
110+
time.sleep(2)
111+
for area in text_area:
112+
area.background_color = 0x000088
113+
print("background color is {:06x}".format(text_area[0].background_color))
114+
time.sleep(2)
115+
for area in text_area:
116+
area.background_color = 0x00FF00
117+
print("background color is {:06x}".format(text_area[0].background_color))
118+
time.sleep(2)
119+
for area in text_area:
120+
area.background_color = 0xFF0000
121+
print("background color is {:06x}".format(text_area[0].background_color))
122+
time.sleep(2)
123+
for area in text_area:
124+
area.background_color = None
125+
print("background color is {}".format(text_area[0].background_color))

0 commit comments

Comments
 (0)