Skip to content

Commit 11ee4d0

Browse files
authored
Merge pull request #126 from FoamyGuy/label_base_class
Label base class
2 parents d91f5d3 + 43398ef commit 11ee4d0

File tree

3 files changed

+298
-383
lines changed

3 files changed

+298
-383
lines changed

adafruit_display_text/__init__.py

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66
Display Text module helper functions
77
"""
8+
from displayio import Group, Palette
89

910

1011
def wrap_text_to_pixels(string, max_width, font=None, indent0="", indent1=""):
@@ -141,3 +142,224 @@ def chunks(lst, n):
141142
if the_lines[0][0] == " ":
142143
the_lines[0] = the_lines[0][1:]
143144
return the_lines
145+
146+
147+
class LabelBase(Group):
148+
"""Super class that all other types of labels will extend. This contains
149+
all of the properties and functions that work the same way in all labels.
150+
151+
subclasses should implement _set_text, _set_font, and _set_line_spacing to
152+
have the correct behavior fo rthat type of label.
153+
154+
:param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``.
155+
Must include a capital M for measuring character size.
156+
:param str text: Text to display
157+
:param int max_glyphs: Unnecessary parameter (provided only for direct compability
158+
with label.py)
159+
:param int color: Color of all text in RGB hex
160+
:param int background_color: Color of the background, use `None` for transparent
161+
:param double line_spacing: Line spacing of text to display
162+
:param boolean background_tight: Set `True` only if you want background box to tightly
163+
surround text. When set to 'True' Padding parameters will be ignored.
164+
:param int padding_top: Additional pixels added to background bounding box at top
165+
:param int padding_bottom: Additional pixels added to background bounding box at bottom
166+
:param int padding_left: Additional pixels added to background bounding box at left
167+
:param int padding_right: Additional pixels added to background bounding box at right
168+
:param (float,float) anchor_point: Point that anchored_position moves relative to.
169+
Tuple with decimal percentage of width and height.
170+
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)
171+
:param (int,int) anchored_position: Position relative to the anchor_point. Tuple
172+
containing x,y pixel coordinates.
173+
:param int scale: Integer value of the pixel scaling
174+
:param bool save_text: Set True to save the text string as a constant in the
175+
label structure. Set False to reduce memory use.
176+
:param: bool base_alignment: when True allows to align text label to the baseline.
177+
This is helpful when two or more labels need to be aligned to the same baseline"""
178+
179+
# pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments
180+
def __init__(
181+
self,
182+
font,
183+
x=0,
184+
y=0,
185+
text="",
186+
max_glyphs=None,
187+
# with label.py
188+
color=0xFFFFFF,
189+
background_color=None,
190+
line_spacing=1.25,
191+
background_tight=False,
192+
padding_top=0,
193+
padding_bottom=0,
194+
padding_left=0,
195+
padding_right=0,
196+
anchor_point=None,
197+
anchored_position=None,
198+
save_text=True, # can reduce memory use if save_text = False
199+
scale=1,
200+
base_alignment=False,
201+
**kwargs,
202+
):
203+
super().__init__(max_size=1, x=x, y=y, scale=1)
204+
205+
self._font = font
206+
self.palette = Palette(2)
207+
self._color = color
208+
self._background_color = background_color
209+
210+
self._bounding_box = None
211+
self._anchor_point = anchor_point
212+
self._anchored_position = anchored_position
213+
214+
# local group will hold background and text
215+
# the self group scale should always remain at 1, the self.local_group will
216+
# be used to set the scale of the label
217+
self.local_group = None
218+
219+
self._text = text
220+
221+
def _get_ascent_descent(self):
222+
""" Private function to calculate ascent and descent font values """
223+
if hasattr(self.font, "ascent"):
224+
return self.font.ascent, self.font.descent
225+
226+
# check a few glyphs for maximum ascender and descender height
227+
glyphs = "M j'" # choose glyphs with highest ascender and lowest
228+
try:
229+
self._font.load_glyphs(glyphs)
230+
except AttributeError:
231+
# Builtin font doesn't have or need load_glyphs
232+
pass
233+
# descender, will depend upon font used
234+
ascender_max = descender_max = 0
235+
for char in glyphs:
236+
this_glyph = self._font.get_glyph(ord(char))
237+
if this_glyph:
238+
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
239+
descender_max = max(descender_max, -this_glyph.dy)
240+
return ascender_max, descender_max
241+
242+
def _get_ascent(self):
243+
return self._get_ascent_descent()[0]
244+
245+
@property
246+
def font(self):
247+
"""Font to use for text display."""
248+
return self._font
249+
250+
def _set_font(self, new_font):
251+
# subclasses should override this
252+
pass
253+
254+
@font.setter
255+
def font(self, new_font):
256+
self._set_font(new_font)
257+
258+
@property
259+
def color(self):
260+
"""Color of the text as an RGB hex number."""
261+
return self._color
262+
263+
@color.setter
264+
def color(self, new_color):
265+
self._color = new_color
266+
if new_color is not None:
267+
self.palette[1] = new_color
268+
self.palette.make_opaque(1)
269+
else:
270+
self.palette[1] = 0
271+
self.palette.make_transparent(1)
272+
273+
@property
274+
def background_color(self):
275+
"""Color of the background as an RGB hex number."""
276+
return self._background_color
277+
278+
@background_color.setter
279+
def background_color(self, new_color):
280+
self._background_color = new_color
281+
if new_color is not None:
282+
self.palette[0] = new_color
283+
self.palette.make_opaque(0)
284+
else:
285+
self.palette[0] = 0
286+
self.palette.make_transparent(0)
287+
288+
@property
289+
def anchor_point(self):
290+
"""Point that anchored_position moves relative to.
291+
Tuple with decimal percentage of width and height.
292+
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)"""
293+
return self._anchor_point
294+
295+
@anchor_point.setter
296+
def anchor_point(self, new_anchor_point):
297+
self._anchor_point = new_anchor_point
298+
self.anchored_position = (
299+
self._anchored_position
300+
) # update the anchored_position using setter
301+
302+
@property
303+
def anchored_position(self):
304+
"""Position relative to the anchor_point. Tuple containing x,y
305+
pixel coordinates."""
306+
return self._anchored_position
307+
308+
@anchored_position.setter
309+
def anchored_position(self, new_position):
310+
self._anchored_position = new_position
311+
# Set anchored_position
312+
if (self._anchor_point is not None) and (self._anchored_position is not None):
313+
self.x = int(
314+
new_position[0]
315+
- (self._bounding_box[0] * self.scale)
316+
- round(self._anchor_point[0] * (self._bounding_box[2] * self.scale))
317+
)
318+
self.y = int(
319+
new_position[1]
320+
- (self._bounding_box[1] * self.scale)
321+
- round(self._anchor_point[1] * self._bounding_box[3] * self.scale)
322+
)
323+
324+
@property
325+
def scale(self):
326+
"""Set the scaling of the label, in integer values"""
327+
return self.local_group.scale
328+
329+
@scale.setter
330+
def scale(self, new_scale):
331+
self.local_group.scale = new_scale
332+
self.anchored_position = self._anchored_position # update the anchored_position
333+
334+
def _set_text(self, new_text, scale):
335+
# subclasses should override this
336+
pass
337+
338+
@property
339+
def text(self):
340+
"""Text to be displayed."""
341+
return self._text
342+
343+
@text.setter # Cannot set color or background color with text setter, use separate setter
344+
def text(self, new_text):
345+
self._set_text(new_text, self.scale)
346+
347+
@property
348+
def bounding_box(self):
349+
"""An (x, y, w, h) tuple that completely covers all glyphs. The
350+
first two numbers are offset from the x, y origin of this group"""
351+
return tuple(self._bounding_box)
352+
353+
@property
354+
def line_spacing(self):
355+
"""The amount of space between lines of text, in multiples of the font's
356+
bounding-box height. (E.g. 1.0 is the bounding-box height)"""
357+
return self._line_spacing
358+
359+
def _set_line_spacing(self, new_line_spacing):
360+
# subclass should override this.
361+
pass
362+
363+
@line_spacing.setter
364+
def line_spacing(self, new_line_spacing):
365+
self._set_line_spacing(new_line_spacing)

0 commit comments

Comments
 (0)