From 4dc752a28c53a6698d239fc7c6f8a82fe6edac5c Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Fri, 21 Feb 2020 18:46:09 -0500 Subject: [PATCH 01/12] Super custom badge added. --- adafruit_pybadger/pybadger_base.py | 153 +++++++++++++++++++++++++---- 1 file changed, 135 insertions(+), 18 deletions(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index 98c2517..a4de079 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -58,7 +58,7 @@ import displayio import neopixel from adafruit_display_shapes.rect import Rect -from adafruit_display_text.label import Label +from adafruit_display_text import label from adafruit_bitmap_font import bitmap_font import terminalio import adafruit_miniqr @@ -77,6 +77,43 @@ def load_font(fontname, text): font.load_glyphs(text.encode('utf-8')) return font +class _PyBadgerCustomBadge: + """Easily display lines of text on CLUE display.""" + def __init__(self, background_group): + self._label = label + self.display = board.DISPLAY + + self.custom_badge_group = displayio.Group(max_size=20) + + self.text_group = displayio.Group(max_size=20) + + self._lines = [] + for _ in range(1): + self._lines.append(self._add_text_line()) + + self.custom_badge_group.append(background_group) + self.custom_badge_group.append(self.text_group) + + def __getitem__(self, item): + """Fetch the Nth text line Group""" + if len(self._lines) - 1 < item: + for _ in range(item - (len(self._lines) - 1)): + self._lines.append(self._add_text_line()) + return self._lines[item] + + def _add_text_line(self, color=0xFFFFFF): + """Adds a line on the display of the specified color and returns the label object.""" + text_label = self._label.Label(font=terminalio.FONT, text="", max_glyphs=45, color=color) + self.text_group.append(text_label) + return text_label + + def custom_badge_group(): + return self.custom_badge_group + + def show(self): + """Call show() to display the badge lines.""" + self.display.show(self.custom_badge_group) + # pylint: disable=too-many-instance-attributes class PyBadgerBase: """PyBadger base class.""" @@ -84,6 +121,29 @@ class PyBadgerBase: _audio_out = None _neopixel_count = None + # Color variables available for import. + RED = (255, 0, 0) + YELLOW = (255, 255, 0) + ORANGE = (255, 150, 0) + GREEN = (0, 255, 0) + TEAL = (0, 255, 120) + CYAN = (0, 255, 255) + BLUE = (0, 0, 255) + PURPLE = (180, 0, 255) + MAGENTA = (255, 0, 150) + WHITE = (255, 255, 255) + BLACK = (0, 0, 0) + + GOLD = (255, 222, 30) + PINK = (242, 90, 255) + AQUA = (50, 255, 255) + JADE = (0, 255, 40) + AMBER = (255, 100, 0) + VIOLET = (255, 0, 255) + SKY = (0, 180, 255) + + RAINBOW = (RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE) + # Button Constants BUTTON_LEFT = const(128) BUTTON_UP = const(64) @@ -97,6 +157,11 @@ class PyBadgerBase: def __init__(self, *, pixels_brightness=1.0): self._light_sensor = None self._accelerometer = None + self._label = label + self.custom_badge_object = None + self._y_position = 1 + self._line_number = 0 + self._background_group = None # Display self.display = board.DISPLAY @@ -118,6 +183,70 @@ def __init__(self, *, pixels_brightness=1.0): self._sine_wave = None self._sine_wave_sample = None + def _custom_badge(self): + background_group = self._background_group + if not background_group: + background_group = self._badge_background() + return _PyBadgerCustomBadge(background_group) + + def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), + rectangle_drop=0.4, rectangle_height=0.5): + self._background_group = self._badge_background(background_color, rectangle_color, + rectangle_drop, rectangle_height) + return self._background_group + + @classmethod + def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), + rectangle_drop=0.4, rectangle_height=0.5): + """Populate the background color, and rectangle color block over it as the background for + a name badge.""" + background_group = displayio.Group(max_size=2) + color_bitmap = displayio.Bitmap(board.DISPLAY.width, board.DISPLAY.height, 1) + color_palette = displayio.Palette(1) + color_palette[0] = background_color + + bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) + background_group.append(bg_sprite) + + rectangle = Rect(0, (int(board.DISPLAY.height * rectangle_drop)), board.DISPLAY.width, + (int(board.DISPLAY.height * rectangle_height)), fill=rectangle_color) + background_group.append(rectangle) + return background_group + + def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, + left_justify=False): + if isinstance(font, str): + font = load_font(font, text) + + if self.custom_badge_object is None: + self.custom_badge_object = self._custom_badge() + + self.custom_badge_object[self._line_number].font = font + self.custom_badge_object[self._line_number].scale = scale + self.custom_badge_object[self._line_number].text = text + self.custom_badge_object[self._line_number].color = color + + _, _, width, height = self.custom_badge_object[self._line_number].bounding_box + if not left_justify: + self.custom_badge_object[self._line_number].x = (self.display.width // 2) - \ + ((width * scale) // 2) + else: + self.custom_badge_object[self._line_number].x = 0 + + trim_y = 0 + if font is terminalio.FONT: + trim_y = 4 * scale + self.custom_badge_object[self._line_number].y = self._y_position + ((height // 2) * + scale) - trim_y + if font is terminalio.FONT: + self._y_position += height * scale - trim_y + else: + self._y_position += height * scale + 4 + self._line_number += 1 + + def show(self): + return self.custom_badge_object.show() + # pylint: disable=too-many-arguments def _create_label_group(self, text, font, scale, height_adjustment, @@ -128,7 +257,7 @@ def _create_label_group(self, text, font, font = load_font(font, text) group = displayio.Group(scale=scale) - label = Label(font, text=text, line_spacing=line_spacing) + label = self._label.Label(font, text=text, line_spacing=line_spacing) _, _, width, _ = label.bounding_box label.x = ((self.display.width // (width_adjustment * scale)) - width // 2) label.y = int(self.display.height * (height_adjustment / scale)) @@ -277,21 +406,6 @@ def show_badge(self, *, background_color=0xFF0000, foreground_color=0xFFFFFF, "Blinka". """ - splash = displayio.Group(max_size=20) - - color_bitmap = displayio.Bitmap(self.display.width, self.display.height, 1) - color_palette = displayio.Palette(1) - color_palette[0] = background_color - - bg_sprite = displayio.TileGrid(color_bitmap, - pixel_shader=color_palette, - x=0, y=0) - splash.append(bg_sprite) - - rect = Rect(0, (int(self.display.height * 0.4)), self.display.width, - (int(self.display.height * 0.5)), fill=foreground_color) - splash.append(rect) - hello_group = self._create_label_group(text=hello_string, font=hello_font, scale=hello_scale, @@ -311,12 +425,15 @@ def show_badge(self, *, background_color=0xFF0000, foreground_color=0xFFFFFF, color=foreground_text_color) group = displayio.Group() - group.append(splash) + group.append(self._badge_background(background_color=background_color, + rectangle_color=foreground_color)) group.append(hello_group) group.append(my_name_is_group) group.append(name_group) self.display.show(group) + + def show_terminal(self): """Revert to terminalio screen. From ad1c351c0f94bb5d06135b9816189041ffd04663 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Sat, 22 Feb 2020 10:43:01 -0500 Subject: [PATCH 02/12] Linting. --- adafruit_pybadger/pybadger_base.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index a4de079..73451e9 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -107,9 +107,6 @@ def _add_text_line(self, color=0xFFFFFF): self.text_group.append(text_label) return text_label - def custom_badge_group(): - return self.custom_badge_group - def show(self): """Call show() to display the badge lines.""" self.display.show(self.custom_badge_group) @@ -197,7 +194,7 @@ def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 2 @classmethod def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), - rectangle_drop=0.4, rectangle_height=0.5): + rectangle_drop=0.4, rectangle_height=0.5): """Populate the background color, and rectangle color block over it as the background for a name badge.""" background_group = displayio.Group(max_size=2) @@ -213,6 +210,7 @@ def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 2 background_group.append(rectangle) return background_group + # pylint: disable=too-many-arguments def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, left_justify=False): if isinstance(font, str): @@ -237,7 +235,7 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, if font is terminalio.FONT: trim_y = 4 * scale self.custom_badge_object[self._line_number].y = self._y_position + ((height // 2) * - scale) - trim_y + scale) - trim_y if font is terminalio.FONT: self._y_position += height * scale - trim_y else: @@ -256,14 +254,14 @@ def _create_label_group(self, text, font, if isinstance(font, str): font = load_font(font, text) - group = displayio.Group(scale=scale) - label = self._label.Label(font, text=text, line_spacing=line_spacing) - _, _, width, _ = label.bounding_box - label.x = ((self.display.width // (width_adjustment * scale)) - width // 2) - label.y = int(self.display.height * (height_adjustment / scale)) - label.color = color - group.append(label) - return group + create_label_group = displayio.Group(scale=scale) + create_label = self._label.Label(font, text=text, line_spacing=line_spacing) + _, _, width, _ = create_label.bounding_box + create_label.x = ((self.display.width // (width_adjustment * scale)) - width // 2) + create_label.y = int(self.display.height * (height_adjustment / scale)) + create_label.color = color + create_label_group.append(create_label) + return create_label_group def _check_for_movement(self, movement_threshold=10): """Checks to see if board is moving. Used to auto-dim display when not moving.""" @@ -426,7 +424,7 @@ def show_badge(self, *, background_color=0xFF0000, foreground_color=0xFFFFFF, group = displayio.Group() group.append(self._badge_background(background_color=background_color, - rectangle_color=foreground_color)) + rectangle_color=foreground_color)) group.append(hello_group) group.append(my_name_is_group) group.append(name_group) From 2252e3f6dede0e19dd4d704dbc5d7c6dc913c5a5 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Tue, 25 Feb 2020 16:31:39 -0500 Subject: [PATCH 03/12] Functional. Need to sort out code.py. --- adafruit_pybadger/pybadger_base.py | 200 +++++++++++++++++++++++------ 1 file changed, 160 insertions(+), 40 deletions(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index 73451e9..e6ef73d 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -25,7 +25,6 @@ Base class for badge-focused CircuitPython helper library. - * Author(s): Kattni Rembor Implementation Notes @@ -41,7 +40,7 @@ **Software and Dependencies:** * Adafruit CircuitPython firmware for the supported boards: - https://github.com/adafruit/circuitpython/releases + https://circuitpython.org/downloads """ @@ -78,22 +77,19 @@ def load_font(fontname, text): return font class _PyBadgerCustomBadge: - """Easily display lines of text on CLUE display.""" - def __init__(self, background_group): + """Easily display lines of text on the display.""" + def __init__(self, background_group=None, background_filename=None): self._label = label self.display = board.DISPLAY + self._background_filename = background_filename + self._background_group = background_group self.custom_badge_group = displayio.Group(max_size=20) - self.text_group = displayio.Group(max_size=20) - self._lines = [] for _ in range(1): self._lines.append(self._add_text_line()) - self.custom_badge_group.append(background_group) - self.custom_badge_group.append(self.text_group) - def __getitem__(self, item): """Fetch the Nth text line Group""" if len(self._lines) - 1 < item: @@ -101,14 +97,40 @@ def __getitem__(self, item): self._lines.append(self._add_text_line()) return self._lines[item] + @staticmethod + def _add_image_background(file_handle): + on_disk_bitmap = displayio.OnDiskBitmap(file_handle) + background_image = displayio.TileGrid(on_disk_bitmap, + pixel_shader=displayio.ColorConverter()) + return background_image + def _add_text_line(self, color=0xFFFFFF): """Adds a line on the display of the specified color and returns the label object.""" text_label = self._label.Label(font=terminalio.FONT, text="", max_glyphs=45, color=color) - self.text_group.append(text_label) return text_label def show(self): """Call show() to display the badge lines.""" + + self.display.show(self.custom_badge_group) + if self._background_filename: + with open(self._background_filename, "rb") as file_handle: + background_image = self._add_image_background(file_handle) + self.custom_badge_group.append(background_image) + for image_label in self._lines: + self.custom_badge_group.append(image_label) + + try: + # Refresh display in CircuitPython 5 + self.display.refresh() + except AttributeError: + # Refresh display in CircuitPython 4 + self.display.wait_for_frame() + else: + self.custom_badge_group.append(self._background_group) + for background_label in self._lines: + self.custom_badge_group.append(background_label) + self.display.show(self.custom_badge_group) # pylint: disable=too-many-instance-attributes @@ -138,6 +160,11 @@ class PyBadgerBase: AMBER = (255, 100, 0) VIOLET = (255, 0, 255) SKY = (0, 180, 255) + DEEP_PURPLE = (100, 0, 150) + PYTHON_YELLOW = (255, 213, 69) + PYTHON_BLUE = (55, 112, 159) + BLINKA_PURPLE = (102, 45, 145) + BLINKA_PINK = (231, 33, 138) RAINBOW = (RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE) @@ -155,10 +182,11 @@ def __init__(self, *, pixels_brightness=1.0): self._light_sensor = None self._accelerometer = None self._label = label - self.custom_badge_object = None + self._custom_badge_object = None self._y_position = 1 self._line_number = 0 self._background_group = None + self._image_filename = None # Display self.display = board.DISPLAY @@ -181,13 +209,35 @@ def __init__(self, *, pixels_brightness=1.0): self._sine_wave_sample = None def _custom_badge(self): - background_group = self._background_group - if not background_group: - background_group = self._badge_background() - return _PyBadgerCustomBadge(background_group) + if not self._background_group and not self._image_filename: + raise ValueError("You must provide a bitmap image filename.") + if not self._background_group: + self._background_group = self._badge_background() + return _PyBadgerCustomBadge(background_group=self._background_group, + background_filename=self._image_filename) def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), rectangle_drop=0.4, rectangle_height=0.5): + """Create a customisable badge background made up of a background color with a rectangle + color block over it. Defaults are for ``show_badge``. + + :param tuple background_color: The color to fill the entire screen as a background. + :param tuple rectangle_color: The color of a rectangle that displays over the background. + :param float rectangle_drop: The distance from the top of the display to begin displaying + the rectangle. Float represents a percentage of the display, + e.g. 0.4 = 40% of the display. Defaults to ``0.4``. + :param float rectangle_height: The height of the rectangle. Float represents a percentage of + the display, e.g. 0.5 = 50% of the display. Defaults to + ``0.5``. + + .. code-block:: python + + from adafruit_pybadger import pybadger + + pybadger.badge_background(background_color=pybadger.WHITE, + rectangle_color=pybadger.PURPLE, + rectangle_drop=0.2, rectangle_height=0.6) + """ self._background_group = self._badge_background(background_color, rectangle_color, rectangle_drop, rectangle_height) return self._background_group @@ -195,7 +245,7 @@ def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 2 @classmethod def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), rectangle_drop=0.4, rectangle_height=0.5): - """Populate the background color, and rectangle color block over it as the background for + """Populate the background color with a rectangle color block over it as the background for a name badge.""" background_group = displayio.Group(max_size=2) color_bitmap = displayio.Bitmap(board.DISPLAY.width, board.DISPLAY.height, 1) @@ -210,46 +260,116 @@ def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 2 background_group.append(rectangle) return background_group + def image_background(self, image_name=None): + """Create a bitmap image background. + + :param str image_name: The name of the bitmap image as a string including ``.bmp``, e.g. + ``"Blinka.bmp"``. Image file name is required. + + .. code-block:: python + + from adafruit_pybadger import pybadger + + pybadger.image_background("Blinka.bmp") + """ + self._image_filename = image_name + # pylint: disable=too-many-arguments def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, - left_justify=False): + left_justify=False, padding_above=0): + """Add a line of text to the display. Designed to work with ``badge_background`` for a + color-block style badge, or with ``image_background`` for a badge with a background image. + + :param str text: The text to display. Defaults to displaying a blank line if no text is + provided. + :param tuple color: The color of the line of text. Defaults to ``(0, 0, 0)``. + :param int scale: The scale of the text. Must be an integer 1 or higher. Defaults to ``1``. + :param font: The font used for displaying the text. Defaults to ``terminalio.FONT``. + :param left_justify: Left-justify the line of text. Defaults to ``False`` which centers the + font on the display. + :param int padding_above: Add padding above the displayed line of text. A ``padding_above`` + of ``1`` is equivalent to the height of one line of text, ``2`` + is equivalent to the height of two lines of text, etc. Defaults + to ``0``. + + .. code-block:: python + + from adafruit_pybadger import pybadger + + pybadger.badge_background(background_color=pybadger.WHITE, + rectangle_color=pybadger.PURPLE, + rectangle_drop=0.2, rectangle_height=0.6) + + pybadger.badge_line(text="@blinka", color=pybadger.BLINKA_PURPLE, scale=4, + padding_above=1) + pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, + padding_above=2) + pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=3, + padding_above=1) + pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=4, + padding_above=4) + + pybadger.show() + + while True: + pass + """ if isinstance(font, str): font = load_font(font, text) - if self.custom_badge_object is None: - self.custom_badge_object = self._custom_badge() + if self._custom_badge_object is None: + self._custom_badge_object = self._custom_badge() - self.custom_badge_object[self._line_number].font = font - self.custom_badge_object[self._line_number].scale = scale - self.custom_badge_object[self._line_number].text = text - self.custom_badge_object[self._line_number].color = color + self._custom_badge_object[self._line_number].font = font + self._custom_badge_object[self._line_number].scale = scale + self._custom_badge_object[self._line_number].text = text + self._custom_badge_object[self._line_number].color = color - _, _, width, height = self.custom_badge_object[self._line_number].bounding_box + _, _, width, height = self._custom_badge_object[self._line_number].bounding_box if not left_justify: - self.custom_badge_object[self._line_number].x = (self.display.width // 2) - \ + self._custom_badge_object[self._line_number].x = (self.display.width // 2) - \ ((width * scale) // 2) else: - self.custom_badge_object[self._line_number].x = 0 + self._custom_badge_object[self._line_number].x = 0 trim_y = 0 + trim_padding = 0 if font is terminalio.FONT: trim_y = 4 * scale - self.custom_badge_object[self._line_number].y = self._y_position + ((height // 2) * - scale) - trim_y - if font is terminalio.FONT: - self._y_position += height * scale - trim_y + trim_padding = 4 * padding_above + + if not padding_above: + self._custom_badge_object[self._line_number].y = self._y_position + ((height // 2) * + scale) - trim_y + + if font is terminalio.FONT: + self._y_position += height * scale - trim_y + else: + self._y_position += height * scale + 4 + else: - self._y_position += height * scale + 4 + self._custom_badge_object[self._line_number].y = self._y_position +\ + (((height // 2) * scale) - trim_y) +\ + ((height * padding_above) - + trim_padding) + + if font is terminalio.FONT: + self._y_position += ((height * scale - trim_y) + ((height * padding_above) - + trim_padding)) + else: + self._y_position += height * scale + 4 + self._line_number += 1 def show(self): - return self.custom_badge_object.show() + """Call ``show()`` to display the badge lines of text.""" + return self._custom_badge_object.show() # pylint: disable=too-many-arguments def _create_label_group(self, text, font, scale, height_adjustment, color=0xFFFFFF, width_adjustment=2, line_spacing=0.75): - """Create a label group with the given text, font, and spacing""" + """Create a label group with the given text, font, and spacing.""" # If the given font is a string, treat it as a file path and try to load it if isinstance(font, str): font = load_font(font, text) @@ -378,19 +498,20 @@ def show_business_card(self, *, image_name=None, name_string=None, name_scale=1, self.display.wait_for_frame() # pylint: disable=too-many-locals - def show_badge(self, *, background_color=0xFF0000, foreground_color=0xFFFFFF, - background_text_color=0xFFFFFF, foreground_text_color=0x000000, + def show_badge(self, *, background_color=(255, 0, 0), foreground_color=(255, 255, 255), + background_text_color=(255, 255, 255), foreground_text_color=(0, 0, 0), hello_font=terminalio.FONT, hello_scale=1, hello_string="HELLO", my_name_is_font=terminalio.FONT, my_name_is_scale=1, my_name_is_string="MY NAME IS", name_font=terminalio.FONT, name_scale=1, name_string="Blinka"): """Create a "Hello My Name is"-style badge. - :param background_color: The color of the background. Defaults to 0xFF0000. - :param foreground_color: The color of the foreground rectangle. Defaults to 0xFFFFFF. + :param background_color: The color of the background. Defaults to ``(255, 0, 0)``. + :param foreground_color: The color of the foreground rectangle. Defaults to + ``(255, 255, 255)``. :param background_text_color: The color of the "HELLO MY NAME IS" text. Defaults to - 0xFFFFFF. - :param foreground_text_color: The color of the name text. Defaults to 0x000000. + ``(255, 255, 255)``. + :param foreground_text_color: The color of the name text. Defaults to ``(0, 0, 0)``. :param hello_font: The font for the "HELLO" string. Defaults to ``terminalio.FONT``. :param hello_scale: The size scale of the "HELLO" string. Defaults to 1. :param hello_string: The first string of the badge. Defaults to "HELLO". @@ -434,7 +555,6 @@ def show_badge(self, *, background_color=0xFF0000, foreground_color=0xFFFFFF, def show_terminal(self): """Revert to terminalio screen. - """ self.display.show(None) From f9d5117b665717e04dd290b52df56771179d68ab Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Tue, 25 Feb 2020 21:39:45 -0500 Subject: [PATCH 04/12] Refactor into PyBadgerBase class. Now works. --- adafruit_pybadger/pybadger_base.py | 134 ++++++++++------------------- 1 file changed, 45 insertions(+), 89 deletions(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index e6ef73d..2052610 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -76,63 +76,6 @@ def load_font(fontname, text): font.load_glyphs(text.encode('utf-8')) return font -class _PyBadgerCustomBadge: - """Easily display lines of text on the display.""" - def __init__(self, background_group=None, background_filename=None): - self._label = label - self.display = board.DISPLAY - self._background_filename = background_filename - self._background_group = background_group - - self.custom_badge_group = displayio.Group(max_size=20) - - self._lines = [] - for _ in range(1): - self._lines.append(self._add_text_line()) - - def __getitem__(self, item): - """Fetch the Nth text line Group""" - if len(self._lines) - 1 < item: - for _ in range(item - (len(self._lines) - 1)): - self._lines.append(self._add_text_line()) - return self._lines[item] - - @staticmethod - def _add_image_background(file_handle): - on_disk_bitmap = displayio.OnDiskBitmap(file_handle) - background_image = displayio.TileGrid(on_disk_bitmap, - pixel_shader=displayio.ColorConverter()) - return background_image - - def _add_text_line(self, color=0xFFFFFF): - """Adds a line on the display of the specified color and returns the label object.""" - text_label = self._label.Label(font=terminalio.FONT, text="", max_glyphs=45, color=color) - return text_label - - def show(self): - """Call show() to display the badge lines.""" - - self.display.show(self.custom_badge_group) - if self._background_filename: - with open(self._background_filename, "rb") as file_handle: - background_image = self._add_image_background(file_handle) - self.custom_badge_group.append(background_image) - for image_label in self._lines: - self.custom_badge_group.append(image_label) - - try: - # Refresh display in CircuitPython 5 - self.display.refresh() - except AttributeError: - # Refresh display in CircuitPython 4 - self.display.wait_for_frame() - else: - self.custom_badge_group.append(self._background_group) - for background_label in self._lines: - self.custom_badge_group.append(background_label) - - self.display.show(self.custom_badge_group) - # pylint: disable=too-many-instance-attributes class PyBadgerBase: """PyBadger base class.""" @@ -182,11 +125,11 @@ def __init__(self, *, pixels_brightness=1.0): self._light_sensor = None self._accelerometer = None self._label = label - self._custom_badge_object = None self._y_position = 1 - self._line_number = 0 self._background_group = None - self._image_filename = None + self._background_image_filename = None + self._lines = [] + self._created_background = False # Display self.display = board.DISPLAY @@ -208,13 +151,32 @@ def __init__(self, *, pixels_brightness=1.0): self._sine_wave = None self._sine_wave_sample = None - def _custom_badge(self): - if not self._background_group and not self._image_filename: - raise ValueError("You must provide a bitmap image filename.") - if not self._background_group: - self._background_group = self._badge_background() - return _PyBadgerCustomBadge(background_group=self._background_group, - background_filename=self._image_filename) + def _create_badge_background(self): + self._created_background = True + + if self._background_group is None: + self._background_group = displayio.Group(max_size=30) + + self.display.show(self._background_group) + + if self._background_image_filename: + with open(self._background_image_filename, "rb") as file_handle: + on_disk_bitmap = displayio.OnDiskBitmap(file_handle) + background_image = displayio.TileGrid(on_disk_bitmap, + pixel_shader=displayio.ColorConverter()) + self._background_group.append(background_image) + for image_label in self._lines: + self._background_group.append(image_label) + + try: + # Refresh display in CircuitPython 5 + self.display.refresh() + except AttributeError: + # Refresh display in CircuitPython 4 + self.display.wait_for_frame() + else: + for background_label in self._lines: + self._background_group.append(background_label) def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 255, 255), rectangle_drop=0.4, rectangle_height=0.5): @@ -247,7 +209,7 @@ def _badge_background(cls, background_color=(255, 0, 0), rectangle_color=(255, 2 rectangle_drop=0.4, rectangle_height=0.5): """Populate the background color with a rectangle color block over it as the background for a name badge.""" - background_group = displayio.Group(max_size=2) + background_group = displayio.Group(max_size=30) color_bitmap = displayio.Bitmap(board.DISPLAY.width, board.DISPLAY.height, 1) color_palette = displayio.Palette(1) color_palette[0] = background_color @@ -272,7 +234,7 @@ def image_background(self, image_name=None): pybadger.image_background("Blinka.bmp") """ - self._image_filename = image_name + self._background_image_filename = image_name # pylint: disable=too-many-arguments def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, @@ -317,20 +279,15 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, if isinstance(font, str): font = load_font(font, text) - if self._custom_badge_object is None: - self._custom_badge_object = self._custom_badge() - - self._custom_badge_object[self._line_number].font = font - self._custom_badge_object[self._line_number].scale = scale - self._custom_badge_object[self._line_number].text = text - self._custom_badge_object[self._line_number].color = color + text_label = self._label.Label(font=font, text=text, max_glyphs=45, color=color, + scale=scale) + self._lines.append(text_label) - _, _, width, height = self._custom_badge_object[self._line_number].bounding_box + _, _, width, height = text_label.bounding_box if not left_justify: - self._custom_badge_object[self._line_number].x = (self.display.width // 2) - \ - ((width * scale) // 2) + text_label.x = (self.display.width // 2) - ((width * scale) // 2) else: - self._custom_badge_object[self._line_number].x = 0 + text_label.x = 0 trim_y = 0 trim_padding = 0 @@ -339,8 +296,7 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, trim_padding = 4 * padding_above if not padding_above: - self._custom_badge_object[self._line_number].y = self._y_position + ((height // 2) * - scale) - trim_y + text_label.y = self._y_position + ((height // 2) * scale) - trim_y if font is terminalio.FONT: self._y_position += height * scale - trim_y @@ -348,10 +304,8 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, self._y_position += height * scale + 4 else: - self._custom_badge_object[self._line_number].y = self._y_position +\ - (((height // 2) * scale) - trim_y) +\ - ((height * padding_above) - - trim_padding) + text_label.y = self._y_position + (((height // 2) * scale) - trim_y) + \ + ((height * padding_above) - trim_padding) if font is terminalio.FONT: self._y_position += ((height * scale - trim_y) + ((height * padding_above) - @@ -359,11 +313,13 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, else: self._y_position += height * scale + 4 - self._line_number += 1 - def show(self): """Call ``show()`` to display the badge lines of text.""" - return self._custom_badge_object.show() + + if not self._created_background: + self._create_badge_background() + + self.display.show(self._background_group) # pylint: disable=too-many-arguments def _create_label_group(self, text, font, From b4a59f6c001383f4a38c571d7cc26bd53fee50fb Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Tue, 25 Feb 2020 21:52:49 -0500 Subject: [PATCH 05/12] Added examples for CLUE and PyBadge --- examples/pybadger_clue_custom_badge.py | 20 ++++++++++++++++++++ examples/pybadger_custom_badge.py | 13 +++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 examples/pybadger_clue_custom_badge.py create mode 100644 examples/pybadger_custom_badge.py diff --git a/examples/pybadger_clue_custom_badge.py b/examples/pybadger_clue_custom_badge.py new file mode 100644 index 0000000..9085b2f --- /dev/null +++ b/examples/pybadger_clue_custom_badge.py @@ -0,0 +1,20 @@ +"""""" + +from adafruit_pybadger import pybadger + +pybadger.badge_background(background_color=pybadger.WHITE, rectangle_color=pybadger.PURPLE, + rectangle_drop=0.2, rectangle_height=0.6) + +pybadger.badge_line(text="@blinka", color=pybadger.BLINKA_PURPLE, scale=4, padding_above=1) +pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, padding_above=2) +pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=3, padding_above=1) +pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=4, padding_above=4) + +pybadger.show() + +while True: + if pybadger.button.a: + pybadger.show() + + if pybadger.button.b: + pybadger.show_qr_code() diff --git a/examples/pybadger_custom_badge.py b/examples/pybadger_custom_badge.py new file mode 100644 index 0000000..b67fde5 --- /dev/null +++ b/examples/pybadger_custom_badge.py @@ -0,0 +1,13 @@ +"""Custom badge for PyBadge or PyGamer.""" +from adafruit_pybadger import pybadger + +pybadger.badge_background(background_color=pybadger.WHITE, rectangle_color=pybadger.PURPLE, + rectangle_drop=0.2, rectangle_height=0.6) + +pybadger.badge_line(text="@circuitpython", color=pybadger.BLINKA_PURPLE, scale=1, padding_above=1) +pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=3, padding_above=1) +pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=2, padding_above=1) +pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=2, padding_above=2) + +while True: + pybadger.show() \ No newline at end of file From 436ce7b6e6ff29879bb64a9fbc8550fdfa40c972 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Tue, 25 Feb 2020 21:56:37 -0500 Subject: [PATCH 06/12] Example update. --- examples/pybadger_clue_custom_badge.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/pybadger_clue_custom_badge.py b/examples/pybadger_clue_custom_badge.py index 9085b2f..4edca66 100644 --- a/examples/pybadger_clue_custom_badge.py +++ b/examples/pybadger_clue_custom_badge.py @@ -5,8 +5,8 @@ pybadger.badge_background(background_color=pybadger.WHITE, rectangle_color=pybadger.PURPLE, rectangle_drop=0.2, rectangle_height=0.6) -pybadger.badge_line(text="@blinka", color=pybadger.BLINKA_PURPLE, scale=4, padding_above=1) -pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, padding_above=2) +pybadger.badge_line(text="@circuitpython", color=pybadger.BLINKA_PURPLE, scale=2, padding_above=2) +pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, padding_above=3) pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=3, padding_above=1) pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=4, padding_above=4) @@ -18,3 +18,4 @@ if pybadger.button.b: pybadger.show_qr_code() + From de49f6793f67bb237d31624b9dc88d6290322b5c Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Tue, 25 Feb 2020 21:57:38 -0500 Subject: [PATCH 07/12] Whitespace. --- examples/pybadger_clue_custom_badge.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/pybadger_clue_custom_badge.py b/examples/pybadger_clue_custom_badge.py index 4edca66..6d9b3dc 100644 --- a/examples/pybadger_clue_custom_badge.py +++ b/examples/pybadger_clue_custom_badge.py @@ -18,4 +18,3 @@ if pybadger.button.b: pybadger.show_qr_code() - From f485fdafb867cf246e4aca36be6c560e237bf614 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Wed, 26 Feb 2020 12:47:41 -0500 Subject: [PATCH 08/12] More thorough docs. --- adafruit_pybadger/pybadger_base.py | 64 ++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index 2052610..dba5903 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -109,8 +109,6 @@ class PyBadgerBase: BLINKA_PURPLE = (102, 45, 145) BLINKA_PINK = (231, 33, 138) - RAINBOW = (RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE) - # Button Constants BUTTON_LEFT = const(128) BUTTON_UP = const(64) @@ -121,7 +119,7 @@ class PyBadgerBase: BUTTON_A = const(2) BUTTON_B = const(1) - def __init__(self, *, pixels_brightness=1.0): + def __init__(self): self._light_sensor = None self._accelerometer = None self._label = label @@ -137,7 +135,7 @@ def __init__(self, *, pixels_brightness=1.0): # NeoPixels self._neopixels = neopixel.NeoPixel(board.NEOPIXEL, self._neopixel_count, - brightness=pixels_brightness, pixel_order=neopixel.GRB) + brightness=1, pixel_order=neopixel.GRB) # Auto dim display based on movement self._last_accelerometer = None @@ -199,6 +197,9 @@ def badge_background(self, background_color=(255, 0, 0), rectangle_color=(255, 2 pybadger.badge_background(background_color=pybadger.WHITE, rectangle_color=pybadger.PURPLE, rectangle_drop=0.2, rectangle_height=0.6) + + while True: + pybadger.show() """ self._background_group = self._badge_background(background_color, rectangle_color, rectangle_drop, rectangle_height) @@ -233,6 +234,9 @@ def image_background(self, image_name=None): from adafruit_pybadger import pybadger pybadger.image_background("Blinka.bmp") + + while True: + pybadger.show() """ self._background_image_filename = image_name @@ -262,19 +266,17 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, rectangle_color=pybadger.PURPLE, rectangle_drop=0.2, rectangle_height=0.6) - pybadger.badge_line(text="@blinka", color=pybadger.BLINKA_PURPLE, scale=4, - padding_above=1) - pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, + pybadger.badge_line(text="@circuitpython", color=pybadger.BLINKA_PURPLE, scale=2, padding_above=2) + pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, + padding_above=3) pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=3, padding_above=1) pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=4, padding_above=4) - pybadger.show() - while True: - pass + pybadger.show() """ if isinstance(font, str): font = load_font(font, text) @@ -314,8 +316,7 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, self._y_position += height * scale + 4 def show(self): - """Call ``show()`` to display the badge lines of text.""" - + """Call ``pybadger.show()`` to display the custom badge elements.""" if not self._created_background: self._create_badge_background() @@ -357,6 +358,12 @@ def auto_dim_display(self, delay=5.0, movement_threshold=10): :param int movement_threshold: Threshold required for movement to be considered stopped. Change to increase or decrease sensitivity. + .. code-block:: python + + from adafruit_pybadger import pybadger + + while True: + pybadger.auto_dim_display(delay=10) """ if not self._check_for_movement(movement_threshold=movement_threshold): current_time = time.monotonic() @@ -383,7 +390,7 @@ def acceleration(self): @property def brightness(self): - """Display brightness.""" + """Display brightness. Must be a value between ``0`` and ``1``.""" return self.display.brightness @brightness.setter @@ -417,6 +424,14 @@ def show_business_card(self, *, image_name=None, name_string=None, name_scale=1, :param email_font_two: The font for the second email string. Defaults to ``terminalio.FONT``. + .. code-block:: python + from adafruit_pybadger import pybadger + + while True: + pybadger.show_business_card(image_name="Blinka.bmp", name_string="Blinka", + name_scale=2, email_string_one="blinka@", + email_string_two="adafruit.com") + """ business_card_label_groups = [] if name_string: @@ -480,6 +495,14 @@ def show_badge(self, *, background_color=(255, 0, 0), foreground_color=(255, 255 :param name_string: The third string of the badge - change to be your name. Defaults to "Blinka". + .. code-block:: python + + from adafruit_pybadger import pybadger + + while True: + pybadger.show_badge(name_string="Blinka", hello_scale=2, my_name_is_scale=2, + name_scale=3) + """ hello_group = self._create_label_group(text=hello_string, font=hello_font, @@ -528,11 +551,18 @@ def bitmap_qr(matrix): bitmap[x + border_pixels, y + border_pixels] = 0 return bitmap - def show_qr_code(self, *, data="https://circuitpython.org"): - """Generate a QR code and display it for ``dwell`` seconds. + def show_qr_code(self, data="https://circuitpython.org"): + """Generate a QR code. :param string data: A string of data for the QR code + .. code-block:: python + + from adafruit_pybadger import pybadger + + while True: + pybadger.show_qr_code("https://adafruit.com") + """ qr_code = adafruit_miniqr.QRCode(qr_type=3, error_correct=adafruit_miniqr.L) qr_code.add_data(bytearray(data)) @@ -585,7 +615,7 @@ def play_tone(self, frequency, duration): def start_tone(self, frequency): """ Produce a tone using the speaker. Try changing frequency to change - the pitch of the tone. + the pitch of the tone. Use ``stop_tone`` to stop the tone. :param int frequency: The frequency of the tone in Hz @@ -601,7 +631,7 @@ def start_tone(self, frequency): self._sample.play(self._sine_wave_sample, loop=True) def stop_tone(self): - """ Use with start_tone to stop the tone produced. + """ Use with ``start_tone`` to stop the tone produced. """ # Stop playing any tones. if self._sample is not None and self._sample.playing: From 9e20e5b5b6d28ce3f25602a2438430c7f0b80ee0 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Wed, 26 Feb 2020 12:50:50 -0500 Subject: [PATCH 09/12] Whitespace and endings. --- examples/pybadger_clue_custom_badge.py | 3 +-- examples/pybadger_custom_badge.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/pybadger_clue_custom_badge.py b/examples/pybadger_clue_custom_badge.py index 6d9b3dc..b98140b 100644 --- a/examples/pybadger_clue_custom_badge.py +++ b/examples/pybadger_clue_custom_badge.py @@ -1,5 +1,4 @@ -"""""" - +"""Custom badge example for Adafruit CLUE.""" from adafruit_pybadger import pybadger pybadger.badge_background(background_color=pybadger.WHITE, rectangle_color=pybadger.PURPLE, diff --git a/examples/pybadger_custom_badge.py b/examples/pybadger_custom_badge.py index b67fde5..f1eca4f 100644 --- a/examples/pybadger_custom_badge.py +++ b/examples/pybadger_custom_badge.py @@ -10,4 +10,4 @@ pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=2, padding_above=2) while True: - pybadger.show() \ No newline at end of file + pybadger.show() From 7d29575425d4410638b5396ce9c7bec98343d0c3 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Wed, 26 Feb 2020 12:57:27 -0500 Subject: [PATCH 10/12] Whitespace or args. --- adafruit_pybadger/pybadger_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index dba5903..abc7ff6 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -425,6 +425,7 @@ def show_business_card(self, *, image_name=None, name_string=None, name_scale=1, ``terminalio.FONT``. .. code-block:: python + from adafruit_pybadger import pybadger while True: From ca1f2aec16502be7e2c27a38a71bbd7236604889 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Wed, 26 Feb 2020 13:54:16 -0500 Subject: [PATCH 11/12] Example update. --- examples/pybadger_clue_custom_badge.py | 2 +- examples/pybadger_custom_badge.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pybadger_clue_custom_badge.py b/examples/pybadger_clue_custom_badge.py index b98140b..a544c1a 100644 --- a/examples/pybadger_clue_custom_badge.py +++ b/examples/pybadger_clue_custom_badge.py @@ -6,7 +6,7 @@ pybadger.badge_line(text="@circuitpython", color=pybadger.BLINKA_PURPLE, scale=2, padding_above=2) pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=5, padding_above=3) -pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=3, padding_above=1) +pybadger.badge_line(text="CircuitPythonista", color=pybadger.WHITE, scale=2, padding_above=2) pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=4, padding_above=4) pybadger.show() diff --git a/examples/pybadger_custom_badge.py b/examples/pybadger_custom_badge.py index f1eca4f..2cd384b 100644 --- a/examples/pybadger_custom_badge.py +++ b/examples/pybadger_custom_badge.py @@ -5,8 +5,8 @@ rectangle_drop=0.2, rectangle_height=0.6) pybadger.badge_line(text="@circuitpython", color=pybadger.BLINKA_PURPLE, scale=1, padding_above=1) -pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=3, padding_above=1) -pybadger.badge_line(text="CircuitPython", color=pybadger.WHITE, scale=2, padding_above=1) +pybadger.badge_line(text="Blinka", color=pybadger.WHITE, scale=3, padding_above=2) +pybadger.badge_line(text="CircuitPythonista", color=pybadger.WHITE, scale=1, padding_above=1) pybadger.badge_line(text="she/her", color=pybadger.BLINKA_PINK, scale=2, padding_above=2) while True: From 6da6a493ee0b8b6f0f8286977ae9264fb251323f Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Wed, 26 Feb 2020 14:09:32 -0500 Subject: [PATCH 12/12] Update docs. --- adafruit_pybadger/pybadger_base.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/adafruit_pybadger/pybadger_base.py b/adafruit_pybadger/pybadger_base.py index abc7ff6..22c2500 100755 --- a/adafruit_pybadger/pybadger_base.py +++ b/adafruit_pybadger/pybadger_base.py @@ -258,6 +258,10 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, is equivalent to the height of two lines of text, etc. Defaults to ``0``. + The following example is designed to work on CLUE. To adapt for PyBadge or PyGamer, change + the ``scale`` and ``padding_above`` values to fit the text to the display. Examples for + CLUE, and PyBadge and PyGamer are included in the examples folder in the library repo. + .. code-block:: python from adafruit_pybadger import pybadger @@ -316,7 +320,8 @@ def badge_line(self, text=" ", color=(0, 0, 0), scale=1, font=terminalio.FONT, self._y_position += height * scale + 4 def show(self): - """Call ``pybadger.show()`` to display the custom badge elements.""" + """Call ``pybadger.show()`` to display the custom badge elements. If ``show()`` is not + called, the custom badge elements will not be displayed.""" if not self._created_background: self._create_badge_background()