cardiograph-computer/python-microcontrollers/meowbit/adafruit_display_text/scrolling_label.py

161 lines
5.1 KiB
Python

# SPDX-FileCopyrightText: 2019 Scott Shawcroft for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_display_text.scrolling_label`
====================================================
Displays text into a fixed-width label that scrolls leftward
if the full_text is large enough to need it.
* 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 adafruit_ticks
from adafruit_display_text import bitmap_label
try:
from typing import Optional
from fontio import FontProtocol
except ImportError:
pass
class ScrollingLabel(bitmap_label.Label):
"""ScrollingLabel - A fixed-width label that will scroll to the left
in order to show the full text if it's larger than the fixed-width.
:param font: The font to use for the label.
:type: ~fontio.FontProtocol
:param int max_characters: The number of characters that sets the fixed-width. Default is 10.
:param str text: The full text to show in the label. If this is longer than
``max_characters`` then the label will scroll to show everything.
:param float animate_time: The number of seconds in between scrolling animation
frames. Default is 0.3 seconds.
:param int current_index: The index of the first visible character in the label.
Default is 0, the first character. Will increase while scrolling."""
# pylint: disable=too-many-arguments
def __init__(
self,
font: FontProtocol,
max_characters: int = 10,
text: Optional[str] = "",
animate_time: Optional[float] = 0.3,
current_index: Optional[int] = 0,
**kwargs
) -> None:
super().__init__(font, **kwargs)
self.animate_time = animate_time
self._current_index = current_index
self._last_animate_time = -1
self.max_characters = max_characters
if text and text[-1] != " ":
text = "{} ".format(text)
self._full_text = text
self.update()
def update(self, force: bool = False) -> None:
"""Attempt to update the display. If ``animate_time`` has elapsed since
previews animation frame then move the characters over by 1 index.
Must be called in the main loop of user code.
:param bool force: whether to ignore ``animation_time`` and force the update.
Default is False.
:return: None
"""
_now = adafruit_ticks.ticks_ms()
if force or adafruit_ticks.ticks_less(
self._last_animate_time + int(self.animate_time * 1000), _now
):
if len(self.full_text) <= self.max_characters:
if self._text != self.full_text:
super()._set_text(self.full_text, self.scale)
self._last_animate_time = _now
return
if self.current_index + self.max_characters <= len(self.full_text):
_showing_string = self.full_text[
self.current_index : self.current_index + self.max_characters
]
else:
_showing_string_start = self.full_text[self.current_index :]
_showing_string_end = "{}".format(
self.full_text[
: (self.current_index + self.max_characters)
% len(self.full_text)
]
)
_showing_string = "{}{}".format(
_showing_string_start, _showing_string_end
)
super()._set_text(_showing_string, self.scale)
self.current_index += 1
self._last_animate_time = _now
return
@property
def current_index(self) -> int:
"""Index of the first visible character.
:return int: The current index
"""
return self._current_index
@current_index.setter
def current_index(self, new_index: int) -> None:
if self.full_text:
self._current_index = new_index % len(self.full_text)
else:
self._current_index = 0
@property
def full_text(self) -> str:
"""The full text to be shown. If it's longer than ``max_characters`` then
scrolling will occur as needed.
:return str: The full text of this label.
"""
return self._full_text
@full_text.setter
def full_text(self, new_text: str) -> None:
if new_text and new_text[-1] != " ":
new_text = "{} ".format(new_text)
if new_text != self._full_text:
self._full_text = new_text
self.current_index = 0
self.update(True)
@property
def text(self):
"""The full text to be shown. If it's longer than ``max_characters`` then
scrolling will occur as needed.
:return str: The full text of this label.
"""
return self.full_text
@text.setter
def text(self, new_text):
self.full_text = new_text