Compare commits
No commits in common. "use-ascent-descent" and "master" have entirely different histories.
use-ascent
...
master
7 changed files with 210 additions and 584 deletions
|
|
@ -1,69 +0,0 @@
|
||||||
"""
|
|
||||||
Display Text module helper functions
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# The MIT License (MIT)
|
|
||||||
#
|
|
||||||
# Copyright (c) 2020 Tim C for Adafruit Industries LLC
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
# THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_text_to_lines(string, max_chars):
|
|
||||||
"""wrap_text_to_lines function
|
|
||||||
A helper that will return a list of lines with word-break wrapping
|
|
||||||
|
|
||||||
:param str string: The text to be wrapped
|
|
||||||
:param int max_chars: The maximum number of characters on a line before wrapping
|
|
||||||
|
|
||||||
:return list the_lines: A list of lines where each line is separated based on the amount
|
|
||||||
of max_chars provided
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def chunks(lst, n):
|
|
||||||
"""Yield successive n-sized chunks from lst."""
|
|
||||||
for i in range(0, len(lst), n):
|
|
||||||
yield lst[i : i + n]
|
|
||||||
|
|
||||||
string = string.replace("\n", "").replace("\r", "") # Strip confusing newlines
|
|
||||||
words = string.split(" ")
|
|
||||||
the_lines = []
|
|
||||||
the_line = ""
|
|
||||||
for w in words:
|
|
||||||
if len(w) > max_chars:
|
|
||||||
parts = []
|
|
||||||
for part in chunks(w, max_chars - 1):
|
|
||||||
parts.append("{}-".format(part))
|
|
||||||
the_lines.extend(parts[:-1])
|
|
||||||
the_line = parts[-1][:-1]
|
|
||||||
continue
|
|
||||||
|
|
||||||
if len(the_line + " " + w) <= max_chars:
|
|
||||||
the_line += " " + w
|
|
||||||
else:
|
|
||||||
the_lines.append(the_line)
|
|
||||||
the_line = "" + w
|
|
||||||
if the_line: # Last line remaining
|
|
||||||
the_lines.append(the_line)
|
|
||||||
# Remove first space from first line:
|
|
||||||
if the_lines[0][0] == " ":
|
|
||||||
the_lines[0] = the_lines[0][1:]
|
|
||||||
return the_lines
|
|
||||||
|
|
@ -50,12 +50,13 @@ class Label(displayio.Group):
|
||||||
"""A label displaying a string of text that is stored in a bitmap.
|
"""A label displaying a string of text that is stored in a bitmap.
|
||||||
Note: This ``bitmap_label.py`` library utilizes a bitmap to display the text.
|
Note: This ``bitmap_label.py`` library utilizes a bitmap to display the text.
|
||||||
This method is memory-conserving relative to ``label.py``.
|
This method is memory-conserving relative to ``label.py``.
|
||||||
The ``max_glyphs`` parameter is ignored and is present
|
For the bitmap_label library, the font, text, and line_spacing must be set at
|
||||||
|
instancing and are immutable. The ``max_glyphs`` parameter is ignored and is present
|
||||||
only for direct compatability with label.py.
|
only for direct compatability with label.py.
|
||||||
|
For use cases where text changes are required after the initial instancing, please
|
||||||
For further reduction in memory usage, set ``save_text=False`` (text string will not
|
use the `label.py` library.
|
||||||
be stored and ``line_spacing`` and ``font`` are immutable with ``save_text``
|
For further reduction in memory usage, set save_text to False (text string will not
|
||||||
set to ``False``).
|
be stored).
|
||||||
|
|
||||||
The origin point set by ``x`` and ``y``
|
The origin point set by ``x`` and ``y``
|
||||||
properties will be the left edge of the bounding box, and in the center of a M
|
properties will be the left edge of the bounding box, and in the center of a M
|
||||||
|
|
@ -66,28 +67,28 @@ class Label(displayio.Group):
|
||||||
Must include a capital M for measuring character size.
|
Must include a capital M for measuring character size.
|
||||||
:param str text: Text to display
|
:param str text: Text to display
|
||||||
:param int max_glyphs: Unnecessary parameter (provided only for direct compability
|
:param int max_glyphs: Unnecessary parameter (provided only for direct compability
|
||||||
with label.py)
|
with label.py)
|
||||||
:param int color: Color of all text in RGB hex
|
:param int color: Color of all text in RGB hex
|
||||||
:param int background_color: Color of the background, use `None` for transparent
|
:param int background_color: Color of the background, use `None` for transparent
|
||||||
:param double line_spacing: Line spacing of text to display
|
:param double line_spacing: Line spacing of text to display
|
||||||
:param boolean background_tight: Set `True` only if you want background box to tightly
|
:param boolean background_tight: Set `True` only if you want background box to tightly
|
||||||
surround text
|
surround text
|
||||||
:param int padding_top: Additional pixels added to background bounding box at top
|
: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_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_left: Additional pixels added to background bounding box at left
|
||||||
:param int padding_right: Additional pixels added to background bounding box at right
|
: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 (double,double) anchor_point: Point that anchored_position moves relative to.
|
||||||
Tuple with decimal percentage of width and height.
|
Tuple with decimal percentage of width and height.
|
||||||
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)
|
(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
|
:param (int,int) anchored_position: Position relative to the anchor_point. Tuple
|
||||||
containing x,y pixel coordinates.
|
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 save_text: Set True to save the text string as a constant in the
|
: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.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments
|
# 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
|
# pylint: disable=too-many-branches, no-self-use
|
||||||
# Note: max_glyphs parameter is unnecessary, this is used for direct
|
# Note: max_glyphs parameter is unnecessary, this is used for direct
|
||||||
# compatibility with label.py
|
# compatibility with label.py
|
||||||
|
|
||||||
|
|
@ -110,217 +111,128 @@ class Label(displayio.Group):
|
||||||
anchor_point=None,
|
anchor_point=None,
|
||||||
anchored_position=None,
|
anchored_position=None,
|
||||||
save_text=True, # can reduce memory use if save_text = False
|
save_text=True, # can reduce memory use if save_text = False
|
||||||
scale=1,
|
**kwargs
|
||||||
**kwargs,
|
|
||||||
):
|
):
|
||||||
|
|
||||||
# instance the Group
|
if text == "":
|
||||||
# self Group will contain a single local_group which contains a Group (self.local_group)
|
raise RuntimeError(
|
||||||
# which contains a TileGrid (self.tilegrid) which contains the text bitmap (self.bitmap)
|
"Please provide text string, or use label.py for mutable text"
|
||||||
super().__init__(
|
)
|
||||||
max_size=1, x=x, y=y, scale=1, **kwargs,
|
|
||||||
)
|
|
||||||
# the self group scale should always remain at 1, the self.local_group will
|
|
||||||
# be used to set the scale
|
|
||||||
# **kwargs will pass any additional arguments provided to the Label
|
|
||||||
|
|
||||||
self.local_group = displayio.Group(
|
|
||||||
max_size=1, scale=scale
|
|
||||||
) # local_group holds the tileGrid and sets the scaling
|
|
||||||
self.append(
|
|
||||||
self.local_group
|
|
||||||
) # the local_group will always stay in the self Group
|
|
||||||
|
|
||||||
self._font = font
|
self._font = font
|
||||||
self._text = text
|
|
||||||
|
|
||||||
# Create the two-color palette
|
# Scale will be passed to Group using kwargs.
|
||||||
self.palette = displayio.Palette(2)
|
if "scale" in kwargs.keys():
|
||||||
self.color = color
|
self._scale = kwargs["scale"]
|
||||||
self.background_color = background_color
|
else:
|
||||||
|
self._scale = 1
|
||||||
|
|
||||||
self._anchor_point = anchor_point
|
self._line_spacing = line_spacing
|
||||||
self._anchored_position = anchored_position
|
self._save_text = save_text
|
||||||
|
|
||||||
# call the text updater with all the arguments.
|
|
||||||
self._reset_text(
|
|
||||||
font=font,
|
|
||||||
x=x,
|
|
||||||
y=y,
|
|
||||||
text=text,
|
|
||||||
line_spacing=line_spacing,
|
|
||||||
background_tight=background_tight,
|
|
||||||
padding_top=padding_top,
|
|
||||||
padding_bottom=padding_bottom,
|
|
||||||
padding_left=padding_left,
|
|
||||||
padding_right=padding_right,
|
|
||||||
anchor_point=anchor_point,
|
|
||||||
anchored_position=anchored_position,
|
|
||||||
save_text=save_text,
|
|
||||||
scale=scale,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _reset_text(
|
|
||||||
self,
|
|
||||||
font=None,
|
|
||||||
x=None,
|
|
||||||
y=None,
|
|
||||||
text=None,
|
|
||||||
line_spacing=None,
|
|
||||||
background_tight=None,
|
|
||||||
padding_top=None,
|
|
||||||
padding_bottom=None,
|
|
||||||
padding_left=None,
|
|
||||||
padding_right=None,
|
|
||||||
anchor_point=None,
|
|
||||||
anchored_position=None,
|
|
||||||
save_text=None,
|
|
||||||
scale=None,
|
|
||||||
):
|
|
||||||
|
|
||||||
# Store all the instance variables
|
|
||||||
if font is not None:
|
|
||||||
self._font = font
|
|
||||||
if x is not None:
|
|
||||||
self.x = x
|
|
||||||
if y is not None:
|
|
||||||
self.y = y
|
|
||||||
if line_spacing is not None:
|
|
||||||
self._line_spacing = line_spacing
|
|
||||||
if background_tight is not None:
|
|
||||||
self._background_tight = background_tight
|
|
||||||
if padding_top is not None:
|
|
||||||
self._padding_top = max(0, padding_top)
|
|
||||||
if padding_bottom is not None:
|
|
||||||
self._padding_bottom = max(0, padding_bottom)
|
|
||||||
if padding_left is not None:
|
|
||||||
self._padding_left = max(0, padding_left)
|
|
||||||
if padding_right is not None:
|
|
||||||
self._padding_right = max(0, padding_right)
|
|
||||||
if anchor_point is not None:
|
|
||||||
self.anchor_point = anchor_point
|
|
||||||
if anchored_position is not None:
|
|
||||||
self._anchored_position = anchored_position
|
|
||||||
if save_text is not None:
|
|
||||||
self._save_text = save_text
|
|
||||||
if (
|
|
||||||
scale is not None
|
|
||||||
): # Scale will be defined in local_group (Note: self should have scale=1)
|
|
||||||
self.scale = scale # call the setter
|
|
||||||
|
|
||||||
# if text is not provided as a parameter (text is None), use the previous value.
|
|
||||||
if (text is None) and self._save_text:
|
|
||||||
text = self._text
|
|
||||||
|
|
||||||
if self._save_text: # text string will be saved
|
if self._save_text: # text string will be saved
|
||||||
self._text = text
|
self._text = text
|
||||||
else:
|
else:
|
||||||
self._text = None # save a None value since text string is not saved
|
self._text = None # save a None value since text string is not saved
|
||||||
|
|
||||||
# Check for empty string
|
# limit padding to >= 0
|
||||||
if (text == "") or (
|
padding_top = max(0, padding_top)
|
||||||
text is None
|
padding_bottom = max(0, padding_bottom)
|
||||||
): # If empty string, just create a zero-sized bounding box and that's it.
|
padding_left = max(0, padding_left)
|
||||||
|
padding_right = max(0, padding_right)
|
||||||
|
|
||||||
self._bounding_box = (
|
# Calculate the text bounding box
|
||||||
0,
|
|
||||||
0,
|
# Calculate tight box to provide bounding box dimensions to match label for
|
||||||
0, # zero width with text == ""
|
# anchor_position calculations
|
||||||
0, # zero height with text == ""
|
(
|
||||||
|
tight_box_x,
|
||||||
|
tight_box_y,
|
||||||
|
tight_x_offset,
|
||||||
|
tight_y_offset,
|
||||||
|
) = self._text_bounding_box(
|
||||||
|
text, font, self._line_spacing, background_tight=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if background_tight:
|
||||||
|
box_x = tight_box_x
|
||||||
|
box_y = tight_box_y
|
||||||
|
y_offset = tight_y_offset
|
||||||
|
x_offset = tight_x_offset
|
||||||
|
|
||||||
|
else:
|
||||||
|
(box_x, box_y, x_offset, y_offset) = self._text_bounding_box(
|
||||||
|
text, font, self._line_spacing, background_tight=background_tight,
|
||||||
)
|
)
|
||||||
# Clear out any items in the self.local_group Group, in case this is an
|
# Calculate the background size including padding
|
||||||
# update to the bitmap_label
|
box_x = box_x + padding_left + padding_right
|
||||||
for _ in self.local_group:
|
box_y = box_y + padding_top + padding_bottom
|
||||||
self.local_group.pop(0)
|
|
||||||
|
|
||||||
else: # The text string is not empty, so create the Bitmap and TileGrid and
|
# Create the two-color palette
|
||||||
# append to the self Group
|
self.palette = displayio.Palette(2)
|
||||||
|
|
||||||
# Calculate the text bounding box
|
self.background_color = background_color
|
||||||
|
self.color = color
|
||||||
|
|
||||||
# Calculate both "tight" and "loose" bounding box dimensions to match label for
|
# Create the bitmap and TileGrid
|
||||||
# anchor_position calculations
|
self.bitmap = displayio.Bitmap(box_x, box_y, len(self.palette))
|
||||||
(
|
|
||||||
box_x,
|
|
||||||
tight_box_y,
|
|
||||||
x_offset,
|
|
||||||
tight_y_offset,
|
|
||||||
loose_box_y,
|
|
||||||
loose_y_offset,
|
|
||||||
) = self._text_bounding_box(
|
|
||||||
text, self._font, self._line_spacing,
|
|
||||||
) # calculate the box size for a tight and loose backgrounds
|
|
||||||
|
|
||||||
if self._background_tight:
|
# Place the text into the Bitmap
|
||||||
box_y = tight_box_y
|
self._place_text(
|
||||||
y_offset = tight_y_offset
|
self.bitmap,
|
||||||
|
text,
|
||||||
|
font,
|
||||||
|
self._line_spacing,
|
||||||
|
padding_left - x_offset,
|
||||||
|
padding_top + y_offset,
|
||||||
|
)
|
||||||
|
|
||||||
else: # calculate the box size for a loose background
|
label_position_yoffset = int( # To calibrate with label.py positioning
|
||||||
box_y = loose_box_y
|
(font.get_glyph(ord("M")).height) / 2
|
||||||
y_offset = loose_y_offset
|
)
|
||||||
|
|
||||||
# Calculate the background size including padding
|
self.tilegrid = displayio.TileGrid(
|
||||||
box_x = box_x + self._padding_left + self._padding_right
|
self.bitmap,
|
||||||
box_y = box_y + self._padding_top + self._padding_bottom
|
pixel_shader=self.palette,
|
||||||
|
width=1,
|
||||||
|
height=1,
|
||||||
|
tile_width=box_x,
|
||||||
|
tile_height=box_y,
|
||||||
|
default_tile=0,
|
||||||
|
x=-padding_left + x_offset,
|
||||||
|
y=label_position_yoffset - y_offset - padding_top,
|
||||||
|
)
|
||||||
|
|
||||||
# Create the bitmap and TileGrid
|
# instance the Group
|
||||||
self.bitmap = displayio.Bitmap(box_x, box_y, len(self.palette))
|
# this Group will contain just one TileGrid with one contained bitmap
|
||||||
|
super().__init__(
|
||||||
|
max_size=1, x=x, y=y, **kwargs
|
||||||
|
) # this will include any arguments, including scale
|
||||||
|
self.append(self.tilegrid) # add the bitmap's tilegrid to the group
|
||||||
|
|
||||||
# Place the text into the Bitmap
|
# Update bounding_box values. Note: To be consistent with label.py,
|
||||||
self._place_text(
|
# this is the bounding box for the text only, not including the background.
|
||||||
self.bitmap,
|
|
||||||
text,
|
|
||||||
self._font,
|
|
||||||
self._line_spacing,
|
|
||||||
self._padding_left - x_offset,
|
|
||||||
self._padding_top + y_offset,
|
|
||||||
)
|
|
||||||
|
|
||||||
label_position_yoffset = int( # To calibrate with label.py positioning
|
self._bounding_box = (
|
||||||
(self._font.get_glyph(ord("M")).height) / 2
|
self.tilegrid.x,
|
||||||
)
|
self.tilegrid.y,
|
||||||
|
tight_box_x,
|
||||||
self.tilegrid = displayio.TileGrid(
|
tight_box_y,
|
||||||
self.bitmap,
|
)
|
||||||
pixel_shader=self.palette,
|
|
||||||
width=1,
|
|
||||||
height=1,
|
|
||||||
tile_width=box_x,
|
|
||||||
tile_height=box_y,
|
|
||||||
default_tile=0,
|
|
||||||
x=-self._padding_left + x_offset,
|
|
||||||
y=label_position_yoffset - y_offset - self._padding_top,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Clear out any items in the local_group Group, in case this is an update to
|
|
||||||
# the bitmap_label
|
|
||||||
for _ in self.local_group:
|
|
||||||
self.local_group.pop(0)
|
|
||||||
self.local_group.append(
|
|
||||||
self.tilegrid
|
|
||||||
) # add the bitmap's tilegrid to the group
|
|
||||||
|
|
||||||
# Update bounding_box values. Note: To be consistent with label.py,
|
|
||||||
# this is the bounding box for the text only, not including the background.
|
|
||||||
self._bounding_box = (
|
|
||||||
self.tilegrid.x,
|
|
||||||
self.tilegrid.y,
|
|
||||||
box_x,
|
|
||||||
tight_box_y,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
self._anchored_position = anchored_position
|
||||||
|
self.anchor_point = anchor_point
|
||||||
self.anchored_position = (
|
self.anchored_position = (
|
||||||
self._anchored_position
|
self._anchored_position
|
||||||
) # set the anchored_position with setter after bitmap is created, sets the
|
) # sets anchored_position with setter after bitmap is created
|
||||||
# x,y positions of the label
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _line_spacing_ypixels(font, line_spacing):
|
def _line_spacing_ypixels(font, line_spacing):
|
||||||
# Note: Scaling is provided at the Group level
|
# Note: Scale is not implemented at this time, any scaling is pushed up to the Group level
|
||||||
return_value = int(line_spacing * font.get_bounding_box()[1])
|
return_value = int(line_spacing * font.get_bounding_box()[1])
|
||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
def _text_bounding_box(self, text, font, line_spacing):
|
def _text_bounding_box(self, text, font, line_spacing, background_tight=False):
|
||||||
|
|
||||||
# This empirical approach checks several glyphs for maximum ascender and descender height
|
# This empirical approach checks several glyphs for maximum ascender and descender height
|
||||||
# (consistent with label.py)
|
# (consistent with label.py)
|
||||||
|
|
@ -328,7 +240,7 @@ class Label(displayio.Group):
|
||||||
# descender, will depend upon font used
|
# descender, will depend upon font used
|
||||||
|
|
||||||
try:
|
try:
|
||||||
font.load_glyphs(text + glyphs)
|
self._font.load_glyphs(text + glyphs)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# ignore if font does not have load_glyphs
|
# ignore if font does not have load_glyphs
|
||||||
pass
|
pass
|
||||||
|
|
@ -351,6 +263,8 @@ class Label(displayio.Group):
|
||||||
top = bottom = y_start
|
top = bottom = y_start
|
||||||
|
|
||||||
y_offset_tight = int((font.get_glyph(ord("M")).height) / 2)
|
y_offset_tight = int((font.get_glyph(ord("M")).height) / 2)
|
||||||
|
# this needs to be reviewed (also in label.py), since it doesn't respond
|
||||||
|
# properly to the number of newlines.
|
||||||
|
|
||||||
newline = False
|
newline = False
|
||||||
|
|
||||||
|
|
@ -391,25 +305,17 @@ class Label(displayio.Group):
|
||||||
left = 0
|
left = 0
|
||||||
|
|
||||||
final_box_width = right - left
|
final_box_width = right - left
|
||||||
|
if background_tight:
|
||||||
|
final_box_height = bottom - top
|
||||||
|
final_y_offset = -top + y_offset_tight
|
||||||
|
|
||||||
final_box_height_tight = bottom - top
|
else:
|
||||||
final_y_offset_tight = -top + y_offset_tight
|
final_box_height = (lines - 1) * self._line_spacing_ypixels(
|
||||||
|
font, line_spacing
|
||||||
|
) + (ascender_max + descender_max)
|
||||||
|
final_y_offset = ascender_max
|
||||||
|
|
||||||
final_box_height_loose = (lines - 1) * self._line_spacing_ypixels(
|
return (final_box_width, final_box_height, left, final_y_offset)
|
||||||
font, line_spacing
|
|
||||||
) + (ascender_max + descender_max)
|
|
||||||
final_y_offset_loose = ascender_max
|
|
||||||
|
|
||||||
# return (final_box_width, final_box_height, left, final_y_offset)
|
|
||||||
|
|
||||||
return (
|
|
||||||
final_box_width,
|
|
||||||
final_box_height_tight,
|
|
||||||
left,
|
|
||||||
final_y_offset_tight,
|
|
||||||
final_box_height_loose,
|
|
||||||
final_y_offset_loose,
|
|
||||||
)
|
|
||||||
|
|
||||||
# pylint: disable=too-many-nested-blocks
|
# pylint: disable=too-many-nested-blocks
|
||||||
def _place_text(
|
def _place_text(
|
||||||
|
|
@ -422,13 +328,20 @@ class Label(displayio.Group):
|
||||||
yposition,
|
yposition,
|
||||||
text_palette_index=1,
|
text_palette_index=1,
|
||||||
background_palette_index=0,
|
background_palette_index=0,
|
||||||
skip_index=0, # set to None to write all pixels, other wise skip this palette index
|
print_only_pixels=True, # print_only_pixels = True: only update the bitmap where the glyph
|
||||||
# when copying glyph bitmaps (this is important for slanted text
|
# pixel color is > 0. This is especially useful for script fonts where glyph
|
||||||
# where rectangulary glyph boxes overlap)
|
# bounding boxes overlap
|
||||||
|
# Set `print_only_pixels=False` to write all pixels
|
||||||
):
|
):
|
||||||
# placeText - Writes text into a bitmap at the specified location.
|
# placeText - Writes text into a bitmap at the specified location.
|
||||||
#
|
#
|
||||||
# Note: scale is pushed up to Group level
|
# Verify paletteIndex is working properly with * operator, especially
|
||||||
|
# if accommodating multicolored fonts
|
||||||
|
#
|
||||||
|
# Note: Scale is not implemented at this time, is pushed up to Group level
|
||||||
|
|
||||||
|
bitmap_width = bitmap.width
|
||||||
|
bitmap_height = bitmap.height
|
||||||
|
|
||||||
x_start = xposition # starting x position (left margin)
|
x_start = xposition # starting x position (left margin)
|
||||||
y_start = yposition
|
y_start = yposition
|
||||||
|
|
@ -472,111 +385,47 @@ class Label(displayio.Group):
|
||||||
) # for type BuiltinFont, this creates the x-offset in the glyph bitmap.
|
) # for type BuiltinFont, this creates the x-offset in the glyph bitmap.
|
||||||
# for BDF loaded fonts, this should equal 0
|
# for BDF loaded fonts, this should equal 0
|
||||||
|
|
||||||
self._blit(
|
for y in range(my_glyph.height):
|
||||||
bitmap,
|
for x in range(my_glyph.width):
|
||||||
xposition + my_glyph.dx,
|
x_placement = x + xposition + my_glyph.dx
|
||||||
yposition - my_glyph.height - my_glyph.dy,
|
y_placement = y + yposition - my_glyph.height - my_glyph.dy
|
||||||
my_glyph.bitmap,
|
|
||||||
x_1=glyph_offset_x,
|
if (bitmap_width > x_placement >= 0) and (
|
||||||
y_1=0,
|
bitmap_height > y_placement >= 0
|
||||||
x_2=glyph_offset_x + my_glyph.width,
|
):
|
||||||
y_2=0 + my_glyph.height,
|
|
||||||
skip_index=skip_index, # do not copy over any 0 background pixels
|
# Allows for remapping the bitmap indexes using paletteIndex
|
||||||
)
|
# for background and text.
|
||||||
|
palette_indexes = (
|
||||||
|
background_palette_index,
|
||||||
|
text_palette_index,
|
||||||
|
)
|
||||||
|
|
||||||
|
this_pixel_color = palette_indexes[
|
||||||
|
my_glyph.bitmap[
|
||||||
|
y * my_glyph.bitmap.width + x + glyph_offset_x
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
if not print_only_pixels or this_pixel_color > 0:
|
||||||
|
# write all characters if printOnlyPixels = False,
|
||||||
|
# or if thisPixelColor is > 0
|
||||||
|
bitmap[
|
||||||
|
y_placement * bitmap_width + x_placement
|
||||||
|
] = this_pixel_color
|
||||||
|
elif y_placement > bitmap_height:
|
||||||
|
break
|
||||||
|
|
||||||
xposition = xposition + my_glyph.shift_x
|
xposition = xposition + my_glyph.shift_x
|
||||||
|
|
||||||
return (left, top, right - left, bottom - top) # bounding_box
|
return (left, top, right - left, bottom - top) # bounding_box
|
||||||
|
|
||||||
def _blit(
|
|
||||||
self,
|
|
||||||
bitmap, # target bitmap
|
|
||||||
x, # target x upper left corner
|
|
||||||
y, # target y upper left corner
|
|
||||||
source_bitmap, # source bitmap
|
|
||||||
x_1=0, # source x start
|
|
||||||
y_1=0, # source y start
|
|
||||||
x_2=None, # source x end
|
|
||||||
y_2=None, # source y end
|
|
||||||
skip_index=None, # palette index that will not be copied
|
|
||||||
# (for example: the background color of a glyph)
|
|
||||||
):
|
|
||||||
|
|
||||||
if hasattr(bitmap, "blit"): # if bitmap has a built-in blit function, call it
|
|
||||||
# this function should perform its own input checks
|
|
||||||
bitmap.blit(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
source_bitmap,
|
|
||||||
x1=x_1,
|
|
||||||
y1=y_1,
|
|
||||||
x2=x_2,
|
|
||||||
y2=y_2,
|
|
||||||
skip_index=skip_index,
|
|
||||||
)
|
|
||||||
|
|
||||||
else: # perform pixel by pixel copy of the bitmap
|
|
||||||
|
|
||||||
# Perform input checks
|
|
||||||
|
|
||||||
if x_2 is None:
|
|
||||||
x_2 = source_bitmap.width
|
|
||||||
if y_2 is None:
|
|
||||||
y_2 = source_bitmap.height
|
|
||||||
|
|
||||||
# Rearrange so that x_1 < x_2 and y1 < y2
|
|
||||||
if x_1 > x_2:
|
|
||||||
x_1, x_2 = x_2, x_1
|
|
||||||
if y_1 > y_2:
|
|
||||||
y_1, y_2 = y_2, y_1
|
|
||||||
|
|
||||||
# Ensure that x2 and y2 are within source bitmap size
|
|
||||||
x_2 = min(x_2, source_bitmap.width)
|
|
||||||
y_2 = min(y_2, source_bitmap.height)
|
|
||||||
|
|
||||||
for y_count in range(y_2 - y_1):
|
|
||||||
for x_count in range(x_2 - x_1):
|
|
||||||
x_placement = x + x_count
|
|
||||||
y_placement = y + y_count
|
|
||||||
|
|
||||||
if (bitmap.width > x_placement >= 0) and (
|
|
||||||
bitmap.height > y_placement >= 0
|
|
||||||
): # ensure placement is within target bitmap
|
|
||||||
|
|
||||||
# get the palette index from the source bitmap
|
|
||||||
this_pixel_color = source_bitmap[
|
|
||||||
y_1
|
|
||||||
+ (
|
|
||||||
y_count * source_bitmap.width
|
|
||||||
) # Direct index into a bitmap array is speedier than [x,y] tuple
|
|
||||||
+ x_1
|
|
||||||
+ x_count
|
|
||||||
]
|
|
||||||
|
|
||||||
if (skip_index is None) or (this_pixel_color != skip_index):
|
|
||||||
bitmap[ # Direct index into a bitmap array is speedier than [x,y] tuple
|
|
||||||
y_placement * bitmap.width + x_placement
|
|
||||||
] = this_pixel_color
|
|
||||||
elif y_placement > bitmap.height:
|
|
||||||
break
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bounding_box(self):
|
def bounding_box(self):
|
||||||
"""An (x, y, w, h) tuple that completely covers all glyphs. The
|
"""An (x, y, w, h) tuple that completely covers all glyphs. The
|
||||||
first two numbers are offset from the x, y origin of this group"""
|
first two numbers are offset from the x, y origin of this group"""
|
||||||
return self._bounding_box
|
return self._bounding_box
|
||||||
|
|
||||||
@property
|
|
||||||
def scale(self):
|
|
||||||
"""Set the scaling of the label, in integer values"""
|
|
||||||
return self._scale
|
|
||||||
|
|
||||||
@scale.setter
|
|
||||||
def scale(self, new_scale):
|
|
||||||
self.local_group.scale = new_scale
|
|
||||||
self._scale = new_scale
|
|
||||||
self.anchored_position = self._anchored_position # update the anchored_position
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def line_spacing(self):
|
def line_spacing(self):
|
||||||
"""The amount of space between lines of text, in multiples of the font's
|
"""The amount of space between lines of text, in multiples of the font's
|
||||||
|
|
@ -585,10 +434,9 @@ class Label(displayio.Group):
|
||||||
|
|
||||||
@line_spacing.setter
|
@line_spacing.setter
|
||||||
def line_spacing(self, new_line_spacing):
|
def line_spacing(self, new_line_spacing):
|
||||||
if self._save_text:
|
raise RuntimeError(
|
||||||
self._reset_text(line_spacing=new_line_spacing)
|
"line_spacing is immutable for bitmap_label.py; use label.py for mutable line_spacing"
|
||||||
else:
|
)
|
||||||
raise RuntimeError("line_spacing is immutable when save_text is False")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color(self):
|
def color(self):
|
||||||
|
|
@ -625,22 +473,22 @@ class Label(displayio.Group):
|
||||||
"""Text to displayed."""
|
"""Text to displayed."""
|
||||||
return self._text
|
return self._text
|
||||||
|
|
||||||
@text.setter # Cannot set color or background color with text setter, use separate setter
|
@text.setter
|
||||||
def text(self, new_text):
|
def text(self, new_text):
|
||||||
self._reset_text(text=new_text)
|
raise RuntimeError(
|
||||||
|
"text is immutable for bitmap_label.py; use label.py library for mutable text"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def font(self):
|
def font(self):
|
||||||
"""Font to use for text display."""
|
"""Font to use for text display."""
|
||||||
return self._font
|
return self.font
|
||||||
|
|
||||||
@font.setter
|
@font.setter
|
||||||
def font(self, new_font):
|
def font(self, new_font):
|
||||||
self._font = new_font
|
raise RuntimeError(
|
||||||
if self._save_text:
|
"font is immutable for bitmap_label.py; use label.py library for mutable font"
|
||||||
self._reset_text(font=new_font)
|
)
|
||||||
else:
|
|
||||||
raise RuntimeError("font is immutable when save_text is False")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def anchor_point(self):
|
def anchor_point(self):
|
||||||
|
|
@ -665,15 +513,16 @@ class Label(displayio.Group):
|
||||||
@anchored_position.setter
|
@anchored_position.setter
|
||||||
def anchored_position(self, new_position):
|
def anchored_position(self, new_position):
|
||||||
self._anchored_position = new_position
|
self._anchored_position = new_position
|
||||||
|
|
||||||
# Set anchored_position
|
# Set anchored_position
|
||||||
if (self._anchor_point is not None) and (self._anchored_position is not None):
|
if (self._anchor_point is not None) and (self._anchored_position is not None):
|
||||||
self.x = int(
|
self.x = int(
|
||||||
new_position[0]
|
new_position[0]
|
||||||
- (self._bounding_box[0] * self.scale)
|
- (self._bounding_box[0] * self._scale)
|
||||||
- round(self._anchor_point[0] * (self._bounding_box[2] * self.scale))
|
- round(self._anchor_point[0] * (self._bounding_box[2] * self._scale))
|
||||||
)
|
)
|
||||||
self.y = int(
|
self.y = int(
|
||||||
new_position[1]
|
new_position[1]
|
||||||
- (self._bounding_box[1] * self.scale)
|
- (self._bounding_box[1] * self._scale)
|
||||||
- round(self._anchor_point[1] * self._bounding_box[3] * self.scale)
|
- round(self._anchor_point[1] * self._bounding_box[3] * self._scale)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -79,25 +79,18 @@ class Label(displayio.Group):
|
||||||
padding_right=0,
|
padding_right=0,
|
||||||
anchor_point=None,
|
anchor_point=None,
|
||||||
anchored_position=None,
|
anchored_position=None,
|
||||||
scale=1,
|
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
|
if "scale" in kwargs.keys():
|
||||||
|
self._scale = kwargs["scale"]
|
||||||
|
else:
|
||||||
|
self._scale = 1
|
||||||
if not max_glyphs and not text:
|
if not max_glyphs and not text:
|
||||||
raise RuntimeError("Please provide a max size, or initial text")
|
raise RuntimeError("Please provide a max size, or initial text")
|
||||||
if not max_glyphs:
|
if not max_glyphs:
|
||||||
max_glyphs = len(text)
|
max_glyphs = len(text)
|
||||||
# add one to max_size for the background bitmap tileGrid
|
# add one to max_size for the background bitmap tileGrid
|
||||||
|
super().__init__(max_size=max_glyphs + 1, **kwargs)
|
||||||
# instance the Group
|
|
||||||
# self Group will contain a single local_group which contains a Group (self.local_group)
|
|
||||||
# which contains a TileGrid
|
|
||||||
super().__init__(
|
|
||||||
max_size=1, scale=1, **kwargs
|
|
||||||
) # The self scale should always be 1
|
|
||||||
self.local_group = displayio.Group(
|
|
||||||
max_size=max_glyphs + 1, scale=scale
|
|
||||||
) # local_group will set the scale
|
|
||||||
self.append(self.local_group)
|
|
||||||
|
|
||||||
self.width = max_glyphs
|
self.width = max_glyphs
|
||||||
self._font = font
|
self._font = font
|
||||||
|
|
@ -129,8 +122,6 @@ class Label(displayio.Group):
|
||||||
self._padding_left = padding_left
|
self._padding_left = padding_left
|
||||||
self._padding_right = padding_right
|
self._padding_right = padding_right
|
||||||
|
|
||||||
self._scale = scale
|
|
||||||
|
|
||||||
if text is not None:
|
if text is not None:
|
||||||
self._update_text(str(text))
|
self._update_text(str(text))
|
||||||
if (anchored_position is not None) and (anchor_point is not None):
|
if (anchored_position is not None) and (anchor_point is not None):
|
||||||
|
|
@ -147,17 +138,28 @@ class Label(displayio.Group):
|
||||||
y_box_offset = self._boundingbox[1]
|
y_box_offset = self._boundingbox[1]
|
||||||
|
|
||||||
else: # draw a "loose" bounding box to include any ascenders/descenders.
|
else: # draw a "loose" bounding box to include any ascenders/descenders.
|
||||||
ascent, descent = self._get_ascent_descent()
|
|
||||||
|
# check a few glyphs for maximum ascender and descender height
|
||||||
|
# Enhancement: it would be preferred to access the font "FONT_ASCENT" and
|
||||||
|
# "FONT_DESCENT" in the imported BDF file
|
||||||
|
glyphs = "M j'" # choose glyphs with highest ascender and lowest
|
||||||
|
# descender, will depend upon font used
|
||||||
|
ascender_max = descender_max = 0
|
||||||
|
for char in glyphs:
|
||||||
|
this_glyph = self._font.get_glyph(ord(char))
|
||||||
|
if this_glyph:
|
||||||
|
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
|
||||||
|
descender_max = max(descender_max, -this_glyph.dy)
|
||||||
|
|
||||||
box_width = self._boundingbox[2] + self._padding_left + self._padding_right
|
box_width = self._boundingbox[2] + self._padding_left + self._padding_right
|
||||||
x_box_offset = -self._padding_left
|
x_box_offset = -self._padding_left
|
||||||
box_height = (
|
box_height = (
|
||||||
(ascent + descent)
|
(ascender_max + descender_max)
|
||||||
+ int((lines - 1) * self.height * self._line_spacing)
|
+ int((lines - 1) * self.height * self._line_spacing)
|
||||||
+ self._padding_top
|
+ self._padding_top
|
||||||
+ self._padding_bottom
|
+ self._padding_bottom
|
||||||
)
|
)
|
||||||
y_box_offset = -ascent + y_offset - self._padding_top
|
y_box_offset = -ascender_max + y_offset - self._padding_top
|
||||||
|
|
||||||
box_width = max(0, box_width) # remove any negative values
|
box_width = max(0, box_width) # remove any negative values
|
||||||
box_height = max(0, box_height) # remove any negative values
|
box_height = max(0, box_height) # remove any negative values
|
||||||
|
|
@ -172,35 +174,12 @@ class Label(displayio.Group):
|
||||||
|
|
||||||
return tile_grid
|
return tile_grid
|
||||||
|
|
||||||
def _get_ascent_descent(self):
|
|
||||||
if hasattr(self.font, "ascent"):
|
|
||||||
return self.font.ascent, self.font.descent
|
|
||||||
|
|
||||||
# check a few glyphs for maximum ascender and descender height
|
|
||||||
glyphs = "M j'" # choose glyphs with highest ascender and lowest
|
|
||||||
try:
|
|
||||||
self._font.load_glyphs(glyphs)
|
|
||||||
except AttributeError:
|
|
||||||
# Builtin font doesn't have or need load_glyphs
|
|
||||||
pass
|
|
||||||
# descender, will depend upon font used
|
|
||||||
ascender_max = descender_max = 0
|
|
||||||
for char in glyphs:
|
|
||||||
this_glyph = self._font.get_glyph(ord(char))
|
|
||||||
if this_glyph:
|
|
||||||
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
|
|
||||||
descender_max = max(descender_max, -this_glyph.dy)
|
|
||||||
return ascender_max, descender_max
|
|
||||||
|
|
||||||
def _get_ascent(self):
|
|
||||||
return self._get_ascent_descent()[0]
|
|
||||||
|
|
||||||
def _update_background_color(self, new_color):
|
def _update_background_color(self, new_color):
|
||||||
|
|
||||||
if new_color is None:
|
if new_color is None:
|
||||||
self._background_palette.make_transparent(0)
|
self._background_palette.make_transparent(0)
|
||||||
if self._added_background_tilegrid:
|
if self._added_background_tilegrid:
|
||||||
self.local_group.pop(0)
|
self.pop(0)
|
||||||
self._added_background_tilegrid = False
|
self._added_background_tilegrid = False
|
||||||
else:
|
else:
|
||||||
self._background_palette.make_opaque(0)
|
self._background_palette.make_opaque(0)
|
||||||
|
|
@ -208,7 +187,7 @@ class Label(displayio.Group):
|
||||||
self._background_color = new_color
|
self._background_color = new_color
|
||||||
|
|
||||||
lines = self._text.rstrip("\n").count("\n") + 1
|
lines = self._text.rstrip("\n").count("\n") + 1
|
||||||
y_offset = self._get_ascent() // 2
|
y_offset = int((self._font.get_glyph(ord("M")).height) / 2)
|
||||||
|
|
||||||
if not self._added_background_tilegrid: # no bitmap is in the self Group
|
if not self._added_background_tilegrid: # no bitmap is in the self Group
|
||||||
# add bitmap if text is present and bitmap sizes > 0 pixels
|
# add bitmap if text is present and bitmap sizes > 0 pixels
|
||||||
|
|
@ -221,16 +200,10 @@ class Label(displayio.Group):
|
||||||
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
|
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
if (
|
if len(self) > 0:
|
||||||
len(self.local_group) > 0
|
self.insert(0, self._create_background_box(lines, y_offset))
|
||||||
): # This can be simplified in CP v6.0, when group.append(0) bug is corrected
|
|
||||||
self.local_group.insert(
|
|
||||||
0, self._create_background_box(lines, y_offset)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.local_group.append(
|
self.append(self._create_background_box(lines, y_offset))
|
||||||
self._create_background_box(lines, y_offset)
|
|
||||||
)
|
|
||||||
self._added_background_tilegrid = True
|
self._added_background_tilegrid = True
|
||||||
|
|
||||||
else: # a bitmap is present in the self Group
|
else: # a bitmap is present in the self Group
|
||||||
|
|
@ -244,9 +217,9 @@ class Label(displayio.Group):
|
||||||
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
|
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
self.local_group[0] = self._create_background_box(lines, y_offset)
|
self[0] = self._create_background_box(lines, y_offset)
|
||||||
else: # delete the existing bitmap
|
else: # delete the existing bitmap
|
||||||
self.local_group.pop(0)
|
self.pop(0)
|
||||||
self._added_background_tilegrid = False
|
self._added_background_tilegrid = False
|
||||||
|
|
||||||
def _update_text(
|
def _update_text(
|
||||||
|
|
@ -260,7 +233,13 @@ class Label(displayio.Group):
|
||||||
i = 0
|
i = 0
|
||||||
tilegrid_count = i
|
tilegrid_count = i
|
||||||
|
|
||||||
y_offset = self._get_ascent() // 2
|
try:
|
||||||
|
self._font.load_glyphs(new_text + "M")
|
||||||
|
except AttributeError:
|
||||||
|
# ignore if font does not have load_glyphs
|
||||||
|
pass
|
||||||
|
|
||||||
|
y_offset = int((self._font.get_glyph(ord("M")).height) / 2)
|
||||||
|
|
||||||
right = top = bottom = 0
|
right = top = bottom = 0
|
||||||
left = None
|
left = None
|
||||||
|
|
@ -305,10 +284,10 @@ class Label(displayio.Group):
|
||||||
x=position_x,
|
x=position_x,
|
||||||
y=position_y,
|
y=position_y,
|
||||||
)
|
)
|
||||||
if tilegrid_count < len(self.local_group):
|
if tilegrid_count < len(self):
|
||||||
self.local_group[tilegrid_count] = face
|
self[tilegrid_count] = face
|
||||||
else:
|
else:
|
||||||
self.local_group.append(face)
|
self.append(face)
|
||||||
tilegrid_count += 1
|
tilegrid_count += 1
|
||||||
x += glyph.shift_x
|
x += glyph.shift_x
|
||||||
i += 1
|
i += 1
|
||||||
|
|
@ -317,8 +296,8 @@ class Label(displayio.Group):
|
||||||
if left is None:
|
if left is None:
|
||||||
left = 0
|
left = 0
|
||||||
|
|
||||||
while len(self.local_group) > tilegrid_count: # i:
|
while len(self) > tilegrid_count: # i:
|
||||||
self.local_group.pop()
|
self.pop()
|
||||||
self._text = new_text
|
self._text = new_text
|
||||||
self._boundingbox = (left, top, right - left, bottom - top)
|
self._boundingbox = (left, top, right - left, bottom - top)
|
||||||
|
|
||||||
|
|
@ -340,7 +319,6 @@ class Label(displayio.Group):
|
||||||
@line_spacing.setter
|
@line_spacing.setter
|
||||||
def line_spacing(self, spacing):
|
def line_spacing(self, spacing):
|
||||||
self._line_spacing = spacing
|
self._line_spacing = spacing
|
||||||
self.text = self._text # redraw the box
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color(self):
|
def color(self):
|
||||||
|
|
@ -380,18 +358,6 @@ class Label(displayio.Group):
|
||||||
except RuntimeError as run_error:
|
except RuntimeError as run_error:
|
||||||
raise RuntimeError("Text length exceeds max_glyphs") from run_error
|
raise RuntimeError("Text length exceeds max_glyphs") from run_error
|
||||||
|
|
||||||
@property
|
|
||||||
def scale(self):
|
|
||||||
"""Set the scaling of the label, in integer values"""
|
|
||||||
return self._scale
|
|
||||||
|
|
||||||
@scale.setter
|
|
||||||
def scale(self, new_scale):
|
|
||||||
current_anchored_position = self.anchored_position
|
|
||||||
self._scale = new_scale
|
|
||||||
self.local_group.scale = new_scale
|
|
||||||
self.anchored_position = current_anchored_position
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def font(self):
|
def font(self):
|
||||||
"""Font to use for text display."""
|
"""Font to use for text display."""
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,3 @@
|
||||||
|
|
||||||
.. automodule:: adafruit_display_text.label
|
.. automodule:: adafruit_display_text.label
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. automodule:: adafruit_display_text.bitmap_label
|
|
||||||
:members:
|
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
"""
|
|
||||||
Basic display_text.label example script
|
|
||||||
adapted for use on MagTag.
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
import board
|
|
||||||
import displayio
|
|
||||||
import terminalio
|
|
||||||
from adafruit_display_text import label
|
|
||||||
|
|
||||||
# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.)
|
|
||||||
# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.)
|
|
||||||
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus
|
|
||||||
display = board.DISPLAY
|
|
||||||
|
|
||||||
# wait until we can draw
|
|
||||||
time.sleep(display.time_to_refresh)
|
|
||||||
|
|
||||||
# main group to hold everything
|
|
||||||
main_group = displayio.Group()
|
|
||||||
|
|
||||||
# white background. Scaled to save RAM
|
|
||||||
bg_bitmap = displayio.Bitmap(display.width // 8, display.height // 8, 1)
|
|
||||||
bg_palette = displayio.Palette(1)
|
|
||||||
bg_palette[0] = 0xFFFFFF
|
|
||||||
bg_sprite = displayio.TileGrid(bg_bitmap, x=0, y=0, pixel_shader=bg_palette)
|
|
||||||
bg_group = displayio.Group(scale=8)
|
|
||||||
bg_group.append(bg_sprite)
|
|
||||||
main_group.append(bg_group)
|
|
||||||
|
|
||||||
# first example label
|
|
||||||
TEXT = "Hello world"
|
|
||||||
text_area = label.Label(
|
|
||||||
terminalio.FONT,
|
|
||||||
text=TEXT,
|
|
||||||
color=0xFFFFFF,
|
|
||||||
background_color=0x666666,
|
|
||||||
padding_top=1,
|
|
||||||
padding_bottom=3,
|
|
||||||
padding_right=4,
|
|
||||||
padding_left=4,
|
|
||||||
)
|
|
||||||
text_area.x = 10
|
|
||||||
text_area.y = 14
|
|
||||||
main_group.append(text_area)
|
|
||||||
|
|
||||||
# second example label
|
|
||||||
another_text = label.Label(
|
|
||||||
terminalio.FONT,
|
|
||||||
scale=2,
|
|
||||||
text="MagTag display_text\nexample",
|
|
||||||
color=0x000000,
|
|
||||||
background_color=0x999999,
|
|
||||||
padding_top=1,
|
|
||||||
padding_bottom=3,
|
|
||||||
padding_right=4,
|
|
||||||
padding_left=4,
|
|
||||||
)
|
|
||||||
# centered
|
|
||||||
another_text.anchor_point = (0.5, 0.5)
|
|
||||||
another_text.anchored_position = (display.width // 2, display.height // 2)
|
|
||||||
main_group.append(another_text)
|
|
||||||
|
|
||||||
# show the main group and refresh.
|
|
||||||
display.show(main_group)
|
|
||||||
display.refresh()
|
|
||||||
while True:
|
|
||||||
pass
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
"""
|
|
||||||
This example shows how to create a display_text label and show it
|
|
||||||
with a Matrix Portal
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
adafruit_matrixportal - https://github.com/adafruit/Adafruit_CircuitPython_MatrixPortal
|
|
||||||
|
|
||||||
Copy it from the current libraries bundle into the lib folder on your device.
|
|
||||||
"""
|
|
||||||
import terminalio
|
|
||||||
from adafruit_matrixportal.matrix import Matrix
|
|
||||||
from adafruit_display_text import label
|
|
||||||
|
|
||||||
matrix = Matrix()
|
|
||||||
display = matrix.display
|
|
||||||
|
|
||||||
text = "Hello\nworld"
|
|
||||||
text_area = label.Label(terminalio.FONT, text=text)
|
|
||||||
text_area.x = 1
|
|
||||||
text_area.y = 4
|
|
||||||
display.show(text_area)
|
|
||||||
while True:
|
|
||||||
pass
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
"""
|
|
||||||
This example illustrates how to use the wrap_text_to_lines
|
|
||||||
helper function.
|
|
||||||
"""
|
|
||||||
import board
|
|
||||||
import terminalio
|
|
||||||
from adafruit_display_text import label, wrap_text_to_lines
|
|
||||||
|
|
||||||
# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.)
|
|
||||||
# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.)
|
|
||||||
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus
|
|
||||||
display = board.DISPLAY
|
|
||||||
|
|
||||||
text = (
|
|
||||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, "
|
|
||||||
"sed do eiusmod tempor incididunt ut labore et dolore magna "
|
|
||||||
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
|
|
||||||
"ullamco laboris nisi ut aliquip ex ea commodo consequat."
|
|
||||||
)
|
|
||||||
text = "\n".join(wrap_text_to_lines(text, 28))
|
|
||||||
text_area = label.Label(terminalio.FONT, text=text)
|
|
||||||
text_area.x = 10
|
|
||||||
text_area.y = 10
|
|
||||||
display.show(text_area)
|
|
||||||
while True:
|
|
||||||
pass
|
|
||||||
Loading…
Reference in a new issue