diff --git a/.travis.yml b/.travis.yml index f5f2442..6b62afb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,14 +12,20 @@ cache: pip: true deploy: - provider: releases - api_key: $GITHUB_TOKEN - file_glob: true - file: $TRAVIS_BUILD_DIR/bundles/* - skip_cleanup: true - overwrite: true - on: - tags: true + - provider: releases + api_key: "$GITHUB_TOKEN" + file_glob: true + file: "$TRAVIS_BUILD_DIR/bundles/*" + skip_cleanup: true + overwrite: true + on: + tags: true + - provider: pypi + user: adafruit-travis + password: + secure: "P8vHzlHSkY7aLsGMD12+43hG4eHcxjqFWaKYhvtoUlbTjOtHD+ZlzFG8rSXooUEdJZWYy9SDFShGfNMvws1I5opNFV0HA2Cs14jBeYa9hFi0p/7Box0tAHZbi6aGGcho/WbwQqUgaOkH0QJnsYgZedu65S1SXVkl7zfcORMRw3dXBM5UY5Q7KP8X/62CC78P1dPC/2127vyn98qHVEiT7rtCkBgXUM3WuPz2VadaLodvAD/E0xwqJXqZmDIM2stc223m9n9plXPahUHl9grT9oH8KhJP9Wr6uaRjAOhbFKimKFWTEcc1ugHjH8U+UFRk+OVTDNf5etgiQMs82x2Ssfoz+yi6z/HMQN2uc9TM4kAGrPUZIcZTVaniCtGSfa7HZSj60uxDkTMKuOt5B+ey5bGjpRAsNxTRJtgT8taIWURO4YU9Il3orPr9ByIp1OqjRmHwGF0PXK+U5G6UEP+JP9R8OvS9Q71nOrDZmFAD0krw9ZxO4p4T93bgV4ELkoI8RLbudqh68FG6XYwg2hr+VPT/9eLuYeOGdHB7vNAc1qumOX+e3bbC0BdpexxYyBtgaWsbGZEP9F2uYi20wUWGnM1agFXpua1JiWAqKf14ML5ysOTsyWKJ8+IXNtQIyY9z9gD5TCiNgkyiHbDEg2JA2ATOuWz42UzhdxntXBCuV00=" + on: + tags: true install: - pip install -r requirements.txt @@ -27,7 +33,7 @@ install: - pip install --force-reinstall pylint==1.9.2 script: - - pylint adafruit_display_text.py + - pylint adafruit_display_text/*.py - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-display_text --library_location . - cd docs && sphinx-build -E -W -b html . _build/html && cd .. diff --git a/README.rst b/README.rst index 540afe3..1ad30d4 100644 --- a/README.rst +++ b/README.rst @@ -28,8 +28,17 @@ This is easily achieved by downloading Usage Example ============= +For a board with a built-in display. + .. code:: python + import board + import terminalio + from adafruit_display_text import text_area + + text = "Hello world" + text_area = text_area.TextArea(terminalio.FONT, text=text, width=len(text)) + board.DISPLAY.show(text_area) Contributing diff --git a/adafruit_display_text/text_area.py b/adafruit_display_text/text_area.py index 2feb990..e0f2fbc 100644 --- a/adafruit_display_text/text_area.py +++ b/adafruit_display_text/text_area.py @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """ -`adafruit_display_text` +`adafruit_display_text.text_area` ==================================================== Displays text using CircuitPython's displayio. @@ -44,31 +44,31 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git" +class TextArea(displayio.Group): + """An area displaying a string of textself. -class TextArea: - def __init__(self, font, *, text=None, width=None, color=0x0, height=1): + :param Font font: A font class that has ``get_bounding_box`` and ``get_glyph`` + :param str text: Text to display + :param int width: Area width in characters + :param int height: Area height in characters + :param int color: Color of all text in RGB hex""" + def __init__(self, font, *, text=None, width=None, height=1, color=0xffffff): if not width and not text: raise RuntimeError("Please provide a width") if not width: width = len(text) + super().__init__(max_size=width * height) self.width = width self.font = font self._text = None - self.p = displayio.Palette(2) - self.p.make_transparent(0) - self.p[1] = color - - self.group = displayio.Group(max_size=width * height) + self.palette = displayio.Palette(2) + self.palette.make_transparent(0) + self.palette[1] = color bounds = self.font.get_bounding_box() self.height = bounds[1] - self.sprites = [None] * (width * height) - - self._x = 0 - self._y = 0 - if text: self._update_text(text) @@ -77,79 +77,56 @@ def _update_text(self, new_text): x = 0 y = 0 i = 0 - first_different = self._text is not None - for c in new_text: - if chr(ord(c)) == '\n': + old_c = 0 + for character in new_text: + if character == '\n': y += int(self.height * 1.25) x = 0 continue - glyph = self.font.get_glyph(ord(c)) + glyph = self.font.get_glyph(ord(character)) if not glyph: continue - # Remove any characters that are different - if first_different and c != self._text[i]: - # TODO(tannewt): Make this smarter when we can remove and add things into the middle - # of a group. - for _ in range(len(self.sprites) - i): - try: - self.group.pop() - except IndexError: - break - first_different = False - if not first_different: - position = (self._x + x, self._y + y + self.height - glyph["bounds"][1] - glyph["bounds"][3]) - try: - face = displayio.TileGrid(glyph["bitmap"], pixel_shader=self.p, position=position) - except: - face = displayio.Sprite(glyph["bitmap"], pixel_shader=self.p, position=position) - self.group.append(face) - self.sprites[i] = face - x += glyph["shift"][0] + position_y = y + self.height - glyph.height - glyph.dy + if not self._text or old_c >= len(self._text) or character != self._text[old_c]: + face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette, + default_tile=glyph.tile_index, + tile_width=glyph.width, tile_height=glyph.height, + position=(x, position_y)) + if i < len(self): + self[i] = face + else: + self.append(face) + elif self._text and character == self._text[old_c]: + self[i].position = (x, position_y) + + x += glyph.shift_x # TODO skip this for control sequences or non-printables. i += 1 - - # TODO: support multiple lines by adjusting y + old_c += 1 + # skip all non-prinables in the old string + while (self._text and old_c < len(self._text) and + (self._text[old_c] == '\n' or not self.font.get_glyph(ord(self._text[old_c])))): + old_c += 1 + # Remove the rest + while len(self) > i: + self.pop() self._text = new_text @property def color(self): - return self.p[1] + """Color of the text as an RGB hex number.""" + return self.palette[1] @color.setter - def color(self, c): - self.p[1] = c + def color(self, new_color): + self.palette[1] = new_color @property - def text(self, t): - self._text = t + def text(self): + """Text to display.""" + return self._text @text.setter - def text(self, t): - self._update_text(t) - - @property - def y(self): - return self._y - - @y.setter - def y(self, new_y): - for sprite in self.sprites: - if not sprite: - continue - pos = sprite.position - sprite.position = (pos[0], (pos[1] - self._y) + new_y) - self._y = new_y - - @property - def x(self): - return self._x - - @x.setter - def x(self, new_x): - for sprite in self.sprites: - if not sprite: - continue - pos = sprite.position - sprite.position = ((pos[0] - self._x) + new_x, pos[1]) - self._x = new_x + def text(self, new_text): + self._update_text(new_text) diff --git a/docs/api.rst b/docs/api.rst index 3919acb..e54848c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,5 +4,5 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" -.. automodule:: adafruit_display_text +.. automodule:: adafruit_display_text.text_area :members: diff --git a/docs/conf.py b/docs/conf.py index a1508ee..62eeb8b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,7 @@ # Uncomment the below if you use native CircuitPython modules such as # digitalio, micropython and busio. List the modules you use. Without it, the # autodoc module docs will fail to generate with a warning. -# autodoc_mock_imports = ["digitalio", "busio"] +autodoc_mock_imports = ["displayio"] intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} diff --git a/docs/index.rst b/docs/index.rst index 3cadad3..603a3f2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,15 +23,9 @@ Table of Contents .. toctree:: :caption: Tutorials -.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave - the toctree above for use later. - .. toctree:: :caption: Related Products -.. todo:: Add any product links here. If there are none, then simply delete this todo and leave - the toctree above for use later. - .. toctree:: :caption: Other Links diff --git a/examples/pyportal.py b/examples/pyportal.py index 30f889e..ecfa6fd 100644 --- a/examples/pyportal.py +++ b/examples/pyportal.py @@ -1,16 +1,14 @@ -import board -import displayio import os -import gc -import pulseio -import random import time +import board +import pulseio import microcontroller +import displayio from adafruit_bitmap_font import bitmap_font from adafruit_display_text.text_area import TextArea -backlight = pulseio.PWMOut(microcontroller.pin.PB21) +backlight = pulseio.PWMOut(microcontroller.pin.PB21) #pylint: disable=no-member max_brightness = 2 ** 15 @@ -35,14 +33,12 @@ print("Font load {}".format(font.name)) area = TextArea(font, text=demo_text) area.y = y - splash.append(area.group) + splash.append(area) y += area.height # Wait for the image to load. board.DISPLAY.wait_for_frame() - gc.collect() - print("mem free:", gc.mem_free()) # Wait forever time.sleep(600)