Skip to content

Commit 646b46d

Browse files
author
Margaret Matocha
committed
Merge remote-tracking branch 'upstream/master'
2 parents ec7b69a + 225b0b1 commit 646b46d

File tree

6 files changed

+292
-44
lines changed

6 files changed

+292
-44
lines changed

adafruit_display_text/label.py

Lines changed: 115 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,29 @@ def __init__(
6767
*,
6868
x=0,
6969
y=0,
70-
text=None,
70+
text="",
7171
max_glyphs=None,
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
):
82+
if "scale" in kwargs.keys():
83+
self._scale = kwargs["scale"]
84+
else:
85+
self._scale = 1
7786
if not max_glyphs and not text:
7887
raise RuntimeError("Please provide a max size, or initial text")
7988
if not max_glyphs:
8089
max_glyphs = len(text)
81-
super().__init__(max_size=max_glyphs, **kwargs)
90+
# add one to max_size for the background bitmap tileGrid
91+
super().__init__(max_size=max_glyphs + 1, **kwargs)
92+
8293
self.width = max_glyphs
8394
self._font = font
8495
self._text = None
@@ -87,28 +98,95 @@ def __init__(
8798
self.y = y
8899

89100
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
101+
self.palette[0] = 0
102+
self.palette.make_transparent(0)
98103
self.palette[1] = color
99104

100-
bounds = self._font.get_bounding_box()
101-
self.height = bounds[1]
105+
self.height = self._font.get_bounding_box()[1]
102106
self._line_spacing = line_spacing
103107
self._boundingbox = None
104108

109+
self._background_tight = (
110+
background_tight # sets padding status for text background box
111+
)
112+
113+
self._background_color = background_color
114+
self._background_palette = displayio.Palette(1)
115+
self.append(
116+
displayio.TileGrid(
117+
displayio.Bitmap(0, 0, 1), pixel_shader=self._background_palette
118+
)
119+
) # initialize with a blank tilegrid placeholder for background
120+
121+
self._padding_top = padding_top
122+
self._padding_bottom = padding_bottom
123+
self._padding_left = padding_left
124+
self._padding_right = padding_right
125+
105126
if text is not None:
106127
self._update_text(str(text))
107128

129+
def _create_background_box(self, lines, y_offset):
130+
131+
left = self._boundingbox[0]
132+
133+
if self._background_tight: # draw a tight bounding box
134+
box_width = self._boundingbox[2]
135+
box_height = self._boundingbox[3]
136+
x_box_offset = 0
137+
y_box_offset = self._boundingbox[1]
138+
139+
else: # draw a "loose" bounding box to include any ascenders/descenders.
140+
141+
# check a few glyphs for maximum ascender and descender height
142+
# Enhancement: it would be preferred to access the font "FONT_ASCENT" and
143+
# "FONT_DESCENT" in the imported BDF file
144+
glyphs = "M j'" # choose glyphs with highest ascender and lowest
145+
# descender, will depend upon font used
146+
ascender_max = descender_max = 0
147+
for char in glyphs:
148+
this_glyph = self._font.get_glyph(ord(char))
149+
if this_glyph:
150+
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
151+
descender_max = max(descender_max, -this_glyph.dy)
152+
153+
box_width = self._boundingbox[2] + self._padding_left + self._padding_right
154+
x_box_offset = -self._padding_left
155+
box_height = (
156+
(ascender_max + descender_max)
157+
+ int((lines - 1) * self.height * self._line_spacing)
158+
+ self._padding_top
159+
+ self._padding_bottom
160+
)
161+
y_box_offset = -ascender_max + y_offset - self._padding_top
162+
163+
self._update_background_color(self._background_color)
164+
box_width = max(0, box_width) # remove any negative values
165+
box_height = max(0, box_height) # remove any negative values
166+
167+
background_bitmap = displayio.Bitmap(box_width, box_height, 1)
168+
tile_grid = displayio.TileGrid(
169+
background_bitmap,
170+
pixel_shader=self._background_palette,
171+
x=left + x_box_offset,
172+
y=y_box_offset,
173+
)
174+
175+
return tile_grid
176+
177+
def _update_background_color(self, new_color):
178+
179+
if new_color is None:
180+
self._background_palette.make_transparent(0)
181+
else:
182+
self._background_palette.make_opaque(0)
183+
self._background_palette[0] = new_color
184+
self._background_color = new_color
185+
108186
def _update_text(self, new_text): # pylint: disable=too-many-locals
109187
x = 0
110188
y = 0
111-
i = 0
189+
i = 1
112190
old_c = 0
113191
y_offset = int(
114192
(
@@ -118,17 +196,19 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
118196
/ 2
119197
)
120198
left = right = top = bottom = 0
199+
lines = 1
121200
for character in new_text:
122201
if character == "\n":
123202
y += int(self.height * self._line_spacing)
124203
x = 0
204+
lines += 1
125205
continue
126206
glyph = self._font.get_glyph(ord(character))
127207
if not glyph:
128208
continue
129-
right = max(right, x + glyph.width)
209+
right = max(right, x + glyph.shift_x)
130210
if y == 0: # first line, find the Ascender height
131-
top = min(top, -glyph.height + y_offset)
211+
top = min(top, -glyph.height - glyph.dy + y_offset)
132212
bottom = max(bottom, y - glyph.dy + y_offset)
133213
position_y = y - glyph.height - glyph.dy + y_offset
134214
position_x = x + glyph.dx
@@ -138,6 +218,7 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
138218
or character != self._text[old_c]
139219
):
140220
try:
221+
# pylint: disable=unexpected-keyword-arg
141222
face = displayio.TileGrid(
142223
glyph.bitmap,
143224
pixel_shader=self.palette,
@@ -161,14 +242,14 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
161242
else:
162243
self.append(face)
163244
elif self._text and character == self._text[old_c]:
245+
164246
try:
165247
self[i].position = (position_x, position_y)
166248
except AttributeError:
167249
self[i].x = position_x
168250
self[i].y = position_y
169251

170252
x += glyph.shift_x
171-
172253
# TODO skip this for control sequences or non-printables.
173254
i += 1
174255
old_c += 1
@@ -187,6 +268,7 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
187268
self.pop()
188269
self._text = new_text
189270
self._boundingbox = (left, top, left + right, bottom - top)
271+
self[0] = self._create_background_box(lines, y_offset)
190272

191273
@property
192274
def bounding_box(self):
@@ -216,20 +298,11 @@ def color(self, new_color):
216298
@property
217299
def background_color(self):
218300
"""Color of the background as an RGB hex number."""
219-
if not self._transparent_background:
220-
return self.palette[0]
221-
return None
301+
return self._background_color
222302

223303
@background_color.setter
224304
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
305+
self._update_background_color(new_color)
233306

234307
@property
235308
def text(self):
@@ -238,9 +311,12 @@ def text(self):
238311

239312
@text.setter
240313
def text(self, new_text):
241-
current_anchored_position = self.anchored_position
242-
self._update_text(str(new_text))
243-
self.anchored_position = current_anchored_position
314+
try:
315+
current_anchored_position = self.anchored_position
316+
self._update_text(str(new_text))
317+
self.anchored_position = current_anchored_position
318+
except RuntimeError:
319+
raise RuntimeError("Text length exceeds max_glyphs")
244320

245321
@property
246322
def font(self):
@@ -253,8 +329,7 @@ def font(self, new_font):
253329
current_anchored_position = self.anchored_position
254330
self._text = ""
255331
self._font = new_font
256-
bounds = self._font.get_bounding_box()
257-
self.height = bounds[1]
332+
self.height = self._font.get_bounding_box()[1]
258333
self._update_text(str(old_text))
259334
self.anchored_position = current_anchored_position
260335

@@ -290,13 +365,15 @@ def anchored_position(self):
290365

291366
@anchored_position.setter
292367
def anchored_position(self, new_position):
293-
self.x = int(
368+
new_x = int(
294369
new_position[0]
295-
- self._boundingbox[0]
296-
- self._anchor_point[0] * self._boundingbox[2]
370+
- self._anchor_point[0] * (self._boundingbox[2] * self._scale)
297371
)
298-
self.y = int(
372+
new_y = self.y = int(
299373
new_position[1]
300-
- self._boundingbox[1]
301-
- self._anchor_point[1] * self._boundingbox[3]
374+
- self._anchor_point[1] * (self._boundingbox[3] * self._scale)
375+
+ (self._boundingbox[3] * self._scale) / 2
302376
)
377+
self._boundingbox = (new_x, new_y, self._boundingbox[2], self._boundingbox[3])
378+
self.x = new_x
379+
self.y = new_y

examples/display_text_anchored_position.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"""
44
import board
55
import terminalio
6-
from adafruit_display_text import label
76
import displayio
7+
from adafruit_display_text import label
88

99
DISPLAY_WIDTH = 320
1010
DISPLAY_HEIGHT = 240
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)