From 8c8df5ccaa261cd93af3da441daa47b186be6d26 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 11 Feb 2019 17:53:41 -0800 Subject: [PATCH 1/7] Subclass Group and use new accessors. Fixes #1 --- adafruit_display_text/text_area.py | 71 +++++++----------------------- 1 file changed, 15 insertions(+), 56 deletions(-) diff --git a/adafruit_display_text/text_area.py b/adafruit_display_text/text_area.py index 2feb990..26cd9d7 100644 --- a/adafruit_display_text/text_area.py +++ b/adafruit_display_text/text_area.py @@ -45,10 +45,11 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git" -class TextArea: - def __init__(self, font, *, text=None, width=None, color=0x0, height=1): +class TextArea(displayio.Group): + def __init__(self, font, *, text=None, width=None, color=0xffffff, height=1): if not width and not text: raise RuntimeError("Please provide a width") + super().__init__(max_size=width * height) if not width: width = len(text) self.width = width @@ -59,16 +60,9 @@ def __init__(self, font, *, text=None, width=None, color=0x0, height=1): self.p.make_transparent(0) self.p[1] = color - self.group = displayio.Group(max_size=width * height) - 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) @@ -86,30 +80,21 @@ def _update_text(self, new_text): glyph = self.font.get_glyph(ord(c)) 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] + if not self._text or i >= len(self._text) or c != self._text[i]: + face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.p, default_tile=glyph.tile_index, + tile_width=glyph.width, tile_height=glyph.height, + position=(x, y + self.height - glyph.height - glyph.dy)) + if i < len(self): + self[i] = face + else: + self.append(face) + x += glyph.shift_x # TODO skip this for control sequences or non-printables. i += 1 - - # TODO: support multiple lines by adjusting y + # Remove the rest + while len(self) > i: + self.pop() self._text = new_text @property @@ -127,29 +112,3 @@ def text(self, t): @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 From 911ab7f1f5261946f5ea671ca23ee1f33ed7e12c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 12 Feb 2019 14:53:54 -0800 Subject: [PATCH 2/7] Lint and fixup docs --- .travis.yml | 2 +- README.rst | 9 ++++++ adafruit_display_text/text_area.py | 44 ++++++++++++++++++------------ docs/api.rst | 2 +- docs/conf.py | 2 +- docs/index.rst | 6 ---- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index f5f2442..0684d4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,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 26cd9d7..f0c4ce0 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,9 +44,15 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git" - class TextArea(displayio.Group): - def __init__(self, font, *, text=None, width=None, color=0xffffff, height=1): + """An area displaying a string of textself. + + :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") super().__init__(max_size=width * height) @@ -56,9 +62,9 @@ def __init__(self, font, *, text=None, width=None, color=0xffffff, height=1): self.font = font self._text = None - self.p = displayio.Palette(2) - self.p.make_transparent(0) - self.p[1] = color + self.palette = displayio.Palette(2) + self.palette.make_transparent(0) + self.palette[1] = color bounds = self.font.get_bounding_box() self.height = bounds[1] @@ -71,17 +77,17 @@ 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': + 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 - if not self._text or i >= len(self._text) or c != self._text[i]: - face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.p, default_tile=glyph.tile_index, + if not self._text or i >= len(self._text) or character != self._text[i]: + face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette, + default_tile=glyph.tile_index, tile_width=glyph.width, tile_height=glyph.height, position=(x, y + self.height - glyph.height - glyph.dy)) if i < len(self): @@ -99,16 +105,18 @@ def _update_text(self, new_text): @property def color(self): + """Color of the text as an RGB hex number.""" return self.p[1] @color.setter - def color(self, c): - self.p[1] = c + def color(self, new_color): + self.p[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) + 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 From 12d5c11499b3632390fd709feab6b63763fec143 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 12 Feb 2019 14:58:09 -0800 Subject: [PATCH 3/7] Add pypi to Travis.yml --- .travis.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0684d4f..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 From 90ae502daa5d731ca8fe613af441595b770132eb Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 12 Feb 2019 15:07:15 -0800 Subject: [PATCH 4/7] Lint example --- examples/pyportal.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/pyportal.py b/examples/pyportal.py index 30f889e..08998bf 100644 --- a/examples/pyportal.py +++ b/examples/pyportal.py @@ -1,10 +1,9 @@ +import os +import time import board import displayio -import os -import gc import pulseio -import random -import time + import microcontroller from adafruit_bitmap_font import bitmap_font @@ -35,14 +34,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) From 43bee28d54979f0382cd30f3cf8dcb981f06186b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 12 Feb 2019 15:10:28 -0800 Subject: [PATCH 5/7] Ignore missing member --- examples/pyportal.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/pyportal.py b/examples/pyportal.py index 08998bf..ecfa6fd 100644 --- a/examples/pyportal.py +++ b/examples/pyportal.py @@ -1,15 +1,14 @@ import os import time import board -import displayio 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 From 6647f1cd3b17116f146cf62a9b79370a21f5131a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 13 Feb 2019 12:13:27 -0800 Subject: [PATCH 6/7] A couple fixes to TextArea --- adafruit_display_text/text_area.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/adafruit_display_text/text_area.py b/adafruit_display_text/text_area.py index f0c4ce0..349cdb9 100644 --- a/adafruit_display_text/text_area.py +++ b/adafruit_display_text/text_area.py @@ -55,9 +55,9 @@ class TextArea(displayio.Group): def __init__(self, font, *, text=None, width=None, height=1, color=0xffffff): if not width and not text: raise RuntimeError("Please provide a width") - super().__init__(max_size=width * height) if not width: width = len(text) + super().__init__(max_size=width * height) self.width = width self.font = font self._text = None @@ -77,6 +77,7 @@ def _update_text(self, new_text): x = 0 y = 0 i = 0 + old_c = 0 for character in new_text: if character == '\n': y += int(self.height * 1.25) @@ -85,19 +86,27 @@ def _update_text(self, new_text): glyph = self.font.get_glyph(ord(character)) if not glyph: continue - if not self._text or i >= len(self._text) or character != self._text[i]: + 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, y + self.height - glyph.height - glyph.dy)) + 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 + 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() @@ -106,11 +115,11 @@ def _update_text(self, new_text): @property def color(self): """Color of the text as an RGB hex number.""" - return self.p[1] + return self.palette[1] @color.setter def color(self, new_color): - self.p[1] = new_color + self.palette[1] = new_color @property def text(self): From 5fc08a963fda1c6362b0325e6490fc19b2f5fd8f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 13 Feb 2019 12:22:13 -0800 Subject: [PATCH 7/7] Fix long line --- adafruit_display_text/text_area.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_display_text/text_area.py b/adafruit_display_text/text_area.py index 349cdb9..e0f2fbc 100644 --- a/adafruit_display_text/text_area.py +++ b/adafruit_display_text/text_area.py @@ -105,7 +105,8 @@ def _update_text(self, new_text): i += 1 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]))): + 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: