Skip to content

Commit a404b09

Browse files
committed
first commit with mutable text, font and line_spacing
1 parent 59c9544 commit a404b09

File tree

1 file changed

+183
-105
lines changed

1 file changed

+183
-105
lines changed

adafruit_display_text/bitmap_label.py

Lines changed: 183 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def __init__(
9898
x=0,
9999
y=0,
100100
text="",
101-
max_glyphs=None, # This input parameter is ignored, only present for compatibility
102-
# with label.py
101+
max_glyphs=None, # This input parameter is ignored, only present for compatibility
102+
# with label.py
103103
color=0xFFFFFF,
104104
background_color=None,
105105
line_spacing=1.25,
@@ -114,117 +114,199 @@ def __init__(
114114
**kwargs
115115
):
116116

117-
if text == "":
118-
raise RuntimeError(
119-
"Please provide text string, or use label.py for mutable text"
120-
)
117+
# instance the Group
118+
# this Group will contain just one TileGrid with one contained bitmap
119+
super().__init__(
120+
max_size=1, x=x, y=y, **kwargs
121+
) # this will include any arguments, including scale
121122

122123
self._font = font
123124

124-
# Scale will be passed to Group using kwargs.
125-
if "scale" in kwargs.keys():
126-
self._scale = kwargs["scale"]
127-
else:
128-
self._scale = 1
125+
# Create the two-color palette
126+
self.palette = displayio.Palette(2)
127+
self.color = color
128+
self.background_color = background_color
129+
130+
self._anchor_point = anchor_point
131+
self._anchored_position = anchored_position
132+
133+
self._scale = 1 # initialize to the default scale of 1
134+
135+
# call the text updater with all the arguments.
136+
self._reset_text(font=font,
137+
x=x,
138+
y=y,
139+
text=text,
140+
# color=color,
141+
# background_color=background_color,
142+
line_spacing=line_spacing,
143+
background_tight=background_tight,
144+
padding_top=padding_top,
145+
padding_bottom=padding_bottom,
146+
padding_left=padding_left,
147+
padding_right=padding_right,
148+
anchor_point=anchor_point,
149+
anchored_position=anchored_position,
150+
save_text=save_text,
151+
**kwargs,
152+
)
129153

130-
self._line_spacing = line_spacing
131-
self._save_text = save_text
154+
155+
def _reset_text(
156+
self,
157+
font=None,
158+
x=None,
159+
y=None,
160+
text=None,
161+
line_spacing=None,
162+
background_tight=None,
163+
padding_top=None,
164+
padding_bottom=None,
165+
padding_left=None,
166+
padding_right=None,
167+
anchor_point=None,
168+
anchored_position=None,
169+
save_text=None,
170+
**kwargs
171+
):
172+
173+
# store the instance variables
174+
175+
print('_reset_text Text string to print: {}'.format(text))
176+
177+
# Store all the instance variables
178+
if font is not None:
179+
self._font = font
180+
if x is not None:
181+
self.x = x
182+
if y is not None:
183+
self.y = y
184+
# if color is not None:
185+
# self.color = color
186+
# if background_color is not None:
187+
# self.background_color = background_color
188+
if line_spacing is not None:
189+
self._line_spacing = line_spacing
190+
if background_tight is not None:
191+
self._background_tight = background_tight
192+
if padding_top is not None:
193+
self._padding_top = max(0, padding_top)
194+
if padding_bottom is not None:
195+
self._padding_bottom = max(0, padding_bottom)
196+
if padding_left is not None:
197+
self._padding_left = max(0, padding_left)
198+
if padding_right is not None:
199+
self._padding_right = max(0, padding_right)
200+
if anchor_point is not None:
201+
self.anchor_point = anchor_point
202+
if anchored_position is not None:
203+
self._anchored_position = anchored_position
204+
if save_text is not None:
205+
self._save_text = save_text
206+
207+
# if text is not provided as a parameter (text is None), use the previous value.
208+
if (text is None) and self._save_text:
209+
text = self._text
132210

133211
if self._save_text: # text string will be saved
134212
self._text = text
135213
else:
136214
self._text = None # save a None value since text string is not saved
137215

138-
# limit padding to >= 0
139-
padding_top = max(0, padding_top)
140-
padding_bottom = max(0, padding_bottom)
141-
padding_left = max(0, padding_left)
142-
padding_right = max(0, padding_right)
143-
144-
# Calculate the text bounding box
145-
146-
# Calculate tight box to provide bounding box dimensions to match label for
147-
# anchor_position calculations
148-
(
149-
tight_box_x,
150-
tight_box_y,
151-
tight_x_offset,
152-
tight_y_offset,
153-
) = self._text_bounding_box(
154-
text, font, self._line_spacing, background_tight=True,
155-
)
156-
157-
if background_tight:
158-
box_x = tight_box_x
159-
box_y = tight_box_y
160-
y_offset = tight_y_offset
161-
x_offset = tight_x_offset
162-
163-
else:
164-
(box_x, box_y, x_offset, y_offset) = self._text_bounding_box(
165-
text, font, self._line_spacing, background_tight=background_tight,
166-
)
167-
# Calculate the background size including padding
168-
box_x = box_x + padding_left + padding_right
169-
box_y = box_y + padding_top + padding_bottom
216+
# Scale will be passed to Group using kwargs.
217+
if "scale" in kwargs.keys():
218+
self._scale = kwargs["scale"]
170219

171-
# Create the two-color palette
172-
self.palette = displayio.Palette(2)
173220

174-
self.background_color = background_color
175-
self.color = color
221+
# Check for empty string
222+
if (text == "") or (text is None): # If empty string, just create a zero-sized bounding box and that's it.
176223

177-
# Create the bitmap and TileGrid
178-
self.bitmap = displayio.Bitmap(box_x, box_y, len(self.palette))
179-
180-
# Place the text into the Bitmap
181-
self._place_text(
182-
self.bitmap,
183-
text,
184-
font,
185-
self._line_spacing,
186-
padding_left - x_offset,
187-
padding_top + y_offset,
188-
)
189-
190-
label_position_yoffset = int( # To calibrate with label.py positioning
191-
(font.get_glyph(ord("M")).height) / 2
192-
)
193-
194-
self.tilegrid = displayio.TileGrid(
195-
self.bitmap,
196-
pixel_shader=self.palette,
197-
width=1,
198-
height=1,
199-
tile_width=box_x,
200-
tile_height=box_y,
201-
default_tile=0,
202-
x=-padding_left + x_offset,
203-
y=label_position_yoffset - y_offset - padding_top,
204-
)
224+
self._bounding_box = (
225+
0,
226+
0,
227+
0, # zero width with text == ""
228+
0, # zero height with text == ""
229+
)
230+
# Clear out any items in the self Group, in case this is an update to the bitmap_label
231+
for item in self:
232+
self.pop(0)
233+
234+
else: # The text string is not empty, so create the Bitmap and TileGrid and append to the self Group
235+
236+
237+
# Calculate the text bounding box
238+
239+
# Calculate tight box to provide bounding box dimensions to match label for
240+
# anchor_position calculations
241+
(
242+
tight_box_x,
243+
tight_box_y,
244+
tight_x_offset,
245+
tight_y_offset,
246+
) = self._text_bounding_box(
247+
text, self._font, self._line_spacing, background_tight=True,
248+
) # calculate the box size for a tight background
249+
250+
if self._background_tight:
251+
box_x = tight_box_x
252+
box_y = tight_box_y
253+
y_offset = tight_y_offset
254+
x_offset = tight_x_offset
255+
256+
else: # calculate the box size for a loose background
257+
(box_x, box_y, x_offset, y_offset) = self._text_bounding_box(
258+
text, self._font, self._line_spacing, background_tight=self._background_tight,
259+
)
260+
# Calculate the background size including padding
261+
box_x = box_x + self._padding_left + self._padding_right
262+
box_y = box_y + self._padding_top + self._padding_bottom
263+
264+
# Create the bitmap and TileGrid
265+
self.bitmap = displayio.Bitmap(box_x, box_y, len(self.palette))
266+
267+
# Place the text into the Bitmap
268+
self._place_text(
269+
self.bitmap,
270+
text,
271+
self._font,
272+
self._line_spacing,
273+
self._padding_left - x_offset,
274+
self._padding_top + y_offset,
275+
)
205276

206-
# instance the Group
207-
# this Group will contain just one TileGrid with one contained bitmap
208-
super().__init__(
209-
max_size=1, x=x, y=y, **kwargs
210-
) # this will include any arguments, including scale
211-
self.append(self.tilegrid) # add the bitmap's tilegrid to the group
277+
label_position_yoffset = int( # To calibrate with label.py positioning
278+
(self._font.get_glyph(ord("M")).height) / 2
279+
)
212280

213-
# Update bounding_box values. Note: To be consistent with label.py,
214-
# this is the bounding box for the text only, not including the background.
281+
self.tilegrid = displayio.TileGrid(
282+
self.bitmap,
283+
pixel_shader=self.palette,
284+
width=1,
285+
height=1,
286+
tile_width=box_x,
287+
tile_height=box_y,
288+
default_tile=0,
289+
x=-self._padding_left + x_offset,
290+
y=label_position_yoffset - y_offset - self._padding_top,
291+
)
215292

216-
self._bounding_box = (
217-
self.tilegrid.x,
218-
self.tilegrid.y,
219-
tight_box_x,
220-
tight_box_y,
221-
)
293+
# Clear out any items in the self Group, in case this is an update to the bitmap_label
294+
for item in self:
295+
self.pop(0)
296+
self.append(self.tilegrid) # add the bitmap's tilegrid to the group
297+
298+
# Update bounding_box values. Note: To be consistent with label.py,
299+
# this is the bounding box for the text only, not including the background.
300+
self._bounding_box = (
301+
self.tilegrid.x,
302+
self.tilegrid.y,
303+
tight_box_x,
304+
tight_box_y,
305+
)
222306

223-
self._anchored_position = anchored_position
224-
self.anchor_point = anchor_point
225307
self.anchored_position = (
226308
self._anchored_position
227-
) # sets anchored_position with setter after bitmap is created
309+
) # set the anchored_position with setter after bitmap is created, sets the x,y positions of the label
228310

