Compare commits
227 commits
ladyada-pa
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d28b6c6d1 | ||
|
|
59c9544605 | ||
|
|
f83687c47a | ||
|
|
61dac4d83d | ||
|
|
3f9ea73480 | ||
|
|
cf6d7130d0 | ||
|
|
ec28d2a8ec | ||
|
|
704744f417 | ||
|
|
1421c5d57e | ||
|
|
7d70ca7a7f | ||
|
|
518cc0c45d | ||
|
|
f37e66c2d3 | ||
|
|
5ff8c19af7 | ||
|
|
3b03903091 | ||
|
|
54acb53d11 | ||
|
|
6862809305 | ||
|
|
c30285993a | ||
|
|
5a514ce4ef | ||
|
|
a99517f50e | ||
|
|
62de33b401 | ||
|
|
11f7fe8b11 | ||
|
|
b598e15e79 | ||
|
|
ff4be2722d | ||
|
|
42579f870e | ||
|
|
d4517644f6 | ||
|
|
b0d1d5914a | ||
|
|
12440fd02a | ||
|
|
c16dac7dc2 | ||
|
|
b14b9455fd | ||
|
|
3084b17078 | ||
|
|
8c98dacd81 | ||
|
|
e443db2874 | ||
|
|
b6662efe48 | ||
|
|
e08643cdf8 | ||
|
|
61481a7182 | ||
|
|
dc3dcd2044 | ||
|
|
b66efa1323 | ||
|
|
e89c457f19 | ||
|
|
4cfc2a4675 | ||
|
|
6aac22d59d | ||
|
|
3c9e414c8a | ||
|
|
6a30b327dc | ||
|
|
119a7d0aed | ||
|
|
dfe6899570 | ||
|
|
4bdfb61e8d | ||
|
|
9ffd22a7b9 | ||
|
|
93756e43e6 | ||
|
|
9640d00d04 | ||
|
|
8a164973b6 | ||
|
|
accdb87056 | ||
|
|
ace3e7891f | ||
|
|
d0c7d38c56 | ||
|
|
25ff802a7c | ||
|
|
be6747308d | ||
|
|
4a7e7a017e | ||
|
|
b628dffa0e | ||
|
|
bf8577692c | ||
|
|
32f2bf2422 | ||
|
|
ab0158d623 | ||
|
|
d855e29c3e | ||
|
|
9fa93fe67d | ||
|
|
94e81582ea | ||
|
|
1649a68d60 | ||
|
|
bc70c46818 | ||
|
|
9b0fe91a6a | ||
|
|
dd13c494d7 | ||
|
|
85c9a7f4f6 | ||
|
|
fa74a7c121 | ||
|
|
bbc0ea9a68 | ||
|
|
48f2fb04b2 | ||
|
|
b3114027f3 | ||
|
|
f5195246cb | ||
|
|
a07b79fa45 | ||
|
|
ec98a7f54a | ||
|
|
b6ec018298 | ||
|
|
c2e3a79dc9 | ||
|
|
05affa4097 | ||
|
|
f106d483a1 | ||
|
|
c5af1119d9 | ||
|
|
aa4d0a0036 | ||
|
|
2063412f78 | ||
|
|
fdd5bd8894 | ||
|
|
51e13b2e61 | ||
|
|
2d65dc0f5c | ||
|
|
631d0447b3 | ||
|
|
062b1bc747 | ||
|
|
0b524cfe2b | ||
|
|
11b6fcbbe2 | ||
|
|
c9309dae6a | ||
|
|
2caeb592cc | ||
|
|
646b46d405 | ||
|
|
225b0b176a | ||
|
|
d020baba0f | ||
|
|
1dcecb9979 | ||
|
|
5fe2117df3 | ||
|
|
f5288fc8b5 | ||
|
|
0e42a2ddda | ||
|
|
d9ac04ec61 | ||
|
|
819eb1dda5 | ||
|
|
8661ce1f35 | ||
|
|
207cbc610c | ||
|
|
27411f5d09 | ||
|
|
cb5e370df4 | ||
|
|
d9f759eb43 | ||
|
|
1f2bf53313 | ||
|
|
05bd0ad842 | ||
|
|
93130c4da3 | ||
|
|
1be4aa3473 | ||
|
|
2efbd77edd | ||
|
|
f8c69dbe6b | ||
|
|
dcd466207c | ||
|
|
b49ec93f37 | ||
|
|
a1714217d2 | ||
|
|
9f4c2df9b2 | ||
|
|
a52eede646 | ||
|
|
c6951dcb69 | ||
|
|
04ba5b35b3 | ||
|
|
a90c00e4ac | ||
|
|
5c11366c86 | ||
|
|
ae577587e4 | ||
|
|
ee5a5ab408 | ||
|
|
7464d08d45 | ||
|
|
c41ca13f0a | ||
|
|
a51392c727 | ||
|
|
30e5a24edd | ||
|
|
b536f4fad9 | ||
|
|
fb0cfee6cc | ||
|
|
a392523a38 | ||
|
|
463fc685c4 | ||
|
|
387d67e25f | ||
|
|
713692a889 | ||
|
|
ec7b69ac69 | ||
|
|
a2cec0b8d9 | ||
|
|
e191c8a0e0 | ||
|
|
6695e3c7c4 | ||
|
|
a102ba2125 | ||
|
|
68c9522a34 | ||
|
|
83f43decae | ||
|
|
ac63a182ec | ||
|
|
173d0c5b67 | ||
|
|
ed64879d2d | ||
|
|
0defe7dea3 | ||
|
|
1c19264523 | ||
|
|
4acafa4b4f | ||
|
|
69cc1bf893 | ||
|
|
02f26d93e0 | ||
|
|
12d8b25f94 | ||
|
|
995f3decba | ||
|
|
e60fb65c70 | ||
|
|
a1c4859ca7 | ||
|
|
96f2f11555 | ||
|
|
52a3becd77 | ||
|
|
a2473b518e | ||
|
|
b5593bc5e5 | ||
|
|
b0ca00ef2f | ||
|
|
37febaef3c | ||
|
|
bb79810529 | ||
|
|
756088bbfc | ||
|
|
9a73454013 | ||
|
|
f26a881300 | ||
|
|
f91b78daa6 | ||
|
|
25c5a1aaba | ||
|
|
b45453a3ca | ||
|
|
ec69e74f9b | ||
|
|
ab57157574 | ||
|
|
c63451352f | ||
|
|
67d1fb32f5 | ||
|
|
81e07aadc4 | ||
|
|
83f581d752 | ||
|
|
f27dd3174e | ||
|
|
19183b701c | ||
|
|
509f9569b0 | ||
|
|
55a495e864 | ||
|
|
b506a0af03 | ||
|
|
72c5b627b9 | ||
|
|
4d65e55273 | ||
|
|
0fe25b5307 | ||
|
|
870643ae4e | ||
|
|
46b04fea72 | ||
|
|
80ebaa9b0d | ||
|
|
5dfc291763 | ||
|
|
fb70ae4b70 | ||
|
|
7868b40ae4 | ||
|
|
eae4cb4f48 | ||
|
|
39431ec92d | ||
|
|
cefd4545f5 | ||
|
|
2086944a56 | ||
|
|
3fa0b2c695 | ||
|
|
0d8bc6377c | ||
|
|
89ce1010af | ||
|
|
d84df43673 | ||
|
|
142054af67 | ||
|
|
36e199ac74 | ||
|
|
45d124932f | ||
|
|
193f6b5169 | ||
|
|
8ca3c1a724 | ||
|
|
afeb2a2669 | ||
|
|
4d53a379ab | ||
|
|
86130b39f2 | ||
|
|
344775b34a | ||
|
|
7c74bcd8ad | ||
|
|
12b47af9c2 | ||
|
|
2fdd09b0ff | ||
|
|
3c1734bb97 | ||
|
|
06bec73c12 | ||
|
|
85a0c6566f | ||
|
|
09bd2439bb | ||
|
|
da9710781c | ||
|
|
ac195417fc | ||
|
|
5583c493ce | ||
|
|
8bd76d98c7 | ||
|
|
a12762d7b6 | ||
|
|
1bbd0b8d4e | ||
|
|
5076127411 | ||
|
|
a507e09991 | ||
|
|
dce386c9c3 | ||
|
|
9ce37d2ced | ||
|
|
c2693bc02a | ||
|
|
56f474b2c5 | ||
|
|
1b0e3eb1da | ||
|
|
13323a09f9 | ||
|
|
ea45562020 | ||
|
|
2cc1ccb842 | ||
|
|
836918575b | ||
|
|
a23e5ff8b5 | ||
|
|
5ec1c88226 | ||
|
|
f297762fe0 |
21 changed files with 5801 additions and 201 deletions
57
.github/workflows/build.yml
vendored
Normal file
57
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
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
|
||||||
81
.github/workflows/release.yml
vendored
Normal file
81
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
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
7
.gitignore
vendored
|
|
@ -1,6 +1,11 @@
|
||||||
|
*.mpy
|
||||||
|
.idea
|
||||||
__pycache__
|
__pycache__
|
||||||
_build
|
_build
|
||||||
*.pyc
|
*.pyc
|
||||||
.env
|
.env
|
||||||
build*
|
|
||||||
bundles
|
bundles
|
||||||
|
*.DS_Store
|
||||||
|
.eggs
|
||||||
|
dist
|
||||||
|
**/*.egg-info
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ confidence=
|
||||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||||
# --disable=W"
|
# --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=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
|
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
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
# 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
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
|
|
||||||
39
.travis.yml
39
.travis.yml
|
|
@ -1,39 +0,0 @@
|
||||||
# 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 ..
|
|
||||||
|
|
@ -34,6 +34,8 @@ Examples of unacceptable behavior by participants include:
|
||||||
* Excessive or unwelcome helping; answering outside the scope of the question
|
* Excessive or unwelcome helping; answering outside the scope of the question
|
||||||
asked
|
asked
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
* 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
|
* Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or electronic
|
* Publishing others' private information, such as a physical or electronic
|
||||||
address, without explicit permission
|
address, without explicit permission
|
||||||
|
|
@ -72,10 +74,10 @@ You may report in the following ways:
|
||||||
In any situation, you may send an email to <support@adafruit.com>.
|
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
|
On the Adafruit Discord, you may send an open message from any channel
|
||||||
to all Community Helpers by tagging @community helpers. You may also send an
|
to all Community Moderators by tagging @community moderators. You may
|
||||||
open message from any channel, or a direct message to @kattni#1507,
|
also send an open message from any channel, or a direct message to
|
||||||
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
|
@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
|
||||||
@Andon#8175.
|
@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
|
||||||
|
|
||||||
Email and direct message reports will be kept confidential.
|
Email and direct message reports will be kept confidential.
|
||||||
|
|
||||||
|
|
|
||||||
33
README.rst
33
README.rst
|
|
@ -6,11 +6,11 @@ Introduction
|
||||||
:alt: Documentation Status
|
:alt: Documentation Status
|
||||||
|
|
||||||
.. image:: https://img.shields.io/discord/327254708534116352.svg
|
.. image:: https://img.shields.io/discord/327254708534116352.svg
|
||||||
:target: https://discord.gg/nBQh6qu
|
:target: https://adafru.it/discord
|
||||||
:alt: Discord
|
:alt: Discord
|
||||||
|
|
||||||
.. image:: https://travis-ci.com/adafruit/Adafruit_CircuitPython_Display_Text.svg?branch=master
|
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Display_Text/workflows/Build%20CI/badge.svg
|
||||||
:target: https://travis-ci.com/adafruit/Adafruit_CircuitPython_Display_Text
|
:target: https://github.com/adafruit/Adafruit_CircuitPython_Display_Text/actions/
|
||||||
:alt: Build Status
|
:alt: Build Status
|
||||||
|
|
||||||
Displays text using CircuitPython's displayio.
|
Displays text using CircuitPython's displayio.
|
||||||
|
|
@ -36,11 +36,14 @@ For a board with a built-in display.
|
||||||
import terminalio
|
import terminalio
|
||||||
from adafruit_display_text import label
|
from adafruit_display_text import label
|
||||||
|
|
||||||
|
|
||||||
text = "Hello world"
|
text = "Hello world"
|
||||||
text_area = label.Label(terminalio.FONT, text=text)
|
text_area = label.Label(terminalio.FONT, text=text)
|
||||||
text_area.x = 10
|
text_area.x = 10
|
||||||
text_area.y = 10
|
text_area.y = 10
|
||||||
board.DISPLAY.show(text_area)
|
board.DISPLAY.show(text_area)
|
||||||
|
while True:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
|
|
@ -51,25 +54,7 @@ Contributions are welcome! Please read our `Code of Conduct
|
||||||
before contributing to help this project stay welcoming.
|
before contributing to help this project stay welcoming.
|
||||||
|
|
||||||
|
|
||||||
Sphinx documentation
|
Documentation
|
||||||
-----------------------
|
=============
|
||||||
|
|
||||||
Sphinx is used to build the documentation based on rST files and comments in the code. First,
|
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>`_.
|
||||||
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.
|
|
||||||
|
|
|
||||||
528
adafruit_display_text/bitmap_label.py
Executable file
528
adafruit_display_text/bitmap_label.py
Executable file
|
|
@ -0,0 +1,528 @@
|
||||||
|
# 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)
|
||||||
|
)
|
||||||
350
adafruit_display_text/label.py
Normal file → Executable file
350
adafruit_display_text/label.py
Normal file → Executable file
|
|
@ -44,100 +44,265 @@ import displayio
|
||||||
__version__ = "0.0.0-auto.0"
|
__version__ = "0.0.0-auto.0"
|
||||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"
|
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Display_Text.git"
|
||||||
|
|
||||||
|
|
||||||
class Label(displayio.Group):
|
class Label(displayio.Group):
|
||||||
"""A label displaying a string of text. The origin point set by ``x`` and ``y``
|
"""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
|
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,
|
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.
|
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``
|
: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 str text: Text to display
|
||||||
:param int max_glyphs: The largest quantity of glyphs we will display
|
:param int max_glyphs: The largest quantity of glyphs we will display
|
||||||
:param int color: Color of all text in RGB hex
|
:param int color: Color of all text in RGB hex
|
||||||
:param double line_spacing: Line spacing of text to display"""
|
:param double line_spacing: Line spacing of text to display"""
|
||||||
def __init__(self, font, *, text=None, max_glyphs=None, color=0xffffff,
|
|
||||||
line_spacing=1.25, **kwargs):
|
# 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
|
||||||
if not max_glyphs and not text:
|
if not max_glyphs and not text:
|
||||||
raise RuntimeError("Please provide a max size, or initial text")
|
raise RuntimeError("Please provide a max size, or initial text")
|
||||||
if not max_glyphs:
|
if not max_glyphs:
|
||||||
max_glyphs = len(text)
|
max_glyphs = len(text)
|
||||||
super().__init__(max_size=max_glyphs, **kwargs)
|
# add one to max_size for the background bitmap tileGrid
|
||||||
|
super().__init__(max_size=max_glyphs + 1, **kwargs)
|
||||||
|
|
||||||
self.width = max_glyphs
|
self.width = max_glyphs
|
||||||
self.font = font
|
self._font = font
|
||||||
self._text = None
|
self._text = None
|
||||||
|
self._anchor_point = anchor_point
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
self.palette = displayio.Palette(2)
|
self.height = self._font.get_bounding_box()[1]
|
||||||
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._line_spacing = line_spacing
|
||||||
self._boundingbox = None
|
self._boundingbox = None
|
||||||
|
|
||||||
if text:
|
self._background_tight = (
|
||||||
self._update_text(text)
|
background_tight # sets padding status for text background box
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create the two-color text palette
|
||||||
|
self.palette = displayio.Palette(2)
|
||||||
|
self.palette[0] = 0
|
||||||
|
self.palette.make_transparent(0)
|
||||||
|
self.color = color
|
||||||
|
|
||||||
def _update_text(self, new_text): # pylint: disable=too-many-locals
|
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
|
||||||
x = 0
|
x = 0
|
||||||
y = 0
|
y = 0
|
||||||
|
if self._added_background_tilegrid:
|
||||||
|
i = 1
|
||||||
|
else:
|
||||||
i = 0
|
i = 0
|
||||||
old_c = 0
|
tilegrid_count = i
|
||||||
y_offset = int((self.font.get_glyph(ord('M')).height -
|
|
||||||
new_text.count('\n') * self.height * self.line_spacing) / 2)
|
try:
|
||||||
#print("y offset from baseline", y_offset)
|
self._font.load_glyphs(new_text + "M")
|
||||||
left = right = top = bottom = 0
|
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
|
||||||
|
|
||||||
for character in new_text:
|
for character in new_text:
|
||||||
if character == '\n':
|
if character == "\n":
|
||||||
y += int(self.height * self._line_spacing)
|
y += int(self.height * self._line_spacing)
|
||||||
x = 0
|
x = 0
|
||||||
continue
|
continue
|
||||||
glyph = self.font.get_glyph(ord(character))
|
glyph = self._font.get_glyph(ord(character))
|
||||||
if not glyph:
|
if not glyph:
|
||||||
continue
|
continue
|
||||||
right = max(right, x+glyph.width)
|
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
|
if y == 0: # first line, find the Ascender height
|
||||||
top = min(top, -glyph.height+y_offset)
|
top = min(top, -glyph.height - glyph.dy + y_offset)
|
||||||
bottom = max(bottom, y-glyph.dy+y_offset)
|
bottom = max(bottom, y - glyph.dy + y_offset)
|
||||||
position_y = y - glyph.height - glyph.dy + y_offset
|
position_y = y - glyph.height - glyph.dy + y_offset
|
||||||
position_x = x + glyph.dx
|
position_x = x + glyph.dx
|
||||||
if not self._text or old_c >= len(self._text) or character != self._text[old_c]:
|
if glyph.width > 0 and glyph.height > 0:
|
||||||
try:
|
try:
|
||||||
face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette,
|
# pylint: disable=unexpected-keyword-arg
|
||||||
|
face = displayio.TileGrid(
|
||||||
|
glyph.bitmap,
|
||||||
|
pixel_shader=self.palette,
|
||||||
default_tile=glyph.tile_index,
|
default_tile=glyph.tile_index,
|
||||||
tile_width=glyph.width, tile_height=glyph.height,
|
tile_width=glyph.width,
|
||||||
position=(position_x, position_y))
|
tile_height=glyph.height,
|
||||||
|
position=(position_x, position_y),
|
||||||
|
)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
face = displayio.TileGrid(glyph.bitmap, pixel_shader=self.palette,
|
face = displayio.TileGrid(
|
||||||
|
glyph.bitmap,
|
||||||
|
pixel_shader=self.palette,
|
||||||
default_tile=glyph.tile_index,
|
default_tile=glyph.tile_index,
|
||||||
tile_width=glyph.width, tile_height=glyph.height,
|
tile_width=glyph.width,
|
||||||
x=position_x, y=position_y)
|
tile_height=glyph.height,
|
||||||
if i < len(self):
|
x=position_x,
|
||||||
self[i] = face
|
y=position_y,
|
||||||
|
)
|
||||||
|
if tilegrid_count < len(self):
|
||||||
|
self[tilegrid_count] = face
|
||||||
else:
|
else:
|
||||||
self.append(face)
|
self.append(face)
|
||||||
elif self._text and character == self._text[old_c]:
|
tilegrid_count += 1
|
||||||
try:
|
|
||||||
self[i].position = (position_x, position_y)
|
|
||||||
except AttributeError:
|
|
||||||
self[i].x = position_x
|
|
||||||
self[i].y = position_y
|
|
||||||
|
|
||||||
x += glyph.shift_x
|
x += glyph.shift_x
|
||||||
|
|
||||||
# TODO skip this for control sequences or non-printables.
|
|
||||||
i += 1
|
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
|
# Remove the rest
|
||||||
while len(self) > i:
|
|
||||||
|
if left is None:
|
||||||
|
left = 0
|
||||||
|
|
||||||
|
while len(self) > tilegrid_count: # i:
|
||||||
self.pop()
|
self.pop()
|
||||||
self._text = new_text
|
self._text = new_text
|
||||||
self._boundingbox = (left, top, left+right, bottom-top)
|
self._boundingbox = (left, top, right - left, bottom - top)
|
||||||
|
|
||||||
|
if self.background_color is not None:
|
||||||
|
self._update_background_color(self._background_color)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bounding_box(self):
|
def bounding_box(self):
|
||||||
|
|
@ -162,7 +327,22 @@ class Label(displayio.Group):
|
||||||
|
|
||||||
@color.setter
|
@color.setter
|
||||||
def color(self, new_color):
|
def color(self, new_color):
|
||||||
|
self._color = new_color
|
||||||
|
if new_color is not None:
|
||||||
self.palette[1] = new_color
|
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)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self):
|
||||||
|
|
@ -171,4 +351,74 @@ class Label(displayio.Group):
|
||||||
|
|
||||||
@text.setter
|
@text.setter
|
||||||
def text(self, new_text):
|
def text(self, new_text):
|
||||||
self._update_text(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)
|
||||||
|
)
|
||||||
|
|
|
||||||
88
docs/conf.py
88
docs/conf.py
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
|
||||||
|
sys.path.insert(0, os.path.abspath(".."))
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -10,10 +11,10 @@ sys.path.insert(0, os.path.abspath('..'))
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
'sphinx.ext.intersphinx',
|
"sphinx.ext.intersphinx",
|
||||||
'sphinx.ext.napoleon',
|
"sphinx.ext.napoleon",
|
||||||
'sphinx.ext.todo',
|
"sphinx.ext.todo",
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: Please Read!
|
# TODO: Please Read!
|
||||||
|
|
@ -23,29 +24,32 @@ extensions = [
|
||||||
autodoc_mock_imports = ["displayio"]
|
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.
|
# 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.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Adafruit Display_Text Library'
|
project = "Adafruit Display_Text Library"
|
||||||
copyright = u'2019 Scott Shawcroft'
|
copyright = "2019 Scott Shawcroft"
|
||||||
author = u'Scott Shawcroft'
|
author = "Scott Shawcroft"
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = u'1.0'
|
version = "1.0"
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = u'1.0'
|
release = "1.0"
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
@ -57,7 +61,7 @@ language = None
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
# This patterns also effect to html_static_path and html_extra_path
|
# 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
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
|
|
@ -69,7 +73,7 @@ default_role = "any"
|
||||||
add_function_parentheses = True
|
add_function_parentheses = True
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# 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.
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
|
|
@ -84,32 +88,33 @@ napoleon_numpy_docstring = False
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# 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
|
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||||
try:
|
try:
|
||||||
import sphinx_rtd_theme
|
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:
|
except:
|
||||||
html_theme = 'default'
|
html_theme = "default"
|
||||||
html_theme_path = ['.']
|
html_theme_path = ["."]
|
||||||
else:
|
else:
|
||||||
html_theme_path = ['.']
|
html_theme_path = ["."]
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# 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 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
|
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
# pixels large.
|
# pixels large.
|
||||||
#
|
#
|
||||||
html_favicon = '_static/favicon.ico'
|
html_favicon = "_static/favicon.ico"
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'AdafruitDisplay_textLibrarydoc'
|
htmlhelp_basename = "AdafruitDisplay_textLibrarydoc"
|
||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
|
@ -117,15 +122,12 @@ latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#
|
#
|
||||||
# 'papersize': 'letterpaper',
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#
|
#
|
||||||
# 'pointsize': '10pt',
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#
|
#
|
||||||
# 'preamble': '',
|
# 'preamble': '',
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
# Latex figure (float) alignment
|
||||||
#
|
#
|
||||||
# 'figure_align': 'htbp',
|
# 'figure_align': 'htbp',
|
||||||
|
|
@ -135,8 +137,13 @@ latex_elements = {
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'AdafruitDisplay_TextLibrary.tex', u'AdafruitDisplay_Text Library Documentation',
|
(
|
||||||
author, 'manual'),
|
master_doc,
|
||||||
|
"AdafruitDisplay_TextLibrary.tex",
|
||||||
|
"AdafruitDisplay_Text Library Documentation",
|
||||||
|
author,
|
||||||
|
"manual",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# -- Options for manual page output ---------------------------------------
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
@ -144,8 +151,13 @@ latex_documents = [
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
(master_doc, 'AdafruitDisplay_Textlibrary', u'Adafruit Display_Text Library Documentation',
|
(
|
||||||
[author], 1)
|
master_doc,
|
||||||
|
"AdafruitDisplay_Textlibrary",
|
||||||
|
"Adafruit Display_Text Library Documentation",
|
||||||
|
[author],
|
||||||
|
1,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# -- Options for Texinfo output -------------------------------------------
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
@ -154,7 +166,13 @@ man_pages = [
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
(master_doc, 'AdafruitDisplay_TextLibrary', u'Adafruit Display_Text Library Documentation',
|
(
|
||||||
author, 'AdafruitDisplay_TextLibrary', 'One line description of project.',
|
master_doc,
|
||||||
'Miscellaneous'),
|
"AdafruitDisplay_TextLibrary",
|
||||||
|
"Adafruit Display_Text Library Documentation",
|
||||||
|
author,
|
||||||
|
"AdafruitDisplay_TextLibrary",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
63
examples/display_text_anchored_position.py
Normal file
63
examples/display_text_anchored_position.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
"""
|
||||||
|
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
|
||||||
27
examples/display_text_background_color.py
Normal file
27
examples/display_text_background_color.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
"""
|
||||||
|
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
|
||||||
125
examples/display_text_background_color_padding.py
Executable file
125
examples/display_text_background_color_padding.py
Executable file
|
|
@ -0,0 +1,125 @@
|
||||||
|
"""
|
||||||
|
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))
|
||||||
12
examples/display_text_bitmap_label_simpletest.py
Normal file
12
examples/display_text_bitmap_label_simpletest.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
||||||
222
examples/display_text_label_vs_bitmap_label_comparison.py
Normal file
222
examples/display_text_label_vs_bitmap_label_comparison.py
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
# 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
|
||||||
|
|
@ -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 os
|
||||||
import time
|
import time
|
||||||
import board
|
import board
|
||||||
import pulseio
|
|
||||||
import microcontroller
|
|
||||||
import displayio
|
import displayio
|
||||||
|
|
||||||
from adafruit_bitmap_font import bitmap_font
|
from adafruit_bitmap_font import bitmap_font
|
||||||
from adafruit_display_text.label import Label
|
from adafruit_display_text.label import Label
|
||||||
|
|
||||||
backlight = pulseio.PWMOut(microcontroller.pin.PB21) #pylint: disable=no-member
|
fonts = list(
|
||||||
|
filter(lambda x: x.endswith("bdf") and not x.startswith("."), os.listdir("/"))
|
||||||
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]
|
fonts = [bitmap_font.load_font(x) for x in fonts]
|
||||||
|
|
||||||
|
|
||||||
print("fade up")
|
print("fade up")
|
||||||
# Fade up the backlight
|
# Fade up the backlight
|
||||||
for b in range(100):
|
for b in range(100):
|
||||||
backlight.duty_cycle = b * max_brightness // 100
|
board.DISPLAY.brightness = b / 100
|
||||||
time.sleep(0.01) # default (0.01)
|
time.sleep(0.01) # default (0.01)
|
||||||
|
|
||||||
demos = ["CircuitPython = Code + Community", "accents - üàêùéáçãÍóí", "others - αψ◌"]
|
demos = ["CircuitPython = Code + Community", "accents - üàêùéáçãÍóí", "others - αψ◌"]
|
||||||
|
|
@ -38,16 +38,19 @@ for demo_text in demos:
|
||||||
y += area.height
|
y += area.height
|
||||||
|
|
||||||
# Wait for the image to load.
|
# 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 forever
|
# Wait for 10 minutes (600 seconds)
|
||||||
time.sleep(600)
|
time.sleep(600)
|
||||||
|
|
||||||
# Fade down the backlight
|
# Fade down the backlight
|
||||||
for b in range(50, -1, -1):
|
for b in range(100, -1, -1):
|
||||||
backlight.duty_cycle = b * max_brightness // 100
|
board.DISPLAY.brightness = b / 100
|
||||||
time.sleep(0.005) # default (0.005)
|
time.sleep(0.01) # default (0.01)
|
||||||
|
|
||||||
print("fade down")
|
print("fade down")
|
||||||
|
|
||||||
# splash.pop()
|
time.sleep(10)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
import os
|
import os
|
||||||
import board
|
import board
|
||||||
import displayio
|
import displayio
|
||||||
from adafruit_display_text.label import Label
|
|
||||||
from adafruit_bitmap_font import bitmap_font
|
from adafruit_bitmap_font import bitmap_font
|
||||||
|
from adafruit_display_text.label import Label
|
||||||
|
|
||||||
|
|
||||||
# the current working directory (where this file is)
|
# the current working directory (where this file is)
|
||||||
cwd = ("/"+__file__).rsplit('/', 1)[0]
|
cwd = ("/" + __file__).rsplit("/", 1)[0]
|
||||||
fonts = [file for file in os.listdir(cwd+"/fonts/")
|
fonts = [
|
||||||
if (file.endswith(".bdf") and not file.startswith("._"))]
|
file
|
||||||
|
for file in os.listdir(cwd + "/fonts/")
|
||||||
|
if (file.endswith(".bdf") and not file.startswith("._"))
|
||||||
|
]
|
||||||
for i, filename in enumerate(fonts):
|
for i, filename in enumerate(fonts):
|
||||||
fonts[i] = cwd+"/fonts/"+filename
|
fonts[i] = cwd + "/fonts/" + filename
|
||||||
print(fonts)
|
print(fonts)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
@ -26,14 +30,12 @@ board.DISPLAY.show(splash)
|
||||||
color_bitmap = displayio.Bitmap(320, 240, 1)
|
color_bitmap = displayio.Bitmap(320, 240, 1)
|
||||||
color_palette = displayio.Palette(1)
|
color_palette = displayio.Palette(1)
|
||||||
color_palette[0] = 0xFFFFFF
|
color_palette[0] = 0xFFFFFF
|
||||||
bg_sprite = displayio.TileGrid(color_bitmap,
|
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
|
||||||
pixel_shader=color_palette,
|
|
||||||
x=0, y=0)
|
|
||||||
splash.append(bg_sprite)
|
splash.append(bg_sprite)
|
||||||
|
|
||||||
# Load the font
|
# Load the font
|
||||||
font = bitmap_font.load_font(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)
|
print(DISPLAY_STRING)
|
||||||
|
|
||||||
|
|
@ -48,13 +50,16 @@ print(dims)
|
||||||
textbg_bitmap = displayio.Bitmap(dims[2], dims[3], 1)
|
textbg_bitmap = displayio.Bitmap(dims[2], dims[3], 1)
|
||||||
textbg_palette = displayio.Palette(1)
|
textbg_palette = displayio.Palette(1)
|
||||||
textbg_palette[0] = 0xFF0000
|
textbg_palette[0] = 0xFF0000
|
||||||
textbg_sprite = displayio.TileGrid(textbg_bitmap,
|
textbg_sprite = displayio.TileGrid(
|
||||||
pixel_shader=textbg_palette,
|
textbg_bitmap, pixel_shader=textbg_palette, x=text.x + dims[0], y=text.y + dims[1]
|
||||||
x=text.x+dims[0], y=text.y+dims[1])
|
)
|
||||||
splash.append(textbg_sprite)
|
splash.append(textbg_sprite)
|
||||||
splash.append(text)
|
splash.append(text)
|
||||||
board.DISPLAY.refresh_soon()
|
try:
|
||||||
board.DISPLAY.wait_for_frame()
|
board.DISPLAY.refresh(target_frames_per_second=60)
|
||||||
|
except AttributeError:
|
||||||
|
board.DISPLAY.refresh_soon()
|
||||||
|
board.DISPLAY.wait_for_frame()
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
|
||||||
4194
fonts/Helvetica-Bold-16.bdf
Executable file
4194
fonts/Helvetica-Bold-16.bdf
Executable file
File diff suppressed because it is too large
Load diff
|
|
@ -1,2 +1,2 @@
|
||||||
Adafruit-Blinka
|
Adafruit-Blinka
|
||||||
|
adafruit-blinka-displayio
|
||||||
|
|
|
||||||
50
setup.py
Normal file
50
setup.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
"""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"],
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue