189 lines
6.2 KiB
Python
189 lines
6.2 KiB
Python
# SPDX-FileCopyrightText: 2023 Tim C
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
`adafruit_display_text.outlined_label`
|
|
====================================================
|
|
|
|
Subclass of BitmapLabel that adds outline color and stroke size
|
|
functionalities.
|
|
|
|
* Author(s): Tim Cocks
|
|
|
|
Implementation Notes
|
|
--------------------
|
|
|
|
**Hardware:**
|
|
|
|
**Software and Dependencies:**
|
|
|
|
* Adafruit CircuitPython firmware for the supported boards:
|
|
https://circuitpython.org/downloads
|
|
|
|
"""
|
|
__version__ = "3.2.2"
|
|
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"
|
|
|
|
import bitmaptools
|
|
from displayio import Palette, Bitmap
|
|
from adafruit_display_text import bitmap_label
|
|
|
|
try:
|
|
from typing import Optional, Tuple, Union
|
|
from fontio import FontProtocol
|
|
except ImportError:
|
|
pass
|
|
|
|
|
|
class OutlinedLabel(bitmap_label.Label):
|
|
"""
|
|
OutlinedLabel - A BitmapLabel subclass that includes arguments and properties for specifying
|
|
outline_size and outline_color to get drawn as a stroke around the text.
|
|
|
|
:param Union[Tuple, int] outline_color: The color of the outline stroke as RGB tuple, or hex.
|
|
:param int outline_size: The size in pixels of the outline stroke.
|
|
|
|
"""
|
|
|
|
# pylint: disable=too-many-arguments
|
|
def __init__(
|
|
self,
|
|
font,
|
|
outline_color: Union[int, Tuple] = 0x999999,
|
|
outline_size: int = 1,
|
|
padding_top: Optional[int] = None,
|
|
padding_bottom: Optional[int] = None,
|
|
padding_left: Optional[int] = None,
|
|
padding_right: Optional[int] = None,
|
|
**kwargs
|
|
):
|
|
if padding_top is None:
|
|
padding_top = outline_size + 0
|
|
if padding_bottom is None:
|
|
padding_bottom = outline_size + 2
|
|
if padding_left is None:
|
|
padding_left = outline_size + 0
|
|
if padding_right is None:
|
|
padding_right = outline_size + 0
|
|
|
|
super().__init__(
|
|
font,
|
|
padding_top=padding_top,
|
|
padding_bottom=padding_bottom,
|
|
padding_left=padding_left,
|
|
padding_right=padding_right,
|
|
**kwargs
|
|
)
|
|
|
|
_background_color = self._palette[0]
|
|
_foreground_color = self._palette[1]
|
|
_background_is_transparent = self._palette.is_transparent(0)
|
|
self._palette = Palette(3)
|
|
self._palette[0] = _background_color
|
|
self._palette[1] = _foreground_color
|
|
self._palette[2] = outline_color
|
|
if _background_is_transparent:
|
|
self._palette.make_transparent(0)
|
|
|
|
self._outline_size = outline_size
|
|
self._stamp_source = Bitmap((outline_size * 2) + 1, (outline_size * 2) + 1, 3)
|
|
self._stamp_source.fill(2)
|
|
|
|
self._bitmap = None
|
|
|
|
self._reset_text(
|
|
font=font,
|
|
text=self._text,
|
|
line_spacing=self._line_spacing,
|
|
scale=self.scale,
|
|
)
|
|
|
|
def _add_outline(self):
|
|
"""
|
|
Blit the outline into the labels Bitmap. We will stamp self._stamp_source for each
|
|
pixel of the foreground color but skip the foreground color when we blit.
|
|
:return: None
|
|
"""
|
|
if hasattr(self, "_stamp_source"):
|
|
for y in range(self.bitmap.height):
|
|
for x in range(self.bitmap.width):
|
|
if self.bitmap[x, y] == 1:
|
|
try:
|
|
bitmaptools.blit(
|
|
self.bitmap,
|
|
self._stamp_source,
|
|
x - self._outline_size,
|
|
y - self._outline_size,
|
|
skip_dest_index=1,
|
|
)
|
|
except ValueError as value_error:
|
|
raise ValueError(
|
|
"Padding must be big enough to fit outline_size "
|
|
"all the way around the text. "
|
|
"Try using either larger padding sizes, or smaller outline_size."
|
|
) from value_error
|
|
|
|
def _place_text(
|
|
self,
|
|
bitmap: Bitmap,
|
|
text: str,
|
|
font: FontProtocol,
|
|
xposition: int,
|
|
yposition: int,
|
|
skip_index: int = 0, # set to None to write all pixels, other wise skip this palette index
|
|
# when copying glyph bitmaps (this is important for slanted text
|
|
# where rectangular glyph boxes overlap)
|
|
) -> Tuple[int, int, int, int]:
|
|
"""
|
|
Copy the glpyphs that represent the value of the string into the labels Bitmap.
|
|
:param bitmap: The bitmap to place text into
|
|
:param text: The text to render
|
|
:param font: The font to render the text in
|
|
:param xposition: x location of the starting point within the bitmap
|
|
:param yposition: y location of the starting point within the bitmap
|
|
:param skip_index: Color index to skip during rendering instead of covering up
|
|
:return Tuple bounding_box: tuple with x, y, width, height values of the bitmap
|
|
"""
|
|
parent_result = super()._place_text(
|
|
bitmap, text, font, xposition, yposition, skip_index=skip_index
|
|
)
|
|
|
|
self._add_outline()
|
|
|
|
return parent_result
|
|
|
|
@property
|
|
def outline_color(self):
|
|
"""Color of the outline to draw around the text."""
|
|
return self._palette[2]
|
|
|
|
@outline_color.setter
|
|
def outline_color(self, new_outline_color):
|
|
self._palette[2] = new_outline_color
|
|
|
|
@property
|
|
def outline_size(self):
|
|
"""Stroke size of the outline to draw around the text."""
|
|
return self._outline_size
|
|
|
|
@outline_size.setter
|
|
def outline_size(self, new_outline_size):
|
|
self._outline_size = new_outline_size
|
|
|
|
self._padding_top = new_outline_size + 0
|
|
self._padding_bottom = new_outline_size + 2
|
|
self._padding_left = new_outline_size + 0
|
|
self._padding_right = new_outline_size + 0
|
|
|
|
self._stamp_source = Bitmap(
|
|
(new_outline_size * 2) + 1, (new_outline_size * 2) + 1, 3
|
|
)
|
|
self._stamp_source.fill(2)
|
|
self._reset_text(
|
|
font=self._font,
|
|
text=self._text,
|
|
line_spacing=self._line_spacing,
|
|
scale=self.scale,
|
|
)
|