229311
@staticmethod
230312
def _line_spacing_ypixels(font, line_spacing):
@@ -240,7 +322,7 @@ def _text_bounding_box(self, text, font, line_spacing, background_tight=False):
240322
# descender, will depend upon font used
241323

242324
try:
243-
self._font.load_glyphs(text + glyphs)
325+
font.load_glyphs(text + glyphs)
244326
except AttributeError:
245327
# ignore if font does not have load_glyphs
246328
pass
@@ -434,9 +516,8 @@ def line_spacing(self):
434516

435517
@line_spacing.setter
436518
def line_spacing(self, new_line_spacing):
437-
raise RuntimeError(
438-
"line_spacing is immutable for bitmap_label.py; use label.py for mutable line_spacing"
439-
)
519+
self._reset_text(line_spacing=new_line_spacing)
520+
440521

441522
@property
442523
def color(self):
@@ -473,11 +554,10 @@ def text(self):
473554
"""Text to displayed."""
474555
return self._text
475556

476-
@text.setter
557+
@text.setter # Cannot set color or background color with text setter, use separate setter
477558
def text(self, new_text):
478-
raise RuntimeError(
479-
"text is immutable for bitmap_label.py; use label.py library for mutable text"
480-
)
559+
self._reset_text(text=new_text)
560+
print('updated text: {}'.format(new_text))
481561

482562
@property
483563
def font(self):
@@ -486,9 +566,7 @@ def font(self):
486566

487567
@font.setter
488568
def font(self, new_font):
489-
raise RuntimeError(
490-
"font is immutable for bitmap_label.py; use label.py library for mutable font"
491-
)
569+
self._reset_text(font=new_font)
492570

493571
@property
494572
def anchor_point(self):

0 commit comments

Comments
 (0)