Compare commits

..

No commits in common. "master" and "ladyada-patch-1" have entirely different histories.

21 changed files with 201 additions and 5801 deletions

View file

@ -1,57 +0,0 @@
name: Build CI
on: [pull_request, push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme
- name: Library version
run: git describe --dirty --always --tags
- name: Check formatting
run: |
black --check --target-version=py35 .
- name: PyLint
run: |
pylint $( find . -path './adafruit*.py' )
([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace $( find . -path "./examples/*.py" ))
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Build docs
working-directory: docs
run: sphinx-build -E -W -b html . _build/html

View file

@ -1,81 +0,0 @@
name: Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
run: |
source actions-ci/install.sh
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Upload Release Assets
# the 'official' actions version does not yet support dynamically
# supplying asset names to upload. @csexton's version chosen based on
# discussion in the issue below, as its the simplest to implement and
# allows for selecting files with a pattern.
# https://github.com/actions/upload-release-asset/issues/4
#uses: actions/upload-release-asset@v1.0.1
uses: csexton/release-asset-action@master
with:
pattern: "bundles/*"
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Set up Python
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
env:
TWINE_USERNAME: ${{ secrets.pypi_username }}
TWINE_PASSWORD: ${{ secrets.pypi_password }}
run: |
python setup.py sdist
twine upload dist/*

7
.gitignore vendored
View file

@ -1,11 +1,6 @@
*.mpy
.idea
__pycache__
_build
*.pyc
.env
build*
bundles
*.DS_Store
.eggs
dist
**/*.egg-info

View file

@ -52,7 +52,7 @@ confidence=
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

39
.travis.yml Normal file
View file

@ -0,0 +1,39 @@
# This is a common .travis.yml for generating library release zip files for
# CircuitPython library releases using circuitpython-build-tools.
# See https://github.com/adafruit/circuitpython-build-tools for detailed setup
# instructions.
dist: xenial
language: python
python:
- "3.6"
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: 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
- pip install circuitpython-build-tools Sphinx sphinx-rtd-theme
- pip install --force-reinstall pylint==1.9.2
script:
- 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 ..

View file

@ -34,8 +34,6 @@ Examples of unacceptable behavior by participants include:
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Promoting or spreading disinformation, lies, or conspiracy theories against
a person, group, organisation, project, or community
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
@ -74,10 +72,10 @@ You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Moderators by tagging @community moderators. You may
also send an open message from any channel, or a direct message to
@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.

View file

@ -6,11 +6,11 @@ Introduction
:alt: Documentation Status
.. image:: https://img.shields.io/discord/327254708534116352.svg
:target: https://adafru.it/discord
:target: https://discord.gg/nBQh6qu
:alt: Discord
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Display_Text/workflows/Build%20CI/badge.svg
:target: https://github.com/adafruit/Adafruit_CircuitPython_Display_Text/actions/
.. image:: https://travis-ci.com/adafruit/Adafruit_CircuitPython_Display_Text.svg?branch=master
:target: https://travis-ci.com/adafruit/Adafruit_CircuitPython_Display_Text
:alt: Build Status
Displays text using CircuitPython's displayio.
@ -36,14 +36,11 @@ For a board with a built-in display.
import terminalio
from adafruit_display_text import label
text = "Hello world"
text_area = label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
while True:
pass
Contributing
@ -54,7 +51,25 @@ Contributions are welcome! Please read our `Code of Conduct
before contributing to help this project stay welcoming.
Documentation
=============
Sphinx documentation
-----------------------
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
Sphinx is used to build the documentation based on rST files and comments in the code. First,
install dependencies (feel free to reuse the virtual environment from above):
.. code-block:: shell
python3 -m venv .env
source .env/bin/activate
pip install Sphinx sphinx-rtd-theme
Now, once you have the virtual environment activated:
.. code-block:: shell
cd docs
sphinx-build -E -W -b html . _build/html
This will output the documentation to ``docs/_build/html``. Open the index.html in your browser to
view them. It will also (due to -W) error out on any warning like Travis will. This is a good way to
locally verify it will pass.

View file

@ -1,528 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2020 Kevin Matocha
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`bitmap_label`
================================================================================
Text graphics handling for CircuitPython, including text boxes
* Author(s): Kevin Matocha
Implementation Notes
--------------------
**Hardware:**
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
import displayio
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"
class Label(displayio.Group):
"""A label displaying a string of text that is stored in a bitmap.
Note: This ``bitmap_label.py`` library utilizes a bitmap to display the text.
This method is memory-conserving relative to ``label.py``.
For the bitmap_label library, the font, text, and line_spacing must be set at
instancing and are immutable. The ``max_glyphs`` parameter is ignored and is present
only for direct compatability with label.py.
For use cases where text changes are required after the initial instancing, please
use the `label.py` library.
For further reduction in memory usage, set save_text to False (text string will not
be stored).
The origin point set by ``x`` and ``y``
properties will be the left edge of the bounding box, and in the center of a M
glyph (if its one line), or the (number of lines * linespacing + M)/2. That is,
it will try to have it be center-left as close as possible.
:param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``.
Must include a capital M for measuring character size.
:param str text: Text to display
:param int max_glyphs: Unnecessary parameter (provided only for direct compability
with label.py)
:param int color: Color of all text in RGB hex
:param int background_color: Color of the background, use `None` for transparent
:param double line_spacing: Line spacing of text to display
:param boolean background_tight: Set `True` only if you want background box to tightly
surround text
:param int padding_top: Additional pixels added to background bounding box at top
:param int padding_bottom: Additional pixels added to background bounding box at bottom
:param int padding_left: Additional pixels added to background bounding box at left
:param int padding_right: Additional pixels added to background bounding box at right
:param (double,double) anchor_point: Point that anchored_position moves relative to.
Tuple with decimal percentage of width and height.
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)
:param (int,int) anchored_position: Position relative to the anchor_point. Tuple
containing x,y pixel coordinates.
:param int scale: Integer value of the pixel scaling
:param bool save_text: Set True to save the text string as a constant in the
label structure. Set False to reduce memory use.
"""
# pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments
# pylint: disable=too-many-branches, no-self-use
# Note: max_glyphs parameter is unnecessary, this is used for direct
# compatibility with label.py
def __init__(
self,
font,
x=0,
y=0,
text="",
max_glyphs=None, # This input parameter is ignored, only present for compatibility
# with label.py
color=0xFFFFFF,
background_color=None,
line_spacing=1.25,
background_tight=False,
padding_top=0,
padding_bottom=0,
padding_left=0,
padding_right=0,
anchor_point=None,
anchored_position=None,
save_text=True, # can reduce memory use if save_text = False
**kwargs
):
if text == "":
raise RuntimeError(
"Please provide text string, or use label.py for mutable text"
)
self._font = font
# Scale will be passed to Group using kwargs.
if "scale" in kwargs.keys():
self._scale = kwargs["scale"]
else:
self._scale = 1
self._line_spacing = line_spacing
self._save_text = save_text
if self._save_text: # text string will be saved
self._text = text
else:
self._text = None # save a None value since text string is not saved
# limit padding to >= 0
padding_top = max(0, padding_top)
padding_bottom = max(0, padding_bottom)
padding_left = max(0, padding_left)
padding_right = max(0, padding_right)
# Calculate the text bounding box
# Calculate tight box to provide bounding box dimensions to match label for
# anchor_position calculations
(
tight_box_x,
tight_box_y,
tight_x_offset,
tight_y_offset,
) = self._text_bounding_box(
text, font, self._line_spacing, background_tight=True,
)
if background_tight:
box_x = tight_box_x
box_y = tight_box_y
y_offset = tight_y_offset
x_offset = tight_x_offset
else:
(box_x, box_y, x_offset, y_offset) = self._text_bounding_box(
text, font, self._line_spacing, background_tight=background_tight,
)
# Calculate the background size including padding
box_x = box_x + padding_left + padding_right
box_y = box_y + padding_top + padding_bottom
# Create the two-color palette
self.palette = displayio.Palette(2)
self.background_color = background_color
self.color = color
# Create the bitmap and TileGrid
self.bitmap = displayio.Bitmap(box_x, box_y, len(self.palette))
# Place the text into the Bitmap
self._place_text(
self.bitmap,
text,
font,
self._line_spacing,
padding_left - x_offset,
padding_top + y_offset,
)
label_position_yoffset = int( # To calibrate with label.py positioning
(font.get_glyph(ord("M")).height) / 2
)
self.tilegrid = displayio.TileGrid(
self.bitmap,
pixel_shader=self.palette,
width=1,
height=1,
tile_width=box_x,
tile_height=box_y,
default_tile=0,
x=-padding_left + x_offset,
y=label_position_yoffset - y_offset - padding_top,
)
# instance the Group
# this Group will contain just one TileGrid with one contained bitmap
super().__init__(
max_size=1, x=x, y=y, **kwargs
) # this will include any arguments, including scale
self.append(self.tilegrid) # add the bitmap's tilegrid to the group
# Update bounding_box values. Note: To be consistent with label.py,
# this is the bounding box for the text only, not including the background.
self._bounding_box = (
self.tilegrid.x,
self.tilegrid.y,
tight_box_x,
tight_box_y,
)
self._anchored_position = anchored_position
self.anchor_point = anchor_point
self.anchored_position = (
self._anchored_position
) # sets anchored_position with setter after bitmap is created
@staticmethod
def _line_spacing_ypixels(font, line_spacing):
# Note: Scale is not implemented at this time, any scaling is pushed up to the Group level
return_value = int(line_spacing * font.get_bounding_box()[1])
return return_value
def _text_bounding_box(self, text, font, line_spacing, background_tight=False):
# This empirical approach checks several glyphs for maximum ascender and descender height
# (consistent with label.py)
glyphs = "M j'" # choose glyphs with highest ascender and lowest
# descender, will depend upon font used
try:
self._font.load_glyphs(text + glyphs)
except AttributeError:
# ignore if font does not have load_glyphs
pass
ascender_max = descender_max = 0
for char in glyphs:
this_glyph = font.get_glyph(ord(char))
if this_glyph:
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
descender_max = max(descender_max, -this_glyph.dy)
lines = 1
xposition = (
x_start
) = yposition = y_start = 0 # starting x and y position (left margin)
left = None
right = x_start
top = bottom = y_start
y_offset_tight = int((font.get_glyph(ord("M")).height) / 2)
# this needs to be reviewed (also in label.py), since it doesn't respond
# properly to the number of newlines.
newline = False
for char in text:
if char == "\n": # newline
newline = True
else:
my_glyph = font.get_glyph(ord(char))
if my_glyph is None: # Error checking: no glyph found
print("Glyph not found: {}".format(repr(char)))
else:
if newline:
newline = False
xposition = x_start # reset to left column
yposition = yposition + self._line_spacing_ypixels(
font, line_spacing
) # Add a newline
lines += 1
if xposition == x_start:
if left is None:
left = my_glyph.dx
else:
left = min(left, my_glyph.dx)
xright = xposition + my_glyph.width + my_glyph.dx
xposition += my_glyph.shift_x
right = max(right, xposition, xright)
if yposition == y_start: # first line, find the Ascender height
top = min(top, -my_glyph.height - my_glyph.dy + y_offset_tight)
bottom = max(bottom, yposition - my_glyph.dy + y_offset_tight)
if left is None:
left = 0
final_box_width = right - left
if background_tight:
final_box_height = bottom - top
final_y_offset = -top + y_offset_tight
else:
final_box_height = (lines - 1) * self._line_spacing_ypixels(
font, line_spacing
) + (ascender_max + descender_max)
final_y_offset = ascender_max
return (final_box_width, final_box_height, left, final_y_offset)
# pylint: disable=too-many-nested-blocks
def _place_text(
self,
bitmap,
text,
font,
line_spacing,
xposition,
yposition,
text_palette_index=1,
background_palette_index=0,
print_only_pixels=True, # print_only_pixels = True: only update the bitmap where the glyph
# pixel color is > 0. This is especially useful for script fonts where glyph
# bounding boxes overlap
# Set `print_only_pixels=False` to write all pixels
):
# placeText - Writes text into a bitmap at the specified location.
#
# Verify paletteIndex is working properly with * operator, especially
# if accommodating multicolored fonts
#
# Note: Scale is not implemented at this time, is pushed up to Group level
bitmap_width = bitmap.width
bitmap_height = bitmap.height
x_start = xposition # starting x position (left margin)
y_start = yposition
left = None
right = x_start
top = bottom = y_start
for char in text:
if char == "\n": # newline
xposition = x_start # reset to left column
yposition = yposition + self._line_spacing_ypixels(
font, line_spacing
) # Add a newline
else:
my_glyph = font.get_glyph(ord(char))
if my_glyph is None: # Error checking: no glyph found
print("Glyph not found: {}".format(repr(char)))
else:
if xposition == x_start:
if left is None:
left = my_glyph.dx
else:
left = min(left, my_glyph.dx)
right = max(
right,
xposition + my_glyph.shift_x,
xposition + my_glyph.width + my_glyph.dx,
)
if yposition == y_start: # first line, find the Ascender height
top = min(top, -my_glyph.height - my_glyph.dy)
bottom = max(bottom, yposition - my_glyph.dy)
glyph_offset_x = (
my_glyph.tile_index * my_glyph.width
) # for type BuiltinFont, this creates the x-offset in the glyph bitmap.
# for BDF loaded fonts, this should equal 0
for y in range(my_glyph.height):
for x in range(my_glyph.width):
x_placement = x + xposition + my_glyph.dx
y_placement = y + yposition - my_glyph.height - my_glyph.dy
if (bitmap_width > x_placement >= 0) and (
bitmap_height > y_placement >= 0
):
# Allows for remapping the bitmap indexes using paletteIndex
# for background and text.
palette_indexes = (
background_palette_index,
text_palette_index,
)
this_pixel_color = palette_indexes[
my_glyph.bitmap[
y * my_glyph.bitmap.width + x + glyph_offset_x
]
]
if not print_only_pixels or this_pixel_color > 0:
# write all characters if printOnlyPixels = False,
# or if thisPixelColor is > 0
bitmap[
y_placement * bitmap_width + x_placement
] = this_pixel_color
elif y_placement > bitmap_height:
break
xposition = xposition + my_glyph.shift_x
return (left, top, right - left, bottom - top) # bounding_box
@property
def bounding_box(self):
"""An (x, y, w, h) tuple that completely covers all glyphs. The
first two numbers are offset from the x, y origin of this group"""
return self._bounding_box
@property
def line_spacing(self):
"""The amount of space between lines of text, in multiples of the font's
bounding-box height. (E.g. 1.0 is the bounding-box height)"""
return self._line_spacing
@line_spacing.setter
def line_spacing(self, new_line_spacing):
raise RuntimeError(
"line_spacing is immutable for bitmap_label.py; use label.py for mutable line_spacing"
)
@property
def color(self):
"""Color of the text as an RGB hex number."""
return self._color
@color.setter
def color(self, new_color):
self._color = new_color
if new_color is not None:
self.palette[1] = new_color
self.palette.make_opaque(1)
else:
self.palette[1] = 0
self.palette.make_transparent(1)
@property
def background_color(self):
"""Color of the background as an RGB hex number."""
return self._background_color
@background_color.setter
def background_color(self, new_color):
self._background_color = new_color
if new_color is not None:
self.palette[0] = new_color
self.palette.make_opaque(0)
else:
self.palette[0] = 0
self.palette.make_transparent(0)
@property
def text(self):
"""Text to displayed."""
return self._text
@text.setter
def text(self, new_text):
raise RuntimeError(
"text is immutable for bitmap_label.py; use label.py library for mutable text"
)
@property
def font(self):
"""Font to use for text display."""
return self.font
@font.setter
def font(self, new_font):
raise RuntimeError(
"font is immutable for bitmap_label.py; use label.py library for mutable font"
)
@property
def anchor_point(self):
"""Point that anchored_position moves relative to.
Tuple with decimal percentage of width and height.
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)"""
return self._anchor_point
@anchor_point.setter
def anchor_point(self, new_anchor_point):
self._anchor_point = new_anchor_point
self.anchored_position = (
self._anchored_position
) # update the anchored_position using setter
@property
def anchored_position(self):
"""Position relative to the anchor_point. Tuple containing x,y
pixel coordinates."""
return self._anchored_position
@anchored_position.setter
def anchored_position(self, new_position):
self._anchored_position = new_position
# Set anchored_position
if (self._anchor_point is not None) and (self._anchored_position is not None):
self.x = int(
new_position[0]
- (self._bounding_box[0] * self._scale)
- round(self._anchor_point[0] * (self._bounding_box[2] * self._scale))
)
self.y = int(
new_position[1]
- (self._bounding_box[1] * self._scale)
- round(self._anchor_point[1] * self._bounding_box[3] * self._scale)
)

360
adafruit_display_text/label.py Executable file → Normal file
View file

@ -44,265 +44,100 @@ import displayio
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"
class Label(displayio.Group):
"""A label displaying a string of text. The origin point set by ``x`` and ``y``
properties will be the left edge of the bounding box, and in the center of a M
glyph (if its one line), or the (number of lines * linespacing + M)/2. That is,
it will try to have it be center-left as close as possible.
:param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``.
Must include a capital M for measuring character size.
:param Font font: A font class that has ``get_bounding_box`` and ``get_glyph``
:param str text: Text to display
:param int max_glyphs: The largest quantity of glyphs we will display
:param int color: Color of all text in RGB hex
:param double line_spacing: Line spacing of text to display"""
# pylint: disable=too-many-instance-attributes, too-many-locals
# This has a lot of getters/setters, maybe it needs cleanup.
def __init__(
self,
font,
*,
x=0,
y=0,
text="",
max_glyphs=None,
color=0xFFFFFF,
background_color=None,
line_spacing=1.25,
background_tight=False,
padding_top=0,
padding_bottom=0,
padding_left=0,
padding_right=0,
anchor_point=None,
anchored_position=None,
**kwargs
):
if "scale" in kwargs.keys():
self._scale = kwargs["scale"]
else:
self._scale = 1
def __init__(self, font, *, text=None, max_glyphs=None, color=0xffffff,
line_spacing=1.25, **kwargs):
if not max_glyphs and not text:
raise RuntimeError("Please provide a max size, or initial text")
if not max_glyphs:
max_glyphs = len(text)
# add one to max_size for the background bitmap tileGrid
super().__init__(max_size=max_glyphs + 1, **kwargs)
super().__init__(max_size=max_glyphs, **kwargs)
self.width = max_glyphs
self._font = font
self.font = font
self._text = None
self._anchor_point = anchor_point
self.x = x
self.y = y
self.height = self._font.get_bounding_box()[1]
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._line_spacing = line_spacing
self._boundingbox = None
self._background_tight = (
background_tight # sets padding status for text background box
)
if text:
self._update_text(text)
# Create the two-color text palette
self.palette = displayio.Palette(2)
self.palette[0] = 0
self.palette.make_transparent(0)
self.color = color
self._background_color = background_color
self._background_palette = displayio.Palette(1)
self._added_background_tilegrid = False
self._padding_top = padding_top
self._padding_bottom = padding_bottom
self._padding_left = padding_left
self._padding_right = padding_right
if text is not None:
self._update_text(str(text))
if (anchored_position is not None) and (anchor_point is not None):
self.anchored_position = anchored_position
def _create_background_box(self, lines, y_offset):
left = self._boundingbox[0]
if self._background_tight: # draw a tight bounding box
box_width = self._boundingbox[2]
box_height = self._boundingbox[3]
x_box_offset = 0
y_box_offset = self._boundingbox[1]
else: # draw a "loose" bounding box to include any ascenders/descenders.
# check a few glyphs for maximum ascender and descender height
# Enhancement: it would be preferred to access the font "FONT_ASCENT" and
# "FONT_DESCENT" in the imported BDF file
glyphs = "M j'" # choose glyphs with highest ascender and lowest
# descender, will depend upon font used
ascender_max = descender_max = 0
for char in glyphs:
this_glyph = self._font.get_glyph(ord(char))
if this_glyph:
ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy)
descender_max = max(descender_max, -this_glyph.dy)
box_width = self._boundingbox[2] + self._padding_left + self._padding_right
x_box_offset = -self._padding_left
box_height = (
(ascender_max + descender_max)
+ int((lines - 1) * self.height * self._line_spacing)
+ self._padding_top
+ self._padding_bottom
)
y_box_offset = -ascender_max + y_offset - self._padding_top
box_width = max(0, box_width) # remove any negative values
box_height = max(0, box_height) # remove any negative values
background_bitmap = displayio.Bitmap(box_width, box_height, 1)
tile_grid = displayio.TileGrid(
background_bitmap,
pixel_shader=self._background_palette,
x=left + x_box_offset,
y=y_box_offset,
)
return tile_grid
def _update_background_color(self, new_color):
if new_color is None:
self._background_palette.make_transparent(0)
if self._added_background_tilegrid:
self.pop(0)
self._added_background_tilegrid = False
else:
self._background_palette.make_opaque(0)
self._background_palette[0] = new_color
self._background_color = new_color
lines = self._text.rstrip("\n").count("\n") + 1
y_offset = int((self._font.get_glyph(ord("M")).height) / 2)
if not self._added_background_tilegrid: # no bitmap is in the self Group
# add bitmap if text is present and bitmap sizes > 0 pixels
if (
(len(self._text) > 0)
and (
self._boundingbox[2] + self._padding_left + self._padding_right > 0
)
and (
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
)
):
if len(self) > 0:
self.insert(0, self._create_background_box(lines, y_offset))
else:
self.append(self._create_background_box(lines, y_offset))
self._added_background_tilegrid = True
else: # a bitmap is present in the self Group
# update bitmap if text is present and bitmap sizes > 0 pixels
if (
(len(self._text) > 0)
and (
self._boundingbox[2] + self._padding_left + self._padding_right > 0
)
and (
self._boundingbox[3] + self._padding_top + self._padding_bottom > 0
)
):
self[0] = self._create_background_box(lines, y_offset)
else: # delete the existing bitmap
self.pop(0)
self._added_background_tilegrid = False
def _update_text(
self, new_text
): # pylint: disable=too-many-locals ,too-many-branches, too-many-statements
def _update_text(self, new_text): # pylint: disable=too-many-locals
x = 0
y = 0
if self._added_background_tilegrid:
i = 1
else:
i = 0
tilegrid_count = i
try:
self._font.load_glyphs(new_text + "M")
except AttributeError:
# ignore if font does not have load_glyphs
pass
y_offset = int((self._font.get_glyph(ord("M")).height) / 2)
right = top = bottom = 0
left = None
i = 0
old_c = 0
y_offset = int((self.font.get_glyph(ord('M')).height -
new_text.count('\n') * self.height * self.line_spacing) / 2)
#print("y offset from baseline", y_offset)
left = right = top = bottom = 0
for character in new_text:
if character == "\n":
if character == '\n':
y += int(self.height * self._line_spacing)
x = 0
continue
glyph = self._font.get_glyph(ord(character))
glyph = self.font.get_glyph(ord(character))
if not glyph:
continue
right = max(right, x + glyph.shift_x, x + glyph.width + glyph.dx)
if x == 0:
if left is None:
left = glyph.dx
else:
left = min(left, glyph.dx)
if y == 0: # first line, find the Ascender height
top = min(top, -glyph.height - glyph.dy + y_offset)
bottom = max(bottom, y - glyph.dy + y_offset)
right = max(right, x+glyph.width)
if y == 0: # first line, find the Ascender height
top = min(top, -glyph.height+y_offset)
bottom = max(bottom, y-glyph.dy+y_offset)
position_y = y - glyph.height - glyph.dy + y_offset
position_x = x + glyph.dx
if glyph.width > 0 and glyph.height > 0:
if not self._text or old_c >= len(self._text) or character != self._text[old_c]:
try:
# pylint: disable=unexpected-keyword-arg
face = displayio.TileGrid(
glyph.bitmap,
pixel_shader=self.palette,
default_tile=glyph.tile_index,
tile_width=glyph.width,
tile_height=glyph.height,
position=(position_x, position_y),
)
face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette,
default_tile=glyph.tile_index,
tile_width=glyph.width, tile_height=glyph.height,
position=(position_x, position_y))
except TypeError:
face = displayio.TileGrid(
glyph.bitmap,
pixel_shader=self.palette,
default_tile=glyph.tile_index,
tile_width=glyph.width,
tile_height=glyph.height,
x=position_x,
y=position_y,
)
if tilegrid_count < len(self):
self[tilegrid_count] = face
face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette,
default_tile=glyph.tile_index,
tile_width=glyph.width, tile_height=glyph.height,
x=position_x, y=position_y)
if i < len(self):
self[i] = face
else:
self.append(face)
tilegrid_count += 1
elif self._text and character == self._text[old_c]:
try:
self[i].position = (position_x, position_y)
except AttributeError:
self[i].x = position_x
self[i].y = 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
if left is None:
left = 0
while len(self) > tilegrid_count: # i:
while len(self) > i:
self.pop()
self._text = new_text
self._boundingbox = (left, top, right - left, bottom - top)
if self.background_color is not None:
self._update_background_color(self._background_color)
self._boundingbox = (left, top, left+right, bottom-top)
@property
def bounding_box(self):
@ -327,22 +162,7 @@ class Label(displayio.Group):
@color.setter
def color(self, new_color):
self._color = new_color
if new_color is not None:
self.palette[1] = new_color
self.palette.make_opaque(1)
else:
self.palette[1] = 0
self.palette.make_transparent(1)
@property
def background_color(self):
"""Color of the background as an RGB hex number."""
return self._background_color
@background_color.setter
def background_color(self, new_color):
self._update_background_color(new_color)
self.palette[1] = new_color
@property
def text(self):
@ -351,74 +171,4 @@ class Label(displayio.Group):
@text.setter
def text(self, new_text):
try:
current_anchored_position = self.anchored_position
self._update_text(str(new_text))
self.anchored_position = current_anchored_position
except RuntimeError as run_error:
raise RuntimeError("Text length exceeds max_glyphs") from run_error
@property
def font(self):
"""Font to use for text display."""
return self._font
@font.setter
def font(self, new_font):
old_text = self._text
current_anchored_position = self.anchored_position
self._text = ""
self._font = new_font
self.height = self._font.get_bounding_box()[1]
self._update_text(str(old_text))
self.anchored_position = current_anchored_position
@property
def anchor_point(self):
"""Point that anchored_position moves relative to.
Tuple with decimal percentage of width and height.
(E.g. (0,0) is top left, (1.0, 0.5): is middle right.)"""
return self._anchor_point
@anchor_point.setter
def anchor_point(self, new_anchor_point):
if self._anchor_point is not None:
current_anchored_position = self.anchored_position
self._anchor_point = new_anchor_point
self.anchored_position = current_anchored_position
else:
self._anchor_point = new_anchor_point
@property
def anchored_position(self):
"""Position relative to the anchor_point. Tuple containing x,y
pixel coordinates."""
if self._anchor_point is None:
return None
return (
int(
self.x
+ (self._boundingbox[0] * self._scale)
+ round(self._anchor_point[0] * self._boundingbox[2] * self._scale)
),
int(
self.y
+ (self._boundingbox[1] * self._scale)
+ round(self._anchor_point[1] * self._boundingbox[3] * self._scale)
),
)
@anchored_position.setter
def anchored_position(self, new_position):
if (self._anchor_point is None) or (new_position is None):
return # Note: anchor_point must be set before setting anchored_position
self.x = int(
new_position[0]
- (self._boundingbox[0] * self._scale)
- round(self._anchor_point[0] * (self._boundingbox[2] * self._scale))
)
self.y = int(
new_position[1]
- (self._boundingbox[1] * self._scale)
- round(self._anchor_point[1] * self._boundingbox[3] * self._scale)
)
self._update_text(new_text)

View file

@ -2,8 +2,7 @@
import os
import sys
sys.path.insert(0, os.path.abspath(".."))
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------
@ -11,10 +10,10 @@ sys.path.insert(0, os.path.abspath(".."))
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.todo',
]
# TODO: Please Read!
@ -24,32 +23,29 @@ extensions = [
autodoc_mock_imports = ["displayio"]
intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
}
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
templates_path = ['_templates']
source_suffix = ".rst"
source_suffix = '.rst'
# The master toctree document.
master_doc = "index"
master_doc = 'index'
# General information about the project.
project = "Adafruit Display_Text Library"
copyright = "2019 Scott Shawcroft"
author = "Scott Shawcroft"
project = u'Adafruit Display_Text Library'
copyright = u'2019 Scott Shawcroft'
author = u'Scott Shawcroft'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "1.0"
version = u'1.0'
# The full version, including alpha/beta/rc tags.
release = "1.0"
release = u'1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -61,7 +57,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"]
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md']
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -73,7 +69,7 @@ default_role = "any"
add_function_parentheses = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -88,62 +84,59 @@ napoleon_numpy_docstring = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.']
except:
html_theme = "default"
html_theme_path = ["."]
html_theme = 'default'
html_theme_path = ['.']
else:
html_theme_path = ["."]
html_theme_path = ['.']
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
html_static_path = ['_static']
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
html_favicon = "_static/favicon.ico"
html_favicon = '_static/favicon.ico'
# Output file base name for HTML help builder.
htmlhelp_basename = "AdafruitDisplay_textLibrarydoc"
htmlhelp_basename = 'AdafruitDisplay_textLibrarydoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(
master_doc,
"AdafruitDisplay_TextLibrary.tex",
"AdafruitDisplay_Text Library Documentation",
author,
"manual",
),
(master_doc, 'AdafruitDisplay_TextLibrary.tex', u'AdafruitDisplay_Text Library Documentation',
author, 'manual'),
]
# -- Options for manual page output ---------------------------------------
@ -151,13 +144,8 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(
master_doc,
"AdafruitDisplay_Textlibrary",
"Adafruit Display_Text Library Documentation",
[author],
1,
)
(master_doc, 'AdafruitDisplay_Textlibrary', u'Adafruit Display_Text Library Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
@ -166,13 +154,7 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"AdafruitDisplay_TextLibrary",
"Adafruit Display_Text Library Documentation",
author,
"AdafruitDisplay_TextLibrary",
"One line description of project.",
"Miscellaneous",
),
(master_doc, 'AdafruitDisplay_TextLibrary', u'Adafruit Display_Text Library Documentation',
author, 'AdafruitDisplay_TextLibrary', 'One line description of project.',
'Miscellaneous'),
]

View file

@ -1,63 +0,0 @@
"""
This examples shows the use of anchor_point and anchored_position.
"""
import board
import terminalio
import displayio
from adafruit_display_text import label
DISPLAY_WIDTH = 320
DISPLAY_HEIGHT = 240
TEXT = "Hello"
text_area_top_left = label.Label(terminalio.FONT, text=TEXT)
text_area_top_left.anchor_point = (0.0, 0.0)
text_area_top_left.anchored_position = (0, 0)
text_area_top_middle = label.Label(terminalio.FONT, text=TEXT)
text_area_top_middle.anchor_point = (0.5, 0.0)
text_area_top_middle.anchored_position = (DISPLAY_WIDTH / 2, 0)
text_area_top_right = label.Label(terminalio.FONT, text=TEXT)
text_area_top_right.anchor_point = (1.0, 0.0)
text_area_top_right.anchored_position = (DISPLAY_WIDTH, 0)
text_area_middle_left = label.Label(terminalio.FONT, text=TEXT)
text_area_middle_left.anchor_point = (0.0, 0.5)
text_area_middle_left.anchored_position = (0, DISPLAY_HEIGHT / 2)
text_area_middle_middle = label.Label(terminalio.FONT, text=TEXT)
text_area_middle_middle.anchor_point = (0.5, 0.5)
text_area_middle_middle.anchored_position = (DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2)
text_area_middle_right = label.Label(terminalio.FONT, text=TEXT)
text_area_middle_right.anchor_point = (1.0, 0.5)
text_area_middle_right.anchored_position = (DISPLAY_WIDTH, DISPLAY_HEIGHT / 2)
text_area_bottom_left = label.Label(terminalio.FONT, text=TEXT)
text_area_bottom_left.anchor_point = (0.0, 1.0)
text_area_bottom_left.anchored_position = (0, DISPLAY_HEIGHT)
text_area_bottom_middle = label.Label(terminalio.FONT, text=TEXT)
text_area_bottom_middle.anchor_point = (0.5, 1.0)
text_area_bottom_middle.anchored_position = (DISPLAY_WIDTH / 2, DISPLAY_HEIGHT)
text_area_bottom_right = label.Label(terminalio.FONT, text=TEXT)
text_area_bottom_right.anchor_point = (1.0, 1.0)
text_area_bottom_right.anchored_position = (DISPLAY_WIDTH, DISPLAY_HEIGHT)
text_group = displayio.Group(max_size=9)
text_group.append(text_area_top_middle)
text_group.append(text_area_top_left)
text_group.append(text_area_top_right)
text_group.append(text_area_middle_middle)
text_group.append(text_area_middle_left)
text_group.append(text_area_middle_right)
text_group.append(text_area_bottom_middle)
text_group.append(text_area_bottom_left)
text_group.append(text_area_bottom_right)
board.DISPLAY.show(text_group)
while True:
pass

View file

@ -1,27 +0,0 @@
"""
This examples shows the use color and background_color
"""
import time
import board
import terminalio
from adafruit_display_text import label
text = " Color Background Hello world"
text_area = label.Label(
terminalio.FONT, text=text, color=0x0000FF, background_color=0xFFAA00
)
text_area.x = 10
text_area.y = 10
print("background color is {:06x}".format(text_area.background_color))
board.DISPLAY.show(text_area)
time.sleep(2)
text_area.background_color = 0xFF0000
print("background color is {:06x}".format(text_area.background_color))
time.sleep(2)
text_area.background_color = None
print("background color is {}".format(text_area.background_color))
while True:
pass

View file

@ -1,125 +0,0 @@
"""
This examples shows the use color and background_color
"""
import time
import board
import displayio
# from adafruit_st7789 import ST7789
from adafruit_ili9341 import ILI9341
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
# Setup the SPI display
print("Starting the display...") # goes to serial only
displayio.release_displays()
spi = board.SPI()
tft_cs = board.D9 # arbitrary, pin not used
tft_dc = board.D10
tft_backlight = board.D12
tft_reset = board.D11
while not spi.try_lock():
spi.configure(baudrate=32000000)
spi.unlock()
display_bus = displayio.FourWire(
spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_reset,
baudrate=32000000,
polarity=1,
phase=1,
)
print("spi.frequency: {}".format(spi.frequency))
DISPLAY_WIDTH = 320
DISPLAY_HEIGHT = 240
# display = ST7789(display_bus, width=240, height=240, rotation=0, rowstart=80, colstart=0)
display = ILI9341(
display_bus,
width=DISPLAY_WIDTH,
height=DISPLAY_HEIGHT,
rotation=180,
auto_refresh=True,
)
display.show(None)
# font=terminalio.FONT # this is the Builtin fixed dimension font
font = bitmap_font.load_font("fonts/Helvetica-Bold-16.bdf")
text = []
text.append("none") # no ascenders or descenders
text.append("pop quops") # only descenders
text.append("MONSTERs are tall") # only ascenders
text.append("MONSTERs ate pop quops") # both ascenders and descenders
text.append("MONSTER quops\nnewline quops") # with newline
display.auto_refresh = True
myGroup = displayio.Group(max_size=6)
display.show(myGroup)
text_area = []
myPadding = 4
for i, thisText in enumerate(text):
text_area.append(
label.Label(
font,
text=thisText,
color=0xFFFFFF,
background_color=None,
background_tight=False,
padding_top=myPadding,
padding_bottom=myPadding,
padding_left=myPadding,
padding_right=myPadding,
)
)
this_x = 10
this_y = 10 + i * 40
text_area[i].x = 10
text_area[i].y = 3 + i * 50
text_area[i].anchor_point = (0, 0)
text_area[i].anchored_position = (this_x, this_y)
myGroup.append(text_area[i])
print("background color is {}".format(text_area[0].background_color))
while True:
time.sleep(2)
text_area[0].text = "text" # change some text in an existing text box
# Note: changed text must fit within existing number of characters
# when the Label was created
for area in text_area:
area.background_color = 0xFF0000
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0x000088
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0x00FF00
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = 0xFF0000
print("background color is {:06x}".format(text_area[0].background_color))
time.sleep(2)
for area in text_area:
area.background_color = None
print("background color is {}".format(text_area[0].background_color))

View file

@ -1,12 +0,0 @@
import board
import terminalio
from adafruit_display_text import bitmap_label
text = "Hello world"
text_area = bitmap_label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
while True:
pass

View file

@ -1,222 +0,0 @@
# Sample for comparing label and bitmap_label positioning with Builtin or loaded BDF fonts
# pylint: disable=no-member
import gc
import board
import displayio
import terminalio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import bitmap_label
from adafruit_display_text import label
# pylint: disable=no-member
##########
# Use this Boolean variables to select which font style to use
##########
use_builtinfont = False # Set True to use the terminalio.FONT BuiltinFont,
fontToUse = terminalio.FONT
# Set False to use a BDF loaded font, see "fontFiles" below
##########
if not use_builtinfont:
# load the fonts
print("loading font...")
fontList = []
# Load some proportional fonts
fontFile = "fonts/Helvetica-Bold-16.bdf"
fontToUse = bitmap_font.load_font(fontFile)
# Set scaling factor for display text
my_scale = 1
# Setup the SPI display
if "DISPLAY" not in dir(board):
# Setup the LCD display with driver
# You may need to change this to match the display driver for the chipset
# used on your display
from adafruit_ili9341 import ILI9341
displayio.release_displays()
# setup the SPI bus
spi = board.SPI()
tft_cs = board.D9 # arbitrary, pin not used
tft_dc = board.D10
tft_backlight = board.D12
tft_reset = board.D11
while not spi.try_lock():
spi.configure(baudrate=32000000)
spi.unlock()
display_bus = displayio.FourWire(
spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_reset,
baudrate=32000000,
polarity=1,
phase=1,
)
# Number of pixels in the display
DISPLAY_WIDTH = 320
DISPLAY_HEIGHT = 240
# create the display
display = ILI9341(
display_bus,
width=DISPLAY_WIDTH,
height=DISPLAY_HEIGHT,
rotation=180, # The rotation can be adjusted to match your configuration.
auto_refresh=True,
native_frames_per_second=90,
)
# reset the display to show nothing.
display.show(None)
else:
# built-in display
display = board.DISPLAY
print("Display is started")
preload_glyphs = (
True # set this to True if you want to preload the font glyphs into memory
)
# preloading the glyphs will help speed up the rendering of text but will use more RAM
if preload_glyphs and not use_builtinfont:
# identify the glyphs to load into memory -> increases rendering speed
glyphs = (
b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-_,.:?!'\n "
)
print("loading glyphs...")
fontToUse.load_glyphs(glyphs)
print("Glyphs are loaded.")
print("Fonts completed loading.")
# create group
long_string = "The purple snake\nbrings python fun\nto everyone."
label2_padding = 10
#####
# Create the "bitmap_label.py" versions of the text labels.
gc.collect()
bitmap_label_start = gc.mem_free()
bmap_label1 = bitmap_label.Label(
font=fontToUse,
text="bitmap_label",
color=0xFFFFFF,
background_color=0xFF0000,
padding_bottom=0,
padding_left=0,
padding_right=0,
padding_top=0,
background_tight=True,
line_spacing=1.25,
scale=my_scale,
anchor_point=(0.0, 0),
anchored_position=(10, 60),
)
bmap_label2 = bitmap_label.Label(
font=fontToUse,
text=long_string,
color=0x000000,
max_glyphs=len(long_string),
background_color=0xFFFF00,
padding_bottom=label2_padding,
padding_left=0,
padding_right=0,
padding_top=label2_padding,
background_tight=False,
line_spacing=1.25,
scale=my_scale,
anchor_point=(0.0, 0),
anchored_position=(10, 120),
)
gc.collect()
bitmap_label_end = gc.mem_free()
print("bitmap_label used: {} memory".format(bitmap_label_start - bitmap_label_end))
bmap_group = displayio.Group(max_size=4) # Create a group for displaying
bmap_group.append(bmap_label1)
bmap_group.append(bmap_label2)
#####
# Create the "label.py" versions of the text labels.
gc.collect()
label_start = gc.mem_free()
label1 = label.Label(
font=fontToUse,
text="label",
color=0xFFFFFF,
background_color=0xFF0000,
padding_bottom=0,
padding_left=0,
padding_right=0,
padding_top=0,
background_tight=True,
line_spacing=1.25,
scale=my_scale,
anchor_point=(1.0, 0),
anchored_position=(display.width - 10, 60),
)
label2 = label.Label(
font=fontToUse,
text=long_string,
color=0x000000,
max_glyphs=len(long_string),
background_color=0xFFFF00,
padding_bottom=label2_padding,
padding_left=0,
padding_right=0,
padding_top=label2_padding,
background_tight=False,
line_spacing=1.25,
scale=my_scale,
anchor_point=(1.0, 0),
anchored_position=(display.width - 10, 120),
)
gc.collect()
label_end = gc.mem_free()
print("label used: {} memory".format(label_start - label_end))
label_group = displayio.Group(max_size=4) # Create a group for displaying
label_group.append(label1)
label_group.append(label2)
print("***")
main_group = displayio.Group()
main_group.append(label_group)
main_group.append(bmap_group)
display.auto_refresh = True
display.show(main_group)
while True:
pass

View file

@ -1,25 +1,25 @@
"""
This example show the use of the backlight as well as using labels to simulate
a terminal using a font on the PyPortal
"""
import os
import time
import board
import pulseio
import microcontroller
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
fonts = list(
filter(lambda x: x.endswith("bdf") and not x.startswith("."), os.listdir("/"))
)
backlight = pulseio.PWMOut(microcontroller.pin.PB21) #pylint: disable=no-member
max_brightness = 2 ** 15
fonts = list(filter(lambda x: x.endswith("bdf") and not x.startswith("."), os.listdir("/")))
fonts = [bitmap_font.load_font(x) for x in fonts]
print("fade up")
# Fade up the backlight
for b in range(100):
board.DISPLAY.brightness = b / 100
backlight.duty_cycle = b * max_brightness // 100
time.sleep(0.01) # default (0.01)
demos = ["CircuitPython = Code + Community", "accents - üàêùéáçãÍóí", "others - αψ◌"]
@ -38,19 +38,16 @@ for demo_text in demos:
y += area.height
# Wait for the image to load.
try:
board.DISPLAY.refresh(target_frames_per_second=60)
except AttributeError:
board.DISPLAY.wait_for_frame()
board.DISPLAY.wait_for_frame()
# Wait for 10 minutes (600 seconds)
# Wait forever
time.sleep(600)
# Fade down the backlight
for b in range(100, -1, -1):
board.DISPLAY.brightness = b / 100
time.sleep(0.01) # default (0.01)
for b in range(50, -1, -1):
backlight.duty_cycle = b * max_brightness // 100
time.sleep(0.005) # default (0.005)
print("fade down")
time.sleep(10)
# splash.pop()

View file

@ -1,12 +0,0 @@
import board
import terminalio
from adafruit_display_text import label
text = "Hello world"
text_area = label.Label(terminalio.FONT, text=text)
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
while True:
pass

View file

@ -1,19 +1,15 @@
import os
import board
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
from adafruit_bitmap_font import bitmap_font
# the current working directory (where this file is)
cwd = ("/" + __file__).rsplit("/", 1)[0]
fonts = [
file
for file in os.listdir(cwd + "/fonts/")
if (file.endswith(".bdf") and not file.startswith("._"))
]
cwd = ("/"+__file__).rsplit('/', 1)[0]
fonts = [file for file in os.listdir(cwd+"/fonts/")
if (file.endswith(".bdf") and not file.startswith("._"))]
for i, filename in enumerate(fonts):
fonts[i] = cwd + "/fonts/" + filename
fonts[i] = cwd+"/fonts/"+filename
print(fonts)
##########################################################################
@ -30,12 +26,14 @@ board.DISPLAY.show(splash)
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)
# Load the font
font = bitmap_font.load_font(THE_FONT)
font.load_glyphs(DISPLAY_STRING.encode("utf-8"))
font.load_glyphs(DISPLAY_STRING.encode('utf-8'))
print(DISPLAY_STRING)
@ -50,16 +48,13 @@ print(dims)
textbg_bitmap = displayio.Bitmap(dims[2], dims[3], 1)
textbg_palette = displayio.Palette(1)
textbg_palette[0] = 0xFF0000
textbg_sprite = displayio.TileGrid(
textbg_bitmap, pixel_shader=textbg_palette, x=text.x + dims[0], y=text.y + dims[1]
)
textbg_sprite = displayio.TileGrid(textbg_bitmap,
pixel_shader=textbg_palette,
x=text.x+dims[0], y=text.y+dims[1])
splash.append(textbg_sprite)
splash.append(text)
try:
board.DISPLAY.refresh(target_frames_per_second=60)
except AttributeError:
board.DISPLAY.refresh_soon()
board.DISPLAY.wait_for_frame()
board.DISPLAY.refresh_soon()
board.DISPLAY.wait_for_frame()
while True:

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
Adafruit-Blinka
adafruit-blinka-displayio

View file

@ -1,50 +0,0 @@
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name="adafruit-circuitpython-display-text",
use_scm_version=True,
setup_requires=["setuptools_scm"],
description="Displays text using CircuitPython's displayio.",
long_description=long_description,
long_description_content_type="text/x-rst",
# The project's main homepage.
url="https://github.com/adafruit/Adafruit_CircuitPython_Display_Text",
# Author details
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=["Adafruit-Blinka", "adafruit-blinka-displayio",],
# Choose your license
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords="adafruit blinka circuitpython micropython bitmap fonts text display tft lcd displayio",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
packages=["adafruit_display_text"],
)