Skip to content

Bitmap label base alignment #120

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 12 commits into from
Feb 20, 2021
Merged
26 changes: 19 additions & 7 deletions adafruit_display_text/bitmap_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Label(displayio.Group):
Note: This ``bitmap_label.py`` library utilizes a bitmap to display the text.
This method is memory-conserving relative to ``label.py``.
The ``max_glyphs`` parameter is ignored and is present
only for direct compatability with label.py.
only for direct compatibility with label.py.

For further reduction in memory usage, set ``save_text=False`` (text string will not
be stored and ``line_spacing`` and ``font`` are immutable with ``save_text``
Expand All @@ -54,19 +54,21 @@ class Label(displayio.Group):
:param int background_color: Color of the background, use `None` for transparent
:param double line_spacing: Line spacing of text to display
:param boolean background_tight: Set `True` only if you want background box to tightly
surround text
surround text. When set to 'True' Padding parameters will be ignored.
:param int padding_top: Additional pixels added to background bounding box at top
:param int padding_bottom: Additional pixels added to background bounding box at bottom
:param int padding_left: Additional pixels added to background bounding box at left
:param int padding_right: Additional pixels added to background bounding box at right
:param (double,double) anchor_point: Point that anchored_position moves relative to.
:param (float,float) anchor_point: Point that anchored_position moves relative to.
Tuple with decimal percentage of width and height.
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)
:param (int,int) anchored_position: Position relative to the anchor_point. Tuple
containing x,y pixel coordinates.
:param int scale: Integer value of the pixel scaling
:param bool save_text: Set True to save the text string as a constant in the
label structure. Set False to reduce memory use."""
label structure. Set False to reduce memory use.
:param: bool base_alignment: when True allows to align text label to the baseline.
This is helpful when two or more labels need to be aligned to the same baseline"""

# pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments
# pylint: disable=too-many-branches, no-self-use, too-many-statements
Expand All @@ -93,6 +95,7 @@ def __init__(
anchored_position=None,
save_text=True, # can reduce memory use if save_text = False
scale=1,
base_alignment=False,
**kwargs,
):

Expand Down Expand Up @@ -128,6 +131,8 @@ def __init__(
self._anchor_point = anchor_point
self._anchored_position = anchored_position

self.base_alignment = base_alignment

# call the text updater with all the arguments.
self._reset_text(
font=font,
Expand All @@ -144,6 +149,7 @@ def __init__(
anchored_position=anchored_position,
save_text=save_text,
scale=scale,
base_alignment=base_alignment,
)

def _reset_text(
Expand All @@ -162,6 +168,7 @@ def _reset_text(
anchored_position=None,
save_text=None,
scale=None,
base_alignment=None,
):

# Store all the instance variables
Expand Down Expand Up @@ -189,6 +196,8 @@ def _reset_text(
self._anchored_position = anchored_position
if save_text is not None:
self._save_text = save_text
if base_alignment is not None:
self.base_alignment = base_alignment

# if text is not provided as a parameter (text is None), use the previous value.
if (text is None) and self._save_text:
Expand Down Expand Up @@ -260,8 +269,10 @@ def _reset_text(
self._padding_top + y_offset,
)

# To calibrate with label.py positioning
label_position_yoffset = self._get_ascent() // 2
if self.base_alignment:
label_position_yoffset = 0
else:
label_position_yoffset = self._get_ascent() // 2

self.tilegrid = displayio.TileGrid(
self.bitmap,
Expand Down Expand Up @@ -303,6 +314,7 @@ def _reset_text(
# x,y positions of the label

def _get_ascent_descent(self):
""" Private function to calculate ascent and descent font values """
if hasattr(self.font, "ascent"):
return self.font.ascent, self.font.descent

Expand Down Expand Up @@ -615,7 +627,7 @@ def background_color(self, new_color):

@property
def text(self):
"""Text to displayed."""
"""Text to be displayed."""
return self._text

@text.setter # Cannot set color or background color with text setter, use separate setter
Expand Down
17 changes: 13 additions & 4 deletions adafruit_display_text/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ class Label(displayio.Group):
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)
:param (int,int) anchored_position: Position relative to the anchor_point. Tuple
containing x,y pixel coordinates.
:param int scale: Integer value of the pixel scaling"""
:param int scale: Integer value of the pixel scaling
:param bool base_alignment: when True allows to align text label to the baseline.
This is helpful when two or more labels need to be aligned to the same baseline"""

# pylint: disable=too-many-instance-attributes, too-many-locals
# This has a lot of getters/setters, maybe it needs cleanup.
Expand All @@ -83,6 +85,7 @@ def __init__(
anchor_point=None,
anchored_position=None,
scale=1,
base_alignment=False,
**kwargs
):
if not max_glyphs and not text:
Expand Down Expand Up @@ -129,6 +132,7 @@ def __init__(
self._padding_bottom = padding_bottom
self._padding_left = padding_left
self._padding_right = padding_right
self.base_alignment = base_alignment

if text is not None:
self._update_text(str(text))
Expand Down Expand Up @@ -159,7 +163,10 @@ def _create_background_box(self, lines, y_offset):
+ self._padding_top
+ self._padding_bottom
)
y_box_offset = -ascent + y_offset - self._padding_top
if self.base_alignment:
y_box_offset = -ascent - self._padding_top
else:
y_box_offset = -ascent + y_offset - self._padding_top

box_width = max(0, box_width) # remove any negative values
box_height = max(0, box_height) # remove any negative values
Expand Down Expand Up @@ -263,8 +270,10 @@ def _update_text(
else:
i = 0
tilegrid_count = i

y_offset = self._get_ascent() // 2
if self.base_alignment:
y_offset = 0
else:
y_offset = self._get_ascent() // 2

right = top = bottom = 0
left = None
Expand Down
75 changes: 75 additions & 0 deletions examples/display_text_label_align_baseline_comparison.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# SPDX-FileCopyrightText: 2021 Jose David Montoya for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
This example shows the use of base_alignment parameter.
"""

import board
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label


display = board.DISPLAY

# Font definition. You can choose any two fonts available in your system
MEDIUM_FONT = bitmap_font.load_font("LeagueSpartan-Bold-16.bdf")
BIG_FONT = bitmap_font.load_font("IBMPlexMono-Medium-24_jep.bdf")

TEXT_RIGHT = "MG"
TEXT_LEFT = "32.47"

main_group = displayio.Group()

# Create labels
# Base Alignment parameter False
left_text = label.Label(
BIG_FONT,
text=TEXT_LEFT,
color=0x000000,
background_color=0x999999,
x=10,
y=50,
base_alignment=False,
)
main_group.append(left_text)

right_text = label.Label(
MEDIUM_FONT,
text=TEXT_RIGHT,
color=0x000000,
background_color=0x999999,
x=80,
y=50,
base_alignment=False,
)
main_group.append(right_text)

# Base Alignment parameter True
left_text_aligned = label.Label(
BIG_FONT,
text=TEXT_LEFT,
color=0x000000,
background_color=0x999999,
x=10,
y=100,
base_alignment=True,
)
main_group.append(left_text_aligned)

right_text_aligned = label.Label(
MEDIUM_FONT,
text=TEXT_RIGHT,
color=0x000000,
background_color=0x999999,
x=80,
y=100,
base_alignment=True,
)

main_group.append(right_text_aligned)
display.show(main_group)

while True:
pass